av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
[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 *
17269bdf
FB
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.
de6d9b64 10 *
17269bdf 11 * This library is distributed in the hope that it will be useful,
de6d9b64 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17269bdf
FB
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
de6d9b64 15 *
17269bdf
FB
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
de6d9b64 19 */
de6d9b64
FB
20#include "avformat.h"
21
de6d9b64
FB
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 */
25
26#define TAG_END 0
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
747a0554 32#define TAG_STREAMHEAD 45
de6d9b64
FB
33#define TAG_STREAMBLOCK 19
34#define TAG_JPEG2 21
747a0554
TU
35#define TAG_PLACEOBJECT2 26
36#define TAG_STREAMHEAD2 45
37#define TAG_VIDEOSTREAM 60
38#define TAG_VIDEOFRAME 61
de6d9b64
FB
39
40#define TAG_LONG 0x100
41
42/* flags for shape definition */
43#define FLAG_MOVETO 0x01
44#define FLAG_SETFILL0 0x02
45#define FLAG_SETFILL1 0x04
46
747a0554
TU
47#define SWF_VIDEO_CODEC_FLV1 0x02
48
49#define AUDIO_FIFO_SIZE 65536
50
de6d9b64
FB
51/* character id used */
52#define BITMAP_ID 0
747a0554 53#define VIDEO_ID 0
de6d9b64
FB
54#define SHAPE_ID 1
55
747a0554
TU
56typedef struct SWFFrame_s {
57 void *data;
58 int size;
59 struct SWFFrame_s *prev;
60 struct SWFFrame_s *next;
61} SWFFrame;
62
de6d9b64 63typedef struct {
747a0554 64
8be1c656
FB
65 offset_t duration_pos;
66 offset_t tag_pos;
747a0554
TU
67
68 int samples_per_frame;
69 int sound_samples;
70 int video_samples;
71 int skip_samples;
72 int swf_frame_number;
73 int video_frame_number;
74 int ms_per_frame;
75 int ch_id;
de6d9b64 76 int tag;
747a0554
TU
77
78 uint8_t *audio_fifo;
79 int audio_in_pos;
80 int audio_out_pos;
81 int audio_size;
82
83 int video_type;
84 int audio_type;
85
86 SWFFrame *frame_head;
87 SWFFrame *frame_tail;
de6d9b64
FB
88} SWFContext;
89
747a0554
TU
90static const int sSampleRates[3][4] = {
91 {44100, 48000, 32000, 0},
92 {22050, 24000, 16000, 0},
93 {11025, 12000, 8000, 0},
94};
95
96static 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}
100 },
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}
104 },
105};
106
107static const int sSamplesPerFrame[3][3] =
108{
109 { 384, 1152, 1152 },
110 { 384, 1152, 576 },
111 { 384, 1152, 576 }
112};
113
114static const int sBitsPerSlot[3] = {
115 32,
116 8,
117 8
118};
119
120static int swf_mp3_info(void *data, int *byteSize, int *samplesPerFrame, int *sampleRate, int *isMono )
121{
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);
127 int bitRate = 0;
128 int bitsPerSlot = sBitsPerSlot[layerID];
129 int isPadded = ((header >> 9) & 0x01);
130
131 if ( (( header >> 21 ) & 0x7ff) != 0x7ff ) {
132 return 0;
133 }
134
135 *isMono = ((header >> 6) & 0x03) == 0x03;
136
137 if ( (header >> 19 ) & 0x01 ) {
138 *sampleRate = sSampleRates[0][sampleRateID];
139 bitRate = sBitRates[0][layerID][bitRateID] * 1000;
140 *samplesPerFrame = sSamplesPerFrame[0][layerID];
141 } else {
142 if ( (header >> 20) & 0x01 ) {
143 *sampleRate = sSampleRates[1][sampleRateID];
144 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
145 *samplesPerFrame = sSamplesPerFrame[1][layerID];
146 } else {
147 *sampleRate = sSampleRates[2][sampleRateID];
148 bitRate = sBitRates[1][layerID][bitRateID] * 1000;
149 *samplesPerFrame = sSamplesPerFrame[2][layerID];
150 }
151 }
152
153 *byteSize = ( ( ( ( *samplesPerFrame * (bitRate / bitsPerSlot) ) / *sampleRate ) + isPadded ) );
154
155 return 1;
156}
157
764ef400 158#ifdef CONFIG_ENCODERS
de6d9b64
FB
159static void put_swf_tag(AVFormatContext *s, int tag)
160{
161 SWFContext *swf = s->priv_data;
162 ByteIOContext *pb = &s->pb;
163
164 swf->tag_pos = url_ftell(pb);
165 swf->tag = tag;
166 /* reserve some room for the tag */
167 if (tag & TAG_LONG) {
168 put_le16(pb, 0);
169 put_le32(pb, 0);
170 } else {
171 put_le16(pb, 0);
172 }
173}
174
175static void put_swf_end_tag(AVFormatContext *s)
176{
177 SWFContext *swf = s->priv_data;
178 ByteIOContext *pb = &s->pb;
8be1c656 179 offset_t pos;
de6d9b64
FB
180 int tag_len, tag;
181
182 pos = url_ftell(pb);
183 tag_len = pos - swf->tag_pos - 2;
184 tag = swf->tag;
185 url_fseek(pb, swf->tag_pos, SEEK_SET);
186 if (tag & TAG_LONG) {
187 tag &= ~TAG_LONG;
188 put_le16(pb, (tag << 6) | 0x3f);
189 put_le32(pb, tag_len - 4);
190 } else {
191 assert(tag_len < 0x3f);
192 put_le16(pb, (tag << 6) | tag_len);
193 }
194 url_fseek(pb, pos, SEEK_SET);
195}
196
197static inline void max_nbits(int *nbits_ptr, int val)
198{
199 int n;
200
201 if (val == 0)
202 return;
203 val = abs(val);
204 n = 1;
205 while (val != 0) {
206 n++;
207 val >>= 1;
208 }
209 if (n > *nbits_ptr)
210 *nbits_ptr = n;
211}
212
213static void put_swf_rect(ByteIOContext *pb,
214 int xmin, int xmax, int ymin, int ymax)
215{
216 PutBitContext p;
0c1a9eda 217 uint8_t buf[256];
de6d9b64
FB
218 int nbits, mask;
219
117a5490 220 init_put_bits(&p, buf, sizeof(buf));
de6d9b64
FB
221
222 nbits = 0;
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;
228
229 /* rectangle info */
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);
235
236 flush_put_bits(&p);
17592475 237 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
de6d9b64
FB
238}
239
240static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
241{
242 int nbits, mask;
243
244 put_bits(pb, 1, 1); /* edge */
245 put_bits(pb, 1, 1); /* line select */
246 nbits = 2;
247 max_nbits(&nbits, dx);
248 max_nbits(&nbits, dy);
249
250 mask = (1 << nbits) - 1;
251 put_bits(pb, 4, nbits - 2); /* 16 bits precision */
252 if (dx == 0) {
253 put_bits(pb, 1, 0);
254 put_bits(pb, 1, 1);
255 put_bits(pb, nbits, dy & mask);
256 } else if (dy == 0) {
257 put_bits(pb, 1, 0);
258 put_bits(pb, 1, 0);
259 put_bits(pb, nbits, dx & mask);
260 } else {
261 put_bits(pb, 1, 1);
262 put_bits(pb, nbits, dx & mask);
263 put_bits(pb, nbits, dy & mask);
264 }
265}
266
267#define FRAC_BITS 16
268
747a0554 269/* put matrix */
de6d9b64
FB
270static void put_swf_matrix(ByteIOContext *pb,
271 int a, int b, int c, int d, int tx, int ty)
272{
273 PutBitContext p;
0c1a9eda 274 uint8_t buf[256];
747a0554 275 int nbits;
de6d9b64 276
117a5490 277 init_put_bits(&p, buf, sizeof(buf));
de6d9b64
FB
278
279 put_bits(&p, 1, 1); /* a, d present */
747a0554
TU
280 nbits = 1;
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);
de6d9b64
FB
286
287 put_bits(&p, 1, 1); /* b, c present */
747a0554
TU
288 nbits = 1;
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);
294
295 nbits = 1;
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);
de6d9b64
FB
301
302 flush_put_bits(&p);
17592475 303 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
de6d9b64
FB
304}
305
747a0554 306/* */
de6d9b64
FB
307static int swf_write_header(AVFormatContext *s)
308{
309 SWFContext *swf;
310 ByteIOContext *pb = &s->pb;
311 AVCodecContext *enc, *audio_enc, *video_enc;
312 PutBitContext p;
0c1a9eda 313 uint8_t buf1[256];
14bea432 314 int i, width, height, rate, rate_base;
de6d9b64 315
1ea4f593 316 swf = av_malloc(sizeof(SWFContext));
de6d9b64
FB
317 if (!swf)
318 return -1;
319 s->priv_data = swf;
320
747a0554
TU
321 swf->ch_id = -1;
322 swf->audio_in_pos = 0;
323 swf->audio_out_pos = 0;
324 swf->audio_size = 0;
325 swf->audio_fifo = av_malloc(AUDIO_FIFO_SIZE);
326 swf->frame_head = 0;
327 swf->frame_tail = 0;
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;
333
de6d9b64
FB
334 video_enc = NULL;
335 audio_enc = NULL;
336 for(i=0;i<s->nb_streams;i++) {
337 enc = &s->streams[i]->codec;
338 if (enc->codec_type == CODEC_TYPE_AUDIO)
339 audio_enc = enc;
747a0554
TU
340 else {
341 if ( enc->codec_id == CODEC_ID_FLV1 || enc->codec_id == CODEC_ID_MJPEG ) {
342 video_enc = enc;
343 } else {
bc874dae 344 av_log(enc, AV_LOG_ERROR, "SWF only supports 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;
361 rate = video_enc->frame_rate;
14bea432 362 rate_base = video_enc->frame_rate_base;
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");
747a0554
TU
374 if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {
375 put_byte(pb, 6); /* version (version 6 and above support FLV1 codec) */
376 } else {
377 put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */
378 }
de6d9b64
FB
379 put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
380 (will be patched if not streamed) */
381
747a0554 382 put_swf_rect(pb, 0, width * 20, 0, height * 20);
14bea432 383 put_le16(pb, (rate * 256) / rate_base); /* frame rate */
de6d9b64 384 swf->duration_pos = url_ftell(pb);
14bea432 385 put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */
de6d9b64
FB
386
387 /* define a shape with the jpeg inside */
747a0554
TU
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);
391
392 put_le16(pb, SHAPE_ID); /* ID of shape */
393 /* bounding rectangle */
394 put_swf_rect(pb, 0, width, 0, height);
395 /* style info */
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 */
de6d9b64 403
747a0554
TU
404 /* shape drawing */
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 */
408
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 */
de6d9b64 415
747a0554
TU
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);
de6d9b64 421
747a0554
TU
422 /* end of shape */
423 put_bits(&p, 1, 0); /* not an edge */
424 put_bits(&p, 5, 0);
de6d9b64 425
747a0554
TU
426 flush_put_bits(&p);
427 put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
de6d9b64 428
747a0554
TU
429 put_swf_end_tag(s);
430 }
de6d9b64 431
747a0554 432 if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) {
de6d9b64
FB
433 int v;
434
435 /* start sound */
747a0554 436 put_swf_tag(s, TAG_STREAMHEAD2);
de6d9b64
FB
437
438 v = 0;
439 switch(audio_enc->sample_rate) {
440 case 11025:
441 v |= 1 << 2;
442 break;
443 case 22050:
444 v |= 2 << 2;
445 break;
446 case 44100:
447 v |= 3 << 2;
448 break;
449 default:
450 /* not supported */
747a0554 451 av_free(swf->audio_fifo);
1ea4f593 452 av_free(swf);
de6d9b64
FB
453 return -1;
454 }
747a0554 455 v |= 0x02; /* 16 bit playback */
de6d9b64 456 if (audio_enc->channels == 2)
747a0554
TU
457 v |= 0x01; /* stereo playback */
458 put_byte(&s->pb, v);
de6d9b64 459 v |= 0x20; /* mp3 compressed */
de6d9b64 460 put_byte(&s->pb, v);
747a0554
TU
461 put_le16(&s->pb, swf->samples_per_frame); /* avg samples per frame */
462 put_le16(&s->pb, 0);
de6d9b64
FB
463
464 put_swf_end_tag(s);
465 }
466
467 put_flush_packet(&s->pb);
468 return 0;
469}
470
471static int swf_write_video(AVFormatContext *s,
49057904 472 AVCodecContext *enc, const uint8_t *buf, int size)
de6d9b64 473{
747a0554 474 SWFContext *swf = s->priv_data;
de6d9b64 475 ByteIOContext *pb = &s->pb;
747a0554
TU
476 int c = 0;
477 int outSize = 0;
478 int outSamples = 0;
479
480 /* Flash Player limit */
d3e18ad0 481 if ( swf->swf_frame_number == 16000 ) {
bc874dae 482 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
de6d9b64
FB
483 }
484
747a0554
TU
485 /* Store video data in queue */
486 if ( enc->codec_type == CODEC_TYPE_VIDEO ) {
487 SWFFrame *new_frame = av_malloc(sizeof(SWFFrame));
488 new_frame->prev = 0;
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;
496 }
497 }
498
499 if ( swf->audio_type ) {
500 /* Prescan audio data for this swf frame */
501retry_swf_audio_packet:
502 if ( ( swf->audio_size-outSize ) >= 4 ) {
503 int mp3FrameSize = 0;
504 int mp3SampleRate = 0;
505 int mp3IsMono = 0;
506 int mp3SamplesPerFrame = 0;
507
508 /* copy out mp3 header from ring buffer */
509 uint8_t header[4];
510 for (c=0; c<4; c++) {
511 header[c] = swf->audio_fifo[(swf->audio_in_pos+outSize+c) % AUDIO_FIFO_SIZE];
512 }
513
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;
520 }
521 }
522 } else {
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 ++;
527 swf->audio_size --;
528 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
529 goto retry_swf_audio_packet;
530 }
531 }
532
533 /* audio stream is behind video stream, bail */
534 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
535 return 0;
536 }
de6d9b64 537
747a0554
TU
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;
542 }
543 }
de6d9b64 544
747a0554
TU
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);
557 put_byte(pb, 0);
558 put_byte(pb, SWF_VIDEO_CODEC_FLV1);
559 put_swf_end_tag(s);
560
561 /* place the video object for the first time */
562 put_swf_tag(s, TAG_PLACEOBJECT2);
563 put_byte(pb, 0x36);
564 put_le16(pb, 1);
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 );
568 put_byte(pb, 'v');
569 put_byte(pb, 'i');
570 put_byte(pb, 'd');
571 put_byte(pb, 'e');
572 put_byte(pb, 'o');
573 put_byte(pb, 0x00);
574 put_swf_end_tag(s);
575 } else {
576 /* mark the character for update */
577 put_swf_tag(s, TAG_PLACEOBJECT2);
578 put_byte(pb, 0x11);
579 put_le16(pb, 1);
580 put_le16(pb, swf->video_frame_number );
581 put_swf_end_tag(s);
582 }
583
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);
591 put_swf_end_tag(s);
592 }
de6d9b64 593
747a0554
TU
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 */
600 put_swf_end_tag(s);
601
602 /* free the bitmap */
603 put_swf_tag(s, TAG_FREECHARACTER);
604 put_le16(pb, BITMAP_ID);
605 put_swf_end_tag(s);
606 }
607
608 put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
609
610 put_le16(pb, BITMAP_ID); /* ID of the image */
611
612 /* a dummy jpeg header seems to be required */
613 put_byte(pb, 0xff);
614 put_byte(pb, 0xd8);
615 put_byte(pb, 0xff);
616 put_byte(pb, 0xd9);
617 /* write the jpeg image */
618 put_buffer(pb, swf->frame_tail->data, swf->frame_tail->size);
619
620 put_swf_end_tag(s);
621
622 /* draw the shape */
623
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);
628 put_swf_end_tag(s);
629 } else {
630 /* invalid codec */
631 }
632
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);
638 }
639 swf->frame_tail->next = 0;
640 } else {
641 swf->frame_head = 0;
642 }
643 swf->swf_frame_number ++;
644 }
645 }
de6d9b64 646
747a0554 647 swf->video_samples += swf->samples_per_frame;
de6d9b64 648
747a0554
TU
649 /* streaming sound always should be placed just before showframe tags */
650 if ( outSize > 0 ) {
651 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
652 put_le16(pb, outSamples);
653 put_le16(pb, 0);
654 for (c=0; c<outSize; c++) {
655 put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]);
656 }
657 put_swf_end_tag(s);
de6d9b64 658
747a0554
TU
659 /* update FIFO */
660 swf->sound_samples += outSamples;
661 swf->audio_in_pos += outSize;
662 swf->audio_size -= outSize;
663 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
664 }
665
de6d9b64
FB
666 /* output the frame */
667 put_swf_tag(s, TAG_SHOWFRAME);
668 put_swf_end_tag(s);
669
670 put_flush_packet(&s->pb);
747a0554 671
de6d9b64
FB
672 return 0;
673}
674
747a0554
TU
675static int swf_write_audio(AVFormatContext *s,
676 AVCodecContext *enc, const uint8_t *buf, int size)
de6d9b64 677{
747a0554
TU
678 SWFContext *swf = s->priv_data;
679 int c = 0;
de6d9b64 680
747a0554 681 /* Flash Player limit */
d3e18ad0 682 if ( swf->swf_frame_number == 16000 ) {
bc874dae 683 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
747a0554
TU
684 }
685
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];
689 }
690 swf->audio_size += size;
691 swf->audio_out_pos += size;
692 swf->audio_out_pos %= AUDIO_FIFO_SIZE;
693 }
694
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);
698 }
de6d9b64 699
de6d9b64
FB
700 return 0;
701}
702
703static int swf_write_packet(AVFormatContext *s, int stream_index,
49057904 704 const uint8_t *buf, int size, int64_t pts)
de6d9b64
FB
705{
706 AVCodecContext *codec = &s->streams[stream_index]->codec;
707 if (codec->codec_type == CODEC_TYPE_AUDIO)
747a0554 708 return swf_write_audio(s, codec, buf, size);
de6d9b64
FB
709 else
710 return swf_write_video(s, codec, buf, size);
711}
712
713static int swf_write_trailer(AVFormatContext *s)
714{
715 SWFContext *swf = s->priv_data;
716 ByteIOContext *pb = &s->pb;
717 AVCodecContext *enc, *video_enc;
718 int file_size, i;
719
720 video_enc = NULL;
721 for(i=0;i<s->nb_streams;i++) {
722 enc = &s->streams[i]->codec;
723 if (enc->codec_type == CODEC_TYPE_VIDEO)
724 video_enc = enc;
725 }
726
727 put_swf_tag(s, TAG_END);
728 put_swf_end_tag(s);
729
730 put_flush_packet(&s->pb);
731
732 /* patch file size and number of frames if not streamed */
733 if (!url_is_streamed(&s->pb) && video_enc) {
734 file_size = url_ftell(pb);
735 url_fseek(pb, 4, SEEK_SET);
736 put_le32(pb, file_size);
737 url_fseek(pb, swf->duration_pos, SEEK_SET);
738 put_le16(pb, video_enc->frame_number);
739 }
747a0554
TU
740
741 av_free(swf->audio_fifo);
742
de6d9b64
FB
743 return 0;
744}
764ef400 745#endif //CONFIG_ENCODERS
de6d9b64 746
747a0554
TU
747/*********************************************/
748/* Extract FLV encoded frame and MP3 from swf
749 Note that the detection of the real frame
750 is inaccurate at this point as it can be
751 quite tricky to determine, you almost certainly
752 will get a bad audio/video sync */
de6d9b64
FB
753
754static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
755{
756 int tag, len;
757
758 if (url_feof(pb))
759 return -1;
760
761 tag = get_le16(pb);
762 len = tag & 0x3f;
763 tag = tag >> 6;
764 if (len == 0x3f) {
765 len = get_le32(pb);
766 }
767 *len_ptr = len;
768 return tag;
769}
770
c9a65ca8
FB
771
772static int swf_probe(AVProbeData *p)
773{
774 /* check file header */
775 if (p->buf_size <= 16)
776 return 0;
777 if (p->buf[0] == 'F' && p->buf[1] == 'W' &&
17269bdf 778 p->buf[2] == 'S')
c9a65ca8
FB
779 return AVPROBE_SCORE_MAX;
780 else
781 return 0;
782}
783
de6d9b64
FB
784static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
785{
747a0554 786 SWFContext *swf = 0;
de6d9b64
FB
787 ByteIOContext *pb = &s->pb;
788 int nbits, len, frame_rate, tag, v;
747a0554
TU
789 offset_t firstTagOff;
790 AVStream *ast = 0;
791 AVStream *vst = 0;
792
793 swf = av_malloc(sizeof(SWFContext));
794 if (!swf)
795 return -1;
796 s->priv_data = swf;
de6d9b64
FB
797
798 if ((get_be32(pb) & 0xffffff00) != MKBETAG('F', 'W', 'S', 0))
799 return -EIO;
800 get_le32(pb);
801 /* skip rectangle size */
802 nbits = get_byte(pb) >> 3;
803 len = (4 * nbits - 3 + 7) / 8;
804 url_fskip(pb, len);
805 frame_rate = get_le16(pb);
806 get_le16(pb); /* frame count */
747a0554
TU
807
808 av_set_pts_info(s, 24, 1, 1000); /* 24 bit pts in ms */
809
810 /* The Flash Player converts 8.8 frame rates
811 to milliseconds internally. Do the same to get
812 a correct framerate */
813 swf->ms_per_frame = ( 1000 * 256 ) / frame_rate;
814 swf->samples_per_frame = 0;
815 swf->ch_id = -1;
816
817 firstTagOff = url_ftell(pb);
de6d9b64
FB
818 for(;;) {
819 tag = get_swf_tag(pb, &len);
820 if (tag < 0) {
747a0554
TU
821 if ( ast || vst ) {
822 if ( vst && ast ) {
823 vst->codec.frame_rate = ast->codec.sample_rate / swf->samples_per_frame;
824 vst->codec.frame_rate_base = 1;
825 }
826 break;
827 }
bc874dae 828 av_log(s, AV_LOG_ERROR, "No media found in SWF\n");
de6d9b64
FB
829 return -EIO;
830 }
747a0554
TU
831 if ( tag == TAG_VIDEOSTREAM && !vst) {
832 swf->ch_id = get_le16(pb);
833 get_le16(pb);
834 get_le16(pb);
835 get_le16(pb);
836 get_byte(pb);
837 /* Check for FLV1 */
838 if ( get_byte(pb) == SWF_VIDEO_CODEC_FLV1 ) {
839 vst = av_new_stream(s, 0);
840 vst->codec.codec_type = CODEC_TYPE_VIDEO;
841 vst->codec.codec_id = CODEC_ID_FLV1;
842 if ( swf->samples_per_frame ) {
843 vst->codec.frame_rate = 1000. / swf->ms_per_frame;
844 vst->codec.frame_rate_base = 1;
845 }
846 }
847 } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) {
de6d9b64
FB
848 /* streaming found */
849 get_byte(pb);
850 v = get_byte(pb);
747a0554 851 swf->samples_per_frame = get_le16(pb);
647b7762
GK
852 if (len!=4)
853 url_fskip(pb,len-4);
de6d9b64
FB
854 /* if mp3 streaming found, OK */
855 if ((v & 0x20) != 0) {
747a0554
TU
856 if ( tag == TAG_STREAMHEAD2 ) {
857 get_le16(pb);
858 }
859 ast = av_new_stream(s, 1);
860 if (!ast)
de6d9b64 861 return -ENOMEM;
1e491e29 862
de6d9b64 863 if (v & 0x01)
747a0554 864 ast->codec.channels = 2;
de6d9b64 865 else
747a0554 866 ast->codec.channels = 1;
de6d9b64
FB
867
868 switch((v>> 2) & 0x03) {
869 case 1:
747a0554 870 ast->codec.sample_rate = 11025;
de6d9b64
FB
871 break;
872 case 2:
747a0554 873 ast->codec.sample_rate = 22050;
de6d9b64
FB
874 break;
875 case 3:
747a0554 876 ast->codec.sample_rate = 44100;
de6d9b64
FB
877 break;
878 default:
747a0554 879 av_free(ast);
de6d9b64
FB
880 return -EIO;
881 }
747a0554
TU
882 ast->codec.codec_type = CODEC_TYPE_AUDIO;
883 ast->codec.codec_id = CODEC_ID_MP3;
de6d9b64
FB
884 }
885 } else {
886 url_fskip(pb, len);
887 }
888 }
747a0554
TU
889 url_fseek(pb, firstTagOff, SEEK_SET);
890
de6d9b64
FB
891 return 0;
892}
893
894static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
895{
747a0554 896 SWFContext *swf = s->priv_data;
de6d9b64 897 ByteIOContext *pb = &s->pb;
747a0554
TU
898 AVStream *st = 0;
899 int tag, len, i, frame;
de6d9b64
FB
900
901 for(;;) {
902 tag = get_swf_tag(pb, &len);
903 if (tag < 0)
904 return -EIO;
747a0554
TU
905 if (tag == TAG_VIDEOFRAME) {
906 for( i=0; i<s->nb_streams; i++ ) {
907 st = s->streams[i];
908 if (st->id == 0) {
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);
915 return pkt->size;
916 } else {
917 url_fskip(pb, len-2);
918 continue;
919 }
920 }
921 }
922 url_fskip(pb, len);
923 } else if (tag == TAG_STREAMBLOCK) {
924 for( i=0; i<s->nb_streams; i++ ) {
925 st = s->streams[i];
926 if (st->id == 1) {
927 av_new_packet(pkt, len);
928 pkt->stream_index = st->index;
929 get_buffer(pb, pkt->data, pkt->size);
930 return pkt->size;
931 }
932 }
933 url_fskip(pb, len);
de6d9b64
FB
934 } else {
935 url_fskip(pb, len);
936 }
937 }
938 return 0;
939}
940
941static int swf_read_close(AVFormatContext *s)
942{
943 return 0;
944}
945
c9a65ca8
FB
946static AVInputFormat swf_iformat = {
947 "swf",
948 "Flash format",
747a0554 949 sizeof(SWFContext),
c9a65ca8
FB
950 swf_probe,
951 swf_read_header,
952 swf_read_packet,
953 swf_read_close,
954};
955
764ef400 956#ifdef CONFIG_ENCODERS
c9a65ca8 957static AVOutputFormat swf_oformat = {
de6d9b64
FB
958 "swf",
959 "Flash format",
960 "application/x-shockwave-flash",
961 "swf",
c9a65ca8 962 sizeof(SWFContext),
747a0554
TU
963 CODEC_ID_MP3,
964 CODEC_ID_FLV1,
de6d9b64
FB
965 swf_write_header,
966 swf_write_packet,
967 swf_write_trailer,
de6d9b64 968};
764ef400 969#endif //CONFIG_ENCODERS
c9a65ca8
FB
970
971int swf_init(void)
972{
973 av_register_input_format(&swf_iformat);
764ef400 974#ifdef CONFIG_ENCODERS
c9a65ca8 975 av_register_output_format(&swf_oformat);
764ef400 976#endif //CONFIG_ENCODERS
c9a65ca8
FB
977 return 0;
978}