annotate ffmpeg/libavformat/swfenc.c @ 13:844d341cf643 tip

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