Mercurial > libavformat.hg
annotate assdec.c @ 6415:d2ca6ecc8b43 libavformat
Added option to write frames interleaved (yet disabled)
For this reason, a MuxerContext and write_trailer()-function was added,
to track the previous packet and flush the last packet at the end.
author | bindhammer |
---|---|
date | Thu, 26 Aug 2010 10:03:09 +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 }; |