xref: /third_party/ffmpeg/libavformat/swfdec.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Flash Compatible Streaming Format demuxer
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.h"
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ci#if CONFIG_ZLIB
26cabdff1aSopenharmony_ci#include <zlib.h>
27cabdff1aSopenharmony_ci#endif
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
30cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h"
31cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
32cabdff1aSopenharmony_ci#include "libavutil/internal.h"
33cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
34cabdff1aSopenharmony_ci#include "libavcodec/get_bits.h"
35cabdff1aSopenharmony_ci#include "demux.h"
36cabdff1aSopenharmony_ci#include "swf.h"
37cabdff1aSopenharmony_ci#include "flv.h"
38cabdff1aSopenharmony_ci
39cabdff1aSopenharmony_citypedef struct SWFDecContext {
40cabdff1aSopenharmony_ci    int samples_per_frame;
41cabdff1aSopenharmony_ci    int frame_rate;
42cabdff1aSopenharmony_ci#if CONFIG_ZLIB
43cabdff1aSopenharmony_ci#define ZBUF_SIZE 4096
44cabdff1aSopenharmony_ci    AVIOContext *zpb;
45cabdff1aSopenharmony_ci    uint8_t *zbuf_in;
46cabdff1aSopenharmony_ci    uint8_t *zbuf_out;
47cabdff1aSopenharmony_ci    z_stream zstream;
48cabdff1aSopenharmony_ci#endif
49cabdff1aSopenharmony_ci} SWFDecContext;
50cabdff1aSopenharmony_ci
51cabdff1aSopenharmony_cistatic const AVCodecTag swf_audio_codec_tags[] = {
52cabdff1aSopenharmony_ci    { AV_CODEC_ID_PCM_S16LE,  0x00 },
53cabdff1aSopenharmony_ci    { AV_CODEC_ID_ADPCM_SWF,  0x01 },
54cabdff1aSopenharmony_ci    { AV_CODEC_ID_MP3,        0x02 },
55cabdff1aSopenharmony_ci    { AV_CODEC_ID_PCM_S16LE,  0x03 },
56cabdff1aSopenharmony_ci    { AV_CODEC_ID_NELLYMOSER, 0x06 },
57cabdff1aSopenharmony_ci    { AV_CODEC_ID_NONE,          0 },
58cabdff1aSopenharmony_ci};
59cabdff1aSopenharmony_ci
60cabdff1aSopenharmony_cistatic int get_swf_tag(AVIOContext *pb, int *len_ptr)
61cabdff1aSopenharmony_ci{
62cabdff1aSopenharmony_ci    int tag, len;
63cabdff1aSopenharmony_ci
64cabdff1aSopenharmony_ci    if (avio_feof(pb))
65cabdff1aSopenharmony_ci        return AVERROR_EOF;
66cabdff1aSopenharmony_ci
67cabdff1aSopenharmony_ci    tag = avio_rl16(pb);
68cabdff1aSopenharmony_ci    len = tag & 0x3f;
69cabdff1aSopenharmony_ci    tag = tag >> 6;
70cabdff1aSopenharmony_ci    if (len == 0x3f) {
71cabdff1aSopenharmony_ci        len = avio_rl32(pb);
72cabdff1aSopenharmony_ci    }
73cabdff1aSopenharmony_ci    *len_ptr = len;
74cabdff1aSopenharmony_ci    return tag;
75cabdff1aSopenharmony_ci}
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci
78cabdff1aSopenharmony_cistatic int swf_probe(const AVProbeData *p)
79cabdff1aSopenharmony_ci{
80cabdff1aSopenharmony_ci    GetBitContext gb;
81cabdff1aSopenharmony_ci    int len, xmin, xmax, ymin, ymax;
82cabdff1aSopenharmony_ci
83cabdff1aSopenharmony_ci    if(p->buf_size < 15)
84cabdff1aSopenharmony_ci        return 0;
85cabdff1aSopenharmony_ci
86cabdff1aSopenharmony_ci    /* check file header */
87cabdff1aSopenharmony_ci    if (   AV_RB24(p->buf) != AV_RB24("CWS")
88cabdff1aSopenharmony_ci        && AV_RB24(p->buf) != AV_RB24("FWS"))
89cabdff1aSopenharmony_ci        return 0;
90cabdff1aSopenharmony_ci
91cabdff1aSopenharmony_ci    if (   AV_RB24(p->buf) == AV_RB24("CWS")
92cabdff1aSopenharmony_ci        && p->buf[3] <= 20)
93cabdff1aSopenharmony_ci        return AVPROBE_SCORE_MAX / 4 + 1;
94cabdff1aSopenharmony_ci
95cabdff1aSopenharmony_ci    if (init_get_bits8(&gb, p->buf + 8, p->buf_size - 8) < 0)
96cabdff1aSopenharmony_ci        return 0;
97cabdff1aSopenharmony_ci
98cabdff1aSopenharmony_ci    len = get_bits(&gb, 5);
99cabdff1aSopenharmony_ci    if (!len)
100cabdff1aSopenharmony_ci        return 0;
101cabdff1aSopenharmony_ci    xmin = get_bits_long(&gb, len);
102cabdff1aSopenharmony_ci    xmax = get_bits_long(&gb, len);
103cabdff1aSopenharmony_ci    ymin = get_bits_long(&gb, len);
104cabdff1aSopenharmony_ci    ymax = get_bits_long(&gb, len);
105cabdff1aSopenharmony_ci    if (xmin || ymin || !xmax || !ymax)
106cabdff1aSopenharmony_ci        return 0;
107cabdff1aSopenharmony_ci
108cabdff1aSopenharmony_ci    if (p->buf[3] >= 20 || xmax < 16 || ymax < 16)
109cabdff1aSopenharmony_ci        return AVPROBE_SCORE_MAX / 4;
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci    return AVPROBE_SCORE_EXTENSION + 1;
112cabdff1aSopenharmony_ci}
113cabdff1aSopenharmony_ci
114cabdff1aSopenharmony_ci#if CONFIG_ZLIB
115cabdff1aSopenharmony_cistatic int zlib_refill(void *opaque, uint8_t *buf, int buf_size)
116cabdff1aSopenharmony_ci{
117cabdff1aSopenharmony_ci    AVFormatContext *s = opaque;
118cabdff1aSopenharmony_ci    SWFDecContext *swf = s->priv_data;
119cabdff1aSopenharmony_ci    z_stream *z = &swf->zstream;
120cabdff1aSopenharmony_ci    int ret;
121cabdff1aSopenharmony_ci
122cabdff1aSopenharmony_ciretry:
123cabdff1aSopenharmony_ci    if (!z->avail_in) {
124cabdff1aSopenharmony_ci        int n = avio_read(s->pb, swf->zbuf_in, ZBUF_SIZE);
125cabdff1aSopenharmony_ci        if (n < 0)
126cabdff1aSopenharmony_ci            return n;
127cabdff1aSopenharmony_ci        z->next_in  = swf->zbuf_in;
128cabdff1aSopenharmony_ci        z->avail_in = n;
129cabdff1aSopenharmony_ci    }
130cabdff1aSopenharmony_ci
131cabdff1aSopenharmony_ci    z->next_out  = buf;
132cabdff1aSopenharmony_ci    z->avail_out = buf_size;
133cabdff1aSopenharmony_ci
134cabdff1aSopenharmony_ci    ret = inflate(z, Z_NO_FLUSH);
135cabdff1aSopenharmony_ci    if (ret == Z_STREAM_END)
136cabdff1aSopenharmony_ci        return AVERROR_EOF;
137cabdff1aSopenharmony_ci    if (ret != Z_OK)
138cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
139cabdff1aSopenharmony_ci
140cabdff1aSopenharmony_ci    if (buf_size - z->avail_out == 0)
141cabdff1aSopenharmony_ci        goto retry;
142cabdff1aSopenharmony_ci
143cabdff1aSopenharmony_ci    return buf_size - z->avail_out;
144cabdff1aSopenharmony_ci}
145cabdff1aSopenharmony_ci
146cabdff1aSopenharmony_cistatic av_cold int swf_read_close(AVFormatContext *avctx);
147cabdff1aSopenharmony_ci#endif
148cabdff1aSopenharmony_ci
149cabdff1aSopenharmony_cistatic int swf_read_header(AVFormatContext *s)
150cabdff1aSopenharmony_ci{
151cabdff1aSopenharmony_ci    SWFDecContext *swf = s->priv_data;
152cabdff1aSopenharmony_ci    AVIOContext *pb = s->pb;
153cabdff1aSopenharmony_ci    int nbits, len, tag;
154cabdff1aSopenharmony_ci
155cabdff1aSopenharmony_ci    tag = avio_rb32(pb) & 0xffffff00;
156cabdff1aSopenharmony_ci    avio_rl32(pb);
157cabdff1aSopenharmony_ci
158cabdff1aSopenharmony_ci    if (tag == MKBETAG('C', 'W', 'S', 0)) {
159cabdff1aSopenharmony_ci        av_log(s, AV_LOG_INFO, "SWF compressed file detected\n");
160cabdff1aSopenharmony_ci#if CONFIG_ZLIB
161cabdff1aSopenharmony_ci        if (inflateInit(&swf->zstream) != Z_OK) {
162cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "Unable to init zlib context\n");
163cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
164cabdff1aSopenharmony_ci        }
165cabdff1aSopenharmony_ci        if (!(swf->zbuf_in  = av_malloc(ZBUF_SIZE)) ||
166cabdff1aSopenharmony_ci            !(swf->zbuf_out = av_malloc(ZBUF_SIZE)) ||
167cabdff1aSopenharmony_ci            !(swf->zpb = avio_alloc_context(swf->zbuf_out, ZBUF_SIZE, 0,
168cabdff1aSopenharmony_ci                                            s, zlib_refill, NULL, NULL))) {
169cabdff1aSopenharmony_ci            swf_read_close(s);
170cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
171cabdff1aSopenharmony_ci        }
172cabdff1aSopenharmony_ci        swf->zpb->seekable = 0;
173cabdff1aSopenharmony_ci        pb = swf->zpb;
174cabdff1aSopenharmony_ci#else
175cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "zlib support is required to read SWF compressed files\n");
176cabdff1aSopenharmony_ci        return AVERROR(EIO);
177cabdff1aSopenharmony_ci#endif
178cabdff1aSopenharmony_ci    } else if (tag != MKBETAG('F', 'W', 'S', 0))
179cabdff1aSopenharmony_ci        return AVERROR(EIO);
180cabdff1aSopenharmony_ci    /* skip rectangle size */
181cabdff1aSopenharmony_ci    nbits = avio_r8(pb) >> 3;
182cabdff1aSopenharmony_ci    len = (4 * nbits - 3 + 7) / 8;
183cabdff1aSopenharmony_ci    avio_skip(pb, len);
184cabdff1aSopenharmony_ci    swf->frame_rate = avio_rl16(pb); /* 8.8 fixed */
185cabdff1aSopenharmony_ci    avio_rl16(pb); /* frame count */
186cabdff1aSopenharmony_ci
187cabdff1aSopenharmony_ci    swf->samples_per_frame = 0;
188cabdff1aSopenharmony_ci    s->ctx_flags |= AVFMTCTX_NOHEADER;
189cabdff1aSopenharmony_ci    return 0;
190cabdff1aSopenharmony_ci}
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_cistatic AVStream *create_new_audio_stream(AVFormatContext *s, int id, int info)
193cabdff1aSopenharmony_ci{
194cabdff1aSopenharmony_ci    int sample_rate_code, sample_size_code;
195cabdff1aSopenharmony_ci    AVStream *ast = avformat_new_stream(s, NULL);
196cabdff1aSopenharmony_ci    if (!ast)
197cabdff1aSopenharmony_ci        return NULL;
198cabdff1aSopenharmony_ci    ast->id = id;
199cabdff1aSopenharmony_ci    av_channel_layout_default(&ast->codecpar->ch_layout, 1 + (info & 1));
200cabdff1aSopenharmony_ci    ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
201cabdff1aSopenharmony_ci    ast->codecpar->codec_id   = ff_codec_get_id(swf_audio_codec_tags, info>>4 & 15);
202cabdff1aSopenharmony_ci    ffstream(ast)->need_parsing = AVSTREAM_PARSE_FULL;
203cabdff1aSopenharmony_ci    sample_rate_code = info>>2 & 3;
204cabdff1aSopenharmony_ci    sample_size_code = info>>1 & 1;
205cabdff1aSopenharmony_ci    if (!sample_size_code && ast->codecpar->codec_id == AV_CODEC_ID_PCM_S16LE)
206cabdff1aSopenharmony_ci        ast->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
207cabdff1aSopenharmony_ci    ast->codecpar->sample_rate = 44100 >> (3 - sample_rate_code);
208cabdff1aSopenharmony_ci    avpriv_set_pts_info(ast, 64, 1, ast->codecpar->sample_rate);
209cabdff1aSopenharmony_ci    return ast;
210cabdff1aSopenharmony_ci}
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_cistatic int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
213cabdff1aSopenharmony_ci{
214cabdff1aSopenharmony_ci    SWFDecContext *swf = s->priv_data;
215cabdff1aSopenharmony_ci    AVIOContext *pb = s->pb;
216cabdff1aSopenharmony_ci    AVStream *vst = NULL, *ast = NULL, *st = 0;
217cabdff1aSopenharmony_ci    int tag, len, i, frame, v, res;
218cabdff1aSopenharmony_ci
219cabdff1aSopenharmony_ci#if CONFIG_ZLIB
220cabdff1aSopenharmony_ci    if (swf->zpb)
221cabdff1aSopenharmony_ci        pb = swf->zpb;
222cabdff1aSopenharmony_ci#endif
223cabdff1aSopenharmony_ci
224cabdff1aSopenharmony_ci    for(;;) {
225cabdff1aSopenharmony_ci        uint64_t pos = avio_tell(pb);
226cabdff1aSopenharmony_ci        tag = get_swf_tag(pb, &len);
227cabdff1aSopenharmony_ci        if (tag < 0)
228cabdff1aSopenharmony_ci            return tag;
229cabdff1aSopenharmony_ci        if (len < 0) {
230cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "invalid tag length: %d\n", len);
231cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
232cabdff1aSopenharmony_ci        }
233cabdff1aSopenharmony_ci        if (tag == TAG_VIDEOSTREAM) {
234cabdff1aSopenharmony_ci            int ch_id = avio_rl16(pb);
235cabdff1aSopenharmony_ci            len -= 2;
236cabdff1aSopenharmony_ci
237cabdff1aSopenharmony_ci            for (i=0; i<s->nb_streams; i++) {
238cabdff1aSopenharmony_ci                st = s->streams[i];
239cabdff1aSopenharmony_ci                if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->id == ch_id)
240cabdff1aSopenharmony_ci                    goto skip;
241cabdff1aSopenharmony_ci            }
242cabdff1aSopenharmony_ci
243cabdff1aSopenharmony_ci            avio_rl16(pb);
244cabdff1aSopenharmony_ci            avio_rl16(pb);
245cabdff1aSopenharmony_ci            avio_rl16(pb);
246cabdff1aSopenharmony_ci            avio_r8(pb);
247cabdff1aSopenharmony_ci            /* Check for FLV1 */
248cabdff1aSopenharmony_ci            vst = avformat_new_stream(s, NULL);
249cabdff1aSopenharmony_ci            if (!vst)
250cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
251cabdff1aSopenharmony_ci            vst->id = ch_id;
252cabdff1aSopenharmony_ci            vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
253cabdff1aSopenharmony_ci            vst->codecpar->codec_id = ff_codec_get_id(ff_swf_codec_tags, avio_r8(pb));
254cabdff1aSopenharmony_ci            avpriv_set_pts_info(vst, 16, 256, swf->frame_rate);
255cabdff1aSopenharmony_ci            len -= 8;
256cabdff1aSopenharmony_ci        } else if (tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) {
257cabdff1aSopenharmony_ci            /* streaming found */
258cabdff1aSopenharmony_ci
259cabdff1aSopenharmony_ci            for (i=0; i<s->nb_streams; i++) {
260cabdff1aSopenharmony_ci                st = s->streams[i];
261cabdff1aSopenharmony_ci                if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->id == -1)
262cabdff1aSopenharmony_ci                    goto skip;
263cabdff1aSopenharmony_ci            }
264cabdff1aSopenharmony_ci
265cabdff1aSopenharmony_ci            avio_r8(pb);
266cabdff1aSopenharmony_ci            v = avio_r8(pb);
267cabdff1aSopenharmony_ci            swf->samples_per_frame = avio_rl16(pb);
268cabdff1aSopenharmony_ci            ast = create_new_audio_stream(s, -1, v); /* -1 to avoid clash with video stream ch_id */
269cabdff1aSopenharmony_ci            if (!ast)
270cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
271cabdff1aSopenharmony_ci            len -= 4;
272cabdff1aSopenharmony_ci        } else if (tag == TAG_DEFINESOUND) {
273cabdff1aSopenharmony_ci            /* audio stream */
274cabdff1aSopenharmony_ci            int ch_id = avio_rl16(pb);
275cabdff1aSopenharmony_ci
276cabdff1aSopenharmony_ci            for (i=0; i<s->nb_streams; i++) {
277cabdff1aSopenharmony_ci                st = s->streams[i];
278cabdff1aSopenharmony_ci                if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->id == ch_id)
279cabdff1aSopenharmony_ci                    goto skip;
280cabdff1aSopenharmony_ci            }
281cabdff1aSopenharmony_ci
282cabdff1aSopenharmony_ci            // FIXME: The entire audio stream is stored in a single chunk/tag. Normally,
283cabdff1aSopenharmony_ci            // these are smaller audio streams in DEFINESOUND tags, but it's technically
284cabdff1aSopenharmony_ci            // possible they could be huge. Break it up into multiple packets if it's big.
285cabdff1aSopenharmony_ci            v = avio_r8(pb);
286cabdff1aSopenharmony_ci            ast = create_new_audio_stream(s, ch_id, v);
287cabdff1aSopenharmony_ci            if (!ast)
288cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
289cabdff1aSopenharmony_ci            ast->duration = avio_rl32(pb); // number of samples
290cabdff1aSopenharmony_ci            if (((v>>4) & 15) == 2) { // MP3 sound data record
291cabdff1aSopenharmony_ci                ffstream(ast)->skip_samples = avio_rl16(pb);
292cabdff1aSopenharmony_ci                len -= 2;
293cabdff1aSopenharmony_ci            }
294cabdff1aSopenharmony_ci            len -= 7;
295cabdff1aSopenharmony_ci            if ((res = av_get_packet(pb, pkt, len)) < 0)
296cabdff1aSopenharmony_ci                return res;
297cabdff1aSopenharmony_ci            pkt->pos = pos;
298cabdff1aSopenharmony_ci            pkt->stream_index = ast->index;
299cabdff1aSopenharmony_ci            return pkt->size;
300cabdff1aSopenharmony_ci        } else if (tag == TAG_VIDEOFRAME) {
301cabdff1aSopenharmony_ci            int ch_id = avio_rl16(pb);
302cabdff1aSopenharmony_ci            len -= 2;
303cabdff1aSopenharmony_ci            for(i=0; i<s->nb_streams; i++) {
304cabdff1aSopenharmony_ci                st = s->streams[i];
305cabdff1aSopenharmony_ci                if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->id == ch_id) {
306cabdff1aSopenharmony_ci                    int pkt_flags = 0;
307cabdff1aSopenharmony_ci                    frame = avio_rl16(pb);
308cabdff1aSopenharmony_ci                    len -= 2;
309cabdff1aSopenharmony_ci                    if (len <= 0)
310cabdff1aSopenharmony_ci                        goto skip;
311cabdff1aSopenharmony_ci                    if (st->codecpar->codec_id == AV_CODEC_ID_FLASHSV) {
312cabdff1aSopenharmony_ci                        unsigned flags = avio_r8(pb);
313cabdff1aSopenharmony_ci                        len--;
314cabdff1aSopenharmony_ci                        if (len <= 0)
315cabdff1aSopenharmony_ci                            goto skip;
316cabdff1aSopenharmony_ci                        pkt_flags |= (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY ? AV_PKT_FLAG_KEY : 0;
317cabdff1aSopenharmony_ci                    }
318cabdff1aSopenharmony_ci                    if ((res = av_get_packet(pb, pkt, len)) < 0)
319cabdff1aSopenharmony_ci                        return res;
320cabdff1aSopenharmony_ci                    pkt->pos = pos;
321cabdff1aSopenharmony_ci                    pkt->pts = frame;
322cabdff1aSopenharmony_ci                    pkt->stream_index = st->index;
323cabdff1aSopenharmony_ci                    pkt->flags |= pkt_flags;
324cabdff1aSopenharmony_ci                    return pkt->size;
325cabdff1aSopenharmony_ci                }
326cabdff1aSopenharmony_ci            }
327cabdff1aSopenharmony_ci        } else if (tag == TAG_DEFINEBITSLOSSLESS || tag == TAG_DEFINEBITSLOSSLESS2) {
328cabdff1aSopenharmony_ci#if CONFIG_ZLIB
329cabdff1aSopenharmony_ci            long out_len;
330cabdff1aSopenharmony_ci            uint8_t *buf = NULL, *zbuf = NULL, *pal;
331cabdff1aSopenharmony_ci            uint32_t colormap[AVPALETTE_COUNT] = {0};
332cabdff1aSopenharmony_ci            const int alpha_bmp = tag == TAG_DEFINEBITSLOSSLESS2;
333cabdff1aSopenharmony_ci            const int colormapbpp = 3 + alpha_bmp;
334cabdff1aSopenharmony_ci            int linesize, colormapsize = 0;
335cabdff1aSopenharmony_ci
336cabdff1aSopenharmony_ci            const int ch_id   = avio_rl16(pb);
337cabdff1aSopenharmony_ci            const int bmp_fmt = avio_r8(pb);
338cabdff1aSopenharmony_ci            const int width   = avio_rl16(pb);
339cabdff1aSopenharmony_ci            const int height  = avio_rl16(pb);
340cabdff1aSopenharmony_ci            int pix_fmt;
341cabdff1aSopenharmony_ci
342cabdff1aSopenharmony_ci            len -= 2+1+2+2;
343cabdff1aSopenharmony_ci
344cabdff1aSopenharmony_ci            switch (bmp_fmt) {
345cabdff1aSopenharmony_ci            case 3: // PAL-8
346cabdff1aSopenharmony_ci                linesize = width;
347cabdff1aSopenharmony_ci                colormapsize = avio_r8(pb) + 1;
348cabdff1aSopenharmony_ci                len--;
349cabdff1aSopenharmony_ci                break;
350cabdff1aSopenharmony_ci            case 4: // RGB15
351cabdff1aSopenharmony_ci                linesize = width * 2;
352cabdff1aSopenharmony_ci                break;
353cabdff1aSopenharmony_ci            case 5: // RGB24 (0RGB)
354cabdff1aSopenharmony_ci                linesize = width * 4;
355cabdff1aSopenharmony_ci                break;
356cabdff1aSopenharmony_ci            default:
357cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR, "invalid bitmap format %d, skipped\n", bmp_fmt);
358cabdff1aSopenharmony_ci                goto bitmap_end_skip;
359cabdff1aSopenharmony_ci            }
360cabdff1aSopenharmony_ci
361cabdff1aSopenharmony_ci            linesize = FFALIGN(linesize, 4);
362cabdff1aSopenharmony_ci
363cabdff1aSopenharmony_ci            if (av_image_check_size(width, height, 0, s) < 0 ||
364cabdff1aSopenharmony_ci                linesize >= INT_MAX / height ||
365cabdff1aSopenharmony_ci                linesize * height >= INT_MAX - colormapsize * colormapbpp) {
366cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR, "invalid frame size %dx%d\n", width, height);
367cabdff1aSopenharmony_ci                goto bitmap_end_skip;
368cabdff1aSopenharmony_ci            }
369cabdff1aSopenharmony_ci
370cabdff1aSopenharmony_ci            out_len = colormapsize * colormapbpp + linesize * height;
371cabdff1aSopenharmony_ci
372cabdff1aSopenharmony_ci            ff_dlog(s, "bitmap: ch=%d fmt=%d %dx%d (linesize=%d) len=%d->%ld pal=%d\n",
373cabdff1aSopenharmony_ci                    ch_id, bmp_fmt, width, height, linesize, len, out_len, colormapsize);
374cabdff1aSopenharmony_ci
375cabdff1aSopenharmony_ci            if (len * 17373LL < out_len)
376cabdff1aSopenharmony_ci                goto bitmap_end_skip;
377cabdff1aSopenharmony_ci
378cabdff1aSopenharmony_ci            zbuf = av_malloc(len);
379cabdff1aSopenharmony_ci            if (!zbuf) {
380cabdff1aSopenharmony_ci                res = AVERROR(ENOMEM);
381cabdff1aSopenharmony_ci                goto bitmap_end;
382cabdff1aSopenharmony_ci            }
383cabdff1aSopenharmony_ci
384cabdff1aSopenharmony_ci            len = avio_read(pb, zbuf, len);
385cabdff1aSopenharmony_ci            if (len < 0)
386cabdff1aSopenharmony_ci                goto bitmap_end_skip;
387cabdff1aSopenharmony_ci
388cabdff1aSopenharmony_ci            buf  = av_malloc(out_len);
389cabdff1aSopenharmony_ci            if (!buf) {
390cabdff1aSopenharmony_ci                res = AVERROR(ENOMEM);
391cabdff1aSopenharmony_ci                goto bitmap_end;
392cabdff1aSopenharmony_ci            }
393cabdff1aSopenharmony_ci            if ((res = uncompress(buf, &out_len, zbuf, len)) != Z_OK) {
394cabdff1aSopenharmony_ci                av_log(s, AV_LOG_WARNING, "Failed to uncompress one bitmap\n");
395cabdff1aSopenharmony_ci                goto bitmap_end_skip;
396cabdff1aSopenharmony_ci            }
397cabdff1aSopenharmony_ci
398cabdff1aSopenharmony_ci            for (i = 0; i < s->nb_streams; i++) {
399cabdff1aSopenharmony_ci                st = s->streams[i];
400cabdff1aSopenharmony_ci                if (st->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO && st->id == -3)
401cabdff1aSopenharmony_ci                    break;
402cabdff1aSopenharmony_ci            }
403cabdff1aSopenharmony_ci            if (i == s->nb_streams) {
404cabdff1aSopenharmony_ci                vst = avformat_new_stream(s, NULL);
405cabdff1aSopenharmony_ci                if (!vst) {
406cabdff1aSopenharmony_ci                    res = AVERROR(ENOMEM);
407cabdff1aSopenharmony_ci                    goto bitmap_end;
408cabdff1aSopenharmony_ci                }
409cabdff1aSopenharmony_ci                vst->id = -3; /* -3 to avoid clash with video stream and audio stream */
410cabdff1aSopenharmony_ci                vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
411cabdff1aSopenharmony_ci                vst->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
412cabdff1aSopenharmony_ci                avpriv_set_pts_info(vst, 64, 256, swf->frame_rate);
413cabdff1aSopenharmony_ci                st = vst;
414cabdff1aSopenharmony_ci            }
415cabdff1aSopenharmony_ci
416cabdff1aSopenharmony_ci            if ((res = av_new_packet(pkt, out_len - colormapsize * colormapbpp)) < 0)
417cabdff1aSopenharmony_ci                goto bitmap_end;
418cabdff1aSopenharmony_ci            if (!st->codecpar->width && !st->codecpar->height) {
419cabdff1aSopenharmony_ci                st->codecpar->width  = width;
420cabdff1aSopenharmony_ci                st->codecpar->height = height;
421cabdff1aSopenharmony_ci            } else {
422cabdff1aSopenharmony_ci                ff_add_param_change(pkt, 0, 0, 0, width, height);
423cabdff1aSopenharmony_ci            }
424cabdff1aSopenharmony_ci            pkt->pos = pos;
425cabdff1aSopenharmony_ci            pkt->stream_index = st->index;
426cabdff1aSopenharmony_ci
427cabdff1aSopenharmony_ci            if (linesize * height > pkt->size) {
428cabdff1aSopenharmony_ci                res = AVERROR_INVALIDDATA;
429cabdff1aSopenharmony_ci                goto bitmap_end;
430cabdff1aSopenharmony_ci            }
431cabdff1aSopenharmony_ci
432cabdff1aSopenharmony_ci            switch (bmp_fmt) {
433cabdff1aSopenharmony_ci            case 3:
434cabdff1aSopenharmony_ci                pix_fmt = AV_PIX_FMT_PAL8;
435cabdff1aSopenharmony_ci                for (i = 0; i < colormapsize; i++)
436cabdff1aSopenharmony_ci                    if (alpha_bmp)  colormap[i] = buf[3]<<24 | AV_RB24(buf + 4*i);
437cabdff1aSopenharmony_ci                    else            colormap[i] = 0xffU <<24 | AV_RB24(buf + 3*i);
438cabdff1aSopenharmony_ci                pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
439cabdff1aSopenharmony_ci                if (!pal) {
440cabdff1aSopenharmony_ci                    res = AVERROR(ENOMEM);
441cabdff1aSopenharmony_ci                    goto bitmap_end;
442cabdff1aSopenharmony_ci                }
443cabdff1aSopenharmony_ci                memcpy(pal, colormap, AVPALETTE_SIZE);
444cabdff1aSopenharmony_ci                break;
445cabdff1aSopenharmony_ci            case 4:
446cabdff1aSopenharmony_ci                pix_fmt = AV_PIX_FMT_RGB555;
447cabdff1aSopenharmony_ci                break;
448cabdff1aSopenharmony_ci            case 5:
449cabdff1aSopenharmony_ci                pix_fmt = alpha_bmp ? AV_PIX_FMT_ARGB : AV_PIX_FMT_0RGB;
450cabdff1aSopenharmony_ci                break;
451cabdff1aSopenharmony_ci            default:
452cabdff1aSopenharmony_ci                av_assert0(0);
453cabdff1aSopenharmony_ci            }
454cabdff1aSopenharmony_ci            if (st->codecpar->format != AV_PIX_FMT_NONE && st->codecpar->format != pix_fmt) {
455cabdff1aSopenharmony_ci                av_log(s, AV_LOG_ERROR, "pixel format change unsupported\n");
456cabdff1aSopenharmony_ci            } else
457cabdff1aSopenharmony_ci                st->codecpar->format = pix_fmt;
458cabdff1aSopenharmony_ci
459cabdff1aSopenharmony_ci            memcpy(pkt->data, buf + colormapsize*colormapbpp, linesize * height);
460cabdff1aSopenharmony_ci
461cabdff1aSopenharmony_ci            res = pkt->size;
462cabdff1aSopenharmony_ci
463cabdff1aSopenharmony_cibitmap_end:
464cabdff1aSopenharmony_ci            av_freep(&zbuf);
465cabdff1aSopenharmony_ci            av_freep(&buf);
466cabdff1aSopenharmony_ci            return res;
467cabdff1aSopenharmony_cibitmap_end_skip:
468cabdff1aSopenharmony_ci            av_freep(&zbuf);
469cabdff1aSopenharmony_ci            av_freep(&buf);
470cabdff1aSopenharmony_ci#else
471cabdff1aSopenharmony_ci            av_log(s, AV_LOG_ERROR, "this file requires zlib support compiled in\n");
472cabdff1aSopenharmony_ci#endif
473cabdff1aSopenharmony_ci        } else if (tag == TAG_STREAMBLOCK) {
474cabdff1aSopenharmony_ci            for (i = 0; i < s->nb_streams; i++) {
475cabdff1aSopenharmony_ci                st = s->streams[i];
476cabdff1aSopenharmony_ci                if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->id == -1) {
477cabdff1aSopenharmony_ci                    if (st->codecpar->codec_id == AV_CODEC_ID_MP3) {
478cabdff1aSopenharmony_ci                        avio_skip(pb, 4);
479cabdff1aSopenharmony_ci                        len -= 4;
480cabdff1aSopenharmony_ci                        if (len <= 0)
481cabdff1aSopenharmony_ci                            goto skip;
482cabdff1aSopenharmony_ci                        if ((res = av_get_packet(pb, pkt, len)) < 0)
483cabdff1aSopenharmony_ci                            return res;
484cabdff1aSopenharmony_ci                    } else { // ADPCM, PCM
485cabdff1aSopenharmony_ci                        if (len <= 0)
486cabdff1aSopenharmony_ci                            goto skip;
487cabdff1aSopenharmony_ci                        if ((res = av_get_packet(pb, pkt, len)) < 0)
488cabdff1aSopenharmony_ci                            return res;
489cabdff1aSopenharmony_ci                    }
490cabdff1aSopenharmony_ci                    pkt->pos          = pos;
491cabdff1aSopenharmony_ci                    pkt->stream_index = st->index;
492cabdff1aSopenharmony_ci                    return pkt->size;
493cabdff1aSopenharmony_ci                }
494cabdff1aSopenharmony_ci            }
495cabdff1aSopenharmony_ci        } else if (tag == TAG_JPEG2) {
496cabdff1aSopenharmony_ci            for (i=0; i<s->nb_streams; i++) {
497cabdff1aSopenharmony_ci                st = s->streams[i];
498cabdff1aSopenharmony_ci                if (st->codecpar->codec_id == AV_CODEC_ID_MJPEG && st->id == -2)
499cabdff1aSopenharmony_ci                    break;
500cabdff1aSopenharmony_ci            }
501cabdff1aSopenharmony_ci            if (i == s->nb_streams) {
502cabdff1aSopenharmony_ci                vst = avformat_new_stream(s, NULL);
503cabdff1aSopenharmony_ci                if (!vst)
504cabdff1aSopenharmony_ci                    return AVERROR(ENOMEM);
505cabdff1aSopenharmony_ci                vst->id = -2; /* -2 to avoid clash with video stream and audio stream */
506cabdff1aSopenharmony_ci                vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
507cabdff1aSopenharmony_ci                vst->codecpar->codec_id = AV_CODEC_ID_MJPEG;
508cabdff1aSopenharmony_ci                avpriv_set_pts_info(vst, 64, 256, swf->frame_rate);
509cabdff1aSopenharmony_ci                st = vst;
510cabdff1aSopenharmony_ci            }
511cabdff1aSopenharmony_ci            avio_rl16(pb); /* BITMAP_ID */
512cabdff1aSopenharmony_ci            len -= 2;
513cabdff1aSopenharmony_ci            if (len < 4)
514cabdff1aSopenharmony_ci                goto skip;
515cabdff1aSopenharmony_ci            if ((res = av_new_packet(pkt, len)) < 0)
516cabdff1aSopenharmony_ci                return res;
517cabdff1aSopenharmony_ci            if (avio_read(pb, pkt->data, 4) != 4) {
518cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
519cabdff1aSopenharmony_ci            }
520cabdff1aSopenharmony_ci            if (AV_RB32(pkt->data) == 0xffd8ffd9 ||
521cabdff1aSopenharmony_ci                AV_RB32(pkt->data) == 0xffd9ffd8) {
522cabdff1aSopenharmony_ci                /* old SWF files containing SOI/EOI as data start */
523cabdff1aSopenharmony_ci                /* files created by swink have reversed tag */
524cabdff1aSopenharmony_ci                pkt->size -= 4;
525cabdff1aSopenharmony_ci                memset(pkt->data+pkt->size, 0, 4);
526cabdff1aSopenharmony_ci                res = avio_read(pb, pkt->data, pkt->size);
527cabdff1aSopenharmony_ci            } else {
528cabdff1aSopenharmony_ci                res = avio_read(pb, pkt->data + 4, pkt->size - 4);
529cabdff1aSopenharmony_ci                if (res >= 0)
530cabdff1aSopenharmony_ci                    res += 4;
531cabdff1aSopenharmony_ci            }
532cabdff1aSopenharmony_ci            if (res != pkt->size) {
533cabdff1aSopenharmony_ci                if (res < 0) {
534cabdff1aSopenharmony_ci                    return res;
535cabdff1aSopenharmony_ci                }
536cabdff1aSopenharmony_ci                av_shrink_packet(pkt, res);
537cabdff1aSopenharmony_ci            }
538cabdff1aSopenharmony_ci
539cabdff1aSopenharmony_ci            pkt->pos = pos;
540cabdff1aSopenharmony_ci            pkt->stream_index = st->index;
541cabdff1aSopenharmony_ci            return pkt->size;
542cabdff1aSopenharmony_ci        } else {
543cabdff1aSopenharmony_ci            av_log(s, AV_LOG_DEBUG, "Unknown tag: %d\n", tag);
544cabdff1aSopenharmony_ci        }
545cabdff1aSopenharmony_ci    skip:
546cabdff1aSopenharmony_ci        if(len<0)
547cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "Clipping len %d\n", len);
548cabdff1aSopenharmony_ci        len = FFMAX(0, len);
549cabdff1aSopenharmony_ci        avio_skip(pb, len);
550cabdff1aSopenharmony_ci    }
551cabdff1aSopenharmony_ci}
552cabdff1aSopenharmony_ci
553cabdff1aSopenharmony_ci#if CONFIG_ZLIB
554cabdff1aSopenharmony_cistatic av_cold int swf_read_close(AVFormatContext *avctx)
555cabdff1aSopenharmony_ci{
556cabdff1aSopenharmony_ci    SWFDecContext *s = avctx->priv_data;
557cabdff1aSopenharmony_ci    inflateEnd(&s->zstream);
558cabdff1aSopenharmony_ci    av_freep(&s->zbuf_in);
559cabdff1aSopenharmony_ci    av_freep(&s->zbuf_out);
560cabdff1aSopenharmony_ci    avio_context_free(&s->zpb);
561cabdff1aSopenharmony_ci    return 0;
562cabdff1aSopenharmony_ci}
563cabdff1aSopenharmony_ci#endif
564cabdff1aSopenharmony_ci
565cabdff1aSopenharmony_ciconst AVInputFormat ff_swf_demuxer = {
566cabdff1aSopenharmony_ci    .name           = "swf",
567cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash)"),
568cabdff1aSopenharmony_ci    .priv_data_size = sizeof(SWFDecContext),
569cabdff1aSopenharmony_ci    .read_probe     = swf_probe,
570cabdff1aSopenharmony_ci    .read_header    = swf_read_header,
571cabdff1aSopenharmony_ci    .read_packet    = swf_read_packet,
572cabdff1aSopenharmony_ci#if CONFIG_ZLIB
573cabdff1aSopenharmony_ci    .read_close     = swf_read_close,
574cabdff1aSopenharmony_ci#endif
575cabdff1aSopenharmony_ci};
576