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