]> git.sesse.net Git - ffmpeg/blob - libavformat/swf.c
14a1dc3907890746811125be09aea1b84eaeb44d
[ffmpeg] / libavformat / swf.c
1 /*
2  * Flash Compatible Streaming Format
3  * Copyright (c) 2000 Fabrice Bellard.
4  * Copyright (c) 2003 Tinic Uro.
5  *
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.
10  *
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.
15  *
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
19  */
20 #include "avformat.h"
21 #include "bitstream.h"
22
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 */
26
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
40
41 #define TAG_LONG         0x100
42
43 /* flags for shape definition */
44 #define FLAG_MOVETO      0x01
45 #define FLAG_SETFILL0    0x02
46 #define FLAG_SETFILL1    0x04
47
48 #define SWF_VIDEO_CODEC_FLV1    0x02
49
50 #define AUDIO_FIFO_SIZE 65536
51
52 /* character id used */
53 #define BITMAP_ID 0
54 #define VIDEO_ID 0
55 #define SHAPE_ID  1
56
57 #undef NDEBUG
58 #include <assert.h>
59
60 typedef struct {
61
62     offset_t duration_pos;
63     offset_t tag_pos;
64
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;
73
74     uint8_t *audio_fifo;
75     int audio_in_pos;
76     int audio_out_pos;
77     int audio_size;
78
79     int video_type;
80     int audio_type;
81 } SWFContext;
82
83 static const int sSampleRates[3][4] = {
84     {44100, 48000, 32000, 0},
85     {22050, 24000, 16000, 0},
86     {11025, 12000,  8000, 0},
87 };
88
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}
93     },
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}
97     },
98 };
99
100 static const int sSamplesPerFrame[3][3] =
101 {
102     {  384,     1152,    1152 },
103     {  384,     1152,     576 },
104     {  384,     1152,     576 }
105 };
106
107 static const int sBitsPerSlot[3] = {
108     32,
109     8,
110     8
111 };
112
113 static int swf_mp3_info(void *data, int *byteSize, int *samplesPerFrame, int *sampleRate, int *isMono )
114 {
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);
123
124     if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) {
125         return 0;
126     }
127
128     *isMono = ((header >>  6) & 0x03) == 0x03;
129
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];
143         }
144     }
145
146     *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) );
147
148     return 1;
149 }
150
151 #ifdef CONFIG_MUXERS
152 static void put_swf_tag(AVFormatContext *s, int tag)
153 {
154     SWFContext *swf = s->priv_data;
155     ByteIOContext *pb = &s->pb;
156
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);
165     }
166 }
167
168 static void put_swf_end_tag(AVFormatContext *s)
169 {
170     SWFContext *swf = s->priv_data;
171     ByteIOContext *pb = &s->pb;
172     offset_t pos;
173     int tag_len, tag;
174
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);
186     }
187     url_fseek(pb, pos, SEEK_SET);
188 }
189
190 static inline void max_nbits(int *nbits_ptr, int val)
191 {
192     int n;
193
194     if (val == 0)
195         return;
196     val = abs(val);
197     n = 1;
198     while (val != 0) {
199         n++;
200         val >>= 1;
201     }
202     if (n > *nbits_ptr)
203         *nbits_ptr = n;
204 }
205
206 static void put_swf_rect(ByteIOContext *pb,
207                          int xmin, int xmax, int ymin, int ymax)
208 {
209     PutBitContext p;
210     uint8_t buf[256];
211     int nbits, mask;
212
213     init_put_bits(&p, buf, sizeof(buf));
214
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;
221
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);
228
229     flush_put_bits(&p);
230     put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
231 }
232
233 static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
234 {
235     int nbits, mask;
236
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);
242
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);
257     }
258 }
259
260 #define FRAC_BITS 16
261
262 /* put matrix */
263 static void put_swf_matrix(ByteIOContext *pb,
264                            int a, int b, int c, int d, int tx, int ty)
265 {
266     PutBitContext p;
267     uint8_t buf[256];
268     int nbits;
269
270     init_put_bits(&p, buf, sizeof(buf));
271
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);
279
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);
287
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);
294
295     flush_put_bits(&p);
296     put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
297 }
298
299 /* */
300 static int swf_write_header(AVFormatContext *s)
301 {
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;
308
309     swf = av_malloc(sizeof(SWFContext));
310     if (!swf)
311         return -1;
312     s->priv_data = swf;
313
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;
323
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;
336             }
337         }
338     }
339
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;
353     }
354
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;
361     }
362
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) */
368     }
369     put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
370                                       (will be patched if not streamed) */
371
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 */
376
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);
381
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 */
393
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 */
398
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 */
405
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);
411
412         /* end of shape */
413         put_bits(&p, 1, 0); /* not an edge */
414         put_bits(&p, 5, 0);
415
416         flush_put_bits(&p);
417         put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
418
419         put_swf_end_tag(s);
420     }
421
422     if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) {
423         int v;
424
425         /* start sound */
426         put_swf_tag(s, TAG_STREAMHEAD2);
427
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;
444         }
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);
453
454         put_swf_end_tag(s);
455     }
456
457     put_flush_packet(&s->pb);
458     return 0;
459 }
460
461 static int swf_write_video(AVFormatContext *s,
462                            AVCodecContext *enc, const uint8_t *buf, int size)
463 {
464     SWFContext *swf = s->priv_data;
465     ByteIOContext *pb = &s->pb;
466     int c = 0;
467     int outSize = 0;
468     int outSamples = 0;
469
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");
473     }
474
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;
483
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];
488             }
489
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;
496                     }
497                 }
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;
506             }
507         }
508
509         /* audio stream is behind video stream, bail */
510         if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
511             return 0;
512         }
513     }
514
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);
526
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);
548                 }
549
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);
563
564                     /* free the bitmap */
565                     put_swf_tag(s, TAG_FREECHARACTER);
566                     put_le16(pb, BITMAP_ID);
567                     put_swf_end_tag(s);
568                 }
569
570                 put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
571
572                 put_le16(pb, BITMAP_ID); /* ID of the image */
573
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);
581
582                 put_swf_end_tag(s);
583
584                 /* draw the shape */
585
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 */
593             }
594
595             swf->swf_frame_number ++;
596
597     swf->video_samples += swf->samples_per_frame;
598
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]);
606         }
607         put_swf_end_tag(s);
608
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;
614     }
615
616     /* output the frame */
617     put_swf_tag(s, TAG_SHOWFRAME);
618     put_swf_end_tag(s);
619
620     put_flush_packet(&s->pb);
621
622     return 0;
623 }
624
625 static int swf_write_audio(AVFormatContext *s,
626                            AVCodecContext *enc, const uint8_t *buf, int size)
627 {
628     SWFContext *swf = s->priv_data;
629     int c = 0;
630
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");
634     }
635
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];
639         }
640         swf->audio_size += size;
641         swf->audio_out_pos += size;
642         swf->audio_out_pos %= AUDIO_FIFO_SIZE;
643     }
644
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);
648     }
649
650     return 0;
651 }
652
653 static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)
654 {
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);
660 }
661
662 static int swf_write_trailer(AVFormatContext *s)
663 {
664     SWFContext *swf = s->priv_data;
665     ByteIOContext *pb = &s->pb;
666     AVCodecContext *enc, *video_enc;
667     int file_size, i;
668
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;
674     }
675
676     put_swf_tag(s, TAG_END);
677     put_swf_end_tag(s);
678
679     put_flush_packet(&s->pb);
680
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);
688     }
689
690     av_free(swf->audio_fifo);
691
692     return 0;
693 }
694 #endif //CONFIG_MUXERS
695
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 */
702
703 static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
704 {
705     int tag, len;
706
707     if (url_feof(pb))
708         return -1;
709
710     tag = get_le16(pb);
711     len = tag & 0x3f;
712     tag = tag >> 6;
713     if (len == 0x3f) {
714         len = get_le32(pb);
715     }
716 //    av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
717     *len_ptr = len;
718     return tag;
719 }
720
721
722 static int swf_probe(AVProbeData *p)
723 {
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;
732 }
733
734 static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
735 {
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;
742
743     swf = av_malloc(sizeof(SWFContext));
744     if (!swf)
745         return -1;
746     s->priv_data = swf;
747
748     tag = get_be32(pb) & 0xffffff00;
749
750     if (tag == MKBETAG('C', 'W', 'S', 0))
751     {
752         av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
753         return AVERROR_IO;
754     }
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 */
764
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;
771
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;
780                 }
781                 break;
782             }
783             av_log(s, AV_LOG_ERROR, "No media found in SWF\n");
784             return AVERROR_IO;
785         }
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 */
796
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;
802                 }
803             }
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);
815                 }
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;
820
821                 if (v & 0x01)
822                     ast->codec->channels = 2;
823                 else
824                     ast->codec->channels = 1;
825
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;
839                 }
840                 ast->codec->codec_type = CODEC_TYPE_AUDIO;
841                 ast->codec->codec_id = CODEC_ID_MP3;
842             }
843         } else {
844             url_fskip(pb, len);
845         }
846     }
847     url_fseek(pb, firstTagOff, SEEK_SET);
848
849     return 0;
850 }
851
852 static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
853 {
854     SWFContext *swf = s->priv_data;
855     ByteIOContext *pb = &s->pb;
856     AVStream *st = 0;
857     int tag, len, i, frame;
858
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;
876                     }
877                 }
878             }
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;
887                 }
888             }
889             url_fskip(pb, len);
890         } else {
891             url_fskip(pb, len);
892         }
893     }
894     return 0;
895 }
896
897 static int swf_read_close(AVFormatContext *s)
898 {
899      return 0;
900 }
901
902 static AVInputFormat swf_demuxer = {
903     "swf",
904     "Flash format",
905     sizeof(SWFContext),
906     swf_probe,
907     swf_read_header,
908     swf_read_packet,
909     swf_read_close,
910 };
911
912 #ifdef CONFIG_MUXERS
913 static AVOutputFormat swf_muxer = {
914     "swf",
915     "Flash format",
916     "application/x-shockwave-flash",
917     "swf",
918     sizeof(SWFContext),
919     CODEC_ID_MP3,
920     CODEC_ID_FLV1,
921     swf_write_header,
922     swf_write_packet,
923     swf_write_trailer,
924 };
925 #endif //CONFIG_MUXERS
926
927 int swf_init(void)
928 {
929     av_register_input_format(&swf_demuxer);
930 #ifdef CONFIG_MUXERS
931     av_register_output_format(&swf_muxer);
932 #endif //CONFIG_MUXERS
933     return 0;
934 }