swfenc.c 15.6 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/put_bits.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, put_bits_ptr(&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, put_bits_ptr(&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;
195
                swf->audio_fifo= av_fifo_alloc(AUDIO_FIFO_SIZE);
196 197
                if (!swf->audio_fifo)
                    return AVERROR(ENOMEM);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
198
            } else {
199
                av_log(s, AV_LOG_ERROR, "SWF muxer only supports MP3\n");
Baptiste Coudurier's avatar
Baptiste Coudurier committed
200 201 202
                return -1;
            }
        } else {
203 204 205
            if (enc->codec_id == CODEC_ID_VP6F ||
                enc->codec_id == CODEC_ID_FLV1 ||
                enc->codec_id == CODEC_ID_MJPEG) {
206
                swf->video_enc = enc;
207
            } else {
208
                av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n");
209 210 211
                return -1;
            }
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
212 213
    }

214
    if (!swf->video_enc) {
215
        /* currently, cannot work correctly if audio only */
Fabrice Bellard's avatar
Fabrice Bellard committed
216 217
        width = 320;
        height = 200;
218 219
        rate = 10;
        rate_base= 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
220
    } else {
221 222 223 224
        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
225 226
    }

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

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

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

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

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

252
    /* avm2/swf v9 (also v8?) files require a file attribute tag */
253
    if (version == 9) {
254 255 256 257 258
        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
259
    /* define a shape with the jpeg inside */
260
    if (swf->video_enc && swf->video_enc->codec_id == CODEC_ID_MJPEG) {
261 262 263 264 265 266 267 268 269 270
        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 */
271
        put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
272
                       0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
273
        put_byte(pb, 0); /* no line style */
274

275 276 277 278
        /* 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 */
279

280 281 282 283 284 285
        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 */
286

287 288 289 290 291
        /* 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);
292

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

297
        flush_put_bits(&p);
298
        put_buffer(pb, buf1, put_bits_ptr(&p) - p.buf);
Fabrice Bellard's avatar
Fabrice Bellard committed
299

300 301
        put_swf_end_tag(s);
    }
302

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

        /* start sound */
307
        put_swf_tag(s, TAG_STREAMHEAD2);
308
        switch(swf->audio_enc->sample_rate) {
Baptiste Coudurier's avatar
Baptiste Coudurier committed
309 310 311
        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
312 313
        default:
            /* not supported */
Diego Biurrun's avatar
Diego Biurrun committed
314
            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
315 316
            return -1;
        }
317
        v |= 0x02; /* 16 bit playback */
318
        if (swf->audio_enc->channels == 2)
319
            v |= 0x01; /* stereo playback */
320
        put_byte(s->pb, v);
Fabrice Bellard's avatar
Fabrice Bellard committed
321
        v |= 0x20; /* mp3 compressed */
322 323 324
        put_byte(s->pb, v);
        put_le16(s->pb, swf->samples_per_frame);  /* avg samples per frame */
        put_le16(s->pb, 0);
325

Fabrice Bellard's avatar
Fabrice Bellard committed
326 327 328
        put_swf_end_tag(s);
    }

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

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

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

343 344
    if (enc->codec_id == CODEC_ID_VP6F ||
        enc->codec_id == CODEC_ID_FLV1) {
345
        if (swf->video_frame_number == 0) {
346 347 348
            /* create a new video object */
            put_swf_tag(s, TAG_VIDEOSTREAM);
            put_le16(pb, VIDEO_ID);
349
            swf->vframes_pos = url_ftell(pb);
350
            put_le16(pb, 15000); /* hard flash player limit */
351 352 353
            put_le16(pb, enc->width);
            put_le16(pb, enc->height);
            put_byte(pb, 0);
354
            put_byte(pb,ff_codec_get_tag(swf_codec_tags,enc->codec_id));
355 356 357 358 359 360 361 362
            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);
363
            put_le16(pb, swf->video_frame_number);
Baptiste Coudurier's avatar
Baptiste Coudurier committed
364
            put_tag(pb, "video");
365 366 367 368 369 370 371
            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);
372
            put_le16(pb, swf->video_frame_number);
373 374
            put_swf_end_tag(s);
        }
375

376 377 378
        /* set video frame data */
        put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG);
        put_le16(pb, VIDEO_ID);
379
        put_le16(pb, swf->video_frame_number++);
380 381
        put_buffer(pb, buf, size);
        put_swf_end_tag(s);
382
    } else if (enc->codec_id == CODEC_ID_MJPEG) {
383 384 385 386 387 388 389 390 391 392 393 394
        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);
        }
395

396
        put_swf_tag(s, TAG_JPEG2 | TAG_LONG);
397

398
        put_le16(pb, BITMAP_ID); /* ID of the image */
399

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

405
        put_swf_end_tag(s);
406

407
        /* draw the shape */
408

409 410 411 412 413 414
        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);
    }
415

Baptiste Coudurier's avatar
Baptiste Coudurier committed
416
    swf->swf_frame_number++;
Fabrice Bellard's avatar
Fabrice Bellard committed
417

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

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

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

435
    put_flush_packet(s->pb);
436

Fabrice Bellard's avatar
Fabrice Bellard committed
437 438 439
    return 0;
}

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

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

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

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

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

    return 0;
}

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

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

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

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

492
    put_flush_packet(s->pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
493 494

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

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