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
|
---|
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
---|
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 {
|
---|
31 | int64_t pts;
|
---|
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;
|
---|
43 | uint8_t header[FRAME_HEADER_SIZE];
|
---|
44 |
|
---|
45 | /* read and write */
|
---|
46 | int first_packet; /* true if first packet, needed to set the discontinuity tag */
|
---|
47 | int first_frame_in_packet; /* true if first frame in packet, needed to know if PTS information is valid */
|
---|
48 | int packet_size;
|
---|
49 | int frame_offset;
|
---|
50 | int64_t pts;
|
---|
51 | uint8_t *packet_ptr, *packet_end;
|
---|
52 | uint8_t packet[FFM_PACKET_SIZE];
|
---|
53 | } FFMContext;
|
---|
54 |
|
---|
55 | static int64_t get_pts(AVFormatContext *s, offset_t pos);
|
---|
56 |
|
---|
57 | /* disable pts hack for testing */
|
---|
58 | int ffm_nopts = 0;
|
---|
59 |
|
---|
60 | #ifdef CONFIG_MUXERS
|
---|
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 |
|
---|
70 | if (url_ftell(pb) % ffm->packet_size)
|
---|
71 | av_abort();
|
---|
72 |
|
---|
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);
|
---|
82 | put_flush_packet(pb);
|
---|
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,
|
---|
93 | const uint8_t *buf, int size,
|
---|
94 | int64_t pts, int first)
|
---|
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 */
|
---|
136 | put_le32(pb, MKTAG('F', 'F', 'M', '1'));
|
---|
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];
|
---|
145 | bit_rate += st->codec->bit_rate;
|
---|
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;
|
---|
155 | av_set_pts_info(st, 64, 1, 1000000);
|
---|
156 | st->priv_data = fst;
|
---|
157 |
|
---|
158 | codec = st->codec;
|
---|
159 | /* generic info */
|
---|
160 | put_be32(pb, codec->codec_id);
|
---|
161 | put_byte(pb, codec->codec_type);
|
---|
162 | put_be32(pb, codec->bit_rate);
|
---|
163 | put_be32(pb, st->quality);
|
---|
164 | put_be32(pb, codec->flags);
|
---|
165 | put_be32(pb, codec->flags2);
|
---|
166 | put_be32(pb, codec->debug);
|
---|
167 | /* specific info */
|
---|
168 | switch(codec->codec_type) {
|
---|
169 | case CODEC_TYPE_VIDEO:
|
---|
170 | put_be32(pb, codec->time_base.num);
|
---|
171 | put_be32(pb, codec->time_base.den);
|
---|
172 | put_be16(pb, codec->width);
|
---|
173 | put_be16(pb, codec->height);
|
---|
174 | put_be16(pb, codec->gop_size);
|
---|
175 | put_be32(pb, codec->pix_fmt);
|
---|
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);
|
---|
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));
|
---|
190 | put_be32(pb, codec->dct_algo);
|
---|
191 | put_be32(pb, codec->strict_std_compliance);
|
---|
192 | put_be32(pb, codec->max_b_frames);
|
---|
193 | put_be32(pb, codec->luma_elim_threshold);
|
---|
194 | put_be32(pb, codec->chroma_elim_threshold);
|
---|
195 | put_be32(pb, codec->mpeg_quant);
|
---|
196 | put_be32(pb, codec->intra_dc_precision);
|
---|
197 | put_be32(pb, codec->me_method);
|
---|
198 | put_be32(pb, codec->mb_decision);
|
---|
199 | put_be32(pb, codec->nsse_weight);
|
---|
200 | put_be32(pb, codec->frame_skip_cmp);
|
---|
201 | put_be64(pb, av_dbl2int(codec->rc_buffer_aggressivity));
|
---|
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:
|
---|
209 | return -1;
|
---|
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;
|
---|
227 | assert(ffm->packet_end >= ffm->packet);
|
---|
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 |
|
---|
241 | static int ffm_write_packet(AVFormatContext *s, AVPacket *pkt)
|
---|
242 | {
|
---|
243 | AVStream *st = s->streams[pkt->stream_index];
|
---|
244 | FFMStream *fst = st->priv_data;
|
---|
245 | int64_t pts;
|
---|
246 | uint8_t header[FRAME_HEADER_SIZE];
|
---|
247 | int duration;
|
---|
248 | int size= pkt->size;
|
---|
249 |
|
---|
250 | //XXX/FIXME use duration from pkt
|
---|
251 | if (st->codec->codec_type == CODEC_TYPE_AUDIO) {
|
---|
252 | duration = ((float)st->codec->frame_size / st->codec->sample_rate * 1000000.0);
|
---|
253 | } else {
|
---|
254 | duration = (1000000.0 * st->codec->time_base.num / (float)st->codec->time_base.den);
|
---|
255 | }
|
---|
256 |
|
---|
257 | pts = fst->pts;
|
---|
258 | /* packet size & key_frame */
|
---|
259 | header[0] = pkt->stream_index;
|
---|
260 | header[1] = 0;
|
---|
261 | if (pkt->flags & PKT_FLAG_KEY)
|
---|
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);
|
---|
270 | ffm_write_data(s, pkt->data, size, pts, 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)) {
|
---|
288 | int64_t size;
|
---|
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 | }
|
---|
298 | #endif //CONFIG_MUXERS
|
---|
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,
|
---|
332 | uint8_t *buf, int size, int first)
|
---|
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);
|
---|
351 | ffm->first_frame_in_packet = 1;
|
---|
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);
|
---|
355 | if (ffm->packet_end < ffm->packet)
|
---|
356 | return -1;
|
---|
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)
|
---|
371 | return -1;
|
---|
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 |
|
---|
390 | static void adjust_write_index(AVFormatContext *s)
|
---|
391 | {
|
---|
392 | FFMContext *ffm = s->priv_data;
|
---|
393 | ByteIOContext *pb = &s->pb;
|
---|
394 | int64_t pts;
|
---|
395 | //offset_t orig_write_index = ffm->write_index;
|
---|
396 | offset_t pos_min, pos_max;
|
---|
397 | int64_t pts_start;
|
---|
398 | offset_t ptr = url_ftell(pb);
|
---|
399 |
|
---|
400 |
|
---|
401 | pos_min = 0;
|
---|
402 | pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
|
---|
403 |
|
---|
404 | pts_start = get_pts(s, pos_min);
|
---|
405 |
|
---|
406 | pts = get_pts(s, pos_max);
|
---|
407 |
|
---|
408 | if (pts - 100000 > pts_start)
|
---|
409 | goto end;
|
---|
410 |
|
---|
411 | ffm->write_index = FFM_PACKET_SIZE;
|
---|
412 |
|
---|
413 | pts_start = get_pts(s, pos_min);
|
---|
414 |
|
---|
415 | pts = get_pts(s, pos_max);
|
---|
416 |
|
---|
417 | if (pts - 100000 <= pts_start) {
|
---|
418 | while (1) {
|
---|
419 | offset_t newpos;
|
---|
420 | int64_t newpts;
|
---|
421 |
|
---|
422 | newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE;
|
---|
423 |
|
---|
424 | if (newpos == pos_min)
|
---|
425 | break;
|
---|
426 |
|
---|
427 | newpts = get_pts(s, newpos);
|
---|
428 |
|
---|
429 | if (newpts - 100000 <= pts) {
|
---|
430 | pos_max = newpos;
|
---|
431 | pts = newpts;
|
---|
432 | } else {
|
---|
433 | pos_min = newpos;
|
---|
434 | }
|
---|
435 | }
|
---|
436 | ffm->write_index += pos_max;
|
---|
437 | }
|
---|
438 |
|
---|
439 | //printf("Adjusted write index from %lld to %lld: pts=%0.6f\n", orig_write_index, ffm->write_index, pts / 1000000.);
|
---|
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. );
|
---|
441 |
|
---|
442 | end:
|
---|
443 | url_fseek(pb, ptr, SEEK_SET);
|
---|
444 | }
|
---|
445 |
|
---|
446 |
|
---|
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;
|
---|
454 | int i, nb_streams;
|
---|
455 | uint32_t tag;
|
---|
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)) {
|
---|
467 | ffm->file_size = url_fsize(pb);
|
---|
468 | adjust_write_index(s);
|
---|
469 | } else {
|
---|
470 | ffm->file_size = (uint64_t_C(1) << 63) - 1;
|
---|
471 | }
|
---|
472 |
|
---|
473 | nb_streams = get_be32(pb);
|
---|
474 | get_be32(pb); /* total bitrate */
|
---|
475 | /* read each stream */
|
---|
476 | for(i=0;i<nb_streams;i++) {
|
---|
477 | char rc_eq_buf[128];
|
---|
478 |
|
---|
479 | st = av_new_stream(s, 0);
|
---|
480 | if (!st)
|
---|
481 | goto fail;
|
---|
482 | fst = av_mallocz(sizeof(FFMStream));
|
---|
483 | if (!fst)
|
---|
484 | goto fail;
|
---|
485 | s->streams[i] = st;
|
---|
486 |
|
---|
487 | av_set_pts_info(st, 64, 1, 1000000);
|
---|
488 |
|
---|
489 | st->priv_data = fst;
|
---|
490 |
|
---|
491 | codec = st->codec;
|
---|
492 | /* generic info */
|
---|
493 | codec->codec_id = get_be32(pb);
|
---|
494 | codec->codec_type = get_byte(pb); /* codec_type */
|
---|
495 | codec->bit_rate = get_be32(pb);
|
---|
496 | st->quality = get_be32(pb);
|
---|
497 | codec->flags = get_be32(pb);
|
---|
498 | codec->flags2 = get_be32(pb);
|
---|
499 | codec->debug = get_be32(pb);
|
---|
500 | /* specific info */
|
---|
501 | switch(codec->codec_type) {
|
---|
502 | case CODEC_TYPE_VIDEO:
|
---|
503 | codec->time_base.num = get_be32(pb);
|
---|
504 | codec->time_base.den = get_be32(pb);
|
---|
505 | codec->width = get_be16(pb);
|
---|
506 | codec->height = get_be16(pb);
|
---|
507 | codec->gop_size = get_be16(pb);
|
---|
508 | codec->pix_fmt = get_be32(pb);
|
---|
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);
|
---|
515 | codec->rc_eq = av_strdup(get_strz(pb, rc_eq_buf, sizeof(rc_eq_buf)));
|
---|
516 | codec->rc_max_rate = get_be32(pb);
|
---|
517 | codec->rc_min_rate = get_be32(pb);
|
---|
518 | codec->rc_buffer_size = get_be32(pb);
|
---|
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));
|
---|
523 | codec->dct_algo = get_be32(pb);
|
---|
524 | codec->strict_std_compliance = get_be32(pb);
|
---|
525 | codec->max_b_frames = get_be32(pb);
|
---|
526 | codec->luma_elim_threshold = get_be32(pb);
|
---|
527 | codec->chroma_elim_threshold = get_be32(pb);
|
---|
528 | codec->mpeg_quant = get_be32(pb);
|
---|
529 | codec->intra_dc_precision = get_be32(pb);
|
---|
530 | codec->me_method = get_be32(pb);
|
---|
531 | codec->mb_decision = get_be32(pb);
|
---|
532 | codec->nsse_weight = get_be32(pb);
|
---|
533 | codec->frame_skip_cmp = get_be32(pb);
|
---|
534 | codec->rc_buffer_aggressivity = av_int2dbl(get_be64(pb));
|
---|
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
|
---|
586 | if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) !=
|
---|
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];
|
---|
609 | pkt->pos = url_ftell(&s->pb);
|
---|
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 | }
|
---|
619 | if (ffm->first_frame_in_packet)
|
---|
620 | {
|
---|
621 | pkt->pts = ffm->pts;
|
---|
622 | ffm->first_frame_in_packet = 0;
|
---|
623 | }
|
---|
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 |
|
---|
649 | static int64_t get_pts(AVFormatContext *s, offset_t pos)
|
---|
650 | {
|
---|
651 | ByteIOContext *pb = &s->pb;
|
---|
652 | int64_t pts;
|
---|
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 */
|
---|
666 | static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags)
|
---|
667 | {
|
---|
668 | FFMContext *ffm = s->priv_data;
|
---|
669 | offset_t pos_min, pos_max, pos;
|
---|
670 | int64_t pts_min, pts_max, pts;
|
---|
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);
|
---|
686 | pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
|
---|
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 | }
|
---|
701 | pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
|
---|
702 | if (pos > 0)
|
---|
703 | pos -= FFM_PACKET_SIZE;
|
---|
704 | found:
|
---|
705 | ffm_seek1(s, pos);
|
---|
706 | return 0;
|
---|
707 | }
|
---|
708 |
|
---|
709 | #ifdef CONFIG_FFSERVER
|
---|
710 | offset_t ffm_read_write_index(int fd)
|
---|
711 | {
|
---|
712 | uint8_t buf[8];
|
---|
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++)
|
---|
720 | pos |= (int64_t)buf[i] << (56 - i * 8);
|
---|
721 | return pos;
|
---|
722 | }
|
---|
723 |
|
---|
724 | void ffm_write_write_index(int fd, offset_t pos)
|
---|
725 | {
|
---|
726 | uint8_t buf[8];
|
---|
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 | }
|
---|
741 | #endif // CONFIG_FFSERVER
|
---|
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 &&
|
---|
758 | p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' &&
|
---|
759 | p->buf[3] == '1')
|
---|
760 | return AVPROBE_SCORE_MAX + 1;
|
---|
761 | return 0;
|
---|
762 | }
|
---|
763 |
|
---|
764 | static AVInputFormat ffm_demuxer = {
|
---|
765 | "ffm",
|
---|
766 | "ffm format",
|
---|
767 | sizeof(FFMContext),
|
---|
768 | ffm_probe,
|
---|
769 | ffm_read_header,
|
---|
770 | ffm_read_packet,
|
---|
771 | ffm_read_close,
|
---|
772 | ffm_seek,
|
---|
773 | };
|
---|
774 |
|
---|
775 | #ifdef CONFIG_MUXERS
|
---|
776 | static AVOutputFormat ffm_muxer = {
|
---|
777 | "ffm",
|
---|
778 | "ffm format",
|
---|
779 | "",
|
---|
780 | "ffm",
|
---|
781 | sizeof(FFMContext),
|
---|
782 | /* not really used */
|
---|
783 | CODEC_ID_MP2,
|
---|
784 | CODEC_ID_MPEG1VIDEO,
|
---|
785 | ffm_write_header,
|
---|
786 | ffm_write_packet,
|
---|
787 | ffm_write_trailer,
|
---|
788 | };
|
---|
789 | #endif //CONFIG_MUXERS
|
---|
790 |
|
---|
791 | int ffm_init(void)
|
---|
792 | {
|
---|
793 | av_register_input_format(&ffm_demuxer);
|
---|
794 | #ifdef CONFIG_MUXERS
|
---|
795 | av_register_output_format(&ffm_muxer);
|
---|
796 | #endif //CONFIG_MUXERS
|
---|
797 | return 0;
|
---|
798 | }
|
---|