00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avformat.h"
00023 #include "internal.h"
00024
00025 #define MAX_LINESIZE 2000
00026
00027 typedef struct ASSContext{
00028 uint8_t *event_buffer;
00029 uint8_t **event;
00030 unsigned int event_count;
00031 unsigned int event_index;
00032 }ASSContext;
00033
00034 static int probe(AVProbeData *p)
00035 {
00036 const char *header= "[Script Info]";
00037
00038 if( !memcmp(p->buf , header, strlen(header))
00039 || !memcmp(p->buf+3, header, strlen(header)))
00040 return AVPROBE_SCORE_MAX;
00041
00042 return 0;
00043 }
00044
00045 static int read_close(AVFormatContext *s)
00046 {
00047 ASSContext *ass = s->priv_data;
00048
00049 av_freep(&ass->event_buffer);
00050 av_freep(&ass->event);
00051
00052 return 0;
00053 }
00054
00055 static int64_t get_pts(const uint8_t *p)
00056 {
00057 int hour, min, sec, hsec;
00058
00059 if(sscanf(p, "%*[^,],%d:%d:%d%*c%d", &hour, &min, &sec, &hsec) != 4)
00060 return AV_NOPTS_VALUE;
00061
00062
00063
00064 min+= 60*hour;
00065 sec+= 60*min;
00066
00067 return sec*100+hsec;
00068 }
00069
00070 static int event_cmp(uint8_t **a, uint8_t **b)
00071 {
00072 return get_pts(*a) - get_pts(*b);
00073 }
00074
00075 static int read_header(AVFormatContext *s, AVFormatParameters *ap)
00076 {
00077 int i, len, header_remaining;
00078 ASSContext *ass = s->priv_data;
00079 AVIOContext *pb = s->pb;
00080 AVStream *st;
00081 int allocated[2]={0};
00082 uint8_t *p, **dst[2]={0};
00083 int pos[2]={0};
00084
00085 st = av_new_stream(s, 0);
00086 if (!st)
00087 return -1;
00088 av_set_pts_info(st, 64, 1, 100);
00089 st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
00090 st->codec->codec_id= CODEC_ID_SSA;
00091
00092 header_remaining= INT_MAX;
00093 dst[0] = &st->codec->extradata;
00094 dst[1] = &ass->event_buffer;
00095 while(!url_feof(pb)){
00096 uint8_t line[MAX_LINESIZE];
00097
00098 len = ff_get_line(pb, line, sizeof(line));
00099
00100 if(!memcmp(line, "[Events]", 8))
00101 header_remaining= 2;
00102 else if(line[0]=='[')
00103 header_remaining= INT_MAX;
00104
00105 i= header_remaining==0;
00106
00107 if(i && get_pts(line) == AV_NOPTS_VALUE)
00108 continue;
00109
00110 p = av_fast_realloc(*(dst[i]), &allocated[i], pos[i]+MAX_LINESIZE);
00111 if(!p)
00112 goto fail;
00113 *(dst[i])= p;
00114 memcpy(p + pos[i], line, len+1);
00115 pos[i] += len;
00116 if(i) ass->event_count++;
00117 else header_remaining--;
00118 }
00119 st->codec->extradata_size= pos[0];
00120
00121 if(ass->event_count >= UINT_MAX / sizeof(*ass->event))
00122 goto fail;
00123
00124 ass->event= av_malloc(ass->event_count * sizeof(*ass->event));
00125 p= ass->event_buffer;
00126 for(i=0; i<ass->event_count; i++){
00127 ass->event[i]= p;
00128 while(*p && *p != '\n')
00129 p++;
00130 p++;
00131 }
00132
00133 qsort(ass->event, ass->event_count, sizeof(*ass->event), (void*)event_cmp);
00134
00135 return 0;
00136
00137 fail:
00138 read_close(s);
00139
00140 return -1;
00141 }
00142
00143 static int read_packet(AVFormatContext *s, AVPacket *pkt)
00144 {
00145 ASSContext *ass = s->priv_data;
00146 uint8_t *p, *end;
00147
00148 if(ass->event_index >= ass->event_count)
00149 return AVERROR(EIO);
00150
00151 p= ass->event[ ass->event_index ];
00152
00153 end= strchr(p, '\n');
00154 av_new_packet(pkt, end ? end-p+1 : strlen(p));
00155 pkt->flags |= AV_PKT_FLAG_KEY;
00156 pkt->pos= p - ass->event_buffer + s->streams[0]->codec->extradata_size;
00157 pkt->pts= pkt->dts= get_pts(p);
00158 memcpy(pkt->data, p, pkt->size);
00159
00160 ass->event_index++;
00161
00162 return 0;
00163 }
00164
00165 static int read_seek2(AVFormatContext *s, int stream_index,
00166 int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
00167 {
00168 ASSContext *ass = s->priv_data;
00169
00170 if (flags & AVSEEK_FLAG_BYTE) {
00171 return AVERROR(ENOSYS);
00172 } else if (flags & AVSEEK_FLAG_FRAME) {
00173 if (ts < 0 || ts >= ass->event_count)
00174 return AVERROR(ERANGE);
00175 ass->event_index = ts;
00176 } else {
00177 int i, idx = -1;
00178 int64_t min_ts_diff = INT64_MAX;
00179 if (stream_index == -1) {
00180 AVRational time_base = s->streams[0]->time_base;
00181 ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
00182 min_ts = av_rescale_rnd(min_ts, time_base.den,
00183 time_base.num * (int64_t)AV_TIME_BASE,
00184 AV_ROUND_UP);
00185 max_ts = av_rescale_rnd(max_ts, time_base.den,
00186 time_base.num * (int64_t)AV_TIME_BASE,
00187 AV_ROUND_DOWN);
00188 }
00189
00190 for (i=0; i<ass->event_count; i++) {
00191 int64_t pts = get_pts(ass->event[i]);
00192 int64_t ts_diff = FFABS(pts - ts);
00193 if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) {
00194 min_ts_diff = ts_diff;
00195 idx = i;
00196 }
00197 }
00198 if (idx < 0)
00199 return AVERROR(ERANGE);
00200 ass->event_index = idx;
00201 }
00202 return 0;
00203 }
00204
00205 AVInputFormat ff_ass_demuxer = {
00206 .name = "ass",
00207 .long_name = NULL_IF_CONFIG_SMALL("Advanced SubStation Alpha subtitle format"),
00208 .priv_data_size = sizeof(ASSContext),
00209 .read_probe = probe,
00210 .read_header = read_header,
00211 .read_packet = read_packet,
00212 .read_close = read_close,
00213 .read_seek2 = read_seek2,
00214 };