1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Flash Screen Video decoder
3cabdff1aSopenharmony_ci * Copyright (C) 2004 Alex Beregszaszi
4cabdff1aSopenharmony_ci * Copyright (C) 2006 Benjamin Larsson
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/**
24cabdff1aSopenharmony_ci * @file
25cabdff1aSopenharmony_ci * Flash Screen Video decoder
26cabdff1aSopenharmony_ci * @author Alex Beregszaszi
27cabdff1aSopenharmony_ci * @author Benjamin Larsson
28cabdff1aSopenharmony_ci * @author Daniel Verkamp
29cabdff1aSopenharmony_ci * @author Konstantin Shishkov
30cabdff1aSopenharmony_ci *
31cabdff1aSopenharmony_ci * A description of the bitstream format for Flash Screen Video version 1/2
32cabdff1aSopenharmony_ci * is part of the SWF File Format Specification (version 10), which can be
33cabdff1aSopenharmony_ci * downloaded from http://www.adobe.com/devnet/swf.html.
34cabdff1aSopenharmony_ci */
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_ci#include "config_components.h"
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_ci#include <stdio.h>
39cabdff1aSopenharmony_ci#include <stdlib.h>
40cabdff1aSopenharmony_ci#include <zlib.h>
41cabdff1aSopenharmony_ci
42cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
43cabdff1aSopenharmony_ci#include "avcodec.h"
44cabdff1aSopenharmony_ci#include "bytestream.h"
45cabdff1aSopenharmony_ci#include "codec_internal.h"
46cabdff1aSopenharmony_ci#include "get_bits.h"
47cabdff1aSopenharmony_ci#include "internal.h"
48cabdff1aSopenharmony_ci#include "zlib_wrapper.h"
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_citypedef struct BlockInfo {
51cabdff1aSopenharmony_ci    const uint8_t *pos;
52cabdff1aSopenharmony_ci    int      size;
53cabdff1aSopenharmony_ci} BlockInfo;
54cabdff1aSopenharmony_ci
55cabdff1aSopenharmony_citypedef struct FlashSVContext {
56cabdff1aSopenharmony_ci    AVCodecContext *avctx;
57cabdff1aSopenharmony_ci    AVFrame        *frame;
58cabdff1aSopenharmony_ci    int             image_width, image_height;
59cabdff1aSopenharmony_ci    int             block_width, block_height;
60cabdff1aSopenharmony_ci    uint8_t        *tmpblock;
61cabdff1aSopenharmony_ci    int             block_size;
62cabdff1aSopenharmony_ci    int             ver;
63cabdff1aSopenharmony_ci    const uint32_t *pal;
64cabdff1aSopenharmony_ci    int             is_keyframe;
65cabdff1aSopenharmony_ci    const uint8_t  *keyframedata;
66cabdff1aSopenharmony_ci    AVBufferRef    *keyframedata_buf;
67cabdff1aSopenharmony_ci    uint8_t        *keyframe;
68cabdff1aSopenharmony_ci    BlockInfo      *blocks;
69cabdff1aSopenharmony_ci    int             color_depth;
70cabdff1aSopenharmony_ci    int             zlibprime_curr, zlibprime_prev;
71cabdff1aSopenharmony_ci    int             diff_start, diff_height;
72cabdff1aSopenharmony_ci    FFZStream       zstream;
73cabdff1aSopenharmony_ci    uint8_t         tmp[UINT16_MAX];
74cabdff1aSopenharmony_ci} FlashSVContext;
75cabdff1aSopenharmony_ci
76cabdff1aSopenharmony_cistatic int decode_hybrid(const uint8_t *sptr, const uint8_t *sptr_end, uint8_t *dptr, int dx, int dy,
77cabdff1aSopenharmony_ci                         int h, int w, int stride, const uint32_t *pal)
78cabdff1aSopenharmony_ci{
79cabdff1aSopenharmony_ci    int x, y;
80cabdff1aSopenharmony_ci    const uint8_t *orig_src = sptr;
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_ci    for (y = dx + h; y > dx; y--) {
83cabdff1aSopenharmony_ci        uint8_t *dst = dptr + (y * stride) + dy * 3;
84cabdff1aSopenharmony_ci        for (x = 0; x < w; x++) {
85cabdff1aSopenharmony_ci            if (sptr >= sptr_end)
86cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
87cabdff1aSopenharmony_ci            if (*sptr & 0x80) {
88cabdff1aSopenharmony_ci                /* 15-bit color */
89cabdff1aSopenharmony_ci                unsigned c = AV_RB16(sptr) & ~0x8000;
90cabdff1aSopenharmony_ci                unsigned b =  c        & 0x1F;
91cabdff1aSopenharmony_ci                unsigned g = (c >>  5) & 0x1F;
92cabdff1aSopenharmony_ci                unsigned r =  c >> 10;
93cabdff1aSopenharmony_ci                /* 000aaabb -> aaabbaaa  */
94cabdff1aSopenharmony_ci                *dst++ = (b << 3) | (b >> 2);
95cabdff1aSopenharmony_ci                *dst++ = (g << 3) | (g >> 2);
96cabdff1aSopenharmony_ci                *dst++ = (r << 3) | (r >> 2);
97cabdff1aSopenharmony_ci                sptr += 2;
98cabdff1aSopenharmony_ci            } else {
99cabdff1aSopenharmony_ci                /* palette index */
100cabdff1aSopenharmony_ci                uint32_t c = pal[*sptr++];
101cabdff1aSopenharmony_ci                bytestream_put_le24(&dst, c);
102cabdff1aSopenharmony_ci            }
103cabdff1aSopenharmony_ci        }
104cabdff1aSopenharmony_ci    }
105cabdff1aSopenharmony_ci    return sptr - orig_src;
106cabdff1aSopenharmony_ci}
107cabdff1aSopenharmony_ci
108cabdff1aSopenharmony_cistatic av_cold int flashsv_decode_end(AVCodecContext *avctx)
109cabdff1aSopenharmony_ci{
110cabdff1aSopenharmony_ci    FlashSVContext *s = avctx->priv_data;
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci    ff_inflate_end(&s->zstream);
113cabdff1aSopenharmony_ci    /* release the frame if needed */
114cabdff1aSopenharmony_ci    av_frame_free(&s->frame);
115cabdff1aSopenharmony_ci
116cabdff1aSopenharmony_ci    /* free the tmpblock */
117cabdff1aSopenharmony_ci    av_freep(&s->tmpblock);
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_ci    return 0;
120cabdff1aSopenharmony_ci}
121cabdff1aSopenharmony_ci
122cabdff1aSopenharmony_cistatic av_cold int flashsv_decode_init(AVCodecContext *avctx)
123cabdff1aSopenharmony_ci{
124cabdff1aSopenharmony_ci    FlashSVContext *s = avctx->priv_data;
125cabdff1aSopenharmony_ci
126cabdff1aSopenharmony_ci    s->avctx          = avctx;
127cabdff1aSopenharmony_ci    avctx->pix_fmt = AV_PIX_FMT_BGR24;
128cabdff1aSopenharmony_ci
129cabdff1aSopenharmony_ci    s->frame = av_frame_alloc();
130cabdff1aSopenharmony_ci    if (!s->frame) {
131cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
132cabdff1aSopenharmony_ci    }
133cabdff1aSopenharmony_ci
134cabdff1aSopenharmony_ci    return ff_inflate_init(&s->zstream, avctx);
135cabdff1aSopenharmony_ci}
136cabdff1aSopenharmony_ci
137cabdff1aSopenharmony_cistatic int flashsv2_prime(FlashSVContext *s, const uint8_t *src, int size)
138cabdff1aSopenharmony_ci{
139cabdff1aSopenharmony_ci    int zret; // Zlib return code
140cabdff1aSopenharmony_ci    static const uint8_t zlib_header[] = { 0x78, 0x01 };
141cabdff1aSopenharmony_ci    z_stream *const zstream = &s->zstream.zstream;
142cabdff1aSopenharmony_ci    uint8_t *data = s->tmpblock;
143cabdff1aSopenharmony_ci    unsigned remaining;
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci    if (!src)
146cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    zstream->next_in   = src;
149cabdff1aSopenharmony_ci    zstream->avail_in  = size;
150cabdff1aSopenharmony_ci    zstream->next_out  = data;
151cabdff1aSopenharmony_ci    zstream->avail_out = s->block_size * 3;
152cabdff1aSopenharmony_ci    zret = inflate(zstream, Z_SYNC_FLUSH);
153cabdff1aSopenharmony_ci    if (zret != Z_OK && zret != Z_STREAM_END)
154cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
155cabdff1aSopenharmony_ci    remaining = s->block_size * 3 - zstream->avail_out;
156cabdff1aSopenharmony_ci
157cabdff1aSopenharmony_ci    if ((zret = inflateReset(zstream)) != Z_OK) {
158cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret);
159cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
160cabdff1aSopenharmony_ci    }
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_ci    /* Create input for zlib that is equivalent to encoding the output
163cabdff1aSopenharmony_ci     * from above and decoding it again (the net result of this is that
164cabdff1aSopenharmony_ci     * the dictionary of past decoded data is correctly primed and
165cabdff1aSopenharmony_ci     * the adler32 checksum is correctly initialized).
166cabdff1aSopenharmony_ci     * This is accomplished by synthetizing blocks of uncompressed data
167cabdff1aSopenharmony_ci     * out of the output from above. See section 3.2.4 of RFC 1951. */
168cabdff1aSopenharmony_ci    zstream->next_in  = zlib_header;
169cabdff1aSopenharmony_ci    zstream->avail_in = sizeof(zlib_header);
170cabdff1aSopenharmony_ci    zret = inflate(zstream, Z_SYNC_FLUSH);
171cabdff1aSopenharmony_ci    if (zret != Z_OK)
172cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
173cabdff1aSopenharmony_ci    while (remaining > 0) {
174cabdff1aSopenharmony_ci        unsigned block_size = FFMIN(UINT16_MAX, remaining);
175cabdff1aSopenharmony_ci        uint8_t header[5];
176cabdff1aSopenharmony_ci        /* Bit 0: Non-last-block, bits 1-2: BTYPE for uncompressed block */
177cabdff1aSopenharmony_ci        header[0] = 0;
178cabdff1aSopenharmony_ci        /* Block size */
179cabdff1aSopenharmony_ci        AV_WL16(header + 1, block_size);
180cabdff1aSopenharmony_ci        /* Block size (one's complement) */
181cabdff1aSopenharmony_ci        AV_WL16(header + 3, block_size ^ 0xFFFF);
182cabdff1aSopenharmony_ci        zstream->next_in   = header;
183cabdff1aSopenharmony_ci        zstream->avail_in  = sizeof(header);
184cabdff1aSopenharmony_ci        zstream->next_out  = s->tmp;
185cabdff1aSopenharmony_ci        zstream->avail_out = sizeof(s->tmp);
186cabdff1aSopenharmony_ci        zret = inflate(zstream, Z_SYNC_FLUSH);
187cabdff1aSopenharmony_ci        if (zret != Z_OK)
188cabdff1aSopenharmony_ci            return AVERROR_UNKNOWN;
189cabdff1aSopenharmony_ci        zstream->next_in   = data;
190cabdff1aSopenharmony_ci        zstream->avail_in  = block_size;
191cabdff1aSopenharmony_ci        zret = inflate(zstream, Z_SYNC_FLUSH);
192cabdff1aSopenharmony_ci        if (zret != Z_OK)
193cabdff1aSopenharmony_ci            return AVERROR_UNKNOWN;
194cabdff1aSopenharmony_ci        data      += block_size;
195cabdff1aSopenharmony_ci        remaining -= block_size;
196cabdff1aSopenharmony_ci    }
197cabdff1aSopenharmony_ci
198cabdff1aSopenharmony_ci    return 0;
199cabdff1aSopenharmony_ci}
200cabdff1aSopenharmony_ci
201cabdff1aSopenharmony_cistatic int flashsv_decode_block(AVCodecContext *avctx, const AVPacket *avpkt,
202cabdff1aSopenharmony_ci                                GetBitContext *gb, int block_size,
203cabdff1aSopenharmony_ci                                int width, int height, int x_pos, int y_pos,
204cabdff1aSopenharmony_ci                                int blk_idx)
205cabdff1aSopenharmony_ci{
206cabdff1aSopenharmony_ci    struct FlashSVContext *s = avctx->priv_data;
207cabdff1aSopenharmony_ci    z_stream *const zstream = &s->zstream.zstream;
208cabdff1aSopenharmony_ci    uint8_t *line = s->tmpblock;
209cabdff1aSopenharmony_ci    int k;
210cabdff1aSopenharmony_ci    int ret = inflateReset(zstream);
211cabdff1aSopenharmony_ci    if (ret != Z_OK) {
212cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
213cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
214cabdff1aSopenharmony_ci    }
215cabdff1aSopenharmony_ci    if (s->zlibprime_curr || s->zlibprime_prev) {
216cabdff1aSopenharmony_ci        ret = flashsv2_prime(s,
217cabdff1aSopenharmony_ci                             s->blocks[blk_idx].pos,
218cabdff1aSopenharmony_ci                             s->blocks[blk_idx].size);
219cabdff1aSopenharmony_ci        if (ret < 0)
220cabdff1aSopenharmony_ci            return ret;
221cabdff1aSopenharmony_ci    }
222cabdff1aSopenharmony_ci    zstream->next_in   = avpkt->data + get_bits_count(gb) / 8;
223cabdff1aSopenharmony_ci    zstream->avail_in  = block_size;
224cabdff1aSopenharmony_ci    zstream->next_out  = s->tmpblock;
225cabdff1aSopenharmony_ci    zstream->avail_out = s->block_size * 3;
226cabdff1aSopenharmony_ci    ret = inflate(zstream, Z_FINISH);
227cabdff1aSopenharmony_ci    if (ret == Z_DATA_ERROR) {
228cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Zlib resync occurred\n");
229cabdff1aSopenharmony_ci        inflateSync(zstream);
230cabdff1aSopenharmony_ci        ret = inflate(zstream, Z_FINISH);
231cabdff1aSopenharmony_ci    }
232cabdff1aSopenharmony_ci
233cabdff1aSopenharmony_ci    if (ret != Z_OK && ret != Z_STREAM_END) {
234cabdff1aSopenharmony_ci        //return -1;
235cabdff1aSopenharmony_ci    }
236cabdff1aSopenharmony_ci
237cabdff1aSopenharmony_ci    if (s->is_keyframe) {
238cabdff1aSopenharmony_ci        s->blocks[blk_idx].pos  = s->keyframedata + (get_bits_count(gb) / 8);
239cabdff1aSopenharmony_ci        s->blocks[blk_idx].size = block_size;
240cabdff1aSopenharmony_ci    }
241cabdff1aSopenharmony_ci
242cabdff1aSopenharmony_ci    y_pos += s->diff_start;
243cabdff1aSopenharmony_ci
244cabdff1aSopenharmony_ci    if (!s->color_depth) {
245cabdff1aSopenharmony_ci        /* Flash Screen Video stores the image upside down, so copy
246cabdff1aSopenharmony_ci         * lines to destination in reverse order. */
247cabdff1aSopenharmony_ci        for (k = 1; k <= s->diff_height; k++) {
248cabdff1aSopenharmony_ci            memcpy(s->frame->data[0] + x_pos * 3 +
249cabdff1aSopenharmony_ci                   (s->image_height - y_pos - k) * s->frame->linesize[0],
250cabdff1aSopenharmony_ci                   line, width * 3);
251cabdff1aSopenharmony_ci            /* advance source pointer to next line */
252cabdff1aSopenharmony_ci            line += width * 3;
253cabdff1aSopenharmony_ci        }
254cabdff1aSopenharmony_ci    } else {
255cabdff1aSopenharmony_ci        /* hybrid 15-bit/palette mode */
256cabdff1aSopenharmony_ci        ret = decode_hybrid(s->tmpblock, zstream->next_out,
257cabdff1aSopenharmony_ci                      s->frame->data[0],
258cabdff1aSopenharmony_ci                      s->image_height - (y_pos + 1 + s->diff_height),
259cabdff1aSopenharmony_ci                      x_pos, s->diff_height, width,
260cabdff1aSopenharmony_ci                      s->frame->linesize[0], s->pal);
261cabdff1aSopenharmony_ci        if (ret < 0) {
262cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "decode_hybrid failed\n");
263cabdff1aSopenharmony_ci            return ret;
264cabdff1aSopenharmony_ci        }
265cabdff1aSopenharmony_ci    }
266cabdff1aSopenharmony_ci    skip_bits_long(gb, 8 * block_size); /* skip the consumed bits */
267cabdff1aSopenharmony_ci    return 0;
268cabdff1aSopenharmony_ci}
269cabdff1aSopenharmony_ci
270cabdff1aSopenharmony_cistatic int flashsv_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
271cabdff1aSopenharmony_ci                                int *got_frame, AVPacket *avpkt)
272cabdff1aSopenharmony_ci{
273cabdff1aSopenharmony_ci    int buf_size = avpkt->size;
274cabdff1aSopenharmony_ci    FlashSVContext *s = avctx->priv_data;
275cabdff1aSopenharmony_ci    int h_blocks, v_blocks, h_part, v_part, i, j, ret;
276cabdff1aSopenharmony_ci    GetBitContext gb;
277cabdff1aSopenharmony_ci    int last_blockwidth = s->block_width;
278cabdff1aSopenharmony_ci    int last_blockheight= s->block_height;
279cabdff1aSopenharmony_ci
280cabdff1aSopenharmony_ci    /* no supplementary picture */
281cabdff1aSopenharmony_ci    if (buf_size == 0)
282cabdff1aSopenharmony_ci        return 0;
283cabdff1aSopenharmony_ci    if (buf_size < 4)
284cabdff1aSopenharmony_ci        return -1;
285cabdff1aSopenharmony_ci
286cabdff1aSopenharmony_ci    if ((ret = init_get_bits8(&gb, avpkt->data, buf_size)) < 0)
287cabdff1aSopenharmony_ci        return ret;
288cabdff1aSopenharmony_ci
289cabdff1aSopenharmony_ci    /* start to parse the bitstream */
290cabdff1aSopenharmony_ci    s->block_width  = 16 * (get_bits(&gb, 4) + 1);
291cabdff1aSopenharmony_ci    s->image_width  = get_bits(&gb, 12);
292cabdff1aSopenharmony_ci    s->block_height = 16 * (get_bits(&gb, 4) + 1);
293cabdff1aSopenharmony_ci    s->image_height = get_bits(&gb, 12);
294cabdff1aSopenharmony_ci
295cabdff1aSopenharmony_ci    if (   last_blockwidth != s->block_width
296cabdff1aSopenharmony_ci        || last_blockheight!= s->block_height)
297cabdff1aSopenharmony_ci        av_freep(&s->blocks);
298cabdff1aSopenharmony_ci
299cabdff1aSopenharmony_ci    if (s->ver == 2) {
300cabdff1aSopenharmony_ci        skip_bits(&gb, 6);
301cabdff1aSopenharmony_ci        if (get_bits1(&gb)) {
302cabdff1aSopenharmony_ci            avpriv_request_sample(avctx, "iframe");
303cabdff1aSopenharmony_ci            return AVERROR_PATCHWELCOME;
304cabdff1aSopenharmony_ci        }
305cabdff1aSopenharmony_ci        if (get_bits1(&gb)) {
306cabdff1aSopenharmony_ci            avpriv_request_sample(avctx, "Custom palette");
307cabdff1aSopenharmony_ci            return AVERROR_PATCHWELCOME;
308cabdff1aSopenharmony_ci        }
309cabdff1aSopenharmony_ci    }
310cabdff1aSopenharmony_ci
311cabdff1aSopenharmony_ci    /* calculate number of blocks and size of border (partial) blocks */
312cabdff1aSopenharmony_ci    h_blocks = s->image_width  / s->block_width;
313cabdff1aSopenharmony_ci    h_part   = s->image_width  % s->block_width;
314cabdff1aSopenharmony_ci    v_blocks = s->image_height / s->block_height;
315cabdff1aSopenharmony_ci    v_part   = s->image_height % s->block_height;
316cabdff1aSopenharmony_ci
317cabdff1aSopenharmony_ci    /* the block size could change between frames, make sure the buffer
318cabdff1aSopenharmony_ci     * is large enough, if not, get a larger one */
319cabdff1aSopenharmony_ci    if (s->block_size < s->block_width * s->block_height) {
320cabdff1aSopenharmony_ci        int tmpblock_size = 3 * s->block_width * s->block_height, err;
321cabdff1aSopenharmony_ci
322cabdff1aSopenharmony_ci        if ((err = av_reallocp(&s->tmpblock, tmpblock_size)) < 0) {
323cabdff1aSopenharmony_ci            s->block_size = 0;
324cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
325cabdff1aSopenharmony_ci                   "Cannot allocate decompression buffer.\n");
326cabdff1aSopenharmony_ci            return err;
327cabdff1aSopenharmony_ci        }
328cabdff1aSopenharmony_ci    }
329cabdff1aSopenharmony_ci    s->block_size = s->block_width * s->block_height;
330cabdff1aSopenharmony_ci
331cabdff1aSopenharmony_ci    /* initialize the image size once */
332cabdff1aSopenharmony_ci    if (avctx->width == 0 && avctx->height == 0) {
333cabdff1aSopenharmony_ci        if ((ret = ff_set_dimensions(avctx, s->image_width, s->image_height)) < 0)
334cabdff1aSopenharmony_ci            return ret;
335cabdff1aSopenharmony_ci    }
336cabdff1aSopenharmony_ci
337cabdff1aSopenharmony_ci    /* check for changes of image width and image height */
338cabdff1aSopenharmony_ci    if (avctx->width != s->image_width || avctx->height != s->image_height) {
339cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
340cabdff1aSopenharmony_ci               "Frame width or height differs from first frame!\n");
341cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "fh = %d, fv %d  vs  ch = %d, cv = %d\n",
342cabdff1aSopenharmony_ci               avctx->height, avctx->width, s->image_height, s->image_width);
343cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
344cabdff1aSopenharmony_ci    }
345cabdff1aSopenharmony_ci
346cabdff1aSopenharmony_ci    /* we care for keyframes only in Screen Video v2 */
347cabdff1aSopenharmony_ci    s->is_keyframe = (avpkt->flags & AV_PKT_FLAG_KEY) && (s->ver == 2);
348cabdff1aSopenharmony_ci    if (s->is_keyframe) {
349cabdff1aSopenharmony_ci        int err = av_buffer_replace(&s->keyframedata_buf, avpkt->buf);
350cabdff1aSopenharmony_ci        if (err < 0)
351cabdff1aSopenharmony_ci            return err;
352cabdff1aSopenharmony_ci        s->keyframedata = avpkt->data;
353cabdff1aSopenharmony_ci        if (s->blocks)
354cabdff1aSopenharmony_ci            memset(s->blocks, 0, (v_blocks + !!v_part) * (h_blocks + !!h_part) *
355cabdff1aSopenharmony_ci                                 sizeof(s->blocks[0]));
356cabdff1aSopenharmony_ci    }
357cabdff1aSopenharmony_ci    if(s->ver == 2 && !s->blocks)
358cabdff1aSopenharmony_ci        s->blocks = av_mallocz((v_blocks + !!v_part) * (h_blocks + !!h_part) *
359cabdff1aSopenharmony_ci                               sizeof(s->blocks[0]));
360cabdff1aSopenharmony_ci
361cabdff1aSopenharmony_ci    ff_dlog(avctx, "image: %dx%d block: %dx%d num: %dx%d part: %dx%d\n",
362cabdff1aSopenharmony_ci            s->image_width, s->image_height, s->block_width, s->block_height,
363cabdff1aSopenharmony_ci            h_blocks, v_blocks, h_part, v_part);
364cabdff1aSopenharmony_ci
365cabdff1aSopenharmony_ci    if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
366cabdff1aSopenharmony_ci        return ret;
367cabdff1aSopenharmony_ci
368cabdff1aSopenharmony_ci    /* loop over all block columns */
369cabdff1aSopenharmony_ci    for (j = 0; j < v_blocks + (v_part ? 1 : 0); j++) {
370cabdff1aSopenharmony_ci
371cabdff1aSopenharmony_ci        int y_pos  = j * s->block_height; // vertical position in frame
372cabdff1aSopenharmony_ci        int cur_blk_height = (j < v_blocks) ? s->block_height : v_part;
373cabdff1aSopenharmony_ci
374cabdff1aSopenharmony_ci        /* loop over all block rows */
375cabdff1aSopenharmony_ci        for (i = 0; i < h_blocks + (h_part ? 1 : 0); i++) {
376cabdff1aSopenharmony_ci            int x_pos = i * s->block_width; // horizontal position in frame
377cabdff1aSopenharmony_ci            int cur_blk_width = (i < h_blocks) ? s->block_width : h_part;
378cabdff1aSopenharmony_ci            int has_diff = 0;
379cabdff1aSopenharmony_ci
380cabdff1aSopenharmony_ci            /* get the size of the compressed zlib chunk */
381cabdff1aSopenharmony_ci            int size = get_bits(&gb, 16);
382cabdff1aSopenharmony_ci
383cabdff1aSopenharmony_ci            s->color_depth    = 0;
384cabdff1aSopenharmony_ci            s->zlibprime_curr = 0;
385cabdff1aSopenharmony_ci            s->zlibprime_prev = 0;
386cabdff1aSopenharmony_ci            s->diff_start     = 0;
387cabdff1aSopenharmony_ci            s->diff_height    = cur_blk_height;
388cabdff1aSopenharmony_ci
389cabdff1aSopenharmony_ci            if (8 * size > get_bits_left(&gb)) {
390cabdff1aSopenharmony_ci                av_frame_unref(s->frame);
391cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
392cabdff1aSopenharmony_ci            }
393cabdff1aSopenharmony_ci
394cabdff1aSopenharmony_ci            if (s->ver == 2 && size) {
395cabdff1aSopenharmony_ci                skip_bits(&gb, 3);
396cabdff1aSopenharmony_ci                s->color_depth    = get_bits(&gb, 2);
397cabdff1aSopenharmony_ci                has_diff          = get_bits1(&gb);
398cabdff1aSopenharmony_ci                s->zlibprime_curr = get_bits1(&gb);
399cabdff1aSopenharmony_ci                s->zlibprime_prev = get_bits1(&gb);
400cabdff1aSopenharmony_ci
401cabdff1aSopenharmony_ci                if (s->color_depth != 0 && s->color_depth != 2) {
402cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_ERROR,
403cabdff1aSopenharmony_ci                           "%dx%d invalid color depth %d\n",
404cabdff1aSopenharmony_ci                           i, j, s->color_depth);
405cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
406cabdff1aSopenharmony_ci                }
407cabdff1aSopenharmony_ci
408cabdff1aSopenharmony_ci                if (has_diff) {
409cabdff1aSopenharmony_ci                    if (size < 3) {
410cabdff1aSopenharmony_ci                        av_log(avctx, AV_LOG_ERROR, "size too small for diff\n");
411cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
412cabdff1aSopenharmony_ci                    }
413cabdff1aSopenharmony_ci                    if (!s->keyframe) {
414cabdff1aSopenharmony_ci                        av_log(avctx, AV_LOG_ERROR,
415cabdff1aSopenharmony_ci                               "Inter frame without keyframe\n");
416cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
417cabdff1aSopenharmony_ci                    }
418cabdff1aSopenharmony_ci                    s->diff_start  = get_bits(&gb, 8);
419cabdff1aSopenharmony_ci                    s->diff_height = get_bits(&gb, 8);
420cabdff1aSopenharmony_ci                    if (s->diff_start + s->diff_height > cur_blk_height) {
421cabdff1aSopenharmony_ci                        av_log(avctx, AV_LOG_ERROR,
422cabdff1aSopenharmony_ci                               "Block parameters invalid: %d + %d > %d\n",
423cabdff1aSopenharmony_ci                               s->diff_start, s->diff_height, cur_blk_height);
424cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
425cabdff1aSopenharmony_ci                    }
426cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_DEBUG,
427cabdff1aSopenharmony_ci                           "%dx%d diff start %d height %d\n",
428cabdff1aSopenharmony_ci                           i, j, s->diff_start, s->diff_height);
429cabdff1aSopenharmony_ci                    size -= 2;
430cabdff1aSopenharmony_ci                }
431cabdff1aSopenharmony_ci
432cabdff1aSopenharmony_ci                if (s->zlibprime_prev)
433cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_DEBUG, "%dx%d zlibprime_prev\n", i, j);
434cabdff1aSopenharmony_ci
435cabdff1aSopenharmony_ci                if (s->zlibprime_curr) {
436cabdff1aSopenharmony_ci                    int col = get_bits(&gb, 8);
437cabdff1aSopenharmony_ci                    int row = get_bits(&gb, 8);
438cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_DEBUG, "%dx%d zlibprime_curr %dx%d\n",
439cabdff1aSopenharmony_ci                           i, j, col, row);
440cabdff1aSopenharmony_ci                    if (size < 3) {
441cabdff1aSopenharmony_ci                        av_log(avctx, AV_LOG_ERROR, "size too small for zlibprime_curr\n");
442cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
443cabdff1aSopenharmony_ci                    }
444cabdff1aSopenharmony_ci                    size -= 2;
445cabdff1aSopenharmony_ci                    avpriv_request_sample(avctx, "zlibprime_curr");
446cabdff1aSopenharmony_ci                    return AVERROR_PATCHWELCOME;
447cabdff1aSopenharmony_ci                }
448cabdff1aSopenharmony_ci                if (!s->blocks && (s->zlibprime_curr || s->zlibprime_prev)) {
449cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_ERROR,
450cabdff1aSopenharmony_ci                           "no data available for zlib priming\n");
451cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
452cabdff1aSopenharmony_ci                }
453cabdff1aSopenharmony_ci                size--; // account for flags byte
454cabdff1aSopenharmony_ci            }
455cabdff1aSopenharmony_ci
456cabdff1aSopenharmony_ci            if (has_diff) {
457cabdff1aSopenharmony_ci                int k;
458cabdff1aSopenharmony_ci                int off = (s->image_height - y_pos - 1) * s->frame->linesize[0];
459cabdff1aSopenharmony_ci
460cabdff1aSopenharmony_ci                for (k = 0; k < cur_blk_height; k++) {
461cabdff1aSopenharmony_ci                    int x = off - k * s->frame->linesize[0] + x_pos * 3;
462cabdff1aSopenharmony_ci                    memcpy(s->frame->data[0] + x, s->keyframe + x,
463cabdff1aSopenharmony_ci                           cur_blk_width * 3);
464cabdff1aSopenharmony_ci                }
465cabdff1aSopenharmony_ci            }
466cabdff1aSopenharmony_ci
467cabdff1aSopenharmony_ci            /* skip unchanged blocks, which have size 0 */
468cabdff1aSopenharmony_ci            if (size) {
469cabdff1aSopenharmony_ci                if (flashsv_decode_block(avctx, avpkt, &gb, size,
470cabdff1aSopenharmony_ci                                         cur_blk_width, cur_blk_height,
471cabdff1aSopenharmony_ci                                         x_pos, y_pos,
472cabdff1aSopenharmony_ci                                         i + j * (h_blocks + !!h_part)))
473cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_ERROR,
474cabdff1aSopenharmony_ci                           "error in decompression of block %dx%d\n", i, j);
475cabdff1aSopenharmony_ci            }
476cabdff1aSopenharmony_ci        }
477cabdff1aSopenharmony_ci    }
478cabdff1aSopenharmony_ci    if (s->is_keyframe && s->ver == 2) {
479cabdff1aSopenharmony_ci        if (!s->keyframe) {
480cabdff1aSopenharmony_ci            s->keyframe = av_malloc(s->frame->linesize[0] * avctx->height);
481cabdff1aSopenharmony_ci            if (!s->keyframe) {
482cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "Cannot allocate image data\n");
483cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
484cabdff1aSopenharmony_ci            }
485cabdff1aSopenharmony_ci        }
486cabdff1aSopenharmony_ci        memcpy(s->keyframe, s->frame->data[0],
487cabdff1aSopenharmony_ci               s->frame->linesize[0] * avctx->height);
488cabdff1aSopenharmony_ci    }
489cabdff1aSopenharmony_ci
490cabdff1aSopenharmony_ci    if ((ret = av_frame_ref(rframe, s->frame)) < 0)
491cabdff1aSopenharmony_ci        return ret;
492cabdff1aSopenharmony_ci
493cabdff1aSopenharmony_ci    *got_frame = 1;
494cabdff1aSopenharmony_ci
495cabdff1aSopenharmony_ci    if ((get_bits_count(&gb) / 8) != buf_size)
496cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "buffer not fully consumed (%d != %d)\n",
497cabdff1aSopenharmony_ci               buf_size, (get_bits_count(&gb) / 8));
498cabdff1aSopenharmony_ci
499cabdff1aSopenharmony_ci    /* report that the buffer was completely consumed */
500cabdff1aSopenharmony_ci    return buf_size;
501cabdff1aSopenharmony_ci}
502cabdff1aSopenharmony_ci
503cabdff1aSopenharmony_ci#if CONFIG_FLASHSV_DECODER
504cabdff1aSopenharmony_ciconst FFCodec ff_flashsv_decoder = {
505cabdff1aSopenharmony_ci    .p.name         = "flashsv",
506cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Flash Screen Video v1"),
507cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
508cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_FLASHSV,
509cabdff1aSopenharmony_ci    .priv_data_size = sizeof(FlashSVContext),
510cabdff1aSopenharmony_ci    .init           = flashsv_decode_init,
511cabdff1aSopenharmony_ci    .close          = flashsv_decode_end,
512cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(flashsv_decode_frame),
513cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1,
514cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
515cabdff1aSopenharmony_ci    .p.pix_fmts     = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE },
516cabdff1aSopenharmony_ci};
517cabdff1aSopenharmony_ci#endif /* CONFIG_FLASHSV_DECODER */
518cabdff1aSopenharmony_ci
519cabdff1aSopenharmony_ci#if CONFIG_FLASHSV2_DECODER
520cabdff1aSopenharmony_cistatic const uint32_t ff_flashsv2_default_palette[128] = {
521cabdff1aSopenharmony_ci    0x000000, 0x333333, 0x666666, 0x999999, 0xCCCCCC, 0xFFFFFF,
522cabdff1aSopenharmony_ci    0x330000, 0x660000, 0x990000, 0xCC0000, 0xFF0000, 0x003300,
523cabdff1aSopenharmony_ci    0x006600, 0x009900, 0x00CC00, 0x00FF00, 0x000033, 0x000066,
524cabdff1aSopenharmony_ci    0x000099, 0x0000CC, 0x0000FF, 0x333300, 0x666600, 0x999900,
525cabdff1aSopenharmony_ci    0xCCCC00, 0xFFFF00, 0x003333, 0x006666, 0x009999, 0x00CCCC,
526cabdff1aSopenharmony_ci    0x00FFFF, 0x330033, 0x660066, 0x990099, 0xCC00CC, 0xFF00FF,
527cabdff1aSopenharmony_ci    0xFFFF33, 0xFFFF66, 0xFFFF99, 0xFFFFCC, 0xFF33FF, 0xFF66FF,
528cabdff1aSopenharmony_ci    0xFF99FF, 0xFFCCFF, 0x33FFFF, 0x66FFFF, 0x99FFFF, 0xCCFFFF,
529cabdff1aSopenharmony_ci    0xCCCC33, 0xCCCC66, 0xCCCC99, 0xCCCCFF, 0xCC33CC, 0xCC66CC,
530cabdff1aSopenharmony_ci    0xCC99CC, 0xCCFFCC, 0x33CCCC, 0x66CCCC, 0x99CCCC, 0xFFCCCC,
531cabdff1aSopenharmony_ci    0x999933, 0x999966, 0x9999CC, 0x9999FF, 0x993399, 0x996699,
532cabdff1aSopenharmony_ci    0x99CC99, 0x99FF99, 0x339999, 0x669999, 0xCC9999, 0xFF9999,
533cabdff1aSopenharmony_ci    0x666633, 0x666699, 0x6666CC, 0x6666FF, 0x663366, 0x669966,
534cabdff1aSopenharmony_ci    0x66CC66, 0x66FF66, 0x336666, 0x996666, 0xCC6666, 0xFF6666,
535cabdff1aSopenharmony_ci    0x333366, 0x333399, 0x3333CC, 0x3333FF, 0x336633, 0x339933,
536cabdff1aSopenharmony_ci    0x33CC33, 0x33FF33, 0x663333, 0x993333, 0xCC3333, 0xFF3333,
537cabdff1aSopenharmony_ci    0x003366, 0x336600, 0x660033, 0x006633, 0x330066, 0x663300,
538cabdff1aSopenharmony_ci    0x336699, 0x669933, 0x993366, 0x339966, 0x663399, 0x996633,
539cabdff1aSopenharmony_ci    0x6699CC, 0x99CC66, 0xCC6699, 0x66CC99, 0x9966CC, 0xCC9966,
540cabdff1aSopenharmony_ci    0x99CCFF, 0xCCFF99, 0xFF99CC, 0x99FFCC, 0xCC99FF, 0xFFCC99,
541cabdff1aSopenharmony_ci    0x111111, 0x222222, 0x444444, 0x555555, 0xAAAAAA, 0xBBBBBB,
542cabdff1aSopenharmony_ci    0xDDDDDD, 0xEEEEEE
543cabdff1aSopenharmony_ci};
544cabdff1aSopenharmony_ci
545cabdff1aSopenharmony_cistatic av_cold int flashsv2_decode_init(AVCodecContext *avctx)
546cabdff1aSopenharmony_ci{
547cabdff1aSopenharmony_ci    FlashSVContext *s = avctx->priv_data;
548cabdff1aSopenharmony_ci    int ret;
549cabdff1aSopenharmony_ci
550cabdff1aSopenharmony_ci    ret = flashsv_decode_init(avctx);
551cabdff1aSopenharmony_ci    if (ret < 0)
552cabdff1aSopenharmony_ci        return ret;
553cabdff1aSopenharmony_ci    s->pal = ff_flashsv2_default_palette;
554cabdff1aSopenharmony_ci    s->ver = 2;
555cabdff1aSopenharmony_ci
556cabdff1aSopenharmony_ci    return 0;
557cabdff1aSopenharmony_ci}
558cabdff1aSopenharmony_ci
559cabdff1aSopenharmony_cistatic av_cold int flashsv2_decode_end(AVCodecContext *avctx)
560cabdff1aSopenharmony_ci{
561cabdff1aSopenharmony_ci    FlashSVContext *s = avctx->priv_data;
562cabdff1aSopenharmony_ci
563cabdff1aSopenharmony_ci    av_buffer_unref(&s->keyframedata_buf);
564cabdff1aSopenharmony_ci    s->keyframedata = NULL;
565cabdff1aSopenharmony_ci    av_freep(&s->blocks);
566cabdff1aSopenharmony_ci    av_freep(&s->keyframe);
567cabdff1aSopenharmony_ci    flashsv_decode_end(avctx);
568cabdff1aSopenharmony_ci
569cabdff1aSopenharmony_ci    return 0;
570cabdff1aSopenharmony_ci}
571cabdff1aSopenharmony_ci
572cabdff1aSopenharmony_ciconst FFCodec ff_flashsv2_decoder = {
573cabdff1aSopenharmony_ci    .p.name         = "flashsv2",
574cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Flash Screen Video v2"),
575cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
576cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_FLASHSV2,
577cabdff1aSopenharmony_ci    .priv_data_size = sizeof(FlashSVContext),
578cabdff1aSopenharmony_ci    .init           = flashsv2_decode_init,
579cabdff1aSopenharmony_ci    .close          = flashsv2_decode_end,
580cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(flashsv_decode_frame),
581cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1,
582cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
583cabdff1aSopenharmony_ci    .p.pix_fmts     = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE },
584cabdff1aSopenharmony_ci};
585cabdff1aSopenharmony_ci#endif /* CONFIG_FLASHSV2_DECODER */
586