Mercurial > libavformat.hg
annotate assdec.c @ 6491:b7f807b4cd88 libavformat tip
In mov demuxer, check that nb_streams is valid before using it in read_dac3
| author | bcoudurier |
|---|---|
| date | Tue, 28 Sep 2010 00:33:21 +0000 |
| parents | 8788871cbc99 |
| children |
| rev | line source |
|---|---|
| 3942 | 1 /* |
| 2 * SSA/ASS demuxer | |
| 3 * Copyright (c) 2008 Michael Niedermayer | |
| 4 * | |
| 5 * This file is part of FFmpeg. | |
| 6 * | |
| 7 * FFmpeg is free software; you can redistribute it and/or | |
| 8 * modify it under the terms of the GNU Lesser General Public | |
| 9 * License as published by the Free Software Foundation; either | |
| 10 * version 2.1 of the License, or (at your option) any later version. | |
| 11 * | |
| 12 * FFmpeg is distributed in the hope that it will be useful, | |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 * Lesser General Public License for more details. | |
| 16 * | |
| 17 * You should have received a copy of the GNU Lesser General Public | |
| 18 * License along with FFmpeg; if not, write to the Free Software | |
| 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 20 */ | |
| 21 | |
| 22 #include "avformat.h" | |
| 6300 | 23 #include "internal.h" |
| 3942 | 24 |
| 25 #define MAX_LINESIZE 2000 | |
| 26 | |
| 27 typedef struct ASSContext{ | |
| 28 uint8_t *event_buffer; | |
| 29 uint8_t **event; | |
| 30 unsigned int event_count; | |
| 31 unsigned int event_index; | |
| 32 }ASSContext; | |
| 33 | |
| 34 static int probe(AVProbeData *p) | |
| 35 { | |
| 36 const char *header= "[Script Info]"; | |
| 37 | |
| 38 if( !memcmp(p->buf , header, strlen(header)) | |
| 39 || !memcmp(p->buf+3, header, strlen(header))) | |
| 40 return AVPROBE_SCORE_MAX; | |
| 41 | |
| 42 return 0; | |
| 43 } | |
| 44 | |
| 45 static int read_close(AVFormatContext *s) | |
| 46 { | |
| 47 ASSContext *ass = s->priv_data; | |
| 48 | |
| 49 av_freep(&ass->event_buffer); | |
| 50 av_freep(&ass->event); | |
| 51 | |
| 52 return 0; | |
| 53 } | |
| 54 | |
| 55 static int64_t get_pts(const uint8_t *p) | |
| 56 { | |
| 57 int hour, min, sec, hsec; | |
| 58 | |
| 59 if(sscanf(p, "%*[^,],%d:%d:%d%*c%d", &hour, &min, &sec, &hsec) != 4) | |
| 60 return AV_NOPTS_VALUE; | |
| 61 | |
| 62 // av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d [%s]\n", i, hour, min, sec, hsec, p); | |
| 63 | |
| 64 min+= 60*hour; | |
| 65 sec+= 60*min; | |
| 66 | |
| 67 return sec*100+hsec; | |
| 68 } | |
| 69 | |
| 70 static int event_cmp(uint8_t **a, uint8_t **b) | |
| 71 { | |
| 72 return get_pts(*a) - get_pts(*b); | |
| 73 } | |
| 74 | |
| 75 static int read_header(AVFormatContext *s, AVFormatParameters *ap) | |
| 76 { | |
| 6303 | 77 int i, len, header_remaining; |
| 3942 | 78 ASSContext *ass = s->priv_data; |
| 79 ByteIOContext *pb = s->pb; | |
| 80 AVStream *st; | |
| 81 int allocated[2]={0}; | |
| 82 uint8_t *p, **dst[2]={0}; | |
| 83 int pos[2]={0}; | |
| 84 | |
| 85 st = av_new_stream(s, 0); | |
| 86 if (!st) | |
| 87 return -1; | |
| 88 av_set_pts_info(st, 64, 1, 100); | |
|
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
4484
diff
changeset
|
89 st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; |
| 3942 | 90 st->codec->codec_id= CODEC_ID_SSA; |
| 91 | |
| 92 header_remaining= INT_MAX; | |
| 93 dst[0] = &st->codec->extradata; | |
| 94 dst[1] = &ass->event_buffer; | |
| 95 while(!url_feof(pb)){ | |
| 96 uint8_t line[MAX_LINESIZE]; | |
| 97 | |
| 6303 | 98 len = ff_get_line(pb, line, sizeof(line)); |
| 3942 | 99 |
| 100 if(!memcmp(line, "[Events]", 8)) | |
| 101 header_remaining= 2; | |
| 102 else if(line[0]=='[') | |
| 103 header_remaining= INT_MAX; | |
| 104 | |
| 105 i= header_remaining==0; | |
| 106 | |
| 107 if(i && get_pts(line) == AV_NOPTS_VALUE) | |
| 108 continue; | |
| 109 | |
| 110 p = av_fast_realloc(*(dst[i]), &allocated[i], pos[i]+MAX_LINESIZE); | |
| 111 if(!p) | |
| 112 goto fail; | |
| 113 *(dst[i])= p; | |
| 6303 | 114 memcpy(p + pos[i], line, len+1); |
| 115 pos[i] += len; | |
| 3942 | 116 if(i) ass->event_count++; |
| 117 else header_remaining--; | |
| 118 } | |
| 119 st->codec->extradata_size= pos[0]; | |
| 120 | |
| 121 if(ass->event_count >= UINT_MAX / sizeof(*ass->event)) | |
| 122 goto fail; | |
| 123 | |
| 124 ass->event= av_malloc(ass->event_count * sizeof(*ass->event)); | |
| 125 p= ass->event_buffer; | |
| 126 for(i=0; i<ass->event_count; i++){ | |
| 127 ass->event[i]= p; | |
| 128 while(*p && *p != '\n') | |
| 129 p++; | |
| 3943 | 130 p++; |
| 3942 | 131 } |
| 132 | |
|
4484
da64b6d7a2d9
Silence "assdec.c:146: warning: passing argument 4 of ?qsort? from incompatible pointer type"
michael
parents:
3950
diff
changeset
|
133 qsort(ass->event, ass->event_count, sizeof(*ass->event), (void*)event_cmp); |
| 3942 | 134 |
| 135 return 0; | |
| 136 | |
| 137 fail: | |
| 138 read_close(s); | |
| 139 | |
| 140 return -1; | |
| 141 } | |
| 142 | |
| 143 static int read_packet(AVFormatContext *s, AVPacket *pkt) | |
| 144 { | |
| 145 ASSContext *ass = s->priv_data; | |
| 3943 | 146 uint8_t *p, *end; |
| 3942 | 147 |
| 148 if(ass->event_index >= ass->event_count) | |
| 149 return AVERROR(EIO); | |
| 150 | |
| 151 p= ass->event[ ass->event_index ]; | |
| 152 | |
| 3943 | 153 end= strchr(p, '\n'); |
| 154 av_new_packet(pkt, end ? end-p+1 : strlen(p)); | |
|
5913
11bb10c37225
Replace all occurences of PKT_FLAG_KEY with AV_PKT_FLAG_KEY.
cehoyos
parents:
5910
diff
changeset
|
155 pkt->flags |= AV_PKT_FLAG_KEY; |
| 3942 | 156 pkt->pos= p - ass->event_buffer + s->streams[0]->codec->extradata_size; |
| 157 pkt->pts= pkt->dts= get_pts(p); | |
| 158 memcpy(pkt->data, p, pkt->size); | |
| 159 | |
| 160 ass->event_index++; | |
| 161 | |
| 162 return 0; | |
| 163 } | |
| 164 | |
| 6337 | 165 static int read_seek2(AVFormatContext *s, int stream_index, |
| 166 int64_t min_ts, int64_t ts, int64_t max_ts, int flags) | |
| 167 { | |
| 168 ASSContext *ass = s->priv_data; | |
| 169 | |
| 170 if (flags & AVSEEK_FLAG_BYTE) { | |
| 171 return AVERROR_NOTSUPP; | |
| 172 } else if (flags & AVSEEK_FLAG_FRAME) { | |
| 173 if (ts < 0 || ts >= ass->event_count) | |
| 174 return AVERROR(ERANGE); | |
| 175 ass->event_index = ts; | |
| 176 } else { | |
| 177 int i, idx = -1; | |
| 178 int64_t min_ts_diff = INT64_MAX; | |
| 179 if (stream_index == -1) { | |
| 180 AVRational time_base = s->streams[0]->time_base; | |
| 181 ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base); | |
| 182 min_ts = av_rescale_rnd(min_ts, time_base.den, | |
| 183 time_base.num * (int64_t)AV_TIME_BASE, | |
| 184 AV_ROUND_UP); | |
| 185 max_ts = av_rescale_rnd(max_ts, time_base.den, | |
| 186 time_base.num * (int64_t)AV_TIME_BASE, | |
| 187 AV_ROUND_DOWN); | |
| 188 } | |
| 189 /* TODO: ass->event[] is sorted by pts so we could do a binary search */ | |
| 190 for (i=0; i<ass->event_count; i++) { | |
| 191 int64_t pts = get_pts(ass->event[i]); | |
| 192 int64_t ts_diff = FFABS(pts - ts); | |
| 193 if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) { | |
| 194 min_ts_diff = ts_diff; | |
| 195 idx = i; | |
| 196 } | |
| 197 } | |
| 198 if (idx < 0) | |
| 199 return AVERROR(ERANGE); | |
| 200 ass->event_index = idx; | |
| 201 } | |
| 202 return 0; | |
| 203 } | |
| 204 | |
| 3942 | 205 AVInputFormat ass_demuxer = { |
| 206 "ass", | |
| 6241 | 207 NULL_IF_CONFIG_SMALL("Advanced SubStation Alpha subtitle format"), |
| 3942 | 208 sizeof(ASSContext), |
| 209 probe, | |
| 210 read_header, | |
| 211 read_packet, | |
| 212 read_close, | |
| 6337 | 213 .read_seek2 = read_seek2, |
| 3942 | 214 }; |
