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 AVCodecTag 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
);
694 url_fseek(pb
, file_size
, SEEK_SET
);
697 av_free(swf
->audio_fifo
);
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
)
723 // av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
729 static int swf_probe(AVProbeData
*p
)
731 /* check file header */
732 if (p
->buf_size
<= 16)
734 if ((p
->buf
[0] == 'F' || p
->buf
[0] == 'C') && p
->buf
[1] == 'W' &&
736 return AVPROBE_SCORE_MAX
;
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
;
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");
757 if (tag
!= MKBETAG('F', 'W', 'S', 0))
760 /* skip rectangle size */
761 nbits
= get_byte(pb
) >> 3;
762 len
= (4 * nbits
- 3 + 7) / 8;
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
);
775 tag
= get_swf_tag(pb
, &len
);
779 vst
->codec
->time_base
.den
= ast
->codec
->sample_rate
/ swf
->samples_per_frame
;
780 vst
->codec
->time_base
.num
= 1;
784 av_log(s
, AV_LOG_ERROR
, "No media found in SWF\n");
787 if ( tag
== TAG_VIDEOSTREAM
&& !vst
) {
788 int ch_id
= get_le16(pb
);
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
;
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
;
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
)
819 ast
->codec
->sample_rate
= 11025 << (sample_rate_code
-1);
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;
837 url_fseek(pb
, firstTagOff
, SEEK_SET
);
842 static int swf_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
844 SWFContext
*swf
= s
->priv_data
;
845 ByteIOContext
*pb
= &s
->pb
;
847 int tag
, len
, i
, frame
;
850 tag
= get_swf_tag(pb
, &len
);
853 if (tag
== TAG_VIDEOFRAME
) {
854 int ch_id
= get_le16(pb
);
856 for( i
=0; i
<s
->nb_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
;
866 } else if (tag
== TAG_STREAMBLOCK
) {
867 st
= s
->streams
[swf
->audio_stream_index
];
868 if (st
->codec
->codec_id
== CODEC_ID_MP3
) {
870 av_get_packet(pb
, pkt
, len
-4);
871 pkt
->stream_index
= st
->index
;
874 } else if (tag
== TAG_JPEG2
) {
875 for (i
=0; i
<s
->nb_streams
; i
++) {
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 */
884 get_buffer(pb
, pkt
->data
, pkt
->size
);
886 get_buffer(pb
, pkt
->data
+ 4, pkt
->size
- 4);
888 pkt
->stream_index
= st
->index
;
898 static int swf_read_close(AVFormatContext
*s
)
903 #ifdef CONFIG_SWF_DEMUXER
904 AVInputFormat swf_demuxer
= {
914 #ifdef CONFIG_SWF_MUXER
915 AVOutputFormat swf_muxer
= {
918 "application/x-shockwave-flash",