Added codec id for QCELP.
[FFMpeg-mirror/ordered_chapters.git] / libavformat / swf.c
blob67a63308d4943e7c55849cbe624e825143256b58
1 /*
2 * Flash Compatible Streaming Format
3 * Copyright (c) 2000 Fabrice Bellard.
4 * Copyright (c) 2003 Tinic Uro.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "avformat.h"
21 #include "bitstream.h"
23 /* should have a generic way to indicate probable size */
24 #define DUMMY_FILE_SIZE (100 * 1024 * 1024)
25 #define DUMMY_DURATION 600 /* in seconds */
27 #define TAG_END 0
28 #define TAG_SHOWFRAME 1
29 #define TAG_DEFINESHAPE 2
30 #define TAG_FREECHARACTER 3
31 #define TAG_PLACEOBJECT 4
32 #define TAG_REMOVEOBJECT 5
33 #define TAG_STREAMHEAD 18
34 #define TAG_STREAMBLOCK 19
35 #define TAG_JPEG2 21
36 #define TAG_PLACEOBJECT2 26
37 #define TAG_STREAMHEAD2 45
38 #define TAG_VIDEOSTREAM 60
39 #define TAG_VIDEOFRAME 61
41 #define TAG_LONG 0x100
43 /* flags for shape definition */
44 #define FLAG_MOVETO 0x01
45 #define FLAG_SETFILL0 0x02
46 #define FLAG_SETFILL1 0x04
48 #define SWF_VIDEO_CODEC_FLV1 0x02
50 #define AUDIO_FIFO_SIZE 65536
52 /* character id used */
53 #define BITMAP_ID 0
54 #define VIDEO_ID 0
55 #define SHAPE_ID 1
57 #undef NDEBUG
58 #include <assert.h>
60 typedef struct {
62 offset_t duration_pos;
63 offset_t tag_pos;
65 int samples_per_frame;
66 int sound_samples;
67 int video_samples;
68 int swf_frame_number;
69 int video_frame_number;
70 int ms_per_frame;
71 int ch_id;
72 int tag;
74 uint8_t *audio_fifo;
75 int audio_in_pos;
76 int audio_out_pos;
77 int audio_size;
79 int video_type;
80 int audio_type;
81 } SWFContext;
83 static const int sSampleRates[3][4] = {
84 {44100, 48000, 32000, 0},
85 {22050, 24000, 16000, 0},
86 {11025, 12000, 8000, 0},
89 static const int sBitRates[2][3][15] = {
90 { { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448},
91 { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384},
92 { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320}
94 { { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256},
95 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160},
96 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}
100 static const int sSamplesPerFrame[3][3] =
102 { 384, 1152, 1152 },
103 { 384, 1152, 576 },
104 { 384, 1152, 576 }
107 static const int sBitsPerSlot[3] = {
113 static int swf_mp3_info(void *data, int *byteSize, int *samplesPerFrame, int *sampleRate, int *isMono )
115 uint8_t *dataTmp = (uint8_t *)data;
116 uint32_t header = ( (uint32_t)dataTmp[0] << 24 ) | ( (uint32_t)dataTmp[1] << 16 ) | ( (uint32_t)dataTmp[2] << 8 ) | (uint32_t)dataTmp[3];
117 int layerID = 3 - ((header >> 17) & 0x03);
118 int bitRateID = ((header >> 12) & 0x0f);
119 int sampleRateID = ((header >> 10) & 0x03);
120 int bitRate = 0;
121 int bitsPerSlot = sBitsPerSlot[layerID];
122 int isPadded = ((header >> 9) & 0x01);
124 if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) {
125 return 0;
128 *isMono = ((header >> 6) & 0x03) == 0x03;
130 if ( (header >> 19 ) & 0x01 ) {
131 *sampleRate = sSampleRates[0][sampleRateID];
132 bitRate = sBitRates[0][layerID][bitRateID] * 1000;
133 *samplesPerFrame = sSamplesPerFrame[0][layerID];
134 } else {
135 if ( (header >> 20) & 0x01 ) {
136 *sampleRate = sSampleRates[1][sampleRateID];
137 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
138 *samplesPerFrame = sSamplesPerFrame[1][layerID];
139 } else {
140 *sampleRate = sSampleRates[2][sampleRateID];
141 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
142 *samplesPerFrame = sSamplesPerFrame[2][layerID];
146 *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) );
148 return 1;
151 #ifdef CONFIG_MUXERS
152 static void put_swf_tag(AVFormatContext *s, int tag)
154 SWFContext *swf = s->priv_data;
155 ByteIOContext *pb = &s->pb;
157 swf->tag_pos = url_ftell(pb);
158 swf->tag = tag;
159 /* reserve some room for the tag */
160 if (tag & TAG_LONG) {
161 put_le16(pb, 0);
162 put_le32(pb, 0);
163 } else {
164 put_le16(pb, 0);
168 static void put_swf_end_tag(AVFormatContext *s)
170 SWFContext *swf = s->priv_data;
171 ByteIOContext *pb = &s->pb;
172 offset_t pos;
173 int tag_len, tag;
175 pos = url_ftell(pb);
176 tag_len = pos - swf->tag_pos - 2;
177 tag = swf->tag;
178 url_fseek(pb, swf->tag_pos, SEEK_SET);
179 if (tag & TAG_LONG) {
180 tag &= ~TAG_LONG;
181 put_le16(pb, (tag << 6) | 0x3f);
182 put_le32(pb, tag_len - 4);
183 } else {
184 assert(tag_len < 0x3f);
185 put_le16(pb, (tag << 6) | tag_len);
187 url_fseek(pb, pos, SEEK_SET);
190 static inline void max_nbits(int *nbits_ptr, int val)
192 int n;
194 if (val == 0)
195 return;
196 val = abs(val);
197 n = 1;
198 while (val != 0) {
199 n++;
200 val >>= 1;
202 if (n > *nbits_ptr)
203 *nbits_ptr = n;
206 static void put_swf_rect(ByteIOContext *pb,
207 int xmin, int xmax, int ymin, int ymax)
209 PutBitContext p;
210 uint8_t buf[256];
211 int nbits, mask;
213 init_put_bits(&p, buf, sizeof(buf));
215 nbits = 0;
216 max_nbits(&nbits, xmin);
217 max_nbits(&nbits, xmax);
218 max_nbits(&nbits, ymin);
219 max_nbits(&nbits, ymax);
220 mask = (1 << nbits) - 1;
222 /* rectangle info */
223 put_bits(&p, 5, nbits);
224 put_bits(&p, nbits, xmin & mask);
225 put_bits(&p, nbits, xmax & mask);
226 put_bits(&p, nbits, ymin & mask);
227 put_bits(&p, nbits, ymax & mask);
229 flush_put_bits(&p);
230 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
233 static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
235 int nbits, mask;
237 put_bits(pb, 1, 1); /* edge */
238 put_bits(pb, 1, 1); /* line select */
239 nbits = 2;
240 max_nbits(&nbits, dx);
241 max_nbits(&nbits, dy);
243 mask = (1 << nbits) - 1;
244 put_bits(pb, 4, nbits - 2); /* 16 bits precision */
245 if (dx == 0) {
246 put_bits(pb, 1, 0);
247 put_bits(pb, 1, 1);
248 put_bits(pb, nbits, dy & mask);
249 } else if (dy == 0) {
250 put_bits(pb, 1, 0);
251 put_bits(pb, 1, 0);
252 put_bits(pb, nbits, dx & mask);
253 } else {
254 put_bits(pb, 1, 1);
255 put_bits(pb, nbits, dx & mask);
256 put_bits(pb, nbits, dy & mask);
260 #define FRAC_BITS 16
262 /* put matrix */
263 static void put_swf_matrix(ByteIOContext *pb,
264 int a, int b, int c, int d, int tx, int ty)
266 PutBitContext p;
267 uint8_t buf[256];
268 int nbits;
270 init_put_bits(&p, buf, sizeof(buf));
272 put_bits(&p, 1, 1); /* a, d present */
273 nbits = 1;
274 max_nbits(&nbits, a);
275 max_nbits(&nbits, d);
276 put_bits(&p, 5, nbits); /* nb bits */
277 put_bits(&p, nbits, a);
278 put_bits(&p, nbits, d);
280 put_bits(&p, 1, 1); /* b, c present */
281 nbits = 1;
282 max_nbits(&nbits, c);
283 max_nbits(&nbits, b);
284 put_bits(&p, 5, nbits); /* nb bits */
285 put_bits(&p, nbits, c);
286 put_bits(&p, nbits, b);
288 nbits = 1;
289 max_nbits(&nbits, tx);
290 max_nbits(&nbits, ty);
291 put_bits(&p, 5, nbits); /* nb bits */
292 put_bits(&p, nbits, tx);
293 put_bits(&p, nbits, ty);
295 flush_put_bits(&p);
296 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
299 /* */
300 static int swf_write_header(AVFormatContext *s)
302 SWFContext *swf;
303 ByteIOContext *pb = &s->pb;
304 AVCodecContext *enc, *audio_enc, *video_enc;
305 PutBitContext p;
306 uint8_t buf1[256];
307 int i, width, height, rate, rate_base;
309 swf = av_malloc(sizeof(SWFContext));
310 if (!swf)
311 return -1;
312 s->priv_data = swf;
314 swf->ch_id = -1;
315 swf->audio_in_pos = 0;
316 swf->audio_out_pos = 0;
317 swf->audio_size = 0;
318 swf->audio_fifo = av_malloc(AUDIO_FIFO_SIZE);
319 swf->sound_samples = 0;
320 swf->video_samples = 0;
321 swf->swf_frame_number = 0;
322 swf->video_frame_number = 0;
324 video_enc = NULL;
325 audio_enc = NULL;
326 for(i=0;i<s->nb_streams;i++) {
327 enc = s->streams[i]->codec;
328 if (enc->codec_type == CODEC_TYPE_AUDIO)
329 audio_enc = enc;
330 else {
331 if ( enc->codec_id == CODEC_ID_FLV1 || enc->codec_id == CODEC_ID_MJPEG ) {
332 video_enc = enc;
333 } else {
334 av_log(enc, AV_LOG_ERROR, "SWF only supports FLV1 and MJPEG\n");
335 return -1;
340 if (!video_enc) {
341 /* currenty, cannot work correctly if audio only */
342 swf->video_type = 0;
343 width = 320;
344 height = 200;
345 rate = 10;
346 rate_base= 1;
347 } else {
348 swf->video_type = video_enc->codec_id;
349 width = video_enc->width;
350 height = video_enc->height;
351 rate = video_enc->time_base.den;
352 rate_base = video_enc->time_base.num;
355 if (!audio_enc ) {
356 swf->audio_type = 0;
357 swf->samples_per_frame = ( 44100. * rate_base ) / rate;
358 } else {
359 swf->audio_type = audio_enc->codec_id;
360 swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate;
363 put_tag(pb, "FWS");
364 if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {
365 put_byte(pb, 6); /* version (version 6 and above support FLV1 codec) */
366 } else {
367 put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */
369 put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
370 (will be patched if not streamed) */
372 put_swf_rect(pb, 0, width * 20, 0, height * 20);
373 put_le16(pb, (rate * 256) / rate_base); /* frame rate */
374 swf->duration_pos = url_ftell(pb);
375 put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */
377 /* define a shape with the jpeg inside */
378 if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {
379 } else if ( video_enc && video_enc->codec_id == CODEC_ID_MJPEG ) {
380 put_swf_tag(s, TAG_DEFINESHAPE);
382 put_le16(pb, SHAPE_ID); /* ID of shape */
383 /* bounding rectangle */
384 put_swf_rect(pb, 0, width, 0, height);
385 /* style info */
386 put_byte(pb, 1); /* one fill style */
387 put_byte(pb, 0x41); /* clipped bitmap fill */
388 put_le16(pb, BITMAP_ID); /* bitmap ID */
389 /* position of the bitmap */
390 put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
391 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
392 put_byte(pb, 0); /* no line style */
394 /* shape drawing */
395 init_put_bits(&p, buf1, sizeof(buf1));
396 put_bits(&p, 4, 1); /* one fill bit */
397 put_bits(&p, 4, 0); /* zero line bit */
399 put_bits(&p, 1, 0); /* not an edge */
400 put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
401 put_bits(&p, 5, 1); /* nbits */
402 put_bits(&p, 1, 0); /* X */
403 put_bits(&p, 1, 0); /* Y */
404 put_bits(&p, 1, 1); /* set fill style 1 */
406 /* draw the rectangle ! */
407 put_swf_line_edge(&p, width, 0);
408 put_swf_line_edge(&p, 0, height);
409 put_swf_line_edge(&p, -width, 0);
410 put_swf_line_edge(&p, 0, -height);
412 /* end of shape */
413 put_bits(&p, 1, 0); /* not an edge */
414 put_bits(&p, 5, 0);
416 flush_put_bits(&p);
417 put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
419 put_swf_end_tag(s);
422 if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) {
423 int v;
425 /* start sound */
426 put_swf_tag(s, TAG_STREAMHEAD2);
428 v = 0;
429 switch(audio_enc->sample_rate) {
430 case 11025:
431 v |= 1 << 2;
432 break;
433 case 22050:
434 v |= 2 << 2;
435 break;
436 case 44100:
437 v |= 3 << 2;
438 break;
439 default:
440 /* not supported */
441 av_free(swf->audio_fifo);
442 av_free(swf);
443 return -1;
445 v |= 0x02; /* 16 bit playback */
446 if (audio_enc->channels == 2)
447 v |= 0x01; /* stereo playback */
448 put_byte(&s->pb, v);
449 v |= 0x20; /* mp3 compressed */
450 put_byte(&s->pb, v);
451 put_le16(&s->pb, swf->samples_per_frame); /* avg samples per frame */
452 put_le16(&s->pb, 0);
454 put_swf_end_tag(s);
457 put_flush_packet(&s->pb);
458 return 0;
461 static int swf_write_video(AVFormatContext *s,
462 AVCodecContext *enc, const uint8_t *buf, int size)
464 SWFContext *swf = s->priv_data;
465 ByteIOContext *pb = &s->pb;
466 int c = 0;
467 int outSize = 0;
468 int outSamples = 0;
470 /* Flash Player limit */
471 if ( swf->swf_frame_number == 16000 ) {
472 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
475 if ( swf->audio_type ) {
476 /* Prescan audio data for this swf frame */
477 retry_swf_audio_packet:
478 if ( ( swf->audio_size-outSize ) >= 4 ) {
479 int mp3FrameSize = 0;
480 int mp3SampleRate = 0;
481 int mp3IsMono = 0;
482 int mp3SamplesPerFrame = 0;
484 /* copy out mp3 header from ring buffer */
485 uint8_t header[4];
486 for (c=0; c<4; c++) {
487 header[c] = swf->audio_fifo[(swf->audio_in_pos+outSize+c) % AUDIO_FIFO_SIZE];
490 if ( swf_mp3_info(header,&mp3FrameSize,&mp3SamplesPerFrame,&mp3SampleRate,&mp3IsMono) ) {
491 if ( ( swf->audio_size-outSize ) >= mp3FrameSize ) {
492 outSize += mp3FrameSize;
493 outSamples += mp3SamplesPerFrame;
494 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
495 goto retry_swf_audio_packet;
498 } else {
499 /* invalid mp3 data, skip forward
500 we need to do this since the Flash Player
501 does not like custom headers */
502 swf->audio_in_pos ++;
503 swf->audio_size --;
504 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
505 goto retry_swf_audio_packet;
509 /* audio stream is behind video stream, bail */
510 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
511 return 0;
515 if ( swf->video_type == CODEC_ID_FLV1 ) {
516 if ( swf->video_frame_number == 0 ) {
517 /* create a new video object */
518 put_swf_tag(s, TAG_VIDEOSTREAM);
519 put_le16(pb, VIDEO_ID);
520 put_le16(pb, 15000 ); /* hard flash player limit */
521 put_le16(pb, enc->width);
522 put_le16(pb, enc->height);
523 put_byte(pb, 0);
524 put_byte(pb, SWF_VIDEO_CODEC_FLV1);
525 put_swf_end_tag(s);
527 /* place the video object for the first time */
528 put_swf_tag(s, TAG_PLACEOBJECT2);
529 put_byte(pb, 0x36);
530 put_le16(pb, 1);
531 put_le16(pb, VIDEO_ID);
532 put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
533 put_le16(pb, swf->video_frame_number );
534 put_byte(pb, 'v');
535 put_byte(pb, 'i');
536 put_byte(pb, 'd');
537 put_byte(pb, 'e');
538 put_byte(pb, 'o');
539 put_byte(pb, 0x00);
540 put_swf_end_tag(s);
541 } else {
542 /* mark the character for update */
543 put_swf_tag(s, TAG_PLACEOBJECT2);
544 put_byte(pb, 0x11);
545 put_le16(pb, 1);
546 put_le16(pb, swf->video_frame_number );
547 put_swf_end_tag(s);
550 /* set video frame data */
551 put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);
552 put_le16(pb, VIDEO_ID);
553 put_le16(pb, swf->video_frame_number++ );
554 put_buffer(pb, buf, size);
555 put_swf_end_tag(s);
556 } else if ( swf->video_type == CODEC_ID_MJPEG ) {
557 if (swf->swf_frame_number > 0) {
558 /* remove the shape */
559 put_swf_tag(s, TAG_REMOVEOBJECT);
560 put_le16(pb, SHAPE_ID); /* shape ID */
561 put_le16(pb, 1); /* depth */
562 put_swf_end_tag(s);
564 /* free the bitmap */
565 put_swf_tag(s, TAG_FREECHARACTER);
566 put_le16(pb, BITMAP_ID);
567 put_swf_end_tag(s);
570 put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
572 put_le16(pb, BITMAP_ID); /* ID of the image */
574 /* a dummy jpeg header seems to be required */
575 put_byte(pb, 0xff);
576 put_byte(pb, 0xd8);
577 put_byte(pb, 0xff);
578 put_byte(pb, 0xd9);
579 /* write the jpeg image */
580 put_buffer(pb, buf, size);
582 put_swf_end_tag(s);
584 /* draw the shape */
586 put_swf_tag(s, TAG_PLACEOBJECT);
587 put_le16(pb, SHAPE_ID); /* shape ID */
588 put_le16(pb, 1); /* depth */
589 put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0);
590 put_swf_end_tag(s);
591 } else {
592 /* invalid codec */
595 swf->swf_frame_number ++;
597 swf->video_samples += swf->samples_per_frame;
599 /* streaming sound always should be placed just before showframe tags */
600 if ( outSize > 0 ) {
601 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
602 put_le16(pb, outSamples);
603 put_le16(pb, 0);
604 for (c=0; c<outSize; c++) {
605 put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]);
607 put_swf_end_tag(s);
609 /* update FIFO */
610 swf->sound_samples += outSamples;
611 swf->audio_in_pos += outSize;
612 swf->audio_size -= outSize;
613 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
616 /* output the frame */
617 put_swf_tag(s, TAG_SHOWFRAME);
618 put_swf_end_tag(s);
620 put_flush_packet(&s->pb);
622 return 0;
625 static int swf_write_audio(AVFormatContext *s,
626 AVCodecContext *enc, const uint8_t *buf, int size)
628 SWFContext *swf = s->priv_data;
629 int c = 0;
631 /* Flash Player limit */
632 if ( swf->swf_frame_number == 16000 ) {
633 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
636 if (enc->codec_id == CODEC_ID_MP3 ) {
637 for (c=0; c<size; c++) {
638 swf->audio_fifo[(swf->audio_out_pos+c)%AUDIO_FIFO_SIZE] = buf[c];
640 swf->audio_size += size;
641 swf->audio_out_pos += size;
642 swf->audio_out_pos %= AUDIO_FIFO_SIZE;
645 /* if audio only stream make sure we add swf frames */
646 if ( swf->video_type == 0 ) {
647 swf_write_video(s, enc, 0, 0);
650 return 0;
653 static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)
655 AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
656 if (codec->codec_type == CODEC_TYPE_AUDIO)
657 return swf_write_audio(s, codec, pkt->data, pkt->size);
658 else
659 return swf_write_video(s, codec, pkt->data, pkt->size);
662 static int swf_write_trailer(AVFormatContext *s)
664 SWFContext *swf = s->priv_data;
665 ByteIOContext *pb = &s->pb;
666 AVCodecContext *enc, *video_enc;
667 int file_size, i;
669 video_enc = NULL;
670 for(i=0;i<s->nb_streams;i++) {
671 enc = s->streams[i]->codec;
672 if (enc->codec_type == CODEC_TYPE_VIDEO)
673 video_enc = enc;
676 put_swf_tag(s, TAG_END);
677 put_swf_end_tag(s);
679 put_flush_packet(&s->pb);
681 /* patch file size and number of frames if not streamed */
682 if (!url_is_streamed(&s->pb) && video_enc) {
683 file_size = url_ftell(pb);
684 url_fseek(pb, 4, SEEK_SET);
685 put_le32(pb, file_size);
686 url_fseek(pb, swf->duration_pos, SEEK_SET);
687 put_le16(pb, video_enc->frame_number);
690 av_free(swf->audio_fifo);
692 return 0;
694 #endif //CONFIG_MUXERS
696 /*********************************************/
697 /* Extract FLV encoded frame and MP3 from swf
698 Note that the detection of the real frame
699 is inaccurate at this point as it can be
700 quite tricky to determine, you almost certainly
701 will get a bad audio/video sync */
703 static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
705 int tag, len;
707 if (url_feof(pb))
708 return -1;
710 tag = get_le16(pb);
711 len = tag & 0x3f;
712 tag = tag >> 6;
713 if (len == 0x3f) {
714 len = get_le32(pb);
716 // av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
717 *len_ptr = len;
718 return tag;
722 static int swf_probe(AVProbeData *p)
724 /* check file header */
725 if (p->buf_size <= 16)
726 return 0;
727 if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
728 p->buf[2] == 'S')
729 return AVPROBE_SCORE_MAX;
730 else
731 return 0;
734 static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
736 SWFContext *swf = 0;
737 ByteIOContext *pb = &s->pb;
738 int nbits, len, frame_rate, tag, v;
739 offset_t firstTagOff;
740 AVStream *ast = 0;
741 AVStream *vst = 0;
743 swf = av_malloc(sizeof(SWFContext));
744 if (!swf)
745 return -1;
746 s->priv_data = swf;
748 tag = get_be32(pb) & 0xffffff00;
750 if (tag == MKBETAG('C', 'W', 'S', 0))
752 av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
753 return AVERROR_IO;
755 if (tag != MKBETAG('F', 'W', 'S', 0))
756 return AVERROR_IO;
757 get_le32(pb);
758 /* skip rectangle size */
759 nbits = get_byte(pb) >> 3;
760 len = (4 * nbits - 3 + 7) / 8;
761 url_fskip(pb, len);
762 frame_rate = get_le16(pb);
763 get_le16(pb); /* frame count */
765 /* The Flash Player converts 8.8 frame rates
766 to milliseconds internally. Do the same to get
767 a correct framerate */
768 swf->ms_per_frame = ( 1000 * 256 ) / frame_rate;
769 swf->samples_per_frame = 0;
770 swf->ch_id = -1;
772 firstTagOff = url_ftell(pb);
773 for(;;) {
774 tag = get_swf_tag(pb, &len);
775 if (tag < 0) {
776 if ( ast || vst ) {
777 if ( vst && ast ) {
778 vst->codec->time_base.den = ast->codec->sample_rate / swf->samples_per_frame;
779 vst->codec->time_base.num = 1;
781 break;
783 av_log(s, AV_LOG_ERROR, "No media found in SWF\n");
784 return AVERROR_IO;
786 if ( tag == TAG_VIDEOSTREAM && !vst) {
787 swf->ch_id = get_le16(pb);
788 get_le16(pb);
789 get_le16(pb);
790 get_le16(pb);
791 get_byte(pb);
792 /* Check for FLV1 */
793 if ( get_byte(pb) == SWF_VIDEO_CODEC_FLV1 ) {
794 vst = av_new_stream(s, 0);
795 av_set_pts_info(vst, 24, 1, 1000); /* 24 bit pts in ms */
797 vst->codec->codec_type = CODEC_TYPE_VIDEO;
798 vst->codec->codec_id = CODEC_ID_FLV1;
799 if ( swf->samples_per_frame ) {
800 vst->codec->time_base.den = 1000. / swf->ms_per_frame;
801 vst->codec->time_base.num = 1;
804 } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) {
805 /* streaming found */
806 get_byte(pb);
807 v = get_byte(pb);
808 swf->samples_per_frame = get_le16(pb);
809 if (len!=4)
810 url_fskip(pb,len-4);
811 /* if mp3 streaming found, OK */
812 if ((v & 0x20) != 0) {
813 if ( tag == TAG_STREAMHEAD2 ) {
814 get_le16(pb);
816 ast = av_new_stream(s, 1);
817 av_set_pts_info(ast, 24, 1, 1000); /* 24 bit pts in ms */
818 if (!ast)
819 return -ENOMEM;
821 if (v & 0x01)
822 ast->codec->channels = 2;
823 else
824 ast->codec->channels = 1;
826 switch((v>> 2) & 0x03) {
827 case 1:
828 ast->codec->sample_rate = 11025;
829 break;
830 case 2:
831 ast->codec->sample_rate = 22050;
832 break;
833 case 3:
834 ast->codec->sample_rate = 44100;
835 break;
836 default:
837 av_free(ast);
838 return AVERROR_IO;
840 ast->codec->codec_type = CODEC_TYPE_AUDIO;
841 ast->codec->codec_id = CODEC_ID_MP3;
843 } else {
844 url_fskip(pb, len);
847 url_fseek(pb, firstTagOff, SEEK_SET);
849 return 0;
852 static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
854 SWFContext *swf = s->priv_data;
855 ByteIOContext *pb = &s->pb;
856 AVStream *st = 0;
857 int tag, len, i, frame;
859 for(;;) {
860 tag = get_swf_tag(pb, &len);
861 if (tag < 0)
862 return AVERROR_IO;
863 if (tag == TAG_VIDEOFRAME) {
864 for( i=0; i<s->nb_streams; i++ ) {
865 st = s->streams[i];
866 if (st->id == 0) {
867 if ( get_le16(pb) == swf->ch_id ) {
868 frame = get_le16(pb);
869 av_get_packet(pb, pkt, len-4);
870 pkt->pts = frame * swf->ms_per_frame;
871 pkt->stream_index = st->index;
872 return pkt->size;
873 } else {
874 url_fskip(pb, len-2);
875 continue;
879 url_fskip(pb, len);
880 } else if (tag == TAG_STREAMBLOCK) {
881 for( i=0; i<s->nb_streams; i++ ) {
882 st = s->streams[i];
883 if (st->id == 1) {
884 av_get_packet(pb, pkt, len);
885 pkt->stream_index = st->index;
886 return pkt->size;
889 url_fskip(pb, len);
890 } else {
891 url_fskip(pb, len);
894 return 0;
897 static int swf_read_close(AVFormatContext *s)
899 return 0;
902 #ifdef CONFIG_SWF_DEMUXER
903 AVInputFormat swf_demuxer = {
904 "swf",
905 "Flash format",
906 sizeof(SWFContext),
907 swf_probe,
908 swf_read_header,
909 swf_read_packet,
910 swf_read_close,
912 #endif
913 #ifdef CONFIG_SWF_MUXER
914 AVOutputFormat swf_muxer = {
915 "swf",
916 "Flash format",
917 "application/x-shockwave-flash",
918 "swf",
919 sizeof(SWFContext),
920 CODEC_ID_MP3,
921 CODEC_ID_FLV1,
922 swf_write_header,
923 swf_write_packet,
924 swf_write_trailer,
926 #endif