change myself to mov.c maintainer in favor of Francois, who agreed
[libav.git] / libavformat / swf.c
CommitLineData
de6d9b64
FB
1/*
2 * Flash Compatible Streaming Format
17269bdf 3 * Copyright (c) 2000 Fabrice Bellard.
747a0554 4 * Copyright (c) 2003 Tinic Uro.
de6d9b64 5 *
b78e7197
DB
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
17269bdf
FB
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
b78e7197 11 * version 2.1 of the License, or (at your option) any later version.
de6d9b64 12 *
b78e7197 13 * FFmpeg is distributed in the hope that it will be useful,
de6d9b64 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17269bdf
FB
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
de6d9b64 17 *
17269bdf 18 * You should have received a copy of the GNU Lesser General Public
b78e7197 19 * License along with FFmpeg; if not, write to the Free Software
5509bffa 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
de6d9b64 21 */
de6d9b64 22#include "avformat.h"
2de7795a 23#include "bitstream.h"
5ce117c3 24#include "riff.h" /* for CodecTag */
de6d9b64 25
de6d9b64
FB
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 */
29
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
98d82b22 36#define TAG_STREAMHEAD 18
de6d9b64
FB
37#define TAG_STREAMBLOCK 19
38#define TAG_JPEG2 21
747a0554
TU
39#define TAG_PLACEOBJECT2 26
40#define TAG_STREAMHEAD2 45
bb270c08 41#define TAG_VIDEOSTREAM 60
747a0554 42#define TAG_VIDEOFRAME 61
de6d9b64
FB
43
44#define TAG_LONG 0x100
45
46/* flags for shape definition */
47#define FLAG_MOVETO 0x01
48#define FLAG_SETFILL0 0x02
49#define FLAG_SETFILL1 0x04
50
747a0554
TU
51#define AUDIO_FIFO_SIZE 65536
52
de6d9b64
FB
53/* character id used */
54#define BITMAP_ID 0
747a0554 55#define VIDEO_ID 0
de6d9b64
FB
56#define SHAPE_ID 1
57
14a68b89
MN
58#undef NDEBUG
59#include <assert.h>
747a0554 60
de6d9b64 61typedef struct {
5b1e5dce 62 int audio_stream_index;
8be1c656
FB
63 offset_t duration_pos;
64 offset_t tag_pos;
115329f1 65
747a0554
TU
66 int samples_per_frame;
67 int sound_samples;
68 int video_samples;
747a0554
TU
69 int swf_frame_number;
70 int video_frame_number;
71 int ms_per_frame;
de6d9b64 72 int tag;
747a0554
TU
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;
de6d9b64
FB
81} SWFContext;
82
7caf0cc6 83static const AVCodecTag swf_codec_tags[] = {
5ce117c3
AJ
84 {CODEC_ID_FLV1, 0x02},
85 {CODEC_ID_VP6F, 0x04},
86 {0, 0},
87};
88
dd8a46d9
BC
89static const AVCodecTag swf_audio_codec_tags[] = {
90 {CODEC_ID_PCM_S16LE, 0x00},
91 {CODEC_ID_ADPCM_SWF, 0x01},
92 {CODEC_ID_MP3, 0x02},
93 {CODEC_ID_PCM_S16LE, 0x03},
94 //{CODEC_ID_NELLYMOSER, 0x06},
95 {0, 0},
96};
97
747a0554
TU
98static const int sSampleRates[3][4] = {
99 {44100, 48000, 32000, 0},
100 {22050, 24000, 16000, 0},
101 {11025, 12000, 8000, 0},
102};
103
104static const int sBitRates[2][3][15] = {
105 { { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448},
106 { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384},
107 { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320}
108 },
109 { { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256},
110 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160},
111 { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}
112 },
113};
114
115static const int sSamplesPerFrame[3][3] =
116{
117 { 384, 1152, 1152 },
118 { 384, 1152, 576 },
119 { 384, 1152, 576 }
120};
121
122static const int sBitsPerSlot[3] = {
123 32,
124 8,
125 8
126};
127
128static int swf_mp3_info(void *data, int *byteSize, int *samplesPerFrame, int *sampleRate, int *isMono )
129{
950d94ad 130 uint32_t header = AV_RB32(data);
747a0554
TU
131 int layerID = 3 - ((header >> 17) & 0x03);
132 int bitRateID = ((header >> 12) & 0x0f);
133 int sampleRateID = ((header >> 10) & 0x03);
134 int bitRate = 0;
135 int bitsPerSlot = sBitsPerSlot[layerID];
136 int isPadded = ((header >> 9) & 0x01);
115329f1 137
747a0554
TU
138 if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) {
139 return 0;
140 }
141
142 *isMono = ((header >> 6) & 0x03) == 0x03;
143
144 if ( (header >> 19 ) & 0x01 ) {
145 *sampleRate = sSampleRates[0][sampleRateID];
146 bitRate = sBitRates[0][layerID][bitRateID] * 1000;
147 *samplesPerFrame = sSamplesPerFrame[0][layerID];
148 } else {
149 if ( (header >> 20) & 0x01 ) {
150 *sampleRate = sSampleRates[1][sampleRateID];
151 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
152 *samplesPerFrame = sSamplesPerFrame[1][layerID];
153 } else {
154 *sampleRate = sSampleRates[2][sampleRateID];
155 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
156 *samplesPerFrame = sSamplesPerFrame[2][layerID];
157 }
158 }
159
160 *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) );
161
162 return 1;
163}
164
a9e35095 165#ifdef CONFIG_MUXERS
de6d9b64
FB
166static void put_swf_tag(AVFormatContext *s, int tag)
167{
168 SWFContext *swf = s->priv_data;
169 ByteIOContext *pb = &s->pb;
170
171 swf->tag_pos = url_ftell(pb);
172 swf->tag = tag;
173 /* reserve some room for the tag */
174 if (tag & TAG_LONG) {
175 put_le16(pb, 0);
176 put_le32(pb, 0);
177 } else {
178 put_le16(pb, 0);
179 }
180}
181
182static void put_swf_end_tag(AVFormatContext *s)
183{
184 SWFContext *swf = s->priv_data;
185 ByteIOContext *pb = &s->pb;
8be1c656 186 offset_t pos;
de6d9b64
FB
187 int tag_len, tag;
188
189 pos = url_ftell(pb);
190 tag_len = pos - swf->tag_pos - 2;
191 tag = swf->tag;
192 url_fseek(pb, swf->tag_pos, SEEK_SET);
193 if (tag & TAG_LONG) {
194 tag &= ~TAG_LONG;
195 put_le16(pb, (tag << 6) | 0x3f);
196 put_le32(pb, tag_len - 4);
197 } else {
198 assert(tag_len < 0x3f);
199 put_le16(pb, (tag << 6) | tag_len);
200 }
201 url_fseek(pb, pos, SEEK_SET);
202}
203
204static inline void max_nbits(int *nbits_ptr, int val)
205{
206 int n;
207
208 if (val == 0)
209 return;
210 val = abs(val);
211 n = 1;
212 while (val != 0) {
213 n++;
214 val >>= 1;
215 }
216 if (n > *nbits_ptr)
217 *nbits_ptr = n;
218}
219
115329f1 220static void put_swf_rect(ByteIOContext *pb,
de6d9b64
FB
221 int xmin, int xmax, int ymin, int ymax)
222{
223 PutBitContext p;
0c1a9eda 224 uint8_t buf[256];
de6d9b64
FB
225 int nbits, mask;
226
117a5490 227 init_put_bits(&p, buf, sizeof(buf));
115329f1 228
de6d9b64
FB
229 nbits = 0;
230 max_nbits(&nbits, xmin);
231 max_nbits(&nbits, xmax);
232 max_nbits(&nbits, ymin);
233 max_nbits(&nbits, ymax);
234 mask = (1 << nbits) - 1;
235
236 /* rectangle info */
237 put_bits(&p, 5, nbits);
238 put_bits(&p, nbits, xmin & mask);
239 put_bits(&p, nbits, xmax & mask);
240 put_bits(&p, nbits, ymin & mask);
241 put_bits(&p, nbits, ymax & mask);
115329f1 242
de6d9b64 243 flush_put_bits(&p);
17592475 244 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
de6d9b64
FB
245}
246
247static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
248{
249 int nbits, mask;
250
251 put_bits(pb, 1, 1); /* edge */
252 put_bits(pb, 1, 1); /* line select */
253 nbits = 2;
254 max_nbits(&nbits, dx);
255 max_nbits(&nbits, dy);
256
257 mask = (1 << nbits) - 1;
258 put_bits(pb, 4, nbits - 2); /* 16 bits precision */
259 if (dx == 0) {
115329f1
DB
260 put_bits(pb, 1, 0);
261 put_bits(pb, 1, 1);
de6d9b64
FB
262 put_bits(pb, nbits, dy & mask);
263 } else if (dy == 0) {
115329f1
DB
264 put_bits(pb, 1, 0);
265 put_bits(pb, 1, 0);
de6d9b64
FB
266 put_bits(pb, nbits, dx & mask);
267 } else {
115329f1 268 put_bits(pb, 1, 1);
de6d9b64
FB
269 put_bits(pb, nbits, dx & mask);
270 put_bits(pb, nbits, dy & mask);
271 }
272}
273
274#define FRAC_BITS 16
275
747a0554 276/* put matrix */
de6d9b64
FB
277static void put_swf_matrix(ByteIOContext *pb,
278 int a, int b, int c, int d, int tx, int ty)
279{
280 PutBitContext p;
0c1a9eda 281 uint8_t buf[256];
747a0554 282 int nbits;
de6d9b64 283
117a5490 284 init_put_bits(&p, buf, sizeof(buf));
115329f1 285
de6d9b64 286 put_bits(&p, 1, 1); /* a, d present */
747a0554
TU
287 nbits = 1;
288 max_nbits(&nbits, a);
289 max_nbits(&nbits, d);
290 put_bits(&p, 5, nbits); /* nb bits */
291 put_bits(&p, nbits, a);
292 put_bits(&p, nbits, d);
115329f1 293
de6d9b64 294 put_bits(&p, 1, 1); /* b, c present */
747a0554
TU
295 nbits = 1;
296 max_nbits(&nbits, c);
297 max_nbits(&nbits, b);
298 put_bits(&p, 5, nbits); /* nb bits */
299 put_bits(&p, nbits, c);
300 put_bits(&p, nbits, b);
301
302 nbits = 1;
303 max_nbits(&nbits, tx);
304 max_nbits(&nbits, ty);
305 put_bits(&p, 5, nbits); /* nb bits */
306 put_bits(&p, nbits, tx);
307 put_bits(&p, nbits, ty);
de6d9b64
FB
308
309 flush_put_bits(&p);
17592475 310 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
de6d9b64
FB
311}
312
747a0554 313/* */
de6d9b64
FB
314static int swf_write_header(AVFormatContext *s)
315{
fed7d067 316 SWFContext *swf = s->priv_data;
de6d9b64
FB
317 ByteIOContext *pb = &s->pb;
318 AVCodecContext *enc, *audio_enc, *video_enc;
319 PutBitContext p;
0c1a9eda 320 uint8_t buf1[256];
14bea432 321 int i, width, height, rate, rate_base;
de6d9b64 322
747a0554
TU
323 swf->audio_in_pos = 0;
324 swf->audio_out_pos = 0;
325 swf->audio_size = 0;
326 swf->audio_fifo = av_malloc(AUDIO_FIFO_SIZE);
747a0554
TU
327 swf->sound_samples = 0;
328 swf->video_samples = 0;
329 swf->swf_frame_number = 0;
330 swf->video_frame_number = 0;
747a0554 331
de6d9b64
FB
332 video_enc = NULL;
333 audio_enc = NULL;
334 for(i=0;i<s->nb_streams;i++) {
01f4895c 335 enc = s->streams[i]->codec;
de6d9b64
FB
336 if (enc->codec_type == CODEC_TYPE_AUDIO)
337 audio_enc = enc;
747a0554 338 else {
5ce117c3
AJ
339 if ( enc->codec_id == CODEC_ID_VP6F ||
340 enc->codec_id == CODEC_ID_FLV1 ||
341 enc->codec_id == CODEC_ID_MJPEG ) {
747a0554
TU
342 video_enc = enc;
343 } else {
5ce117c3 344 av_log(enc, AV_LOG_ERROR, "SWF only supports VP6, FLV1 and MJPEG\n");
747a0554
TU
345 return -1;
346 }
347 }
de6d9b64
FB
348 }
349
350 if (!video_enc) {
351 /* currenty, cannot work correctly if audio only */
747a0554 352 swf->video_type = 0;
de6d9b64
FB
353 width = 320;
354 height = 200;
14bea432
MN
355 rate = 10;
356 rate_base= 1;
de6d9b64 357 } else {
747a0554 358 swf->video_type = video_enc->codec_id;
de6d9b64
FB
359 width = video_enc->width;
360 height = video_enc->height;
c0df9d75
MN
361 rate = video_enc->time_base.den;
362 rate_base = video_enc->time_base.num;
de6d9b64
FB
363 }
364
747a0554
TU
365 if (!audio_enc ) {
366 swf->audio_type = 0;
367 swf->samples_per_frame = ( 44100. * rate_base ) / rate;
368 } else {
369 swf->audio_type = audio_enc->codec_id;
370 swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate;
371 }
372
de6d9b64 373 put_tag(pb, "FWS");
5ce117c3
AJ
374 if ( video_enc && video_enc->codec_id == CODEC_ID_VP6F ) {
375 put_byte(pb, 8); /* version (version 8 and above support VP6 codec) */
376 } else if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {
747a0554
TU
377 put_byte(pb, 6); /* version (version 6 and above support FLV1 codec) */
378 } else {
379 put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */
380 }
115329f1
DB
381 put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
382 (will be patched if not streamed) */
de6d9b64 383
747a0554 384 put_swf_rect(pb, 0, width * 20, 0, height * 20);
14bea432 385 put_le16(pb, (rate * 256) / rate_base); /* frame rate */
de6d9b64 386 swf->duration_pos = url_ftell(pb);
14bea432 387 put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */
115329f1 388
de6d9b64 389 /* define a shape with the jpeg inside */
5ce117c3
AJ
390 if ( video_enc && (video_enc->codec_id == CODEC_ID_VP6F ||
391 video_enc->codec_id == CODEC_ID_FLV1 )) {
747a0554
TU
392 } else if ( video_enc && video_enc->codec_id == CODEC_ID_MJPEG ) {
393 put_swf_tag(s, TAG_DEFINESHAPE);
394
395 put_le16(pb, SHAPE_ID); /* ID of shape */
396 /* bounding rectangle */
397 put_swf_rect(pb, 0, width, 0, height);
398 /* style info */
399 put_byte(pb, 1); /* one fill style */
400 put_byte(pb, 0x41); /* clipped bitmap fill */
401 put_le16(pb, BITMAP_ID); /* bitmap ID */
402 /* position of the bitmap */
115329f1 403 put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
747a0554
TU
404 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
405 put_byte(pb, 0); /* no line style */
115329f1 406
747a0554
TU
407 /* shape drawing */
408 init_put_bits(&p, buf1, sizeof(buf1));
409 put_bits(&p, 4, 1); /* one fill bit */
410 put_bits(&p, 4, 0); /* zero line bit */
115329f1 411
747a0554
TU
412 put_bits(&p, 1, 0); /* not an edge */
413 put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
414 put_bits(&p, 5, 1); /* nbits */
415 put_bits(&p, 1, 0); /* X */
416 put_bits(&p, 1, 0); /* Y */
417 put_bits(&p, 1, 1); /* set fill style 1 */
115329f1 418
747a0554
TU
419 /* draw the rectangle ! */
420 put_swf_line_edge(&p, width, 0);
421 put_swf_line_edge(&p, 0, height);
422 put_swf_line_edge(&p, -width, 0);
423 put_swf_line_edge(&p, 0, -height);
115329f1 424
747a0554
TU
425 /* end of shape */
426 put_bits(&p, 1, 0); /* not an edge */
427 put_bits(&p, 5, 0);
de6d9b64 428
747a0554
TU
429 flush_put_bits(&p);
430 put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
de6d9b64 431
747a0554
TU
432 put_swf_end_tag(s);
433 }
115329f1 434
747a0554 435 if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) {
de6d9b64
FB
436 int v;
437
438 /* start sound */
747a0554 439 put_swf_tag(s, TAG_STREAMHEAD2);
de6d9b64
FB
440
441 v = 0;
442 switch(audio_enc->sample_rate) {
443 case 11025:
444 v |= 1 << 2;
445 break;
446 case 22050:
447 v |= 2 << 2;
448 break;
449 case 44100:
450 v |= 3 << 2;
451 break;
452 default:
453 /* not supported */
43a86864 454 av_log(s, AV_LOG_ERROR, "swf doesnt support that sample rate, choose from (44100, 22050, 11025)\n");
747a0554 455 av_free(swf->audio_fifo);
de6d9b64
FB
456 return -1;
457 }
747a0554 458 v |= 0x02; /* 16 bit playback */
de6d9b64 459 if (audio_enc->channels == 2)
747a0554
TU
460 v |= 0x01; /* stereo playback */
461 put_byte(&s->pb, v);
de6d9b64 462 v |= 0x20; /* mp3 compressed */
de6d9b64 463 put_byte(&s->pb, v);
747a0554
TU
464 put_le16(&s->pb, swf->samples_per_frame); /* avg samples per frame */
465 put_le16(&s->pb, 0);
115329f1 466
de6d9b64
FB
467 put_swf_end_tag(s);
468 }
469
470 put_flush_packet(&s->pb);
471 return 0;
472}
473
115329f1 474static int swf_write_video(AVFormatContext *s,
49057904 475 AVCodecContext *enc, const uint8_t *buf, int size)
de6d9b64 476{
747a0554 477 SWFContext *swf = s->priv_data;
de6d9b64 478 ByteIOContext *pb = &s->pb;
747a0554
TU
479 int c = 0;
480 int outSize = 0;
481 int outSamples = 0;
115329f1 482
747a0554 483 /* Flash Player limit */
d3e18ad0 484 if ( swf->swf_frame_number == 16000 ) {
bc874dae 485 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
de6d9b64
FB
486 }
487
747a0554
TU
488 if ( swf->audio_type ) {
489 /* Prescan audio data for this swf frame */
490retry_swf_audio_packet:
491 if ( ( swf->audio_size-outSize ) >= 4 ) {
492 int mp3FrameSize = 0;
493 int mp3SampleRate = 0;
494 int mp3IsMono = 0;
495 int mp3SamplesPerFrame = 0;
115329f1 496
747a0554
TU
497 /* copy out mp3 header from ring buffer */
498 uint8_t header[4];
499 for (c=0; c<4; c++) {
500 header[c] = swf->audio_fifo[(swf->audio_in_pos+outSize+c) % AUDIO_FIFO_SIZE];
501 }
115329f1 502
747a0554
TU
503 if ( swf_mp3_info(header,&mp3FrameSize,&mp3SamplesPerFrame,&mp3SampleRate,&mp3IsMono) ) {
504 if ( ( swf->audio_size-outSize ) >= mp3FrameSize ) {
505 outSize += mp3FrameSize;
506 outSamples += mp3SamplesPerFrame;
507 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
508 goto retry_swf_audio_packet;
509 }
510 }
511 } else {
512 /* invalid mp3 data, skip forward
115329f1 513 we need to do this since the Flash Player
747a0554
TU
514 does not like custom headers */
515 swf->audio_in_pos ++;
516 swf->audio_size --;
517 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
518 goto retry_swf_audio_packet;
519 }
520 }
115329f1 521
747a0554
TU
522 /* audio stream is behind video stream, bail */
523 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
524 return 0;
525 }
747a0554 526 }
de6d9b64 527
5ce117c3
AJ
528 if ( swf->video_type == CODEC_ID_VP6F ||
529 swf->video_type == CODEC_ID_FLV1 ) {
747a0554
TU
530 if ( swf->video_frame_number == 0 ) {
531 /* create a new video object */
532 put_swf_tag(s, TAG_VIDEOSTREAM);
533 put_le16(pb, VIDEO_ID);
534 put_le16(pb, 15000 ); /* hard flash player limit */
535 put_le16(pb, enc->width);
536 put_le16(pb, enc->height);
537 put_byte(pb, 0);
5ce117c3 538 put_byte(pb,codec_get_tag(swf_codec_tags,swf->video_type));
747a0554 539 put_swf_end_tag(s);
115329f1 540
747a0554
TU
541 /* place the video object for the first time */
542 put_swf_tag(s, TAG_PLACEOBJECT2);
543 put_byte(pb, 0x36);
544 put_le16(pb, 1);
545 put_le16(pb, VIDEO_ID);
546 put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
547 put_le16(pb, swf->video_frame_number );
548 put_byte(pb, 'v');
549 put_byte(pb, 'i');
550 put_byte(pb, 'd');
551 put_byte(pb, 'e');
552 put_byte(pb, 'o');
553 put_byte(pb, 0x00);
554 put_swf_end_tag(s);
555 } else {
556 /* mark the character for update */
557 put_swf_tag(s, TAG_PLACEOBJECT2);
558 put_byte(pb, 0x11);
559 put_le16(pb, 1);
560 put_le16(pb, swf->video_frame_number );
561 put_swf_end_tag(s);
562 }
115329f1 563
747a0554
TU
564 /* set video frame data */
565 put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);
115329f1 566 put_le16(pb, VIDEO_ID);
747a0554 567 put_le16(pb, swf->video_frame_number++ );
14a68b89 568 put_buffer(pb, buf, size);
747a0554 569 put_swf_end_tag(s);
747a0554
TU
570 } else if ( swf->video_type == CODEC_ID_MJPEG ) {
571 if (swf->swf_frame_number > 0) {
572 /* remove the shape */
573 put_swf_tag(s, TAG_REMOVEOBJECT);
574 put_le16(pb, SHAPE_ID); /* shape ID */
575 put_le16(pb, 1); /* depth */
576 put_swf_end_tag(s);
115329f1 577
747a0554
TU
578 /* free the bitmap */
579 put_swf_tag(s, TAG_FREECHARACTER);
580 put_le16(pb, BITMAP_ID);
581 put_swf_end_tag(s);
582 }
115329f1 583
747a0554 584 put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
115329f1 585
747a0554 586 put_le16(pb, BITMAP_ID); /* ID of the image */
115329f1 587
747a0554 588 /* a dummy jpeg header seems to be required */
115329f1 589 put_byte(pb, 0xff);
747a0554
TU
590 put_byte(pb, 0xd8);
591 put_byte(pb, 0xff);
592 put_byte(pb, 0xd9);
593 /* write the jpeg image */
14a68b89 594 put_buffer(pb, buf, size);
115329f1 595
747a0554 596 put_swf_end_tag(s);
115329f1 597
747a0554 598 /* draw the shape */
115329f1 599
747a0554
TU
600 put_swf_tag(s, TAG_PLACEOBJECT);
601 put_le16(pb, SHAPE_ID); /* shape ID */
602 put_le16(pb, 1); /* depth */
603 put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0);
604 put_swf_end_tag(s);
605 } else {
606 /* invalid codec */
607 }
115329f1 608
747a0554 609 swf->swf_frame_number ++;
de6d9b64 610
747a0554 611 swf->video_samples += swf->samples_per_frame;
de6d9b64 612
747a0554
TU
613 /* streaming sound always should be placed just before showframe tags */
614 if ( outSize > 0 ) {
615 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
616 put_le16(pb, outSamples);
617 put_le16(pb, 0);
618 for (c=0; c<outSize; c++) {
619 put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]);
620 }
621 put_swf_end_tag(s);
115329f1 622
747a0554
TU
623 /* update FIFO */
624 swf->sound_samples += outSamples;
625 swf->audio_in_pos += outSize;
626 swf->audio_size -= outSize;
627 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
628 }
629
de6d9b64
FB
630 /* output the frame */
631 put_swf_tag(s, TAG_SHOWFRAME);
632 put_swf_end_tag(s);
115329f1 633
de6d9b64 634 put_flush_packet(&s->pb);
115329f1 635
de6d9b64
FB
636 return 0;
637}
638
115329f1 639static int swf_write_audio(AVFormatContext *s,
747a0554 640 AVCodecContext *enc, const uint8_t *buf, int size)
de6d9b64 641{
747a0554
TU
642 SWFContext *swf = s->priv_data;
643 int c = 0;
de6d9b64 644
747a0554 645 /* Flash Player limit */
d3e18ad0 646 if ( swf->swf_frame_number == 16000 ) {
bc874dae 647 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
747a0554
TU
648 }
649
650 if (enc->codec_id == CODEC_ID_MP3 ) {
651 for (c=0; c<size; c++) {
652 swf->audio_fifo[(swf->audio_out_pos+c)%AUDIO_FIFO_SIZE] = buf[c];
653 }
654 swf->audio_size += size;
655 swf->audio_out_pos += size;
656 swf->audio_out_pos %= AUDIO_FIFO_SIZE;
657 }
658
659 /* if audio only stream make sure we add swf frames */
660 if ( swf->video_type == 0 ) {
661 swf_write_video(s, enc, 0, 0);
662 }
de6d9b64 663
de6d9b64
FB
664 return 0;
665}
666
e928649b 667static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)
de6d9b64 668{
01f4895c 669 AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
de6d9b64 670 if (codec->codec_type == CODEC_TYPE_AUDIO)
e928649b 671 return swf_write_audio(s, codec, pkt->data, pkt->size);
de6d9b64 672 else
e928649b 673 return swf_write_video(s, codec, pkt->data, pkt->size);
de6d9b64
FB
674}
675
676static int swf_write_trailer(AVFormatContext *s)
677{
678 SWFContext *swf = s->priv_data;
679 ByteIOContext *pb = &s->pb;
680 AVCodecContext *enc, *video_enc;
681 int file_size, i;
682
683 video_enc = NULL;
684 for(i=0;i<s->nb_streams;i++) {
01f4895c 685 enc = s->streams[i]->codec;
de6d9b64
FB
686 if (enc->codec_type == CODEC_TYPE_VIDEO)
687 video_enc = enc;
688 }
689
690 put_swf_tag(s, TAG_END);
691 put_swf_end_tag(s);
115329f1 692
de6d9b64
FB
693 put_flush_packet(&s->pb);
694
695 /* patch file size and number of frames if not streamed */
696 if (!url_is_streamed(&s->pb) && video_enc) {
697 file_size = url_ftell(pb);
698 url_fseek(pb, 4, SEEK_SET);
699 put_le32(pb, file_size);
700 url_fseek(pb, swf->duration_pos, SEEK_SET);
701 put_le16(pb, video_enc->frame_number);
3439dc95 702 url_fseek(pb, file_size, SEEK_SET);
de6d9b64 703 }
115329f1 704
747a0554
TU
705 av_free(swf->audio_fifo);
706
de6d9b64
FB
707 return 0;
708}
a9e35095 709#endif //CONFIG_MUXERS
de6d9b64 710
747a0554
TU
711/*********************************************/
712/* Extract FLV encoded frame and MP3 from swf
713 Note that the detection of the real frame
714 is inaccurate at this point as it can be
115329f1 715 quite tricky to determine, you almost certainly
747a0554 716 will get a bad audio/video sync */
de6d9b64
FB
717
718static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
719{
720 int tag, len;
115329f1 721
de6d9b64
FB
722 if (url_feof(pb))
723 return -1;
724
725 tag = get_le16(pb);
726 len = tag & 0x3f;
727 tag = tag >> 6;
728 if (len == 0x3f) {
729 len = get_le32(pb);
730 }
e227d197 731// av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
de6d9b64
FB
732 *len_ptr = len;
733 return tag;
734}
735
c9a65ca8
FB
736
737static int swf_probe(AVProbeData *p)
738{
739 /* check file header */
740 if (p->buf_size <= 16)
741 return 0;
e227d197 742 if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
17269bdf 743 p->buf[2] == 'S')
c9a65ca8
FB
744 return AVPROBE_SCORE_MAX;
745 else
746 return 0;
747}
748
de6d9b64
FB
749static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
750{
2ab573cd 751 SWFContext *swf = s->priv_data;
de6d9b64
FB
752 ByteIOContext *pb = &s->pb;
753 int nbits, len, frame_rate, tag, v;
3922c59f 754 offset_t frame_offset = -1;
747a0554
TU
755 AVStream *ast = 0;
756 AVStream *vst = 0;
757
e227d197
AB
758 tag = get_be32(pb) & 0xffffff00;
759
760 if (tag == MKBETAG('C', 'W', 'S', 0))
761 {
bb270c08 762 av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
e227d197
AB
763 return AVERROR_IO;
764 }
765 if (tag != MKBETAG('F', 'W', 'S', 0))
0bd586c5 766 return AVERROR_IO;
de6d9b64
FB
767 get_le32(pb);
768 /* skip rectangle size */
769 nbits = get_byte(pb) >> 3;
770 len = (4 * nbits - 3 + 7) / 8;
771 url_fskip(pb, len);
772 frame_rate = get_le16(pb);
773 get_le16(pb); /* frame count */
115329f1
DB
774
775 /* The Flash Player converts 8.8 frame rates
776 to milliseconds internally. Do the same to get
747a0554
TU
777 a correct framerate */
778 swf->ms_per_frame = ( 1000 * 256 ) / frame_rate;
779 swf->samples_per_frame = 0;
747a0554 780
de6d9b64 781 for(;;) {
3922c59f 782 offset_t tag_offset = url_ftell(pb);
de6d9b64 783 tag = get_swf_tag(pb, &len);
3922c59f
BC
784 if (tag < 0 || tag == TAG_VIDEOFRAME || tag == TAG_STREAMBLOCK) {
785 url_fseek(pb, frame_offset == -1 ? tag_offset : frame_offset, SEEK_SET);
786 break;
de6d9b64 787 }
747a0554 788 if ( tag == TAG_VIDEOSTREAM && !vst) {
432cef76 789 int ch_id = get_le16(pb);
747a0554
TU
790 get_le16(pb);
791 get_le16(pb);
792 get_le16(pb);
793 get_byte(pb);
794 /* Check for FLV1 */
432cef76 795 vst = av_new_stream(s, ch_id);
b4bcf810
BC
796 vst->codec->codec_type = CODEC_TYPE_VIDEO;
797 vst->codec->codec_id = codec_get_id(swf_codec_tags, get_byte(pb));
747a0554 798 } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) {
de6d9b64 799 /* streaming found */
8f36d4ba 800 int sample_rate_code;
de6d9b64
FB
801 get_byte(pb);
802 v = get_byte(pb);
747a0554 803 swf->samples_per_frame = get_le16(pb);
5b1e5dce 804 ast = av_new_stream(s, -1); /* -1 to avoid clash with video stream ch_id */
ec54839a 805 av_set_pts_info(ast, 24, 1, 1000); /* 24 bit pts in ms */
5b1e5dce 806 swf->audio_stream_index = ast->index;
ec54839a
BC
807 ast->codec->channels = 1 + (v&1);
808 ast->codec->codec_type = CODEC_TYPE_AUDIO;
dd8a46d9 809 ast->codec->codec_id = codec_get_id(swf_audio_codec_tags, (v>>4) & 15);
ec54839a 810 ast->need_parsing = 1;
8f36d4ba
BC
811 sample_rate_code= (v>>2) & 3;
812 if (!sample_rate_code)
ec54839a 813 return AVERROR_IO;
8f36d4ba 814 ast->codec->sample_rate = 11025 << (sample_rate_code-1);
ec54839a
BC
815 if (len > 4)
816 url_fskip(pb,len-4);
817
a0dc1ccd
BC
818 } else if (tag == TAG_JPEG2 && !vst) {
819 vst = av_new_stream(s, -2); /* -2 to avoid clash with video stream and audio stream */
a0dc1ccd
BC
820 vst->codec->codec_type = CODEC_TYPE_VIDEO;
821 vst->codec->codec_id = CODEC_ID_MJPEG;
a0dc1ccd 822 url_fskip(pb, len);
3922c59f 823 frame_offset = tag_offset;
de6d9b64
FB
824 } else {
825 url_fskip(pb, len);
826 }
827 }
024c7378
BC
828 if (vst) {
829 av_set_pts_info(vst, 24, 1, 1000); /* 24 bit pts in ms */
830 if (swf->ms_per_frame) {
831 vst->codec->time_base.den = 1000. / swf->ms_per_frame;
832 vst->codec->time_base.num = 1;
833 }
834 }
de6d9b64
FB
835 return 0;
836}
837
838static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
839{
747a0554 840 SWFContext *swf = s->priv_data;
de6d9b64 841 ByteIOContext *pb = &s->pb;
747a0554
TU
842 AVStream *st = 0;
843 int tag, len, i, frame;
115329f1 844
de6d9b64
FB
845 for(;;) {
846 tag = get_swf_tag(pb, &len);
115329f1 847 if (tag < 0)
0bd586c5 848 return AVERROR_IO;
747a0554 849 if (tag == TAG_VIDEOFRAME) {
432cef76 850 int ch_id = get_le16(pb);
655254f0 851 len -= 2;
747a0554 852 for( i=0; i<s->nb_streams; i++ ) {
bb270c08 853 st = s->streams[i];
432cef76
BC
854 if (st->codec->codec_type == CODEC_TYPE_VIDEO && st->id == ch_id) {
855 frame = get_le16(pb);
655254f0 856 av_get_packet(pb, pkt, len-2);
432cef76
BC
857 pkt->pts = frame * swf->ms_per_frame;
858 pkt->stream_index = st->index;
859 return pkt->size;
747a0554 860 }
115329f1 861 }
747a0554 862 } else if (tag == TAG_STREAMBLOCK) {
5b1e5dce
BC
863 st = s->streams[swf->audio_stream_index];
864 if (st->codec->codec_id == CODEC_ID_MP3) {
865 url_fskip(pb, 4);
866 av_get_packet(pb, pkt, len-4);
dd8a46d9
BC
867 } else { // ADPCM, PCM
868 av_get_packet(pb, pkt, len);
747a0554 869 }
dd8a46d9
BC
870 pkt->stream_index = st->index;
871 return pkt->size;
a0dc1ccd
BC
872 } else if (tag == TAG_JPEG2) {
873 for (i=0; i<s->nb_streams; i++) {
874 st = s->streams[i];
875 if (st->id == -2) {
876 get_le16(pb); /* BITMAP_ID */
877 av_new_packet(pkt, len-2);
878 get_buffer(pb, pkt->data, 4);
fead30d4 879 if (AV_RB32(pkt->data) == 0xffd8ffd9) {
a0dc1ccd
BC
880 /* old SWF files containing SOI/EOI as data start */
881 pkt->size -= 4;
882 get_buffer(pb, pkt->data, pkt->size);
883 } else {
884 get_buffer(pb, pkt->data + 4, pkt->size - 4);
885 }
886 pkt->stream_index = st->index;
887 return pkt->size;
888 }
889 }
de6d9b64 890 }
655254f0 891 url_fskip(pb, len);
de6d9b64
FB
892 }
893 return 0;
894}
895
896static int swf_read_close(AVFormatContext *s)
897{
898 return 0;
899}
900
ff70e601
MR
901#ifdef CONFIG_SWF_DEMUXER
902AVInputFormat swf_demuxer = {
c9a65ca8
FB
903 "swf",
904 "Flash format",
747a0554 905 sizeof(SWFContext),
c9a65ca8
FB
906 swf_probe,
907 swf_read_header,
908 swf_read_packet,
909 swf_read_close,
910};
ff70e601
MR
911#endif
912#ifdef CONFIG_SWF_MUXER
913AVOutputFormat swf_muxer = {
de6d9b64
FB
914 "swf",
915 "Flash format",
916 "application/x-shockwave-flash",
917 "swf",
c9a65ca8 918 sizeof(SWFContext),
747a0554
TU
919 CODEC_ID_MP3,
920 CODEC_ID_FLV1,
de6d9b64
FB
921 swf_write_header,
922 swf_write_packet,
923 swf_write_trailer,
de6d9b64 924};
ff70e601 925#endif