| @@ -22,24 +22,25 @@ | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include "libavutil/mathematics.h" | #include "libavutil/mathematics.h" | ||||
| #include "avformat.h" | #include "avformat.h" | ||||
| #include "internal.h" | #include "internal.h" | ||||
| #define MAX_LINESIZE 2000 | #define MAX_LINESIZE 2000 | ||||
| typedef struct ASSContext{ | |||||
| typedef struct ASSContext { | |||||
| uint8_t *event_buffer; | uint8_t *event_buffer; | ||||
| uint8_t **event; | uint8_t **event; | ||||
| unsigned int event_count; | unsigned int event_count; | ||||
| unsigned int event_index; | unsigned int event_index; | ||||
| }ASSContext; | |||||
| } ASSContext; | |||||
| static int probe(AVProbeData *p) | static int probe(AVProbeData *p) | ||||
| { | { | ||||
| const char *header= "[Script Info]"; | |||||
| const char *header = "[Script Info]"; | |||||
| if( !memcmp(p->buf , header, strlen(header)) | |||||
| || !memcmp(p->buf+3, header, strlen(header))) | |||||
| if (!memcmp(p->buf, header, strlen(header)) || | |||||
| !memcmp(p->buf + 3, header, strlen(header))) | |||||
| return AVPROBE_SCORE_MAX; | return AVPROBE_SCORE_MAX; | ||||
| return 0; | return 0; | ||||
| @@ -59,15 +60,15 @@ static int64_t get_pts(const uint8_t *p) | |||||
| { | { | ||||
| int hour, min, sec, hsec; | int hour, min, sec, hsec; | ||||
| if(sscanf(p, "%*[^,],%d:%d:%d%*c%d", &hour, &min, &sec, &hsec) != 4) | |||||
| if (sscanf(p, "%*[^,],%d:%d:%d%*c%d", &hour, &min, &sec, &hsec) != 4) | |||||
| return AV_NOPTS_VALUE; | return AV_NOPTS_VALUE; | ||||
| av_dlog(NULL, "%d %d %d %d [%s]\n", hour, min, sec, hsec, p); | av_dlog(NULL, "%d %d %d %d [%s]\n", hour, min, sec, hsec, p); | ||||
| min+= 60*hour; | |||||
| sec+= 60*min; | |||||
| min += 60 * hour; | |||||
| sec += 60 * min; | |||||
| return sec*100+hsec; | |||||
| return sec * 100 + hsec; | |||||
| } | } | ||||
| static int event_cmp(const void *_a, const void *_b) | static int event_cmp(const void *_a, const void *_b) | ||||
| @@ -82,54 +83,56 @@ static int read_header(AVFormatContext *s) | |||||
| ASSContext *ass = s->priv_data; | ASSContext *ass = s->priv_data; | ||||
| AVIOContext *pb = s->pb; | AVIOContext *pb = s->pb; | ||||
| AVStream *st; | AVStream *st; | ||||
| int allocated[2]={0}; | |||||
| uint8_t *p, **dst[2]={0}; | |||||
| int pos[2]={0}; | |||||
| int allocated[2] = { 0 }; | |||||
| uint8_t *p, **dst[2] = { 0 }; | |||||
| int pos[2] = { 0 }; | |||||
| st = avformat_new_stream(s, NULL); | st = avformat_new_stream(s, NULL); | ||||
| if (!st) | if (!st) | ||||
| return -1; | return -1; | ||||
| avpriv_set_pts_info(st, 64, 1, 100); | avpriv_set_pts_info(st, 64, 1, 100); | ||||
| st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; | st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; | ||||
| st->codec->codec_id= AV_CODEC_ID_SSA; | |||||
| st->codec->codec_id = AV_CODEC_ID_SSA; | |||||
| header_remaining= INT_MAX; | |||||
| header_remaining = INT_MAX; | |||||
| dst[0] = &st->codec->extradata; | dst[0] = &st->codec->extradata; | ||||
| dst[1] = &ass->event_buffer; | dst[1] = &ass->event_buffer; | ||||
| while(!pb->eof_reached){ | |||||
| while (!pb->eof_reached) { | |||||
| uint8_t line[MAX_LINESIZE]; | uint8_t line[MAX_LINESIZE]; | ||||
| len = ff_get_line(pb, line, sizeof(line)); | len = ff_get_line(pb, line, sizeof(line)); | ||||
| if(!memcmp(line, "[Events]", 8)) | |||||
| header_remaining= 2; | |||||
| else if(line[0]=='[') | |||||
| header_remaining= INT_MAX; | |||||
| if (!memcmp(line, "[Events]", 8)) | |||||
| header_remaining = 2; | |||||
| else if (line[0] == '[') | |||||
| header_remaining = INT_MAX; | |||||
| i= header_remaining==0; | |||||
| i = header_remaining == 0; | |||||
| if(i && get_pts(line) == AV_NOPTS_VALUE) | |||||
| if (i && get_pts(line) == AV_NOPTS_VALUE) | |||||
| continue; | continue; | ||||
| p = av_fast_realloc(*(dst[i]), &allocated[i], pos[i]+MAX_LINESIZE); | |||||
| if(!p) | |||||
| p = av_fast_realloc(*(dst[i]), &allocated[i], pos[i] + MAX_LINESIZE); | |||||
| if (!p) | |||||
| goto fail; | goto fail; | ||||
| *(dst[i])= p; | |||||
| memcpy(p + pos[i], line, len+1); | |||||
| *(dst[i]) = p; | |||||
| memcpy(p + pos[i], line, len + 1); | |||||
| pos[i] += len; | pos[i] += len; | ||||
| if(i) ass->event_count++; | |||||
| else header_remaining--; | |||||
| if (i) | |||||
| ass->event_count++; | |||||
| else | |||||
| header_remaining--; | |||||
| } | } | ||||
| st->codec->extradata_size= pos[0]; | |||||
| st->codec->extradata_size = pos[0]; | |||||
| if(ass->event_count >= UINT_MAX / sizeof(*ass->event)) | |||||
| if (ass->event_count >= UINT_MAX / sizeof(*ass->event)) | |||||
| goto fail; | goto fail; | ||||
| ass->event= av_malloc(ass->event_count * sizeof(*ass->event)); | |||||
| p= ass->event_buffer; | |||||
| for(i=0; i<ass->event_count; i++){ | |||||
| ass->event[i]= p; | |||||
| while(*p && *p != '\n') | |||||
| ass->event = av_malloc(ass->event_count * sizeof(*ass->event)); | |||||
| p = ass->event_buffer; | |||||
| for (i = 0; i < ass->event_count; i++) { | |||||
| ass->event[i] = p; | |||||
| while (*p && *p != '\n') | |||||
| p++; | p++; | ||||
| p++; | p++; | ||||
| } | } | ||||
| @@ -149,16 +152,16 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) | |||||
| ASSContext *ass = s->priv_data; | ASSContext *ass = s->priv_data; | ||||
| uint8_t *p, *end; | uint8_t *p, *end; | ||||
| if(ass->event_index >= ass->event_count) | |||||
| if (ass->event_index >= ass->event_count) | |||||
| return AVERROR(EIO); | return AVERROR(EIO); | ||||
| p= ass->event[ ass->event_index ]; | |||||
| p = ass->event[ass->event_index]; | |||||
| end= strchr(p, '\n'); | |||||
| av_new_packet(pkt, end ? end-p+1 : strlen(p)); | |||||
| end = strchr(p, '\n'); | |||||
| av_new_packet(pkt, end ? end - p + 1 : strlen(p)); | |||||
| pkt->flags |= AV_PKT_FLAG_KEY; | pkt->flags |= AV_PKT_FLAG_KEY; | ||||
| pkt->pos= p - ass->event_buffer + s->streams[0]->codec->extradata_size; | |||||
| pkt->pts= pkt->dts= get_pts(p); | |||||
| pkt->pos = p - ass->event_buffer + s->streams[0]->codec->extradata_size; | |||||
| pkt->pts = pkt->dts = get_pts(p); | |||||
| memcpy(pkt->data, p, pkt->size); | memcpy(pkt->data, p, pkt->size); | ||||
| ass->event_index++; | ass->event_index++; | ||||
| @@ -182,21 +185,21 @@ static int read_seek2(AVFormatContext *s, int stream_index, | |||||
| int64_t min_ts_diff = INT64_MAX; | int64_t min_ts_diff = INT64_MAX; | ||||
| if (stream_index == -1) { | if (stream_index == -1) { | ||||
| AVRational time_base = s->streams[0]->time_base; | AVRational time_base = s->streams[0]->time_base; | ||||
| ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base); | |||||
| ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base); | |||||
| min_ts = av_rescale_rnd(min_ts, time_base.den, | min_ts = av_rescale_rnd(min_ts, time_base.den, | ||||
| time_base.num * (int64_t)AV_TIME_BASE, | |||||
| time_base.num * (int64_t) AV_TIME_BASE, | |||||
| AV_ROUND_UP); | AV_ROUND_UP); | ||||
| max_ts = av_rescale_rnd(max_ts, time_base.den, | max_ts = av_rescale_rnd(max_ts, time_base.den, | ||||
| time_base.num * (int64_t)AV_TIME_BASE, | |||||
| time_base.num * (int64_t) AV_TIME_BASE, | |||||
| AV_ROUND_DOWN); | AV_ROUND_DOWN); | ||||
| } | } | ||||
| /* TODO: ass->event[] is sorted by pts so we could do a binary search */ | /* TODO: ass->event[] is sorted by pts so we could do a binary search */ | ||||
| for (i=0; i<ass->event_count; i++) { | |||||
| int64_t pts = get_pts(ass->event[i]); | |||||
| for (i = 0; i < ass->event_count; i++) { | |||||
| int64_t pts = get_pts(ass->event[i]); | |||||
| int64_t ts_diff = FFABS(pts - ts); | int64_t ts_diff = FFABS(pts - ts); | ||||
| if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) { | if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) { | ||||
| min_ts_diff = ts_diff; | min_ts_diff = ts_diff; | ||||
| idx = i; | |||||
| idx = i; | |||||
| } | } | ||||
| } | } | ||||
| if (idx < 0) | if (idx < 0) | ||||