swfenc.c 15.5 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1
/*
2
 * Flash Compatible Streaming Format muxer
3 4
 * Copyright (c) 2000 Fabrice Bellard
 * Copyright (c) 2003 Tinic Uro
Fabrice Bellard's avatar
Fabrice Bellard committed
5
 *
6 7 8
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
9 10
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
12
 *
13
 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
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
Fabrice Bellard's avatar
Fabrice Bellard committed
21
 */
22 23

#include "libavcodec/bitstream.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
24
#include "avformat.h"
Baptiste Coudurier's avatar
Baptiste Coudurier committed
25
#include "swf.h"
26

Fabrice Bellard's avatar
Fabrice Bellard committed
27 28 29
static void put_swf_tag(AVFormatContext *s, int tag)
{
    SWFContext *swf = s->priv_data;
30
    ByteIOContext *pb = s->pb;
Fabrice Bellard's avatar
Fabrice Bellard committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

    swf->tag_pos = url_ftell(pb);
    swf->tag = tag;
    /* reserve some room for the tag */
    if (tag & TAG_LONG) {
        put_le16(pb, 0);
        put_le32(pb, 0);
    } else {
        put_le16(pb, 0);
    }
}

static void put_swf_end_tag(AVFormatContext *s)
{
    SWFContext *swf = s->priv_data;
46
    ByteIOContext *pb = s->pb;
47
    int64_t pos;
Fabrice Bellard's avatar
Fabrice Bellard committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
    int tag_len, tag;

    pos = url_ftell(pb);
    tag_len = pos - swf->tag_pos - 2;
    tag = swf->tag;
    url_fseek(pb, swf->tag_pos, SEEK_SET);
    if (tag & TAG_LONG) {
        tag &= ~TAG_LONG;
        put_le16(pb, (tag << 6) | 0x3f);
        put_le32(pb, tag_len - 4);
    } else {
        assert(tag_len < 0x3f);
        put_le16(pb, (tag << 6) | tag_len);
    }
    url_fseek(pb, pos, SEEK_SET);
}

static inline void max_nbits(int *nbits_ptr, int val)
{
    int n;

    if (val == 0)
        return;
    val = abs(val);
    n = 1;
    while (val != 0) {
        n++;
        val >>= 1;
    }
    if (n > *nbits_ptr)
        *nbits_ptr = n;
}

81
static void put_swf_rect(ByteIOContext *pb,
Fabrice Bellard's avatar
Fabrice Bellard committed
82 83 84
                         int xmin, int xmax, int ymin, int ymax)
{
    PutBitContext p;
85
    uint8_t buf[256];
Fabrice Bellard's avatar
Fabrice Bellard committed
86 87
    int nbits, mask;

Alex Beregszaszi's avatar
Alex Beregszaszi committed
88
    init_put_bits(&p, buf, sizeof(buf));
89

Fabrice Bellard's avatar
Fabrice Bellard committed
90 91 92 93 94 95 96 97 98 99 100 101 102
    nbits = 0;
    max_nbits(&nbits, xmin);
    max_nbits(&nbits, xmax);
    max_nbits(&nbits, ymin);
    max_nbits(&nbits, ymax);
    mask = (1 << nbits) - 1;

    /* rectangle info */
    put_bits(&p, 5, nbits);
    put_bits(&p, nbits, xmin & mask);
    put_bits(&p, nbits, xmax & mask);
    put_bits(&p, nbits, ymin & mask);
    put_bits(&p, nbits, ymax & mask);
103

Fabrice Bellard's avatar
Fabrice Bellard committed
104
    flush_put_bits(&p);
105
    put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
Fabrice Bellard's avatar
Fabrice Bellard committed
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
}

