1 /*
2 * Flash Compatible Streaming Format muxer
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
23 #include "libavcodec/put_bits.h"
24 #include "libavutil/avassert.h"
25 #include "avformat.h"
26 #include "swf.h"
27
put_swf_tag(AVFormatContext * s,int tag)28 static void put_swf_tag(AVFormatContext *s, int tag)
29 {
30 SWFContext *swf = s->priv_data;
31 AVIOContext *pb = s->pb;
32
33 swf->tag_pos = avio_tell(pb);
34 swf->tag = tag;
35 /* reserve some room for the tag */
36 if (tag & TAG_LONG) {
37 avio_wl16(pb, 0);
38 avio_wl32(pb, 0);
39 } else {
40 avio_wl16(pb, 0);
41 }
42 }
43
put_swf_end_tag(AVFormatContext * s)44 static void put_swf_end_tag(AVFormatContext *s)
45 {
46 SWFContext *swf = s->priv_data;
47 AVIOContext *pb = s->pb;
48 int64_t pos;
49 int tag_len, tag;
50
51 pos = avio_tell(pb);
52 tag_len = pos - swf->tag_pos - 2;
53 tag = swf->tag;
54 avio_seek(pb, swf->tag_pos, SEEK_SET);
55 if (tag & TAG_LONG) {
56 tag &= ~TAG_LONG;
57 avio_wl16(pb, (tag << 6) | 0x3f);
58 avio_wl32(pb, tag_len - 4);
59 } else {
60 av_assert0(tag_len < 0x3f);
61 avio_wl16(pb, (tag << 6) | tag_len);
62 }
63 avio_seek(pb, pos, SEEK_SET);
64 }
65
max_nbits(int * nbits_ptr,int val)66 static inline void max_nbits(int *nbits_ptr, int val)
67 {
68 int n;
69
70 if (val == 0)
71 return;
72 val = FFABS(val);
73 n = 1;
74 while (val != 0) {
75 n++;
76 val >>= 1;
77 }
78 if (n > *nbits_ptr)
79 *nbits_ptr = n;
80 }
81
put_swf_rect(AVIOContext * pb,int xmin,int xmax,int ymin,int ymax)82 static void put_swf_rect(AVIOContext *pb,
83 int xmin, int xmax, int ymin, int ymax)
84 {
85 PutBitContext p;
86 uint8_t buf[256];
87 int nbits, mask;
88
89 init_put_bits(&p, buf, sizeof(buf));
90
91 nbits = 0;
92 max_nbits(&nbits, xmin);
93 max_nbits(&nbits, xmax);
94 max_nbits(&nbits, ymin);
95 max_nbits(&nbits, ymax);
96 mask = (1 << nbits) - 1;
97
98 /* rectangle info */
99 put_bits(&p, 5, nbits);
100 put_bits(&p, nbits, xmin & mask);
101 put_bits(&p, nbits, xmax & mask);
102 put_bits(&p, nbits, ymin & mask);
103 put_bits(&p, nbits, ymax & mask);
104
105 flush_put_bits(&p);
106 avio_write(pb, buf, put_bits_ptr(&p) - p.buf);
107 }
108
put_swf_line_edge(PutBitContext * pb,int dx,int dy)109 static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
110 {
111 int nbits, mask;
112
113 put_bits(pb, 1, 1); /* edge */
114 put_bits(pb, 1, 1); /* line select */
115 nbits = 2;
116 max_nbits(&nbits, dx);
117 max_nbits(&nbits, dy);
118
119 mask = (1 << nbits) - 1;
120 put_bits(pb, 4, nbits - 2); /* 16 bits precision */
121 if (dx == 0) {
122 put_bits(pb, 1, 0);
123 put_bits(pb, 1, 1);
124 put_bits(pb, nbits, dy & mask);
125 } else if (dy == 0) {
126 put_bits(pb, 1, 0);
127 put_bits(pb, 1, 0);
128 put_bits(pb, nbits, dx & mask);
129 } else {
130 put_bits(pb, 1, 1);
131 put_bits(pb, nbits, dx & mask);
132 put_bits(pb, nbits, dy & mask);
133 }
134 }
135
136 #define FRAC_BITS 16
137
put_swf_matrix(AVIOContext * pb,int a,int b,int c,int d,int tx,int ty)138 static void put_swf_matrix(AVIOContext *pb,
139 int a, int b, int c, int d, int tx, int ty)
140 {
141 PutBitContext p;
142 uint8_t buf[256];
143 int nbits;
144
145 init_put_bits(&p, buf, sizeof(buf));
146
147 put_bits(&p, 1, 1); /* a, d present */
148 nbits = 1;
149 max_nbits(&nbits, a);
150 max_nbits(&nbits, d);
151 put_bits(&p, 5, nbits); /* nb bits */
152 put_bits(&p, nbits, a);
153 put_bits(&p, nbits, d);
154
155 put_bits(&p, 1, 1); /* b, c present */
156 nbits = 1;
157 max_nbits(&nbits, c);
158 max_nbits(&nbits, b);
159 put_bits(&p, 5, nbits); /* nb bits */
160 put_bits(&p, nbits, c);
161 put_bits(&p, nbits, b);
162
163 nbits = 1;
164 max_nbits(&nbits, tx);
165 max_nbits(&nbits, ty);
166 put_bits(&p, 5, nbits); /* nb bits */
167 put_bits(&p, nbits, tx);
168 put_bits(&p, nbits, ty);
169
170 flush_put_bits(&p);
171 avio_write(pb, buf, put_bits_ptr(&p) - p.buf);
172 }
173
swf_write_header(AVFormatContext * s)174 static int swf_write_header(AVFormatContext *s)
175 {
176 SWFContext *swf = s->priv_data;
177 AVIOContext *pb = s->pb;
178 PutBitContext p;
179 uint8_t buf1[256];
180 int i, width, height, rate, rate_base;
181 int version;
182
183 swf->sound_samples = 0;
184 swf->swf_frame_number = 0;
185 swf->video_frame_number = 0;
186
187 for(i=0;i<s->nb_streams;i++) {
188 AVCodecParameters *par = s->streams[i]->codecpar;
189 if (par->codec_type == AVMEDIA_TYPE_AUDIO) {
190 if (swf->audio_par) {
191 av_log(s, AV_LOG_ERROR, "SWF muxer only supports 1 audio stream\n");
192 return AVERROR_INVALIDDATA;
193 }
194 if (par->codec_id == AV_CODEC_ID_MP3) {
195 swf->audio_par = par;
196 swf->audio_fifo= av_fifo_alloc(AUDIO_FIFO_SIZE);
197 if (!swf->audio_fifo)
198 return AVERROR(ENOMEM);
199 } else {
200 av_log(s, AV_LOG_ERROR, "SWF muxer only supports MP3\n");
201 return -1;
202 }
203 } else {
204 if (swf->video_par) {
205 av_log(s, AV_LOG_ERROR, "SWF muxer only supports 1 video stream\n");
206 return AVERROR_INVALIDDATA;
207 }
208 if (par->codec_id == AV_CODEC_ID_VP6F ||
209 par->codec_id == AV_CODEC_ID_FLV1 ||
210 par->codec_id == AV_CODEC_ID_MJPEG) {
211 swf->video_st = s->streams[i];
212 swf->video_par = par;
213 } else {
214 av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n");
215 return -1;
216 }
217 }
218 }
219
220 if (!swf->video_par) {
221 /* currently, cannot work correctly if audio only */
222 width = 320;
223 height = 200;
224 rate = 10;
225 rate_base= 1;
226 } else {
227 width = swf->video_par->width;
228 height = swf->video_par->height;
229 // TODO: should be avg_frame_rate
230 rate = swf->video_st->time_base.den;
231 rate_base = swf->video_st->time_base.num;
232 }
233
234 if (!swf->audio_par)
235 swf->samples_per_frame = (44100LL * rate_base) / rate;
236 else
237 swf->samples_per_frame = (swf->audio_par->sample_rate * rate_base) / rate;
238
239 avio_write(pb, "FWS", 3);
240
241 if (!strcmp("avm2", s->oformat->name))
242 version = 9;
243 else if (swf->video_par && swf->video_par->codec_id == AV_CODEC_ID_VP6F)
244 version = 8; /* version 8 and above support VP6 codec */
245 else if (swf->video_par && swf->video_par->codec_id == AV_CODEC_ID_FLV1)
246 version = 6; /* version 6 and above support FLV1 codec */
247 else
248 version = 4; /* version 4 for mpeg audio support */
249 avio_w8(pb, version);
250
251 avio_wl32(pb, DUMMY_FILE_SIZE); /* dummy size
252 (will be patched if not streamed) */
253
254 put_swf_rect(pb, 0, width * 20, 0, height * 20);
255 if ((rate * 256LL) / rate_base >= (1<<16)) {
256 av_log(s, AV_LOG_ERROR, "Invalid (too large) frame rate %d/%d\n", rate, rate_base);
257 return AVERROR(EINVAL);
258 }
259 avio_wl16(pb, (rate * 256LL) / rate_base); /* frame rate */
260 swf->duration_pos = avio_tell(pb);
261 avio_wl16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */
262
263 /* avm2/swf v9 (also v8?) files require a file attribute tag */
264 if (version == 9) {
265 put_swf_tag(s, TAG_FILEATTRIBUTES);
266 avio_wl32(pb, 1<<3); /* set ActionScript v3/AVM2 flag */
267 put_swf_end_tag(s);
268 }
269
270 /* define a shape with the jpeg inside */
271 if (swf->video_par && swf->video_par->codec_id == AV_CODEC_ID_MJPEG) {
272 put_swf_tag(s, TAG_DEFINESHAPE);
273
274 avio_wl16(pb, SHAPE_ID); /* ID of shape */
275 /* bounding rectangle */
276 put_swf_rect(pb, 0, width, 0, height);
277 /* style info */
278 avio_w8(pb, 1); /* one fill style */
279 avio_w8(pb, 0x41); /* clipped bitmap fill */
280 avio_wl16(pb, BITMAP_ID); /* bitmap ID */
281 /* position of the bitmap */
282 put_swf_matrix(pb, 1 << FRAC_BITS, 0,
283 0, 1 << FRAC_BITS, 0, 0);
284 avio_w8(pb, 0); /* no line style */
285
286 /* shape drawing */
287 init_put_bits(&p, buf1, sizeof(buf1));
288 put_bits(&p, 4, 1); /* one fill bit */
289 put_bits(&p, 4, 0); /* zero line bit */
290
291 put_bits(&p, 1, 0); /* not an edge */
292 put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
293 put_bits(&p, 5, 1); /* nbits */
294 put_bits(&p, 1, 0); /* X */
295 put_bits(&p, 1, 0); /* Y */
296 put_bits(&p, 1, 1); /* set fill style 1 */
297
298 /* draw the rectangle ! */
299 put_swf_line_edge(&p, width, 0);
300 put_swf_line_edge(&p, 0, height);
301 put_swf_line_edge(&p, -width, 0);
302 put_swf_line_edge(&p, 0, -height);
303
304 /* end of shape */
305 put_bits(&p, 1, 0); /* not an edge */
306 put_bits(&p, 5, 0);
307
308 flush_put_bits(&p);
309 avio_write(pb, buf1, put_bits_ptr(&p) - p.buf);
310
311 put_swf_end_tag(s);
312 }
313
314 if (swf->audio_par && swf->audio_par->codec_id == AV_CODEC_ID_MP3) {
315 int v = 0;
316
317 /* start sound */
318 put_swf_tag(s, TAG_STREAMHEAD2);
319 switch(swf->audio_par->sample_rate) {
320 case 11025: v |= 1 << 2; break;
321 case 22050: v |= 2 << 2; break;
322 case 44100: v |= 3 << 2; break;
323 default:
324 /* not supported */
325 av_log(s, AV_LOG_ERROR, "swf does not support that sample rate, choose from (44100, 22050, 11025).\n");
326 return -1;
327 }
328 v |= 0x02; /* 16 bit playback */
329 if (swf->audio_par->channels == 2)
330 v |= 0x01; /* stereo playback */
331 avio_w8(s->pb, v);
332 v |= 0x20; /* mp3 compressed */
333 avio_w8(s->pb, v);
334 avio_wl16(s->pb, swf->samples_per_frame); /* avg samples per frame */
335 avio_wl16(s->pb, 0);
336
337 put_swf_end_tag(s);
338 }
339
340 return 0;
341 }
342
swf_write_video(AVFormatContext * s,AVCodecParameters * par,const uint8_t * buf,int size)343 static int swf_write_video(AVFormatContext *s,
344 AVCodecParameters *par, const uint8_t *buf, int size)
345 {
346 SWFContext *swf = s->priv_data;
347 AVIOContext *pb = s->pb;
348
349 /* Flash Player limit */
350 if (swf->swf_frame_number == 16000)
351 av_log(s, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
352
353 if (par->codec_id == AV_CODEC_ID_VP6F ||
354 par->codec_id == AV_CODEC_ID_FLV1) {
355 if (swf->video_frame_number == 0) {
356 /* create a new video object */
357 put_swf_tag(s, TAG_VIDEOSTREAM);
358 avio_wl16(pb, VIDEO_ID);
359 swf->vframes_pos = avio_tell(pb);
360 avio_wl16(pb, 15000); /* hard flash player limit */
361 avio_wl16(pb, par->width);
362 avio_wl16(pb, par->height);
363 avio_w8(pb, 0);
364 avio_w8(pb,ff_codec_get_tag(ff_swf_codec_tags, par->codec_id));
365 put_swf_end_tag(s);
366
367 /* place the video object for the first time */
368 put_swf_tag(s, TAG_PLACEOBJECT2);
369 avio_w8(pb, 0x36);
370 avio_wl16(pb, 1);
371 avio_wl16(pb, VIDEO_ID);
372 put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
373 avio_wl16(pb, swf->video_frame_number);
374 avio_write(pb, "video", 5);
375 avio_w8(pb, 0x00);
376 put_swf_end_tag(s);
377 } else {
378 /* mark the character for update */
379 put_swf_tag(s, TAG_PLACEOBJECT2);
380 avio_w8(pb, 0x11);
381 avio_wl16(pb, 1);
382 avio_wl16(pb, swf->video_frame_number);
383 put_swf_end_tag(s);
384 }
385
386 /* set video frame data */
387 put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);
388 avio_wl16(pb, VIDEO_ID);
389 avio_wl16(pb, swf->video_frame_number++);
390 avio_write(pb, buf, size);
391 put_swf_end_tag(s);
392 } else if (par->codec_id == AV_CODEC_ID_MJPEG) {
393 if (swf->swf_frame_number > 0) {
394 /* remove the shape */
395 put_swf_tag(s, TAG_REMOVEOBJECT);
396 avio_wl16(pb, SHAPE_ID); /* shape ID */
397 avio_wl16(pb, 1); /* depth */
398 put_swf_end_tag(s);
399
400 /* free the bitmap */
401 put_swf_tag(s, TAG_FREECHARACTER);
402 avio_wl16(pb, BITMAP_ID);
403 put_swf_end_tag(s);
404 }
405
406 put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
407
408 avio_wl16(pb, BITMAP_ID); /* ID of the image */
409
410 /* a dummy jpeg header seems to be required */
411 avio_wb32(pb, 0xffd8ffd9);
412 /* write the jpeg image */
413 avio_write(pb, buf, size);
414
415 put_swf_end_tag(s);
416
417 /* draw the shape */
418
419 put_swf_tag(s, TAG_PLACEOBJECT);
420 avio_wl16(pb, SHAPE_ID); /* shape ID */
421 avio_wl16(pb, 1); /* depth */
422 put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0);
423 put_swf_end_tag(s);
424 }
425
426 swf->swf_frame_number++;
427
428 /* streaming sound always should be placed just before showframe tags */
429 if (swf->audio_par && av_fifo_size(swf->audio_fifo)) {
430 int frame_size = av_fifo_size(swf->audio_fifo);
431 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
432 avio_wl16(pb, swf->sound_samples);
433 avio_wl16(pb, 0); // seek samples
434 av_fifo_generic_read(swf->audio_fifo, pb, frame_size, (void*)avio_write);
435 put_swf_end_tag(s);
436
437 /* update FIFO */
438 swf->sound_samples = 0;
439 }
440
441 /* output the frame */
442 put_swf_tag(s, TAG_SHOWFRAME);
443 put_swf_end_tag(s);
444
445 return 0;
446 }
447
swf_write_audio(AVFormatContext * s,AVCodecParameters * par,uint8_t * buf,int size)448 static int swf_write_audio(AVFormatContext *s,
449 AVCodecParameters *par, uint8_t *buf, int size)
450 {
451 SWFContext *swf = s->priv_data;
452
453 /* Flash Player limit */
454 if (swf->swf_frame_number == 16000)
455 av_log(s, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
456
457 if (av_fifo_size(swf->audio_fifo) + size > AUDIO_FIFO_SIZE) {
458 av_log(s, AV_LOG_ERROR, "audio fifo too small to mux audio essence\n");
459 return -1;
460 }
461
462 av_fifo_generic_write(swf->audio_fifo, buf, size, NULL);
463 swf->sound_samples += av_get_audio_frame_duration2(par, size);
464
465 /* if audio only stream make sure we add swf frames */
466 if (!swf->video_par)
467 swf_write_video(s, par, 0, 0);
468
469 return 0;
470 }
471
swf_write_packet(AVFormatContext * s,AVPacket * pkt)472 static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)
473 {
474 AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar;
475 if (par->codec_type == AVMEDIA_TYPE_AUDIO)
476 return swf_write_audio(s, par, pkt->data, pkt->size);
477 else
478 return swf_write_video(s, par, pkt->data, pkt->size);
479 }
480
swf_write_trailer(AVFormatContext * s)481 static int swf_write_trailer(AVFormatContext *s)
482 {
483 SWFContext *swf = s->priv_data;
484 AVIOContext *pb = s->pb;
485 AVCodecParameters *par, *video_par;
486 int file_size, i;
487
488 video_par = NULL;
489 for(i=0;i<s->nb_streams;i++) {
490 par = s->streams[i]->codecpar;
491 if (par->codec_type == AVMEDIA_TYPE_VIDEO)
492 video_par = par;
493 else {
494 av_fifo_freep(&swf->audio_fifo);
495 }
496 }
497
498 put_swf_tag(s, TAG_END);
499 put_swf_end_tag(s);
500
501 /* patch file size and number of frames if not streamed */
502 if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && video_par) {
503 file_size = avio_tell(pb);
504 avio_seek(pb, 4, SEEK_SET);
505 avio_wl32(pb, file_size);
506 avio_seek(pb, swf->duration_pos, SEEK_SET);
507 avio_wl16(pb, swf->video_frame_number);
508 if (swf->vframes_pos) {
509 avio_seek(pb, swf->vframes_pos, SEEK_SET);
510 avio_wl16(pb, swf->video_frame_number);
511 }
512 avio_seek(pb, file_size, SEEK_SET);
513 }
514 return 0;
515 }
516
517 #if CONFIG_SWF_MUXER
518 AVOutputFormat ff_swf_muxer = {
519 .name = "swf",
520 .long_name = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash)"),
521 .mime_type = "application/x-shockwave-flash",
522 .extensions = "swf",
523 .priv_data_size = sizeof(SWFContext),
524 .audio_codec = AV_CODEC_ID_MP3,
525 .video_codec = AV_CODEC_ID_FLV1,
526 .write_header = swf_write_header,
527 .write_packet = swf_write_packet,
528 .write_trailer = swf_write_trailer,
529 .flags = AVFMT_TS_NONSTRICT,
530 };
531 #endif
532 #if CONFIG_AVM2_MUXER
533 AVOutputFormat ff_avm2_muxer = {
534 .name = "avm2",
535 .long_name = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash) (AVM2)"),
536 .mime_type = "application/x-shockwave-flash",
537 .priv_data_size = sizeof(SWFContext),
538 .audio_codec = AV_CODEC_ID_MP3,
539 .video_codec = AV_CODEC_ID_FLV1,
540 .write_header = swf_write_header,
541 .write_packet = swf_write_packet,
542 .write_trailer = swf_write_trailer,
543 .flags = AVFMT_TS_NONSTRICT,
544 };
545 #endif
546