808
|
1 /*
|
|
2 * Flash Compatible Streaming Format
|
|
3 * Copyright (c) 2000 Fabrice Bellard.
|
|
4 * Copyright (c) 2003 Tinic Uro.
|
|
5 *
|
|
6 * This file is part of FFmpeg.
|
|
7 *
|
|
8 * FFmpeg is free software; you can redistribute it and/or
|
|
9 * modify it under the terms of the GNU Lesser General Public
|
|
10 * License as published by the Free Software Foundation; either
|
|
11 * version 2.1 of the License, or (at your option) any later version.
|
|
12 *
|
|
13 * FFmpeg is distributed in the hope that it will be useful,
|
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
16 * Lesser General Public License for more details.
|
|
17 *
|
|
18 * You should have received a copy of the GNU Lesser General Public
|
|
19 * License along with FFmpeg; if not, write to the Free Software
|
|
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
21 */
|
|
22 #include "avformat.h"
|
|
23 #include "bitstream.h"
|
|
24 #include "riff.h" /* for CodecTag */
|
|
25
|
|
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
|
|
36 #define TAG_STREAMHEAD 18
|
|
37 #define TAG_STREAMBLOCK 19
|
|
38 #define TAG_JPEG2 21
|
|
39 #define TAG_PLACEOBJECT2 26
|
|
40 #define TAG_STREAMHEAD2 45
|
|
41 #define TAG_VIDEOSTREAM 60
|
|
42 #define TAG_VIDEOFRAME 61
|
|
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
|
|
51 #define AUDIO_FIFO_SIZE 65536
|
|
52
|
|
53 /* character id used */
|
|
54 #define BITMAP_ID 0
|
|
55 #define VIDEO_ID 0
|
|
56 #define SHAPE_ID 1
|
|
57
|
|
58 #undef NDEBUG
|
|
59 #include <assert.h>
|
|
60
|
|
61 typedef struct {
|
|
62
|
|
63 offset_t duration_pos;
|
|
64 offset_t tag_pos;
|
|
65
|
|
66 int samples_per_frame;
|
|
67 int sound_samples;
|
|
68 int video_samples;
|
|
69 int swf_frame_number;
|
|
70 int video_frame_number;
|
|
71 int ms_per_frame;
|
|
72 int ch_id;
|
|
73 int tag;
|
|
74
|
|
75 uint8_t *audio_fifo;
|
|
76 int audio_in_pos;
|
|
77 int audio_out_pos;
|
|
78 int audio_size;
|
|
79
|
|
80 int video_type;
|
|
81 int audio_type;
|
|
82 } SWFContext;
|
|
83
|
|
84 static const CodecTag swf_codec_tags[] = {
|
|
85 {CODEC_ID_FLV1, 0x02},
|
|
86 {CODEC_ID_VP6F, 0x04},
|
|
87 {0, 0},
|
|
88 };
|
|
89
|
|
90 static const int sSampleRates[3][4] = {
|
|
91 {44100, 48000, 32000, 0},
|
|
92 {22050, 24000, 16000, 0},
|
|
93 {11025, 12000, 8000, 0},
|
|
94 };
|
|
95
|
|
96 static 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
|
|
107 static const int sSamplesPerFrame[3][3] =
|
|
108 {
|
|
109 { 384, 1152, 1152 },
|
|
110 { 384, 1152, 576 },
|
|
111 { 384, 1152, 576 }
|
|
112 };
|
|
113
|
|
114 static const int sBitsPerSlot[3] = {
|
|
115 32,
|
|
116 8,
|
|
117 8
|
|
118 };
|
|
119
|
|
120 static 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
|
|
158 #ifdef CONFIG_MUXERS
|
|
159 static 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
|
|
175 static void put_swf_end_tag(AVFormatContext *s)
|
|
176 {
|
|
177 SWFContext *swf = s->priv_data;
|
|
178 ByteIOContext *pb = &s->pb;
|
|
179 offset_t pos;
|
|
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
|
|
197 static 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
|
|
213 static void put_swf_rect(ByteIOContext *pb,
|
|
214 int xmin, int xmax, int ymin, int ymax)
|
|
215 {
|
|
216 PutBitContext p;
|
|
217 uint8_t buf[256];
|
|
218 int nbits, mask;
|
|
219
|
|
220 init_put_bits(&p, buf, sizeof(buf));
|
|
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);
|
|
237 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
|
|
238 }
|
|
239
|
|
240 static 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
|
|
269 /* put matrix */
|
|
270 static void put_swf_matrix(ByteIOContext *pb,
|
|
271 int a, int b, int c, int d, int tx, int ty)
|
|
272 {
|
|
273 PutBitContext p;
|
|
274 uint8_t buf[256];
|
|
275 int nbits;
|
|
276
|
|
277 init_put_bits(&p, buf, sizeof(buf));
|
|
278
|
|
279 put_bits(&p, 1, 1); /* a, d present */
|
|
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);
|
|
286
|
|
287 put_bits(&p, 1, 1); /* b, c present */
|
|
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);
|
|
301
|
|
302 flush_put_bits(&p);
|
|
303 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
|
|
304 }
|
|
305
|
|
306 /* */
|
|
307 static 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;
|
|
313 uint8_t buf1[256];
|
|
314 int i, width, height, rate, rate_base;
|
|
315
|
|
316 swf = av_malloc(sizeof(SWFContext));
|
|
317 if (!swf)
|
|
318 return -1;
|
|
319 s->priv_data = swf;
|
|
320
|
|
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->sound_samples = 0;
|
|
327 swf->video_samples = 0;
|
|
328 swf->swf_frame_number = 0;
|
|
329 swf->video_frame_number = 0;
|
|
330
|
|
331 video_enc = NULL;
|
|
332 audio_enc = NULL;
|
|
333 for(i=0;i<s->nb_streams;i++) {
|
|
334 enc = s->streams[i]->codec;
|
|
335 if (enc->codec_type == CODEC_TYPE_AUDIO)
|
|
336 audio_enc = enc;
|
|
337 else {
|
|
338 if ( enc->codec_id == CODEC_ID_VP6F ||
|
|
339 enc->codec_id == CODEC_ID_FLV1 ||
|
|
340 enc->codec_id == CODEC_ID_MJPEG ) {
|
|
341 video_enc = enc;
|
|
342 } else {
|
|
343 av_log(enc, AV_LOG_ERROR, "SWF only supports VP6, FLV1 and MJPEG\n");
|
|
344 return -1;
|
|
345 }
|
|
346 }
|
|
347 }
|
|
348
|
|
349 if (!video_enc) {
|
|
350 /* currenty, cannot work correctly if audio only */
|
|
351 swf->video_type = 0;
|
|
352 width = 320;
|
|
353 height = 200;
|
|
354 rate = 10;
|
|
355 rate_base= 1;
|
|
356 } else {
|
|
357 swf->video_type = video_enc->codec_id;
|
|
358 width = video_enc->width;
|
|
359 height = video_enc->height;
|
|
360 rate = video_enc->time_base.den;
|
|
361 rate_base = video_enc->time_base.num;
|
|
362 }
|
|
363
|
|
364 if (!audio_enc ) {
|
|
365 swf->audio_type = 0;
|
|
366 swf->samples_per_frame = ( 44100. * rate_base ) / rate;
|
|
367 } else {
|
|
368 swf->audio_type = audio_enc->codec_id;
|
|
369 swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate;
|
|
370 }
|
|
371
|
|
372 put_tag(pb, "FWS");
|
|
373 if ( video_enc && video_enc->codec_id == CODEC_ID_VP6F ) {
|
|
374 put_byte(pb, 8); /* version (version 8 and above support VP6 codec) */
|
|
375 } else if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {
|
|
376 put_byte(pb, 6); /* version (version 6 and above support FLV1 codec) */
|
|
377 } else {
|
|
378 put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */
|
|
379 }
|
|
380 put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
|
|
381 (will be patched if not streamed) */
|
|
382
|
|
383 put_swf_rect(pb, 0, width * 20, 0, height * 20);
|
|
384 put_le16(pb, (rate * 256) / rate_base); /* frame rate */
|
|
385 swf->duration_pos = url_ftell(pb);
|
|
386 put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */
|
|
387
|
|
388 /* define a shape with the jpeg inside */
|
|
389 if ( video_enc && (video_enc->codec_id == CODEC_ID_VP6F ||
|
|
390 video_enc->codec_id == CODEC_ID_FLV1 )) {
|
|
391 } else if ( video_enc && video_enc->codec_id == CODEC_ID_MJPEG ) {
|
|
392 put_swf_tag(s, TAG_DEFINESHAPE);
|
|
393
|
|
394 put_le16(pb, SHAPE_ID); /* ID of shape */
|
|
395 /* bounding rectangle */
|
|
396 put_swf_rect(pb, 0, width, 0, height);
|
|
397 /* style info */
|
|
398 put_byte(pb, 1); /* one fill style */
|
|
399 put_byte(pb, 0x41); /* clipped bitmap fill */
|
|
400 put_le16(pb, BITMAP_ID); /* bitmap ID */
|
|
401 /* position of the bitmap */
|
|
402 put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
|
|
403 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
|
|
404 put_byte(pb, 0); /* no line style */
|
|
405
|
|
406 /* shape drawing */
|
|
407 init_put_bits(&p, buf1, sizeof(buf1));
|
|
408 put_bits(&p, 4, 1); /* one fill bit */
|
|
409 put_bits(&p, 4, 0); /* zero line bit */
|
|
410
|
|
411 put_bits(&p, 1, 0); /* not an edge */
|
|
412 put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
|
|
413 put_bits(&p, 5, 1); /* nbits */
|
|
414 put_bits(&p, 1, 0); /* X */
|
|
415 put_bits(&p, 1, 0); /* Y */
|
|
416 put_bits(&p, 1, 1); /* set fill style 1 */
|
|
417
|
|
418 /* draw the rectangle ! */
|
|
419 put_swf_line_edge(&p, width, 0);
|
|
420 put_swf_line_edge(&p, 0, height);
|
|
421 put_swf_line_edge(&p, -width, 0);
|
|
422 put_swf_line_edge(&p, 0, -height);
|
|
423
|
|
424 /* end of shape */
|
|
425 put_bits(&p, 1, 0); /* not an edge */
|
|
426 put_bits(&p, 5, 0);
|
|
427
|
|
428 flush_put_bits(&p);
|
|
429 put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
|
|
430
|
|
431 put_swf_end_tag(s);
|
|
432 }
|
|
433
|
|
434 if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) {
|
|
435 int v;
|
|
436
|
|
437 /* start sound */
|
|
438 put_swf_tag(s, TAG_STREAMHEAD2);
|
|
439
|
|
440 v = 0;
|
|
441 switch(audio_enc->sample_rate) {
|
|
442 case 11025:
|
|
443 v |= 1 << 2;
|
|
444 break;
|
|
445 case 22050:
|
|
446 v |= 2 << 2;
|
|
447 break;
|
|
448 case 44100:
|
|
449 v |= 3 << 2;
|
|
450 break;
|
|
451 default:
|
|
452 /* not supported */
|
|
453 av_free(swf->audio_fifo);
|
|
454 av_free(swf);
|
|
455 return -1;
|
|
456 }
|
|
457 v |= 0x02; /* 16 bit playback */
|
|
458 if (audio_enc->channels == 2)
|
|
459 v |= 0x01; /* stereo playback */
|
|
460 put_byte(&s->pb, v);
|
|
461 v |= 0x20; /* mp3 compressed */
|
|
462 put_byte(&s->pb, v);
|
|
463 put_le16(&s->pb, swf->samples_per_frame); /* avg samples per frame */
|
|
464 put_le16(&s->pb, 0);
|
|
465
|
|
466 put_swf_end_tag(s);
|
|
467 }
|
|
468
|
|
469 put_flush_packet(&s->pb);
|
|
470 return 0;
|
|
471 }
|
|
472
|
|
473 static int swf_write_video(AVFormatContext *s,
|
|
474 AVCodecContext *enc, const uint8_t *buf, int size)
|
|
475 {
|
|
476 SWFContext *swf = s->priv_data;
|
|
477 ByteIOContext *pb = &s->pb;
|
|
478 int c = 0;
|
|
479 int outSize = 0;
|
|
480 int outSamples = 0;
|
|
481
|
|
482 /* Flash Player limit */
|
|
483 if ( swf->swf_frame_number == 16000 ) {
|
|
484 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
|
|
485 }
|
|
486
|
|
487 if ( swf->audio_type ) {
|
|
488 /* Prescan audio data for this swf frame */
|
|
489 retry_swf_audio_packet:
|
|
490 if ( ( swf->audio_size-outSize ) >= 4 ) {
|
|
491 int mp3FrameSize = 0;
|
|
492 int mp3SampleRate = 0;
|
|
493 int mp3IsMono = 0;
|
|
494 int mp3SamplesPerFrame = 0;
|
|
495
|
|
496 /* copy out mp3 header from ring buffer */
|
|
497 uint8_t header[4];
|
|
498 for (c=0; c<4; c++) {
|
|
499 header[c] = swf->audio_fifo[(swf->audio_in_pos+outSize+c) % AUDIO_FIFO_SIZE];
|
|
500 }
|
|
501
|
|
502 if ( swf_mp3_info(header,&mp3FrameSize,&mp3SamplesPerFrame,&mp3SampleRate,&mp3IsMono) ) {
|
|
503 if ( ( swf->audio_size-outSize ) >= mp3FrameSize ) {
|
|
504 outSize += mp3FrameSize;
|
|
505 outSamples += mp3SamplesPerFrame;
|
|
506 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
|
|
507 goto retry_swf_audio_packet;
|
|
508 }
|
|
509 }
|
|
510 } else {
|
|
511 /* invalid mp3 data, skip forward
|
|
512 we need to do this since the Flash Player
|
|
513 does not like custom headers */
|
|
514 swf->audio_in_pos ++;
|
|
515 swf->audio_size --;
|
|
516 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
|
|
517 goto retry_swf_audio_packet;
|
|
518 }
|
|
519 }
|
|
520
|
|
521 /* audio stream is behind video stream, bail */
|
|
522 if ( ( swf->sound_samples + outSamples + swf->samples_per_frame ) < swf->video_samples ) {
|
|
523 return 0;
|
|
524 }
|
|
525 }
|
|
526
|
|
527 if ( swf->video_type == CODEC_ID_VP6F ||
|
|
528 swf->video_type == CODEC_ID_FLV1 ) {
|
|
529 if ( swf->video_frame_number == 0 ) {
|
|
530 /* create a new video object */
|
|
531 put_swf_tag(s, TAG_VIDEOSTREAM);
|
|
532 put_le16(pb, VIDEO_ID);
|
|
533 put_le16(pb, 15000 ); /* hard flash player limit */
|
|
534 put_le16(pb, enc->width);
|
|
535 put_le16(pb, enc->height);
|
|
536 put_byte(pb, 0);
|
|
537 put_byte(pb,codec_get_tag(swf_codec_tags,swf->video_type));
|
|
538 put_swf_end_tag(s);
|
|
539
|
|
540 /* place the video object for the first time */
|
|
541 put_swf_tag(s, TAG_PLACEOBJECT2);
|
|
542 put_byte(pb, 0x36);
|
|
543 put_le16(pb, 1);
|
|
544 put_le16(pb, VIDEO_ID);
|
|
545 put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
|
|
546 put_le16(pb, swf->video_frame_number );
|
|
547 put_byte(pb, 'v');
|
|
548 put_byte(pb, 'i');
|
|
549 put_byte(pb, 'd');
|
|
550 put_byte(pb, 'e');
|
|
551 put_byte(pb, 'o');
|
|
552 put_byte(pb, 0x00);
|
|
553 put_swf_end_tag(s);
|
|
554 } else {
|
|
555 /* mark the character for update */
|
|
556 put_swf_tag(s, TAG_PLACEOBJECT2);
|
|
557 put_byte(pb, 0x11);
|
|
558 put_le16(pb, 1);
|
|
559 put_le16(pb, swf->video_frame_number );
|
|
560 put_swf_end_tag(s);
|
|
561 }
|
|
562
|
|
563 /* set video frame data */
|
|
564 put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);
|
|
565 put_le16(pb, VIDEO_ID);
|
|
566 put_le16(pb, swf->video_frame_number++ );
|
|
567 put_buffer(pb, buf, size);
|
|
568 put_swf_end_tag(s);
|
|
569 } else if ( swf->video_type == CODEC_ID_MJPEG ) {
|
|
570 if (swf->swf_frame_number > 0) {
|
|
571 /* remove the shape */
|
|
572 put_swf_tag(s, TAG_REMOVEOBJECT);
|
|
573 put_le16(pb, SHAPE_ID); /* shape ID */
|
|
574 put_le16(pb, 1); /* depth */
|
|
575 put_swf_end_tag(s);
|
|
576
|
|
577 /* free the bitmap */
|
|
578 put_swf_tag(s, TAG_FREECHARACTER);
|
|
579 put_le16(pb, BITMAP_ID);
|
|
580 put_swf_end_tag(s);
|
|
581 }
|
|
582
|
|
583 put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
|
|
584
|
|
585 put_le16(pb, BITMAP_ID); /* ID of the image */
|
|
586
|
|
587 /* a dummy jpeg header seems to be required */
|
|
588 put_byte(pb, 0xff);
|
|
589 put_byte(pb, 0xd8);
|
|
590 put_byte(pb, 0xff);
|
|
591 put_byte(pb, 0xd9);
|
|
592 /* write the jpeg image */
|
|
593 put_buffer(pb, buf, size);
|
|
594
|
|
595 put_swf_end_tag(s);
|
|
596
|
|
597 /* draw the shape */
|
|
598
|
|
599 put_swf_tag(s, TAG_PLACEOBJECT);
|
|
600 put_le16(pb, SHAPE_ID); /* shape ID */
|
|
601 put_le16(pb, 1); /* depth */
|
|
602 put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0);
|
|
603 put_swf_end_tag(s);
|
|
604 } else {
|
|
605 /* invalid codec */
|
|
606 }
|
|
607
|
|
608 swf->swf_frame_number ++;
|
|
609
|
|
610 swf->video_samples += swf->samples_per_frame;
|
|
611
|
|
612 /* streaming sound always should be placed just before showframe tags */
|
|
613 if ( outSize > 0 ) {
|
|
614 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
|
|
615 put_le16(pb, outSamples);
|
|
616 put_le16(pb, 0);
|
|
617 for (c=0; c<outSize; c++) {
|
|
618 put_byte(pb,swf->audio_fifo[(swf->audio_in_pos+c) % AUDIO_FIFO_SIZE]);
|
|
619 }
|
|
620 put_swf_end_tag(s);
|
|
621
|
|
622 /* update FIFO */
|
|
623 swf->sound_samples += outSamples;
|
|
624 swf->audio_in_pos += outSize;
|
|
625 swf->audio_size -= outSize;
|
|
626 swf->audio_in_pos %= AUDIO_FIFO_SIZE;
|
|
627 }
|
|
628
|
|
629 /* output the frame */
|
|
630 put_swf_tag(s, TAG_SHOWFRAME);
|
|
631 put_swf_end_tag(s);
|
|
632
|
|
633 put_flush_packet(&s->pb);
|
|
634
|
|
635 return 0;
|
|
636 }
|
|
637
|
|
638 static int swf_write_audio(AVFormatContext *s,
|
|
639 AVCodecContext *enc, const uint8_t *buf, int size)
|
|
640 {
|
|
641 SWFContext *swf = s->priv_data;
|
|
642 int c = 0;
|
|
643
|
|
644 /* Flash Player limit */
|
|
645 if ( swf->swf_frame_number == 16000 ) {
|
|
646 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
|
|
647 }
|
|
648
|
|
649 if (enc->codec_id == CODEC_ID_MP3 ) {
|
|
650 for (c=0; c<size; c++) {
|
|
651 swf->audio_fifo[(swf->audio_out_pos+c)%AUDIO_FIFO_SIZE] = buf[c];
|
|
652 }
|
|
653 swf->audio_size += size;
|
|
654 swf->audio_out_pos += size;
|
|
655 swf->audio_out_pos %= AUDIO_FIFO_SIZE;
|
|
656 }
|
|
657
|
|
658 /* if audio only stream make sure we add swf frames */
|
|
659 if ( swf->video_type == 0 ) {
|
|
660 swf_write_video(s, enc, 0, 0);
|
|
661 }
|
|
662
|
|
663 return 0;
|
|
664 }
|
|
665
|
|
666 static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)
|
|
667 {
|
|
668 AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
|
|
669 if (codec->codec_type == CODEC_TYPE_AUDIO)
|
|
670 return swf_write_audio(s, codec, pkt->data, pkt->size);
|
|
671 else
|
|
672 return swf_write_video(s, codec, pkt->data, pkt->size);
|
|
673 }
|
|
674
|
|
675 static int swf_write_trailer(AVFormatContext *s)
|
|
676 {
|
|
677 SWFContext *swf = s->priv_data;
|
|
678 ByteIOContext *pb = &s->pb;
|
|
679 AVCodecContext *enc, *video_enc;
|
|
680 int file_size, i;
|
|
681
|
|
682 video_enc = NULL;
|
|
683 for(i=0;i<s->nb_streams;i++) {
|
|
684 enc = s->streams[i]->codec;
|
|
685 if (enc->codec_type == CODEC_TYPE_VIDEO)
|
|
686 video_enc = enc;
|
|
687 }
|
|
688
|
|
689 put_swf_tag(s, TAG_END);
|
|
690 put_swf_end_tag(s);
|
|
691
|
|
692 put_flush_packet(&s->pb);
|
|
693
|
|
694 /* patch file size and number of frames if not streamed */
|
|
695 if (!url_is_streamed(&s->pb) && video_enc) {
|
|
696 file_size = url_ftell(pb);
|
|
697 url_fseek(pb, 4, SEEK_SET);
|
|
698 put_le32(pb, file_size);
|
|
699 url_fseek(pb, swf->duration_pos, SEEK_SET);
|
|
700 put_le16(pb, video_enc->frame_number);
|
|
701 }
|
|
702
|
|
703 av_free(swf->audio_fifo);
|
|
704
|
|
705 return 0;
|
|
706 }
|
|
707 #endif //CONFIG_MUXERS
|
|
708
|
|
709 /*********************************************/
|
|
710 /* Extract FLV encoded frame and MP3 from swf
|
|
711 Note that the detection of the real frame
|
|
712 is inaccurate at this point as it can be
|
|
713 quite tricky to determine, you almost certainly
|
|
714 will get a bad audio/video sync */
|
|
715
|
|
716 static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
|
|
717 {
|
|
718 int tag, len;
|
|
719
|
|
720 if (url_feof(pb))
|
|
721 return -1;
|
|
722
|
|
723 tag = get_le16(pb);
|
|
724 len = tag & 0x3f;
|
|
725 tag = tag >> 6;
|
|
726 if (len == 0x3f) {
|
|
727 len = get_le32(pb);
|
|
728 }
|
|
729 // av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
|
|
730 *len_ptr = len;
|
|
731 return tag;
|
|
732 }
|
|
733
|
|
734
|
|
735 static int swf_probe(AVProbeData *p)
|
|
736 {
|
|
737 /* check file header */
|
|
738 if (p->buf_size <= 16)
|
|
739 return 0;
|
|
740 if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
|
|
741 p->buf[2] == 'S')
|
|
742 return AVPROBE_SCORE_MAX;
|
|
743 else
|
|
744 return 0;
|
|
745 }
|
|
746
|
|
747 static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
|
|
748 {
|
|
749 SWFContext *swf = 0;
|
|
750 ByteIOContext *pb = &s->pb;
|
|
751 int nbits, len, frame_rate, tag, v;
|
|
752 offset_t firstTagOff;
|
|
753 AVStream *ast = 0;
|
|
754 AVStream *vst = 0;
|
|
755
|
|
756 swf = av_malloc(sizeof(SWFContext));
|
|
757 if (!swf)
|
|
758 return -1;
|
|
759 s->priv_data = swf;
|
|
760
|
|
761 tag = get_be32(pb) & 0xffffff00;
|
|
762
|
|
763 if (tag == MKBETAG('C', 'W', 'S', 0))
|
|
764 {
|
|
765 av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
|
|
766 return AVERROR_IO;
|
|
767 }
|
|
768 if (tag != MKBETAG('F', 'W', 'S', 0))
|
|
769 return AVERROR_IO;
|
|
770 get_le32(pb);
|
|
771 /* skip rectangle size */
|
|
772 nbits = get_byte(pb) >> 3;
|
|
773 len = (4 * nbits - 3 + 7) / 8;
|
|
774 url_fskip(pb, len);
|
|
775 frame_rate = get_le16(pb);
|
|
776 get_le16(pb); /* frame count */
|
|
777
|
|
778 /* The Flash Player converts 8.8 frame rates
|
|
779 to milliseconds internally. Do the same to get
|
|
780 a correct framerate */
|
|
781 swf->ms_per_frame = ( 1000 * 256 ) / frame_rate;
|
|
782 swf->samples_per_frame = 0;
|
|
783 swf->ch_id = -1;
|
|
784
|
|
785 firstTagOff = url_ftell(pb);
|
|
786 for(;;) {
|
|
787 tag = get_swf_tag(pb, &len);
|
|
788 if (tag < 0) {
|
|
789 if ( ast || vst ) {
|
|
790 if ( vst && ast ) {
|
|
791 vst->codec->time_base.den = ast->codec->sample_rate / swf->samples_per_frame;
|
|
792 vst->codec->time_base.num = 1;
|
|
793 }
|
|
794 break;
|
|
795 }
|
|
796 av_log(s, AV_LOG_ERROR, "No media found in SWF\n");
|
|
797 return AVERROR_IO;
|
|
798 }
|
|
799 if ( tag == TAG_VIDEOSTREAM && !vst) {
|
|
800 int codec_id;
|
|
801 swf->ch_id = get_le16(pb);
|
|
802 get_le16(pb);
|
|
803 get_le16(pb);
|
|
804 get_le16(pb);
|
|
805 get_byte(pb);
|
|
806 /* Check for FLV1 */
|
|
807 codec_id = codec_get_id(swf_codec_tags, get_byte(pb));
|
|
808 if ( codec_id ) {
|
|
809 vst = av_new_stream(s, 0);
|
|
810 av_set_pts_info(vst, 24, 1, 1000); /* 24 bit pts in ms */
|
|
811
|
|
812 vst->codec->codec_type = CODEC_TYPE_VIDEO;
|
|
813 vst->codec->codec_id = codec_id;
|
|
814 if ( swf->samples_per_frame ) {
|
|
815 vst->codec->time_base.den = 1000. / swf->ms_per_frame;
|
|
816 vst->codec->time_base.num = 1;
|
|
817 }
|
|
818 }
|
|
819 } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) {
|
|
820 /* streaming found */
|
|
821 get_byte(pb);
|
|
822 v = get_byte(pb);
|
|
823 swf->samples_per_frame = get_le16(pb);
|
|
824 if (len!=4)
|
|
825 url_fskip(pb,len-4);
|
|
826 /* if mp3 streaming found, OK */
|
|
827 if ((v & 0x20) != 0) {
|
|
828 if ( tag == TAG_STREAMHEAD2 ) {
|
|
829 get_le16(pb);
|
|
830 }
|
|
831 ast = av_new_stream(s, 1);
|
|
832 av_set_pts_info(ast, 24, 1, 1000); /* 24 bit pts in ms */
|
|
833 if (!ast)
|
|
834 return -ENOMEM;
|
|
835
|
|
836 if (v & 0x01)
|
|
837 ast->codec->channels = 2;
|
|
838 else
|
|
839 ast->codec->channels = 1;
|
|
840
|
|
841 switch((v>> 2) & 0x03) {
|
|
842 case 1:
|
|
843 ast->codec->sample_rate = 11025;
|
|
844 break;
|
|
845 case 2:
|
|
846 ast->codec->sample_rate = 22050;
|
|
847 break;
|
|
848 case 3:
|
|
849 ast->codec->sample_rate = 44100;
|
|
850 break;
|
|
851 default:
|
|
852 av_free(ast);
|
|
853 return AVERROR_IO;
|
|
854 }
|
|
855 ast->codec->codec_type = CODEC_TYPE_AUDIO;
|
|
856 ast->codec->codec_id = CODEC_ID_MP3;
|
|
857 }
|
|
858 } else {
|
|
859 url_fskip(pb, len);
|
|
860 }
|
|
861 }
|
|
862 url_fseek(pb, firstTagOff, SEEK_SET);
|
|
863
|
|
864 return 0;
|
|
865 }
|
|
866
|
|
867 static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|
868 {
|
|
869 SWFContext *swf = s->priv_data;
|
|
870 ByteIOContext *pb = &s->pb;
|
|
871 AVStream *st = 0;
|
|
872 int tag, len, i, frame;
|
|
873
|
|
874 for(;;) {
|
|
875 tag = get_swf_tag(pb, &len);
|
|
876 if (tag < 0)
|
|
877 return AVERROR_IO;
|
|
878 if (tag == TAG_VIDEOFRAME) {
|
|
879 for( i=0; i<s->nb_streams; i++ ) {
|
|
880 st = s->streams[i];
|
|
881 if (st->id == 0) {
|
|
882 if ( get_le16(pb) == swf->ch_id ) {
|
|
883 frame = get_le16(pb);
|
|
884 av_get_packet(pb, pkt, len-4);
|
|
885 pkt->pts = frame * swf->ms_per_frame;
|
|
886 pkt->stream_index = st->index;
|
|
887 return pkt->size;
|
|
888 } else {
|
|
889 url_fskip(pb, len-2);
|
|
890 continue;
|
|
891 }
|
|
892 }
|
|
893 }
|
|
894 url_fskip(pb, len);
|
|
895 } else if (tag == TAG_STREAMBLOCK) {
|
|
896 for( i=0; i<s->nb_streams; i++ ) {
|
|
897 st = s->streams[i];
|
|
898 if (st->id == 1) {
|
|
899 av_get_packet(pb, pkt, len);
|
|
900 pkt->stream_index = st->index;
|
|
901 return pkt->size;
|
|
902 }
|
|
903 }
|
|
904 url_fskip(pb, len);
|
|
905 } else {
|
|
906 url_fskip(pb, len);
|
|
907 }
|
|
908 }
|
|
909 return 0;
|
|
910 }
|
|
911
|
|
912 static int swf_read_close(AVFormatContext *s)
|
|
913 {
|
|
914 return 0;
|
|
915 }
|
|
916
|
|
917 #ifdef CONFIG_SWF_DEMUXER
|
|
918 AVInputFormat swf_demuxer = {
|
|
919 "swf",
|
|
920 "Flash format",
|
|
921 sizeof(SWFContext),
|
|
922 swf_probe,
|
|
923 swf_read_header,
|
|
924 swf_read_packet,
|
|
925 swf_read_close,
|
|
926 };
|
|
927 #endif
|
|
928 #ifdef CONFIG_SWF_MUXER
|
|
929 AVOutputFormat swf_muxer = {
|
|
930 "swf",
|
|
931 "Flash format",
|
|
932 "application/x-shockwave-flash",
|
|
933 "swf",
|
|
934 sizeof(SWFContext),
|
|
935 CODEC_ID_MP3,
|
|
936 CODEC_ID_FLV1,
|
|
937 swf_write_header,
|
|
938 swf_write_packet,
|
|
939 swf_write_trailer,
|
|
940 };
|
|
941 #endif
|