1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * FLI/FLC Animation Video Decoder
3cabdff1aSopenharmony_ci * Copyright (C) 2003, 2004 The FFmpeg project
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/**
23cabdff1aSopenharmony_ci * @file
24cabdff1aSopenharmony_ci * Autodesk Animator FLI/FLC Video Decoder
25cabdff1aSopenharmony_ci * by Mike Melanson (melanson@pcisys.net)
26cabdff1aSopenharmony_ci * for more information on the .fli/.flc file format and all of its many
27cabdff1aSopenharmony_ci * variations, visit:
28cabdff1aSopenharmony_ci *   http://www.compuphase.com/flic.htm
29cabdff1aSopenharmony_ci *
30cabdff1aSopenharmony_ci * This decoder outputs PAL8/RGB555/RGB565/BGR24. To use this decoder, be
31cabdff1aSopenharmony_ci * sure that your demuxer sends the FLI file header to the decoder via
32cabdff1aSopenharmony_ci * the extradata chunk in AVCodecContext. The chunk should be 128 bytes
33cabdff1aSopenharmony_ci * large. The only exception is for FLI files from the game "Magic Carpet",
34cabdff1aSopenharmony_ci * in which the header is only 12 bytes.
35cabdff1aSopenharmony_ci */
36cabdff1aSopenharmony_ci
37cabdff1aSopenharmony_ci#include <stdio.h>
38cabdff1aSopenharmony_ci#include <stdlib.h>
39cabdff1aSopenharmony_ci#include <string.h>
40cabdff1aSopenharmony_ci
41cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
42cabdff1aSopenharmony_ci#include "avcodec.h"
43cabdff1aSopenharmony_ci#include "bytestream.h"
44cabdff1aSopenharmony_ci#include "codec_internal.h"
45cabdff1aSopenharmony_ci#include "internal.h"
46cabdff1aSopenharmony_ci#include "mathops.h"
47cabdff1aSopenharmony_ci
48cabdff1aSopenharmony_ci#define FLI_256_COLOR 4
49cabdff1aSopenharmony_ci#define FLI_DELTA     7
50cabdff1aSopenharmony_ci#define FLI_COLOR     11
51cabdff1aSopenharmony_ci#define FLI_LC        12
52cabdff1aSopenharmony_ci#define FLI_BLACK     13
53cabdff1aSopenharmony_ci#define FLI_BRUN      15
54cabdff1aSopenharmony_ci#define FLI_COPY      16
55cabdff1aSopenharmony_ci#define FLI_MINI      18
56cabdff1aSopenharmony_ci#define FLI_DTA_BRUN  25
57cabdff1aSopenharmony_ci#define FLI_DTA_COPY  26
58cabdff1aSopenharmony_ci#define FLI_DTA_LC    27
59cabdff1aSopenharmony_ci
60cabdff1aSopenharmony_ci#define FLI_TYPE_CODE     (0xAF11)
61cabdff1aSopenharmony_ci#define FLC_FLX_TYPE_CODE (0xAF12)
62cabdff1aSopenharmony_ci#define FLC_DTA_TYPE_CODE (0xAF44) /* Marks an "Extended FLC" comes from Dave's Targa Animator (DTA) */
63cabdff1aSopenharmony_ci#define FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE (0xAF13)
64cabdff1aSopenharmony_ci
65cabdff1aSopenharmony_ci#define CHECK_PIXEL_PTR(n) \
66cabdff1aSopenharmony_ci    if (pixel_ptr + n > pixel_limit) { \
67cabdff1aSopenharmony_ci        av_log (s->avctx, AV_LOG_ERROR, "Invalid pixel_ptr = %d > pixel_limit = %d\n", \
68cabdff1aSopenharmony_ci        pixel_ptr + n, pixel_limit); \
69cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA; \
70cabdff1aSopenharmony_ci    } \
71cabdff1aSopenharmony_ci
72cabdff1aSopenharmony_citypedef struct FlicDecodeContext {
73cabdff1aSopenharmony_ci    AVCodecContext *avctx;
74cabdff1aSopenharmony_ci    AVFrame *frame;
75cabdff1aSopenharmony_ci
76cabdff1aSopenharmony_ci    unsigned int palette[256];
77cabdff1aSopenharmony_ci    int new_palette;
78cabdff1aSopenharmony_ci    int fli_type;  /* either 0xAF11 or 0xAF12, affects palette resolution */
79cabdff1aSopenharmony_ci} FlicDecodeContext;
80cabdff1aSopenharmony_ci
81cabdff1aSopenharmony_cistatic av_cold int flic_decode_init(AVCodecContext *avctx)
82cabdff1aSopenharmony_ci{
83cabdff1aSopenharmony_ci    FlicDecodeContext *s = avctx->priv_data;
84cabdff1aSopenharmony_ci    unsigned char *fli_header = (unsigned char *)avctx->extradata;
85cabdff1aSopenharmony_ci    int depth;
86cabdff1aSopenharmony_ci
87cabdff1aSopenharmony_ci    if (avctx->extradata_size != 0 &&
88cabdff1aSopenharmony_ci        avctx->extradata_size != 12 &&
89cabdff1aSopenharmony_ci        avctx->extradata_size != 128 &&
90cabdff1aSopenharmony_ci        avctx->extradata_size != 256 &&
91cabdff1aSopenharmony_ci        avctx->extradata_size != 904 &&
92cabdff1aSopenharmony_ci        avctx->extradata_size != 1024) {
93cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Unexpected extradata size %d\n", avctx->extradata_size);
94cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
95cabdff1aSopenharmony_ci    }
96cabdff1aSopenharmony_ci
97cabdff1aSopenharmony_ci    s->avctx = avctx;
98cabdff1aSopenharmony_ci
99cabdff1aSopenharmony_ci    if (s->avctx->extradata_size == 12) {
100cabdff1aSopenharmony_ci        /* special case for magic carpet FLIs */
101cabdff1aSopenharmony_ci        s->fli_type = FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE;
102cabdff1aSopenharmony_ci        depth = 8;
103cabdff1aSopenharmony_ci    } else if (avctx->extradata_size == 1024) {
104cabdff1aSopenharmony_ci        uint8_t *ptr = avctx->extradata;
105cabdff1aSopenharmony_ci        int i;
106cabdff1aSopenharmony_ci
107cabdff1aSopenharmony_ci        for (i = 0; i < 256; i++) {
108cabdff1aSopenharmony_ci            s->palette[i] = AV_RL32(ptr);
109cabdff1aSopenharmony_ci            ptr += 4;
110cabdff1aSopenharmony_ci        }
111cabdff1aSopenharmony_ci        depth = 8;
112cabdff1aSopenharmony_ci        /* FLI in MOV, see e.g. FFmpeg trac issue #626 */
113cabdff1aSopenharmony_ci    } else if (avctx->extradata_size == 0 ||
114cabdff1aSopenharmony_ci               avctx->extradata_size == 256 ||
115cabdff1aSopenharmony_ci        /* see FFmpeg ticket #1234 */
116cabdff1aSopenharmony_ci               avctx->extradata_size == 904) {
117cabdff1aSopenharmony_ci        s->fli_type = FLI_TYPE_CODE;
118cabdff1aSopenharmony_ci        depth = 8;
119cabdff1aSopenharmony_ci    } else {
120cabdff1aSopenharmony_ci        s->fli_type = AV_RL16(&fli_header[4]);
121cabdff1aSopenharmony_ci        depth = AV_RL16(&fli_header[12]);
122cabdff1aSopenharmony_ci    }
123cabdff1aSopenharmony_ci
124cabdff1aSopenharmony_ci    if (depth == 0) {
125cabdff1aSopenharmony_ci        depth = 8; /* Some FLC generators set depth to zero, when they mean 8Bpp. Fix up here */
126cabdff1aSopenharmony_ci    }
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci    if ((s->fli_type == FLC_FLX_TYPE_CODE) && (depth == 16)) {
129cabdff1aSopenharmony_ci        depth = 15; /* Original Autodesk FLX's say the depth is 16Bpp when it is really 15Bpp */
130cabdff1aSopenharmony_ci    }
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci    switch (depth) {
133cabdff1aSopenharmony_ci        case 8  : avctx->pix_fmt = AV_PIX_FMT_PAL8; break;
134cabdff1aSopenharmony_ci        case 15 : avctx->pix_fmt = AV_PIX_FMT_RGB555; break;
135cabdff1aSopenharmony_ci        case 16 : avctx->pix_fmt = AV_PIX_FMT_RGB565; break;
136cabdff1aSopenharmony_ci        case 24 : avctx->pix_fmt = AV_PIX_FMT_BGR24; break;
137cabdff1aSopenharmony_ci        default :
138cabdff1aSopenharmony_ci                  av_log(avctx, AV_LOG_ERROR, "Unknown FLC/FLX depth of %d Bpp is unsupported.\n",depth);
139cabdff1aSopenharmony_ci                  return AVERROR_INVALIDDATA;
140cabdff1aSopenharmony_ci    }
141cabdff1aSopenharmony_ci
142cabdff1aSopenharmony_ci    s->frame = av_frame_alloc();
143cabdff1aSopenharmony_ci    if (!s->frame)
144cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
145cabdff1aSopenharmony_ci
146cabdff1aSopenharmony_ci    s->new_palette = 0;
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    return 0;
149cabdff1aSopenharmony_ci}
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_cistatic int flic_decode_frame_8BPP(AVCodecContext *avctx,
152cabdff1aSopenharmony_ci                                  AVFrame *rframe, int *got_frame,
153cabdff1aSopenharmony_ci                                  const uint8_t *buf, int buf_size)
154cabdff1aSopenharmony_ci{
155cabdff1aSopenharmony_ci    FlicDecodeContext *s = avctx->priv_data;
156cabdff1aSopenharmony_ci
157cabdff1aSopenharmony_ci    GetByteContext g2;
158cabdff1aSopenharmony_ci    int pixel_ptr;
159cabdff1aSopenharmony_ci    int palette_ptr;
160cabdff1aSopenharmony_ci    unsigned char palette_idx1;
161cabdff1aSopenharmony_ci    unsigned char palette_idx2;
162cabdff1aSopenharmony_ci
163cabdff1aSopenharmony_ci    unsigned int frame_size;
164cabdff1aSopenharmony_ci    int num_chunks;
165cabdff1aSopenharmony_ci
166cabdff1aSopenharmony_ci    unsigned int chunk_size;
167cabdff1aSopenharmony_ci    int chunk_type;
168cabdff1aSopenharmony_ci
169cabdff1aSopenharmony_ci    int i, j, ret;
170cabdff1aSopenharmony_ci
171cabdff1aSopenharmony_ci    int color_packets;
172cabdff1aSopenharmony_ci    int color_changes;
173cabdff1aSopenharmony_ci    int color_shift;
174cabdff1aSopenharmony_ci    unsigned char r, g, b;
175cabdff1aSopenharmony_ci
176cabdff1aSopenharmony_ci    int lines;
177cabdff1aSopenharmony_ci    int compressed_lines;
178cabdff1aSopenharmony_ci    int starting_line;
179cabdff1aSopenharmony_ci    int line_packets;
180cabdff1aSopenharmony_ci    int y_ptr;
181cabdff1aSopenharmony_ci    int byte_run;
182cabdff1aSopenharmony_ci    int pixel_skip;
183cabdff1aSopenharmony_ci    int pixel_countdown;
184cabdff1aSopenharmony_ci    unsigned char *pixels;
185cabdff1aSopenharmony_ci    unsigned int pixel_limit;
186cabdff1aSopenharmony_ci
187cabdff1aSopenharmony_ci    bytestream2_init(&g2, buf, buf_size);
188cabdff1aSopenharmony_ci
189cabdff1aSopenharmony_ci    if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
190cabdff1aSopenharmony_ci        return ret;
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_ci    pixels = s->frame->data[0];
193cabdff1aSopenharmony_ci    pixel_limit = s->avctx->height * s->frame->linesize[0];
194cabdff1aSopenharmony_ci    if (buf_size < 16 || buf_size > INT_MAX - (3 * 256 + AV_INPUT_BUFFER_PADDING_SIZE))
195cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
196cabdff1aSopenharmony_ci    frame_size = bytestream2_get_le32(&g2);
197cabdff1aSopenharmony_ci    if (frame_size > buf_size)
198cabdff1aSopenharmony_ci        frame_size = buf_size;
199cabdff1aSopenharmony_ci    bytestream2_skip(&g2, 2); /* skip the magic number */
200cabdff1aSopenharmony_ci    num_chunks = bytestream2_get_le16(&g2);
201cabdff1aSopenharmony_ci    bytestream2_skip(&g2, 8);  /* skip padding */
202cabdff1aSopenharmony_ci
203cabdff1aSopenharmony_ci    if (frame_size < 16)
204cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
205cabdff1aSopenharmony_ci
206cabdff1aSopenharmony_ci    frame_size -= 16;
207cabdff1aSopenharmony_ci
208cabdff1aSopenharmony_ci    /* iterate through the chunks */
209cabdff1aSopenharmony_ci    while ((frame_size >= 6) && (num_chunks > 0) &&
210cabdff1aSopenharmony_ci            bytestream2_get_bytes_left(&g2) >= 4) {
211cabdff1aSopenharmony_ci        int stream_ptr_after_chunk;
212cabdff1aSopenharmony_ci        chunk_size = bytestream2_get_le32(&g2);
213cabdff1aSopenharmony_ci        if (chunk_size > frame_size) {
214cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_WARNING,
215cabdff1aSopenharmony_ci                   "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size);
216cabdff1aSopenharmony_ci            chunk_size = frame_size;
217cabdff1aSopenharmony_ci        }
218cabdff1aSopenharmony_ci        stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size;
219cabdff1aSopenharmony_ci
220cabdff1aSopenharmony_ci        chunk_type = bytestream2_get_le16(&g2);
221cabdff1aSopenharmony_ci
222cabdff1aSopenharmony_ci        switch (chunk_type) {
223cabdff1aSopenharmony_ci        case FLI_256_COLOR:
224cabdff1aSopenharmony_ci        case FLI_COLOR:
225cabdff1aSopenharmony_ci            /* check special case: If this file is from the Magic Carpet
226cabdff1aSopenharmony_ci             * game and uses 6-bit colors even though it reports 256-color
227cabdff1aSopenharmony_ci             * chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during
228cabdff1aSopenharmony_ci             * initialization) */
229cabdff1aSopenharmony_ci            if ((chunk_type == FLI_256_COLOR) && (s->fli_type != FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE))
230cabdff1aSopenharmony_ci                color_shift = 0;
231cabdff1aSopenharmony_ci            else
232cabdff1aSopenharmony_ci                color_shift = 2;
233cabdff1aSopenharmony_ci            /* set up the palette */
234cabdff1aSopenharmony_ci            color_packets = bytestream2_get_le16(&g2);
235cabdff1aSopenharmony_ci            palette_ptr = 0;
236cabdff1aSopenharmony_ci            for (i = 0; i < color_packets; i++) {
237cabdff1aSopenharmony_ci                /* first byte is how many colors to skip */
238cabdff1aSopenharmony_ci                palette_ptr += bytestream2_get_byte(&g2);
239cabdff1aSopenharmony_ci
240cabdff1aSopenharmony_ci                /* next byte indicates how many entries to change */
241cabdff1aSopenharmony_ci                color_changes = bytestream2_get_byte(&g2);
242cabdff1aSopenharmony_ci
243cabdff1aSopenharmony_ci                /* if there are 0 color changes, there are actually 256 */
244cabdff1aSopenharmony_ci                if (color_changes == 0)
245cabdff1aSopenharmony_ci                    color_changes = 256;
246cabdff1aSopenharmony_ci
247cabdff1aSopenharmony_ci                if (bytestream2_tell(&g2) + color_changes * 3 > stream_ptr_after_chunk)
248cabdff1aSopenharmony_ci                    break;
249cabdff1aSopenharmony_ci
250cabdff1aSopenharmony_ci                for (j = 0; j < color_changes; j++) {
251cabdff1aSopenharmony_ci                    unsigned int entry;
252cabdff1aSopenharmony_ci
253cabdff1aSopenharmony_ci                    /* wrap around, for good measure */
254cabdff1aSopenharmony_ci                    if ((unsigned)palette_ptr >= 256)
255cabdff1aSopenharmony_ci                        palette_ptr = 0;
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci                    r = bytestream2_get_byte(&g2) << color_shift;
258cabdff1aSopenharmony_ci                    g = bytestream2_get_byte(&g2) << color_shift;
259cabdff1aSopenharmony_ci                    b = bytestream2_get_byte(&g2) << color_shift;
260cabdff1aSopenharmony_ci                    entry = 0xFFU << 24 | r << 16 | g << 8 | b;
261cabdff1aSopenharmony_ci                    if (color_shift == 2)
262cabdff1aSopenharmony_ci                        entry |= entry >> 6 & 0x30303;
263cabdff1aSopenharmony_ci                    if (s->palette[palette_ptr] != entry)
264cabdff1aSopenharmony_ci                        s->new_palette = 1;
265cabdff1aSopenharmony_ci                    s->palette[palette_ptr++] = entry;
266cabdff1aSopenharmony_ci                }
267cabdff1aSopenharmony_ci            }
268cabdff1aSopenharmony_ci            break;
269cabdff1aSopenharmony_ci
270cabdff1aSopenharmony_ci        case FLI_DELTA:
271cabdff1aSopenharmony_ci            y_ptr = 0;
272cabdff1aSopenharmony_ci            compressed_lines = bytestream2_get_le16(&g2);
273cabdff1aSopenharmony_ci            while (compressed_lines > 0) {
274cabdff1aSopenharmony_ci                if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk)
275cabdff1aSopenharmony_ci                    break;
276cabdff1aSopenharmony_ci                if (y_ptr > pixel_limit)
277cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
278cabdff1aSopenharmony_ci                line_packets = sign_extend(bytestream2_get_le16(&g2), 16);
279cabdff1aSopenharmony_ci                if ((line_packets & 0xC000) == 0xC000) {
280cabdff1aSopenharmony_ci                    // line skip opcode
281cabdff1aSopenharmony_ci                    line_packets = -line_packets;
282cabdff1aSopenharmony_ci                    if (line_packets > s->avctx->height)
283cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
284cabdff1aSopenharmony_ci                    y_ptr += line_packets * s->frame->linesize[0];
285cabdff1aSopenharmony_ci                } else if ((line_packets & 0xC000) == 0x4000) {
286cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_ERROR, "Undefined opcode (%x) in DELTA_FLI\n", line_packets);
287cabdff1aSopenharmony_ci                } else if ((line_packets & 0xC000) == 0x8000) {
288cabdff1aSopenharmony_ci                    // "last byte" opcode
289cabdff1aSopenharmony_ci                    pixel_ptr= y_ptr + s->frame->linesize[0] - 1;
290cabdff1aSopenharmony_ci                    CHECK_PIXEL_PTR(0);
291cabdff1aSopenharmony_ci                    pixels[pixel_ptr] = line_packets & 0xff;
292cabdff1aSopenharmony_ci                } else {
293cabdff1aSopenharmony_ci                    compressed_lines--;
294cabdff1aSopenharmony_ci                    pixel_ptr = y_ptr;
295cabdff1aSopenharmony_ci                    CHECK_PIXEL_PTR(0);
296cabdff1aSopenharmony_ci                    pixel_countdown = s->avctx->width;
297cabdff1aSopenharmony_ci                    for (i = 0; i < line_packets; i++) {
298cabdff1aSopenharmony_ci                        if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk)
299cabdff1aSopenharmony_ci                            break;
300cabdff1aSopenharmony_ci                        /* account for the skip bytes */
301cabdff1aSopenharmony_ci                        pixel_skip = bytestream2_get_byte(&g2);
302cabdff1aSopenharmony_ci                        pixel_ptr += pixel_skip;
303cabdff1aSopenharmony_ci                        pixel_countdown -= pixel_skip;
304cabdff1aSopenharmony_ci                        byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
305cabdff1aSopenharmony_ci                        if (byte_run < 0) {
306cabdff1aSopenharmony_ci                            byte_run = -byte_run;
307cabdff1aSopenharmony_ci                            palette_idx1 = bytestream2_get_byte(&g2);
308cabdff1aSopenharmony_ci                            palette_idx2 = bytestream2_get_byte(&g2);
309cabdff1aSopenharmony_ci                            CHECK_PIXEL_PTR(byte_run * 2);
310cabdff1aSopenharmony_ci                            for (j = 0; j < byte_run; j++, pixel_countdown -= 2) {
311cabdff1aSopenharmony_ci                                pixels[pixel_ptr++] = palette_idx1;
312cabdff1aSopenharmony_ci                                pixels[pixel_ptr++] = palette_idx2;
313cabdff1aSopenharmony_ci                            }
314cabdff1aSopenharmony_ci                        } else {
315cabdff1aSopenharmony_ci                            CHECK_PIXEL_PTR(byte_run * 2);
316cabdff1aSopenharmony_ci                            if (bytestream2_tell(&g2) + byte_run * 2 > stream_ptr_after_chunk)
317cabdff1aSopenharmony_ci                                break;
318cabdff1aSopenharmony_ci                            for (j = 0; j < byte_run * 2; j++, pixel_countdown--) {
319cabdff1aSopenharmony_ci                                pixels[pixel_ptr++] = bytestream2_get_byte(&g2);
320cabdff1aSopenharmony_ci                            }
321cabdff1aSopenharmony_ci                        }
322cabdff1aSopenharmony_ci                    }
323cabdff1aSopenharmony_ci
324cabdff1aSopenharmony_ci                    y_ptr += s->frame->linesize[0];
325cabdff1aSopenharmony_ci                }
326cabdff1aSopenharmony_ci            }
327cabdff1aSopenharmony_ci            break;
328cabdff1aSopenharmony_ci
329cabdff1aSopenharmony_ci        case FLI_LC:
330cabdff1aSopenharmony_ci            /* line compressed */
331cabdff1aSopenharmony_ci            starting_line = bytestream2_get_le16(&g2);
332cabdff1aSopenharmony_ci            if (starting_line >= s->avctx->height)
333cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
334cabdff1aSopenharmony_ci            y_ptr = 0;
335cabdff1aSopenharmony_ci            y_ptr += starting_line * s->frame->linesize[0];
336cabdff1aSopenharmony_ci
337cabdff1aSopenharmony_ci            compressed_lines = bytestream2_get_le16(&g2);
338cabdff1aSopenharmony_ci            while (compressed_lines > 0) {
339cabdff1aSopenharmony_ci                pixel_ptr = y_ptr;
340cabdff1aSopenharmony_ci                CHECK_PIXEL_PTR(0);
341cabdff1aSopenharmony_ci                pixel_countdown = s->avctx->width;
342cabdff1aSopenharmony_ci                if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
343cabdff1aSopenharmony_ci                    break;
344cabdff1aSopenharmony_ci                line_packets = bytestream2_get_byte(&g2);
345cabdff1aSopenharmony_ci                if (line_packets > 0) {
346cabdff1aSopenharmony_ci                    for (i = 0; i < line_packets; i++) {
347cabdff1aSopenharmony_ci                        /* account for the skip bytes */
348cabdff1aSopenharmony_ci                        if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
349cabdff1aSopenharmony_ci                            break;
350cabdff1aSopenharmony_ci                        pixel_skip = bytestream2_get_byte(&g2);
351cabdff1aSopenharmony_ci                        pixel_ptr += pixel_skip;
352cabdff1aSopenharmony_ci                        pixel_countdown -= pixel_skip;
353cabdff1aSopenharmony_ci                        byte_run = sign_extend(bytestream2_get_byte(&g2),8);
354cabdff1aSopenharmony_ci                        if (byte_run > 0) {
355cabdff1aSopenharmony_ci                            CHECK_PIXEL_PTR(byte_run);
356cabdff1aSopenharmony_ci                            if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk)
357cabdff1aSopenharmony_ci                                break;
358cabdff1aSopenharmony_ci                            for (j = 0; j < byte_run; j++, pixel_countdown--) {
359cabdff1aSopenharmony_ci                                pixels[pixel_ptr++] = bytestream2_get_byte(&g2);
360cabdff1aSopenharmony_ci                            }
361cabdff1aSopenharmony_ci                        } else if (byte_run < 0) {
362cabdff1aSopenharmony_ci                            byte_run = -byte_run;
363cabdff1aSopenharmony_ci                            palette_idx1 = bytestream2_get_byte(&g2);
364cabdff1aSopenharmony_ci                            CHECK_PIXEL_PTR(byte_run);
365cabdff1aSopenharmony_ci                            for (j = 0; j < byte_run; j++, pixel_countdown--) {
366cabdff1aSopenharmony_ci                                pixels[pixel_ptr++] = palette_idx1;
367cabdff1aSopenharmony_ci                            }
368cabdff1aSopenharmony_ci                        }
369cabdff1aSopenharmony_ci                    }
370cabdff1aSopenharmony_ci                }
371cabdff1aSopenharmony_ci
372cabdff1aSopenharmony_ci                y_ptr += s->frame->linesize[0];
373cabdff1aSopenharmony_ci                compressed_lines--;
374cabdff1aSopenharmony_ci            }
375cabdff1aSopenharmony_ci            break;
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_ci        case FLI_BLACK:
378cabdff1aSopenharmony_ci            /* set the whole frame to color 0 (which is usually black) */
379cabdff1aSopenharmony_ci            memset(pixels, 0,
380cabdff1aSopenharmony_ci                s->frame->linesize[0] * s->avctx->height);
381cabdff1aSopenharmony_ci            break;
382cabdff1aSopenharmony_ci
383cabdff1aSopenharmony_ci        case FLI_BRUN:
384cabdff1aSopenharmony_ci            /* Byte run compression: This chunk type only occurs in the first
385cabdff1aSopenharmony_ci             * FLI frame and it will update the entire frame. */
386cabdff1aSopenharmony_ci            y_ptr = 0;
387cabdff1aSopenharmony_ci            for (lines = 0; lines < s->avctx->height; lines++) {
388cabdff1aSopenharmony_ci                pixel_ptr = y_ptr;
389cabdff1aSopenharmony_ci                /* disregard the line packets; instead, iterate through all
390cabdff1aSopenharmony_ci                 * pixels on a row */
391cabdff1aSopenharmony_ci                 bytestream2_skip(&g2, 1);
392cabdff1aSopenharmony_ci                pixel_countdown = s->avctx->width;
393cabdff1aSopenharmony_ci                while (pixel_countdown > 0) {
394cabdff1aSopenharmony_ci                    if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
395cabdff1aSopenharmony_ci                        break;
396cabdff1aSopenharmony_ci                    byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
397cabdff1aSopenharmony_ci                    if (!byte_run) {
398cabdff1aSopenharmony_ci                        av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n");
399cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
400cabdff1aSopenharmony_ci                    }
401cabdff1aSopenharmony_ci
402cabdff1aSopenharmony_ci                    if (byte_run > 0) {
403cabdff1aSopenharmony_ci                        palette_idx1 = bytestream2_get_byte(&g2);
404cabdff1aSopenharmony_ci                        CHECK_PIXEL_PTR(byte_run);
405cabdff1aSopenharmony_ci                        for (j = 0; j < byte_run; j++) {
406cabdff1aSopenharmony_ci                            pixels[pixel_ptr++] = palette_idx1;
407cabdff1aSopenharmony_ci                            pixel_countdown--;
408cabdff1aSopenharmony_ci                            if (pixel_countdown < 0)
409cabdff1aSopenharmony_ci                                av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
410cabdff1aSopenharmony_ci                                       pixel_countdown, lines);
411cabdff1aSopenharmony_ci                        }
412cabdff1aSopenharmony_ci                    } else {  /* copy bytes if byte_run < 0 */
413cabdff1aSopenharmony_ci                        byte_run = -byte_run;
414cabdff1aSopenharmony_ci                        CHECK_PIXEL_PTR(byte_run);
415cabdff1aSopenharmony_ci                        if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk)
416cabdff1aSopenharmony_ci                            break;
417cabdff1aSopenharmony_ci                        for (j = 0; j < byte_run; j++) {
418cabdff1aSopenharmony_ci                            pixels[pixel_ptr++] = bytestream2_get_byte(&g2);
419cabdff1aSopenharmony_ci                            pixel_countdown--;
420cabdff1aSopenharmony_ci                            if (pixel_countdown < 0)
421cabdff1aSopenharmony_ci                                av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
422cabdff1aSopenharmony_ci                                       pixel_countdown, lines);
423cabdff1aSopenharmony_ci                        }
424cabdff1aSopenharmony_ci                    }
425cabdff1aSopenharmony_ci                }
426cabdff1aSopenharmony_ci
427cabdff1aSopenharmony_ci                y_ptr += s->frame->linesize[0];
428cabdff1aSopenharmony_ci            }
429cabdff1aSopenharmony_ci            break;
430cabdff1aSopenharmony_ci
431cabdff1aSopenharmony_ci        case FLI_COPY:
432cabdff1aSopenharmony_ci            /* copy the chunk (uncompressed frame) */
433cabdff1aSopenharmony_ci            if (chunk_size - 6 != FFALIGN(s->avctx->width, 4) * s->avctx->height) {
434cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \
435cabdff1aSopenharmony_ci                       "has incorrect size, skipping chunk\n", chunk_size - 6);
436cabdff1aSopenharmony_ci                bytestream2_skip(&g2, chunk_size - 6);
437cabdff1aSopenharmony_ci            } else {
438cabdff1aSopenharmony_ci                for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height;
439cabdff1aSopenharmony_ci                     y_ptr += s->frame->linesize[0]) {
440cabdff1aSopenharmony_ci                    bytestream2_get_buffer(&g2, &pixels[y_ptr],
441cabdff1aSopenharmony_ci                                           s->avctx->width);
442cabdff1aSopenharmony_ci                    if (s->avctx->width & 3)
443cabdff1aSopenharmony_ci                        bytestream2_skip(&g2, 4 - (s->avctx->width & 3));
444cabdff1aSopenharmony_ci                }
445cabdff1aSopenharmony_ci            }
446cabdff1aSopenharmony_ci            break;
447cabdff1aSopenharmony_ci
448cabdff1aSopenharmony_ci        case FLI_MINI:
449cabdff1aSopenharmony_ci            /* some sort of a thumbnail? disregard this chunk... */
450cabdff1aSopenharmony_ci            break;
451cabdff1aSopenharmony_ci
452cabdff1aSopenharmony_ci        default:
453cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type);
454cabdff1aSopenharmony_ci            break;
455cabdff1aSopenharmony_ci        }
456cabdff1aSopenharmony_ci
457cabdff1aSopenharmony_ci        if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) {
458cabdff1aSopenharmony_ci            bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2));
459cabdff1aSopenharmony_ci        } else {
460cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Chunk overread\n");
461cabdff1aSopenharmony_ci            break;
462cabdff1aSopenharmony_ci        }
463cabdff1aSopenharmony_ci
464cabdff1aSopenharmony_ci        frame_size -= chunk_size;
465cabdff1aSopenharmony_ci        num_chunks--;
466cabdff1aSopenharmony_ci    }
467cabdff1aSopenharmony_ci
468cabdff1aSopenharmony_ci    /* by the end of the chunk, the stream ptr should equal the frame
469cabdff1aSopenharmony_ci     * size (minus 1 or 2, possibly); if it doesn't, issue a warning */
470cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(&g2) > 2)
471cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \
472cabdff1aSopenharmony_ci               "and final chunk ptr = %d\n", buf_size,
473cabdff1aSopenharmony_ci               buf_size - bytestream2_get_bytes_left(&g2));
474cabdff1aSopenharmony_ci
475cabdff1aSopenharmony_ci    /* make the palette available on the way out */
476cabdff1aSopenharmony_ci    memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE);
477cabdff1aSopenharmony_ci    if (s->new_palette) {
478cabdff1aSopenharmony_ci        s->frame->palette_has_changed = 1;
479cabdff1aSopenharmony_ci        s->new_palette = 0;
480cabdff1aSopenharmony_ci    }
481cabdff1aSopenharmony_ci
482cabdff1aSopenharmony_ci    if ((ret = av_frame_ref(rframe, s->frame)) < 0)
483cabdff1aSopenharmony_ci        return ret;
484cabdff1aSopenharmony_ci
485cabdff1aSopenharmony_ci    *got_frame = 1;
486cabdff1aSopenharmony_ci
487cabdff1aSopenharmony_ci    return buf_size;
488cabdff1aSopenharmony_ci}
489cabdff1aSopenharmony_ci
490cabdff1aSopenharmony_cistatic int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
491cabdff1aSopenharmony_ci                                      AVFrame *rframe, int *got_frame,
492cabdff1aSopenharmony_ci                                      const uint8_t *buf, int buf_size)
493cabdff1aSopenharmony_ci{
494cabdff1aSopenharmony_ci    /* Note, the only difference between the 15Bpp and 16Bpp */
495cabdff1aSopenharmony_ci    /* Format is the pixel format, the packets are processed the same. */
496cabdff1aSopenharmony_ci    FlicDecodeContext *s = avctx->priv_data;
497cabdff1aSopenharmony_ci
498cabdff1aSopenharmony_ci    GetByteContext g2;
499cabdff1aSopenharmony_ci    int pixel_ptr;
500cabdff1aSopenharmony_ci    unsigned char palette_idx1;
501cabdff1aSopenharmony_ci
502cabdff1aSopenharmony_ci    unsigned int frame_size;
503cabdff1aSopenharmony_ci    int num_chunks;
504cabdff1aSopenharmony_ci
505cabdff1aSopenharmony_ci    unsigned int chunk_size;
506cabdff1aSopenharmony_ci    int chunk_type;
507cabdff1aSopenharmony_ci
508cabdff1aSopenharmony_ci    int i, j, ret;
509cabdff1aSopenharmony_ci
510cabdff1aSopenharmony_ci    int lines;
511cabdff1aSopenharmony_ci    int compressed_lines;
512cabdff1aSopenharmony_ci    int line_packets;
513cabdff1aSopenharmony_ci    int y_ptr;
514cabdff1aSopenharmony_ci    int byte_run;
515cabdff1aSopenharmony_ci    int pixel_skip;
516cabdff1aSopenharmony_ci    int pixel_countdown;
517cabdff1aSopenharmony_ci    unsigned char *pixels;
518cabdff1aSopenharmony_ci    int pixel;
519cabdff1aSopenharmony_ci    unsigned int pixel_limit;
520cabdff1aSopenharmony_ci
521cabdff1aSopenharmony_ci    bytestream2_init(&g2, buf, buf_size);
522cabdff1aSopenharmony_ci
523cabdff1aSopenharmony_ci    if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
524cabdff1aSopenharmony_ci        return ret;
525cabdff1aSopenharmony_ci
526cabdff1aSopenharmony_ci    pixels = s->frame->data[0];
527cabdff1aSopenharmony_ci    pixel_limit = s->avctx->height * s->frame->linesize[0];
528cabdff1aSopenharmony_ci
529cabdff1aSopenharmony_ci    frame_size = bytestream2_get_le32(&g2);
530cabdff1aSopenharmony_ci    bytestream2_skip(&g2, 2);  /* skip the magic number */
531cabdff1aSopenharmony_ci    num_chunks = bytestream2_get_le16(&g2);
532cabdff1aSopenharmony_ci    bytestream2_skip(&g2, 8);  /* skip padding */
533cabdff1aSopenharmony_ci    if (frame_size > buf_size)
534cabdff1aSopenharmony_ci        frame_size = buf_size;
535cabdff1aSopenharmony_ci
536cabdff1aSopenharmony_ci    if (frame_size < 16)
537cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
538cabdff1aSopenharmony_ci    frame_size -= 16;
539cabdff1aSopenharmony_ci
540cabdff1aSopenharmony_ci    /* iterate through the chunks */
541cabdff1aSopenharmony_ci    while ((frame_size > 0) && (num_chunks > 0) &&
542cabdff1aSopenharmony_ci            bytestream2_get_bytes_left(&g2) >= 4) {
543cabdff1aSopenharmony_ci        int stream_ptr_after_chunk;
544cabdff1aSopenharmony_ci        chunk_size = bytestream2_get_le32(&g2);
545cabdff1aSopenharmony_ci        if (chunk_size > frame_size) {
546cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_WARNING,
547cabdff1aSopenharmony_ci                   "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size);
548cabdff1aSopenharmony_ci            chunk_size = frame_size;
549cabdff1aSopenharmony_ci        }
550cabdff1aSopenharmony_ci        stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size;
551cabdff1aSopenharmony_ci
552cabdff1aSopenharmony_ci        chunk_type = bytestream2_get_le16(&g2);
553cabdff1aSopenharmony_ci
554cabdff1aSopenharmony_ci
555cabdff1aSopenharmony_ci        switch (chunk_type) {
556cabdff1aSopenharmony_ci        case FLI_256_COLOR:
557cabdff1aSopenharmony_ci        case FLI_COLOR:
558cabdff1aSopenharmony_ci            /* For some reason, it seems that non-palettized flics do
559cabdff1aSopenharmony_ci             * include one of these chunks in their first frame.
560cabdff1aSopenharmony_ci             * Why I do not know, it seems rather extraneous. */
561cabdff1aSopenharmony_ci            ff_dlog(avctx,
562cabdff1aSopenharmony_ci                    "Unexpected Palette chunk %d in non-palettized FLC\n",
563cabdff1aSopenharmony_ci                    chunk_type);
564cabdff1aSopenharmony_ci            bytestream2_skip(&g2, chunk_size - 6);
565cabdff1aSopenharmony_ci            break;
566cabdff1aSopenharmony_ci
567cabdff1aSopenharmony_ci        case FLI_DELTA:
568cabdff1aSopenharmony_ci        case FLI_DTA_LC:
569cabdff1aSopenharmony_ci            y_ptr = 0;
570cabdff1aSopenharmony_ci            compressed_lines = bytestream2_get_le16(&g2);
571cabdff1aSopenharmony_ci            while (compressed_lines > 0) {
572cabdff1aSopenharmony_ci                if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk)
573cabdff1aSopenharmony_ci                    break;
574cabdff1aSopenharmony_ci                if (y_ptr > pixel_limit)
575cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
576cabdff1aSopenharmony_ci                line_packets = sign_extend(bytestream2_get_le16(&g2), 16);
577cabdff1aSopenharmony_ci                if (line_packets < 0) {
578cabdff1aSopenharmony_ci                    line_packets = -line_packets;
579cabdff1aSopenharmony_ci                    if (line_packets > s->avctx->height)
580cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
581cabdff1aSopenharmony_ci                    y_ptr += line_packets * s->frame->linesize[0];
582cabdff1aSopenharmony_ci                } else {
583cabdff1aSopenharmony_ci                    compressed_lines--;
584cabdff1aSopenharmony_ci                    pixel_ptr = y_ptr;
585cabdff1aSopenharmony_ci                    CHECK_PIXEL_PTR(0);
586cabdff1aSopenharmony_ci                    pixel_countdown = s->avctx->width;
587cabdff1aSopenharmony_ci                    for (i = 0; i < line_packets; i++) {
588cabdff1aSopenharmony_ci                        /* account for the skip bytes */
589cabdff1aSopenharmony_ci                        if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk)
590cabdff1aSopenharmony_ci                            break;
591cabdff1aSopenharmony_ci                        pixel_skip = bytestream2_get_byte(&g2);
592cabdff1aSopenharmony_ci                        pixel_ptr += (pixel_skip*2); /* Pixel is 2 bytes wide */
593cabdff1aSopenharmony_ci                        pixel_countdown -= pixel_skip;
594cabdff1aSopenharmony_ci                        byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
595cabdff1aSopenharmony_ci                        if (byte_run < 0) {
596cabdff1aSopenharmony_ci                            byte_run = -byte_run;
597cabdff1aSopenharmony_ci                            pixel    = bytestream2_get_le16(&g2);
598cabdff1aSopenharmony_ci                            CHECK_PIXEL_PTR(2 * byte_run);
599cabdff1aSopenharmony_ci                            for (j = 0; j < byte_run; j++, pixel_countdown -= 2) {
600cabdff1aSopenharmony_ci                                *((signed short*)(&pixels[pixel_ptr])) = pixel;
601cabdff1aSopenharmony_ci                                pixel_ptr += 2;
602cabdff1aSopenharmony_ci                            }
603cabdff1aSopenharmony_ci                        } else {
604cabdff1aSopenharmony_ci                            if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk)
605cabdff1aSopenharmony_ci                                break;
606cabdff1aSopenharmony_ci                            CHECK_PIXEL_PTR(2 * byte_run);
607cabdff1aSopenharmony_ci                            for (j = 0; j < byte_run; j++, pixel_countdown--) {
608cabdff1aSopenharmony_ci                                *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2);
609cabdff1aSopenharmony_ci                                pixel_ptr += 2;
610cabdff1aSopenharmony_ci                            }
611cabdff1aSopenharmony_ci                        }
612cabdff1aSopenharmony_ci                    }
613cabdff1aSopenharmony_ci
614cabdff1aSopenharmony_ci                    y_ptr += s->frame->linesize[0];
615cabdff1aSopenharmony_ci                }
616cabdff1aSopenharmony_ci            }
617cabdff1aSopenharmony_ci            break;
618cabdff1aSopenharmony_ci
619cabdff1aSopenharmony_ci        case FLI_LC:
620cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n");
621cabdff1aSopenharmony_ci            bytestream2_skip(&g2, chunk_size - 6);
622cabdff1aSopenharmony_ci            break;
623cabdff1aSopenharmony_ci
624cabdff1aSopenharmony_ci        case FLI_BLACK:
625cabdff1aSopenharmony_ci            /* set the whole frame to 0x0000 which is black in both 15Bpp and 16Bpp modes. */
626cabdff1aSopenharmony_ci            memset(pixels, 0x0000,
627cabdff1aSopenharmony_ci                   s->frame->linesize[0] * s->avctx->height);
628cabdff1aSopenharmony_ci            break;
629cabdff1aSopenharmony_ci
630cabdff1aSopenharmony_ci        case FLI_BRUN:
631cabdff1aSopenharmony_ci            y_ptr = 0;
632cabdff1aSopenharmony_ci            for (lines = 0; lines < s->avctx->height; lines++) {
633cabdff1aSopenharmony_ci                pixel_ptr = y_ptr;
634cabdff1aSopenharmony_ci                /* disregard the line packets; instead, iterate through all
635cabdff1aSopenharmony_ci                 * pixels on a row */
636cabdff1aSopenharmony_ci                bytestream2_skip(&g2, 1);
637cabdff1aSopenharmony_ci                pixel_countdown = (s->avctx->width * 2);
638cabdff1aSopenharmony_ci
639cabdff1aSopenharmony_ci                while (pixel_countdown > 0) {
640cabdff1aSopenharmony_ci                    if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
641cabdff1aSopenharmony_ci                        break;
642cabdff1aSopenharmony_ci                    byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
643cabdff1aSopenharmony_ci                    if (byte_run > 0) {
644cabdff1aSopenharmony_ci                        palette_idx1 = bytestream2_get_byte(&g2);
645cabdff1aSopenharmony_ci                        CHECK_PIXEL_PTR(byte_run);
646cabdff1aSopenharmony_ci                        for (j = 0; j < byte_run; j++) {
647cabdff1aSopenharmony_ci                            pixels[pixel_ptr++] = palette_idx1;
648cabdff1aSopenharmony_ci                            pixel_countdown--;
649cabdff1aSopenharmony_ci                            if (pixel_countdown < 0)
650cabdff1aSopenharmony_ci                                av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n",
651cabdff1aSopenharmony_ci                                       pixel_countdown, lines);
652cabdff1aSopenharmony_ci                        }
653cabdff1aSopenharmony_ci                    } else {  /* copy bytes if byte_run < 0 */
654cabdff1aSopenharmony_ci                        byte_run = -byte_run;
655cabdff1aSopenharmony_ci                        if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk)
656cabdff1aSopenharmony_ci                            break;
657cabdff1aSopenharmony_ci                        CHECK_PIXEL_PTR(byte_run);
658cabdff1aSopenharmony_ci                        for (j = 0; j < byte_run; j++) {
659cabdff1aSopenharmony_ci                            palette_idx1 = bytestream2_get_byte(&g2);
660cabdff1aSopenharmony_ci                            pixels[pixel_ptr++] = palette_idx1;
661cabdff1aSopenharmony_ci                            pixel_countdown--;
662cabdff1aSopenharmony_ci                            if (pixel_countdown < 0)
663cabdff1aSopenharmony_ci                                av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
664cabdff1aSopenharmony_ci                                       pixel_countdown, lines);
665cabdff1aSopenharmony_ci                        }
666cabdff1aSopenharmony_ci                    }
667cabdff1aSopenharmony_ci                }
668cabdff1aSopenharmony_ci
669cabdff1aSopenharmony_ci                /* Now FLX is strange, in that it is "byte" as opposed to "pixel" run length compressed.
670cabdff1aSopenharmony_ci                 * This does not give us any good opportunity to perform word endian conversion
671cabdff1aSopenharmony_ci                 * during decompression. So if it is required (i.e., this is not a LE target, we do
672cabdff1aSopenharmony_ci                 * a second pass over the line here, swapping the bytes.
673cabdff1aSopenharmony_ci                 */
674cabdff1aSopenharmony_ci#if HAVE_BIGENDIAN
675cabdff1aSopenharmony_ci                pixel_ptr = y_ptr;
676cabdff1aSopenharmony_ci                pixel_countdown = s->avctx->width;
677cabdff1aSopenharmony_ci                while (pixel_countdown > 0) {
678cabdff1aSopenharmony_ci                    *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[pixel_ptr]);
679cabdff1aSopenharmony_ci                    pixel_ptr += 2;
680cabdff1aSopenharmony_ci                }
681cabdff1aSopenharmony_ci#endif
682cabdff1aSopenharmony_ci                y_ptr += s->frame->linesize[0];
683cabdff1aSopenharmony_ci            }
684cabdff1aSopenharmony_ci            break;
685cabdff1aSopenharmony_ci
686cabdff1aSopenharmony_ci        case FLI_DTA_BRUN:
687cabdff1aSopenharmony_ci            y_ptr = 0;
688cabdff1aSopenharmony_ci            for (lines = 0; lines < s->avctx->height; lines++) {
689cabdff1aSopenharmony_ci                pixel_ptr = y_ptr;
690cabdff1aSopenharmony_ci                /* disregard the line packets; instead, iterate through all
691cabdff1aSopenharmony_ci                 * pixels on a row */
692cabdff1aSopenharmony_ci                bytestream2_skip(&g2, 1);
693cabdff1aSopenharmony_ci                pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */
694cabdff1aSopenharmony_ci
695cabdff1aSopenharmony_ci                while (pixel_countdown > 0) {
696cabdff1aSopenharmony_ci                    if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
697cabdff1aSopenharmony_ci                        break;
698cabdff1aSopenharmony_ci                    byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
699cabdff1aSopenharmony_ci                    if (byte_run > 0) {
700cabdff1aSopenharmony_ci                        pixel    = bytestream2_get_le16(&g2);
701cabdff1aSopenharmony_ci                        CHECK_PIXEL_PTR(2 * byte_run);
702cabdff1aSopenharmony_ci                        for (j = 0; j < byte_run; j++) {
703cabdff1aSopenharmony_ci                            *((signed short*)(&pixels[pixel_ptr])) = pixel;
704cabdff1aSopenharmony_ci                            pixel_ptr += 2;
705cabdff1aSopenharmony_ci                            pixel_countdown--;
706cabdff1aSopenharmony_ci                            if (pixel_countdown < 0)
707cabdff1aSopenharmony_ci                                av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n",
708cabdff1aSopenharmony_ci                                       pixel_countdown);
709cabdff1aSopenharmony_ci                        }
710cabdff1aSopenharmony_ci                    } else {  /* copy pixels if byte_run < 0 */
711cabdff1aSopenharmony_ci                        byte_run = -byte_run;
712cabdff1aSopenharmony_ci                        if (bytestream2_tell(&g2) + 2 * byte_run > stream_ptr_after_chunk)
713cabdff1aSopenharmony_ci                            break;
714cabdff1aSopenharmony_ci                        CHECK_PIXEL_PTR(2 * byte_run);
715cabdff1aSopenharmony_ci                        for (j = 0; j < byte_run; j++) {
716cabdff1aSopenharmony_ci                            *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2);
717cabdff1aSopenharmony_ci                            pixel_ptr  += 2;
718cabdff1aSopenharmony_ci                            pixel_countdown--;
719cabdff1aSopenharmony_ci                            if (pixel_countdown < 0)
720cabdff1aSopenharmony_ci                                av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n",
721cabdff1aSopenharmony_ci                                       pixel_countdown);
722cabdff1aSopenharmony_ci                        }
723cabdff1aSopenharmony_ci                    }
724cabdff1aSopenharmony_ci                }
725cabdff1aSopenharmony_ci
726cabdff1aSopenharmony_ci                y_ptr += s->frame->linesize[0];
727cabdff1aSopenharmony_ci            }
728cabdff1aSopenharmony_ci            break;
729cabdff1aSopenharmony_ci
730cabdff1aSopenharmony_ci        case FLI_COPY:
731cabdff1aSopenharmony_ci        case FLI_DTA_COPY:
732cabdff1aSopenharmony_ci            /* copy the chunk (uncompressed frame) */
733cabdff1aSopenharmony_ci            if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*2) {
734cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \
735cabdff1aSopenharmony_ci                       "bigger than image, skipping chunk\n", chunk_size - 6);
736cabdff1aSopenharmony_ci                bytestream2_skip(&g2, chunk_size - 6);
737cabdff1aSopenharmony_ci            } else {
738cabdff1aSopenharmony_ci
739cabdff1aSopenharmony_ci                if (bytestream2_get_bytes_left(&g2) < 2 * s->avctx->width * s->avctx->height )
740cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
741cabdff1aSopenharmony_ci                for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height;
742cabdff1aSopenharmony_ci                     y_ptr += s->frame->linesize[0]) {
743cabdff1aSopenharmony_ci
744cabdff1aSopenharmony_ci                    pixel_countdown = s->avctx->width;
745cabdff1aSopenharmony_ci                    pixel_ptr = 0;
746cabdff1aSopenharmony_ci                    while (pixel_countdown > 0) {
747cabdff1aSopenharmony_ci                      *((signed short*)(&pixels[y_ptr + pixel_ptr])) = bytestream2_get_le16(&g2);
748cabdff1aSopenharmony_ci                      pixel_ptr += 2;
749cabdff1aSopenharmony_ci                      pixel_countdown--;
750cabdff1aSopenharmony_ci                    }
751cabdff1aSopenharmony_ci                    if (s->avctx->width & 1)
752cabdff1aSopenharmony_ci                        bytestream2_skip(&g2, 2);
753cabdff1aSopenharmony_ci                }
754cabdff1aSopenharmony_ci            }
755cabdff1aSopenharmony_ci            break;
756cabdff1aSopenharmony_ci
757cabdff1aSopenharmony_ci        case FLI_MINI:
758cabdff1aSopenharmony_ci            /* some sort of a thumbnail? disregard this chunk... */
759cabdff1aSopenharmony_ci            bytestream2_skip(&g2, chunk_size - 6);
760cabdff1aSopenharmony_ci            break;
761cabdff1aSopenharmony_ci
762cabdff1aSopenharmony_ci        default:
763cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type);
764cabdff1aSopenharmony_ci            break;
765cabdff1aSopenharmony_ci        }
766cabdff1aSopenharmony_ci
767cabdff1aSopenharmony_ci        if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) {
768cabdff1aSopenharmony_ci            bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2));
769cabdff1aSopenharmony_ci        } else {
770cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Chunk overread\n");
771cabdff1aSopenharmony_ci            break;
772cabdff1aSopenharmony_ci        }
773cabdff1aSopenharmony_ci
774cabdff1aSopenharmony_ci        frame_size -= chunk_size;
775cabdff1aSopenharmony_ci        num_chunks--;
776cabdff1aSopenharmony_ci    }
777cabdff1aSopenharmony_ci
778cabdff1aSopenharmony_ci    /* by the end of the chunk, the stream ptr should equal the frame
779cabdff1aSopenharmony_ci     * size (minus 1, possibly); if it doesn't, issue a warning */
780cabdff1aSopenharmony_ci    if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1))
781cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \
782cabdff1aSopenharmony_ci               "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2));
783cabdff1aSopenharmony_ci
784cabdff1aSopenharmony_ci    if ((ret = av_frame_ref(rframe, s->frame)) < 0)
785cabdff1aSopenharmony_ci        return ret;
786cabdff1aSopenharmony_ci
787cabdff1aSopenharmony_ci    *got_frame = 1;
788cabdff1aSopenharmony_ci
789cabdff1aSopenharmony_ci    return buf_size;
790cabdff1aSopenharmony_ci}
791cabdff1aSopenharmony_ci
792cabdff1aSopenharmony_cistatic int flic_decode_frame_24BPP(AVCodecContext *avctx,
793cabdff1aSopenharmony_ci                                   AVFrame *rframe, int *got_frame,
794cabdff1aSopenharmony_ci                                   const uint8_t *buf, int buf_size)
795cabdff1aSopenharmony_ci{
796cabdff1aSopenharmony_ci    FlicDecodeContext *s = avctx->priv_data;
797cabdff1aSopenharmony_ci
798cabdff1aSopenharmony_ci    GetByteContext g2;
799cabdff1aSopenharmony_ci    int pixel_ptr;
800cabdff1aSopenharmony_ci    unsigned char palette_idx1;
801cabdff1aSopenharmony_ci
802cabdff1aSopenharmony_ci    unsigned int frame_size;
803cabdff1aSopenharmony_ci    int num_chunks;
804cabdff1aSopenharmony_ci
805cabdff1aSopenharmony_ci    unsigned int chunk_size;
806cabdff1aSopenharmony_ci    int chunk_type;
807cabdff1aSopenharmony_ci
808cabdff1aSopenharmony_ci    int i, j, ret;
809cabdff1aSopenharmony_ci
810cabdff1aSopenharmony_ci    int lines;
811cabdff1aSopenharmony_ci    int compressed_lines;
812cabdff1aSopenharmony_ci    int line_packets;
813cabdff1aSopenharmony_ci    int y_ptr;
814cabdff1aSopenharmony_ci    int byte_run;
815cabdff1aSopenharmony_ci    int pixel_skip;
816cabdff1aSopenharmony_ci    int pixel_countdown;
817cabdff1aSopenharmony_ci    unsigned char *pixels;
818cabdff1aSopenharmony_ci    int pixel;
819cabdff1aSopenharmony_ci    unsigned int pixel_limit;
820cabdff1aSopenharmony_ci
821cabdff1aSopenharmony_ci    bytestream2_init(&g2, buf, buf_size);
822cabdff1aSopenharmony_ci
823cabdff1aSopenharmony_ci    if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
824cabdff1aSopenharmony_ci        return ret;
825cabdff1aSopenharmony_ci
826cabdff1aSopenharmony_ci    pixels = s->frame->data[0];
827cabdff1aSopenharmony_ci    pixel_limit = s->avctx->height * s->frame->linesize[0];
828cabdff1aSopenharmony_ci
829cabdff1aSopenharmony_ci    frame_size = bytestream2_get_le32(&g2);
830cabdff1aSopenharmony_ci    bytestream2_skip(&g2, 2);  /* skip the magic number */
831cabdff1aSopenharmony_ci    num_chunks = bytestream2_get_le16(&g2);
832cabdff1aSopenharmony_ci    bytestream2_skip(&g2, 8);  /* skip padding */
833cabdff1aSopenharmony_ci    if (frame_size > buf_size)
834cabdff1aSopenharmony_ci        frame_size = buf_size;
835cabdff1aSopenharmony_ci
836cabdff1aSopenharmony_ci    if (frame_size < 16)
837cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
838cabdff1aSopenharmony_ci    frame_size -= 16;
839cabdff1aSopenharmony_ci
840cabdff1aSopenharmony_ci    /* iterate through the chunks */
841cabdff1aSopenharmony_ci    while ((frame_size > 0) && (num_chunks > 0) &&
842cabdff1aSopenharmony_ci            bytestream2_get_bytes_left(&g2) >= 4) {
843cabdff1aSopenharmony_ci        int stream_ptr_after_chunk;
844cabdff1aSopenharmony_ci        chunk_size = bytestream2_get_le32(&g2);
845cabdff1aSopenharmony_ci        if (chunk_size > frame_size) {
846cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_WARNING,
847cabdff1aSopenharmony_ci                   "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size);
848cabdff1aSopenharmony_ci            chunk_size = frame_size;
849cabdff1aSopenharmony_ci        }
850cabdff1aSopenharmony_ci        stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size;
851cabdff1aSopenharmony_ci
852cabdff1aSopenharmony_ci        chunk_type = bytestream2_get_le16(&g2);
853cabdff1aSopenharmony_ci
854cabdff1aSopenharmony_ci
855cabdff1aSopenharmony_ci        switch (chunk_type) {
856cabdff1aSopenharmony_ci        case FLI_256_COLOR:
857cabdff1aSopenharmony_ci        case FLI_COLOR:
858cabdff1aSopenharmony_ci            /* For some reason, it seems that non-palettized flics do
859cabdff1aSopenharmony_ci             * include one of these chunks in their first frame.
860cabdff1aSopenharmony_ci             * Why I do not know, it seems rather extraneous. */
861cabdff1aSopenharmony_ci            ff_dlog(avctx,
862cabdff1aSopenharmony_ci                    "Unexpected Palette chunk %d in non-palettized FLC\n",
863cabdff1aSopenharmony_ci                    chunk_type);
864cabdff1aSopenharmony_ci            bytestream2_skip(&g2, chunk_size - 6);
865cabdff1aSopenharmony_ci            break;
866cabdff1aSopenharmony_ci
867cabdff1aSopenharmony_ci        case FLI_DELTA:
868cabdff1aSopenharmony_ci        case FLI_DTA_LC:
869cabdff1aSopenharmony_ci            y_ptr = 0;
870cabdff1aSopenharmony_ci            compressed_lines = bytestream2_get_le16(&g2);
871cabdff1aSopenharmony_ci            while (compressed_lines > 0) {
872cabdff1aSopenharmony_ci                if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk)
873cabdff1aSopenharmony_ci                    break;
874cabdff1aSopenharmony_ci                if (y_ptr > pixel_limit)
875cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
876cabdff1aSopenharmony_ci                line_packets = sign_extend(bytestream2_get_le16(&g2), 16);
877cabdff1aSopenharmony_ci                if (line_packets < 0) {
878cabdff1aSopenharmony_ci                    line_packets = -line_packets;
879cabdff1aSopenharmony_ci                    if (line_packets > s->avctx->height)
880cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
881cabdff1aSopenharmony_ci                    y_ptr += line_packets * s->frame->linesize[0];
882cabdff1aSopenharmony_ci                } else {
883cabdff1aSopenharmony_ci                    compressed_lines--;
884cabdff1aSopenharmony_ci                    pixel_ptr = y_ptr;
885cabdff1aSopenharmony_ci                    CHECK_PIXEL_PTR(0);
886cabdff1aSopenharmony_ci                    pixel_countdown = s->avctx->width;
887cabdff1aSopenharmony_ci                    for (i = 0; i < line_packets; i++) {
888cabdff1aSopenharmony_ci                        /* account for the skip bytes */
889cabdff1aSopenharmony_ci                        if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk)
890cabdff1aSopenharmony_ci                            break;
891cabdff1aSopenharmony_ci                        pixel_skip = bytestream2_get_byte(&g2);
892cabdff1aSopenharmony_ci                        pixel_ptr += (pixel_skip*3); /* Pixel is 3 bytes wide */
893cabdff1aSopenharmony_ci                        pixel_countdown -= pixel_skip;
894cabdff1aSopenharmony_ci                        byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
895cabdff1aSopenharmony_ci                        if (byte_run < 0) {
896cabdff1aSopenharmony_ci                            byte_run = -byte_run;
897cabdff1aSopenharmony_ci                            pixel    = bytestream2_get_le24(&g2);
898cabdff1aSopenharmony_ci                            CHECK_PIXEL_PTR(3 * byte_run);
899cabdff1aSopenharmony_ci                            for (j = 0; j < byte_run; j++, pixel_countdown -= 1) {
900cabdff1aSopenharmony_ci                                AV_WL24(&pixels[pixel_ptr], pixel);
901cabdff1aSopenharmony_ci                                pixel_ptr += 3;
902cabdff1aSopenharmony_ci                            }
903cabdff1aSopenharmony_ci                        } else {
904cabdff1aSopenharmony_ci                            if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk)
905cabdff1aSopenharmony_ci                                break;
906cabdff1aSopenharmony_ci                            CHECK_PIXEL_PTR(3 * byte_run);
907cabdff1aSopenharmony_ci                            for (j = 0; j < byte_run; j++, pixel_countdown--) {
908cabdff1aSopenharmony_ci                                pixel = bytestream2_get_le24(&g2);
909cabdff1aSopenharmony_ci                                AV_WL24(&pixels[pixel_ptr], pixel);
910cabdff1aSopenharmony_ci                                pixel_ptr += 3;
911cabdff1aSopenharmony_ci                            }
912cabdff1aSopenharmony_ci                        }
913cabdff1aSopenharmony_ci                    }
914cabdff1aSopenharmony_ci
915cabdff1aSopenharmony_ci                    y_ptr += s->frame->linesize[0];
916cabdff1aSopenharmony_ci                }
917cabdff1aSopenharmony_ci            }
918cabdff1aSopenharmony_ci            break;
919cabdff1aSopenharmony_ci
920cabdff1aSopenharmony_ci        case FLI_LC:
921cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n");
922cabdff1aSopenharmony_ci            bytestream2_skip(&g2, chunk_size - 6);
923cabdff1aSopenharmony_ci            break;
924cabdff1aSopenharmony_ci
925cabdff1aSopenharmony_ci        case FLI_BLACK:
926cabdff1aSopenharmony_ci            /* set the whole frame to 0x00 which is black for 24 bit mode. */
927cabdff1aSopenharmony_ci            memset(pixels, 0x00,
928cabdff1aSopenharmony_ci                   s->frame->linesize[0] * s->avctx->height);
929cabdff1aSopenharmony_ci            break;
930cabdff1aSopenharmony_ci
931cabdff1aSopenharmony_ci        case FLI_BRUN:
932cabdff1aSopenharmony_ci            y_ptr = 0;
933cabdff1aSopenharmony_ci            for (lines = 0; lines < s->avctx->height; lines++) {
934cabdff1aSopenharmony_ci                pixel_ptr = y_ptr;
935cabdff1aSopenharmony_ci                /* disregard the line packets; instead, iterate through all
936cabdff1aSopenharmony_ci                 * pixels on a row */
937cabdff1aSopenharmony_ci                bytestream2_skip(&g2, 1);
938cabdff1aSopenharmony_ci                pixel_countdown = (s->avctx->width * 3);
939cabdff1aSopenharmony_ci
940cabdff1aSopenharmony_ci                while (pixel_countdown > 0) {
941cabdff1aSopenharmony_ci                    if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
942cabdff1aSopenharmony_ci                        break;
943cabdff1aSopenharmony_ci                    byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
944cabdff1aSopenharmony_ci                    if (byte_run > 0) {
945cabdff1aSopenharmony_ci                        palette_idx1 = bytestream2_get_byte(&g2);
946cabdff1aSopenharmony_ci                        CHECK_PIXEL_PTR(byte_run);
947cabdff1aSopenharmony_ci                        for (j = 0; j < byte_run; j++) {
948cabdff1aSopenharmony_ci                            pixels[pixel_ptr++] = palette_idx1;
949cabdff1aSopenharmony_ci                            pixel_countdown--;
950cabdff1aSopenharmony_ci                            if (pixel_countdown < 0)
951cabdff1aSopenharmony_ci                                av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n",
952cabdff1aSopenharmony_ci                                       pixel_countdown, lines);
953cabdff1aSopenharmony_ci                        }
954cabdff1aSopenharmony_ci                    } else {  /* copy bytes if byte_run < 0 */
955cabdff1aSopenharmony_ci                        byte_run = -byte_run;
956cabdff1aSopenharmony_ci                        if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk)
957cabdff1aSopenharmony_ci                            break;
958cabdff1aSopenharmony_ci                        CHECK_PIXEL_PTR(byte_run);
959cabdff1aSopenharmony_ci                        for (j = 0; j < byte_run; j++) {
960cabdff1aSopenharmony_ci                            palette_idx1 = bytestream2_get_byte(&g2);
961cabdff1aSopenharmony_ci                            pixels[pixel_ptr++] = palette_idx1;
962cabdff1aSopenharmony_ci                            pixel_countdown--;
963cabdff1aSopenharmony_ci                            if (pixel_countdown < 0)
964cabdff1aSopenharmony_ci                                av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
965cabdff1aSopenharmony_ci                                       pixel_countdown, lines);
966cabdff1aSopenharmony_ci                        }
967cabdff1aSopenharmony_ci                    }
968cabdff1aSopenharmony_ci                }
969cabdff1aSopenharmony_ci
970cabdff1aSopenharmony_ci                y_ptr += s->frame->linesize[0];
971cabdff1aSopenharmony_ci            }
972cabdff1aSopenharmony_ci            break;
973cabdff1aSopenharmony_ci
974cabdff1aSopenharmony_ci        case FLI_DTA_BRUN:
975cabdff1aSopenharmony_ci            y_ptr = 0;
976cabdff1aSopenharmony_ci            for (lines = 0; lines < s->avctx->height; lines++) {
977cabdff1aSopenharmony_ci                pixel_ptr = y_ptr;
978cabdff1aSopenharmony_ci                /* disregard the line packets; instead, iterate through all
979cabdff1aSopenharmony_ci                 * pixels on a row */
980cabdff1aSopenharmony_ci                bytestream2_skip(&g2, 1);
981cabdff1aSopenharmony_ci                pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */
982cabdff1aSopenharmony_ci
983cabdff1aSopenharmony_ci                while (pixel_countdown > 0) {
984cabdff1aSopenharmony_ci                    if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
985cabdff1aSopenharmony_ci                        break;
986cabdff1aSopenharmony_ci                    byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
987cabdff1aSopenharmony_ci                    if (byte_run > 0) {
988cabdff1aSopenharmony_ci                        pixel = bytestream2_get_le24(&g2);
989cabdff1aSopenharmony_ci                        CHECK_PIXEL_PTR(3 * byte_run);
990cabdff1aSopenharmony_ci                        for (j = 0; j < byte_run; j++) {
991cabdff1aSopenharmony_ci                            AV_WL24(pixels + pixel_ptr, pixel);
992cabdff1aSopenharmony_ci                            pixel_ptr += 3;
993cabdff1aSopenharmony_ci                            pixel_countdown--;
994cabdff1aSopenharmony_ci                            if (pixel_countdown < 0)
995cabdff1aSopenharmony_ci                                av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n",
996cabdff1aSopenharmony_ci                                       pixel_countdown);
997cabdff1aSopenharmony_ci                        }
998cabdff1aSopenharmony_ci                    } else {  /* copy pixels if byte_run < 0 */
999cabdff1aSopenharmony_ci                        byte_run = -byte_run;
1000cabdff1aSopenharmony_ci                        if (bytestream2_tell(&g2) + 3 * byte_run > stream_ptr_after_chunk)
1001cabdff1aSopenharmony_ci                            break;
1002cabdff1aSopenharmony_ci                        CHECK_PIXEL_PTR(3 * byte_run);
1003cabdff1aSopenharmony_ci                        for (j = 0; j < byte_run; j++) {
1004cabdff1aSopenharmony_ci                            pixel = bytestream2_get_le24(&g2);
1005cabdff1aSopenharmony_ci                            AV_WL24(pixels + pixel_ptr, pixel);
1006cabdff1aSopenharmony_ci                            pixel_ptr  += 3;
1007cabdff1aSopenharmony_ci                            pixel_countdown--;
1008cabdff1aSopenharmony_ci                            if (pixel_countdown < 0)
1009cabdff1aSopenharmony_ci                                av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n",
1010cabdff1aSopenharmony_ci                                       pixel_countdown);
1011cabdff1aSopenharmony_ci                        }
1012cabdff1aSopenharmony_ci                    }
1013cabdff1aSopenharmony_ci                }
1014cabdff1aSopenharmony_ci
1015cabdff1aSopenharmony_ci                y_ptr += s->frame->linesize[0];
1016cabdff1aSopenharmony_ci            }
1017cabdff1aSopenharmony_ci            break;
1018cabdff1aSopenharmony_ci
1019cabdff1aSopenharmony_ci        case FLI_COPY:
1020cabdff1aSopenharmony_ci        case FLI_DTA_COPY:
1021cabdff1aSopenharmony_ci            /* copy the chunk (uncompressed frame) */
1022cabdff1aSopenharmony_ci            if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*3) {
1023cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \
1024cabdff1aSopenharmony_ci                       "bigger than image, skipping chunk\n", chunk_size - 6);
1025cabdff1aSopenharmony_ci                bytestream2_skip(&g2, chunk_size - 6);
1026cabdff1aSopenharmony_ci            } else {
1027cabdff1aSopenharmony_ci                for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height;
1028cabdff1aSopenharmony_ci                     y_ptr += s->frame->linesize[0]) {
1029cabdff1aSopenharmony_ci
1030cabdff1aSopenharmony_ci                    bytestream2_get_buffer(&g2, pixels + y_ptr, 3*s->avctx->width);
1031cabdff1aSopenharmony_ci                    if (s->avctx->width & 1)
1032cabdff1aSopenharmony_ci                        bytestream2_skip(&g2, 3);
1033cabdff1aSopenharmony_ci                }
1034cabdff1aSopenharmony_ci            }
1035cabdff1aSopenharmony_ci            break;
1036cabdff1aSopenharmony_ci
1037cabdff1aSopenharmony_ci        case FLI_MINI:
1038cabdff1aSopenharmony_ci            /* some sort of a thumbnail? disregard this chunk... */
1039cabdff1aSopenharmony_ci            bytestream2_skip(&g2, chunk_size - 6);
1040cabdff1aSopenharmony_ci            break;
1041cabdff1aSopenharmony_ci
1042cabdff1aSopenharmony_ci        default:
1043cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type);
1044cabdff1aSopenharmony_ci            break;
1045cabdff1aSopenharmony_ci        }
1046cabdff1aSopenharmony_ci
1047cabdff1aSopenharmony_ci        if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) {
1048cabdff1aSopenharmony_ci            bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2));
1049cabdff1aSopenharmony_ci        } else {
1050cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Chunk overread\n");
1051cabdff1aSopenharmony_ci            break;
1052cabdff1aSopenharmony_ci        }
1053cabdff1aSopenharmony_ci
1054cabdff1aSopenharmony_ci        frame_size -= chunk_size;
1055cabdff1aSopenharmony_ci        num_chunks--;
1056cabdff1aSopenharmony_ci    }
1057cabdff1aSopenharmony_ci
1058cabdff1aSopenharmony_ci    /* by the end of the chunk, the stream ptr should equal the frame
1059cabdff1aSopenharmony_ci     * size (minus 1, possibly); if it doesn't, issue a warning */
1060cabdff1aSopenharmony_ci    if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1))
1061cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \
1062cabdff1aSopenharmony_ci               "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2));
1063cabdff1aSopenharmony_ci
1064cabdff1aSopenharmony_ci    if ((ret = av_frame_ref(rframe, s->frame)) < 0)
1065cabdff1aSopenharmony_ci        return ret;
1066cabdff1aSopenharmony_ci
1067cabdff1aSopenharmony_ci    *got_frame = 1;
1068cabdff1aSopenharmony_ci
1069cabdff1aSopenharmony_ci    return buf_size;
1070cabdff1aSopenharmony_ci}
1071cabdff1aSopenharmony_ci
1072cabdff1aSopenharmony_cistatic int flic_decode_frame(AVCodecContext *avctx, AVFrame *frame,
1073cabdff1aSopenharmony_ci                             int *got_frame, AVPacket *avpkt)
1074cabdff1aSopenharmony_ci{
1075cabdff1aSopenharmony_ci    const uint8_t *buf = avpkt->data;
1076cabdff1aSopenharmony_ci    int buf_size = avpkt->size;
1077cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
1078cabdff1aSopenharmony_ci        return flic_decode_frame_8BPP(avctx, frame, got_frame,
1079cabdff1aSopenharmony_ci                                      buf, buf_size);
1080cabdff1aSopenharmony_ci    } else if ((avctx->pix_fmt == AV_PIX_FMT_RGB555) ||
1081cabdff1aSopenharmony_ci               (avctx->pix_fmt == AV_PIX_FMT_RGB565)) {
1082cabdff1aSopenharmony_ci        return flic_decode_frame_15_16BPP(avctx, frame, got_frame,
1083cabdff1aSopenharmony_ci                                          buf, buf_size);
1084cabdff1aSopenharmony_ci    } else if (avctx->pix_fmt == AV_PIX_FMT_BGR24) {
1085cabdff1aSopenharmony_ci        return flic_decode_frame_24BPP(avctx, frame, got_frame,
1086cabdff1aSopenharmony_ci                                       buf, buf_size);
1087cabdff1aSopenharmony_ci    }
1088cabdff1aSopenharmony_ci
1089cabdff1aSopenharmony_ci    /* Should not get  here, ever as the pix_fmt is processed */
1090cabdff1aSopenharmony_ci    /* in flic_decode_init and the above if should deal with */
1091cabdff1aSopenharmony_ci    /* the finite set of possibilities allowable by here. */
1092cabdff1aSopenharmony_ci    /* But in case we do, just error out. */
1093cabdff1aSopenharmony_ci    av_log(avctx, AV_LOG_ERROR, "Unknown FLC format, my science cannot explain how this happened.\n");
1094cabdff1aSopenharmony_ci    return AVERROR_BUG;
1095cabdff1aSopenharmony_ci}
1096cabdff1aSopenharmony_ci
1097cabdff1aSopenharmony_ci
1098cabdff1aSopenharmony_cistatic av_cold int flic_decode_end(AVCodecContext *avctx)
1099cabdff1aSopenharmony_ci{
1100cabdff1aSopenharmony_ci    FlicDecodeContext *s = avctx->priv_data;
1101cabdff1aSopenharmony_ci
1102cabdff1aSopenharmony_ci    av_frame_free(&s->frame);
1103cabdff1aSopenharmony_ci
1104cabdff1aSopenharmony_ci    return 0;
1105cabdff1aSopenharmony_ci}
1106cabdff1aSopenharmony_ci
1107cabdff1aSopenharmony_ciconst FFCodec ff_flic_decoder = {
1108cabdff1aSopenharmony_ci    .p.name         = "flic",
1109cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Autodesk Animator Flic video"),
1110cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
1111cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_FLIC,
1112cabdff1aSopenharmony_ci    .priv_data_size = sizeof(FlicDecodeContext),
1113cabdff1aSopenharmony_ci    .init           = flic_decode_init,
1114cabdff1aSopenharmony_ci    .close          = flic_decode_end,
1115cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(flic_decode_frame),
1116cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1,
1117cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
1118cabdff1aSopenharmony_ci};
1119