cosmetics, indentation
[libav.git] / libavformat / swf.c
CommitLineData
de6d9b64
FB
1/*
2 * Flash Compatible Streaming Format
17269bdf 3 * Copyright (c) 2000 Fabrice Bellard.
747a0554 4 * Copyright (c) 2003 Tinic Uro.
de6d9b64 5 *
b78e7197
DB
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
17269bdf
FB
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
b78e7197 11 * version 2.1 of the License, or (at your option) any later version.
de6d9b64 12 *
b78e7197 13 * FFmpeg is distributed in the hope that it will be useful,
de6d9b64 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17269bdf
FB
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
de6d9b64 17 *
17269bdf 18 * You should have received a copy of the GNU Lesser General Public
b78e7197 19 * License along with FFmpeg; if not, write to the Free Software
5509bffa 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
de6d9b64 21 */
de6d9b64 22#include "avformat.h"
2de7795a 23#include "bitstream.h"
5ce117c3 24#include "riff.h" /* for CodecTag */
de6d9b64 25
de6d9b64
FB
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
98d82b22 36#define TAG_STREAMHEAD 18
de6d9b64
FB
37#define TAG_STREAMBLOCK 19
38#define TAG_JPEG2 21
747a0554
TU
39#define TAG_PLACEOBJECT2 26
40#define TAG_STREAMHEAD2 45
bb270c08 41#define TAG_VIDEOSTREAM 60
747a0554 42#define TAG_VIDEOFRAME 61
de6d9b64
FB
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
747a0554
TU
51#define AUDIO_FIFO_SIZE 65536
52
de6d9b64
FB
53/* character id used */
54#define BITMAP_ID 0
747a0554 55#define VIDEO_ID 0
de6d9b64
FB
56#define SHAPE_ID 1
57
14a68b89
MN
58#undef NDEBUG
59#include <assert.h>
747a0554 60
de6d9b64 61typedef struct {
5b1e5dce 62 int audio_stream_index;
8be1c656
FB
63 offset_t duration_pos;
64 offset_t tag_pos;
115329f1 65
747a0554
TU
66 int samples_per_frame;
67 int sound_samples;
747a0554
TU
68 int swf_frame_number;
69 int video_frame_number;
b912ef3f 70 int frame_rate;
de6d9b64 71 int tag;
747a0554 72
013e0a8f 73 uint8_t audio_fifo[AUDIO_FIFO_SIZE];
747a0554 74 int audio_in_pos;
747a0554
TU
75
76 int video_type;
77 int audio_type;
de6d9b64
FB
78} SWFContext;
79
7caf0cc6 80static const AVCodecTag swf_codec_tags[] = {
5ce117c3
AJ
81 {CODEC_ID_FLV1, 0x02},
82 {CODEC_ID_VP6F, 0x04},
83 {0, 0},
84};
85
dd8a46d9
BC
86static const AVCodecTag swf_audio_codec_tags[] = {
87 {CODEC_ID_PCM_S16LE, 0x00},
88 {CODEC_ID_ADPCM_SWF, 0x01},
89 {CODEC_ID_MP3, 0x02},
90 {CODEC_ID_PCM_S16LE, 0x03},
91 //{CODEC_ID_NELLYMOSER, 0x06},
92 {0, 0},
93};
94
a9e35095 95#ifdef CONFIG_MUXERS
de6d9b64
FB
96static void put_swf_tag(AVFormatContext *s, int tag)
97{
98 SWFContext *swf = s->priv_data;
99 ByteIOContext *pb = &s->pb;
100
101 swf->tag_pos = url_ftell(pb);
102 swf->tag = tag;
103 /* reserve some room for the tag */
104 if (tag & TAG_LONG) {
105 put_le16(pb, 0);
106 put_le32(pb, 0);
107 } else {
108 put_le16(pb, 0);
109 }
110}
111
112static void put_swf_end_tag(AVFormatContext *s)
113{
114 SWFContext *swf = s->priv_data;
115 ByteIOContext *pb = &s->pb;
8be1c656 116 offset_t pos;
de6d9b64
FB
117 int tag_len, tag;
118
119 pos = url_ftell(pb);
120 tag_len = pos - swf->tag_pos - 2;
121 tag = swf->tag;
122 url_fseek(pb, swf->tag_pos, SEEK_SET);
123 if (tag & TAG_LONG) {
124 tag &= ~TAG_LONG;
125 put_le16(pb, (tag << 6) | 0x3f);
126 put_le32(pb, tag_len - 4);
127 } else {
128 assert(tag_len < 0x3f);
129 put_le16(pb, (tag << 6) | tag_len);
130 }
131 url_fseek(pb, pos, SEEK_SET);
132}
133
134static inline void max_nbits(int *nbits_ptr, int val)
135{
136 int n;
137
138 if (val == 0)
139 return;
140 val = abs(val);
141 n = 1;
142 while (val != 0) {
143 n++;
144 val >>= 1;
145 }
146 if (n > *nbits_ptr)
147 *nbits_ptr = n;
148}
149
115329f1 150static void put_swf_rect(ByteIOContext *pb,
de6d9b64
FB
151 int xmin, int xmax, int ymin, int ymax)
152{
153 PutBitContext p;
0c1a9eda 154 uint8_t buf[256];
de6d9b64
FB
155 int nbits, mask;
156
117a5490 157 init_put_bits(&p, buf, sizeof(buf));
115329f1 158
de6d9b64
FB
159 nbits = 0;
160 max_nbits(&nbits, xmin);
161 max_nbits(&nbits, xmax);
162 max_nbits(&nbits, ymin);
163 max_nbits(&nbits, ymax);
164 mask = (1 << nbits) - 1;
165
166 /* rectangle info */
167 put_bits(&p, 5, nbits);
168 put_bits(&p, nbits, xmin & mask);
169 put_bits(&p, nbits, xmax & mask);
170 put_bits(&p, nbits, ymin & mask);
171 put_bits(&p, nbits, ymax & mask);
115329f1 172
de6d9b64 173 flush_put_bits(&p);
17592475 174 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
de6d9b64
FB
175}
176
177static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
178{
179 int nbits, mask;
180
181 put_bits(pb, 1, 1); /* edge */
182 put_bits(pb, 1, 1); /* line select */
183 nbits = 2;
184 max_nbits(&nbits, dx);
185 max_nbits(&nbits, dy);
186
187 mask = (1 << nbits) - 1;
188 put_bits(pb, 4, nbits - 2); /* 16 bits precision */
189 if (dx == 0) {
c78ed542
BC
190 put_bits(pb, 1, 0);
191 put_bits(pb, 1, 1);
192 put_bits(pb, nbits, dy & mask);
de6d9b64 193 } else if (dy == 0) {
c78ed542
BC
194 put_bits(pb, 1, 0);
195 put_bits(pb, 1, 0);
196 put_bits(pb, nbits, dx & mask);
de6d9b64 197 } else {
c78ed542
BC
198 put_bits(pb, 1, 1);
199 put_bits(pb, nbits, dx & mask);
200 put_bits(pb, nbits, dy & mask);
de6d9b64
FB
201 }
202}
203
204#define FRAC_BITS 16
205
747a0554 206/* put matrix */
de6d9b64
FB
207static void put_swf_matrix(ByteIOContext *pb,
208 int a, int b, int c, int d, int tx, int ty)
209{
210 PutBitContext p;
0c1a9eda 211 uint8_t buf[256];
747a0554 212 int nbits;
de6d9b64 213
117a5490 214 init_put_bits(&p, buf, sizeof(buf));
115329f1 215
de6d9b64 216 put_bits(&p, 1, 1); /* a, d present */
747a0554
TU
217 nbits = 1;
218 max_nbits(&nbits, a);
219 max_nbits(&nbits, d);
220 put_bits(&p, 5, nbits); /* nb bits */
221 put_bits(&p, nbits, a);
222 put_bits(&p, nbits, d);
115329f1 223
de6d9b64 224 put_bits(&p, 1, 1); /* b, c present */
747a0554
TU
225 nbits = 1;
226 max_nbits(&nbits, c);
227 max_nbits(&nbits, b);
228 put_bits(&p, 5, nbits); /* nb bits */
229 put_bits(&p, nbits, c);
230 put_bits(&p, nbits, b);
231
232 nbits = 1;
233 max_nbits(&nbits, tx);
234 max_nbits(&nbits, ty);
235 put_bits(&p, 5, nbits); /* nb bits */
236 put_bits(&p, nbits, tx);
237 put_bits(&p, nbits, ty);
de6d9b64
FB
238
239 flush_put_bits(&p);
17592475 240 put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
de6d9b64
FB
241}
242
747a0554 243/* */
de6d9b64
FB
244static int swf_write_header(AVFormatContext *s)
245{
fed7d067 246 SWFContext *swf = s->priv_data;
de6d9b64
FB
247 ByteIOContext *pb = &s->pb;
248 AVCodecContext *enc, *audio_enc, *video_enc;
249 PutBitContext p;
0c1a9eda 250 uint8_t buf1[256];
14bea432 251 int i, width, height, rate, rate_base;
de6d9b64 252
747a0554 253 swf->audio_in_pos = 0;
747a0554 254 swf->sound_samples = 0;
747a0554
TU
255 swf->swf_frame_number = 0;
256 swf->video_frame_number = 0;
747a0554 257
de6d9b64
FB
258 video_enc = NULL;
259 audio_enc = NULL;
260 for(i=0;i<s->nb_streams;i++) {
01f4895c 261 enc = s->streams[i]->codec;
013e0a8f
BC
262 if (enc->codec_type == CODEC_TYPE_AUDIO) {
263 if (enc->codec_id == CODEC_ID_MP3) {
264 if (!enc->frame_size) {
265 av_log(s, AV_LOG_ERROR, "audio frame size not set\n");
266 return -1;
267 }
268 audio_enc = enc;
269 } else {
5095aaa9 270 av_log(s, AV_LOG_ERROR, "SWF muxer only supports MP3\n");
013e0a8f
BC
271 return -1;
272 }
273 } else {
5ce117c3
AJ
274 if ( enc->codec_id == CODEC_ID_VP6F ||
275 enc->codec_id == CODEC_ID_FLV1 ||
276 enc->codec_id == CODEC_ID_MJPEG ) {
747a0554
TU
277 video_enc = enc;
278 } else {
5095aaa9 279 av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n");
747a0554
TU
280 return -1;
281 }
282 }
de6d9b64
FB
283 }
284
285 if (!video_enc) {
df3a80b5 286 /* currently, cannot work correctly if audio only */
747a0554 287 swf->video_type = 0;
de6d9b64
FB
288 width = 320;
289 height = 200;
14bea432
MN
290 rate = 10;
291 rate_base= 1;
de6d9b64 292 } else {
747a0554 293 swf->video_type = video_enc->codec_id;
de6d9b64
FB
294 width = video_enc->width;
295 height = video_enc->height;
c0df9d75
MN
296 rate = video_enc->time_base.den;
297 rate_base = video_enc->time_base.num;
de6d9b64
FB
298 }
299
747a0554
TU
300 if (!audio_enc ) {
301 swf->audio_type = 0;
302 swf->samples_per_frame = ( 44100. * rate_base ) / rate;
303 } else {
304 swf->audio_type = audio_enc->codec_id;
305 swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate;
306 }
307
de6d9b64 308 put_tag(pb, "FWS");
5ce117c3
AJ
309 if ( video_enc && video_enc->codec_id == CODEC_ID_VP6F ) {
310 put_byte(pb, 8); /* version (version 8 and above support VP6 codec) */
311 } else if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) {
747a0554
TU
312 put_byte(pb, 6); /* version (version 6 and above support FLV1 codec) */
313 } else {
314 put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */
315 }
115329f1
DB
316 put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
317 (will be patched if not streamed) */
de6d9b64 318
747a0554 319 put_swf_rect(pb, 0, width * 20, 0, height * 20);
14bea432 320 put_le16(pb, (rate * 256) / rate_base); /* frame rate */
de6d9b64 321 swf->duration_pos = url_ftell(pb);
14bea432 322 put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */
115329f1 323
de6d9b64 324 /* define a shape with the jpeg inside */
5ce117c3
AJ
325 if ( video_enc && (video_enc->codec_id == CODEC_ID_VP6F ||
326 video_enc->codec_id == CODEC_ID_FLV1 )) {
747a0554
TU
327 } else if ( video_enc && video_enc->codec_id == CODEC_ID_MJPEG ) {
328 put_swf_tag(s, TAG_DEFINESHAPE);
329
330 put_le16(pb, SHAPE_ID); /* ID of shape */
331 /* bounding rectangle */
332 put_swf_rect(pb, 0, width, 0, height);
333 /* style info */
334 put_byte(pb, 1); /* one fill style */
335 put_byte(pb, 0x41); /* clipped bitmap fill */
336 put_le16(pb, BITMAP_ID); /* bitmap ID */
337 /* position of the bitmap */
115329f1 338 put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
c78ed542 339 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
747a0554 340 put_byte(pb, 0); /* no line style */
115329f1 341
747a0554
TU
342 /* shape drawing */
343 init_put_bits(&p, buf1, sizeof(buf1));
344 put_bits(&p, 4, 1); /* one fill bit */
345 put_bits(&p, 4, 0); /* zero line bit */
115329f1 346
747a0554
TU
347 put_bits(&p, 1, 0); /* not an edge */
348 put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
349 put_bits(&p, 5, 1); /* nbits */
350 put_bits(&p, 1, 0); /* X */
351 put_bits(&p, 1, 0); /* Y */
352 put_bits(&p, 1, 1); /* set fill style 1 */
115329f1 353
747a0554
TU
354 /* draw the rectangle ! */
355 put_swf_line_edge(&p, width, 0);
356 put_swf_line_edge(&p, 0, height);
357 put_swf_line_edge(&p, -width, 0);
358 put_swf_line_edge(&p, 0, -height);
115329f1 359
747a0554
TU
360 /* end of shape */
361 put_bits(&p, 1, 0); /* not an edge */
362 put_bits(&p, 5, 0);
de6d9b64 363
747a0554
TU
364 flush_put_bits(&p);
365 put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
de6d9b64 366
747a0554
TU
367 put_swf_end_tag(s);
368 }
115329f1 369
747a0554 370 if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) {
de6d9b64
FB
371 int v;
372
373 /* start sound */
747a0554 374 put_swf_tag(s, TAG_STREAMHEAD2);
de6d9b64
FB
375
376 v = 0;
377 switch(audio_enc->sample_rate) {
378 case 11025:
379 v |= 1 << 2;
380 break;
381 case 22050:
382 v |= 2 << 2;
383 break;
384 case 44100:
385 v |= 3 << 2;
386 break;
387 default:
388 /* not supported */
755bfeab 389 av_log(s, AV_LOG_ERROR, "swf does not support that sample rate, choose from (44100, 22050, 11025).\n");
de6d9b64
FB
390 return -1;
391 }
747a0554 392 v |= 0x02; /* 16 bit playback */
de6d9b64 393 if (audio_enc->channels == 2)
747a0554
TU
394 v |= 0x01; /* stereo playback */
395 put_byte(&s->pb, v);
de6d9b64 396 v |= 0x20; /* mp3 compressed */
de6d9b64 397 put_byte(&s->pb, v);
747a0554
TU
398 put_le16(&s->pb, swf->samples_per_frame); /* avg samples per frame */
399 put_le16(&s->pb, 0);
115329f1 400
de6d9b64
FB
401 put_swf_end_tag(s);
402 }
403
404 put_flush_packet(&s->pb);
405 return 0;
406}
407
115329f1 408static int swf_write_video(AVFormatContext *s,
49057904 409 AVCodecContext *enc, const uint8_t *buf, int size)
de6d9b64 410{
747a0554 411 SWFContext *swf = s->priv_data;
de6d9b64 412 ByteIOContext *pb = &s->pb;
115329f1 413
747a0554 414 /* Flash Player limit */
d3e18ad0 415 if ( swf->swf_frame_number == 16000 ) {
bc874dae 416 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
de6d9b64
FB
417 }
418
c78ed542
BC
419 if ( swf->video_type == CODEC_ID_VP6F ||
420 swf->video_type == CODEC_ID_FLV1 ) {
421 if ( swf->video_frame_number == 0 ) {
422 /* create a new video object */
423 put_swf_tag(s, TAG_VIDEOSTREAM);
424 put_le16(pb, VIDEO_ID);
425 put_le16(pb, 15000 ); /* hard flash player limit */
426 put_le16(pb, enc->width);
427 put_le16(pb, enc->height);
428 put_byte(pb, 0);
429 put_byte(pb,codec_get_tag(swf_codec_tags,swf->video_type));
430 put_swf_end_tag(s);
431
432 /* place the video object for the first time */
433 put_swf_tag(s, TAG_PLACEOBJECT2);
434 put_byte(pb, 0x36);
435 put_le16(pb, 1);
436 put_le16(pb, VIDEO_ID);
437 put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
438 put_le16(pb, swf->video_frame_number );
439 put_byte(pb, 'v');
440 put_byte(pb, 'i');
441 put_byte(pb, 'd');
442 put_byte(pb, 'e');
443 put_byte(pb, 'o');
444 put_byte(pb, 0x00);
445 put_swf_end_tag(s);
446 } else {
447 /* mark the character for update */
448 put_swf_tag(s, TAG_PLACEOBJECT2);
449 put_byte(pb, 0x11);
450 put_le16(pb, 1);
451 put_le16(pb, swf->video_frame_number );
452 put_swf_end_tag(s);
453 }
115329f1 454
c78ed542
BC
455 /* set video frame data */
456 put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);
457 put_le16(pb, VIDEO_ID);
458 put_le16(pb, swf->video_frame_number++ );
459 put_buffer(pb, buf, size);
460 put_swf_end_tag(s);
461 } else if ( swf->video_type == CODEC_ID_MJPEG ) {
462 if (swf->swf_frame_number > 0) {
463 /* remove the shape */
464 put_swf_tag(s, TAG_REMOVEOBJECT);
465 put_le16(pb, SHAPE_ID); /* shape ID */
466 put_le16(pb, 1); /* depth */
467 put_swf_end_tag(s);
468
469 /* free the bitmap */
470 put_swf_tag(s, TAG_FREECHARACTER);
471 put_le16(pb, BITMAP_ID);
472 put_swf_end_tag(s);
473 }
115329f1 474
c78ed542 475 put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
115329f1 476
c78ed542 477 put_le16(pb, BITMAP_ID); /* ID of the image */
115329f1 478
c78ed542
BC
479 /* a dummy jpeg header seems to be required */
480 put_byte(pb, 0xff);
481 put_byte(pb, 0xd8);
482 put_byte(pb, 0xff);
483 put_byte(pb, 0xd9);
484 /* write the jpeg image */
485 put_buffer(pb, buf, size);
115329f1 486
c78ed542 487 put_swf_end_tag(s);
115329f1 488
c78ed542 489 /* draw the shape */
115329f1 490
c78ed542
BC
491 put_swf_tag(s, TAG_PLACEOBJECT);
492 put_le16(pb, SHAPE_ID); /* shape ID */
493 put_le16(pb, 1); /* depth */
494 put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0);
495 put_swf_end_tag(s);
496 } else {
497 /* invalid codec */
498 }
115329f1 499
c78ed542 500 swf->swf_frame_number ++;
de6d9b64 501
747a0554 502 /* streaming sound always should be placed just before showframe tags */
013e0a8f 503 if (swf->audio_type && swf->audio_in_pos) {
747a0554 504 put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
013e0a8f
BC
505 put_le16(pb, swf->sound_samples);
506 put_le16(pb, 0); // seek samples
507 put_buffer(pb, swf->audio_fifo, swf->audio_in_pos);
747a0554 508 put_swf_end_tag(s);
115329f1 509
747a0554 510 /* update FIFO */
013e0a8f
BC
511 swf->sound_samples = 0;
512 swf->audio_in_pos = 0;
747a0554
TU
513 }
514
de6d9b64
FB
515 /* output the frame */
516 put_swf_tag(s, TAG_SHOWFRAME);
517 put_swf_end_tag(s);
115329f1 518
de6d9b64 519 put_flush_packet(&s->pb);
115329f1 520
de6d9b64
FB
521 return 0;
522}
523
115329f1 524static int swf_write_audio(AVFormatContext *s,
747a0554 525 AVCodecContext *enc, const uint8_t *buf, int size)
de6d9b64 526{
747a0554 527 SWFContext *swf = s->priv_data;
de6d9b64 528
747a0554 529 /* Flash Player limit */
d3e18ad0 530 if ( swf->swf_frame_number == 16000 ) {
bc874dae 531 av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
747a0554
TU
532 }
533
013e0a8f
BC
534 if (swf->audio_in_pos + size >= AUDIO_FIFO_SIZE) {
535 av_log(s, AV_LOG_ERROR, "audio fifo too small to mux audio essence\n");
536 return -1;
747a0554
TU
537 }
538
013e0a8f
BC
539 memcpy(swf->audio_fifo + swf->audio_in_pos, buf, size);
540 swf->audio_in_pos += size;
541 swf->sound_samples += enc->frame_size;
542
747a0554
TU
543 /* if audio only stream make sure we add swf frames */
544 if ( swf->video_type == 0 ) {
545 swf_write_video(s, enc, 0, 0);
546 }
de6d9b64 547
de6d9b64
FB
548 return 0;
549}
550
e928649b 551static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)
de6d9b64 552{
01f4895c 553 AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
de6d9b64 554 if (codec->codec_type == CODEC_TYPE_AUDIO)
e928649b 555 return swf_write_audio(s, codec, pkt->data, pkt->size);
de6d9b64 556 else
e928649b 557 return swf_write_video(s, codec, pkt->data, pkt->size);
de6d9b64
FB
558}
559
560static int swf_write_trailer(AVFormatContext *s)
561{
562 SWFContext *swf = s->priv_data;
563 ByteIOContext *pb = &s->pb;
564 AVCodecContext *enc, *video_enc;
565 int file_size, i;
566
567 video_enc = NULL;
568 for(i=0;i<s->nb_streams;i++) {
01f4895c 569 enc = s->streams[i]->codec;
de6d9b64
FB
570 if (enc->codec_type == CODEC_TYPE_VIDEO)
571 video_enc = enc;
572 }
573
574 put_swf_tag(s, TAG_END);
575 put_swf_end_tag(s);
115329f1 576
de6d9b64
FB
577 put_flush_packet(&s->pb);
578
579 /* patch file size and number of frames if not streamed */
580 if (!url_is_streamed(&s->pb) && video_enc) {
581 file_size = url_ftell(pb);
582 url_fseek(pb, 4, SEEK_SET);
583 put_le32(pb, file_size);
584 url_fseek(pb, swf->duration_pos, SEEK_SET);
585 put_le16(pb, video_enc->frame_number);
3439dc95 586 url_fseek(pb, file_size, SEEK_SET);
de6d9b64 587 }
de6d9b64
FB
588 return 0;
589}
a9e35095 590#endif //CONFIG_MUXERS
de6d9b64 591
747a0554
TU
592/*********************************************/
593/* Extract FLV encoded frame and MP3 from swf
594 Note that the detection of the real frame
595 is inaccurate at this point as it can be
115329f1 596 quite tricky to determine, you almost certainly
747a0554 597 will get a bad audio/video sync */
de6d9b64
FB
598
599static int get_swf_tag(ByteIOContext *pb, int *len_ptr)
600{
601 int tag, len;
115329f1 602
de6d9b64
FB
603 if (url_feof(pb))
604 return -1;
605
606 tag = get_le16(pb);
607 len = tag & 0x3f;
608 tag = tag >> 6;
609 if (len == 0x3f) {
610 len = get_le32(pb);
611 }
e227d197 612// av_log(NULL, AV_LOG_DEBUG, "Tag: %d - Len: %d\n", tag, len);
de6d9b64
FB
613 *len_ptr = len;
614 return tag;
615}
616
c9a65ca8
FB
617
618static int swf_probe(AVProbeData *p)
619{
620 /* check file header */
e227d197 621 if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
17269bdf 622 p->buf[2] == 'S')
c9a65ca8
FB
623 return AVPROBE_SCORE_MAX;
624 else
625 return 0;
626}
627
de6d9b64
FB
628static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap)
629{
2ab573cd 630 SWFContext *swf = s->priv_data;
de6d9b64 631 ByteIOContext *pb = &s->pb;
b912ef3f 632 int nbits, len, tag, v;
3922c59f 633 offset_t frame_offset = -1;
747a0554
TU
634 AVStream *ast = 0;
635 AVStream *vst = 0;
636
e227d197
AB
637 tag = get_be32(pb) & 0xffffff00;
638
639 if (tag == MKBETAG('C', 'W', 'S', 0))
640 {
bb270c08 641 av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
6f3e0b21 642 return AVERROR(EIO);
e227d197
AB
643 }
644 if (tag != MKBETAG('F', 'W', 'S', 0))
6f3e0b21 645 return AVERROR(EIO);
de6d9b64
FB
646 get_le32(pb);
647 /* skip rectangle size */
648 nbits = get_byte(pb) >> 3;
649 len = (4 * nbits - 3 + 7) / 8;
650 url_fskip(pb, len);
b912ef3f 651 swf->frame_rate = get_le16(pb); /* 8.8 fixed */
de6d9b64 652 get_le16(pb); /* frame count */
115329f1 653
747a0554 654 swf->samples_per_frame = 0;
c6f05d81
BC
655 s->ctx_flags |= AVFMTCTX_NOHEADER;
656 return 0;
657}
658
659static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
660{
661 SWFContext *swf = s->priv_data;
662 ByteIOContext *pb = &s->pb;
663 AVStream *vst = NULL, *ast = NULL, *st = 0;
664 int tag, len, i, frame, v;
747a0554 665
de6d9b64
FB
666 for(;;) {
667 tag = get_swf_tag(pb, &len);
c6f05d81
BC
668 if (tag < 0)
669 return AVERROR(EIO);
747a0554 670 if ( tag == TAG_VIDEOSTREAM && !vst) {
432cef76 671 int ch_id = get_le16(pb);
747a0554
TU
672 get_le16(pb);
673 get_le16(pb);
674 get_le16(pb);
675 get_byte(pb);
676 /* Check for FLV1 */
432cef76 677 vst = av_new_stream(s, ch_id);
b4bcf810
BC
678 vst->codec->codec_type = CODEC_TYPE_VIDEO;
679 vst->codec->codec_id = codec_get_id(swf_codec_tags, get_byte(pb));
c6f05d81
BC
680 av_set_pts_info(vst, 64, 256, swf->frame_rate);
681 vst->codec->time_base = (AVRational){ 256, swf->frame_rate };
682 len -= 10;
747a0554 683 } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) {
de6d9b64 684 /* streaming found */
8f36d4ba 685 int sample_rate_code;
de6d9b64
FB
686 get_byte(pb);
687 v = get_byte(pb);
747a0554 688 swf->samples_per_frame = get_le16(pb);
5b1e5dce 689 ast = av_new_stream(s, -1); /* -1 to avoid clash with video stream ch_id */
5b1e5dce 690 swf->audio_stream_index = ast->index;
ec54839a
BC
691 ast->codec->channels = 1 + (v&1);
692 ast->codec->codec_type = CODEC_TYPE_AUDIO;
dd8a46d9 693 ast->codec->codec_id = codec_get_id(swf_audio_codec_tags, (v>>4) & 15);
57004ff1 694 ast->need_parsing = AVSTREAM_PARSE_FULL;
8f36d4ba
BC
695 sample_rate_code= (v>>2) & 3;
696 if (!sample_rate_code)
6f3e0b21 697 return AVERROR(EIO);
8f36d4ba 698 ast->codec->sample_rate = 11025 << (sample_rate_code-1);
dc13d0b5 699 av_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
c6f05d81 700 len -= 4;
c78ed542 701 } else if (tag == TAG_VIDEOFRAME) {
432cef76 702 int ch_id = get_le16(pb);
655254f0 703 len -= 2;
747a0554 704 for( i=0; i<s->nb_streams; i++ ) {
bb270c08 705 st = s->streams[i];
432cef76
BC
706 if (st->codec->codec_type == CODEC_TYPE_VIDEO && st->id == ch_id) {
707 frame = get_le16(pb);
655254f0 708 av_get_packet(pb, pkt, len-2);
b912ef3f 709 pkt->pts = frame;
432cef76
BC
710 pkt->stream_index = st->index;
711 return pkt->size;
747a0554 712 }
115329f1 713 }
747a0554 714 } else if (tag == TAG_STREAMBLOCK) {
5b1e5dce
BC
715 st = s->streams[swf->audio_stream_index];
716 if (st->codec->codec_id == CODEC_ID_MP3) {
717 url_fskip(pb, 4);
718 av_get_packet(pb, pkt, len-4);
dd8a46d9
BC
719 } else { // ADPCM, PCM
720 av_get_packet(pb, pkt, len);
747a0554 721 }
dd8a46d9
BC
722 pkt->stream_index = st->index;
723 return pkt->size;
a0dc1ccd
BC
724 } else if (tag == TAG_JPEG2) {
725 for (i=0; i<s->nb_streams; i++) {
726 st = s->streams[i];
c6f05d81
BC
727 if (st->id == -2)
728 break;
729 }
730 if (i == s->nb_streams) {
731 vst = av_new_stream(s, -2); /* -2 to avoid clash with video stream and audio stream */
732 vst->codec->codec_type = CODEC_TYPE_VIDEO;
733 vst->codec->codec_id = CODEC_ID_MJPEG;
734 av_set_pts_info(vst, 64, 256, swf->frame_rate);
735 vst->codec->time_base = (AVRational){ 256, swf->frame_rate };
736 st = vst;
737 }
c78ed542
BC
738 get_le16(pb); /* BITMAP_ID */
739 av_new_packet(pkt, len-2);
740 get_buffer(pb, pkt->data, 4);
741 if (AV_RB32(pkt->data) == 0xffd8ffd9) {
742 /* old SWF files containing SOI/EOI as data start */
743 pkt->size -= 4;
744 get_buffer(pb, pkt->data, pkt->size);
745 } else {
746 get_buffer(pb, pkt->data + 4, pkt->size - 4);
747 }
748 pkt->stream_index = st->index;
749 return pkt->size;
de6d9b64 750 }
655254f0 751 url_fskip(pb, len);
de6d9b64
FB
752 }
753 return 0;
754}
755
756static int swf_read_close(AVFormatContext *s)
757{
c78ed542 758 return 0;
de6d9b64
FB
759}
760
ff70e601
MR
761#ifdef CONFIG_SWF_DEMUXER
762AVInputFormat swf_demuxer = {
c9a65ca8
FB
763 "swf",
764 "Flash format",
747a0554 765 sizeof(SWFContext),
c9a65ca8
FB
766 swf_probe,
767 swf_read_header,
768 swf_read_packet,
769 swf_read_close,
770};
ff70e601
MR
771#endif
772#ifdef CONFIG_SWF_MUXER
773AVOutputFormat swf_muxer = {
de6d9b64
FB
774 "swf",
775 "Flash format",
776 "application/x-shockwave-flash",
777 "swf",
c9a65ca8 778 sizeof(SWFContext),
747a0554
TU
779 CODEC_ID_MP3,
780 CODEC_ID_FLV1,
de6d9b64
FB
781 swf_write_header,
782 swf_write_packet,
783 swf_write_trailer,
de6d9b64 784};
ff70e601 785#endif