Mercurial > libavformat.hg
annotate ffm.c @ 1206:e60bf67d9bf8 libavformat
The reader ignores the size of the ASF data object and keeps on
reading even beyond it.
Therefore if the ASF file includes an index object at its end, the
reader will treat the index like data, but of course will fail since
it thinks that the data is corrupted.
When reading an asf file with an index object, ffmpeg will
complain at the end of the file that it read an invalid header.
Patch by Kohn Emil Dan, < emild A cs P technion P ac P il >
Original thead:
Date: Apr 18, 2006 4:11 PM
Subject: [Ffmpeg-devel] Two ASF related bugs and fixes
author | gpoirier |
---|---|
date | Sat, 29 Jul 2006 16:07:19 +0000 |
parents | d18cc9a1fd02 |
children | 0899bfe4105c |
rev | line source |
---|---|
0 | 1 /* |
2 * FFM (ffserver live feed) encoder and decoder | |
3 * Copyright (c) 2001 Fabrice Bellard. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
887
diff
changeset
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 18 */ |
19 #include "avformat.h" | |
20 #include <unistd.h> | |
21 | |
22 /* The FFM file is made of blocks of fixed size */ | |
23 #define FFM_HEADER_SIZE 14 | |
24 #define PACKET_ID 0x666d | |
25 | |
26 /* each packet contains frames (which can span several packets */ | |
27 #define FRAME_HEADER_SIZE 8 | |
28 #define FLAG_KEY_FRAME 0x01 | |
29 | |
30 typedef struct FFMStream { | |
65 | 31 int64_t pts; |
0 | 32 } FFMStream; |
33 | |
34 enum { | |
35 READ_HEADER, | |
36 READ_DATA, | |
37 }; | |
38 | |
39 typedef struct FFMContext { | |
40 /* only reading mode */ | |
41 offset_t write_index, file_size; | |
42 int read_state; | |
65 | 43 uint8_t header[FRAME_HEADER_SIZE]; |
0 | 44 |
45 /* read and write */ | |
46 int first_packet; /* true if first packet, needed to set the discontinuity tag */ | |
901
c1a07d63a66d
pts fix by (Bryan Mayland / bmayland O leoninedev o com)
michael
parents:
896
diff
changeset
|
47 int first_frame_in_packet; /* true if first frame in packet, needed to know if PTS information is valid */ |
0 | 48 int packet_size; |
49 int frame_offset; | |
65 | 50 int64_t pts; |
51 uint8_t *packet_ptr, *packet_end; | |
52 uint8_t packet[FFM_PACKET_SIZE]; | |
0 | 53 } FFMContext; |
54 | |
318
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
55 static int64_t get_pts(AVFormatContext *s, offset_t pos); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
56 |
0 | 57 /* disable pts hack for testing */ |
58 int ffm_nopts = 0; | |
59 | |
858
66cc656ea404
Replace CONFIG_ENCODERS/CONFIG_DECODERS with CONFIG_MUXERS/CONFIG_DEMUXERS
diego
parents:
823
diff
changeset
|
60 #ifdef CONFIG_MUXERS |
0 | 61 static void flush_packet(AVFormatContext *s) |
62 { | |
63 FFMContext *ffm = s->priv_data; | |
64 int fill_size, h; | |
65 ByteIOContext *pb = &s->pb; | |
66 | |
67 fill_size = ffm->packet_end - ffm->packet_ptr; | |
68 memset(ffm->packet_ptr, 0, fill_size); | |
69 | |
885 | 70 if (url_ftell(pb) % ffm->packet_size) |
318
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
71 av_abort(); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
72 |
0 | 73 /* put header */ |
74 put_be16(pb, PACKET_ID); | |
75 put_be16(pb, fill_size); | |
76 put_be64(pb, ffm->pts); | |
77 h = ffm->frame_offset; | |
78 if (ffm->first_packet) | |
79 h |= 0x8000; | |
80 put_be16(pb, h); | |
81 put_buffer(pb, ffm->packet, ffm->packet_end - ffm->packet); | |
751
dcb459ca11eb
Flush the ffm packet to the wire (or file) whenever we flush the ffm packet.
philipjsg
parents:
744
diff
changeset
|
82 put_flush_packet(pb); |
0 | 83 |
84 /* prepare next packet */ | |
85 ffm->frame_offset = 0; /* no key frame */ | |
86 ffm->pts = 0; /* no pts */ | |
87 ffm->packet_ptr = ffm->packet; | |
88 ffm->first_packet = 0; | |
89 } | |
90 | |
91 /* 'first' is true if first data of a frame */ | |
92 static void ffm_write_data(AVFormatContext *s, | |
241 | 93 const uint8_t *buf, int size, |
65 | 94 int64_t pts, int first) |
0 | 95 { |
96 FFMContext *ffm = s->priv_data; | |
97 int len; | |
98 | |
99 if (first && ffm->frame_offset == 0) | |
100 ffm->frame_offset = ffm->packet_ptr - ffm->packet + FFM_HEADER_SIZE; | |
101 if (first && ffm->pts == 0) | |
102 ffm->pts = pts; | |
103 | |
104 /* write as many packets as needed */ | |
105 while (size > 0) { | |
106 len = ffm->packet_end - ffm->packet_ptr; | |
107 if (len > size) | |
108 len = size; | |
109 memcpy(ffm->packet_ptr, buf, len); | |
110 | |
111 ffm->packet_ptr += len; | |
112 buf += len; | |
113 size -= len; | |
114 if (ffm->packet_ptr >= ffm->packet_end) { | |
115 /* special case : no pts in packet : we leave the current one */ | |
116 if (ffm->pts == 0) | |
117 ffm->pts = pts; | |
118 | |
119 flush_packet(s); | |
120 } | |
121 } | |
122 } | |
123 | |
124 static int ffm_write_header(AVFormatContext *s) | |
125 { | |
126 FFMContext *ffm = s->priv_data; | |
127 AVStream *st; | |
128 FFMStream *fst; | |
129 ByteIOContext *pb = &s->pb; | |
130 AVCodecContext *codec; | |
131 int bit_rate, i; | |
132 | |
133 ffm->packet_size = FFM_PACKET_SIZE; | |
134 | |
135 /* header */ | |
862
aa0abab5e320
fix feed read_header, avoid using put_tag in write_header, to be consistent with read_header, also some minor cosmetics
alex
parents:
858
diff
changeset
|
136 put_le32(pb, MKTAG('F', 'F', 'M', '1')); |
0 | 137 put_be32(pb, ffm->packet_size); |
138 /* XXX: store write position in other file ? */ | |
139 put_be64(pb, ffm->packet_size); /* current write position */ | |
140 | |
141 put_be32(pb, s->nb_streams); | |
142 bit_rate = 0; | |
143 for(i=0;i<s->nb_streams;i++) { | |
144 st = s->streams[i]; | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
145 bit_rate += st->codec->bit_rate; |
0 | 146 } |
147 put_be32(pb, bit_rate); | |
148 | |
149 /* list of streams */ | |
150 for(i=0;i<s->nb_streams;i++) { | |
151 st = s->streams[i]; | |
152 fst = av_mallocz(sizeof(FFMStream)); | |
153 if (!fst) | |
154 goto fail; | |
502
813b0119a98e
ffserver fixes by (Koos Vriezen <koos.vriezen at xs4all dot nl>)
michael
parents:
468
diff
changeset
|
155 av_set_pts_info(st, 64, 1, 1000000); |
0 | 156 st->priv_data = fst; |
157 | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
158 codec = st->codec; |
0 | 159 /* generic info */ |
160 put_be32(pb, codec->codec_id); | |
161 put_byte(pb, codec->codec_type); | |
162 put_be32(pb, codec->bit_rate); | |
887 | 163 put_be32(pb, st->quality); |
0 | 164 put_be32(pb, codec->flags); |
744
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
165 put_be32(pb, codec->flags2); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
166 put_be32(pb, codec->debug); |
0 | 167 /* specific info */ |
168 switch(codec->codec_type) { | |
169 case CODEC_TYPE_VIDEO: | |
743 | 170 put_be32(pb, codec->time_base.num); |
171 put_be32(pb, codec->time_base.den); | |
0 | 172 put_be16(pb, codec->width); |
173 put_be16(pb, codec->height); | |
174 put_be16(pb, codec->gop_size); | |
744
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
175 put_be32(pb, codec->pix_fmt); |
0 | 176 put_byte(pb, codec->qmin); |
177 put_byte(pb, codec->qmax); | |
178 put_byte(pb, codec->max_qdiff); | |
179 put_be16(pb, (int) (codec->qcompress * 10000.0)); | |
180 put_be16(pb, (int) (codec->qblur * 10000.0)); | |
181 put_be32(pb, codec->bit_rate_tolerance); | |
182 put_strz(pb, codec->rc_eq); | |
183 put_be32(pb, codec->rc_max_rate); | |
184 put_be32(pb, codec->rc_min_rate); | |
185 put_be32(pb, codec->rc_buffer_size); | |
823 | 186 put_be64(pb, av_dbl2int(codec->i_quant_factor)); |
187 put_be64(pb, av_dbl2int(codec->b_quant_factor)); | |
188 put_be64(pb, av_dbl2int(codec->i_quant_offset)); | |
189 put_be64(pb, av_dbl2int(codec->b_quant_offset)); | |
0 | 190 put_be32(pb, codec->dct_algo); |
744
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
191 put_be32(pb, codec->strict_std_compliance); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
192 put_be32(pb, codec->max_b_frames); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
193 put_be32(pb, codec->luma_elim_threshold); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
194 put_be32(pb, codec->chroma_elim_threshold); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
195 put_be32(pb, codec->mpeg_quant); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
196 put_be32(pb, codec->intra_dc_precision); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
197 put_be32(pb, codec->me_method); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
198 put_be32(pb, codec->mb_decision); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
199 put_be32(pb, codec->nsse_weight); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
200 put_be32(pb, codec->frame_skip_cmp); |
823 | 201 put_be64(pb, av_dbl2int(codec->rc_buffer_aggressivity)); |
0 | 202 break; |
203 case CODEC_TYPE_AUDIO: | |
204 put_be32(pb, codec->sample_rate); | |
205 put_le16(pb, codec->channels); | |
206 put_le16(pb, codec->frame_size); | |
207 break; | |
208 default: | |
537 | 209 return -1; |
0 | 210 } |
211 /* hack to have real time */ | |
212 if (ffm_nopts) | |
213 fst->pts = 0; | |
214 else | |
215 fst->pts = av_gettime(); | |
216 } | |
217 | |
218 /* flush until end of block reached */ | |
219 while ((url_ftell(pb) % ffm->packet_size) != 0) | |
220 put_byte(pb, 0); | |
221 | |
222 put_flush_packet(pb); | |
223 | |
224 /* init packet mux */ | |
225 ffm->packet_ptr = ffm->packet; | |
226 ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE; | |
537 | 227 assert(ffm->packet_end >= ffm->packet); |
0 | 228 ffm->frame_offset = 0; |
229 ffm->pts = 0; | |
230 ffm->first_packet = 1; | |
231 | |
232 return 0; | |
233 fail: | |
234 for(i=0;i<s->nb_streams;i++) { | |
235 st = s->streams[i]; | |
236 av_freep(&st->priv_data); | |
237 } | |
238 return -1; | |
239 } | |
240 | |
468 | 241 static int ffm_write_packet(AVFormatContext *s, AVPacket *pkt) |
0 | 242 { |
468 | 243 AVStream *st = s->streams[pkt->stream_index]; |
0 | 244 FFMStream *fst = st->priv_data; |
65 | 245 int64_t pts; |
246 uint8_t header[FRAME_HEADER_SIZE]; | |
0 | 247 int duration; |
468 | 248 int size= pkt->size; |
0 | 249 |
468 | 250 //XXX/FIXME use duration from pkt |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
251 if (st->codec->codec_type == CODEC_TYPE_AUDIO) { |
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
252 duration = ((float)st->codec->frame_size / st->codec->sample_rate * 1000000.0); |
0 | 253 } else { |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
254 duration = (1000000.0 * st->codec->time_base.num / (float)st->codec->time_base.den); |
0 | 255 } |
256 | |
257 pts = fst->pts; | |
258 /* packet size & key_frame */ | |
468 | 259 header[0] = pkt->stream_index; |
0 | 260 header[1] = 0; |
468 | 261 if (pkt->flags & PKT_FLAG_KEY) |
0 | 262 header[1] |= FLAG_KEY_FRAME; |
263 header[2] = (size >> 16) & 0xff; | |
264 header[3] = (size >> 8) & 0xff; | |
265 header[4] = size & 0xff; | |
266 header[5] = (duration >> 16) & 0xff; | |
267 header[6] = (duration >> 8) & 0xff; | |
268 header[7] = duration & 0xff; | |
269 ffm_write_data(s, header, FRAME_HEADER_SIZE, pts, 1); | |
468 | 270 ffm_write_data(s, pkt->data, size, pts, 0); |
0 | 271 |
272 fst->pts += duration; | |
273 return 0; | |
274 } | |
275 | |
276 static int ffm_write_trailer(AVFormatContext *s) | |
277 { | |
278 ByteIOContext *pb = &s->pb; | |
279 FFMContext *ffm = s->priv_data; | |
280 | |
281 /* flush packets */ | |
282 if (ffm->packet_ptr > ffm->packet) | |
283 flush_packet(s); | |
284 | |
285 put_flush_packet(pb); | |
286 | |
287 if (!url_is_streamed(pb)) { | |
65 | 288 int64_t size; |
0 | 289 /* update the write offset */ |
290 size = url_ftell(pb); | |
291 url_fseek(pb, 8, SEEK_SET); | |
292 put_be64(pb, size); | |
293 put_flush_packet(pb); | |
294 } | |
295 | |
296 return 0; | |
297 } | |
858
66cc656ea404
Replace CONFIG_ENCODERS/CONFIG_DECODERS with CONFIG_MUXERS/CONFIG_DEMUXERS
diego
parents:
823
diff
changeset
|
298 #endif //CONFIG_MUXERS |
0 | 299 |
300 /* ffm demux */ | |
301 | |
302 static int ffm_is_avail_data(AVFormatContext *s, int size) | |
303 { | |
304 FFMContext *ffm = s->priv_data; | |
305 offset_t pos, avail_size; | |
306 int len; | |
307 | |
308 len = ffm->packet_end - ffm->packet_ptr; | |
309 if (!ffm_nopts) { | |
310 /* XXX: I don't understand this test, so I disabled it for testing */ | |
311 if (size <= len) | |
312 return 1; | |
313 } | |
314 pos = url_ftell(&s->pb); | |
315 if (pos == ffm->write_index) { | |
316 /* exactly at the end of stream */ | |
317 return 0; | |
318 } else if (pos < ffm->write_index) { | |
319 avail_size = ffm->write_index - pos; | |
320 } else { | |
321 avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE); | |
322 } | |
323 avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len; | |
324 if (size <= avail_size) | |
325 return 1; | |
326 else | |
327 return 0; | |
328 } | |
329 | |
330 /* first is true if we read the frame header */ | |
331 static int ffm_read_data(AVFormatContext *s, | |
65 | 332 uint8_t *buf, int size, int first) |
0 | 333 { |
334 FFMContext *ffm = s->priv_data; | |
335 ByteIOContext *pb = &s->pb; | |
336 int len, fill_size, size1, frame_offset; | |
337 | |
338 size1 = size; | |
339 while (size > 0) { | |
340 redo: | |
341 len = ffm->packet_end - ffm->packet_ptr; | |
342 if (len > size) | |
343 len = size; | |
344 if (len == 0) { | |
345 if (url_ftell(pb) == ffm->file_size) | |
346 url_fseek(pb, ffm->packet_size, SEEK_SET); | |
347 retry_read: | |
348 get_be16(pb); /* PACKET_ID */ | |
349 fill_size = get_be16(pb); | |
350 ffm->pts = get_be64(pb); | |
901
c1a07d63a66d
pts fix by (Bryan Mayland / bmayland O leoninedev o com)
michael
parents:
896
diff
changeset
|
351 ffm->first_frame_in_packet = 1; |
0 | 352 frame_offset = get_be16(pb); |
353 get_buffer(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE); | |
354 ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size); | |
318
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
355 if (ffm->packet_end < ffm->packet) |
537 | 356 return -1; |
0 | 357 /* if first packet or resynchronization packet, we must |
358 handle it specifically */ | |
359 if (ffm->first_packet || (frame_offset & 0x8000)) { | |
360 if (!frame_offset) { | |
361 /* This packet has no frame headers in it */ | |
362 if (url_ftell(pb) >= ffm->packet_size * 3) { | |
363 url_fseek(pb, -ffm->packet_size * 2, SEEK_CUR); | |
364 goto retry_read; | |
365 } | |
366 /* This is bad, we cannot find a valid frame header */ | |
367 return 0; | |
368 } | |
369 ffm->first_packet = 0; | |
370 if ((frame_offset & 0x7ffff) < FFM_HEADER_SIZE) | |
537 | 371 return -1; |
0 | 372 ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE; |
373 if (!first) | |
374 break; | |
375 } else { | |
376 ffm->packet_ptr = ffm->packet; | |
377 } | |
378 goto redo; | |
379 } | |
380 memcpy(buf, ffm->packet_ptr, len); | |
381 buf += len; | |
382 ffm->packet_ptr += len; | |
383 size -= len; | |
384 first = 0; | |
385 } | |
386 return size1 - size; | |
387 } | |
388 | |
389 | |
318
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
390 static void adjust_write_index(AVFormatContext *s) |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
391 { |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
392 FFMContext *ffm = s->priv_data; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
393 ByteIOContext *pb = &s->pb; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
394 int64_t pts; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
395 //offset_t orig_write_index = ffm->write_index; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
396 offset_t pos_min, pos_max; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
397 int64_t pts_start; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
398 offset_t ptr = url_ftell(pb); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
399 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
400 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
401 pos_min = 0; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
402 pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
403 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
404 pts_start = get_pts(s, pos_min); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
405 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
406 pts = get_pts(s, pos_max); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
407 |
885 | 408 if (pts - 100000 > pts_start) |
390
3a40642dc4df
adjust_write_index() fix by ("Curi Fabio Eduardo (SFL)" <curif at TELEFONICA dot COM dot AR>)
michael
parents:
318
diff
changeset
|
409 goto end; |
318
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
410 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
411 ffm->write_index = FFM_PACKET_SIZE; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
412 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
413 pts_start = get_pts(s, pos_min); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
414 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
415 pts = get_pts(s, pos_max); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
416 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
417 if (pts - 100000 <= pts_start) { |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
418 while (1) { |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
419 offset_t newpos; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
420 int64_t newpts; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
421 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
422 newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
423 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
424 if (newpos == pos_min) |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
425 break; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
426 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
427 newpts = get_pts(s, newpos); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
428 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
429 if (newpts - 100000 <= pts) { |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
430 pos_max = newpos; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
431 pts = newpts; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
432 } else { |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
433 pos_min = newpos; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
434 } |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
435 } |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
436 ffm->write_index += pos_max; |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
437 } |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
438 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
439 //printf("Adjusted write index from %lld to %lld: pts=%0.6f\n", orig_write_index, ffm->write_index, pts / 1000000.); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
440 //printf("pts range %0.6f - %0.6f\n", get_pts(s, 0) / 1000000. , get_pts(s, ffm->file_size - 2 * FFM_PACKET_SIZE) / 1000000. ); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
441 |
390
3a40642dc4df
adjust_write_index() fix by ("Curi Fabio Eduardo (SFL)" <curif at TELEFONICA dot COM dot AR>)
michael
parents:
318
diff
changeset
|
442 end: |
318
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
443 url_fseek(pb, ptr, SEEK_SET); |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
444 } |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
445 |
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
446 |
0 | 447 static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap) |
448 { | |
449 FFMContext *ffm = s->priv_data; | |
450 AVStream *st; | |
451 FFMStream *fst; | |
452 ByteIOContext *pb = &s->pb; | |
453 AVCodecContext *codec; | |
187 | 454 int i, nb_streams; |
65 | 455 uint32_t tag; |
0 | 456 |
457 /* header */ | |
458 tag = get_le32(pb); | |
459 if (tag != MKTAG('F', 'F', 'M', '1')) | |
460 goto fail; | |
461 ffm->packet_size = get_be32(pb); | |
462 if (ffm->packet_size != FFM_PACKET_SIZE) | |
463 goto fail; | |
464 ffm->write_index = get_be64(pb); | |
465 /* get also filesize */ | |
466 if (!url_is_streamed(pb)) { | |
764
cdb845a57ae4
drop most url_fileno() calls (allows to use ByteIOContext directly in caller apps instead of URLProtocol)
aurel
parents:
751
diff
changeset
|
467 ffm->file_size = url_fsize(pb); |
318
54e915169d48
Add more resilience in reading ffm files. In particular, don't assume
philipjsg
parents:
277
diff
changeset
|
468 adjust_write_index(s); |
0 | 469 } else { |
65 | 470 ffm->file_size = (uint64_t_C(1) << 63) - 1; |
0 | 471 } |
472 | |
187 | 473 nb_streams = get_be32(pb); |
0 | 474 get_be32(pb); /* total bitrate */ |
475 /* read each stream */ | |
187 | 476 for(i=0;i<nb_streams;i++) { |
0 | 477 char rc_eq_buf[128]; |
478 | |
187 | 479 st = av_new_stream(s, 0); |
0 | 480 if (!st) |
481 goto fail; | |
482 fst = av_mallocz(sizeof(FFMStream)); | |
483 if (!fst) | |
484 goto fail; | |
862
aa0abab5e320
fix feed read_header, avoid using put_tag in write_header, to be consistent with read_header, also some minor cosmetics
alex
parents:
858
diff
changeset
|
485 s->streams[i] = st; |
885 | 486 |
468 | 487 av_set_pts_info(st, 64, 1, 1000000); |
885 | 488 |
0 | 489 st->priv_data = fst; |
490 | |
820
feca73904e67
changing AVCodecContext codec -> *codec in AVStream so additions to AVCodecContext dont randomize AVStream and break binary compatibility
michael
parents:
775
diff
changeset
|
491 codec = st->codec; |
0 | 492 /* generic info */ |
862
aa0abab5e320
fix feed read_header, avoid using put_tag in write_header, to be consistent with read_header, also some minor cosmetics
alex
parents:
858
diff
changeset
|
493 codec->codec_id = get_be32(pb); |
aa0abab5e320
fix feed read_header, avoid using put_tag in write_header, to be consistent with read_header, also some minor cosmetics
alex
parents:
858
diff
changeset
|
494 codec->codec_type = get_byte(pb); /* codec_type */ |
0 | 495 codec->bit_rate = get_be32(pb); |
862
aa0abab5e320
fix feed read_header, avoid using put_tag in write_header, to be consistent with read_header, also some minor cosmetics
alex
parents:
858
diff
changeset
|
496 st->quality = get_be32(pb); |
0 | 497 codec->flags = get_be32(pb); |
744
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
498 codec->flags2 = get_be32(pb); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
499 codec->debug = get_be32(pb); |
0 | 500 /* specific info */ |
501 switch(codec->codec_type) { | |
502 case CODEC_TYPE_VIDEO: | |
743 | 503 codec->time_base.num = get_be32(pb); |
504 codec->time_base.den = get_be32(pb); | |
0 | 505 codec->width = get_be16(pb); |
506 codec->height = get_be16(pb); | |
507 codec->gop_size = get_be16(pb); | |
744
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
508 codec->pix_fmt = get_be32(pb); |
0 | 509 codec->qmin = get_byte(pb); |
510 codec->qmax = get_byte(pb); | |
511 codec->max_qdiff = get_byte(pb); | |
512 codec->qcompress = get_be16(pb) / 10000.0; | |
513 codec->qblur = get_be16(pb) / 10000.0; | |
514 codec->bit_rate_tolerance = get_be32(pb); | |
34 | 515 codec->rc_eq = av_strdup(get_strz(pb, rc_eq_buf, sizeof(rc_eq_buf))); |
0 | 516 codec->rc_max_rate = get_be32(pb); |
517 codec->rc_min_rate = get_be32(pb); | |
518 codec->rc_buffer_size = get_be32(pb); | |
823 | 519 codec->i_quant_factor = av_int2dbl(get_be64(pb)); |
520 codec->b_quant_factor = av_int2dbl(get_be64(pb)); | |
521 codec->i_quant_offset = av_int2dbl(get_be64(pb)); | |
522 codec->b_quant_offset = av_int2dbl(get_be64(pb)); | |
0 | 523 codec->dct_algo = get_be32(pb); |
744
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
524 codec->strict_std_compliance = get_be32(pb); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
525 codec->max_b_frames = get_be32(pb); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
526 codec->luma_elim_threshold = get_be32(pb); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
527 codec->chroma_elim_threshold = get_be32(pb); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
528 codec->mpeg_quant = get_be32(pb); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
529 codec->intra_dc_precision = get_be32(pb); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
530 codec->me_method = get_be32(pb); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
531 codec->mb_decision = get_be32(pb); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
532 codec->nsse_weight = get_be32(pb); |
da5b3b9e898e
Add in many fields that have been added to the Codec structure. This means
philipjsg
parents:
743
diff
changeset
|
533 codec->frame_skip_cmp = get_be32(pb); |
823 | 534 codec->rc_buffer_aggressivity = av_int2dbl(get_be64(pb)); |
0 | 535 break; |
536 case CODEC_TYPE_AUDIO: | |
537 codec->sample_rate = get_be32(pb); | |
538 codec->channels = get_le16(pb); | |
539 codec->frame_size = get_le16(pb); | |
540 break; | |
541 default: | |
542 goto fail; | |
543 } | |
544 | |
545 } | |
546 | |
547 /* get until end of block reached */ | |
548 while ((url_ftell(pb) % ffm->packet_size) != 0) | |
549 get_byte(pb); | |
550 | |
551 /* init packet demux */ | |
552 ffm->packet_ptr = ffm->packet; | |
553 ffm->packet_end = ffm->packet; | |
554 ffm->frame_offset = 0; | |
555 ffm->pts = 0; | |
556 ffm->read_state = READ_HEADER; | |
557 ffm->first_packet = 1; | |
558 return 0; | |
559 fail: | |
560 for(i=0;i<s->nb_streams;i++) { | |
561 st = s->streams[i]; | |
562 if (st) { | |
563 av_freep(&st->priv_data); | |
564 av_free(st); | |
565 } | |
566 } | |
567 return -1; | |
568 } | |
569 | |
570 /* return < 0 if eof */ | |
571 static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt) | |
572 { | |
573 int size; | |
574 FFMContext *ffm = s->priv_data; | |
575 int duration; | |
576 | |
577 switch(ffm->read_state) { | |
578 case READ_HEADER: | |
579 if (!ffm_is_avail_data(s, FRAME_HEADER_SIZE)) { | |
580 return -EAGAIN; | |
581 } | |
582 #if 0 | |
583 printf("pos=%08Lx spos=%Lx, write_index=%Lx size=%Lx\n", | |
584 url_ftell(&s->pb), s->pb.pos, ffm->write_index, ffm->file_size); | |
585 #endif | |
885 | 586 if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != |
0 | 587 FRAME_HEADER_SIZE) |
588 return -EAGAIN; | |
589 #if 0 | |
590 { | |
591 int i; | |
592 for(i=0;i<FRAME_HEADER_SIZE;i++) | |
593 printf("%02x ", ffm->header[i]); | |
594 printf("\n"); | |
595 } | |
596 #endif | |
597 ffm->read_state = READ_DATA; | |
598 /* fall thru */ | |
599 case READ_DATA: | |
600 size = (ffm->header[2] << 16) | (ffm->header[3] << 8) | ffm->header[4]; | |
601 if (!ffm_is_avail_data(s, size)) { | |
602 return -EAGAIN; | |
603 } | |
604 | |
605 duration = (ffm->header[5] << 16) | (ffm->header[6] << 8) | ffm->header[7]; | |
606 | |
607 av_new_packet(pkt, size); | |
608 pkt->stream_index = ffm->header[0]; | |
885 | 609 pkt->pos = url_ftell(&s->pb); |
0 | 610 if (ffm->header[1] & FLAG_KEY_FRAME) |
611 pkt->flags |= PKT_FLAG_KEY; | |
612 | |
613 ffm->read_state = READ_HEADER; | |
614 if (ffm_read_data(s, pkt->data, size, 0) != size) { | |
615 /* bad case: desynchronized packet. we cancel all the packet loading */ | |
616 av_free_packet(pkt); | |
617 return -EAGAIN; | |
618 } | |
901
c1a07d63a66d
pts fix by (Bryan Mayland / bmayland O leoninedev o com)
michael
parents:
896
diff
changeset
|
619 if (ffm->first_frame_in_packet) |
c1a07d63a66d
pts fix by (Bryan Mayland / bmayland O leoninedev o com)
michael
parents:
896
diff
changeset
|
620 { |
c1a07d63a66d
pts fix by (Bryan Mayland / bmayland O leoninedev o com)
michael
parents:
896
diff
changeset
|
621 pkt->pts = ffm->pts; |
c1a07d63a66d
pts fix by (Bryan Mayland / bmayland O leoninedev o com)
michael
parents:
896
diff
changeset
|
622 ffm->first_frame_in_packet = 0; |
c1a07d63a66d
pts fix by (Bryan Mayland / bmayland O leoninedev o com)
michael
parents:
896
diff
changeset
|
623 } |
0 | 624 pkt->duration = duration; |
625 break; | |
626 } | |
627 return 0; | |
628 } | |
629 | |
630 //#define DEBUG_SEEK | |
631 | |
632 /* pos is between 0 and file_size - FFM_PACKET_SIZE. It is translated | |
633 by the write position inside this function */ | |
634 static void ffm_seek1(AVFormatContext *s, offset_t pos1) | |
635 { | |
636 FFMContext *ffm = s->priv_data; | |
637 ByteIOContext *pb = &s->pb; | |
638 offset_t pos; | |
639 | |
640 pos = pos1 + ffm->write_index; | |
641 if (pos >= ffm->file_size) | |
642 pos -= (ffm->file_size - FFM_PACKET_SIZE); | |
643 #ifdef DEBUG_SEEK | |
644 printf("seek to %Lx -> %Lx\n", pos1, pos); | |
645 #endif | |
646 url_fseek(pb, pos, SEEK_SET); | |
647 } | |
648 | |
65 | 649 static int64_t get_pts(AVFormatContext *s, offset_t pos) |
0 | 650 { |
651 ByteIOContext *pb = &s->pb; | |
65 | 652 int64_t pts; |
0 | 653 |
654 ffm_seek1(s, pos); | |
655 url_fskip(pb, 4); | |
656 pts = get_be64(pb); | |
657 #ifdef DEBUG_SEEK | |
658 printf("pts=%0.6f\n", pts / 1000000.0); | |
659 #endif | |
660 return pts; | |
661 } | |
662 | |
663 /* seek to a given time in the file. The file read pointer is | |
664 positionned at or before pts. XXX: the following code is quite | |
665 approximative */ | |
558 | 666 static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags) |
0 | 667 { |
668 FFMContext *ffm = s->priv_data; | |
669 offset_t pos_min, pos_max, pos; | |
65 | 670 int64_t pts_min, pts_max, pts; |
0 | 671 double pos1; |
672 | |
673 #ifdef DEBUG_SEEK | |
674 printf("wanted_pts=%0.6f\n", wanted_pts / 1000000.0); | |
675 #endif | |
676 /* find the position using linear interpolation (better than | |
677 dichotomy in typical cases) */ | |
678 pos_min = 0; | |
679 pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE; | |
680 while (pos_min <= pos_max) { | |
681 pts_min = get_pts(s, pos_min); | |
682 pts_max = get_pts(s, pos_max); | |
683 /* linear interpolation */ | |
684 pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) / | |
685 (double)(pts_max - pts_min); | |
65 | 686 pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE; |
0 | 687 if (pos <= pos_min) |
688 pos = pos_min; | |
689 else if (pos >= pos_max) | |
690 pos = pos_max; | |
691 pts = get_pts(s, pos); | |
692 /* check if we are lucky */ | |
693 if (pts == wanted_pts) { | |
694 goto found; | |
695 } else if (pts > wanted_pts) { | |
696 pos_max = pos - FFM_PACKET_SIZE; | |
697 } else { | |
698 pos_min = pos + FFM_PACKET_SIZE; | |
699 } | |
700 } | |
558 | 701 pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; |
0 | 702 if (pos > 0) |
703 pos -= FFM_PACKET_SIZE; | |
704 found: | |
705 ffm_seek1(s, pos); | |
706 return 0; | |
707 } | |
708 | |
905
dbc0145bbf11
Add --disable-protocols option to configure to disable I/O protocol from
diego
parents:
901
diff
changeset
|
709 #ifdef CONFIG_FFSERVER |
0 | 710 offset_t ffm_read_write_index(int fd) |
711 { | |
65 | 712 uint8_t buf[8]; |
0 | 713 offset_t pos; |
714 int i; | |
715 | |
716 lseek(fd, 8, SEEK_SET); | |
717 read(fd, buf, 8); | |
718 pos = 0; | |
719 for(i=0;i<8;i++) | |
187 | 720 pos |= (int64_t)buf[i] << (56 - i * 8); |
0 | 721 return pos; |
722 } | |
723 | |
724 void ffm_write_write_index(int fd, offset_t pos) | |
725 { | |
65 | 726 uint8_t buf[8]; |
0 | 727 int i; |
728 | |
729 for(i=0;i<8;i++) | |
730 buf[i] = (pos >> (56 - i * 8)) & 0xff; | |
731 lseek(fd, 8, SEEK_SET); | |
732 write(fd, buf, 8); | |
733 } | |
734 | |
735 void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size) | |
736 { | |
737 FFMContext *ffm = s->priv_data; | |
738 ffm->write_index = pos; | |
739 ffm->file_size = file_size; | |
740 } | |
905
dbc0145bbf11
Add --disable-protocols option to configure to disable I/O protocol from
diego
parents:
901
diff
changeset
|
741 #endif // CONFIG_FFSERVER |
0 | 742 |
743 static int ffm_read_close(AVFormatContext *s) | |
744 { | |
745 AVStream *st; | |
746 int i; | |
747 | |
748 for(i=0;i<s->nb_streams;i++) { | |
749 st = s->streams[i]; | |
750 av_freep(&st->priv_data); | |
751 } | |
752 return 0; | |
753 } | |
754 | |
755 static int ffm_probe(AVProbeData *p) | |
756 { | |
757 if (p->buf_size >= 4 && | |
885 | 758 p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' && |
0 | 759 p->buf[3] == '1') |
760 return AVPROBE_SCORE_MAX + 1; | |
761 return 0; | |
762 } | |
763 | |
1169 | 764 #ifdef CONFIG_FFM_DEMUXER |
765 AVInputFormat ffm_demuxer = { | |
0 | 766 "ffm", |
767 "ffm format", | |
768 sizeof(FFMContext), | |
769 ffm_probe, | |
770 ffm_read_header, | |
771 ffm_read_packet, | |
772 ffm_read_close, | |
773 ffm_seek, | |
774 }; | |
1169 | 775 #endif |
776 #ifdef CONFIG_FFM_MUXER | |
777 AVOutputFormat ffm_muxer = { | |
0 | 778 "ffm", |
779 "ffm format", | |
780 "", | |
781 "ffm", | |
782 sizeof(FFMContext), | |
783 /* not really used */ | |
784 CODEC_ID_MP2, | |
785 CODEC_ID_MPEG1VIDEO, | |
786 ffm_write_header, | |
787 ffm_write_packet, | |
788 ffm_write_trailer, | |
789 }; | |
1169 | 790 #endif //CONFIG_FFM_MUXER |