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
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 */
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
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 */
62 int audio_stream_index;
63 offset_t duration_pos;
66 int samples_per_frame;
70 int video_frame_number;
83 static const CodecTag swf_codec_tags[] = {
84 {CODEC_ID_FLV1, 0x02},
85 {CODEC_ID_VP6F, 0x04},
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] =
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);
127 int bitsPerSlot = sBitsPerSlot[layerID];
128 int isPadded = ((header >> 9) & 0x01);
130 if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) {
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];
141 if ( (header >> 20) & 0x01 ) {
142 *sampleRate = sSampleRates[1][sampleRateID];
143 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
144 *samplesPerFrame = sSamplesPerFrame[1][layerID];
146 *sampleRate = sSampleRates[2][sampleRateID];
147 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
148 *samplesPerFrame = sSamplesPerFrame[2][layerID];
152 *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) );
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);
165 /* reserve some room for the tag */
166 if (tag & TAG_LONG) {
174 static void put_swf_end_tag(AVFormatContext *s)
176 SWFContext *swf = s->priv_data;
177 ByteIOContext *pb = &s->pb;
182 tag_len = pos - swf->tag_pos - 2;
184 url_fseek(pb, swf->tag_pos, SEEK_SET);
185 if (tag & TAG_LONG) {
187 put_le16(pb, (tag << 6) | 0x3f);
188 put_le32(pb, tag_len - 4);
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)
212 static void put_swf_rect(ByteIOContext *pb,
213 int xmin, int xmax, int ymin, int ymax)
219 init_put_bits(&p, buf, sizeof(buf));
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;
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);
236 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
239 static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
243 put_bits(pb, 1, 1); /* edge */
244 put_bits(pb, 1, 1); /* line select */
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 */
254 put_bits(pb, nbits, dy & mask);
255 } else if (dy == 0) {
258 put_bits(pb, nbits, dx & mask);
261 put_bits(pb, nbits, dx & mask);
262 put_bits(pb, nbits, dy & mask);
269 static void put_swf_matrix(ByteIOContext *pb,
270 int a, int b, int c, int d, int tx, int ty)
276 init_put_bits(&p, buf, sizeof(buf));
278 put_bits(&p, 1, 1); /* a, d present */
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 */
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);
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);
302 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
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;
313 int i, width, height, rate, rate_base;
315 swf->audio_in_pos = 0;
316 swf->audio_out_pos = 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;
326 for(i=0;i<s->nb_streams;i++) {
327 enc = s->streams[i]->codec;
328 if (enc->codec_type == CODEC_TYPE_AUDIO)
331 if ( enc->codec_id == CODEC_ID_VP6F ||
332 enc->codec_id == CODEC_ID_FLV1 ||
333 enc->codec_id == CODEC_ID_MJPEG ) {
336 av_log(enc, AV_LOG_ERROR, "SWF only supports VP6, FLV1 and MJPEG\n");
343 /* currenty, cannot work correctly if audio only */
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;
359 swf->samples_per_frame = ( 44100. * rate_base ) / rate;
361 swf->audio_type = audio_enc->codec_id;
362 swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate;
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) */
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);
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 */
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);
418 put_bits(&p, 1, 0); /* not an edge */
422 put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
427 if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) {
431 put_swf_tag(s, TAG_STREAMHEAD2);
434 switch(audio_enc->sample_rate) {
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);
450 v |= 0x02; /* 16 bit playback */
451 if (audio_enc->channels == 2)
452 v |= 0x01; /* stereo playback */
454 v |= 0x20; /* mp3 compressed */
456 put_le16(&s->pb, swf->samples_per_frame); /* avg samples per frame */
462 put_flush_packet(&s->pb);
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;
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;
487 int mp3SamplesPerFrame = 0;
489 /* copy out mp3 header from ring buffer */
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;
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 ++;
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 ) {
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);
530 put_byte(pb,codec_get_tag(swf_codec_tags,swf->video_type));
533 /* place the video object for the first time */
534 put_swf_tag(s, TAG_PLACEOBJECT2);
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 );
548 /* mark the character for update */
549 put_swf_tag(s, TAG_PLACEOBJECT2);
552 put_le16(pb, swf->video_frame_number );
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);
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 */
570 /* free the bitmap */
571 put_swf_tag(s, TAG_FREECHARACTER);
572 put_le16(pb, BITMAP_ID);
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 */
585 /* write the jpeg image */
586 put_buffer(pb, buf, size);
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);
601 swf->swf_frame_number ++;
603 swf->video_samples += swf->samples_per_frame;
605 /* streaming sound always should be placed just before showframe tags */
607 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
608 put_le16(pb, outSamples);
610 for (c=0; c<outSize; c++) {
611 put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]);
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);
626 put_flush_packet(&s->pb);
631 static int swf_write_audio(AVFormatContext *s,
632 AVCodecContext *enc, const uint8_t *buf, int size)
634 SWFContext *swf = s->priv_data;
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);
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);
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;
676 for(i=0;i<s->nb_streams;i++) {
677 enc = s->streams[i]->codec;
678 if (enc->codec_type == CODEC_TYPE_VIDEO)
682 put_swf_tag(s, TAG_END);
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);
696 av_free(swf->audio_fifo);
700 #endif //CONFIG_MUXERS
702 /*********************************************/
703 /* Extract FLV encoded frame and MP3 from swf
704 Note that the detection of the real frame
705 is inaccurate at this point as it can be
706 quite tricky to determine, you almost certainly
707 will get a bad audio/video sync */
709 static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
722 // av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
728 static int swf_probe(AVProbeData *p)
730 /* check file header */
731 if (p->buf_size <= 16)
733 if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
735 return AVPROBE_SCORE_MAX;
740 static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
743 ByteIOContext *pb = &s->pb;
744 int nbits, len, frame_rate, tag, v;
745 offset_t firstTagOff;
749 swf = av_malloc(sizeof(SWFContext));
754 tag = get_be32(pb) & 0xffffff00;
756 if (tag == MKBETAG('C', 'W', 'S', 0))
758 av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
761 if (tag != MKBETAG('F', 'W', 'S', 0))
764 /* skip rectangle size */
765 nbits = get_byte(pb) >> 3;
766 len = (4 * nbits - 3 + 7) / 8;
768 frame_rate = get_le16(pb);
769 get_le16(pb); /* frame count */
771 /* The Flash Player converts 8.8 frame rates
772 to milliseconds internally. Do the same to get
773 a correct framerate */
774 swf->ms_per_frame = ( 1000 * 256 ) / frame_rate;
775 swf->samples_per_frame = 0;
777 firstTagOff = url_ftell(pb);
779 tag = get_swf_tag(pb, &len);
783 vst->codec->time_base.den = ast->codec->sample_rate / swf->samples_per_frame;
784 vst->codec->time_base.num = 1;
788 av_log(s, AV_LOG_ERROR, "No media found in SWF\n");
791 if ( tag == TAG_VIDEOSTREAM && !vst) {
792 int ch_id = get_le16(pb);
798 vst = av_new_stream(s, ch_id);
799 av_set_pts_info(vst, 24, 1, 1000); /* 24 bit pts in ms */
800 vst->codec->codec_type = CODEC_TYPE_VIDEO;
801 vst->codec->codec_id = codec_get_id(swf_codec_tags, get_byte(pb));
802 if (swf->samples_per_frame) {
803 vst->codec->time_base.den = 1000. / swf->ms_per_frame;
804 vst->codec->time_base.num = 1;
806 } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) {
807 /* streaming found */
810 swf->samples_per_frame = get_le16(pb);
811 ast = av_new_stream(s, -1); /* -1 to avoid clash with video stream ch_id */
812 av_set_pts_info(ast, 24, 1, 1000); /* 24 bit pts in ms */
813 swf->audio_stream_index = ast->index;
814 ast->codec->channels = 1 + (v&1);
815 ast->codec->codec_type = CODEC_TYPE_AUDIO;
817 ast->codec->codec_id = CODEC_ID_MP3;
818 ast->need_parsing = 1;
819 switch((v>> 2) & 0x03) {
821 ast->codec->sample_rate = 11025;
824 ast->codec->sample_rate = 22050;
827 ast->codec->sample_rate = 44100;
836 } else if (tag == TAG_JPEG2 && !vst) {
837 vst = av_new_stream(s, -2); /* -2 to avoid clash with video stream and audio stream */
838 av_set_pts_info(vst, 24, 1, 1000); /* 24 bit pts in ms */
839 vst->codec->codec_type = CODEC_TYPE_VIDEO;
840 vst->codec->codec_id = CODEC_ID_MJPEG;
841 if (swf->samples_per_frame) {
842 vst->codec->time_base.den = 1000. / swf->ms_per_frame;
843 vst->codec->time_base.num = 1;
850 url_fseek(pb, firstTagOff, SEEK_SET);
855 static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
857 SWFContext *swf = s->priv_data;
858 ByteIOContext *pb = &s->pb;
860 int tag, len, i, frame;
863 tag = get_swf_tag(pb, &len);
866 if (tag == TAG_VIDEOFRAME) {
867 int ch_id = get_le16(pb);
869 for( i=0; i<s->nb_streams; i++ ) {
871 if (st->codec->codec_type == CODEC_TYPE_VIDEO && st->id == ch_id) {
872 frame = get_le16(pb);
873 av_get_packet(pb, pkt, len-2);
874 pkt->pts = frame * swf->ms_per_frame;
875 pkt->stream_index = st->index;
879 } else if (tag == TAG_STREAMBLOCK) {
880 st = s->streams[swf->audio_stream_index];
881 if (st->codec->codec_id == CODEC_ID_MP3) {
883 av_get_packet(pb, pkt, len-4);
884 pkt->stream_index = st->index;
887 } else if (tag == TAG_JPEG2) {
888 for (i=0; i<s->nb_streams; i++) {
891 get_le16(pb); /* BITMAP_ID */
892 av_new_packet(pkt, len-2);
893 get_buffer(pb, pkt->data, 4);
894 if (BE_32(pkt->data) == 0xffd8ffd9) {
895 /* old SWF files containing SOI/EOI as data start */
897 get_buffer(pb, pkt->data, pkt->size);
899 get_buffer(pb, pkt->data + 4, pkt->size - 4);
901 pkt->stream_index = st->index;
911 static int swf_read_close(AVFormatContext *s)
916 #ifdef CONFIG_SWF_DEMUXER
917 AVInputFormat swf_demuxer = {
927 #ifdef CONFIG_SWF_MUXER
928 AVOutputFormat swf_muxer = {
931 "application/x-shockwave-flash",