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