static void put_swf_line_edge(PutBitContext *pb, int dx, int dy)
{
    int nbits, mask;

    put_bits(pb, 1, 1); /* edge */
    put_bits(pb, 1, 1); /* line select */
    nbits = 2;
    max_nbits(&nbits, dx);
    max_nbits(&nbits, dy);

    mask = (1 << nbits) - 1;
    put_bits(pb, 4, nbits - 2); /* 16 bits precision */
    if (dx == 0) {
121 122 123
        put_bits(pb, 1, 0);
        put_bits(pb, 1, 1);
        put_bits(pb, nbits, dy & mask);
Fabrice Bellard's avatar
Fabrice Bellard committed
124
    } else if (dy == 0) {
125 126 127
        put_bits(pb, 1, 0);
        put_bits(pb, 1, 0);
        put_bits(pb, nbits, dx & mask);
Fabrice Bellard's avatar
Fabrice Bellard committed
128
    } else {
129 130 131
        put_bits(pb, 1, 1);
        put_bits(pb, nbits, dx & mask);
        put_bits(pb, nbits, dy & mask);
Fabrice Bellard's avatar
Fabrice Bellard committed
132 133 134 135 136 137 138 139 140
    }
}

#define FRAC_BITS 16

static void put_swf_matrix(ByteIOContext *pb,
                           int a, int b, int c, int d, int tx, int ty)
{
    PutBitContext p;
141
    uint8_t buf[256];
142
    int nbits;
Fabrice Bellard's avatar
Fabrice Bellard committed
143

Alex Beregszaszi's avatar
Alex Beregszaszi committed
144
    init_put_bits(&p, buf, sizeof(buf));
145

Fabrice Bellard's avatar
Fabrice Bellard committed
146
    put_bits(&p, 1, 1); /* a, d present */
147 148 149 150 151 152
    nbits = 1;
    max_nbits(&nbits, a);
    max_nbits(&nbits, d);
    put_bits(&p, 5, nbits); /* nb bits */
    put_bits(&p, nbits, a);
    put_bits(&p, nbits, d);
153

Fabrice Bellard's avatar
Fabrice Bellard committed
154
    put_bits(&p, 1, 1); /* b, c present */
155 156 157 158 159 160 161 162 163 164 165 166 167
    nbits = 1;
    max_nbits(&nbits, c);
    max_nbits(&nbits, b);
    put_bits(&p, 5, nbits); /* nb bits */
    put_bits(&p, nbits, c);
    put_bits(&p, nbits, b);

    nbits = 1;
    max_nbits(&nbits, tx);
    max_nbits(&nbits, ty);
    put_bits(&p, 5, nbits); /* nb bits */
    put_bits(&p, nbits, tx);
    put_bits(&p, nbits, ty);
Fabrice Bellard's avatar
Fabrice Bellard committed
168 169

    flush_put_bits(&p);
170
    put_buffer(pb, buf, pbBufPtr(&p) - p.buf);
Fabrice Bellard's avatar
Fabrice Bellard committed
171 172 173 174
}

