1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Zip Motion Blocks Video (ZMBV) decoder
3cabdff1aSopenharmony_ci * Copyright (c) 2006 Konstantin Shishkov
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 * Zip Motion Blocks Video decoder
25cabdff1aSopenharmony_ci */
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci#include <stdio.h>
28cabdff1aSopenharmony_ci#include <stdlib.h>
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#include "libavutil/common.h"
31cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
32cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
33cabdff1aSopenharmony_ci#include "avcodec.h"
34cabdff1aSopenharmony_ci#include "codec_internal.h"
35cabdff1aSopenharmony_ci#include "internal.h"
36cabdff1aSopenharmony_ci#include "zlib_wrapper.h"
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_ci#include <zlib.h>
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_ci#define ZMBV_KEYFRAME 1
41cabdff1aSopenharmony_ci#define ZMBV_DELTAPAL 2
42cabdff1aSopenharmony_ci
43cabdff1aSopenharmony_cienum ZmbvFormat {
44cabdff1aSopenharmony_ci    ZMBV_FMT_NONE  = 0,
45cabdff1aSopenharmony_ci    ZMBV_FMT_1BPP  = 1,
46cabdff1aSopenharmony_ci    ZMBV_FMT_2BPP  = 2,
47cabdff1aSopenharmony_ci    ZMBV_FMT_4BPP  = 3,
48cabdff1aSopenharmony_ci    ZMBV_FMT_8BPP  = 4,
49cabdff1aSopenharmony_ci    ZMBV_FMT_15BPP = 5,
50cabdff1aSopenharmony_ci    ZMBV_FMT_16BPP = 6,
51cabdff1aSopenharmony_ci    ZMBV_FMT_24BPP = 7,
52cabdff1aSopenharmony_ci    ZMBV_FMT_32BPP = 8
53cabdff1aSopenharmony_ci};
54cabdff1aSopenharmony_ci
55cabdff1aSopenharmony_ci/*
56cabdff1aSopenharmony_ci * Decoder context
57cabdff1aSopenharmony_ci */
58cabdff1aSopenharmony_citypedef struct ZmbvContext {
59cabdff1aSopenharmony_ci    AVCodecContext *avctx;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci    int bpp;
62cabdff1aSopenharmony_ci    int alloc_bpp;
63cabdff1aSopenharmony_ci    unsigned int decomp_size;
64cabdff1aSopenharmony_ci    uint8_t* decomp_buf;
65cabdff1aSopenharmony_ci    uint8_t pal[768];
66cabdff1aSopenharmony_ci    uint8_t *prev, *cur;
67cabdff1aSopenharmony_ci    int width, height;
68cabdff1aSopenharmony_ci    int fmt;
69cabdff1aSopenharmony_ci    int comp;
70cabdff1aSopenharmony_ci    int flags;
71cabdff1aSopenharmony_ci    int stride;
72cabdff1aSopenharmony_ci    int bw, bh, bx, by;
73cabdff1aSopenharmony_ci    int decomp_len;
74cabdff1aSopenharmony_ci    int got_keyframe;
75cabdff1aSopenharmony_ci    FFZStream zstream;
76cabdff1aSopenharmony_ci    int (*decode_xor)(struct ZmbvContext *c);
77cabdff1aSopenharmony_ci} ZmbvContext;
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_ci/**
80cabdff1aSopenharmony_ci * Decode XOR'ed frame - 8bpp version
81cabdff1aSopenharmony_ci */
82cabdff1aSopenharmony_ci
83cabdff1aSopenharmony_cistatic int zmbv_decode_xor_8(ZmbvContext *c)
84cabdff1aSopenharmony_ci{
85cabdff1aSopenharmony_ci    uint8_t *src = c->decomp_buf;
86cabdff1aSopenharmony_ci    uint8_t *output, *prev;
87cabdff1aSopenharmony_ci    int8_t *mvec;
88cabdff1aSopenharmony_ci    int x, y;
89cabdff1aSopenharmony_ci    int d, dx, dy, bw2, bh2;
90cabdff1aSopenharmony_ci    int block;
91cabdff1aSopenharmony_ci    int i, j;
92cabdff1aSopenharmony_ci    int mx, my;
93cabdff1aSopenharmony_ci
94cabdff1aSopenharmony_ci    output = c->cur;
95cabdff1aSopenharmony_ci    prev = c->prev;
96cabdff1aSopenharmony_ci
97cabdff1aSopenharmony_ci    if (c->flags & ZMBV_DELTAPAL) {
98cabdff1aSopenharmony_ci        for (i = 0; i < 768; i++)
99cabdff1aSopenharmony_ci            c->pal[i] ^= *src++;
100cabdff1aSopenharmony_ci    }
101cabdff1aSopenharmony_ci
102cabdff1aSopenharmony_ci    mvec = (int8_t*)src;
103cabdff1aSopenharmony_ci    src += ((c->bx * c->by * 2 + 3) & ~3);
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci    block = 0;
106cabdff1aSopenharmony_ci    for (y = 0; y < c->height; y += c->bh) {
107cabdff1aSopenharmony_ci        bh2 = ((c->height - y) > c->bh) ? c->bh : (c->height - y);
108cabdff1aSopenharmony_ci        for (x = 0; x < c->width; x += c->bw) {
109cabdff1aSopenharmony_ci            uint8_t *out, *tprev;
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci            d = mvec[block] & 1;
112cabdff1aSopenharmony_ci            dx = mvec[block] >> 1;
113cabdff1aSopenharmony_ci            dy = mvec[block + 1] >> 1;
114cabdff1aSopenharmony_ci            block += 2;
115cabdff1aSopenharmony_ci
116cabdff1aSopenharmony_ci            bw2 = ((c->width - x) > c->bw) ? c->bw : (c->width - x);
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci            /* copy block - motion vectors out of bounds are used to zero blocks */
119cabdff1aSopenharmony_ci            out = output + x;
120cabdff1aSopenharmony_ci            tprev = prev + x + dx + dy * c->width;
121cabdff1aSopenharmony_ci            mx = x + dx;
122cabdff1aSopenharmony_ci            my = y + dy;
123cabdff1aSopenharmony_ci            for (j = 0; j < bh2; j++) {
124cabdff1aSopenharmony_ci                if (my + j < 0 || my + j >= c->height) {
125cabdff1aSopenharmony_ci                    memset(out, 0, bw2);
126cabdff1aSopenharmony_ci                } else if (mx >= 0 && mx + bw2 <= c->width){
127cabdff1aSopenharmony_ci                    memcpy(out, tprev, sizeof(*out) * bw2);
128cabdff1aSopenharmony_ci                } else {
129cabdff1aSopenharmony_ci                    for (i = 0; i < bw2; i++) {
130cabdff1aSopenharmony_ci                        if (mx + i < 0 || mx + i >= c->width)
131cabdff1aSopenharmony_ci                            out[i] = 0;
132cabdff1aSopenharmony_ci                        else
133cabdff1aSopenharmony_ci                            out[i] = tprev[i];
134cabdff1aSopenharmony_ci                    }
135cabdff1aSopenharmony_ci                }
136cabdff1aSopenharmony_ci                out += c->width;
137cabdff1aSopenharmony_ci                tprev += c->width;
138cabdff1aSopenharmony_ci            }
139cabdff1aSopenharmony_ci
140cabdff1aSopenharmony_ci            if (d) { /* apply XOR'ed difference */
141cabdff1aSopenharmony_ci                out = output + x;
142cabdff1aSopenharmony_ci                for (j = 0; j < bh2; j++) {
143cabdff1aSopenharmony_ci                    for (i = 0; i < bw2; i++)
144cabdff1aSopenharmony_ci                        out[i] ^= *src++;
145cabdff1aSopenharmony_ci                    out += c->width;
146cabdff1aSopenharmony_ci                }
147cabdff1aSopenharmony_ci            }
148cabdff1aSopenharmony_ci        }
149cabdff1aSopenharmony_ci        output += c->width * c->bh;
150cabdff1aSopenharmony_ci        prev += c->width * c->bh;
151cabdff1aSopenharmony_ci    }
152cabdff1aSopenharmony_ci    if (src - c->decomp_buf != c->decomp_len)
153cabdff1aSopenharmony_ci        av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n",
154cabdff1aSopenharmony_ci               src-c->decomp_buf, c->decomp_len);
155cabdff1aSopenharmony_ci    return 0;
156cabdff1aSopenharmony_ci}
157cabdff1aSopenharmony_ci
158cabdff1aSopenharmony_ci/**
159cabdff1aSopenharmony_ci * Decode XOR'ed frame - 15bpp and 16bpp version
160cabdff1aSopenharmony_ci */
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_cistatic int zmbv_decode_xor_16(ZmbvContext *c)
163cabdff1aSopenharmony_ci{
164cabdff1aSopenharmony_ci    uint8_t *src = c->decomp_buf;
165cabdff1aSopenharmony_ci    uint16_t *output, *prev;
166cabdff1aSopenharmony_ci    int8_t *mvec;
167cabdff1aSopenharmony_ci    int x, y;
168cabdff1aSopenharmony_ci    int d, dx, dy, bw2, bh2;
169cabdff1aSopenharmony_ci    int block;
170cabdff1aSopenharmony_ci    int i, j;
171cabdff1aSopenharmony_ci    int mx, my;
172cabdff1aSopenharmony_ci
173cabdff1aSopenharmony_ci    output = (uint16_t*)c->cur;
174cabdff1aSopenharmony_ci    prev = (uint16_t*)c->prev;
175cabdff1aSopenharmony_ci
176cabdff1aSopenharmony_ci    mvec = (int8_t*)src;
177cabdff1aSopenharmony_ci    src += ((c->bx * c->by * 2 + 3) & ~3);
178cabdff1aSopenharmony_ci
179cabdff1aSopenharmony_ci    block = 0;
180cabdff1aSopenharmony_ci    for (y = 0; y < c->height; y += c->bh) {
181cabdff1aSopenharmony_ci        bh2 = ((c->height - y) > c->bh) ? c->bh : (c->height - y);
182cabdff1aSopenharmony_ci        for (x = 0; x < c->width; x += c->bw) {
183cabdff1aSopenharmony_ci            uint16_t *out, *tprev;
184cabdff1aSopenharmony_ci
185cabdff1aSopenharmony_ci            d = mvec[block] & 1;
186cabdff1aSopenharmony_ci            dx = mvec[block] >> 1;
187cabdff1aSopenharmony_ci            dy = mvec[block + 1] >> 1;
188cabdff1aSopenharmony_ci            block += 2;
189cabdff1aSopenharmony_ci
190cabdff1aSopenharmony_ci            bw2 = ((c->width - x) > c->bw) ? c->bw : (c->width - x);
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_ci            /* copy block - motion vectors out of bounds are used to zero blocks */
193cabdff1aSopenharmony_ci            out = output + x;
194cabdff1aSopenharmony_ci            tprev = prev + x + dx + dy * c->width;
195cabdff1aSopenharmony_ci            mx = x + dx;
196cabdff1aSopenharmony_ci            my = y + dy;
197cabdff1aSopenharmony_ci            for (j = 0; j < bh2; j++) {
198cabdff1aSopenharmony_ci                if (my + j < 0 || my + j >= c->height) {
199cabdff1aSopenharmony_ci                    memset(out, 0, bw2 * 2);
200cabdff1aSopenharmony_ci                } else if (mx >= 0 && mx + bw2 <= c->width){
201cabdff1aSopenharmony_ci                    memcpy(out, tprev, sizeof(*out) * bw2);
202cabdff1aSopenharmony_ci                } else {
203cabdff1aSopenharmony_ci                    for (i = 0; i < bw2; i++) {
204cabdff1aSopenharmony_ci                        if (mx + i < 0 || mx + i >= c->width)
205cabdff1aSopenharmony_ci                            out[i] = 0;
206cabdff1aSopenharmony_ci                        else
207cabdff1aSopenharmony_ci                            out[i] = tprev[i];
208cabdff1aSopenharmony_ci                    }
209cabdff1aSopenharmony_ci                }
210cabdff1aSopenharmony_ci                out += c->width;
211cabdff1aSopenharmony_ci                tprev += c->width;
212cabdff1aSopenharmony_ci            }
213cabdff1aSopenharmony_ci
214cabdff1aSopenharmony_ci            if (d) { /* apply XOR'ed difference */
215cabdff1aSopenharmony_ci                out = output + x;
216cabdff1aSopenharmony_ci                for (j = 0; j < bh2; j++){
217cabdff1aSopenharmony_ci                    for (i = 0; i < bw2; i++) {
218cabdff1aSopenharmony_ci                        out[i] ^= *((uint16_t*)src);
219cabdff1aSopenharmony_ci                        src += 2;
220cabdff1aSopenharmony_ci                    }
221cabdff1aSopenharmony_ci                    out += c->width;
222cabdff1aSopenharmony_ci                }
223cabdff1aSopenharmony_ci            }
224cabdff1aSopenharmony_ci        }
225cabdff1aSopenharmony_ci        output += c->width * c->bh;
226cabdff1aSopenharmony_ci        prev += c->width * c->bh;
227cabdff1aSopenharmony_ci    }
228cabdff1aSopenharmony_ci    if (src - c->decomp_buf != c->decomp_len)
229cabdff1aSopenharmony_ci        av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n",
230cabdff1aSopenharmony_ci               src-c->decomp_buf, c->decomp_len);
231cabdff1aSopenharmony_ci    return 0;
232cabdff1aSopenharmony_ci}
233cabdff1aSopenharmony_ci
234cabdff1aSopenharmony_ci#ifdef ZMBV_ENABLE_24BPP
235cabdff1aSopenharmony_ci/**
236cabdff1aSopenharmony_ci * Decode XOR'ed frame - 24bpp version
237cabdff1aSopenharmony_ci */
238cabdff1aSopenharmony_ci
239cabdff1aSopenharmony_cistatic int zmbv_decode_xor_24(ZmbvContext *c)
240cabdff1aSopenharmony_ci{
241cabdff1aSopenharmony_ci    uint8_t *src = c->decomp_buf;
242cabdff1aSopenharmony_ci    uint8_t *output, *prev;
243cabdff1aSopenharmony_ci    int8_t *mvec;
244cabdff1aSopenharmony_ci    int x, y;
245cabdff1aSopenharmony_ci    int d, dx, dy, bw2, bh2;
246cabdff1aSopenharmony_ci    int block;
247cabdff1aSopenharmony_ci    int i, j;
248cabdff1aSopenharmony_ci    int mx, my;
249cabdff1aSopenharmony_ci    int stride;
250cabdff1aSopenharmony_ci
251cabdff1aSopenharmony_ci    output = c->cur;
252cabdff1aSopenharmony_ci    prev = c->prev;
253cabdff1aSopenharmony_ci
254cabdff1aSopenharmony_ci    stride = c->width * 3;
255cabdff1aSopenharmony_ci    mvec = (int8_t*)src;
256cabdff1aSopenharmony_ci    src += ((c->bx * c->by * 2 + 3) & ~3);
257cabdff1aSopenharmony_ci
258cabdff1aSopenharmony_ci    block = 0;
259cabdff1aSopenharmony_ci    for (y = 0; y < c->height; y += c->bh) {
260cabdff1aSopenharmony_ci        bh2 = ((c->height - y) > c->bh) ? c->bh : (c->height - y);
261cabdff1aSopenharmony_ci        for (x = 0; x < c->width; x += c->bw) {
262cabdff1aSopenharmony_ci            uint8_t *out, *tprev;
263cabdff1aSopenharmony_ci
264cabdff1aSopenharmony_ci            d = mvec[block] & 1;
265cabdff1aSopenharmony_ci            dx = mvec[block] >> 1;
266cabdff1aSopenharmony_ci            dy = mvec[block + 1] >> 1;
267cabdff1aSopenharmony_ci            block += 2;
268cabdff1aSopenharmony_ci
269cabdff1aSopenharmony_ci            bw2 = ((c->width - x) > c->bw) ? c->bw : (c->width - x);
270cabdff1aSopenharmony_ci
271cabdff1aSopenharmony_ci            /* copy block - motion vectors out of bounds are used to zero blocks */
272cabdff1aSopenharmony_ci            out = output + x * 3;
273cabdff1aSopenharmony_ci            tprev = prev + (x + dx) * 3 + dy * stride;
274cabdff1aSopenharmony_ci            mx = x + dx;
275cabdff1aSopenharmony_ci            my = y + dy;
276cabdff1aSopenharmony_ci            for (j = 0; j < bh2; j++) {
277cabdff1aSopenharmony_ci                if (my + j < 0 || my + j >= c->height) {
278cabdff1aSopenharmony_ci                    memset(out, 0, bw2 * 3);
279cabdff1aSopenharmony_ci                } else if (mx >= 0 && mx + bw2 <= c->width){
280cabdff1aSopenharmony_ci                    memcpy(out, tprev, 3 * bw2);
281cabdff1aSopenharmony_ci                } else {
282cabdff1aSopenharmony_ci                    for (i = 0; i < bw2; i++){
283cabdff1aSopenharmony_ci                        if (mx + i < 0 || mx + i >= c->width) {
284cabdff1aSopenharmony_ci                            out[i * 3 + 0] = 0;
285cabdff1aSopenharmony_ci                            out[i * 3 + 1] = 0;
286cabdff1aSopenharmony_ci                            out[i * 3 + 2] = 0;
287cabdff1aSopenharmony_ci                        } else {
288cabdff1aSopenharmony_ci                            out[i * 3 + 0] = tprev[i * 3 + 0];
289cabdff1aSopenharmony_ci                            out[i * 3 + 1] = tprev[i * 3 + 1];
290cabdff1aSopenharmony_ci                            out[i * 3 + 2] = tprev[i * 3 + 2];
291cabdff1aSopenharmony_ci                        }
292cabdff1aSopenharmony_ci                    }
293cabdff1aSopenharmony_ci                }
294cabdff1aSopenharmony_ci                out += stride;
295cabdff1aSopenharmony_ci                tprev += stride;
296cabdff1aSopenharmony_ci            }
297cabdff1aSopenharmony_ci
298cabdff1aSopenharmony_ci            if (d) { /* apply XOR'ed difference */
299cabdff1aSopenharmony_ci                out = output + x * 3;
300cabdff1aSopenharmony_ci                for (j = 0; j < bh2; j++) {
301cabdff1aSopenharmony_ci                    for (i = 0; i < bw2; i++) {
302cabdff1aSopenharmony_ci                        out[i * 3 + 0] ^= *src++;
303cabdff1aSopenharmony_ci                        out[i * 3 + 1] ^= *src++;
304cabdff1aSopenharmony_ci                        out[i * 3 + 2] ^= *src++;
305cabdff1aSopenharmony_ci                    }
306cabdff1aSopenharmony_ci                    out += stride;
307cabdff1aSopenharmony_ci                }
308cabdff1aSopenharmony_ci            }
309cabdff1aSopenharmony_ci        }
310cabdff1aSopenharmony_ci        output += stride * c->bh;
311cabdff1aSopenharmony_ci        prev += stride * c->bh;
312cabdff1aSopenharmony_ci    }
313cabdff1aSopenharmony_ci    if (src - c->decomp_buf != c->decomp_len)
314cabdff1aSopenharmony_ci        av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n",
315cabdff1aSopenharmony_ci               src-c->decomp_buf, c->decomp_len);
316cabdff1aSopenharmony_ci    return 0;
317cabdff1aSopenharmony_ci}
318cabdff1aSopenharmony_ci#endif //ZMBV_ENABLE_24BPP
319cabdff1aSopenharmony_ci
320cabdff1aSopenharmony_ci/**
321cabdff1aSopenharmony_ci * Decode XOR'ed frame - 32bpp version
322cabdff1aSopenharmony_ci */
323cabdff1aSopenharmony_ci
324cabdff1aSopenharmony_cistatic int zmbv_decode_xor_32(ZmbvContext *c)
325cabdff1aSopenharmony_ci{
326cabdff1aSopenharmony_ci    uint8_t *src = c->decomp_buf;
327cabdff1aSopenharmony_ci    uint32_t *output, *prev;
328cabdff1aSopenharmony_ci    int8_t *mvec;
329cabdff1aSopenharmony_ci    int x, y;
330cabdff1aSopenharmony_ci    int d, dx, dy, bw2, bh2;
331cabdff1aSopenharmony_ci    int block;
332cabdff1aSopenharmony_ci    int i, j;
333cabdff1aSopenharmony_ci    int mx, my;
334cabdff1aSopenharmony_ci
335cabdff1aSopenharmony_ci    output = (uint32_t*)c->cur;
336cabdff1aSopenharmony_ci    prev = (uint32_t*)c->prev;
337cabdff1aSopenharmony_ci
338cabdff1aSopenharmony_ci    mvec = (int8_t*)src;
339cabdff1aSopenharmony_ci    src += ((c->bx * c->by * 2 + 3) & ~3);
340cabdff1aSopenharmony_ci
341cabdff1aSopenharmony_ci    block = 0;
342cabdff1aSopenharmony_ci    for (y = 0; y < c->height; y += c->bh) {
343cabdff1aSopenharmony_ci        bh2 = ((c->height - y) > c->bh) ? c->bh : (c->height - y);
344cabdff1aSopenharmony_ci        for (x = 0; x < c->width; x += c->bw) {
345cabdff1aSopenharmony_ci            uint32_t *out, *tprev;
346cabdff1aSopenharmony_ci
347cabdff1aSopenharmony_ci            d = mvec[block] & 1;
348cabdff1aSopenharmony_ci            dx = mvec[block] >> 1;
349cabdff1aSopenharmony_ci            dy = mvec[block + 1] >> 1;
350cabdff1aSopenharmony_ci            block += 2;
351cabdff1aSopenharmony_ci
352cabdff1aSopenharmony_ci            bw2 = ((c->width - x) > c->bw) ? c->bw : (c->width - x);
353cabdff1aSopenharmony_ci
354cabdff1aSopenharmony_ci            /* copy block - motion vectors out of bounds are used to zero blocks */
355cabdff1aSopenharmony_ci            out = output + x;
356cabdff1aSopenharmony_ci            tprev = prev + x + dx + dy * c->width;
357cabdff1aSopenharmony_ci            mx = x + dx;
358cabdff1aSopenharmony_ci            my = y + dy;
359cabdff1aSopenharmony_ci            for (j = 0; j < bh2; j++) {
360cabdff1aSopenharmony_ci                if (my + j < 0 || my + j >= c->height) {
361cabdff1aSopenharmony_ci                    memset(out, 0, bw2 * 4);
362cabdff1aSopenharmony_ci                } else if (mx >= 0 && mx + bw2 <= c->width){
363cabdff1aSopenharmony_ci                    memcpy(out, tprev, sizeof(*out) * bw2);
364cabdff1aSopenharmony_ci                } else {
365cabdff1aSopenharmony_ci                    for (i = 0; i < bw2; i++){
366cabdff1aSopenharmony_ci                        if (mx + i < 0 || mx + i >= c->width)
367cabdff1aSopenharmony_ci                            out[i] = 0;
368cabdff1aSopenharmony_ci                        else
369cabdff1aSopenharmony_ci                            out[i] = tprev[i];
370cabdff1aSopenharmony_ci                    }
371cabdff1aSopenharmony_ci                }
372cabdff1aSopenharmony_ci                out += c->width;
373cabdff1aSopenharmony_ci                tprev += c->width;
374cabdff1aSopenharmony_ci            }
375cabdff1aSopenharmony_ci
376cabdff1aSopenharmony_ci            if (d) { /* apply XOR'ed difference */
377cabdff1aSopenharmony_ci                out = output + x;
378cabdff1aSopenharmony_ci                for (j = 0; j < bh2; j++){
379cabdff1aSopenharmony_ci                    for (i = 0; i < bw2; i++) {
380cabdff1aSopenharmony_ci                        out[i] ^= *((uint32_t *) src);
381cabdff1aSopenharmony_ci                        src += 4;
382cabdff1aSopenharmony_ci                    }
383cabdff1aSopenharmony_ci                    out += c->width;
384cabdff1aSopenharmony_ci                }
385cabdff1aSopenharmony_ci            }
386cabdff1aSopenharmony_ci        }
387cabdff1aSopenharmony_ci        output += c->width * c->bh;
388cabdff1aSopenharmony_ci        prev   += c->width * c->bh;
389cabdff1aSopenharmony_ci    }
390cabdff1aSopenharmony_ci    if (src - c->decomp_buf != c->decomp_len)
391cabdff1aSopenharmony_ci        av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n",
392cabdff1aSopenharmony_ci               src-c->decomp_buf, c->decomp_len);
393cabdff1aSopenharmony_ci    return 0;
394cabdff1aSopenharmony_ci}
395cabdff1aSopenharmony_ci
396cabdff1aSopenharmony_ci/**
397cabdff1aSopenharmony_ci * Decode intraframe
398cabdff1aSopenharmony_ci */
399cabdff1aSopenharmony_cistatic int zmbv_decode_intra(ZmbvContext *c)
400cabdff1aSopenharmony_ci{
401cabdff1aSopenharmony_ci    uint8_t *src = c->decomp_buf;
402cabdff1aSopenharmony_ci
403cabdff1aSopenharmony_ci    /* make the palette available on the way out */
404cabdff1aSopenharmony_ci    if (c->fmt == ZMBV_FMT_8BPP) {
405cabdff1aSopenharmony_ci        memcpy(c->pal, src, 768);
406cabdff1aSopenharmony_ci        src += 768;
407cabdff1aSopenharmony_ci    }
408cabdff1aSopenharmony_ci
409cabdff1aSopenharmony_ci    memcpy(c->cur, src, c->width * c->height * (c->bpp / 8));
410cabdff1aSopenharmony_ci    return 0;
411cabdff1aSopenharmony_ci}
412cabdff1aSopenharmony_ci
413cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *frame,
414cabdff1aSopenharmony_ci                        int *got_frame, AVPacket *avpkt)
415cabdff1aSopenharmony_ci{
416cabdff1aSopenharmony_ci    const uint8_t *buf = avpkt->data;
417cabdff1aSopenharmony_ci    int buf_size = avpkt->size;
418cabdff1aSopenharmony_ci    ZmbvContext * const c = avctx->priv_data;
419cabdff1aSopenharmony_ci    int zret = Z_OK; // Zlib return code
420cabdff1aSopenharmony_ci    int len = buf_size;
421cabdff1aSopenharmony_ci    int hi_ver, lo_ver, ret;
422cabdff1aSopenharmony_ci    int expected_size;
423cabdff1aSopenharmony_ci
424cabdff1aSopenharmony_ci    /* parse header */
425cabdff1aSopenharmony_ci    if (len < 1)
426cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
427cabdff1aSopenharmony_ci    c->flags = buf[0];
428cabdff1aSopenharmony_ci    buf++; len--;
429cabdff1aSopenharmony_ci    if (c->flags & ZMBV_KEYFRAME) {
430cabdff1aSopenharmony_ci        c->got_keyframe = 0;
431cabdff1aSopenharmony_ci
432cabdff1aSopenharmony_ci        if (len < 6)
433cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
434cabdff1aSopenharmony_ci        hi_ver = buf[0];
435cabdff1aSopenharmony_ci        lo_ver = buf[1];
436cabdff1aSopenharmony_ci        c->comp = buf[2];
437cabdff1aSopenharmony_ci        c->fmt = buf[3];
438cabdff1aSopenharmony_ci        c->bw = buf[4];
439cabdff1aSopenharmony_ci        c->bh = buf[5];
440cabdff1aSopenharmony_ci        c->decode_xor = NULL;
441cabdff1aSopenharmony_ci
442cabdff1aSopenharmony_ci        buf += 6;
443cabdff1aSopenharmony_ci        len -= 6;
444cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG,
445cabdff1aSopenharmony_ci               "Flags=%X ver=%i.%i comp=%i fmt=%i blk=%ix%i\n",
446cabdff1aSopenharmony_ci               c->flags,hi_ver,lo_ver,c->comp,c->fmt,c->bw,c->bh);
447cabdff1aSopenharmony_ci        if (hi_ver != 0 || lo_ver != 1) {
448cabdff1aSopenharmony_ci            avpriv_request_sample(avctx, "Version %i.%i", hi_ver, lo_ver);
449cabdff1aSopenharmony_ci            return AVERROR_PATCHWELCOME;
450cabdff1aSopenharmony_ci        }
451cabdff1aSopenharmony_ci        if (c->bw == 0 || c->bh == 0) {
452cabdff1aSopenharmony_ci            avpriv_request_sample(avctx, "Block size %ix%i", c->bw, c->bh);
453cabdff1aSopenharmony_ci            return AVERROR_PATCHWELCOME;
454cabdff1aSopenharmony_ci        }
455cabdff1aSopenharmony_ci        if (c->comp != 0 && c->comp != 1) {
456cabdff1aSopenharmony_ci            avpriv_request_sample(avctx, "Compression type %i", c->comp);
457cabdff1aSopenharmony_ci            return AVERROR_PATCHWELCOME;
458cabdff1aSopenharmony_ci        }
459cabdff1aSopenharmony_ci
460cabdff1aSopenharmony_ci        switch (c->fmt) {
461cabdff1aSopenharmony_ci        case ZMBV_FMT_8BPP:
462cabdff1aSopenharmony_ci            c->bpp = 8;
463cabdff1aSopenharmony_ci            c->decode_xor = zmbv_decode_xor_8;
464cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_PAL8;
465cabdff1aSopenharmony_ci            c->stride = c->width;
466cabdff1aSopenharmony_ci            break;
467cabdff1aSopenharmony_ci        case ZMBV_FMT_15BPP:
468cabdff1aSopenharmony_ci        case ZMBV_FMT_16BPP:
469cabdff1aSopenharmony_ci            c->bpp = 16;
470cabdff1aSopenharmony_ci            c->decode_xor = zmbv_decode_xor_16;
471cabdff1aSopenharmony_ci            if (c->fmt == ZMBV_FMT_15BPP)
472cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
473cabdff1aSopenharmony_ci            else
474cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_RGB565LE;
475cabdff1aSopenharmony_ci            c->stride = c->width * 2;
476cabdff1aSopenharmony_ci            break;
477cabdff1aSopenharmony_ci#ifdef ZMBV_ENABLE_24BPP
478cabdff1aSopenharmony_ci        case ZMBV_FMT_24BPP:
479cabdff1aSopenharmony_ci            c->bpp = 24;
480cabdff1aSopenharmony_ci            c->decode_xor = zmbv_decode_xor_24;
481cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_BGR24;
482cabdff1aSopenharmony_ci            c->stride = c->width * 3;
483cabdff1aSopenharmony_ci            break;
484cabdff1aSopenharmony_ci#endif //ZMBV_ENABLE_24BPP
485cabdff1aSopenharmony_ci        case ZMBV_FMT_32BPP:
486cabdff1aSopenharmony_ci            c->bpp = 32;
487cabdff1aSopenharmony_ci            c->decode_xor = zmbv_decode_xor_32;
488cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_BGR0;
489cabdff1aSopenharmony_ci            c->stride = c->width * 4;
490cabdff1aSopenharmony_ci            break;
491cabdff1aSopenharmony_ci        default:
492cabdff1aSopenharmony_ci            c->decode_xor = NULL;
493cabdff1aSopenharmony_ci            avpriv_request_sample(avctx, "Format %i", c->fmt);
494cabdff1aSopenharmony_ci            return AVERROR_PATCHWELCOME;
495cabdff1aSopenharmony_ci        }
496cabdff1aSopenharmony_ci
497cabdff1aSopenharmony_ci        zret = inflateReset(&c->zstream.zstream);
498cabdff1aSopenharmony_ci        if (zret != Z_OK) {
499cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret);
500cabdff1aSopenharmony_ci            return AVERROR_UNKNOWN;
501cabdff1aSopenharmony_ci        }
502cabdff1aSopenharmony_ci
503cabdff1aSopenharmony_ci        if (c->alloc_bpp < c->bpp) {
504cabdff1aSopenharmony_ci            c->cur  = av_realloc_f(c->cur, avctx->width * avctx->height,  (c->bpp / 8));
505cabdff1aSopenharmony_ci            c->prev = av_realloc_f(c->prev, avctx->width * avctx->height,  (c->bpp / 8));
506cabdff1aSopenharmony_ci            c->alloc_bpp = c->bpp;
507cabdff1aSopenharmony_ci        }
508cabdff1aSopenharmony_ci        c->bx = (c->width + c->bw - 1) / c->bw;
509cabdff1aSopenharmony_ci        c->by = (c->height+ c->bh - 1) / c->bh;
510cabdff1aSopenharmony_ci        if (!c->cur || !c->prev) {
511cabdff1aSopenharmony_ci            c->alloc_bpp = 0;
512cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
513cabdff1aSopenharmony_ci        }
514cabdff1aSopenharmony_ci        memset(c->cur, 0, avctx->width * avctx->height * (c->bpp / 8));
515cabdff1aSopenharmony_ci        memset(c->prev, 0, avctx->width * avctx->height * (c->bpp / 8));
516cabdff1aSopenharmony_ci        c->got_keyframe = 1;
517cabdff1aSopenharmony_ci    }
518cabdff1aSopenharmony_ci    if (c->flags & ZMBV_KEYFRAME) {
519cabdff1aSopenharmony_ci        expected_size = avctx->width * avctx->height * (c->bpp / 8);
520cabdff1aSopenharmony_ci    } else {
521cabdff1aSopenharmony_ci        expected_size = (c->bx * c->by * 2 + 3) & ~3;
522cabdff1aSopenharmony_ci    }
523cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_PAL8 &&
524cabdff1aSopenharmony_ci        (c->flags & (ZMBV_DELTAPAL | ZMBV_KEYFRAME)))
525cabdff1aSopenharmony_ci        expected_size += 768;
526cabdff1aSopenharmony_ci
527cabdff1aSopenharmony_ci    if (!c->got_keyframe) {
528cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Error! Got no format or no keyframe!\n");
529cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
530cabdff1aSopenharmony_ci    }
531cabdff1aSopenharmony_ci
532cabdff1aSopenharmony_ci    if (c->comp == 0) { // uncompressed data
533cabdff1aSopenharmony_ci        if (c->decomp_size < len) {
534cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Buffer too small\n");
535cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
536cabdff1aSopenharmony_ci        }
537cabdff1aSopenharmony_ci        memcpy(c->decomp_buf, buf, len);
538cabdff1aSopenharmony_ci        c->decomp_len = len;
539cabdff1aSopenharmony_ci    } else { // ZLIB-compressed data
540cabdff1aSopenharmony_ci        z_stream *const zstream = &c->zstream.zstream;
541cabdff1aSopenharmony_ci
542cabdff1aSopenharmony_ci        zstream->total_in  = zstream->total_out = 0;
543cabdff1aSopenharmony_ci        zstream->next_in   = buf;
544cabdff1aSopenharmony_ci        zstream->avail_in  = len;
545cabdff1aSopenharmony_ci        zstream->next_out  = c->decomp_buf;
546cabdff1aSopenharmony_ci        zstream->avail_out = c->decomp_size;
547cabdff1aSopenharmony_ci        zret = inflate(zstream, Z_SYNC_FLUSH);
548cabdff1aSopenharmony_ci        if (zret != Z_OK && zret != Z_STREAM_END) {
549cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "inflate error %d\n", zret);
550cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
551cabdff1aSopenharmony_ci        }
552cabdff1aSopenharmony_ci        c->decomp_len = zstream->total_out;
553cabdff1aSopenharmony_ci    }
554cabdff1aSopenharmony_ci    if (expected_size > c->decomp_len ||
555cabdff1aSopenharmony_ci        (c->flags & ZMBV_KEYFRAME) && expected_size < c->decomp_len) {
556cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "decompressed size %d is incorrect, expected %d\n", c->decomp_len, expected_size);
557cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
558cabdff1aSopenharmony_ci    }
559cabdff1aSopenharmony_ci    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
560cabdff1aSopenharmony_ci        return ret;
561cabdff1aSopenharmony_ci
562cabdff1aSopenharmony_ci    if (c->flags & ZMBV_KEYFRAME) {
563cabdff1aSopenharmony_ci        frame->key_frame = 1;
564cabdff1aSopenharmony_ci        frame->pict_type = AV_PICTURE_TYPE_I;
565cabdff1aSopenharmony_ci        zmbv_decode_intra(c);
566cabdff1aSopenharmony_ci    } else {
567cabdff1aSopenharmony_ci        frame->key_frame = 0;
568cabdff1aSopenharmony_ci        frame->pict_type = AV_PICTURE_TYPE_P;
569cabdff1aSopenharmony_ci        if (c->decomp_len < 2LL * ((c->width + c->bw - 1) / c->bw) * ((c->height + c->bh - 1) / c->bh))
570cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
571cabdff1aSopenharmony_ci        if (c->decomp_len)
572cabdff1aSopenharmony_ci            c->decode_xor(c);
573cabdff1aSopenharmony_ci    }
574cabdff1aSopenharmony_ci
575cabdff1aSopenharmony_ci    /* update frames */
576cabdff1aSopenharmony_ci    {
577cabdff1aSopenharmony_ci        uint8_t *out, *src;
578cabdff1aSopenharmony_ci        int j;
579cabdff1aSopenharmony_ci
580cabdff1aSopenharmony_ci        out = frame->data[0];
581cabdff1aSopenharmony_ci        src = c->cur;
582cabdff1aSopenharmony_ci        switch (c->fmt) {
583cabdff1aSopenharmony_ci        case ZMBV_FMT_8BPP:
584cabdff1aSopenharmony_ci            for (j = 0; j < 256; j++)
585cabdff1aSopenharmony_ci                AV_WN32(&frame->data[1][j * 4], 0xFFU << 24 | AV_RB24(&c->pal[j * 3]));
586cabdff1aSopenharmony_ci        case ZMBV_FMT_15BPP:
587cabdff1aSopenharmony_ci        case ZMBV_FMT_16BPP:
588cabdff1aSopenharmony_ci#ifdef ZMBV_ENABLE_24BPP
589cabdff1aSopenharmony_ci        case ZMBV_FMT_24BPP:
590cabdff1aSopenharmony_ci#endif
591cabdff1aSopenharmony_ci        case ZMBV_FMT_32BPP:
592cabdff1aSopenharmony_ci            av_image_copy_plane(out, frame->linesize[0], src, c->stride,
593cabdff1aSopenharmony_ci                                c->stride, c->height);
594cabdff1aSopenharmony_ci            break;
595cabdff1aSopenharmony_ci        default:
596cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Cannot handle format %i\n", c->fmt);
597cabdff1aSopenharmony_ci        }
598cabdff1aSopenharmony_ci        FFSWAP(uint8_t *, c->cur, c->prev);
599cabdff1aSopenharmony_ci    }
600cabdff1aSopenharmony_ci    *got_frame = 1;
601cabdff1aSopenharmony_ci
602cabdff1aSopenharmony_ci    /* always report that the buffer was completely consumed */
603cabdff1aSopenharmony_ci    return buf_size;
604cabdff1aSopenharmony_ci}
605cabdff1aSopenharmony_ci
606cabdff1aSopenharmony_cistatic av_cold int decode_init(AVCodecContext *avctx)
607cabdff1aSopenharmony_ci{
608cabdff1aSopenharmony_ci    ZmbvContext * const c = avctx->priv_data;
609cabdff1aSopenharmony_ci
610cabdff1aSopenharmony_ci    c->avctx = avctx;
611cabdff1aSopenharmony_ci
612cabdff1aSopenharmony_ci    c->width = avctx->width;
613cabdff1aSopenharmony_ci    c->height = avctx->height;
614cabdff1aSopenharmony_ci
615cabdff1aSopenharmony_ci    c->bpp = avctx->bits_per_coded_sample;
616cabdff1aSopenharmony_ci
617cabdff1aSopenharmony_ci    if ((avctx->width + 255ULL) * (avctx->height + 64ULL) > FFMIN(avctx->max_pixels, INT_MAX / 4) ) {
618cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Internal buffer (decomp_size) larger than max_pixels or too large\n");
619cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
620cabdff1aSopenharmony_ci    }
621cabdff1aSopenharmony_ci
622cabdff1aSopenharmony_ci    c->decomp_size = (avctx->width + 255) * 4 * (avctx->height + 64);
623cabdff1aSopenharmony_ci
624cabdff1aSopenharmony_ci    /* Allocate decompression buffer */
625cabdff1aSopenharmony_ci    c->decomp_buf = av_mallocz(c->decomp_size);
626cabdff1aSopenharmony_ci    if (!c->decomp_buf) {
627cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
628cabdff1aSopenharmony_ci                "Can't allocate decompression buffer.\n");
629cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
630cabdff1aSopenharmony_ci    }
631cabdff1aSopenharmony_ci
632cabdff1aSopenharmony_ci    return ff_inflate_init(&c->zstream, avctx);
633cabdff1aSopenharmony_ci}
634cabdff1aSopenharmony_ci
635cabdff1aSopenharmony_cistatic av_cold int decode_end(AVCodecContext *avctx)
636cabdff1aSopenharmony_ci{
637cabdff1aSopenharmony_ci    ZmbvContext * const c = avctx->priv_data;
638cabdff1aSopenharmony_ci
639cabdff1aSopenharmony_ci    av_freep(&c->decomp_buf);
640cabdff1aSopenharmony_ci
641cabdff1aSopenharmony_ci    av_freep(&c->cur);
642cabdff1aSopenharmony_ci    av_freep(&c->prev);
643cabdff1aSopenharmony_ci    ff_inflate_end(&c->zstream);
644cabdff1aSopenharmony_ci
645cabdff1aSopenharmony_ci    return 0;
646cabdff1aSopenharmony_ci}
647cabdff1aSopenharmony_ci
648cabdff1aSopenharmony_ciconst FFCodec ff_zmbv_decoder = {
649cabdff1aSopenharmony_ci    .p.name         = "zmbv",
650cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Zip Motion Blocks Video"),
651cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
652cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_ZMBV,
653cabdff1aSopenharmony_ci    .priv_data_size = sizeof(ZmbvContext),
654cabdff1aSopenharmony_ci    .init           = decode_init,
655cabdff1aSopenharmony_ci    .close          = decode_end,
656cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(decode_frame),
657cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1,
658cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
659cabdff1aSopenharmony_ci};
660