1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Interplay MVE Video Decoder
3cabdff1aSopenharmony_ci * Copyright (C) 2003 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 * Interplay MVE Video Decoder by Mike Melanson (melanson@pcisys.net)
25cabdff1aSopenharmony_ci * For more information about the Interplay MVE format, visit:
26cabdff1aSopenharmony_ci *   http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
27cabdff1aSopenharmony_ci * This code is written in such a way that the identifiers match up
28cabdff1aSopenharmony_ci * with the encoding descriptions in the document.
29cabdff1aSopenharmony_ci *
30cabdff1aSopenharmony_ci * This decoder presently only supports a PAL8 output colorspace.
31cabdff1aSopenharmony_ci *
32cabdff1aSopenharmony_ci * An Interplay video frame consists of 2 parts: The decoding map and
33cabdff1aSopenharmony_ci * the video data. A demuxer must load these 2 parts together in a single
34cabdff1aSopenharmony_ci * buffer before sending it through the stream to this decoder.
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
43cabdff1aSopenharmony_ci#define BITSTREAM_READER_LE
44cabdff1aSopenharmony_ci#include "avcodec.h"
45cabdff1aSopenharmony_ci#include "bytestream.h"
46cabdff1aSopenharmony_ci#include "codec_internal.h"
47cabdff1aSopenharmony_ci#include "decode.h"
48cabdff1aSopenharmony_ci#include "get_bits.h"
49cabdff1aSopenharmony_ci#include "hpeldsp.h"
50cabdff1aSopenharmony_ci#include "internal.h"
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_ci#define PALETTE_COUNT 256
53cabdff1aSopenharmony_ci
54cabdff1aSopenharmony_citypedef struct IpvideoContext {
55cabdff1aSopenharmony_ci
56cabdff1aSopenharmony_ci    AVCodecContext *avctx;
57cabdff1aSopenharmony_ci    HpelDSPContext hdsp;
58cabdff1aSopenharmony_ci    AVFrame *second_last_frame;
59cabdff1aSopenharmony_ci    AVFrame *last_frame;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci    /* For format 0x10 */
62cabdff1aSopenharmony_ci    AVFrame *cur_decode_frame;
63cabdff1aSopenharmony_ci    AVFrame *prev_decode_frame;
64cabdff1aSopenharmony_ci
65cabdff1aSopenharmony_ci    const unsigned char *decoding_map;
66cabdff1aSopenharmony_ci    int decoding_map_size;
67cabdff1aSopenharmony_ci    const unsigned char *skip_map;
68cabdff1aSopenharmony_ci    int skip_map_size;
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_ci    int is_16bpp;
71cabdff1aSopenharmony_ci    GetByteContext stream_ptr, mv_ptr;
72cabdff1aSopenharmony_ci    unsigned char *pixel_ptr;
73cabdff1aSopenharmony_ci    int line_inc;
74cabdff1aSopenharmony_ci    int stride;
75cabdff1aSopenharmony_ci    int upper_motion_limit_offset;
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci    uint32_t pal[256];
78cabdff1aSopenharmony_ci} IpvideoContext;
79cabdff1aSopenharmony_ci
80cabdff1aSopenharmony_cistatic int copy_from(IpvideoContext *s, AVFrame *src, AVFrame *dst, int delta_x, int delta_y)
81cabdff1aSopenharmony_ci{
82cabdff1aSopenharmony_ci    int width = dst->width;
83cabdff1aSopenharmony_ci    int current_offset = s->pixel_ptr - dst->data[0];
84cabdff1aSopenharmony_ci    int x = (current_offset % dst->linesize[0]) / (1 + s->is_16bpp);
85cabdff1aSopenharmony_ci    int y = current_offset / dst->linesize[0];
86cabdff1aSopenharmony_ci    int dx = delta_x + x - ((delta_x + x >= width) - (delta_x + x < 0)) * width;
87cabdff1aSopenharmony_ci    int dy = delta_y + y + (delta_x + x >= width) - (delta_x + x < 0);
88cabdff1aSopenharmony_ci    int motion_offset = dy * src->linesize[0] + dx * (1 + s->is_16bpp);
89cabdff1aSopenharmony_ci
90cabdff1aSopenharmony_ci    if (motion_offset < 0) {
91cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "motion offset < 0 (%d)\n", motion_offset);
92cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
93cabdff1aSopenharmony_ci    } else if (motion_offset > s->upper_motion_limit_offset) {
94cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "motion offset above limit (%d >= %d)\n",
95cabdff1aSopenharmony_ci            motion_offset, s->upper_motion_limit_offset);
96cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
97cabdff1aSopenharmony_ci    }
98cabdff1aSopenharmony_ci    if (!src->data[0]) {
99cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "Invalid decode type, corrupted header?\n");
100cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
101cabdff1aSopenharmony_ci    }
102cabdff1aSopenharmony_ci    s->hdsp.put_pixels_tab[!s->is_16bpp][0](s->pixel_ptr, src->data[0] + motion_offset,
103cabdff1aSopenharmony_ci                                            dst->linesize[0], 8);
104cabdff1aSopenharmony_ci    return 0;
105cabdff1aSopenharmony_ci}
106cabdff1aSopenharmony_ci
107cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x0(IpvideoContext *s, AVFrame *frame)
108cabdff1aSopenharmony_ci{
109cabdff1aSopenharmony_ci    return copy_from(s, s->last_frame, frame, 0, 0);
110cabdff1aSopenharmony_ci}
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x1(IpvideoContext *s, AVFrame *frame)
113cabdff1aSopenharmony_ci{
114cabdff1aSopenharmony_ci    return copy_from(s, s->second_last_frame, frame, 0, 0);
115cabdff1aSopenharmony_ci}
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x2(IpvideoContext *s, AVFrame *frame)
118cabdff1aSopenharmony_ci{
119cabdff1aSopenharmony_ci    unsigned char B;
120cabdff1aSopenharmony_ci    int x, y;
121cabdff1aSopenharmony_ci
122cabdff1aSopenharmony_ci    /* copy block from 2 frames ago using a motion vector; need 1 more byte */
123cabdff1aSopenharmony_ci    if (!s->is_16bpp) {
124cabdff1aSopenharmony_ci        B = bytestream2_get_byte(&s->stream_ptr);
125cabdff1aSopenharmony_ci    } else {
126cabdff1aSopenharmony_ci        B = bytestream2_get_byte(&s->mv_ptr);
127cabdff1aSopenharmony_ci    }
128cabdff1aSopenharmony_ci
129cabdff1aSopenharmony_ci    if (B < 56) {
130cabdff1aSopenharmony_ci        x = 8 + (B % 7);
131cabdff1aSopenharmony_ci        y = B / 7;
132cabdff1aSopenharmony_ci    } else {
133cabdff1aSopenharmony_ci        x = -14 + ((B - 56) % 29);
134cabdff1aSopenharmony_ci        y =   8 + ((B - 56) / 29);
135cabdff1aSopenharmony_ci    }
136cabdff1aSopenharmony_ci
137cabdff1aSopenharmony_ci    ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
138cabdff1aSopenharmony_ci    return copy_from(s, s->second_last_frame, frame, x, y);
139cabdff1aSopenharmony_ci}
140cabdff1aSopenharmony_ci
141cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x3(IpvideoContext *s, AVFrame *frame)
142cabdff1aSopenharmony_ci{
143cabdff1aSopenharmony_ci    unsigned char B;
144cabdff1aSopenharmony_ci    int x, y;
145cabdff1aSopenharmony_ci
146cabdff1aSopenharmony_ci    /* copy 8x8 block from current frame from an up/left block */
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    /* need 1 more byte for motion */
149cabdff1aSopenharmony_ci    if (!s->is_16bpp) {
150cabdff1aSopenharmony_ci        B = bytestream2_get_byte(&s->stream_ptr);
151cabdff1aSopenharmony_ci    } else {
152cabdff1aSopenharmony_ci        B = bytestream2_get_byte(&s->mv_ptr);
153cabdff1aSopenharmony_ci    }
154cabdff1aSopenharmony_ci
155cabdff1aSopenharmony_ci    if (B < 56) {
156cabdff1aSopenharmony_ci        x = -(8 + (B % 7));
157cabdff1aSopenharmony_ci        y = -(B / 7);
158cabdff1aSopenharmony_ci    } else {
159cabdff1aSopenharmony_ci        x = -(-14 + ((B - 56) % 29));
160cabdff1aSopenharmony_ci        y = -(  8 + ((B - 56) / 29));
161cabdff1aSopenharmony_ci    }
162cabdff1aSopenharmony_ci
163cabdff1aSopenharmony_ci    ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
164cabdff1aSopenharmony_ci    return copy_from(s, frame, frame, x, y);
165cabdff1aSopenharmony_ci}
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x4(IpvideoContext *s, AVFrame *frame)
168cabdff1aSopenharmony_ci{
169cabdff1aSopenharmony_ci    int x, y;
170cabdff1aSopenharmony_ci    unsigned char B, BL, BH;
171cabdff1aSopenharmony_ci
172cabdff1aSopenharmony_ci    /* copy a block from the previous frame; need 1 more byte */
173cabdff1aSopenharmony_ci    if (!s->is_16bpp) {
174cabdff1aSopenharmony_ci        B = bytestream2_get_byte(&s->stream_ptr);
175cabdff1aSopenharmony_ci    } else {
176cabdff1aSopenharmony_ci        B = bytestream2_get_byte(&s->mv_ptr);
177cabdff1aSopenharmony_ci    }
178cabdff1aSopenharmony_ci
179cabdff1aSopenharmony_ci    BL = B & 0x0F;
180cabdff1aSopenharmony_ci    BH = (B >> 4) & 0x0F;
181cabdff1aSopenharmony_ci    x = -8 + BL;
182cabdff1aSopenharmony_ci    y = -8 + BH;
183cabdff1aSopenharmony_ci
184cabdff1aSopenharmony_ci    ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
185cabdff1aSopenharmony_ci    return copy_from(s, s->last_frame, frame, x, y);
186cabdff1aSopenharmony_ci}
187cabdff1aSopenharmony_ci
188cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x5(IpvideoContext *s, AVFrame *frame)
189cabdff1aSopenharmony_ci{
190cabdff1aSopenharmony_ci    signed char x, y;
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_ci    /* copy a block from the previous frame using an expanded range;
193cabdff1aSopenharmony_ci     * need 2 more bytes */
194cabdff1aSopenharmony_ci    x = bytestream2_get_byte(&s->stream_ptr);
195cabdff1aSopenharmony_ci    y = bytestream2_get_byte(&s->stream_ptr);
196cabdff1aSopenharmony_ci
197cabdff1aSopenharmony_ci    ff_tlog(s->avctx, "motion bytes = %d, %d\n", x, y);
198cabdff1aSopenharmony_ci    return copy_from(s, s->last_frame, frame, x, y);
199cabdff1aSopenharmony_ci}
200cabdff1aSopenharmony_ci
201cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x6(IpvideoContext *s, AVFrame *frame)
202cabdff1aSopenharmony_ci{
203cabdff1aSopenharmony_ci    /* mystery opcode? skip multiple blocks? */
204cabdff1aSopenharmony_ci    av_log(s->avctx, AV_LOG_ERROR, "Help! Mystery opcode 0x6 seen\n");
205cabdff1aSopenharmony_ci
206cabdff1aSopenharmony_ci    /* report success */
207cabdff1aSopenharmony_ci    return 0;
208cabdff1aSopenharmony_ci}
209cabdff1aSopenharmony_ci
210cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x7(IpvideoContext *s, AVFrame *frame)
211cabdff1aSopenharmony_ci{
212cabdff1aSopenharmony_ci    int x, y;
213cabdff1aSopenharmony_ci    unsigned char P[2];
214cabdff1aSopenharmony_ci    unsigned int flags;
215cabdff1aSopenharmony_ci
216cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(&s->stream_ptr) < 4) {
217cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x7\n");
218cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
219cabdff1aSopenharmony_ci    }
220cabdff1aSopenharmony_ci
221cabdff1aSopenharmony_ci    /* 2-color encoding */
222cabdff1aSopenharmony_ci    P[0] = bytestream2_get_byte(&s->stream_ptr);
223cabdff1aSopenharmony_ci    P[1] = bytestream2_get_byte(&s->stream_ptr);
224cabdff1aSopenharmony_ci
225cabdff1aSopenharmony_ci    if (P[0] <= P[1]) {
226cabdff1aSopenharmony_ci
227cabdff1aSopenharmony_ci        /* need 8 more bytes from the stream */
228cabdff1aSopenharmony_ci        for (y = 0; y < 8; y++) {
229cabdff1aSopenharmony_ci            flags = bytestream2_get_byte(&s->stream_ptr) | 0x100;
230cabdff1aSopenharmony_ci            for (; flags != 1; flags >>= 1)
231cabdff1aSopenharmony_ci                *s->pixel_ptr++ = P[flags & 1];
232cabdff1aSopenharmony_ci            s->pixel_ptr += s->line_inc;
233cabdff1aSopenharmony_ci        }
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci    } else {
236cabdff1aSopenharmony_ci
237cabdff1aSopenharmony_ci        /* need 2 more bytes from the stream */
238cabdff1aSopenharmony_ci        flags = bytestream2_get_le16(&s->stream_ptr);
239cabdff1aSopenharmony_ci        for (y = 0; y < 8; y += 2) {
240cabdff1aSopenharmony_ci            for (x = 0; x < 8; x += 2, flags >>= 1) {
241cabdff1aSopenharmony_ci                s->pixel_ptr[x                ] =
242cabdff1aSopenharmony_ci                s->pixel_ptr[x + 1            ] =
243cabdff1aSopenharmony_ci                s->pixel_ptr[x +     s->stride] =
244cabdff1aSopenharmony_ci                s->pixel_ptr[x + 1 + s->stride] = P[flags & 1];
245cabdff1aSopenharmony_ci            }
246cabdff1aSopenharmony_ci            s->pixel_ptr += s->stride * 2;
247cabdff1aSopenharmony_ci        }
248cabdff1aSopenharmony_ci    }
249cabdff1aSopenharmony_ci
250cabdff1aSopenharmony_ci    /* report success */
251cabdff1aSopenharmony_ci    return 0;
252cabdff1aSopenharmony_ci}
253cabdff1aSopenharmony_ci
254cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x8(IpvideoContext *s, AVFrame *frame)
255cabdff1aSopenharmony_ci{
256cabdff1aSopenharmony_ci    int x, y;
257cabdff1aSopenharmony_ci    unsigned char P[4];
258cabdff1aSopenharmony_ci    unsigned int flags = 0;
259cabdff1aSopenharmony_ci
260cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(&s->stream_ptr) < 12) {
261cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x8\n");
262cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
263cabdff1aSopenharmony_ci    }
264cabdff1aSopenharmony_ci
265cabdff1aSopenharmony_ci    /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
266cabdff1aSopenharmony_ci     * either top and bottom or left and right halves */
267cabdff1aSopenharmony_ci    P[0] = bytestream2_get_byte(&s->stream_ptr);
268cabdff1aSopenharmony_ci    P[1] = bytestream2_get_byte(&s->stream_ptr);
269cabdff1aSopenharmony_ci
270cabdff1aSopenharmony_ci    if (P[0] <= P[1]) {
271cabdff1aSopenharmony_ci        for (y = 0; y < 16; y++) {
272cabdff1aSopenharmony_ci            // new values for each 4x4 block
273cabdff1aSopenharmony_ci            if (!(y & 3)) {
274cabdff1aSopenharmony_ci                if (y) {
275cabdff1aSopenharmony_ci                    P[0]  = bytestream2_get_byte(&s->stream_ptr);
276cabdff1aSopenharmony_ci                    P[1]  = bytestream2_get_byte(&s->stream_ptr);
277cabdff1aSopenharmony_ci                }
278cabdff1aSopenharmony_ci                flags = bytestream2_get_le16(&s->stream_ptr);
279cabdff1aSopenharmony_ci            }
280cabdff1aSopenharmony_ci
281cabdff1aSopenharmony_ci            for (x = 0; x < 4; x++, flags >>= 1)
282cabdff1aSopenharmony_ci                *s->pixel_ptr++ = P[flags & 1];
283cabdff1aSopenharmony_ci            s->pixel_ptr += s->stride - 4;
284cabdff1aSopenharmony_ci            // switch to right half
285cabdff1aSopenharmony_ci            if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
286cabdff1aSopenharmony_ci        }
287cabdff1aSopenharmony_ci
288cabdff1aSopenharmony_ci    } else {
289cabdff1aSopenharmony_ci        flags = bytestream2_get_le32(&s->stream_ptr);
290cabdff1aSopenharmony_ci        P[2] = bytestream2_get_byte(&s->stream_ptr);
291cabdff1aSopenharmony_ci        P[3] = bytestream2_get_byte(&s->stream_ptr);
292cabdff1aSopenharmony_ci
293cabdff1aSopenharmony_ci        if (P[2] <= P[3]) {
294cabdff1aSopenharmony_ci
295cabdff1aSopenharmony_ci            /* vertical split; left & right halves are 2-color encoded */
296cabdff1aSopenharmony_ci
297cabdff1aSopenharmony_ci            for (y = 0; y < 16; y++) {
298cabdff1aSopenharmony_ci                for (x = 0; x < 4; x++, flags >>= 1)
299cabdff1aSopenharmony_ci                    *s->pixel_ptr++ = P[flags & 1];
300cabdff1aSopenharmony_ci                s->pixel_ptr += s->stride - 4;
301cabdff1aSopenharmony_ci                // switch to right half
302cabdff1aSopenharmony_ci                if (y == 7) {
303cabdff1aSopenharmony_ci                    s->pixel_ptr -= 8 * s->stride - 4;
304cabdff1aSopenharmony_ci                    P[0]  = P[2];
305cabdff1aSopenharmony_ci                    P[1]  = P[3];
306cabdff1aSopenharmony_ci                    flags = bytestream2_get_le32(&s->stream_ptr);
307cabdff1aSopenharmony_ci                }
308cabdff1aSopenharmony_ci            }
309cabdff1aSopenharmony_ci
310cabdff1aSopenharmony_ci        } else {
311cabdff1aSopenharmony_ci
312cabdff1aSopenharmony_ci            /* horizontal split; top & bottom halves are 2-color encoded */
313cabdff1aSopenharmony_ci
314cabdff1aSopenharmony_ci            for (y = 0; y < 8; y++) {
315cabdff1aSopenharmony_ci                if (y == 4) {
316cabdff1aSopenharmony_ci                    P[0]  = P[2];
317cabdff1aSopenharmony_ci                    P[1]  = P[3];
318cabdff1aSopenharmony_ci                    flags = bytestream2_get_le32(&s->stream_ptr);
319cabdff1aSopenharmony_ci                }
320cabdff1aSopenharmony_ci
321cabdff1aSopenharmony_ci                for (x = 0; x < 8; x++, flags >>= 1)
322cabdff1aSopenharmony_ci                    *s->pixel_ptr++ = P[flags & 1];
323cabdff1aSopenharmony_ci                s->pixel_ptr += s->line_inc;
324cabdff1aSopenharmony_ci            }
325cabdff1aSopenharmony_ci        }
326cabdff1aSopenharmony_ci    }
327cabdff1aSopenharmony_ci
328cabdff1aSopenharmony_ci    /* report success */
329cabdff1aSopenharmony_ci    return 0;
330cabdff1aSopenharmony_ci}
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x9(IpvideoContext *s, AVFrame *frame)
333cabdff1aSopenharmony_ci{
334cabdff1aSopenharmony_ci    int x, y;
335cabdff1aSopenharmony_ci    unsigned char P[4];
336cabdff1aSopenharmony_ci
337cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(&s->stream_ptr) < 8) {
338cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x9\n");
339cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
340cabdff1aSopenharmony_ci    }
341cabdff1aSopenharmony_ci
342cabdff1aSopenharmony_ci    /* 4-color encoding */
343cabdff1aSopenharmony_ci    bytestream2_get_buffer(&s->stream_ptr, P, 4);
344cabdff1aSopenharmony_ci
345cabdff1aSopenharmony_ci    if (P[0] <= P[1]) {
346cabdff1aSopenharmony_ci        if (P[2] <= P[3]) {
347cabdff1aSopenharmony_ci
348cabdff1aSopenharmony_ci            /* 1 of 4 colors for each pixel, need 16 more bytes */
349cabdff1aSopenharmony_ci            for (y = 0; y < 8; y++) {
350cabdff1aSopenharmony_ci                /* get the next set of 8 2-bit flags */
351cabdff1aSopenharmony_ci                int flags = bytestream2_get_le16(&s->stream_ptr);
352cabdff1aSopenharmony_ci                for (x = 0; x < 8; x++, flags >>= 2)
353cabdff1aSopenharmony_ci                    *s->pixel_ptr++ = P[flags & 0x03];
354cabdff1aSopenharmony_ci                s->pixel_ptr += s->line_inc;
355cabdff1aSopenharmony_ci            }
356cabdff1aSopenharmony_ci
357cabdff1aSopenharmony_ci        } else {
358cabdff1aSopenharmony_ci            uint32_t flags;
359cabdff1aSopenharmony_ci
360cabdff1aSopenharmony_ci            /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
361cabdff1aSopenharmony_ci            flags = bytestream2_get_le32(&s->stream_ptr);
362cabdff1aSopenharmony_ci
363cabdff1aSopenharmony_ci            for (y = 0; y < 8; y += 2) {
364cabdff1aSopenharmony_ci                for (x = 0; x < 8; x += 2, flags >>= 2) {
365cabdff1aSopenharmony_ci                    s->pixel_ptr[x                ] =
366cabdff1aSopenharmony_ci                    s->pixel_ptr[x + 1            ] =
367cabdff1aSopenharmony_ci                    s->pixel_ptr[x +     s->stride] =
368cabdff1aSopenharmony_ci                    s->pixel_ptr[x + 1 + s->stride] = P[flags & 0x03];
369cabdff1aSopenharmony_ci                }
370cabdff1aSopenharmony_ci                s->pixel_ptr += s->stride * 2;
371cabdff1aSopenharmony_ci            }
372cabdff1aSopenharmony_ci
373cabdff1aSopenharmony_ci        }
374cabdff1aSopenharmony_ci    } else {
375cabdff1aSopenharmony_ci        uint64_t flags;
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_ci        /* 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes */
378cabdff1aSopenharmony_ci        flags = bytestream2_get_le64(&s->stream_ptr);
379cabdff1aSopenharmony_ci        if (P[2] <= P[3]) {
380cabdff1aSopenharmony_ci            for (y = 0; y < 8; y++) {
381cabdff1aSopenharmony_ci                for (x = 0; x < 8; x += 2, flags >>= 2) {
382cabdff1aSopenharmony_ci                    s->pixel_ptr[x    ] =
383cabdff1aSopenharmony_ci                    s->pixel_ptr[x + 1] = P[flags & 0x03];
384cabdff1aSopenharmony_ci                }
385cabdff1aSopenharmony_ci                s->pixel_ptr += s->stride;
386cabdff1aSopenharmony_ci            }
387cabdff1aSopenharmony_ci        } else {
388cabdff1aSopenharmony_ci            for (y = 0; y < 8; y += 2) {
389cabdff1aSopenharmony_ci                for (x = 0; x < 8; x++, flags >>= 2) {
390cabdff1aSopenharmony_ci                    s->pixel_ptr[x            ] =
391cabdff1aSopenharmony_ci                    s->pixel_ptr[x + s->stride] = P[flags & 0x03];
392cabdff1aSopenharmony_ci                }
393cabdff1aSopenharmony_ci                s->pixel_ptr += s->stride * 2;
394cabdff1aSopenharmony_ci            }
395cabdff1aSopenharmony_ci        }
396cabdff1aSopenharmony_ci    }
397cabdff1aSopenharmony_ci
398cabdff1aSopenharmony_ci    /* report success */
399cabdff1aSopenharmony_ci    return 0;
400cabdff1aSopenharmony_ci}
401cabdff1aSopenharmony_ci
402cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xA(IpvideoContext *s, AVFrame *frame)
403cabdff1aSopenharmony_ci{
404cabdff1aSopenharmony_ci    int x, y;
405cabdff1aSopenharmony_ci    unsigned char P[8];
406cabdff1aSopenharmony_ci    int flags = 0;
407cabdff1aSopenharmony_ci
408cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(&s->stream_ptr) < 16) {
409cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0xA\n");
410cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
411cabdff1aSopenharmony_ci    }
412cabdff1aSopenharmony_ci
413cabdff1aSopenharmony_ci    bytestream2_get_buffer(&s->stream_ptr, P, 4);
414cabdff1aSopenharmony_ci
415cabdff1aSopenharmony_ci    /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
416cabdff1aSopenharmony_ci     * either top and bottom or left and right halves */
417cabdff1aSopenharmony_ci    if (P[0] <= P[1]) {
418cabdff1aSopenharmony_ci
419cabdff1aSopenharmony_ci        /* 4-color encoding for each quadrant; need 32 bytes */
420cabdff1aSopenharmony_ci        for (y = 0; y < 16; y++) {
421cabdff1aSopenharmony_ci            // new values for each 4x4 block
422cabdff1aSopenharmony_ci            if (!(y & 3)) {
423cabdff1aSopenharmony_ci                if (y) bytestream2_get_buffer(&s->stream_ptr, P, 4);
424cabdff1aSopenharmony_ci                flags = bytestream2_get_le32(&s->stream_ptr);
425cabdff1aSopenharmony_ci            }
426cabdff1aSopenharmony_ci
427cabdff1aSopenharmony_ci            for (x = 0; x < 4; x++, flags >>= 2)
428cabdff1aSopenharmony_ci                *s->pixel_ptr++ = P[flags & 0x03];
429cabdff1aSopenharmony_ci
430cabdff1aSopenharmony_ci            s->pixel_ptr += s->stride - 4;
431cabdff1aSopenharmony_ci            // switch to right half
432cabdff1aSopenharmony_ci            if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
433cabdff1aSopenharmony_ci        }
434cabdff1aSopenharmony_ci
435cabdff1aSopenharmony_ci    } else {
436cabdff1aSopenharmony_ci        // vertical split?
437cabdff1aSopenharmony_ci        int vert;
438cabdff1aSopenharmony_ci        uint64_t flags = bytestream2_get_le64(&s->stream_ptr);
439cabdff1aSopenharmony_ci
440cabdff1aSopenharmony_ci        bytestream2_get_buffer(&s->stream_ptr, P + 4, 4);
441cabdff1aSopenharmony_ci        vert = P[4] <= P[5];
442cabdff1aSopenharmony_ci
443cabdff1aSopenharmony_ci        /* 4-color encoding for either left and right or top and bottom
444cabdff1aSopenharmony_ci         * halves */
445cabdff1aSopenharmony_ci
446cabdff1aSopenharmony_ci        for (y = 0; y < 16; y++) {
447cabdff1aSopenharmony_ci            for (x = 0; x < 4; x++, flags >>= 2)
448cabdff1aSopenharmony_ci                *s->pixel_ptr++ = P[flags & 0x03];
449cabdff1aSopenharmony_ci
450cabdff1aSopenharmony_ci            if (vert) {
451cabdff1aSopenharmony_ci                s->pixel_ptr += s->stride - 4;
452cabdff1aSopenharmony_ci                // switch to right half
453cabdff1aSopenharmony_ci                if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
454cabdff1aSopenharmony_ci            } else if (y & 1) s->pixel_ptr += s->line_inc;
455cabdff1aSopenharmony_ci
456cabdff1aSopenharmony_ci            // load values for second half
457cabdff1aSopenharmony_ci            if (y == 7) {
458cabdff1aSopenharmony_ci                memcpy(P, P + 4, 4);
459cabdff1aSopenharmony_ci                flags = bytestream2_get_le64(&s->stream_ptr);
460cabdff1aSopenharmony_ci            }
461cabdff1aSopenharmony_ci        }
462cabdff1aSopenharmony_ci    }
463cabdff1aSopenharmony_ci
464cabdff1aSopenharmony_ci    /* report success */
465cabdff1aSopenharmony_ci    return 0;
466cabdff1aSopenharmony_ci}
467cabdff1aSopenharmony_ci
468cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xB(IpvideoContext *s, AVFrame *frame)
469cabdff1aSopenharmony_ci{
470cabdff1aSopenharmony_ci    int y;
471cabdff1aSopenharmony_ci
472cabdff1aSopenharmony_ci    /* 64-color encoding (each pixel in block is a different color) */
473cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
474cabdff1aSopenharmony_ci        bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8);
475cabdff1aSopenharmony_ci        s->pixel_ptr  += s->stride;
476cabdff1aSopenharmony_ci    }
477cabdff1aSopenharmony_ci
478cabdff1aSopenharmony_ci    /* report success */
479cabdff1aSopenharmony_ci    return 0;
480cabdff1aSopenharmony_ci}
481cabdff1aSopenharmony_ci
482cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xC(IpvideoContext *s, AVFrame *frame)
483cabdff1aSopenharmony_ci{
484cabdff1aSopenharmony_ci    int x, y;
485cabdff1aSopenharmony_ci
486cabdff1aSopenharmony_ci    /* 16-color block encoding: each 2x2 block is a different color */
487cabdff1aSopenharmony_ci    for (y = 0; y < 8; y += 2) {
488cabdff1aSopenharmony_ci        for (x = 0; x < 8; x += 2) {
489cabdff1aSopenharmony_ci            s->pixel_ptr[x                ] =
490cabdff1aSopenharmony_ci            s->pixel_ptr[x + 1            ] =
491cabdff1aSopenharmony_ci            s->pixel_ptr[x +     s->stride] =
492cabdff1aSopenharmony_ci            s->pixel_ptr[x + 1 + s->stride] = bytestream2_get_byte(&s->stream_ptr);
493cabdff1aSopenharmony_ci        }
494cabdff1aSopenharmony_ci        s->pixel_ptr += s->stride * 2;
495cabdff1aSopenharmony_ci    }
496cabdff1aSopenharmony_ci
497cabdff1aSopenharmony_ci    /* report success */
498cabdff1aSopenharmony_ci    return 0;
499cabdff1aSopenharmony_ci}
500cabdff1aSopenharmony_ci
501cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xD(IpvideoContext *s, AVFrame *frame)
502cabdff1aSopenharmony_ci{
503cabdff1aSopenharmony_ci    int y;
504cabdff1aSopenharmony_ci    unsigned char P[2];
505cabdff1aSopenharmony_ci
506cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(&s->stream_ptr) < 4) {
507cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0xD\n");
508cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
509cabdff1aSopenharmony_ci    }
510cabdff1aSopenharmony_ci
511cabdff1aSopenharmony_ci    /* 4-color block encoding: each 4x4 block is a different color */
512cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
513cabdff1aSopenharmony_ci        if (!(y & 3)) {
514cabdff1aSopenharmony_ci            P[0] = bytestream2_get_byte(&s->stream_ptr);
515cabdff1aSopenharmony_ci            P[1] = bytestream2_get_byte(&s->stream_ptr);
516cabdff1aSopenharmony_ci        }
517cabdff1aSopenharmony_ci        memset(s->pixel_ptr,     P[0], 4);
518cabdff1aSopenharmony_ci        memset(s->pixel_ptr + 4, P[1], 4);
519cabdff1aSopenharmony_ci        s->pixel_ptr += s->stride;
520cabdff1aSopenharmony_ci    }
521cabdff1aSopenharmony_ci
522cabdff1aSopenharmony_ci    /* report success */
523cabdff1aSopenharmony_ci    return 0;
524cabdff1aSopenharmony_ci}
525cabdff1aSopenharmony_ci
526cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xE(IpvideoContext *s, AVFrame *frame)
527cabdff1aSopenharmony_ci{
528cabdff1aSopenharmony_ci    int y;
529cabdff1aSopenharmony_ci    unsigned char pix;
530cabdff1aSopenharmony_ci
531cabdff1aSopenharmony_ci    /* 1-color encoding: the whole block is 1 solid color */
532cabdff1aSopenharmony_ci    pix = bytestream2_get_byte(&s->stream_ptr);
533cabdff1aSopenharmony_ci
534cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
535cabdff1aSopenharmony_ci        memset(s->pixel_ptr, pix, 8);
536cabdff1aSopenharmony_ci        s->pixel_ptr += s->stride;
537cabdff1aSopenharmony_ci    }
538cabdff1aSopenharmony_ci
539cabdff1aSopenharmony_ci    /* report success */
540cabdff1aSopenharmony_ci    return 0;
541cabdff1aSopenharmony_ci}
542cabdff1aSopenharmony_ci
543cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xF(IpvideoContext *s, AVFrame *frame)
544cabdff1aSopenharmony_ci{
545cabdff1aSopenharmony_ci    int x, y;
546cabdff1aSopenharmony_ci    unsigned char sample[2];
547cabdff1aSopenharmony_ci
548cabdff1aSopenharmony_ci    /* dithered encoding */
549cabdff1aSopenharmony_ci    sample[0] = bytestream2_get_byte(&s->stream_ptr);
550cabdff1aSopenharmony_ci    sample[1] = bytestream2_get_byte(&s->stream_ptr);
551cabdff1aSopenharmony_ci
552cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
553cabdff1aSopenharmony_ci        for (x = 0; x < 8; x += 2) {
554cabdff1aSopenharmony_ci            *s->pixel_ptr++ = sample[  y & 1 ];
555cabdff1aSopenharmony_ci            *s->pixel_ptr++ = sample[!(y & 1)];
556cabdff1aSopenharmony_ci        }
557cabdff1aSopenharmony_ci        s->pixel_ptr += s->line_inc;
558cabdff1aSopenharmony_ci    }
559cabdff1aSopenharmony_ci
560cabdff1aSopenharmony_ci    /* report success */
561cabdff1aSopenharmony_ci    return 0;
562cabdff1aSopenharmony_ci}
563cabdff1aSopenharmony_ci
564cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s, AVFrame *frame)
565cabdff1aSopenharmony_ci{
566cabdff1aSopenharmony_ci    signed char x, y;
567cabdff1aSopenharmony_ci
568cabdff1aSopenharmony_ci    /* copy a block from the second last frame using an expanded range */
569cabdff1aSopenharmony_ci    x = bytestream2_get_byte(&s->stream_ptr);
570cabdff1aSopenharmony_ci    y = bytestream2_get_byte(&s->stream_ptr);
571cabdff1aSopenharmony_ci
572cabdff1aSopenharmony_ci    ff_tlog(s->avctx, "motion bytes = %d, %d\n", x, y);
573cabdff1aSopenharmony_ci    return copy_from(s, s->second_last_frame, frame, x, y);
574cabdff1aSopenharmony_ci}
575cabdff1aSopenharmony_ci
576cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x7_16(IpvideoContext *s, AVFrame *frame)
577cabdff1aSopenharmony_ci{
578cabdff1aSopenharmony_ci    int x, y;
579cabdff1aSopenharmony_ci    uint16_t P[2];
580cabdff1aSopenharmony_ci    unsigned int flags;
581cabdff1aSopenharmony_ci    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
582cabdff1aSopenharmony_ci
583cabdff1aSopenharmony_ci    /* 2-color encoding */
584cabdff1aSopenharmony_ci    P[0] = bytestream2_get_le16(&s->stream_ptr);
585cabdff1aSopenharmony_ci    P[1] = bytestream2_get_le16(&s->stream_ptr);
586cabdff1aSopenharmony_ci
587cabdff1aSopenharmony_ci    if (!(P[0] & 0x8000)) {
588cabdff1aSopenharmony_ci
589cabdff1aSopenharmony_ci        for (y = 0; y < 8; y++) {
590cabdff1aSopenharmony_ci            flags = bytestream2_get_byte(&s->stream_ptr) | 0x100;
591cabdff1aSopenharmony_ci            for (; flags != 1; flags >>= 1)
592cabdff1aSopenharmony_ci                *pixel_ptr++ = P[flags & 1];
593cabdff1aSopenharmony_ci            pixel_ptr += s->line_inc;
594cabdff1aSopenharmony_ci        }
595cabdff1aSopenharmony_ci
596cabdff1aSopenharmony_ci    } else {
597cabdff1aSopenharmony_ci
598cabdff1aSopenharmony_ci        flags = bytestream2_get_le16(&s->stream_ptr);
599cabdff1aSopenharmony_ci        for (y = 0; y < 8; y += 2) {
600cabdff1aSopenharmony_ci            for (x = 0; x < 8; x += 2, flags >>= 1) {
601cabdff1aSopenharmony_ci                pixel_ptr[x                ] =
602cabdff1aSopenharmony_ci                pixel_ptr[x + 1            ] =
603cabdff1aSopenharmony_ci                pixel_ptr[x +     s->stride] =
604cabdff1aSopenharmony_ci                pixel_ptr[x + 1 + s->stride] = P[flags & 1];
605cabdff1aSopenharmony_ci            }
606cabdff1aSopenharmony_ci            pixel_ptr += s->stride * 2;
607cabdff1aSopenharmony_ci        }
608cabdff1aSopenharmony_ci    }
609cabdff1aSopenharmony_ci
610cabdff1aSopenharmony_ci    return 0;
611cabdff1aSopenharmony_ci}
612cabdff1aSopenharmony_ci
613cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x8_16(IpvideoContext *s, AVFrame *frame)
614cabdff1aSopenharmony_ci{
615cabdff1aSopenharmony_ci    int x, y;
616cabdff1aSopenharmony_ci    uint16_t P[4];
617cabdff1aSopenharmony_ci    unsigned int flags = 0;
618cabdff1aSopenharmony_ci    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
619cabdff1aSopenharmony_ci
620cabdff1aSopenharmony_ci    /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
621cabdff1aSopenharmony_ci     * either top and bottom or left and right halves */
622cabdff1aSopenharmony_ci    P[0] = bytestream2_get_le16(&s->stream_ptr);
623cabdff1aSopenharmony_ci    P[1] = bytestream2_get_le16(&s->stream_ptr);
624cabdff1aSopenharmony_ci
625cabdff1aSopenharmony_ci    if (!(P[0] & 0x8000)) {
626cabdff1aSopenharmony_ci
627cabdff1aSopenharmony_ci        for (y = 0; y < 16; y++) {
628cabdff1aSopenharmony_ci            // new values for each 4x4 block
629cabdff1aSopenharmony_ci            if (!(y & 3)) {
630cabdff1aSopenharmony_ci                if (y) {
631cabdff1aSopenharmony_ci                    P[0] = bytestream2_get_le16(&s->stream_ptr);
632cabdff1aSopenharmony_ci                    P[1] = bytestream2_get_le16(&s->stream_ptr);
633cabdff1aSopenharmony_ci                }
634cabdff1aSopenharmony_ci                flags = bytestream2_get_le16(&s->stream_ptr);
635cabdff1aSopenharmony_ci            }
636cabdff1aSopenharmony_ci
637cabdff1aSopenharmony_ci            for (x = 0; x < 4; x++, flags >>= 1)
638cabdff1aSopenharmony_ci                *pixel_ptr++ = P[flags & 1];
639cabdff1aSopenharmony_ci            pixel_ptr += s->stride - 4;
640cabdff1aSopenharmony_ci            // switch to right half
641cabdff1aSopenharmony_ci            if (y == 7) pixel_ptr -= 8 * s->stride - 4;
642cabdff1aSopenharmony_ci        }
643cabdff1aSopenharmony_ci
644cabdff1aSopenharmony_ci    } else {
645cabdff1aSopenharmony_ci
646cabdff1aSopenharmony_ci        flags = bytestream2_get_le32(&s->stream_ptr);
647cabdff1aSopenharmony_ci        P[2]  = bytestream2_get_le16(&s->stream_ptr);
648cabdff1aSopenharmony_ci        P[3]  = bytestream2_get_le16(&s->stream_ptr);
649cabdff1aSopenharmony_ci
650cabdff1aSopenharmony_ci        if (!(P[2] & 0x8000)) {
651cabdff1aSopenharmony_ci
652cabdff1aSopenharmony_ci            /* vertical split; left & right halves are 2-color encoded */
653cabdff1aSopenharmony_ci
654cabdff1aSopenharmony_ci            for (y = 0; y < 16; y++) {
655cabdff1aSopenharmony_ci                for (x = 0; x < 4; x++, flags >>= 1)
656cabdff1aSopenharmony_ci                    *pixel_ptr++ = P[flags & 1];
657cabdff1aSopenharmony_ci                pixel_ptr += s->stride - 4;
658cabdff1aSopenharmony_ci                // switch to right half
659cabdff1aSopenharmony_ci                if (y == 7) {
660cabdff1aSopenharmony_ci                    pixel_ptr -= 8 * s->stride - 4;
661cabdff1aSopenharmony_ci                    P[0]  = P[2];
662cabdff1aSopenharmony_ci                    P[1]  = P[3];
663cabdff1aSopenharmony_ci                    flags = bytestream2_get_le32(&s->stream_ptr);
664cabdff1aSopenharmony_ci                }
665cabdff1aSopenharmony_ci            }
666cabdff1aSopenharmony_ci
667cabdff1aSopenharmony_ci        } else {
668cabdff1aSopenharmony_ci
669cabdff1aSopenharmony_ci            /* horizontal split; top & bottom halves are 2-color encoded */
670cabdff1aSopenharmony_ci
671cabdff1aSopenharmony_ci            for (y = 0; y < 8; y++) {
672cabdff1aSopenharmony_ci                if (y == 4) {
673cabdff1aSopenharmony_ci                    P[0]  = P[2];
674cabdff1aSopenharmony_ci                    P[1]  = P[3];
675cabdff1aSopenharmony_ci                    flags = bytestream2_get_le32(&s->stream_ptr);
676cabdff1aSopenharmony_ci                }
677cabdff1aSopenharmony_ci
678cabdff1aSopenharmony_ci                for (x = 0; x < 8; x++, flags >>= 1)
679cabdff1aSopenharmony_ci                    *pixel_ptr++ = P[flags & 1];
680cabdff1aSopenharmony_ci                pixel_ptr += s->line_inc;
681cabdff1aSopenharmony_ci            }
682cabdff1aSopenharmony_ci        }
683cabdff1aSopenharmony_ci    }
684cabdff1aSopenharmony_ci
685cabdff1aSopenharmony_ci    /* report success */
686cabdff1aSopenharmony_ci    return 0;
687cabdff1aSopenharmony_ci}
688cabdff1aSopenharmony_ci
689cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x9_16(IpvideoContext *s, AVFrame *frame)
690cabdff1aSopenharmony_ci{
691cabdff1aSopenharmony_ci    int x, y;
692cabdff1aSopenharmony_ci    uint16_t P[4];
693cabdff1aSopenharmony_ci    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
694cabdff1aSopenharmony_ci
695cabdff1aSopenharmony_ci    /* 4-color encoding */
696cabdff1aSopenharmony_ci    for (x = 0; x < 4; x++)
697cabdff1aSopenharmony_ci        P[x] = bytestream2_get_le16(&s->stream_ptr);
698cabdff1aSopenharmony_ci
699cabdff1aSopenharmony_ci    if (!(P[0] & 0x8000)) {
700cabdff1aSopenharmony_ci        if (!(P[2] & 0x8000)) {
701cabdff1aSopenharmony_ci
702cabdff1aSopenharmony_ci            /* 1 of 4 colors for each pixel */
703cabdff1aSopenharmony_ci            for (y = 0; y < 8; y++) {
704cabdff1aSopenharmony_ci                /* get the next set of 8 2-bit flags */
705cabdff1aSopenharmony_ci                int flags = bytestream2_get_le16(&s->stream_ptr);
706cabdff1aSopenharmony_ci                for (x = 0; x < 8; x++, flags >>= 2)
707cabdff1aSopenharmony_ci                    *pixel_ptr++ = P[flags & 0x03];
708cabdff1aSopenharmony_ci                pixel_ptr += s->line_inc;
709cabdff1aSopenharmony_ci            }
710cabdff1aSopenharmony_ci
711cabdff1aSopenharmony_ci        } else {
712cabdff1aSopenharmony_ci            uint32_t flags;
713cabdff1aSopenharmony_ci
714cabdff1aSopenharmony_ci            /* 1 of 4 colors for each 2x2 block */
715cabdff1aSopenharmony_ci            flags = bytestream2_get_le32(&s->stream_ptr);
716cabdff1aSopenharmony_ci
717cabdff1aSopenharmony_ci            for (y = 0; y < 8; y += 2) {
718cabdff1aSopenharmony_ci                for (x = 0; x < 8; x += 2, flags >>= 2) {
719cabdff1aSopenharmony_ci                    pixel_ptr[x                ] =
720cabdff1aSopenharmony_ci                    pixel_ptr[x + 1            ] =
721cabdff1aSopenharmony_ci                    pixel_ptr[x +     s->stride] =
722cabdff1aSopenharmony_ci                    pixel_ptr[x + 1 + s->stride] = P[flags & 0x03];
723cabdff1aSopenharmony_ci                }
724cabdff1aSopenharmony_ci                pixel_ptr += s->stride * 2;
725cabdff1aSopenharmony_ci            }
726cabdff1aSopenharmony_ci
727cabdff1aSopenharmony_ci        }
728cabdff1aSopenharmony_ci    } else {
729cabdff1aSopenharmony_ci        uint64_t flags;
730cabdff1aSopenharmony_ci
731cabdff1aSopenharmony_ci        /* 1 of 4 colors for each 2x1 or 1x2 block */
732cabdff1aSopenharmony_ci        flags = bytestream2_get_le64(&s->stream_ptr);
733cabdff1aSopenharmony_ci        if (!(P[2] & 0x8000)) {
734cabdff1aSopenharmony_ci            for (y = 0; y < 8; y++) {
735cabdff1aSopenharmony_ci                for (x = 0; x < 8; x += 2, flags >>= 2) {
736cabdff1aSopenharmony_ci                    pixel_ptr[x    ] =
737cabdff1aSopenharmony_ci                    pixel_ptr[x + 1] = P[flags & 0x03];
738cabdff1aSopenharmony_ci                }
739cabdff1aSopenharmony_ci                pixel_ptr += s->stride;
740cabdff1aSopenharmony_ci            }
741cabdff1aSopenharmony_ci        } else {
742cabdff1aSopenharmony_ci            for (y = 0; y < 8; y += 2) {
743cabdff1aSopenharmony_ci                for (x = 0; x < 8; x++, flags >>= 2) {
744cabdff1aSopenharmony_ci                    pixel_ptr[x            ] =
745cabdff1aSopenharmony_ci                    pixel_ptr[x + s->stride] = P[flags & 0x03];
746cabdff1aSopenharmony_ci                }
747cabdff1aSopenharmony_ci                pixel_ptr += s->stride * 2;
748cabdff1aSopenharmony_ci            }
749cabdff1aSopenharmony_ci        }
750cabdff1aSopenharmony_ci    }
751cabdff1aSopenharmony_ci
752cabdff1aSopenharmony_ci    /* report success */
753cabdff1aSopenharmony_ci    return 0;
754cabdff1aSopenharmony_ci}
755cabdff1aSopenharmony_ci
756cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xA_16(IpvideoContext *s, AVFrame *frame)
757cabdff1aSopenharmony_ci{
758cabdff1aSopenharmony_ci    int x, y;
759cabdff1aSopenharmony_ci    uint16_t P[8];
760cabdff1aSopenharmony_ci    int flags = 0;
761cabdff1aSopenharmony_ci    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
762cabdff1aSopenharmony_ci
763cabdff1aSopenharmony_ci    for (x = 0; x < 4; x++)
764cabdff1aSopenharmony_ci        P[x] = bytestream2_get_le16(&s->stream_ptr);
765cabdff1aSopenharmony_ci
766cabdff1aSopenharmony_ci    /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
767cabdff1aSopenharmony_ci     * either top and bottom or left and right halves */
768cabdff1aSopenharmony_ci    if (!(P[0] & 0x8000)) {
769cabdff1aSopenharmony_ci
770cabdff1aSopenharmony_ci        /* 4-color encoding for each quadrant */
771cabdff1aSopenharmony_ci        for (y = 0; y < 16; y++) {
772cabdff1aSopenharmony_ci            // new values for each 4x4 block
773cabdff1aSopenharmony_ci            if (!(y & 3)) {
774cabdff1aSopenharmony_ci                if (y)
775cabdff1aSopenharmony_ci                    for (x = 0; x < 4; x++)
776cabdff1aSopenharmony_ci                        P[x] = bytestream2_get_le16(&s->stream_ptr);
777cabdff1aSopenharmony_ci                flags = bytestream2_get_le32(&s->stream_ptr);
778cabdff1aSopenharmony_ci            }
779cabdff1aSopenharmony_ci
780cabdff1aSopenharmony_ci            for (x = 0; x < 4; x++, flags >>= 2)
781cabdff1aSopenharmony_ci                *pixel_ptr++ = P[flags & 0x03];
782cabdff1aSopenharmony_ci
783cabdff1aSopenharmony_ci            pixel_ptr += s->stride - 4;
784cabdff1aSopenharmony_ci            // switch to right half
785cabdff1aSopenharmony_ci            if (y == 7) pixel_ptr -= 8 * s->stride - 4;
786cabdff1aSopenharmony_ci        }
787cabdff1aSopenharmony_ci
788cabdff1aSopenharmony_ci    } else {
789cabdff1aSopenharmony_ci        // vertical split?
790cabdff1aSopenharmony_ci        int vert;
791cabdff1aSopenharmony_ci        uint64_t flags = bytestream2_get_le64(&s->stream_ptr);
792cabdff1aSopenharmony_ci
793cabdff1aSopenharmony_ci        for (x = 4; x < 8; x++)
794cabdff1aSopenharmony_ci            P[x] = bytestream2_get_le16(&s->stream_ptr);
795cabdff1aSopenharmony_ci        vert = !(P[4] & 0x8000);
796cabdff1aSopenharmony_ci
797cabdff1aSopenharmony_ci        /* 4-color encoding for either left and right or top and bottom
798cabdff1aSopenharmony_ci         * halves */
799cabdff1aSopenharmony_ci
800cabdff1aSopenharmony_ci        for (y = 0; y < 16; y++) {
801cabdff1aSopenharmony_ci            for (x = 0; x < 4; x++, flags >>= 2)
802cabdff1aSopenharmony_ci                *pixel_ptr++ = P[flags & 0x03];
803cabdff1aSopenharmony_ci
804cabdff1aSopenharmony_ci            if (vert) {
805cabdff1aSopenharmony_ci                pixel_ptr += s->stride - 4;
806cabdff1aSopenharmony_ci                // switch to right half
807cabdff1aSopenharmony_ci                if (y == 7) pixel_ptr -= 8 * s->stride - 4;
808cabdff1aSopenharmony_ci            } else if (y & 1) pixel_ptr += s->line_inc;
809cabdff1aSopenharmony_ci
810cabdff1aSopenharmony_ci            // load values for second half
811cabdff1aSopenharmony_ci            if (y == 7) {
812cabdff1aSopenharmony_ci                memcpy(P, P + 4, 8);
813cabdff1aSopenharmony_ci                flags = bytestream2_get_le64(&s->stream_ptr);
814cabdff1aSopenharmony_ci            }
815cabdff1aSopenharmony_ci        }
816cabdff1aSopenharmony_ci    }
817cabdff1aSopenharmony_ci
818cabdff1aSopenharmony_ci    /* report success */
819cabdff1aSopenharmony_ci    return 0;
820cabdff1aSopenharmony_ci}
821cabdff1aSopenharmony_ci
822cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xB_16(IpvideoContext *s, AVFrame *frame)
823cabdff1aSopenharmony_ci{
824cabdff1aSopenharmony_ci    int x, y;
825cabdff1aSopenharmony_ci    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
826cabdff1aSopenharmony_ci
827cabdff1aSopenharmony_ci    /* 64-color encoding (each pixel in block is a different color) */
828cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
829cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
830cabdff1aSopenharmony_ci            pixel_ptr[x] = bytestream2_get_le16(&s->stream_ptr);
831cabdff1aSopenharmony_ci        pixel_ptr  += s->stride;
832cabdff1aSopenharmony_ci    }
833cabdff1aSopenharmony_ci
834cabdff1aSopenharmony_ci    /* report success */
835cabdff1aSopenharmony_ci    return 0;
836cabdff1aSopenharmony_ci}
837cabdff1aSopenharmony_ci
838cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xC_16(IpvideoContext *s, AVFrame *frame)
839cabdff1aSopenharmony_ci{
840cabdff1aSopenharmony_ci    int x, y;
841cabdff1aSopenharmony_ci    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
842cabdff1aSopenharmony_ci
843cabdff1aSopenharmony_ci    /* 16-color block encoding: each 2x2 block is a different color */
844cabdff1aSopenharmony_ci    for (y = 0; y < 8; y += 2) {
845cabdff1aSopenharmony_ci        for (x = 0; x < 8; x += 2) {
846cabdff1aSopenharmony_ci            pixel_ptr[x                ] =
847cabdff1aSopenharmony_ci            pixel_ptr[x + 1            ] =
848cabdff1aSopenharmony_ci            pixel_ptr[x +     s->stride] =
849cabdff1aSopenharmony_ci            pixel_ptr[x + 1 + s->stride] = bytestream2_get_le16(&s->stream_ptr);
850cabdff1aSopenharmony_ci        }
851cabdff1aSopenharmony_ci        pixel_ptr += s->stride * 2;
852cabdff1aSopenharmony_ci    }
853cabdff1aSopenharmony_ci
854cabdff1aSopenharmony_ci    /* report success */
855cabdff1aSopenharmony_ci    return 0;
856cabdff1aSopenharmony_ci}
857cabdff1aSopenharmony_ci
858cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xD_16(IpvideoContext *s, AVFrame *frame)
859cabdff1aSopenharmony_ci{
860cabdff1aSopenharmony_ci    int x, y;
861cabdff1aSopenharmony_ci    uint16_t P[2];
862cabdff1aSopenharmony_ci    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
863cabdff1aSopenharmony_ci
864cabdff1aSopenharmony_ci    /* 4-color block encoding: each 4x4 block is a different color */
865cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
866cabdff1aSopenharmony_ci        if (!(y & 3)) {
867cabdff1aSopenharmony_ci            P[0] = bytestream2_get_le16(&s->stream_ptr);
868cabdff1aSopenharmony_ci            P[1] = bytestream2_get_le16(&s->stream_ptr);
869cabdff1aSopenharmony_ci        }
870cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
871cabdff1aSopenharmony_ci            pixel_ptr[x] = P[x >> 2];
872cabdff1aSopenharmony_ci        pixel_ptr += s->stride;
873cabdff1aSopenharmony_ci    }
874cabdff1aSopenharmony_ci
875cabdff1aSopenharmony_ci    /* report success */
876cabdff1aSopenharmony_ci    return 0;
877cabdff1aSopenharmony_ci}
878cabdff1aSopenharmony_ci
879cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xE_16(IpvideoContext *s, AVFrame *frame)
880cabdff1aSopenharmony_ci{
881cabdff1aSopenharmony_ci    int x, y;
882cabdff1aSopenharmony_ci    uint16_t pix;
883cabdff1aSopenharmony_ci    uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr;
884cabdff1aSopenharmony_ci
885cabdff1aSopenharmony_ci    /* 1-color encoding: the whole block is 1 solid color */
886cabdff1aSopenharmony_ci    pix = bytestream2_get_le16(&s->stream_ptr);
887cabdff1aSopenharmony_ci
888cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
889cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
890cabdff1aSopenharmony_ci            pixel_ptr[x] = pix;
891cabdff1aSopenharmony_ci        pixel_ptr += s->stride;
892cabdff1aSopenharmony_ci    }
893cabdff1aSopenharmony_ci
894cabdff1aSopenharmony_ci    /* report success */
895cabdff1aSopenharmony_ci    return 0;
896cabdff1aSopenharmony_ci}
897cabdff1aSopenharmony_ci
898cabdff1aSopenharmony_cistatic int (* const ipvideo_decode_block[])(IpvideoContext *s, AVFrame *frame) = {
899cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1,
900cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3,
901cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5,
902cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7,
903cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0x8, ipvideo_decode_block_opcode_0x9,
904cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB,
905cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD,
906cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF,
907cabdff1aSopenharmony_ci};
908cabdff1aSopenharmony_ci
909cabdff1aSopenharmony_cistatic int (* const ipvideo_decode_block16[])(IpvideoContext *s, AVFrame *frame) = {
910cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0x0,    ipvideo_decode_block_opcode_0x1,
911cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0x2,    ipvideo_decode_block_opcode_0x3,
912cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0x4,    ipvideo_decode_block_opcode_0x5,
913cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0x6_16, ipvideo_decode_block_opcode_0x7_16,
914cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0x8_16, ipvideo_decode_block_opcode_0x9_16,
915cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0xA_16, ipvideo_decode_block_opcode_0xB_16,
916cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0xC_16, ipvideo_decode_block_opcode_0xD_16,
917cabdff1aSopenharmony_ci    ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1,
918cabdff1aSopenharmony_ci};
919cabdff1aSopenharmony_ci
920cabdff1aSopenharmony_cistatic void ipvideo_format_06_firstpass(IpvideoContext *s, AVFrame *frame, int16_t opcode)
921cabdff1aSopenharmony_ci{
922cabdff1aSopenharmony_ci    int line;
923cabdff1aSopenharmony_ci
924cabdff1aSopenharmony_ci    if (!opcode) {
925cabdff1aSopenharmony_ci        for (line = 0; line < 8; ++line) {
926cabdff1aSopenharmony_ci            bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8);
927cabdff1aSopenharmony_ci            s->pixel_ptr += s->stride;
928cabdff1aSopenharmony_ci        }
929cabdff1aSopenharmony_ci    } else {
930cabdff1aSopenharmony_ci        /* Don't try to copy second_last_frame data on the first frames */
931cabdff1aSopenharmony_ci        if (s->avctx->frame_number > 2)
932cabdff1aSopenharmony_ci            copy_from(s, s->second_last_frame, frame, 0, 0);
933cabdff1aSopenharmony_ci    }
934cabdff1aSopenharmony_ci}
935cabdff1aSopenharmony_ci
936cabdff1aSopenharmony_cistatic void ipvideo_format_06_secondpass(IpvideoContext *s, AVFrame *frame, int16_t opcode)
937cabdff1aSopenharmony_ci{
938cabdff1aSopenharmony_ci    int off_x, off_y;
939cabdff1aSopenharmony_ci
940cabdff1aSopenharmony_ci    if (opcode < 0) {
941cabdff1aSopenharmony_ci        off_x = ((uint16_t)opcode - 0xC000) % frame->width;
942cabdff1aSopenharmony_ci        off_y = ((uint16_t)opcode - 0xC000) / frame->width;
943cabdff1aSopenharmony_ci        copy_from(s, s->last_frame, frame, off_x, off_y);
944cabdff1aSopenharmony_ci    } else if (opcode > 0) {
945cabdff1aSopenharmony_ci        off_x = ((uint16_t)opcode - 0x4000) % frame->width;
946cabdff1aSopenharmony_ci        off_y = ((uint16_t)opcode - 0x4000) / frame->width;
947cabdff1aSopenharmony_ci        copy_from(s, frame, frame, off_x, off_y);
948cabdff1aSopenharmony_ci    }
949cabdff1aSopenharmony_ci}
950cabdff1aSopenharmony_ci
951cabdff1aSopenharmony_cistatic void (* const ipvideo_format_06_passes[])(IpvideoContext *s, AVFrame *frame, int16_t op) = {
952cabdff1aSopenharmony_ci    ipvideo_format_06_firstpass, ipvideo_format_06_secondpass,
953cabdff1aSopenharmony_ci};
954cabdff1aSopenharmony_ci
955cabdff1aSopenharmony_cistatic void ipvideo_decode_format_06_opcodes(IpvideoContext *s, AVFrame *frame)
956cabdff1aSopenharmony_ci{
957cabdff1aSopenharmony_ci    int pass, x, y;
958cabdff1aSopenharmony_ci    int16_t opcode;
959cabdff1aSopenharmony_ci    GetByteContext decoding_map_ptr;
960cabdff1aSopenharmony_ci
961cabdff1aSopenharmony_ci    /* this is PAL8, so make the palette available */
962cabdff1aSopenharmony_ci    memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
963cabdff1aSopenharmony_ci    s->stride = frame->linesize[0];
964cabdff1aSopenharmony_ci
965cabdff1aSopenharmony_ci    s->line_inc = s->stride - 8;
966cabdff1aSopenharmony_ci    s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0]
967cabdff1aSopenharmony_ci                                  + (s->avctx->width - 8) * (1 + s->is_16bpp);
968cabdff1aSopenharmony_ci
969cabdff1aSopenharmony_ci    bytestream2_init(&decoding_map_ptr, s->decoding_map, s->decoding_map_size);
970cabdff1aSopenharmony_ci
971cabdff1aSopenharmony_ci    for (pass = 0; pass < 2; ++pass) {
972cabdff1aSopenharmony_ci        bytestream2_seek(&decoding_map_ptr, 0, SEEK_SET);
973cabdff1aSopenharmony_ci        for (y = 0; y < s->avctx->height; y += 8) {
974cabdff1aSopenharmony_ci            for (x = 0; x < s->avctx->width; x += 8) {
975cabdff1aSopenharmony_ci                opcode = bytestream2_get_le16(&decoding_map_ptr);
976cabdff1aSopenharmony_ci
977cabdff1aSopenharmony_ci                ff_tlog(s->avctx,
978cabdff1aSopenharmony_ci                        "  block @ (%3d, %3d): opcode 0x%X, data ptr offset %d\n",
979cabdff1aSopenharmony_ci                        x, y, opcode, bytestream2_tell(&s->stream_ptr));
980cabdff1aSopenharmony_ci
981cabdff1aSopenharmony_ci                s->pixel_ptr = frame->data[0] + x + y * frame->linesize[0];
982cabdff1aSopenharmony_ci                ipvideo_format_06_passes[pass](s, frame, opcode);
983cabdff1aSopenharmony_ci            }
984cabdff1aSopenharmony_ci        }
985cabdff1aSopenharmony_ci    }
986cabdff1aSopenharmony_ci
987cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) {
988cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_DEBUG,
989cabdff1aSopenharmony_ci               "decode finished with %d bytes left over\n",
990cabdff1aSopenharmony_ci               bytestream2_get_bytes_left(&s->stream_ptr));
991cabdff1aSopenharmony_ci    }
992cabdff1aSopenharmony_ci}
993cabdff1aSopenharmony_ci
994cabdff1aSopenharmony_cistatic void ipvideo_format_10_firstpass(IpvideoContext *s, AVFrame *frame, int16_t opcode)
995cabdff1aSopenharmony_ci{
996cabdff1aSopenharmony_ci    int line;
997cabdff1aSopenharmony_ci
998cabdff1aSopenharmony_ci    if (!opcode) {
999cabdff1aSopenharmony_ci        for (line = 0; line < 8; ++line) {
1000cabdff1aSopenharmony_ci            bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8);
1001cabdff1aSopenharmony_ci            s->pixel_ptr += s->stride;
1002cabdff1aSopenharmony_ci        }
1003cabdff1aSopenharmony_ci    }
1004cabdff1aSopenharmony_ci}
1005cabdff1aSopenharmony_ci
1006cabdff1aSopenharmony_cistatic void ipvideo_format_10_secondpass(IpvideoContext *s, AVFrame *frame, int16_t opcode)
1007cabdff1aSopenharmony_ci{
1008cabdff1aSopenharmony_ci    int off_x, off_y;
1009cabdff1aSopenharmony_ci
1010cabdff1aSopenharmony_ci    if (opcode < 0) {
1011cabdff1aSopenharmony_ci        off_x = ((uint16_t)opcode - 0xC000) % s->cur_decode_frame->width;
1012cabdff1aSopenharmony_ci        off_y = ((uint16_t)opcode - 0xC000) / s->cur_decode_frame->width;
1013cabdff1aSopenharmony_ci        copy_from(s, s->prev_decode_frame, s->cur_decode_frame, off_x, off_y);
1014cabdff1aSopenharmony_ci    } else if (opcode > 0) {
1015cabdff1aSopenharmony_ci        off_x = ((uint16_t)opcode - 0x4000) % s->cur_decode_frame->width;
1016cabdff1aSopenharmony_ci        off_y = ((uint16_t)opcode - 0x4000) / s->cur_decode_frame->width;
1017cabdff1aSopenharmony_ci        copy_from(s, s->cur_decode_frame, s->cur_decode_frame, off_x, off_y);
1018cabdff1aSopenharmony_ci    }
1019cabdff1aSopenharmony_ci}
1020cabdff1aSopenharmony_ci
1021cabdff1aSopenharmony_cistatic void (* const ipvideo_format_10_passes[])(IpvideoContext *s, AVFrame *frame, int16_t op) = {
1022cabdff1aSopenharmony_ci    ipvideo_format_10_firstpass, ipvideo_format_10_secondpass,
1023cabdff1aSopenharmony_ci};
1024cabdff1aSopenharmony_ci
1025cabdff1aSopenharmony_cistatic void ipvideo_decode_format_10_opcodes(IpvideoContext *s, AVFrame *frame)
1026cabdff1aSopenharmony_ci{
1027cabdff1aSopenharmony_ci    int pass, x, y, changed_block;
1028cabdff1aSopenharmony_ci    int16_t opcode, skip;
1029cabdff1aSopenharmony_ci    GetByteContext decoding_map_ptr;
1030cabdff1aSopenharmony_ci    GetByteContext skip_map_ptr;
1031cabdff1aSopenharmony_ci
1032cabdff1aSopenharmony_ci    bytestream2_skip(&s->stream_ptr, 14); /* data starts 14 bytes in */
1033cabdff1aSopenharmony_ci
1034cabdff1aSopenharmony_ci    /* this is PAL8, so make the palette available */
1035cabdff1aSopenharmony_ci    memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
1036cabdff1aSopenharmony_ci    s->stride = frame->linesize[0];
1037cabdff1aSopenharmony_ci
1038cabdff1aSopenharmony_ci    s->line_inc = s->stride - 8;
1039cabdff1aSopenharmony_ci    s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0]
1040cabdff1aSopenharmony_ci                                  + (s->avctx->width - 8) * (1 + s->is_16bpp);
1041cabdff1aSopenharmony_ci
1042cabdff1aSopenharmony_ci    bytestream2_init(&decoding_map_ptr, s->decoding_map, s->decoding_map_size);
1043cabdff1aSopenharmony_ci    bytestream2_init(&skip_map_ptr, s->skip_map, s->skip_map_size);
1044cabdff1aSopenharmony_ci
1045cabdff1aSopenharmony_ci    for (pass = 0; pass < 2; ++pass) {
1046cabdff1aSopenharmony_ci        bytestream2_seek(&decoding_map_ptr, 0, SEEK_SET);
1047cabdff1aSopenharmony_ci        bytestream2_seek(&skip_map_ptr, 0, SEEK_SET);
1048cabdff1aSopenharmony_ci        skip = bytestream2_get_le16(&skip_map_ptr);
1049cabdff1aSopenharmony_ci
1050cabdff1aSopenharmony_ci        for (y = 0; y < s->avctx->height; y += 8) {
1051cabdff1aSopenharmony_ci            for (x = 0; x < s->avctx->width; x += 8) {
1052cabdff1aSopenharmony_ci                s->pixel_ptr = s->cur_decode_frame->data[0] + x + y * s->cur_decode_frame->linesize[0];
1053cabdff1aSopenharmony_ci
1054cabdff1aSopenharmony_ci                while (skip <= 0)  {
1055cabdff1aSopenharmony_ci                    if (skip != -0x8000 && skip) {
1056cabdff1aSopenharmony_ci                        opcode = bytestream2_get_le16(&decoding_map_ptr);
1057cabdff1aSopenharmony_ci                        ipvideo_format_10_passes[pass](s, frame, opcode);
1058cabdff1aSopenharmony_ci                        break;
1059cabdff1aSopenharmony_ci                    }
1060cabdff1aSopenharmony_ci                    if (bytestream2_get_bytes_left(&skip_map_ptr) < 2)
1061cabdff1aSopenharmony_ci                        return;
1062cabdff1aSopenharmony_ci                    skip = bytestream2_get_le16(&skip_map_ptr);
1063cabdff1aSopenharmony_ci                }
1064cabdff1aSopenharmony_ci                skip *= 2;
1065cabdff1aSopenharmony_ci            }
1066cabdff1aSopenharmony_ci        }
1067cabdff1aSopenharmony_ci    }
1068cabdff1aSopenharmony_ci
1069cabdff1aSopenharmony_ci    bytestream2_seek(&skip_map_ptr, 0, SEEK_SET);
1070cabdff1aSopenharmony_ci    skip = bytestream2_get_le16(&skip_map_ptr);
1071cabdff1aSopenharmony_ci    for (y = 0; y < s->avctx->height; y += 8) {
1072cabdff1aSopenharmony_ci        for (x = 0; x < s->avctx->width; x += 8) {
1073cabdff1aSopenharmony_ci            changed_block = 0;
1074cabdff1aSopenharmony_ci            s->pixel_ptr = frame->data[0] + x + y*frame->linesize[0];
1075cabdff1aSopenharmony_ci
1076cabdff1aSopenharmony_ci            while (skip <= 0)  {
1077cabdff1aSopenharmony_ci                if (skip != -0x8000 && skip) {
1078cabdff1aSopenharmony_ci                    changed_block = 1;
1079cabdff1aSopenharmony_ci                    break;
1080cabdff1aSopenharmony_ci                }
1081cabdff1aSopenharmony_ci                if (bytestream2_get_bytes_left(&skip_map_ptr) < 2)
1082cabdff1aSopenharmony_ci                    return;
1083cabdff1aSopenharmony_ci                skip = bytestream2_get_le16(&skip_map_ptr);
1084cabdff1aSopenharmony_ci            }
1085cabdff1aSopenharmony_ci
1086cabdff1aSopenharmony_ci            if (changed_block) {
1087cabdff1aSopenharmony_ci                copy_from(s, s->cur_decode_frame, frame, 0, 0);
1088cabdff1aSopenharmony_ci            } else {
1089cabdff1aSopenharmony_ci                /* Don't try to copy last_frame data on the first frame */
1090cabdff1aSopenharmony_ci                if (s->avctx->frame_number)
1091cabdff1aSopenharmony_ci                    copy_from(s, s->last_frame, frame, 0, 0);
1092cabdff1aSopenharmony_ci            }
1093cabdff1aSopenharmony_ci            skip *= 2;
1094cabdff1aSopenharmony_ci        }
1095cabdff1aSopenharmony_ci    }
1096cabdff1aSopenharmony_ci
1097cabdff1aSopenharmony_ci    FFSWAP(AVFrame*, s->prev_decode_frame, s->cur_decode_frame);
1098cabdff1aSopenharmony_ci
1099cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) {
1100cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_DEBUG,
1101cabdff1aSopenharmony_ci               "decode finished with %d bytes left over\n",
1102cabdff1aSopenharmony_ci               bytestream2_get_bytes_left(&s->stream_ptr));
1103cabdff1aSopenharmony_ci    }
1104cabdff1aSopenharmony_ci}
1105cabdff1aSopenharmony_ci
1106cabdff1aSopenharmony_cistatic void ipvideo_decode_format_11_opcodes(IpvideoContext *s, AVFrame *frame)
1107cabdff1aSopenharmony_ci{
1108cabdff1aSopenharmony_ci    int x, y;
1109cabdff1aSopenharmony_ci    unsigned char opcode;
1110cabdff1aSopenharmony_ci    int ret;
1111cabdff1aSopenharmony_ci    GetBitContext gb;
1112cabdff1aSopenharmony_ci
1113cabdff1aSopenharmony_ci    bytestream2_skip(&s->stream_ptr, 14); /* data starts 14 bytes in */
1114cabdff1aSopenharmony_ci    if (!s->is_16bpp) {
1115cabdff1aSopenharmony_ci        /* this is PAL8, so make the palette available */
1116cabdff1aSopenharmony_ci        memcpy(frame->data[1], s->pal, AVPALETTE_SIZE);
1117cabdff1aSopenharmony_ci
1118cabdff1aSopenharmony_ci        s->stride = frame->linesize[0];
1119cabdff1aSopenharmony_ci    } else {
1120cabdff1aSopenharmony_ci        s->stride = frame->linesize[0] >> 1;
1121cabdff1aSopenharmony_ci        s->mv_ptr = s->stream_ptr;
1122cabdff1aSopenharmony_ci        bytestream2_skip(&s->mv_ptr, bytestream2_get_le16(&s->stream_ptr));
1123cabdff1aSopenharmony_ci    }
1124cabdff1aSopenharmony_ci    s->line_inc = s->stride - 8;
1125cabdff1aSopenharmony_ci    s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0]
1126cabdff1aSopenharmony_ci                                  + (s->avctx->width - 8) * (1 + s->is_16bpp);
1127cabdff1aSopenharmony_ci
1128cabdff1aSopenharmony_ci    init_get_bits(&gb, s->decoding_map, s->decoding_map_size * 8);
1129cabdff1aSopenharmony_ci    for (y = 0; y < s->avctx->height; y += 8) {
1130cabdff1aSopenharmony_ci        for (x = 0; x < s->avctx->width; x += 8) {
1131cabdff1aSopenharmony_ci            if (get_bits_left(&gb) < 4)
1132cabdff1aSopenharmony_ci                return;
1133cabdff1aSopenharmony_ci            opcode = get_bits(&gb, 4);
1134cabdff1aSopenharmony_ci
1135cabdff1aSopenharmony_ci            ff_tlog(s->avctx,
1136cabdff1aSopenharmony_ci                    "  block @ (%3d, %3d): encoding 0x%X, data ptr offset %d\n",
1137cabdff1aSopenharmony_ci                    x, y, opcode, bytestream2_tell(&s->stream_ptr));
1138cabdff1aSopenharmony_ci
1139cabdff1aSopenharmony_ci            if (!s->is_16bpp) {
1140cabdff1aSopenharmony_ci                s->pixel_ptr = frame->data[0] + x
1141cabdff1aSopenharmony_ci                              + y*frame->linesize[0];
1142cabdff1aSopenharmony_ci                ret = ipvideo_decode_block[opcode](s, frame);
1143cabdff1aSopenharmony_ci            } else {
1144cabdff1aSopenharmony_ci                s->pixel_ptr = frame->data[0] + x*2
1145cabdff1aSopenharmony_ci                              + y*frame->linesize[0];
1146cabdff1aSopenharmony_ci                ret = ipvideo_decode_block16[opcode](s, frame);
1147cabdff1aSopenharmony_ci            }
1148cabdff1aSopenharmony_ci            if (ret != 0) {
1149cabdff1aSopenharmony_ci                av_log(s->avctx, AV_LOG_ERROR, "decode problem on frame %d, @ block (%d, %d)\n",
1150cabdff1aSopenharmony_ci                       s->avctx->frame_number, x, y);
1151cabdff1aSopenharmony_ci                return;
1152cabdff1aSopenharmony_ci            }
1153cabdff1aSopenharmony_ci        }
1154cabdff1aSopenharmony_ci    }
1155cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) {
1156cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_DEBUG,
1157cabdff1aSopenharmony_ci               "decode finished with %d bytes left over\n",
1158cabdff1aSopenharmony_ci               bytestream2_get_bytes_left(&s->stream_ptr));
1159cabdff1aSopenharmony_ci    }
1160cabdff1aSopenharmony_ci}
1161cabdff1aSopenharmony_ci
1162cabdff1aSopenharmony_cistatic av_cold int ipvideo_decode_init(AVCodecContext *avctx)
1163cabdff1aSopenharmony_ci{
1164cabdff1aSopenharmony_ci    IpvideoContext *s = avctx->priv_data;
1165cabdff1aSopenharmony_ci
1166cabdff1aSopenharmony_ci    s->avctx = avctx;
1167cabdff1aSopenharmony_ci
1168cabdff1aSopenharmony_ci    s->is_16bpp = avctx->bits_per_coded_sample == 16;
1169cabdff1aSopenharmony_ci    avctx->pix_fmt = s->is_16bpp ? AV_PIX_FMT_RGB555 : AV_PIX_FMT_PAL8;
1170cabdff1aSopenharmony_ci
1171cabdff1aSopenharmony_ci    ff_hpeldsp_init(&s->hdsp, avctx->flags);
1172cabdff1aSopenharmony_ci
1173cabdff1aSopenharmony_ci    s->last_frame        = av_frame_alloc();
1174cabdff1aSopenharmony_ci    s->second_last_frame = av_frame_alloc();
1175cabdff1aSopenharmony_ci    s->cur_decode_frame  = av_frame_alloc();
1176cabdff1aSopenharmony_ci    s->prev_decode_frame = av_frame_alloc();
1177cabdff1aSopenharmony_ci    if (!s->last_frame || !s->second_last_frame ||
1178cabdff1aSopenharmony_ci        !s->cur_decode_frame || !s->prev_decode_frame) {
1179cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
1180cabdff1aSopenharmony_ci    }
1181cabdff1aSopenharmony_ci
1182cabdff1aSopenharmony_ci    s->cur_decode_frame->width   = avctx->width;
1183cabdff1aSopenharmony_ci    s->prev_decode_frame->width  = avctx->width;
1184cabdff1aSopenharmony_ci    s->cur_decode_frame->height  = avctx->height;
1185cabdff1aSopenharmony_ci    s->prev_decode_frame->height = avctx->height;
1186cabdff1aSopenharmony_ci    s->cur_decode_frame->format  = avctx->pix_fmt;
1187cabdff1aSopenharmony_ci    s->prev_decode_frame->format = avctx->pix_fmt;
1188cabdff1aSopenharmony_ci
1189cabdff1aSopenharmony_ci    return 0;
1190cabdff1aSopenharmony_ci}
1191cabdff1aSopenharmony_ci
1192cabdff1aSopenharmony_cistatic int ipvideo_decode_frame(AVCodecContext *avctx, AVFrame *frame,
1193cabdff1aSopenharmony_ci                                int *got_frame, AVPacket *avpkt)
1194cabdff1aSopenharmony_ci{
1195cabdff1aSopenharmony_ci    const uint8_t *buf = avpkt->data;
1196cabdff1aSopenharmony_ci    int buf_size = avpkt->size;
1197cabdff1aSopenharmony_ci    IpvideoContext *s = avctx->priv_data;
1198cabdff1aSopenharmony_ci    int ret;
1199cabdff1aSopenharmony_ci    int send_buffer;
1200cabdff1aSopenharmony_ci    int frame_format;
1201cabdff1aSopenharmony_ci    int video_data_size;
1202cabdff1aSopenharmony_ci
1203cabdff1aSopenharmony_ci    if (av_packet_get_side_data(avpkt, AV_PKT_DATA_PARAM_CHANGE, NULL)) {
1204cabdff1aSopenharmony_ci        av_frame_unref(s->last_frame);
1205cabdff1aSopenharmony_ci        av_frame_unref(s->second_last_frame);
1206cabdff1aSopenharmony_ci        av_frame_unref(s->cur_decode_frame);
1207cabdff1aSopenharmony_ci        av_frame_unref(s->prev_decode_frame);
1208cabdff1aSopenharmony_ci    }
1209cabdff1aSopenharmony_ci
1210cabdff1aSopenharmony_ci    if (!s->cur_decode_frame->data[0]) {
1211cabdff1aSopenharmony_ci        ret = ff_get_buffer(avctx, s->cur_decode_frame, 0);
1212cabdff1aSopenharmony_ci        if (ret < 0)
1213cabdff1aSopenharmony_ci            return ret;
1214cabdff1aSopenharmony_ci
1215cabdff1aSopenharmony_ci        ret = ff_get_buffer(avctx, s->prev_decode_frame, 0);
1216cabdff1aSopenharmony_ci        if (ret < 0) {
1217cabdff1aSopenharmony_ci            av_frame_unref(s->cur_decode_frame);
1218cabdff1aSopenharmony_ci            return ret;
1219cabdff1aSopenharmony_ci        }
1220cabdff1aSopenharmony_ci    }
1221cabdff1aSopenharmony_ci
1222cabdff1aSopenharmony_ci    if (buf_size < 8)
1223cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1224cabdff1aSopenharmony_ci
1225cabdff1aSopenharmony_ci    frame_format         = AV_RL8(buf);
1226cabdff1aSopenharmony_ci    send_buffer          = AV_RL8(buf + 1);
1227cabdff1aSopenharmony_ci    video_data_size      = AV_RL16(buf + 2);
1228cabdff1aSopenharmony_ci    s->decoding_map_size = AV_RL16(buf + 4);
1229cabdff1aSopenharmony_ci    s->skip_map_size     = AV_RL16(buf + 6);
1230cabdff1aSopenharmony_ci
1231cabdff1aSopenharmony_ci    switch (frame_format) {
1232cabdff1aSopenharmony_ci    case 0x06:
1233cabdff1aSopenharmony_ci        if (s->decoding_map_size) {
1234cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Decoding map for format 0x06\n");
1235cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1236cabdff1aSopenharmony_ci        }
1237cabdff1aSopenharmony_ci
1238cabdff1aSopenharmony_ci        if (s->skip_map_size) {
1239cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Skip map for format 0x06\n");
1240cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1241cabdff1aSopenharmony_ci        }
1242cabdff1aSopenharmony_ci
1243cabdff1aSopenharmony_ci        if (s->is_16bpp) {
1244cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Video format 0x06 does not support 16bpp movies\n");
1245cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1246cabdff1aSopenharmony_ci        }
1247cabdff1aSopenharmony_ci
1248cabdff1aSopenharmony_ci        /* Decoding map for 0x06 frame format is at the top of pixeldata */
1249cabdff1aSopenharmony_ci        s->decoding_map_size = ((s->avctx->width / 8) * (s->avctx->height / 8)) * 2;
1250cabdff1aSopenharmony_ci        s->decoding_map = buf + 8 + 14; /* 14 bits of op data */
1251cabdff1aSopenharmony_ci        video_data_size -= s->decoding_map_size + 14;
1252cabdff1aSopenharmony_ci        if (video_data_size <= 0 || s->decoding_map_size == 0)
1253cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1254cabdff1aSopenharmony_ci
1255cabdff1aSopenharmony_ci        if (buf_size < 8 + s->decoding_map_size + 14 + video_data_size)
1256cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1257cabdff1aSopenharmony_ci
1258cabdff1aSopenharmony_ci        bytestream2_init(&s->stream_ptr, buf + 8 + s->decoding_map_size + 14, video_data_size);
1259cabdff1aSopenharmony_ci
1260cabdff1aSopenharmony_ci        break;
1261cabdff1aSopenharmony_ci
1262cabdff1aSopenharmony_ci    case 0x10:
1263cabdff1aSopenharmony_ci        if (! s->decoding_map_size) {
1264cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Empty decoding map for format 0x10\n");
1265cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1266cabdff1aSopenharmony_ci        }
1267cabdff1aSopenharmony_ci
1268cabdff1aSopenharmony_ci        if (! s->skip_map_size) {
1269cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Empty skip map for format 0x10\n");
1270cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1271cabdff1aSopenharmony_ci        }
1272cabdff1aSopenharmony_ci
1273cabdff1aSopenharmony_ci        if (s->is_16bpp) {
1274cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Video format 0x10 does not support 16bpp movies\n");
1275cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1276cabdff1aSopenharmony_ci        }
1277cabdff1aSopenharmony_ci
1278cabdff1aSopenharmony_ci        if (buf_size < 8 + video_data_size + s->decoding_map_size + s->skip_map_size)
1279cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1280cabdff1aSopenharmony_ci
1281cabdff1aSopenharmony_ci        bytestream2_init(&s->stream_ptr, buf + 8, video_data_size);
1282cabdff1aSopenharmony_ci        s->decoding_map = buf + 8 + video_data_size;
1283cabdff1aSopenharmony_ci        s->skip_map = buf + 8 + video_data_size + s->decoding_map_size;
1284cabdff1aSopenharmony_ci
1285cabdff1aSopenharmony_ci        break;
1286cabdff1aSopenharmony_ci
1287cabdff1aSopenharmony_ci    case 0x11:
1288cabdff1aSopenharmony_ci        if (! s->decoding_map_size) {
1289cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Empty decoding map for format 0x11\n");
1290cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1291cabdff1aSopenharmony_ci        }
1292cabdff1aSopenharmony_ci
1293cabdff1aSopenharmony_ci        if (s->skip_map_size) {
1294cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Skip map for format 0x11\n");
1295cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1296cabdff1aSopenharmony_ci        }
1297cabdff1aSopenharmony_ci
1298cabdff1aSopenharmony_ci        if (buf_size < 8 + video_data_size + s->decoding_map_size)
1299cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1300cabdff1aSopenharmony_ci
1301cabdff1aSopenharmony_ci        bytestream2_init(&s->stream_ptr, buf + 8, video_data_size);
1302cabdff1aSopenharmony_ci        s->decoding_map = buf + 8 + video_data_size;
1303cabdff1aSopenharmony_ci
1304cabdff1aSopenharmony_ci        break;
1305cabdff1aSopenharmony_ci
1306cabdff1aSopenharmony_ci    default:
1307cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Frame type 0x%02X unsupported\n", frame_format);
1308cabdff1aSopenharmony_ci    }
1309cabdff1aSopenharmony_ci
1310cabdff1aSopenharmony_ci    /* ensure we can't overread the packet */
1311cabdff1aSopenharmony_ci    if (buf_size < 8 + s->decoding_map_size + video_data_size + s->skip_map_size) {
1312cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid IP packet size\n");
1313cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1314cabdff1aSopenharmony_ci    }
1315cabdff1aSopenharmony_ci
1316cabdff1aSopenharmony_ci    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
1317cabdff1aSopenharmony_ci        return ret;
1318cabdff1aSopenharmony_ci
1319cabdff1aSopenharmony_ci    if (!s->is_16bpp) {
1320cabdff1aSopenharmony_ci        frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
1321cabdff1aSopenharmony_ci    }
1322cabdff1aSopenharmony_ci
1323cabdff1aSopenharmony_ci    switch (frame_format) {
1324cabdff1aSopenharmony_ci    case 0x06:
1325cabdff1aSopenharmony_ci        ipvideo_decode_format_06_opcodes(s, frame);
1326cabdff1aSopenharmony_ci        break;
1327cabdff1aSopenharmony_ci    case 0x10:
1328cabdff1aSopenharmony_ci        ipvideo_decode_format_10_opcodes(s, frame);
1329cabdff1aSopenharmony_ci        break;
1330cabdff1aSopenharmony_ci    case 0x11:
1331cabdff1aSopenharmony_ci        ipvideo_decode_format_11_opcodes(s, frame);
1332cabdff1aSopenharmony_ci        break;
1333cabdff1aSopenharmony_ci    }
1334cabdff1aSopenharmony_ci
1335cabdff1aSopenharmony_ci    *got_frame = send_buffer;
1336cabdff1aSopenharmony_ci
1337cabdff1aSopenharmony_ci    /* shuffle frames */
1338cabdff1aSopenharmony_ci    av_frame_unref(s->second_last_frame);
1339cabdff1aSopenharmony_ci    FFSWAP(AVFrame*, s->second_last_frame, s->last_frame);
1340cabdff1aSopenharmony_ci    if ((ret = av_frame_ref(s->last_frame, frame)) < 0)
1341cabdff1aSopenharmony_ci        return ret;
1342cabdff1aSopenharmony_ci
1343cabdff1aSopenharmony_ci    /* report that the buffer was completely consumed */
1344cabdff1aSopenharmony_ci    return buf_size;
1345cabdff1aSopenharmony_ci}
1346cabdff1aSopenharmony_ci
1347cabdff1aSopenharmony_cistatic av_cold int ipvideo_decode_end(AVCodecContext *avctx)
1348cabdff1aSopenharmony_ci{
1349cabdff1aSopenharmony_ci    IpvideoContext *s = avctx->priv_data;
1350cabdff1aSopenharmony_ci
1351cabdff1aSopenharmony_ci    av_frame_free(&s->last_frame);
1352cabdff1aSopenharmony_ci    av_frame_free(&s->second_last_frame);
1353cabdff1aSopenharmony_ci    av_frame_free(&s->cur_decode_frame);
1354cabdff1aSopenharmony_ci    av_frame_free(&s->prev_decode_frame);
1355cabdff1aSopenharmony_ci
1356cabdff1aSopenharmony_ci    return 0;
1357cabdff1aSopenharmony_ci}
1358cabdff1aSopenharmony_ci
1359cabdff1aSopenharmony_ciconst FFCodec ff_interplay_video_decoder = {
1360cabdff1aSopenharmony_ci    .p.name         = "interplayvideo",
1361cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Interplay MVE video"),
1362cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
1363cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_INTERPLAY_VIDEO,
1364cabdff1aSopenharmony_ci    .priv_data_size = sizeof(IpvideoContext),
1365cabdff1aSopenharmony_ci    .init           = ipvideo_decode_init,
1366cabdff1aSopenharmony_ci    .close          = ipvideo_decode_end,
1367cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(ipvideo_decode_frame),
1368cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_PARAM_CHANGE,
1369cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
1370cabdff1aSopenharmony_ci};
1371