static int swf_write_header(AVFormatContext *s)
{
175
    SWFContext *swf = s->priv_data;
176
    ByteIOContext *pb = s->pb;
Fabrice Bellard's avatar
Fabrice Bellard committed
177
    PutBitContext p;
178
    uint8_t buf1[256];
179
    int i, width, height, rate, rate_base;
180
    int version;
Fabrice Bellard's avatar
Fabrice Bellard committed
181

182 183 184 185
    swf->sound_samples = 0;
    swf->swf_frame_number = 0;
    swf->video_frame_number = 0;

Fabrice Bellard's avatar
Fabrice Bellard committed
186
    for(i=0;i<s->nb_streams;i++) {
187
        AVCodecContext *enc = s->streams[i]->codec;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
188 189 190 191 192 193
        if (enc->codec_type == CODEC_TYPE_AUDIO) {
            if (enc->codec_id == CODEC_ID_MP3) {
                if (!enc->frame_size) {
                    av_log(s, AV_LOG_ERROR, "audio frame size not set\n");
                    return -1;
                }
194
                swf->audio_enc = enc;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
195
                av_fifo_init(&swf->audio_fifo, AUDIO_FIFO_SIZE);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
196
            } else {
197
                av_log(s, AV_LOG_ERROR, "SWF muxer only supports MP3\n");
Baptiste Coudurier's avatar
Baptiste Coudurier committed
198 199 200
                return -1;
            }
        } else {
201 202 203
            if (enc->codec_id == CODEC_ID_VP6F ||
                enc->codec_id == CODEC_ID_FLV1 ||
                enc->codec_id == CODEC_ID_MJPEG) {
204
                swf->video_enc = enc;
205
            } else {
206
                av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n");
207 208 209
                return -1;
            }
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
210 211
    }

212
    if (!swf->video_enc) {
213
        /* currently, cannot work correctly if audio only */
Fabrice Bellard's avatar
Fabrice Bellard committed
214 215
        width = 320;
        height = 200;
216 217
        rate = 10;
        rate_base= 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
218
    } else {
219 220 221 222
        width = swf->video_enc->width;
        height = swf->video_enc->height;
        rate = swf->video_enc->time_base.den;
        rate_base = swf->video_enc->time_base.num;
Fabrice Bellard's avatar
Fabrice Bellard committed
223 224
    }

225
    if (!swf->audio_enc)
226
        swf->samples_per_frame = (44100. * rate_base) / rate;
227 228
    else
        swf->samples_per_frame = (swf->audio_enc->sample_rate * rate_base) / rate;
229

Fabrice Bellard's avatar
Fabrice Bellard committed
230
    put_tag(pb, "FWS");
231 232 233

    if (!strcmp("avm2", s->oformat->name))
        version = 9;
234
    else if (swf->video_enc && swf->video_enc->codec_id == CODEC_ID_VP6F)
235
        version = 8; /* version 8 and above support VP6 codec */
236
    else if (swf->video_enc && swf->video_enc->codec_id == CODEC_ID_FLV1)
237
        version = 6; /* version 6 and above support FLV1 codec */
238
    else
239 240 241
        version = 4; /* version 4 for mpeg audio support */
    put_byte(pb, version);

242 243
    put_le32(pb, DUMMY_FILE_SIZE); /* dummy size
                                      (will be patched if not streamed) */
Fabrice Bellard's avatar
Fabrice Bellard committed
244

245
    put_swf_rect(pb, 0, width * 20, 0, height * 20);
246
    put_le16(pb, (rate * 256) / rate_base); /* frame rate */
Fabrice Bellard's avatar
Fabrice Bellard committed
247
    swf->duration_pos = url_ftell(pb);
248
    put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */
249

250
    /* avm2/swf v9 (also v8?) files require a file attribute tag */
251
    if (version == 9) {
252 253 254 255 256
        put_swf_tag(s, TAG_FILEATTRIBUTES);
        put_le32(pb, 1<<3); /* set ActionScript v3/AVM2 flag */
        put_swf_end_tag(s);
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
257
    /* define a shape with the jpeg inside */
258
    if (swf->video_enc && swf->video_enc->codec_id == CODEC_ID_MJPEG) {
259 260 261 262 263 264 265 266 267 268
        put_swf_tag(s, TAG_DEFINESHAPE);

        put_le16(pb, SHAPE_ID); /* ID of shape */
        /* bounding rectangle */
        put_swf_rect(pb, 0, width, 0, height);
        /* style info */
        put_byte(pb, 1); /* one fill style */
        put_byte(pb, 0x41); /* clipped bitmap fill */
        put_le16(pb, BITMAP_ID); /* bitmap ID */
        /* position of the bitmap */
269
        put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
270
                       0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
271
        put_byte(pb, 0); /* no line style */
272

273 274 275 276
        /* shape drawing */
        init_put_bits(&p, buf1, sizeof(buf1));
        put_bits(&p, 4, 1); /* one fill bit */
        put_bits(&p, 4, 0); /* zero line bit */
277

278 279 280 281 282 283
        put_bits(&p, 1, 0); /* not an edge */
        put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0);
        put_bits(&p, 5, 1); /* nbits */
        put_bits(&p, 1, 0); /* X */
        put_bits(&p, 1, 0); /* Y */
        put_bits(&p, 1, 1); /* set fill style 1 */
284

285 286 287 288 289
        /* draw the rectangle ! */
        put_swf_line_edge(&p, width, 0);
        put_swf_line_edge(&p, 0, height);
        put_swf_line_edge(&p, -width, 0);
        put_swf_line_edge(&p, 0, -height);
290

291 292 293
        /* end of shape */
        put_bits(&p, 1, 0); /* not an edge */
        put_bits(&p, 5, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
294

295 296
        flush_put_bits(&p);
        put_buffer(pb, buf1, pbBufPtr(&p) - p.buf);
Fabrice Bellard's avatar
Fabrice Bellard committed
297

298 299
        put_swf_end_tag(s);
    }
300

301
    if (swf->audio_enc && swf->audio_enc->codec_id == CODEC_ID_MP3) {
302
        int v = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
303 304

        /* start sound */
305
        put_swf_tag(s, TAG_STREAMHEAD2);
306
        switch(swf->audio_enc->sample_rate) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
307 308 309
        case 11025: v |= 1 << 2; break;
        case 22050: v |= 2 << 2; break;
        case 44100: v |= 3 << 2; break;
Fabrice Bellard's avatar
Fabrice Bellard committed
310 311
        default:
            /* not supported */
Diego Biurrun's avatar
Diego Biurrun committed
312
            av_log(s, AV_LOG_ERROR, "swf does not support that sample rate, choose from (44100, 22050, 11025).\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
313 314
            return -1;
        }
315
        v |= 0x02; /* 16 bit playback */
316
        if (swf->audio_enc->channels == 2)
317
            v |= 0x01; /* stereo playback */
318
        put_byte(s->pb, v);
Fabrice Bellard's avatar
Fabrice Bellard committed
319
        v |= 0x20; /* mp3 compressed */
320 321 322
        put_byte(s->pb, v);
        put_le16(s->pb, swf->samples_per_frame);  /* avg samples per frame */
        put_le16(s->pb, 0);
323

Fabrice Bellard's avatar
Fabrice Bellard committed
324 325 326
        put_swf_end_tag(s);
    }

327
    put_flush_packet(s->pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
328 329 330
    return 0;
}

331
static int swf_write_video(AVFormatContext *s,
332
                           AVCodecContext *enc, const uint8_t *buf, int size)
Fabrice Bellard's avatar
Fabrice Bellard committed
333
{
334
    SWFContext *swf = s->priv_data;
335
    ByteIOContext *pb = s->pb;
336

337
    /* Flash Player limit */
338
    if (swf->swf_frame_number == 16000)
339
        av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
340

341 342
    if (enc->codec_id == CODEC_ID_VP6F ||
        enc->codec_id == CODEC_ID_FLV1) {
343
        if (swf->video_frame_number == 0) {
344 345 346
            /* create a new video object */
            put_swf_tag(s, TAG_VIDEOSTREAM);
            put_le16(pb, VIDEO_ID);
347
            swf->vframes_pos = url_ftell(pb);
348
            put_le16(pb, 15000); /* hard flash player limit */
349 350 351
            put_le16(pb, enc->width);
            put_le16(pb, enc->height);
            put_byte(pb, 0);
352
            put_byte(pb,codec_get_tag(swf_codec_tags,enc->codec_id));
353 354 355 356 357 358 359 360
            put_swf_end_tag(s);

            /* place the video object for the first time */
            put_swf_tag(s, TAG_PLACEOBJECT2);
            put_byte(pb, 0x36);
            put_le16(pb, 1);
            put_le16(pb, VIDEO_ID);
            put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0);
361
            put_le16(pb, swf->video_frame_number);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
362
            put_tag(pb, "video");
363 364 365 366 367 368 369
            put_byte(pb, 0x00);
            put_swf_end_tag(s);
        } else {
            /* mark the character for update */
            put_swf_tag(s, TAG_PLACEOBJECT2);
            put_byte(pb, 0x11);
            put_le16(pb, 1);
370
            put_le16(pb, swf->video_frame_number);
371 372
            put_swf_end_tag(s);
        }
373

374 375 376
        /* set video frame data */
        put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);
        put_le16(pb, VIDEO_ID);
377
        put_le16(pb, swf->video_frame_number++);
378 379
        put_buffer(pb, buf, size);
        put_swf_end_tag(s);
380
    } else if (enc->codec_id == CODEC_ID_MJPEG) {
381 382 383 384 385 386 387 388 389 390 391 392
        if (swf->swf_frame_number > 0) {
            /* remove the shape */
            put_swf_tag(s, TAG_REMOVEOBJECT);
            put_le16(pb, SHAPE_ID); /* shape ID */
            put_le16(pb, 1); /* depth */
            put_swf_end_tag(s);

            /* free the bitmap */
            put_swf_tag(s, TAG_FREECHARACTER);
            put_le16(pb, BITMAP_ID);
            put_swf_end_tag(s);
        }
393

394
        put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
395

396
        put_le16(pb, BITMAP_ID); /* ID of the image */
397

398
        /* a dummy jpeg header seems to be required */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
399
        put_be32(pb, 0xffd8ffd9);
400 401
        /* write the jpeg image */
        put_buffer(pb, buf, size);
402

403
        put_swf_end_tag(s);
404

405
        /* draw the shape */
406

407 408 409 410 411 412
        put_swf_tag(s, TAG_PLACEOBJECT);
        put_le16(pb, SHAPE_ID); /* shape ID */
        put_le16(pb, 1); /* depth */
        put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0);
        put_swf_end_tag(s);
    }
413

Baptiste Coudurier's avatar
Baptiste Coudurier committed
414
    swf->swf_frame_number++;
Fabrice Bellard's avatar
Fabrice Bellard committed
415

416
    /* streaming sound always should be placed just before showframe tags */
417
    if (swf->audio_enc && av_fifo_size(&swf->audio_fifo)) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
418
        int frame_size = av_fifo_size(&swf->audio_fifo);
419
        put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
420 421
        put_le16(pb, swf->sound_samples);
        put_le16(pb, 0); // seek samples
Baptiste Coudurier's avatar
Baptiste Coudurier committed
422
        av_fifo_generic_read(&swf->audio_fifo, frame_size, &put_buffer, pb);
423
        put_swf_end_tag(s);
424

425
        /* update FIFO */
Baptiste Coudurier's avatar
Baptiste Coudurier committed
426
        swf->sound_samples = 0;
427 428
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
429 430 431
    /* output the frame */
    put_swf_tag(s, TAG_SHOWFRAME);
    put_swf_end_tag(s);
432

433
    put_flush_packet(s->pb);
434

Fabrice Bellard's avatar
Fabrice Bellard committed
435 436 437
    return 0;
}

438
static int swf_write_audio(AVFormatContext *s,
439
                           AVCodecContext *enc, const uint8_t *buf, int size)
Fabrice Bellard's avatar
Fabrice Bellard committed
440
{
441
    SWFContext *swf = s->priv_data;
Fabrice Bellard's avatar
Fabrice Bellard committed
442

443
    /* Flash Player limit */
444
    if (swf->swf_frame_number == 16000)
445
        av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n");
446

Baptiste Coudurier's avatar
Baptiste Coudurier committed
447
    if (av_fifo_size(&swf->audio_fifo) + size > AUDIO_FIFO_SIZE) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
448 449
        av_log(s, AV_LOG_ERROR, "audio fifo too small to mux audio essence\n");
        return -1;
450 451
    }

Baptiste Coudurier's avatar
Baptiste Coudurier committed
452
    av_fifo_generic_write(&swf->audio_fifo, buf, size, NULL);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
453 454
    swf->sound_samples += enc->frame_size;

455
    /* if audio only stream make sure we add swf frames */
456
    if (!swf->video_enc)
457
        swf_write_video(s, enc, 0, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
458 459 460 461

    return 0;
}

462
static int swf_write_packet(AVFormatContext *s, AVPacket *pkt)
Fabrice Bellard's avatar
Fabrice Bellard committed
463
{
464
    AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
465
    if (codec->codec_type == CODEC_TYPE_AUDIO)
466
        return swf_write_audio(s, codec, pkt->data, pkt->size);
Fabrice Bellard's avatar
Fabrice Bellard committed
467
    else
468
        return swf_write_video(s, codec, pkt->data, pkt->size);
Fabrice Bellard's avatar
Fabrice Bellard committed
469 470 471 472 473
}

