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