Remove debug line.
[FFMpeg-mirror/ordered_chapters.git] / libavformat / swf.c
blob3195f8c58a0e8a967fb5df7b01501c5b7d085a4a
1 /*
2 * Flash Compatible Streaming Format
3 * Copyright (c) 2000 Fabrice Bellard.
4 * Copyright (c) 2003 Tinic Uro.
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "avformat.h"
23 #include "bitstream.h"
24 #include "riff.h" /* for CodecTag */
26 /* should have a generic way to indicate probable size */
27 #define DUMMY_FILE_SIZE (100 * 1024 * 1024)
28 #define DUMMY_DURATION 600 /* in seconds */
30 #define TAG_END 0
31 #define TAG_SHOWFRAME 1
32 #define TAG_DEFINESHAPE 2
33 #define TAG_FREECHARACTER 3
34 #define TAG_PLACEOBJECT 4
35 #define TAG_REMOVEOBJECT 5
36 #define TAG_STREAMHEAD 18
37 #define TAG_STREAMBLOCK 19
38 #define TAG_JPEG2 21
39 #define TAG_PLACEOBJECT2 26
40 #define TAG_STREAMHEAD2 45
41 #define TAG_VIDEOSTREAM 60
42 #define TAG_VIDEOFRAME 61
44 #define TAG_LONG 0x100
46 /* flags for shape definition */
47 #define FLAG_MOVETO 0x01
48 #define FLAG_SETFILL0 0x02
49 #define FLAG_SETFILL1 0x04
51 #define AUDIO_FIFO_SIZE 65536
53 /* character id used */
54 #define BITMAP_ID 0
55 #define VIDEO_ID 0
56 #define SHAPE_ID 1
58 #undef NDEBUG
59 #include <assert.h>
61 typedef struct {
62 int audio_stream_index;
63 offset_t duration_pos;
64 offset_t tag_pos;
66 int samples_per_frame;
67 int sound_samples;
68 int video_samples;
69 int swf_frame_number;
70 int video_frame_number;
71 int ms_per_frame;
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 AVCodecTag swf_codec_tags[] = {
84 {CODEC_ID_FLV1, 0x02},
85 {CODEC_ID_VP6F, 0x04},
86 {0, 0},
89 static const int sSampleRates[3][4] = {
90 {44100, 48000, 32000, 0},
91 {22050, 24000, 16000, 0},
92 {11025, 12000, 8000, 0},
95 static const int sBitRates[2][3][15] = {
96 { { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448},
97 { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384},
98 { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320}
100 { { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256},
101 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160},
102 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}
106 static const int sSamplesPerFrame[3][3] =
108 { 384, 1152, 1152 },
109 { 384, 1152, 576 },
110 { 384, 1152, 576 }
113 static const int sBitsPerSlot[3] = {
119 static int swf_mp3_info(void *data, int *byteSize, int *samplesPerFrame, int *sampleRate, int *isMono )
121 uint8_t *dataTmp = (uint8_t *)data;
122 uint32_t header = ( (uint32_t)dataTmp[0] << 24 ) | ( (uint32_t)dataTmp[1] << 16 ) | ( (uint32_t)dataTmp[2] << 8 ) | (uint32_t)dataTmp[3];
123 int layerID = 3 - ((header >> 17) & 0x03);
124 int bitRateID = ((header >> 12) & 0x0f);
125 int sampleRateID = ((header >> 10) & 0x03);
126 int bitRate = 0;
127 int bitsPerSlot = sBitsPerSlot[layerID];
128 int isPadded = ((header >> 9) & 0x01);
130 if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) {
131 return 0;
134 *isMono = ((header >> 6) & 0x03) == 0x03;
136 if ( (header >> 19 ) & 0x01 ) {
137 *sampleRate = sSampleRates[0][sampleRateID];
138 bitRate = sBitRates[0][layerID][bitRateID] * 1000;
139 *samplesPerFrame = sSamplesPerFrame[0][layerID];
140 } else {
141 if ( (header >> 20) & 0x01 ) {
142 *sampleRate = sSampleRates[1][sampleRateID];
143 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
144 *samplesPerFrame = sSamplesPerFrame[1][layerID];
145 } else {
146 *sampleRate = sSampleRates[2][sampleRateID];
147 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
148 *samplesPerFrame = sSamplesPerFrame[2][layerID];
152 *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) );
154 return 1;
157 #ifdef CONFIG_MUXERS
158 static void put_swf_tag(AVFormatContext *s, int tag)
160 SWFContext *swf = s->priv_data;
161 ByteIOContext *pb = &s->pb;
163 swf->tag_pos = url_ftell(pb);
164 swf->tag = tag;
165 /* reserve some room for the tag */
166 if (tag & TAG_LONG) {
167 put_le16(pb, 0);
168 put_le32(pb, 0);
169 } else {
170 put_le16(pb, 0);
174 static void put_swf_end_tag(AVFormatContext *s)
176 SWFContext *swf = s->priv_data;
177 ByteIOContext *pb = &s->pb;
178 offset_t pos;
179 int tag_len, tag;
181 pos = url_ftell(pb);
182 tag_len = pos - swf->tag_pos - 2;
183 tag = swf->tag;
184 url_fseek(pb, swf->tag_pos, SEEK_SET);
185 if (tag & TAG_LONG) {
186 tag &= ~TAG_LONG;
187 put_le16(pb, (tag << 6) | 0x3f);
188 put_le32(pb, tag_len - 4);
189 } else {
190 assert(tag_len < 0x3f);
191 put_le16(pb, (tag << 6) | tag_len);
193 url_fseek(pb, pos, SEEK_SET);
196 static inline void max_nbits(int *nbits_ptr, int val)
198 int n;
200 if (val == 0)
201 return;
202 val = abs(val);
203 n = 1;
204 while (val != 0) {
205 n++;
206 val >>= 1;
208 if (n > *nbits_ptr)
209 *nbits_ptr = n;
212 static void put_swf_rect(ByteIOContext *pb,
213 int xmin, int xmax, int ymin, int ymax)
215 PutBitContext p;
216 uint8_t buf[256];
217 int nbits, mask;
219 init_put_bits(&p, buf, sizeof(buf));
221 nbits = 0;
222 max_nbits(&nbits, xmin);
223 max_nbits(&nbits, xmax);
224 max_nbits(&nbits, ymin);
225 max_nbits(&nbits, ymax);
226 mask = (1 << nbits) - 1;
228 /* rectangle info */
229 put_bits(&p, 5, nbits);
230 put_bits(&p, nbits, xmin & mask);
231 put_bits(&p, nbits, xmax & mask);
232 put_bits(&p, nbits, ymin & mask);
233 put_bits(&p, nbits, ymax & mask);
235 flush_put_bits(&p);
236 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
239 static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
241 int nbits, mask;
243 put_bits(pb, 1, 1); /* edge */
244 put_bits(pb, 1, 1); /* line select */
245 nbits = 2;
246 max_nbits(&nbits, dx);
247 max_nbits(&nbits, dy);
249 mask = (1 << nbits) - 1;
250 put_bits(pb, 4, nbits - 2); /* 16 bits precision */
251 if (dx == 0) {
252 put_bits(pb, 1, 0);
253 put_bits(pb, 1, 1);
254 put_bits(pb, nbits, dy & mask);
255 } else if (dy == 0) {
256 put_bits(pb, 1, 0);
257 put_bits(pb, 1, 0);
258 put_bits(pb, nbits, dx & mask);
259 } else {
260 put_bits(pb, 1, 1);
261 put_bits(pb, nbits, dx & mask);
262 put_bits(pb, nbits, dy & mask);
266 #define FRAC_BITS 16
268 /* put matrix */
269 static void put_swf_matrix(ByteIOContext *pb,
270 int a, int b, int c, int d, int tx, int ty)
272 PutBitContext p;
273 uint8_t buf[256];
274 int nbits;
276 init_put_bits(&p, buf, sizeof(buf));
278 put_bits(&p, 1, 1); /* a, d present */
279 nbits = 1;
280 max_nbits(&nbits, a);
281 max_nbits(&nbits, d);
282 put_bits(&p, 5, nbits); /* nb bits */
283 put_bits(&p, nbits, a);
284 put_bits(&p, nbits, d);
286 put_bits(&p, 1, 1); /* b, c present */
287 nbits = 1;
288 max_nbits(&nbits, c);
289 max_nbits(&nbits, b);
290 put_bits(&p, 5, nbits); /* nb bits */
291 put_bits(&p, nbits, c);
292 put_bits(&p, nbits, b);
294 nbits = 1;
295 max_nbits(&nbits, tx);
296 max_nbits(&nbits, ty);
297 put_bits(&p, 5, nbits); /* nb bits */
298 put_bits(&p, nbits, tx);
299 put_bits(&p, nbits, ty);
301 flush_put_bits(&p);
302 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
305 /* */
306 static int swf_write_header(AVFormatContext *s)
308 SWFContext *swf = s->priv_data;
309 ByteIOContext *pb = &s->pb;
310 AVCodecContext *enc, *audio_enc, *video_enc;
311 PutBitContext p;
312 uint8_t buf1[256];
313 int i, width, height, rate, rate_base;
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_VP6F ||
332 enc->codec_id == CODEC_ID_FLV1 ||
333 enc->codec_id == CODEC_ID_MJPEG ) {
334 video_enc = enc;
335 } else {
336 av_log(enc, AV_LOG_ERROR, "SWF only supports VP6, FLV1 and MJPEG\n");
337 return -1;
342 if (!video_enc) {
343 /* currenty, cannot work correctly if audio only */
344 swf->video_type = 0;
345 width = 320;
346 height = 200;
347 rate = 10;
348 rate_base= 1;
349 } else {
350 swf->video_type = video_enc->codec_id;
351 width = video_enc->width;
352 height = video_enc->height;
353 rate = video_enc->time_base.den;
354 rate_base = video_enc->time_base.num;
357 if (!audio_enc ) {
358 swf->audio_type = 0;
359 swf->samples_per_frame = ( 44100. * rate_base ) / rate;
360 } else {
361 swf->audio_type = audio_enc->codec_id;
362 swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate;
365 put_tag(pb, "FWS");
366 if ( video_enc && video_enc->codec_id == CODEC_ID_VP6F ) {
367 put_byte(pb, 8); /* version (version 8 and above support VP6 codec) */
368 } else if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {
369 put_byte(pb, 6); /* version (version 6 and above support FLV1 codec) */
370 } else {
371 put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */
373 put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
374 (will be patched if not streamed) */
376 put_swf_rect(pb, 0, width * 20, 0, height * 20);
377 put_le16(pb, (rate * 256) / rate_base); /* frame rate */
378 swf->duration_pos = url_ftell(pb);
379 put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */
381 /* define a shape with the jpeg inside */
382 if ( video_enc && (video_enc->codec_id == CODEC_ID_VP6F ||
383 video_enc->codec_id == CODEC_ID_FLV1 )) {
384 } else if ( video_enc && video_enc->codec_id == CODEC_ID_MJPEG ) {
385 put_swf_tag(s, TAG_DEFINESHAPE);
387 put_le16(pb, SHAPE_ID); /* ID of shape */
388 /* bounding rectangle */
389 put_swf_rect(pb, 0, width, 0, height);
390 /* style info */
391 put_byte(pb, 1); /* one fill style */
392 put_byte(pb, 0x41); /* clipped bitmap fill */
393 put_le16(pb, BITMAP_ID); /* bitmap ID */
394 /* position of the bitmap */
395 put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
396 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
397 put_byte(pb, 0); /* no line style */
399 /* shape drawing */
400 init_put_bits(&p, buf1, sizeof(buf1));
401 put_bits(&p, 4, 1); /* one fill bit */
402 put_bits(&p, 4, 0); /* zero line bit */
404 put_bits(&p, 1, 0); /* not an edge */
405 put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
406 put_bits(&p, 5, 1); /* nbits */
407 put_bits(&p, 1, 0); /* X */
408 put_bits(&p, 1, 0); /* Y */
409 put_bits(&p, 1, 1); /* set fill style 1 */
411 /* draw the rectangle ! */
412 put_swf_line_edge(&p, width, 0);
413 put_swf_line_edge(&p, 0, height);
414 put_swf_line_edge(&p, -width, 0);
415 put_swf_line_edge(&p, 0, -height);
417 /* end of shape */
418 put_bits(&p, 1, 0); /* not an edge */
419 put_bits(&p, 5, 0);
421 flush_put_bits(&p);
422 put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
424 put_swf_end_tag(s);
427 if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) {
428 int v;
430 /* start sound */
431 put_swf_tag(s, TAG_STREAMHEAD2);
433 v = 0;
434 switch(audio_enc->sample_rate) {
435 case 11025:
436 v |= 1 << 2;
437 break;
438 case 22050:
439 v |= 2 << 2;
440 break;
441 case 44100:
442 v |= 3 << 2;
443 break;
444 default:
445 /* not supported */
446 av_log(s, AV_LOG_ERROR, "swf doesnt support that sample rate, choose from (44100, 22050, 11025)\n");
447 av_free(swf->audio_fifo);
448 return -1;
450 v |= 0x02; /* 16 bit playback */
451 if (audio_enc->channels == 2)
452 v |= 0x01; /* stereo playback */
453 put_byte(&s->pb, v);
454 v |= 0x20; /* mp3 compressed */
455 put_byte(&s->pb, v);
456 put_le16(&s->pb, swf->samples_per_frame); /* avg samples per frame */
457 put_le16(&s->pb, 0);
459 put_swf_end_tag(s);
462 put_flush_packet(&s->pb);
463 return 0;
466 static int swf_write_video(AVFormatContext *s,
467 AVCodecContext *enc, const uint8_t *buf, int size)
469 SWFContext *swf = s->priv_data;
470 ByteIOContext *pb = &s->pb;
471 int c = 0;
472 int outSize = 0;
473 int outSamples = 0;
475 /* Flash Player limit */
476 if ( swf->swf_frame_number == 16000 ) {
477 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
480 if ( swf->audio_type ) {
481 /* Prescan audio data for this swf frame */
482 retry_swf_audio_packet:
483 if ( ( swf->audio_size-outSize ) >= 4 ) {
484 int mp3FrameSize = 0;
485 int mp3SampleRate = 0;
486 int mp3IsMono = 0;
487 int mp3SamplesPerFrame = 0;
489 /* copy out mp3 header from ring buffer */
490 uint8_t header[4];
491 for (c=0; c<4; c++) {
492 header[c] = swf->audio_fifo[(swf->audio_in_pos+outSize+c) % AUDIO_FIFO_SIZE];
495 if ( swf_mp3_info(header,&mp3FrameSize,&mp3SamplesPerFrame,&mp3SampleRate,&mp3IsMono) ) {
496 if ( ( swf->audio_size-outSize ) >= mp3FrameSize ) {
497 outSize += mp3FrameSize;
498 outSamples += mp3SamplesPerFrame;
499 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
500 goto retry_swf_audio_packet;
503 } else {
504 /* invalid mp3 data, skip forward
505 we need to do this since the Flash Player
506 does not like custom headers */
507 swf->audio_in_pos ++;
508 swf->audio_size --;
509 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
510 goto retry_swf_audio_packet;
514 /* audio stream is behind video stream, bail */
515 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
516 return 0;
520 if ( swf->video_type == CODEC_ID_VP6F ||
521 swf->video_type == CODEC_ID_FLV1 ) {
522 if ( swf->video_frame_number == 0 ) {
523 /* create a new video object */
524 put_swf_tag(s, TAG_VIDEOSTREAM);
525 put_le16(pb, VIDEO_ID);
526 put_le16(pb, 15000 ); /* hard flash player limit */
527 put_le16(pb, enc->width);
528 put_le16(pb, enc->height);
529 put_byte(pb, 0);
530 put_byte(pb,codec_get_tag(swf_codec_tags,swf->video_type));
531 put_swf_end_tag(s);
533 /* place the video object for the first time */
534 put_swf_tag(s, TAG_PLACEOBJECT2);
535 put_byte(pb, 0x36);
536 put_le16(pb, 1);
537 put_le16(pb, VIDEO_ID);
538 put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
539 put_le16(pb, swf->video_frame_number );
540 put_byte(pb, 'v');
541 put_byte(pb, 'i');
542 put_byte(pb, 'd');
543 put_byte(pb, 'e');
544 put_byte(pb, 'o');
545 put_byte(pb, 0x00);
546 put_swf_end_tag(s);
547 } else {
548 /* mark the character for update */
549 put_swf_tag(s, TAG_PLACEOBJECT2);
550 put_byte(pb, 0x11);
551 put_le16(pb, 1);
552 put_le16(pb, swf->video_frame_number );
553 put_swf_end_tag(s);
556 /* set video frame data */
557 put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);
558 put_le16(pb, VIDEO_ID);
559 put_le16(pb, swf->video_frame_number++ );
560 put_buffer(pb, buf, size);
561 put_swf_end_tag(s);
562 } else if ( swf->video_type == CODEC_ID_MJPEG ) {
563 if (swf->swf_frame_number > 0) {
564 /* remove the shape */
565 put_swf_tag(s, TAG_REMOVEOBJECT);
566 put_le16(pb, SHAPE_ID); /* shape ID */
567 put_le16(pb, 1); /* depth */
568 put_swf_end_tag(s);
570 /* free the bitmap */
571 put_swf_tag(s, TAG_FREECHARACTER);
572 put_le16(pb, BITMAP_ID);
573 put_swf_end_tag(s);
576 put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
578 put_le16(pb, BITMAP_ID); /* ID of the image */
580 /* a dummy jpeg header seems to be required */
581 put_byte(pb, 0xff);
582 put_byte(pb, 0xd8);
583 put_byte(pb, 0xff);
584 put_byte(pb, 0xd9);
585 /* write the jpeg image */
586 put_buffer(pb, buf, size);
588 put_swf_end_tag(s);
590 /* draw the shape */
592 put_swf_tag(s, TAG_PLACEOBJECT);
593 put_le16(pb, SHAPE_ID); /* shape ID */
594 put_le16(pb, 1); /* depth */
595 put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0);
596 put_swf_end_tag(s);
597 } else {
598 /* invalid codec */
601 swf->swf_frame_number ++;
603 swf->video_samples += swf->samples_per_frame;
605 /* streaming sound always should be placed just before showframe tags */
606 if ( outSize > 0 ) {
607 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
608 put_le16(pb, outSamples);
609 put_le16(pb, 0);
610 for (c=0; c<outSize; c++) {
611 put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]);
613 put_swf_end_tag(s);
615 /* update FIFO */
616 swf->sound_samples += outSamples;
617 swf->audio_in_pos += outSize;
618 swf->audio_size -= outSize;
619 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
622 /* output the frame */
623 put_swf_tag(s, TAG_SHOWFRAME);
624 put_swf_end_tag(s);
626 put_flush_packet(&s->pb);
628 return 0;
631 static int swf_write_audio(AVFormatContext *s,
632 AVCodecContext *enc, const uint8_t *buf, int size)
634 SWFContext *swf = s->priv_data;
635 int c = 0;
637 /* Flash Player limit */
638 if ( swf->swf_frame_number == 16000 ) {
639 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
642 if (enc->codec_id == CODEC_ID_MP3 ) {
643 for (c=0; c<size; c++) {
644 swf->audio_fifo[(swf->audio_out_pos+c)%AUDIO_FIFO_SIZE] = buf[c];
646 swf->audio_size += size;
647 swf->audio_out_pos += size;
648 swf->audio_out_pos %= AUDIO_FIFO_SIZE;
651 /* if audio only stream make sure we add swf frames */
652 if ( swf->video_type == 0 ) {
653 swf_write_video(s, enc, 0, 0);
656 return 0;
659 static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)
661 AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
662 if (codec->codec_type == CODEC_TYPE_AUDIO)
663 return swf_write_audio(s, codec, pkt->data, pkt->size);
664 else
665 return swf_write_video(s, codec, pkt->data, pkt->size);
668 static int swf_write_trailer(AVFormatContext *s)
670 SWFContext *swf = s->priv_data;
671 ByteIOContext *pb = &s->pb;
672 AVCodecContext *enc, *video_enc;
673 int file_size, i;
675 video_enc = NULL;
676 for(i=0;i<s->nb_streams;i++) {
677 enc = s->streams[i]->codec;
678 if (enc->codec_type == CODEC_TYPE_VIDEO)
679 video_enc = enc;
682 put_swf_tag(s, TAG_END);
683 put_swf_end_tag(s);
685 put_flush_packet(&s->pb);
687 /* patch file size and number of frames if not streamed */
688 if (!url_is_streamed(&s->pb) && video_enc) {
689 file_size = url_ftell(pb);
690 url_fseek(pb, 4, SEEK_SET);
691 put_le32(pb, file_size);
692 url_fseek(pb, swf->duration_pos, SEEK_SET);
693 put_le16(pb, video_enc->frame_number);
694 url_fseek(pb, file_size, SEEK_SET);
697 av_free(swf->audio_fifo);
699 return 0;
701 #endif //CONFIG_MUXERS
703 /*********************************************/
704 /* Extract FLV encoded frame and MP3 from swf
705 Note that the detection of the real frame
706 is inaccurate at this point as it can be
707 quite tricky to determine, you almost certainly
708 will get a bad audio/video sync */
710 static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
712 int tag, len;
714 if (url_feof(pb))
715 return -1;
717 tag = get_le16(pb);
718 len = tag & 0x3f;
719 tag = tag >> 6;
720 if (len == 0x3f) {
721 len = get_le32(pb);
723 // av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
724 *len_ptr = len;
725 return tag;
729 static int swf_probe(AVProbeData *p)
731 /* check file header */
732 if (p->buf_size <= 16)
733 return 0;
734 if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
735 p->buf[2] == 'S')
736 return AVPROBE_SCORE_MAX;
737 else
738 return 0;
741 static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
743 SWFContext *swf = s->priv_data;
744 ByteIOContext *pb = &s->pb;
745 int nbits, len, frame_rate, tag, v;
746 offset_t firstTagOff;
747 AVStream *ast = 0;
748 AVStream *vst = 0;
750 tag = get_be32(pb) & 0xffffff00;
752 if (tag == MKBETAG('C', 'W', 'S', 0))
754 av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
755 return AVERROR_IO;
757 if (tag != MKBETAG('F', 'W', 'S', 0))
758 return AVERROR_IO;
759 get_le32(pb);
760 /* skip rectangle size */
761 nbits = get_byte(pb) >> 3;
762 len = (4 * nbits - 3 + 7) / 8;
763 url_fskip(pb, len);
764 frame_rate = get_le16(pb);
765 get_le16(pb); /* frame count */
767 /* The Flash Player converts 8.8 frame rates
768 to milliseconds internally. Do the same to get
769 a correct framerate */
770 swf->ms_per_frame = ( 1000 * 256 ) / frame_rate;
771 swf->samples_per_frame = 0;
773 firstTagOff = url_ftell(pb);
774 for(;;) {
775 tag = get_swf_tag(pb, &len);
776 if (tag < 0) {
777 if ( ast || vst ) {
778 if ( vst && ast ) {
779 vst->codec->time_base.den = ast->codec->sample_rate / swf->samples_per_frame;
780 vst->codec->time_base.num = 1;
782 break;
784 av_log(s, AV_LOG_ERROR, "No media found in SWF\n");
785 return AVERROR_IO;
787 if ( tag == TAG_VIDEOSTREAM && !vst) {
788 int ch_id = get_le16(pb);
789 get_le16(pb);
790 get_le16(pb);
791 get_le16(pb);
792 get_byte(pb);
793 /* Check for FLV1 */
794 vst = av_new_stream(s, ch_id);
795 av_set_pts_info(vst, 24, 1, 1000); /* 24 bit pts in ms */
796 vst->codec->codec_type = CODEC_TYPE_VIDEO;
797 vst->codec->codec_id = codec_get_id(swf_codec_tags, get_byte(pb));
798 if (swf->samples_per_frame) {
799 vst->codec->time_base.den = 1000. / swf->ms_per_frame;
800 vst->codec->time_base.num = 1;
802 } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) {
803 /* streaming found */
804 int sample_rate_code;
805 get_byte(pb);
806 v = get_byte(pb);
807 swf->samples_per_frame = get_le16(pb);
808 ast = av_new_stream(s, -1); /* -1 to avoid clash with video stream ch_id */
809 av_set_pts_info(ast, 24, 1, 1000); /* 24 bit pts in ms */
810 swf->audio_stream_index = ast->index;
811 ast->codec->channels = 1 + (v&1);
812 ast->codec->codec_type = CODEC_TYPE_AUDIO;
813 if (v & 0x20)
814 ast->codec->codec_id = CODEC_ID_MP3;
815 ast->need_parsing = 1;
816 sample_rate_code= (v>>2) & 3;
817 if (!sample_rate_code)
818 return AVERROR_IO;
819 ast->codec->sample_rate = 11025 << (sample_rate_code-1);
820 if (len > 4)
821 url_fskip(pb,len-4);
823 } else if (tag == TAG_JPEG2 && !vst) {
824 vst = av_new_stream(s, -2); /* -2 to avoid clash with video stream and audio stream */
825 av_set_pts_info(vst, 24, 1, 1000); /* 24 bit pts in ms */
826 vst->codec->codec_type = CODEC_TYPE_VIDEO;
827 vst->codec->codec_id = CODEC_ID_MJPEG;
828 if (swf->samples_per_frame) {
829 vst->codec->time_base.den = 1000. / swf->ms_per_frame;
830 vst->codec->time_base.num = 1;
832 url_fskip(pb, len);
833 } else {
834 url_fskip(pb, len);
837 url_fseek(pb, firstTagOff, SEEK_SET);
839 return 0;
842 static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
844 SWFContext *swf = s->priv_data;
845 ByteIOContext *pb = &s->pb;
846 AVStream *st = 0;
847 int tag, len, i, frame;
849 for(;;) {
850 tag = get_swf_tag(pb, &len);
851 if (tag < 0)
852 return AVERROR_IO;
853 if (tag == TAG_VIDEOFRAME) {
854 int ch_id = get_le16(pb);
855 len -= 2;
856 for( i=0; i<s->nb_streams; i++ ) {
857 st = s->streams[i];
858 if (st->codec->codec_type == CODEC_TYPE_VIDEO && st->id == ch_id) {
859 frame = get_le16(pb);
860 av_get_packet(pb, pkt, len-2);
861 pkt->pts = frame * swf->ms_per_frame;
862 pkt->stream_index = st->index;
863 return pkt->size;
866 } else if (tag == TAG_STREAMBLOCK) {
867 st = s->streams[swf->audio_stream_index];
868 if (st->codec->codec_id == CODEC_ID_MP3) {
869 url_fskip(pb, 4);
870 av_get_packet(pb, pkt, len-4);
871 pkt->stream_index = st->index;
872 return pkt->size;
874 } else if (tag == TAG_JPEG2) {
875 for (i=0; i<s->nb_streams; i++) {
876 st = s->streams[i];
877 if (st->id == -2) {
878 get_le16(pb); /* BITMAP_ID */
879 av_new_packet(pkt, len-2);
880 get_buffer(pb, pkt->data, 4);
881 if (AV_RB32(pkt->data) == 0xffd8ffd9) {
882 /* old SWF files containing SOI/EOI as data start */
883 pkt->size -= 4;
884 get_buffer(pb, pkt->data, pkt->size);
885 } else {
886 get_buffer(pb, pkt->data + 4, pkt->size - 4);
888 pkt->stream_index = st->index;
889 return pkt->size;
893 url_fskip(pb, len);
895 return 0;
898 static int swf_read_close(AVFormatContext *s)
900 return 0;
903 #ifdef CONFIG_SWF_DEMUXER
904 AVInputFormat swf_demuxer = {
905 "swf",
906 "Flash format",
907 sizeof(SWFContext),
908 swf_probe,
909 swf_read_header,
910 swf_read_packet,
911 swf_read_close,
913 #endif
914 #ifdef CONFIG_SWF_MUXER
915 AVOutputFormat swf_muxer = {
916 "swf",
917 "Flash format",
918 "application/x-shockwave-flash",
919 "swf",
920 sizeof(SWFContext),
921 CODEC_ID_MP3,
922 CODEC_ID_FLV1,
923 swf_write_header,
924 swf_write_packet,
925 swf_write_trailer,
927 #endif