static int swf_write_trailer(AVFormatContext *s)
{
    SWFContext *swf = s->priv_data;
474
    ByteIOContext *pb = s->pb;
Fabrice Bellard's avatar
Fabrice Bellard committed
475 476 477 478 479
    AVCodecContext *enc, *video_enc;
    int file_size, i;

    video_enc = NULL;
    for(i=0;i<s->nb_streams;i++) {
480
        enc = s->streams[i]->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed
481 482
        if (enc->codec_type == CODEC_TYPE_VIDEO)
            video_enc = enc;
Baptiste Coudurier's avatar
Baptiste Coudurier committed
483 484
        else
            av_fifo_free(&swf->audio_fifo);
Fabrice Bellard's avatar
Fabrice Bellard committed
485 486 487 488
    }

    put_swf_tag(s, TAG_END);
    put_swf_end_tag(s);
489

490
    put_flush_packet(s->pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
491 492

    /* patch file size and number of frames if not streamed */
493
    if (!url_is_streamed(s->pb) && video_enc) {
Fabrice Bellard's avatar
Fabrice Bellard committed
494 495 496 497
        file_size = url_ftell(pb);
        url_fseek(pb, 4, SEEK_SET);
        put_le32(pb, file_size);
        url_fseek(pb, swf->duration_pos, SEEK_SET);
498
        put_le16(pb, swf->video_frame_number);
499 500
        url_fseek(pb, swf->vframes_pos, SEEK_SET);
        put_le16(pb, swf->video_frame_number);
501
        url_fseek(pb, file_size, SEEK_SET);
Fabrice Bellard's avatar
Fabrice Bellard committed
502 503 504 505
    }
    return 0;
}

506
#if CONFIG_SWF_MUXER
507
AVOutputFormat swf_muxer = {
Fabrice Bellard's avatar
Fabrice Bellard committed
508
    "swf",
509
    NULL_IF_CONFIG_SMALL("Flash format"),
Fabrice Bellard's avatar
Fabrice Bellard committed
510 511
    "application/x-shockwave-flash",
    "swf",
Fabrice Bellard's avatar
Fabrice Bellard committed
512
    sizeof(SWFContext),
513 514
    CODEC_ID_MP3,
    CODEC_ID_FLV1,
Fabrice Bellard's avatar
Fabrice Bellard committed
515 516 517 518
    swf_write_header,
    swf_write_packet,
    swf_write_trailer,
};
519
#endif
520
#if CONFIG_AVM2_MUXER
521 522
AVOutputFormat avm2_muxer = {
    "avm2",
523
    NULL_IF_CONFIG_SMALL("Flash 9 (AVM2) format"),
524
    "application/x-shockwave-flash",
525
    NULL,
526 527 528 529 530 531 532 533
    sizeof(SWFContext),
    CODEC_ID_MP3,
    CODEC_ID_FLV1,
    swf_write_header,
    swf_write_packet,
    swf_write_trailer,
};
#endif