VirtualBox

source: vbox/trunk/src/libs/ffmpeg-20060710/libavformat/swf.c@ 9713

Last change on this file since 9713 was 5776, checked in by vboxsync, 17 years ago

ffmpeg: exported to OSE

File size: 26.9 KB
Line 
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
60typedef 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
83static const int sSampleRates[3][4] = {
84 {44100, 48000, 32000, 0},
85 {22050, 24000, 16000, 0},
86 {11025, 12000, 8000, 0},
87};
88
89static 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
100static const int sSamplesPerFrame[3][3] =
101{
102 { 384, 1152, 1152 },
103 { 384, 1152, 576 },
104 { 384, 1152, 576 }
105};
106
107static const int sBitsPerSlot[3] = {
108 32,
109 8,
110 8
111};
112
113static 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
152static 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
168static 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
190static 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
206static 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
233static 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 */
263static 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/* */
300static 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
461static 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 */
477retry_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
625static 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
653static 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
662static 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
703static 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
722static 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
734static 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
852static 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
897static int swf_read_close(AVFormatContext *s)
898{
899 return 0;
900}
901
902static 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
913static 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
927int 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}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette