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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /* should have a generic way to indicate probable size */
23 #define DUMMY_FILE_SIZE (100 * 1024 * 1024)
24 #define DUMMY_DURATION 600 /* in seconds */
27 #define TAG_SHOWFRAME 1
28 #define TAG_DEFINESHAPE 2
29 #define TAG_FREECHARACTER 3
30 #define TAG_PLACEOBJECT 4
31 #define TAG_REMOVEOBJECT 5
32 #define TAG_STREAMHEAD 45
33 #define TAG_STREAMBLOCK 19
35 #define TAG_PLACEOBJECT2 26
36 #define TAG_STREAMHEAD2 45
37 #define TAG_VIDEOSTREAM 60
38 #define TAG_VIDEOFRAME 61
40 #define TAG_LONG 0x100
42 /* flags for shape definition */
43 #define FLAG_MOVETO 0x01
44 #define FLAG_SETFILL0 0x02
45 #define FLAG_SETFILL1 0x04
47 #define SWF_VIDEO_CODEC_FLV1 0x02
49 #define AUDIO_FIFO_SIZE 65536
51 /* character id used */
56 typedef struct SWFFrame_s {
59 struct SWFFrame_s *prev;
60 struct SWFFrame_s *next;
65 offset_t duration_pos;
68 int samples_per_frame;
73 int video_frame_number;
90 static const int sSampleRates[3][4] = {
91 {44100, 48000, 32000, 0},
92 {22050, 24000, 16000, 0},
93 {11025, 12000, 8000, 0},
96 static const int sBitRates[2][3][15] = {
97 { { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448},
98 { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384},
99 { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320}
101 { { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256},
102 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160},
103 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}
107 static const int sSamplesPerFrame[3][3] =
114 static const int sBitsPerSlot[3] = {
120 static int swf_mp3_info(void *data, int *byteSize, int *samplesPerFrame, int *sampleRate, int *isMono )
122 uint8_t *dataTmp = (uint8_t *)data;
123 uint32_t header = ( (uint32_t)dataTmp[0] << 24 ) | ( (uint32_t)dataTmp[1] << 16 ) | ( (uint32_t)dataTmp[2] << 8 ) | (uint32_t)dataTmp[3];
124 int layerID = 3 - ((header >> 17) & 0x03);
125 int bitRateID = ((header >> 12) & 0x0f);
126 int sampleRateID = ((header >> 10) & 0x03);
128 int bitsPerSlot = sBitsPerSlot[layerID];
129 int isPadded = ((header >> 9) & 0x01);
131 if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) {
135 *isMono = ((header >> 6) & 0x03) == 0x03;
137 if ( (header >> 19 ) & 0x01 ) {
138 *sampleRate = sSampleRates[0][sampleRateID];
139 bitRate = sBitRates[0][layerID][bitRateID] * 1000;
140 *samplesPerFrame = sSamplesPerFrame[0][layerID];
142 if ( (header >> 20) & 0x01 ) {
143 *sampleRate = sSampleRates[1][sampleRateID];
144 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
145 *samplesPerFrame = sSamplesPerFrame[1][layerID];
147 *sampleRate = sSampleRates[2][sampleRateID];
148 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
149 *samplesPerFrame = sSamplesPerFrame[2][layerID];
153 *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) );
158 #ifdef CONFIG_ENCODERS
159 static void put_swf_tag(AVFormatContext *s, int tag)
161 SWFContext *swf = s->priv_data;
162 ByteIOContext *pb = &s->pb;
164 swf->tag_pos = url_ftell(pb);
166 /* reserve some room for the tag */
167 if (tag & TAG_LONG) {
175 static void put_swf_end_tag(AVFormatContext *s)
177 SWFContext *swf = s->priv_data;
178 ByteIOContext *pb = &s->pb;
183 tag_len = pos - swf->tag_pos - 2;
185 url_fseek(pb, swf->tag_pos, SEEK_SET);
186 if (tag & TAG_LONG) {
188 put_le16(pb, (tag << 6) | 0x3f);
189 put_le32(pb, tag_len - 4);
191 assert(tag_len < 0x3f);
192 put_le16(pb, (tag << 6) | tag_len);
194 url_fseek(pb, pos, SEEK_SET);
197 static inline void max_nbits(int *nbits_ptr, int val)
213 static void put_swf_rect(ByteIOContext *pb,
214 int xmin, int xmax, int ymin, int ymax)
220 init_put_bits(&p, buf, sizeof(buf));
223 max_nbits(&nbits, xmin);
224 max_nbits(&nbits, xmax);
225 max_nbits(&nbits, ymin);
226 max_nbits(&nbits, ymax);
227 mask = (1 << nbits) - 1;
230 put_bits(&p, 5, nbits);
231 put_bits(&p, nbits, xmin & mask);
232 put_bits(&p, nbits, xmax & mask);
233 put_bits(&p, nbits, ymin & mask);
234 put_bits(&p, nbits, ymax & mask);
237 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
240 static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
244 put_bits(pb, 1, 1); /* edge */
245 put_bits(pb, 1, 1); /* line select */
247 max_nbits(&nbits, dx);
248 max_nbits(&nbits, dy);
250 mask = (1 << nbits) - 1;
251 put_bits(pb, 4, nbits - 2); /* 16 bits precision */
255 put_bits(pb, nbits, dy & mask);
256 } else if (dy == 0) {
259 put_bits(pb, nbits, dx & mask);
262 put_bits(pb, nbits, dx & mask);
263 put_bits(pb, nbits, dy & mask);
270 static void put_swf_matrix(ByteIOContext *pb,
271 int a, int b, int c, int d, int tx, int ty)
277 init_put_bits(&p, buf, sizeof(buf));
279 put_bits(&p, 1, 1); /* a, d present */
281 max_nbits(&nbits, a);
282 max_nbits(&nbits, d);
283 put_bits(&p, 5, nbits); /* nb bits */
284 put_bits(&p, nbits, a);
285 put_bits(&p, nbits, d);
287 put_bits(&p, 1, 1); /* b, c present */
289 max_nbits(&nbits, c);
290 max_nbits(&nbits, b);
291 put_bits(&p, 5, nbits); /* nb bits */
292 put_bits(&p, nbits, c);
293 put_bits(&p, nbits, b);
296 max_nbits(&nbits, tx);
297 max_nbits(&nbits, ty);
298 put_bits(&p, 5, nbits); /* nb bits */
299 put_bits(&p, nbits, tx);
300 put_bits(&p, nbits, ty);
303 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
307 static int swf_write_header(AVFormatContext *s)
310 ByteIOContext *pb = &s->pb;
311 AVCodecContext *enc, *audio_enc, *video_enc;
314 int i, width, height, rate, rate_base;
316 swf = av_malloc(sizeof(SWFContext));
322 swf->audio_in_pos = 0;
323 swf->audio_out_pos = 0;
325 swf->audio_fifo = av_malloc(AUDIO_FIFO_SIZE);
328 swf->sound_samples = 0;
329 swf->video_samples = 0;
330 swf->swf_frame_number = 0;
331 swf->video_frame_number = 0;
332 swf->skip_samples = 0;
336 for(i=0;i<s->nb_streams;i++) {
337 enc = &s->streams[i]->codec;
338 if (enc->codec_type == CODEC_TYPE_AUDIO)
341 if ( enc->codec_id == CODEC_ID_FLV1 || enc->codec_id == CODEC_ID_MJPEG ) {
344 av_log(enc, AV_LOG_ERROR, "SWF only supports FLV1 and MJPEG\n");
351 /* currenty, cannot work correctly if audio only */
358 swf->video_type = video_enc->codec_id;
359 width = video_enc->width;
360 height = video_enc->height;
361 rate = video_enc->frame_rate;
362 rate_base = video_enc->frame_rate_base;
367 swf->samples_per_frame = ( 44100. * rate_base ) / rate;
369 swf->audio_type = audio_enc->codec_id;
370 swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate;
374 if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {
375 put_byte(pb, 6); /* version (version 6 and above support FLV1 codec) */
377 put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */
379 put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
380 (will be patched if not streamed) */
382 put_swf_rect(pb, 0, width * 20, 0, height * 20);
383 put_le16(pb, (rate * 256) / rate_base); /* frame rate */
384 swf->duration_pos = url_ftell(pb);
385 put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */
387 /* define a shape with the jpeg inside */
388 if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {
389 } else if ( video_enc && video_enc->codec_id == CODEC_ID_MJPEG ) {
390 put_swf_tag(s, TAG_DEFINESHAPE);
392 put_le16(pb, SHAPE_ID); /* ID of shape */
393 /* bounding rectangle */
394 put_swf_rect(pb, 0, width, 0, height);
396 put_byte(pb, 1); /* one fill style */
397 put_byte(pb, 0x41); /* clipped bitmap fill */
398 put_le16(pb, BITMAP_ID); /* bitmap ID */
399 /* position of the bitmap */
400 put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
401 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
402 put_byte(pb, 0); /* no line style */
405 init_put_bits(&p, buf1, sizeof(buf1));
406 put_bits(&p, 4, 1); /* one fill bit */
407 put_bits(&p, 4, 0); /* zero line bit */
409 put_bits(&p, 1, 0); /* not an edge */
410 put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
411 put_bits(&p, 5, 1); /* nbits */
412 put_bits(&p, 1, 0); /* X */
413 put_bits(&p, 1, 0); /* Y */
414 put_bits(&p, 1, 1); /* set fill style 1 */
416 /* draw the rectangle ! */
417 put_swf_line_edge(&p, width, 0);
418 put_swf_line_edge(&p, 0, height);
419 put_swf_line_edge(&p, -width, 0);
420 put_swf_line_edge(&p, 0, -height);
423 put_bits(&p, 1, 0); /* not an edge */
427 put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
432 if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) {
436 put_swf_tag(s, TAG_STREAMHEAD2);
439 switch(audio_enc->sample_rate) {
451 av_free(swf->audio_fifo);
455 v |= 0x02; /* 16 bit playback */
456 if (audio_enc->channels == 2)
457 v |= 0x01; /* stereo playback */
459 v |= 0x20; /* mp3 compressed */
461 put_le16(&s->pb, swf->samples_per_frame); /* avg samples per frame */
467 put_flush_packet(&s->pb);
471 static int swf_write_video(AVFormatContext *s,
472 AVCodecContext *enc, const uint8_t *buf, int size)
474 SWFContext *swf = s->priv_data;
475 ByteIOContext *pb = &s->pb;
480 /* Flash Player limit */
481 if ( swf->swf_frame_number == 16000 ) {
482 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
485 /* Store video data in queue */
486 if ( enc->codec_type == CODEC_TYPE_VIDEO ) {
487 SWFFrame *new_frame = av_malloc(sizeof(SWFFrame));
489 new_frame->next = swf->frame_head;
490 new_frame->data = av_malloc(size);
491 new_frame->size = size;
492 memcpy(new_frame->data,buf,size);
493 swf->frame_head = new_frame;
494 if ( swf->frame_tail == 0 ) {
495 swf->frame_tail = new_frame;
499 if ( swf->audio_type ) {
500 /* Prescan audio data for this swf frame */
501 retry_swf_audio_packet:
502 if ( ( swf->audio_size-outSize ) >= 4 ) {
503 int mp3FrameSize = 0;
504 int mp3SampleRate = 0;
506 int mp3SamplesPerFrame = 0;
508 /* copy out mp3 header from ring buffer */
510 for (c=0; c<4; c++) {
511 header[c] = swf->audio_fifo[(swf->audio_in_pos+outSize+c) % AUDIO_FIFO_SIZE];
514 if ( swf_mp3_info(header,&mp3FrameSize,&mp3SamplesPerFrame,&mp3SampleRate,&mp3IsMono) ) {
515 if ( ( swf->audio_size-outSize ) >= mp3FrameSize ) {
516 outSize += mp3FrameSize;
517 outSamples += mp3SamplesPerFrame;
518 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
519 goto retry_swf_audio_packet;
523 /* invalid mp3 data, skip forward
524 we need to do this since the Flash Player
525 does not like custom headers */
526 swf->audio_in_pos ++;
528 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
529 goto retry_swf_audio_packet;
533 /* audio stream is behind video stream, bail */
534 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
538 /* compute audio/video drift */
539 if ( enc->codec_type == CODEC_TYPE_VIDEO ) {
540 swf->skip_samples = (int)( ( (double)(swf->swf_frame_number) * (double)enc->frame_rate_base * 44100. ) / (double)(enc->frame_rate) );
541 swf->skip_samples -= swf->video_samples;
545 /* check if we need to insert a padding frame */
546 if (swf->skip_samples <= ( swf->samples_per_frame / 2 ) ) {
547 /* no, it is time for a real frame, check if one is available */
548 if ( swf->frame_tail ) {
549 if ( swf->video_type == CODEC_ID_FLV1 ) {
550 if ( swf->video_frame_number == 0 ) {
551 /* create a new video object */
552 put_swf_tag(s, TAG_VIDEOSTREAM);
553 put_le16(pb, VIDEO_ID);
554 put_le16(pb, 15000 ); /* hard flash player limit */
555 put_le16(pb, enc->width);
556 put_le16(pb, enc->height);
558 put_byte(pb, SWF_VIDEO_CODEC_FLV1);
561 /* place the video object for the first time */
562 put_swf_tag(s, TAG_PLACEOBJECT2);
565 put_le16(pb, VIDEO_ID);
566 put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
567 put_le16(pb, swf->video_frame_number );
576 /* mark the character for update */
577 put_swf_tag(s, TAG_PLACEOBJECT2);
580 put_le16(pb, swf->video_frame_number );
584 // write out pending frames
585 for (; ( enc->frame_number - swf->video_frame_number ) > 0;) {
586 /* set video frame data */
587 put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);
588 put_le16(pb, VIDEO_ID);
589 put_le16(pb, swf->video_frame_number++ );
590 put_buffer(pb, swf->frame_tail->data, swf->frame_tail->size);
594 } else if ( swf->video_type == CODEC_ID_MJPEG ) {
595 if (swf->swf_frame_number > 0) {
596 /* remove the shape */
597 put_swf_tag(s, TAG_REMOVEOBJECT);
598 put_le16(pb, SHAPE_ID); /* shape ID */
599 put_le16(pb, 1); /* depth */
602 /* free the bitmap */
603 put_swf_tag(s, TAG_FREECHARACTER);
604 put_le16(pb, BITMAP_ID);
608 put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
610 put_le16(pb, BITMAP_ID); /* ID of the image */
612 /* a dummy jpeg header seems to be required */
617 /* write the jpeg image */
618 put_buffer(pb, swf->frame_tail->data, swf->frame_tail->size);
624 put_swf_tag(s, TAG_PLACEOBJECT);
625 put_le16(pb, SHAPE_ID); /* shape ID */
626 put_le16(pb, 1); /* depth */
627 put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0);
633 av_free(swf->frame_tail->data);
634 swf->frame_tail = swf->frame_tail->prev;
635 if ( swf->frame_tail ) {
636 if ( swf->frame_tail->next ) {
637 av_free(swf->frame_tail->next);
639 swf->frame_tail->next = 0;
643 swf->swf_frame_number ++;
647 swf->video_samples += swf->samples_per_frame;
649 /* streaming sound always should be placed just before showframe tags */
651 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
652 put_le16(pb, outSamples);
654 for (c=0; c<outSize; c++) {
655 put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]);
660 swf->sound_samples += outSamples;
661 swf->audio_in_pos += outSize;
662 swf->audio_size -= outSize;
663 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
666 /* output the frame */
667 put_swf_tag(s, TAG_SHOWFRAME);
670 put_flush_packet(&s->pb);
675 static int swf_write_audio(AVFormatContext *s,
676 AVCodecContext *enc, const uint8_t *buf, int size)
678 SWFContext *swf = s->priv_data;
681 /* Flash Player limit */
682 if ( swf->swf_frame_number == 16000 ) {
683 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
686 if (enc->codec_id == CODEC_ID_MP3 ) {
687 for (c=0; c<size; c++) {
688 swf->audio_fifo[(swf->audio_out_pos+c)%AUDIO_FIFO_SIZE] = buf[c];
690 swf->audio_size += size;
691 swf->audio_out_pos += size;
692 swf->audio_out_pos %= AUDIO_FIFO_SIZE;
695 /* if audio only stream make sure we add swf frames */
696 if ( swf->video_type == 0 ) {
697 swf_write_video(s, enc, 0, 0);
703 static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)
705 AVCodecContext *codec = &s->streams[pkt->stream_index]->codec;
706 if (codec->codec_type == CODEC_TYPE_AUDIO)
707 return swf_write_audio(s, codec, pkt->data, pkt->size);
709 return swf_write_video(s, codec, pkt->data, pkt->size);
712 static int swf_write_trailer(AVFormatContext *s)
714 SWFContext *swf = s->priv_data;
715 ByteIOContext *pb = &s->pb;
716 AVCodecContext *enc, *video_enc;
720 for(i=0;i<s->nb_streams;i++) {
721 enc = &s->streams[i]->codec;
722 if (enc->codec_type == CODEC_TYPE_VIDEO)
726 put_swf_tag(s, TAG_END);
729 put_flush_packet(&s->pb);
731 /* patch file size and number of frames if not streamed */
732 if (!url_is_streamed(&s->pb) && video_enc) {
733 file_size = url_ftell(pb);
734 url_fseek(pb, 4, SEEK_SET);
735 put_le32(pb, file_size);
736 url_fseek(pb, swf->duration_pos, SEEK_SET);
737 put_le16(pb, video_enc->frame_number);
740 av_free(swf->audio_fifo);
744 #endif //CONFIG_ENCODERS
746 /*********************************************/
747 /* Extract FLV encoded frame and MP3 from swf
748 Note that the detection of the real frame
749 is inaccurate at this point as it can be
750 quite tricky to determine, you almost certainly
751 will get a bad audio/video sync */
753 static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
771 static int swf_probe(AVProbeData *p)
773 /* check file header */
774 if (p->buf_size <= 16)
776 if (p->buf[0] == 'F' && p->buf[1] == 'W' &&
778 return AVPROBE_SCORE_MAX;
783 static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
786 ByteIOContext *pb = &s->pb;
787 int nbits, len, frame_rate, tag, v;
788 offset_t firstTagOff;
792 swf = av_malloc(sizeof(SWFContext));
797 if ((get_be32(pb) & 0xffffff00) != MKBETAG('F', 'W', 'S', 0))
800 /* skip rectangle size */
801 nbits = get_byte(pb) >> 3;
802 len = (4 * nbits - 3 + 7) / 8;
804 frame_rate = get_le16(pb);
805 get_le16(pb); /* frame count */
807 /* The Flash Player converts 8.8 frame rates
808 to milliseconds internally. Do the same to get
809 a correct framerate */
810 swf->ms_per_frame = ( 1000 * 256 ) / frame_rate;
811 swf->samples_per_frame = 0;
814 firstTagOff = url_ftell(pb);
816 tag = get_swf_tag(pb, &len);
820 vst->codec.frame_rate = ast->codec.sample_rate / swf->samples_per_frame;
821 vst->codec.frame_rate_base = 1;
825 av_log(s, AV_LOG_ERROR, "No media found in SWF\n");
828 if ( tag == TAG_VIDEOSTREAM && !vst) {
829 swf->ch_id = get_le16(pb);
835 if ( get_byte(pb) == SWF_VIDEO_CODEC_FLV1 ) {
836 vst = av_new_stream(s, 0);
837 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_FLV1;
841 if ( swf->samples_per_frame ) {
842 vst->codec.frame_rate = 1000. / swf->ms_per_frame;
843 vst->codec.frame_rate_base = 1;
846 } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) {
847 /* streaming found */
850 swf->samples_per_frame = get_le16(pb);
853 /* if mp3 streaming found, OK */
854 if ((v & 0x20) != 0) {
855 if ( tag == TAG_STREAMHEAD2 ) {
858 ast = av_new_stream(s, 1);
859 av_set_pts_info(ast, 24, 1, 1000); /* 24 bit pts in ms */
864 ast->codec.channels = 2;
866 ast->codec.channels = 1;
868 switch((v>> 2) & 0x03) {
870 ast->codec.sample_rate = 11025;
873 ast->codec.sample_rate = 22050;
876 ast->codec.sample_rate = 44100;
882 ast->codec.codec_type = CODEC_TYPE_AUDIO;
883 ast->codec.codec_id = CODEC_ID_MP3;
889 url_fseek(pb, firstTagOff, SEEK_SET);
894 static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
896 SWFContext *swf = s->priv_data;
897 ByteIOContext *pb = &s->pb;
899 int tag, len, i, frame;
902 tag = get_swf_tag(pb, &len);
905 if (tag == TAG_VIDEOFRAME) {
906 for( i=0; i<s->nb_streams; i++ ) {
909 if ( get_le16(pb) == swf->ch_id ) {
910 frame = get_le16(pb);
911 av_new_packet(pkt, len-4);
912 pkt->pts = frame * swf->ms_per_frame;
913 pkt->stream_index = st->index;
914 get_buffer(pb, pkt->data, pkt->size);
917 url_fskip(pb, len-2);
923 } else if (tag == TAG_STREAMBLOCK) {
924 for( i=0; i<s->nb_streams; i++ ) {
927 av_new_packet(pkt, len);
928 pkt->stream_index = st->index;
929 get_buffer(pb, pkt->data, pkt->size);
941 static int swf_read_close(AVFormatContext *s)
946 static AVInputFormat swf_iformat = {
956 #ifdef CONFIG_ENCODERS
957 static AVOutputFormat swf_oformat = {
960 "application/x-shockwave-flash",
969 #endif //CONFIG_ENCODERS
973 av_register_input_format(&swf_iformat);
974 #ifdef CONFIG_ENCODERS
975 av_register_output_format(&swf_oformat);
976 #endif //CONFIG_ENCODERS