xref: /third_party/ffmpeg/libavcodec/dxv.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Resolume DXV decoder
3cabdff1aSopenharmony_ci * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
4cabdff1aSopenharmony_ci * Copyright (C) 2018 Paul B Mahol
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16cabdff1aSopenharmony_ci * Lesser General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include <stdint.h>
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci#include "mathops.h"
28cabdff1aSopenharmony_ci#include "avcodec.h"
29cabdff1aSopenharmony_ci#include "bytestream.h"
30cabdff1aSopenharmony_ci#include "codec_internal.h"
31cabdff1aSopenharmony_ci#include "lzf.h"
32cabdff1aSopenharmony_ci#include "texturedsp.h"
33cabdff1aSopenharmony_ci#include "thread.h"
34cabdff1aSopenharmony_ci
35cabdff1aSopenharmony_citypedef struct DXVContext {
36cabdff1aSopenharmony_ci    TextureDSPContext texdsp;
37cabdff1aSopenharmony_ci    GetByteContext gbc;
38cabdff1aSopenharmony_ci
39cabdff1aSopenharmony_ci    uint8_t *tex_data;   // Compressed texture
40cabdff1aSopenharmony_ci    uint8_t *ctex_data;  // Compressed texture
41cabdff1aSopenharmony_ci    int tex_rat;         // Compression ratio
42cabdff1aSopenharmony_ci    int tex_step;        // Distance between blocks
43cabdff1aSopenharmony_ci    int ctex_step;       // Distance between blocks
44cabdff1aSopenharmony_ci    int64_t tex_size;    // Texture size
45cabdff1aSopenharmony_ci    int64_t ctex_size;   // Texture size
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_ci    /* Optimal number of slices for parallel decoding */
48cabdff1aSopenharmony_ci    int slice_count;
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_ci    uint8_t *op_data[4]; // Opcodes
51cabdff1aSopenharmony_ci    int64_t op_size[4];  // Opcodes size
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_ci    int texture_block_w;
54cabdff1aSopenharmony_ci    int texture_block_h;
55cabdff1aSopenharmony_ci
56cabdff1aSopenharmony_ci    int ctexture_block_w;
57cabdff1aSopenharmony_ci    int ctexture_block_h;
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_ci    /* Pointer to the selected decompression function */
60cabdff1aSopenharmony_ci    int (*tex_funct)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block);
61cabdff1aSopenharmony_ci    int (*tex_funct_planar[2])(uint8_t *plane0, ptrdiff_t stride0,
62cabdff1aSopenharmony_ci                               uint8_t *plane1, ptrdiff_t stride1,
63cabdff1aSopenharmony_ci                               const uint8_t *block);
64cabdff1aSopenharmony_ci} DXVContext;
65cabdff1aSopenharmony_ci
66cabdff1aSopenharmony_cistatic void decompress_indices(uint8_t *dst, const uint8_t *src)
67cabdff1aSopenharmony_ci{
68cabdff1aSopenharmony_ci    int block, i;
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_ci    for (block = 0; block < 2; block++) {
71cabdff1aSopenharmony_ci        int tmp = AV_RL24(src);
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ci        /* Unpack 8x3 bit from last 3 byte block */
74cabdff1aSopenharmony_ci        for (i = 0; i < 8; i++)
75cabdff1aSopenharmony_ci            dst[i] = (tmp >> (i * 3)) & 0x7;
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci        src += 3;
78cabdff1aSopenharmony_ci        dst += 8;
79cabdff1aSopenharmony_ci    }
80cabdff1aSopenharmony_ci}
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_cistatic int extract_component(int yo0, int yo1, int code)
83cabdff1aSopenharmony_ci{
84cabdff1aSopenharmony_ci    int yo;
85cabdff1aSopenharmony_ci
86cabdff1aSopenharmony_ci    if (yo0 == yo1) {
87cabdff1aSopenharmony_ci        yo = yo0;
88cabdff1aSopenharmony_ci    } else if (code == 0) {
89cabdff1aSopenharmony_ci        yo = yo0;
90cabdff1aSopenharmony_ci    } else if (code == 1) {
91cabdff1aSopenharmony_ci        yo = yo1;
92cabdff1aSopenharmony_ci    } else {
93cabdff1aSopenharmony_ci        if (yo0 > yo1) {
94cabdff1aSopenharmony_ci            yo = (uint8_t) (((8 - code) * yo0 +
95cabdff1aSopenharmony_ci                             (code - 1) * yo1) / 7);
96cabdff1aSopenharmony_ci        } else {
97cabdff1aSopenharmony_ci            if (code == 6) {
98cabdff1aSopenharmony_ci                yo = 0;
99cabdff1aSopenharmony_ci            } else if (code == 7) {
100cabdff1aSopenharmony_ci                yo = 255;
101cabdff1aSopenharmony_ci            } else {
102cabdff1aSopenharmony_ci                yo = (uint8_t) (((6 - code) * yo0 +
103cabdff1aSopenharmony_ci                                 (code - 1) * yo1) / 5);
104cabdff1aSopenharmony_ci            }
105cabdff1aSopenharmony_ci        }
106cabdff1aSopenharmony_ci    }
107cabdff1aSopenharmony_ci
108cabdff1aSopenharmony_ci    return yo;
109cabdff1aSopenharmony_ci}
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_cistatic int cocg_block(uint8_t *plane0, ptrdiff_t stride0,
112cabdff1aSopenharmony_ci                      uint8_t *plane1, ptrdiff_t stride1,
113cabdff1aSopenharmony_ci                      const uint8_t *block)
114cabdff1aSopenharmony_ci{
115cabdff1aSopenharmony_ci    uint8_t co_indices[16];
116cabdff1aSopenharmony_ci    uint8_t cg_indices[16];
117cabdff1aSopenharmony_ci    uint8_t co0 = *(block);
118cabdff1aSopenharmony_ci    uint8_t co1 = *(block + 1);
119cabdff1aSopenharmony_ci    uint8_t cg0 = *(block + 8);
120cabdff1aSopenharmony_ci    uint8_t cg1 = *(block + 9);
121cabdff1aSopenharmony_ci    int x, y;
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_ci    decompress_indices(co_indices, block + 2);
124cabdff1aSopenharmony_ci    decompress_indices(cg_indices, block + 10);
125cabdff1aSopenharmony_ci
126cabdff1aSopenharmony_ci    for (y = 0; y < 4; y++) {
127cabdff1aSopenharmony_ci        for (x = 0; x < 4; x++) {
128cabdff1aSopenharmony_ci            int co_code = co_indices[x + y * 4];
129cabdff1aSopenharmony_ci            int cg_code = cg_indices[x + y * 4];
130cabdff1aSopenharmony_ci
131cabdff1aSopenharmony_ci            plane0[x] = extract_component(cg0, cg1, cg_code);
132cabdff1aSopenharmony_ci            plane1[x] = extract_component(co0, co1, co_code);
133cabdff1aSopenharmony_ci        }
134cabdff1aSopenharmony_ci        plane0 += stride0;
135cabdff1aSopenharmony_ci        plane1 += stride1;
136cabdff1aSopenharmony_ci    }
137cabdff1aSopenharmony_ci
138cabdff1aSopenharmony_ci    return 16;
139cabdff1aSopenharmony_ci}
140cabdff1aSopenharmony_ci
141cabdff1aSopenharmony_cistatic void yao_subblock(uint8_t *dst, uint8_t *yo_indices,
142cabdff1aSopenharmony_ci                        ptrdiff_t stride, const uint8_t *block)
143cabdff1aSopenharmony_ci{
144cabdff1aSopenharmony_ci    uint8_t yo0 = *(block);
145cabdff1aSopenharmony_ci    uint8_t yo1 = *(block + 1);
146cabdff1aSopenharmony_ci    int x, y;
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    decompress_indices(yo_indices, block + 2);
149cabdff1aSopenharmony_ci
150cabdff1aSopenharmony_ci    for (y = 0; y < 4; y++) {
151cabdff1aSopenharmony_ci        for (x = 0; x < 4; x++) {
152cabdff1aSopenharmony_ci            int yo_code = yo_indices[x + y * 4];
153cabdff1aSopenharmony_ci
154cabdff1aSopenharmony_ci            dst[x] = extract_component(yo0, yo1, yo_code);
155cabdff1aSopenharmony_ci        }
156cabdff1aSopenharmony_ci        dst += stride;
157cabdff1aSopenharmony_ci    }
158cabdff1aSopenharmony_ci}
159cabdff1aSopenharmony_ci
160cabdff1aSopenharmony_cistatic int yo_block(uint8_t *dst, ptrdiff_t stride,
161cabdff1aSopenharmony_ci                    uint8_t *unused0, ptrdiff_t unused1,
162cabdff1aSopenharmony_ci                    const uint8_t *block)
163cabdff1aSopenharmony_ci{
164cabdff1aSopenharmony_ci    uint8_t yo_indices[16];
165cabdff1aSopenharmony_ci
166cabdff1aSopenharmony_ci    yao_subblock(dst,      yo_indices, stride, block);
167cabdff1aSopenharmony_ci    yao_subblock(dst + 4,  yo_indices, stride, block + 8);
168cabdff1aSopenharmony_ci    yao_subblock(dst + 8,  yo_indices, stride, block + 16);
169cabdff1aSopenharmony_ci    yao_subblock(dst + 12, yo_indices, stride, block + 24);
170cabdff1aSopenharmony_ci
171cabdff1aSopenharmony_ci    return 32;
172cabdff1aSopenharmony_ci}
173cabdff1aSopenharmony_ci
174cabdff1aSopenharmony_cistatic int yao_block(uint8_t *plane0, ptrdiff_t stride0,
175cabdff1aSopenharmony_ci                     uint8_t *plane3, ptrdiff_t stride1,
176cabdff1aSopenharmony_ci                     const uint8_t *block)
177cabdff1aSopenharmony_ci{
178cabdff1aSopenharmony_ci    uint8_t yo_indices[16];
179cabdff1aSopenharmony_ci    uint8_t a_indices[16];
180cabdff1aSopenharmony_ci
181cabdff1aSopenharmony_ci    yao_subblock(plane0,      yo_indices, stride0, block);
182cabdff1aSopenharmony_ci    yao_subblock(plane3,      a_indices,  stride1, block + 8);
183cabdff1aSopenharmony_ci    yao_subblock(plane0 + 4,  yo_indices, stride0, block + 16);
184cabdff1aSopenharmony_ci    yao_subblock(plane3 + 4,  a_indices,  stride1, block + 24);
185cabdff1aSopenharmony_ci    yao_subblock(plane0 + 8,  yo_indices, stride0, block + 32);
186cabdff1aSopenharmony_ci    yao_subblock(plane3 + 8,  a_indices,  stride1, block + 40);
187cabdff1aSopenharmony_ci    yao_subblock(plane0 + 12, yo_indices, stride0, block + 48);
188cabdff1aSopenharmony_ci    yao_subblock(plane3 + 12, a_indices,  stride1, block + 56);
189cabdff1aSopenharmony_ci
190cabdff1aSopenharmony_ci    return 64;
191cabdff1aSopenharmony_ci}
192cabdff1aSopenharmony_ci
193cabdff1aSopenharmony_cistatic int decompress_texture_thread(AVCodecContext *avctx, void *arg,
194cabdff1aSopenharmony_ci                                     int slice, int thread_nb)
195cabdff1aSopenharmony_ci{
196cabdff1aSopenharmony_ci    DXVContext *ctx = avctx->priv_data;
197cabdff1aSopenharmony_ci    AVFrame *frame = arg;
198cabdff1aSopenharmony_ci    const uint8_t *d = ctx->tex_data;
199cabdff1aSopenharmony_ci    int w_block = avctx->coded_width / ctx->texture_block_w;
200cabdff1aSopenharmony_ci    int h_block = avctx->coded_height / ctx->texture_block_h;
201cabdff1aSopenharmony_ci    int x, y;
202cabdff1aSopenharmony_ci    int start_slice, end_slice;
203cabdff1aSopenharmony_ci
204cabdff1aSopenharmony_ci    start_slice = h_block * slice / ctx->slice_count;
205cabdff1aSopenharmony_ci    end_slice = h_block * (slice + 1) / ctx->slice_count;
206cabdff1aSopenharmony_ci
207cabdff1aSopenharmony_ci    if (ctx->tex_funct) {
208cabdff1aSopenharmony_ci        for (y = start_slice; y < end_slice; y++) {
209cabdff1aSopenharmony_ci            uint8_t *p = frame->data[0] + y * frame->linesize[0] * ctx->texture_block_h;
210cabdff1aSopenharmony_ci            int off = y * w_block;
211cabdff1aSopenharmony_ci            for (x = 0; x < w_block; x++) {
212cabdff1aSopenharmony_ci                ctx->tex_funct(p + x * 4 * ctx->texture_block_w, frame->linesize[0],
213cabdff1aSopenharmony_ci                               d + (off + x) * ctx->tex_step);
214cabdff1aSopenharmony_ci            }
215cabdff1aSopenharmony_ci        }
216cabdff1aSopenharmony_ci    } else {
217cabdff1aSopenharmony_ci        const uint8_t *c = ctx->ctex_data;
218cabdff1aSopenharmony_ci
219cabdff1aSopenharmony_ci        for (y = start_slice; y < end_slice; y++) {
220cabdff1aSopenharmony_ci            uint8_t *p0 = frame->data[0] + y * frame->linesize[0] * ctx->texture_block_h;
221cabdff1aSopenharmony_ci            uint8_t *p3 = ctx->tex_step != 64 ? NULL : frame->data[3] + y * frame->linesize[3] * ctx->texture_block_h;
222cabdff1aSopenharmony_ci            int off = y * w_block;
223cabdff1aSopenharmony_ci            for (x = 0; x < w_block; x++) {
224cabdff1aSopenharmony_ci                ctx->tex_funct_planar[0](p0 + x * ctx->texture_block_w, frame->linesize[0],
225cabdff1aSopenharmony_ci                                         p3 != NULL ? p3 + x * ctx->texture_block_w : NULL, frame->linesize[3],
226cabdff1aSopenharmony_ci                                         d + (off + x) * ctx->tex_step);
227cabdff1aSopenharmony_ci            }
228cabdff1aSopenharmony_ci        }
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_ci        w_block = (avctx->coded_width / 2) / ctx->ctexture_block_w;
231cabdff1aSopenharmony_ci        h_block = (avctx->coded_height / 2) / ctx->ctexture_block_h;
232cabdff1aSopenharmony_ci        start_slice = h_block * slice / ctx->slice_count;
233cabdff1aSopenharmony_ci        end_slice = h_block * (slice + 1) / ctx->slice_count;
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci        for (y = start_slice; y < end_slice; y++) {
236cabdff1aSopenharmony_ci            uint8_t *p0 = frame->data[1] + y * frame->linesize[1] * ctx->ctexture_block_h;
237cabdff1aSopenharmony_ci            uint8_t *p1 = frame->data[2] + y * frame->linesize[2] * ctx->ctexture_block_h;
238cabdff1aSopenharmony_ci            int off = y * w_block;
239cabdff1aSopenharmony_ci            for (x = 0; x < w_block; x++) {
240cabdff1aSopenharmony_ci                ctx->tex_funct_planar[1](p0 + x * ctx->ctexture_block_w, frame->linesize[1],
241cabdff1aSopenharmony_ci                                         p1 + x * ctx->ctexture_block_w, frame->linesize[2],
242cabdff1aSopenharmony_ci                                         c + (off + x) * ctx->ctex_step);
243cabdff1aSopenharmony_ci            }
244cabdff1aSopenharmony_ci        }
245cabdff1aSopenharmony_ci    }
246cabdff1aSopenharmony_ci
247cabdff1aSopenharmony_ci    return 0;
248cabdff1aSopenharmony_ci}
249cabdff1aSopenharmony_ci
250cabdff1aSopenharmony_ci/* This scheme addresses already decoded elements depending on 2-bit status:
251cabdff1aSopenharmony_ci *   0 -> copy new element
252cabdff1aSopenharmony_ci *   1 -> copy one element from position -x
253cabdff1aSopenharmony_ci *   2 -> copy one element from position -(get_byte() + 2) * x
254cabdff1aSopenharmony_ci *   3 -> copy one element from position -(get_16le() + 0x102) * x
255cabdff1aSopenharmony_ci * x is always 2 for dxt1 and 4 for dxt5. */
256cabdff1aSopenharmony_ci#define CHECKPOINT(x)                                                         \
257cabdff1aSopenharmony_ci    do {                                                                      \
258cabdff1aSopenharmony_ci        if (state == 0) {                                                     \
259cabdff1aSopenharmony_ci            if (bytestream2_get_bytes_left(gbc) < 4)                          \
260cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;                                   \
261cabdff1aSopenharmony_ci            value = bytestream2_get_le32(gbc);                                \
262cabdff1aSopenharmony_ci            state = 16;                                                       \
263cabdff1aSopenharmony_ci        }                                                                     \
264cabdff1aSopenharmony_ci        op = value & 0x3;                                                     \
265cabdff1aSopenharmony_ci        value >>= 2;                                                          \
266cabdff1aSopenharmony_ci        state--;                                                              \
267cabdff1aSopenharmony_ci        switch (op) {                                                         \
268cabdff1aSopenharmony_ci        case 1:                                                               \
269cabdff1aSopenharmony_ci            idx = x;                                                          \
270cabdff1aSopenharmony_ci            break;                                                            \
271cabdff1aSopenharmony_ci        case 2:                                                               \
272cabdff1aSopenharmony_ci            idx = (bytestream2_get_byte(gbc) + 2) * x;                        \
273cabdff1aSopenharmony_ci            if (idx > pos) {                                                  \
274cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "idx %d > %d\n", idx, pos);       \
275cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;                                   \
276cabdff1aSopenharmony_ci            }                                                                 \
277cabdff1aSopenharmony_ci            break;                                                            \
278cabdff1aSopenharmony_ci        case 3:                                                               \
279cabdff1aSopenharmony_ci            idx = (bytestream2_get_le16(gbc) + 0x102) * x;                    \
280cabdff1aSopenharmony_ci            if (idx > pos) {                                                  \
281cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "idx %d > %d\n", idx, pos);       \
282cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;                                   \
283cabdff1aSopenharmony_ci            }                                                                 \
284cabdff1aSopenharmony_ci            break;                                                            \
285cabdff1aSopenharmony_ci        }                                                                     \
286cabdff1aSopenharmony_ci    } while(0)
287cabdff1aSopenharmony_ci
288cabdff1aSopenharmony_cistatic int dxv_decompress_dxt1(AVCodecContext *avctx)
289cabdff1aSopenharmony_ci{
290cabdff1aSopenharmony_ci    DXVContext *ctx = avctx->priv_data;
291cabdff1aSopenharmony_ci    GetByteContext *gbc = &ctx->gbc;
292cabdff1aSopenharmony_ci    uint32_t value, prev, op;
293cabdff1aSopenharmony_ci    int idx = 0, state = 0;
294cabdff1aSopenharmony_ci    int pos = 2;
295cabdff1aSopenharmony_ci
296cabdff1aSopenharmony_ci    /* Copy the first two elements */
297cabdff1aSopenharmony_ci    AV_WL32(ctx->tex_data, bytestream2_get_le32(gbc));
298cabdff1aSopenharmony_ci    AV_WL32(ctx->tex_data + 4, bytestream2_get_le32(gbc));
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_ci    /* Process input until the whole texture has been filled */
301cabdff1aSopenharmony_ci    while (pos + 2 <= ctx->tex_size / 4) {
302cabdff1aSopenharmony_ci        CHECKPOINT(2);
303cabdff1aSopenharmony_ci
304cabdff1aSopenharmony_ci        /* Copy two elements from a previous offset or from the input buffer */
305cabdff1aSopenharmony_ci        if (op) {
306cabdff1aSopenharmony_ci            prev = AV_RL32(ctx->tex_data + 4 * (pos - idx));
307cabdff1aSopenharmony_ci            AV_WL32(ctx->tex_data + 4 * pos, prev);
308cabdff1aSopenharmony_ci            pos++;
309cabdff1aSopenharmony_ci
310cabdff1aSopenharmony_ci            prev = AV_RL32(ctx->tex_data + 4 * (pos - idx));
311cabdff1aSopenharmony_ci            AV_WL32(ctx->tex_data + 4 * pos, prev);
312cabdff1aSopenharmony_ci            pos++;
313cabdff1aSopenharmony_ci        } else {
314cabdff1aSopenharmony_ci            CHECKPOINT(2);
315cabdff1aSopenharmony_ci
316cabdff1aSopenharmony_ci            if (op)
317cabdff1aSopenharmony_ci                prev = AV_RL32(ctx->tex_data + 4 * (pos - idx));
318cabdff1aSopenharmony_ci            else
319cabdff1aSopenharmony_ci                prev = bytestream2_get_le32(gbc);
320cabdff1aSopenharmony_ci            AV_WL32(ctx->tex_data + 4 * pos, prev);
321cabdff1aSopenharmony_ci            pos++;
322cabdff1aSopenharmony_ci
323cabdff1aSopenharmony_ci            CHECKPOINT(2);
324cabdff1aSopenharmony_ci
325cabdff1aSopenharmony_ci            if (op)
326cabdff1aSopenharmony_ci                prev = AV_RL32(ctx->tex_data + 4 * (pos - idx));
327cabdff1aSopenharmony_ci            else
328cabdff1aSopenharmony_ci                prev = bytestream2_get_le32(gbc);
329cabdff1aSopenharmony_ci            AV_WL32(ctx->tex_data + 4 * pos, prev);
330cabdff1aSopenharmony_ci            pos++;
331cabdff1aSopenharmony_ci        }
332cabdff1aSopenharmony_ci    }
333cabdff1aSopenharmony_ci
334cabdff1aSopenharmony_ci    return 0;
335cabdff1aSopenharmony_ci}
336cabdff1aSopenharmony_ci
337cabdff1aSopenharmony_citypedef struct OpcodeTable {
338cabdff1aSopenharmony_ci    int16_t next;
339cabdff1aSopenharmony_ci    uint8_t val1;
340cabdff1aSopenharmony_ci    uint8_t val2;
341cabdff1aSopenharmony_ci} OpcodeTable;
342cabdff1aSopenharmony_ci
343cabdff1aSopenharmony_cistatic int fill_ltable(GetByteContext *gb, uint32_t *table, int *nb_elements)
344cabdff1aSopenharmony_ci{
345cabdff1aSopenharmony_ci    unsigned half = 512, bits = 1023, left = 1024, input, mask;
346cabdff1aSopenharmony_ci    int value, counter = 0, rshift = 10, lshift = 30;
347cabdff1aSopenharmony_ci
348cabdff1aSopenharmony_ci    mask = bytestream2_get_le32(gb) >> 2;
349cabdff1aSopenharmony_ci    while (left) {
350cabdff1aSopenharmony_ci        if (counter >= 256)
351cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
352cabdff1aSopenharmony_ci        value = bits & mask;
353cabdff1aSopenharmony_ci        left -= bits & mask;
354cabdff1aSopenharmony_ci        mask >>= rshift;
355cabdff1aSopenharmony_ci        lshift -= rshift;
356cabdff1aSopenharmony_ci        table[counter++] = value;
357cabdff1aSopenharmony_ci        if (lshift < 16) {
358cabdff1aSopenharmony_ci            if (bytestream2_get_bytes_left(gb) <= 0)
359cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
360cabdff1aSopenharmony_ci
361cabdff1aSopenharmony_ci            input = bytestream2_get_le16(gb);
362cabdff1aSopenharmony_ci            mask += input << lshift;
363cabdff1aSopenharmony_ci            lshift += 16;
364cabdff1aSopenharmony_ci        }
365cabdff1aSopenharmony_ci        if (left < half) {
366cabdff1aSopenharmony_ci            half >>= 1;
367cabdff1aSopenharmony_ci            bits >>= 1;
368cabdff1aSopenharmony_ci            rshift--;
369cabdff1aSopenharmony_ci        }
370cabdff1aSopenharmony_ci    }
371cabdff1aSopenharmony_ci
372cabdff1aSopenharmony_ci    for (; !table[counter - 1]; counter--)
373cabdff1aSopenharmony_ci        if (counter <= 0)
374cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
375cabdff1aSopenharmony_ci
376cabdff1aSopenharmony_ci    *nb_elements = counter;
377cabdff1aSopenharmony_ci
378cabdff1aSopenharmony_ci    if (counter < 256)
379cabdff1aSopenharmony_ci        memset(&table[counter], 0, 4 * (256 - counter));
380cabdff1aSopenharmony_ci
381cabdff1aSopenharmony_ci    if (lshift >= 16)
382cabdff1aSopenharmony_ci        bytestream2_seek(gb, -2, SEEK_CUR);
383cabdff1aSopenharmony_ci
384cabdff1aSopenharmony_ci    return 0;
385cabdff1aSopenharmony_ci}
386cabdff1aSopenharmony_ci
387cabdff1aSopenharmony_cistatic int fill_optable(unsigned *table0, OpcodeTable *table1, int nb_elements)
388cabdff1aSopenharmony_ci{
389cabdff1aSopenharmony_ci    unsigned table2[256] = { 0 };
390cabdff1aSopenharmony_ci    unsigned x = 0;
391cabdff1aSopenharmony_ci    int val0, val1, i, j = 2, k = 0;
392cabdff1aSopenharmony_ci
393cabdff1aSopenharmony_ci    table2[0] = table0[0];
394cabdff1aSopenharmony_ci    for (i = 0; i < nb_elements - 1; i++, table2[i] = val0) {
395cabdff1aSopenharmony_ci        val0 = table0[i + 1] + table2[i];
396cabdff1aSopenharmony_ci    }
397cabdff1aSopenharmony_ci
398cabdff1aSopenharmony_ci    if (!table2[0]) {
399cabdff1aSopenharmony_ci        do {
400cabdff1aSopenharmony_ci            k++;
401cabdff1aSopenharmony_ci        } while (!table2[k]);
402cabdff1aSopenharmony_ci    }
403cabdff1aSopenharmony_ci
404cabdff1aSopenharmony_ci    j = 2;
405cabdff1aSopenharmony_ci    for (i = 1024; i > 0; i--) {
406cabdff1aSopenharmony_ci        for (table1[x].val1 = k; k < 256 && j > table2[k]; k++);
407cabdff1aSopenharmony_ci        x = (x - 383) & 0x3FF;
408cabdff1aSopenharmony_ci        j++;
409cabdff1aSopenharmony_ci    }
410cabdff1aSopenharmony_ci
411cabdff1aSopenharmony_ci    if (nb_elements > 0)
412cabdff1aSopenharmony_ci        memcpy(&table2[0], table0, 4 * nb_elements);
413cabdff1aSopenharmony_ci
414cabdff1aSopenharmony_ci    for (i = 0; i < 1024; i++) {
415cabdff1aSopenharmony_ci        val0 = table1[i].val1;
416cabdff1aSopenharmony_ci        val1 = table2[val0];
417cabdff1aSopenharmony_ci        table2[val0]++;
418cabdff1aSopenharmony_ci        x = 31 - ff_clz(val1);
419cabdff1aSopenharmony_ci        if (x > 10)
420cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
421cabdff1aSopenharmony_ci        table1[i].val2 = 10 - x;
422cabdff1aSopenharmony_ci        table1[i].next = (val1 << table1[i].val2) - 1024;
423cabdff1aSopenharmony_ci    }
424cabdff1aSopenharmony_ci
425cabdff1aSopenharmony_ci    return 0;
426cabdff1aSopenharmony_ci}
427cabdff1aSopenharmony_ci
428cabdff1aSopenharmony_cistatic int get_opcodes(GetByteContext *gb, uint32_t *table, uint8_t *dst, int op_size, int nb_elements)
429cabdff1aSopenharmony_ci{
430cabdff1aSopenharmony_ci    OpcodeTable optable[1024];
431cabdff1aSopenharmony_ci    int sum, x, val, lshift, rshift, ret, i, idx;
432cabdff1aSopenharmony_ci    int64_t size_in_bits;
433cabdff1aSopenharmony_ci    unsigned endoffset, newoffset, offset;
434cabdff1aSopenharmony_ci    unsigned next;
435cabdff1aSopenharmony_ci    uint8_t *src = (uint8_t *)gb->buffer;
436cabdff1aSopenharmony_ci
437cabdff1aSopenharmony_ci    ret = fill_optable(table, optable, nb_elements);
438cabdff1aSopenharmony_ci    if (ret < 0)
439cabdff1aSopenharmony_ci        return ret;
440cabdff1aSopenharmony_ci
441cabdff1aSopenharmony_ci    size_in_bits = bytestream2_get_le32(gb);
442cabdff1aSopenharmony_ci    endoffset = ((size_in_bits + 7) >> 3) - 4;
443cabdff1aSopenharmony_ci    if (endoffset <= 0 || bytestream2_get_bytes_left(gb) < endoffset)
444cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
445cabdff1aSopenharmony_ci
446cabdff1aSopenharmony_ci    offset = endoffset;
447cabdff1aSopenharmony_ci    next = AV_RL32(src + endoffset);
448cabdff1aSopenharmony_ci    rshift = (((size_in_bits & 0xFF) - 1) & 7) + 15;
449cabdff1aSopenharmony_ci    lshift = 32 - rshift;
450cabdff1aSopenharmony_ci    idx = (next >> rshift) & 0x3FF;
451cabdff1aSopenharmony_ci    for (i = 0; i < op_size; i++) {
452cabdff1aSopenharmony_ci        dst[i] = optable[idx].val1;
453cabdff1aSopenharmony_ci        val = optable[idx].val2;
454cabdff1aSopenharmony_ci        sum = val + lshift;
455cabdff1aSopenharmony_ci        x = (next << lshift) >> 1 >> (31 - val);
456cabdff1aSopenharmony_ci        newoffset = offset - (sum >> 3);
457cabdff1aSopenharmony_ci        lshift = sum & 7;
458cabdff1aSopenharmony_ci        idx = x + optable[idx].next;
459cabdff1aSopenharmony_ci        offset = newoffset;
460cabdff1aSopenharmony_ci        if (offset > endoffset)
461cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
462cabdff1aSopenharmony_ci        next = AV_RL32(src + offset);
463cabdff1aSopenharmony_ci    }
464cabdff1aSopenharmony_ci
465cabdff1aSopenharmony_ci    bytestream2_skip(gb, (size_in_bits + 7 >> 3) - 4);
466cabdff1aSopenharmony_ci
467cabdff1aSopenharmony_ci    return 0;
468cabdff1aSopenharmony_ci}
469cabdff1aSopenharmony_ci
470cabdff1aSopenharmony_cistatic int dxv_decompress_opcodes(GetByteContext *gb, void *dstp, size_t op_size)
471cabdff1aSopenharmony_ci{
472cabdff1aSopenharmony_ci    int pos = bytestream2_tell(gb);
473cabdff1aSopenharmony_ci    int flag = bytestream2_peek_byte(gb);
474cabdff1aSopenharmony_ci
475cabdff1aSopenharmony_ci    if ((flag & 3) == 0) {
476cabdff1aSopenharmony_ci        bytestream2_skip(gb, 1);
477cabdff1aSopenharmony_ci        bytestream2_get_buffer(gb, dstp, op_size);
478cabdff1aSopenharmony_ci    } else if ((flag & 3) == 1) {
479cabdff1aSopenharmony_ci        bytestream2_skip(gb, 1);
480cabdff1aSopenharmony_ci        memset(dstp, bytestream2_get_byte(gb), op_size);
481cabdff1aSopenharmony_ci    } else {
482cabdff1aSopenharmony_ci        uint32_t table[256];
483cabdff1aSopenharmony_ci        int ret, elements = 0;
484cabdff1aSopenharmony_ci
485cabdff1aSopenharmony_ci        ret = fill_ltable(gb, table, &elements);
486cabdff1aSopenharmony_ci        if (ret < 0)
487cabdff1aSopenharmony_ci            return ret;
488cabdff1aSopenharmony_ci        ret = get_opcodes(gb, table, dstp, op_size, elements);
489cabdff1aSopenharmony_ci        if (ret < 0)
490cabdff1aSopenharmony_ci            return ret;
491cabdff1aSopenharmony_ci    }
492cabdff1aSopenharmony_ci    return bytestream2_tell(gb) - pos;
493cabdff1aSopenharmony_ci}
494cabdff1aSopenharmony_ci
495cabdff1aSopenharmony_cistatic int dxv_decompress_cgo(DXVContext *ctx, GetByteContext *gb,
496cabdff1aSopenharmony_ci                              uint8_t *tex_data, int tex_size,
497cabdff1aSopenharmony_ci                              uint8_t *op_data, int *oindex,
498cabdff1aSopenharmony_ci                              int op_size,
499cabdff1aSopenharmony_ci                              uint8_t **dstp, int *statep,
500cabdff1aSopenharmony_ci                              uint8_t **tab0, uint8_t **tab1,
501cabdff1aSopenharmony_ci                              int offset)
502cabdff1aSopenharmony_ci{
503cabdff1aSopenharmony_ci    uint8_t *dst = *dstp;
504cabdff1aSopenharmony_ci    uint8_t *tptr0, *tptr1, *tptr3;
505cabdff1aSopenharmony_ci    int oi = *oindex;
506cabdff1aSopenharmony_ci    int state = *statep;
507cabdff1aSopenharmony_ci    int opcode, v, vv;
508cabdff1aSopenharmony_ci
509cabdff1aSopenharmony_ci    if (state <= 0) {
510cabdff1aSopenharmony_ci        if (oi >= op_size)
511cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
512cabdff1aSopenharmony_ci        opcode = op_data[oi++];
513cabdff1aSopenharmony_ci        if (!opcode) {
514cabdff1aSopenharmony_ci            v = bytestream2_get_byte(gb);
515cabdff1aSopenharmony_ci            if (v == 255) {
516cabdff1aSopenharmony_ci                do {
517cabdff1aSopenharmony_ci                    if (bytestream2_get_bytes_left(gb) <= 0)
518cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
519cabdff1aSopenharmony_ci                    opcode = bytestream2_get_le16(gb);
520cabdff1aSopenharmony_ci                    v += opcode;
521cabdff1aSopenharmony_ci                } while (opcode == 0xFFFF);
522cabdff1aSopenharmony_ci            }
523cabdff1aSopenharmony_ci            AV_WL32(dst, AV_RL32(dst - (8 + offset)));
524cabdff1aSopenharmony_ci            AV_WL32(dst + 4, AV_RL32(dst - (4 + offset)));
525cabdff1aSopenharmony_ci            state = v + 4;
526cabdff1aSopenharmony_ci            goto done;
527cabdff1aSopenharmony_ci        }
528cabdff1aSopenharmony_ci
529cabdff1aSopenharmony_ci        switch (opcode) {
530cabdff1aSopenharmony_ci        case 1:
531cabdff1aSopenharmony_ci            AV_WL32(dst, AV_RL32(dst - (8 + offset)));
532cabdff1aSopenharmony_ci            AV_WL32(dst + 4, AV_RL32(dst - (4 + offset)));
533cabdff1aSopenharmony_ci            break;
534cabdff1aSopenharmony_ci        case 2:
535cabdff1aSopenharmony_ci            vv = (8 + offset) * (bytestream2_get_le16(gb) + 1);
536cabdff1aSopenharmony_ci            if (vv < 0 || vv > dst - tex_data)
537cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
538cabdff1aSopenharmony_ci            tptr0 = dst - vv;
539cabdff1aSopenharmony_ci            v = AV_RL32(tptr0);
540cabdff1aSopenharmony_ci            AV_WL32(dst, AV_RL32(tptr0));
541cabdff1aSopenharmony_ci            AV_WL32(dst + 4, AV_RL32(tptr0 + 4));
542cabdff1aSopenharmony_ci            tab0[0x9E3779B1 * (uint16_t)v >> 24] = dst;
543cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
544cabdff1aSopenharmony_ci            break;
545cabdff1aSopenharmony_ci        case 3:
546cabdff1aSopenharmony_ci            AV_WL32(dst, bytestream2_get_le32(gb));
547cabdff1aSopenharmony_ci            AV_WL32(dst + 4, bytestream2_get_le32(gb));
548cabdff1aSopenharmony_ci            tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst;
549cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
550cabdff1aSopenharmony_ci            break;
551cabdff1aSopenharmony_ci        case 4:
552cabdff1aSopenharmony_ci            tptr3 = tab1[bytestream2_get_byte(gb)];
553cabdff1aSopenharmony_ci            if (!tptr3)
554cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
555cabdff1aSopenharmony_ci            AV_WL16(dst, bytestream2_get_le16(gb));
556cabdff1aSopenharmony_ci            AV_WL16(dst + 2, AV_RL16(tptr3));
557cabdff1aSopenharmony_ci            dst[4] = tptr3[2];
558cabdff1aSopenharmony_ci            AV_WL16(dst + 5, bytestream2_get_le16(gb));
559cabdff1aSopenharmony_ci            dst[7] = bytestream2_get_byte(gb);
560cabdff1aSopenharmony_ci            tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst;
561cabdff1aSopenharmony_ci            break;
562cabdff1aSopenharmony_ci        case 5:
563cabdff1aSopenharmony_ci            tptr3 = tab1[bytestream2_get_byte(gb)];
564cabdff1aSopenharmony_ci            if (!tptr3)
565cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
566cabdff1aSopenharmony_ci            AV_WL16(dst, bytestream2_get_le16(gb));
567cabdff1aSopenharmony_ci            AV_WL16(dst + 2, bytestream2_get_le16(gb));
568cabdff1aSopenharmony_ci            dst[4] = bytestream2_get_byte(gb);
569cabdff1aSopenharmony_ci            AV_WL16(dst + 5, AV_RL16(tptr3));
570cabdff1aSopenharmony_ci            dst[7] = tptr3[2];
571cabdff1aSopenharmony_ci            tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst;
572cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
573cabdff1aSopenharmony_ci            break;
574cabdff1aSopenharmony_ci        case 6:
575cabdff1aSopenharmony_ci            tptr0 = tab1[bytestream2_get_byte(gb)];
576cabdff1aSopenharmony_ci            if (!tptr0)
577cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
578cabdff1aSopenharmony_ci            tptr1 = tab1[bytestream2_get_byte(gb)];
579cabdff1aSopenharmony_ci            if (!tptr1)
580cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
581cabdff1aSopenharmony_ci            AV_WL16(dst, bytestream2_get_le16(gb));
582cabdff1aSopenharmony_ci            AV_WL16(dst + 2, AV_RL16(tptr0));
583cabdff1aSopenharmony_ci            dst[4] = tptr0[2];
584cabdff1aSopenharmony_ci            AV_WL16(dst + 5, AV_RL16(tptr1));
585cabdff1aSopenharmony_ci            dst[7] = tptr1[2];
586cabdff1aSopenharmony_ci            tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst;
587cabdff1aSopenharmony_ci            break;
588cabdff1aSopenharmony_ci        case 7:
589cabdff1aSopenharmony_ci            v = (8 + offset) * (bytestream2_get_le16(gb) + 1);
590cabdff1aSopenharmony_ci            if (v < 0 || v > dst - tex_data)
591cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
592cabdff1aSopenharmony_ci            tptr0 = dst - v;
593cabdff1aSopenharmony_ci            AV_WL16(dst, bytestream2_get_le16(gb));
594cabdff1aSopenharmony_ci            AV_WL16(dst + 2, AV_RL16(tptr0 + 2));
595cabdff1aSopenharmony_ci            AV_WL32(dst + 4, AV_RL32(tptr0 + 4));
596cabdff1aSopenharmony_ci            tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst;
597cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
598cabdff1aSopenharmony_ci            break;
599cabdff1aSopenharmony_ci        case 8:
600cabdff1aSopenharmony_ci            tptr1 = tab0[bytestream2_get_byte(gb)];
601cabdff1aSopenharmony_ci            if (!tptr1)
602cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
603cabdff1aSopenharmony_ci            AV_WL16(dst, AV_RL16(tptr1));
604cabdff1aSopenharmony_ci            AV_WL16(dst + 2, bytestream2_get_le16(gb));
605cabdff1aSopenharmony_ci            AV_WL32(dst + 4, bytestream2_get_le32(gb));
606cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
607cabdff1aSopenharmony_ci            break;
608cabdff1aSopenharmony_ci        case 9:
609cabdff1aSopenharmony_ci            tptr1 = tab0[bytestream2_get_byte(gb)];
610cabdff1aSopenharmony_ci            if (!tptr1)
611cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
612cabdff1aSopenharmony_ci            tptr3 = tab1[bytestream2_get_byte(gb)];
613cabdff1aSopenharmony_ci            if (!tptr3)
614cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
615cabdff1aSopenharmony_ci            AV_WL16(dst, AV_RL16(tptr1));
616cabdff1aSopenharmony_ci            AV_WL16(dst + 2, AV_RL16(tptr3));
617cabdff1aSopenharmony_ci            dst[4] = tptr3[2];
618cabdff1aSopenharmony_ci            AV_WL16(dst + 5, bytestream2_get_le16(gb));
619cabdff1aSopenharmony_ci            dst[7] = bytestream2_get_byte(gb);
620cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
621cabdff1aSopenharmony_ci            break;
622cabdff1aSopenharmony_ci        case 10:
623cabdff1aSopenharmony_ci            tptr1 = tab0[bytestream2_get_byte(gb)];
624cabdff1aSopenharmony_ci            if (!tptr1)
625cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
626cabdff1aSopenharmony_ci            tptr3 = tab1[bytestream2_get_byte(gb)];
627cabdff1aSopenharmony_ci            if (!tptr3)
628cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
629cabdff1aSopenharmony_ci            AV_WL16(dst, AV_RL16(tptr1));
630cabdff1aSopenharmony_ci            AV_WL16(dst + 2, bytestream2_get_le16(gb));
631cabdff1aSopenharmony_ci            dst[4] = bytestream2_get_byte(gb);
632cabdff1aSopenharmony_ci            AV_WL16(dst + 5, AV_RL16(tptr3));
633cabdff1aSopenharmony_ci            dst[7] = tptr3[2];
634cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
635cabdff1aSopenharmony_ci            break;
636cabdff1aSopenharmony_ci        case 11:
637cabdff1aSopenharmony_ci            tptr0 = tab0[bytestream2_get_byte(gb)];
638cabdff1aSopenharmony_ci            if (!tptr0)
639cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
640cabdff1aSopenharmony_ci            tptr3 = tab1[bytestream2_get_byte(gb)];
641cabdff1aSopenharmony_ci            if (!tptr3)
642cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
643cabdff1aSopenharmony_ci            tptr1 = tab1[bytestream2_get_byte(gb)];
644cabdff1aSopenharmony_ci            if (!tptr1)
645cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
646cabdff1aSopenharmony_ci            AV_WL16(dst, AV_RL16(tptr0));
647cabdff1aSopenharmony_ci            AV_WL16(dst + 2, AV_RL16(tptr3));
648cabdff1aSopenharmony_ci            dst[4] = tptr3[2];
649cabdff1aSopenharmony_ci            AV_WL16(dst + 5, AV_RL16(tptr1));
650cabdff1aSopenharmony_ci            dst[7] = tptr1[2];
651cabdff1aSopenharmony_ci            break;
652cabdff1aSopenharmony_ci        case 12:
653cabdff1aSopenharmony_ci            tptr1 = tab0[bytestream2_get_byte(gb)];
654cabdff1aSopenharmony_ci            if (!tptr1)
655cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
656cabdff1aSopenharmony_ci            v = (8 + offset) * (bytestream2_get_le16(gb) + 1);
657cabdff1aSopenharmony_ci            if (v < 0 || v > dst - tex_data)
658cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
659cabdff1aSopenharmony_ci            tptr0 = dst - v;
660cabdff1aSopenharmony_ci            AV_WL16(dst, AV_RL16(tptr1));
661cabdff1aSopenharmony_ci            AV_WL16(dst + 2, AV_RL16(tptr0 + 2));
662cabdff1aSopenharmony_ci            AV_WL32(dst + 4, AV_RL32(tptr0 + 4));
663cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
664cabdff1aSopenharmony_ci            break;
665cabdff1aSopenharmony_ci        case 13:
666cabdff1aSopenharmony_ci            AV_WL16(dst, AV_RL16(dst - (8 + offset)));
667cabdff1aSopenharmony_ci            AV_WL16(dst + 2, bytestream2_get_le16(gb));
668cabdff1aSopenharmony_ci            AV_WL32(dst + 4, bytestream2_get_le32(gb));
669cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
670cabdff1aSopenharmony_ci            break;
671cabdff1aSopenharmony_ci        case 14:
672cabdff1aSopenharmony_ci            tptr3 = tab1[bytestream2_get_byte(gb)];
673cabdff1aSopenharmony_ci            if (!tptr3)
674cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
675cabdff1aSopenharmony_ci            AV_WL16(dst, AV_RL16(dst - (8 + offset)));
676cabdff1aSopenharmony_ci            AV_WL16(dst + 2, AV_RL16(tptr3));
677cabdff1aSopenharmony_ci            dst[4] = tptr3[2];
678cabdff1aSopenharmony_ci            AV_WL16(dst + 5, bytestream2_get_le16(gb));
679cabdff1aSopenharmony_ci            dst[7] = bytestream2_get_byte(gb);
680cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
681cabdff1aSopenharmony_ci            break;
682cabdff1aSopenharmony_ci        case 15:
683cabdff1aSopenharmony_ci            tptr3 = tab1[bytestream2_get_byte(gb)];
684cabdff1aSopenharmony_ci            if (!tptr3)
685cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
686cabdff1aSopenharmony_ci            AV_WL16(dst, AV_RL16(dst - (8 + offset)));
687cabdff1aSopenharmony_ci            AV_WL16(dst + 2, bytestream2_get_le16(gb));
688cabdff1aSopenharmony_ci            dst[4] = bytestream2_get_byte(gb);
689cabdff1aSopenharmony_ci            AV_WL16(dst + 5, AV_RL16(tptr3));
690cabdff1aSopenharmony_ci            dst[7] = tptr3[2];
691cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
692cabdff1aSopenharmony_ci            break;
693cabdff1aSopenharmony_ci        case 16:
694cabdff1aSopenharmony_ci            tptr3 = tab1[bytestream2_get_byte(gb)];
695cabdff1aSopenharmony_ci            if (!tptr3)
696cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
697cabdff1aSopenharmony_ci            tptr1 = tab1[bytestream2_get_byte(gb)];
698cabdff1aSopenharmony_ci            if (!tptr1)
699cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
700cabdff1aSopenharmony_ci            AV_WL16(dst, AV_RL16(dst - (8 + offset)));
701cabdff1aSopenharmony_ci            AV_WL16(dst + 2, AV_RL16(tptr3));
702cabdff1aSopenharmony_ci            dst[4] = tptr3[2];
703cabdff1aSopenharmony_ci            AV_WL16(dst + 5, AV_RL16(tptr1));
704cabdff1aSopenharmony_ci            dst[7] = tptr1[2];
705cabdff1aSopenharmony_ci            break;
706cabdff1aSopenharmony_ci        case 17:
707cabdff1aSopenharmony_ci            v = (8 + offset) * (bytestream2_get_le16(gb) + 1);
708cabdff1aSopenharmony_ci            if (v < 0 || v > dst - tex_data)
709cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
710cabdff1aSopenharmony_ci            AV_WL16(dst, AV_RL16(dst - (8 + offset)));
711cabdff1aSopenharmony_ci            AV_WL16(dst + 2, AV_RL16(&dst[-v + 2]));
712cabdff1aSopenharmony_ci            AV_WL32(dst + 4, AV_RL32(&dst[-v + 4]));
713cabdff1aSopenharmony_ci            tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2;
714cabdff1aSopenharmony_ci            break;
715cabdff1aSopenharmony_ci        default:
716cabdff1aSopenharmony_ci            break;
717cabdff1aSopenharmony_ci        }
718cabdff1aSopenharmony_ci    } else {
719cabdff1aSopenharmony_cidone:
720cabdff1aSopenharmony_ci        AV_WL32(dst, AV_RL32(dst - (8 + offset)));
721cabdff1aSopenharmony_ci        AV_WL32(dst + 4, AV_RL32(dst - (4 + offset)));
722cabdff1aSopenharmony_ci        state--;
723cabdff1aSopenharmony_ci    }
724cabdff1aSopenharmony_ci    if (dst - tex_data + 8 > tex_size)
725cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
726cabdff1aSopenharmony_ci    dst += 8;
727cabdff1aSopenharmony_ci
728cabdff1aSopenharmony_ci    *oindex = oi;
729cabdff1aSopenharmony_ci    *dstp = dst;
730cabdff1aSopenharmony_ci    *statep = state;
731cabdff1aSopenharmony_ci
732cabdff1aSopenharmony_ci    return 0;
733cabdff1aSopenharmony_ci}
734cabdff1aSopenharmony_ci
735cabdff1aSopenharmony_cistatic int dxv_decompress_cocg(DXVContext *ctx, GetByteContext *gb,
736cabdff1aSopenharmony_ci                               uint8_t *tex_data, int tex_size,
737cabdff1aSopenharmony_ci                               uint8_t *op_data0, uint8_t *op_data1,
738cabdff1aSopenharmony_ci                               int max_op_size0, int max_op_size1)
739cabdff1aSopenharmony_ci{
740cabdff1aSopenharmony_ci    uint8_t *dst, *tab2[256] = { 0 }, *tab0[256] = { 0 }, *tab3[256] = { 0 }, *tab1[256] = { 0 };
741cabdff1aSopenharmony_ci    int op_offset = bytestream2_get_le32(gb);
742cabdff1aSopenharmony_ci    unsigned op_size0 = bytestream2_get_le32(gb);
743cabdff1aSopenharmony_ci    unsigned op_size1 = bytestream2_get_le32(gb);
744cabdff1aSopenharmony_ci    int data_start = bytestream2_tell(gb);
745cabdff1aSopenharmony_ci    int skip0, skip1, oi0 = 0, oi1 = 0;
746cabdff1aSopenharmony_ci    int ret, state0 = 0, state1 = 0;
747cabdff1aSopenharmony_ci
748cabdff1aSopenharmony_ci    if (op_offset < 12 || op_offset - 12 > bytestream2_get_bytes_left(gb))
749cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
750cabdff1aSopenharmony_ci
751cabdff1aSopenharmony_ci    dst = tex_data;
752cabdff1aSopenharmony_ci    bytestream2_skip(gb, op_offset - 12);
753cabdff1aSopenharmony_ci    if (op_size0 > max_op_size0)
754cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
755cabdff1aSopenharmony_ci    skip0 = dxv_decompress_opcodes(gb, op_data0, op_size0);
756cabdff1aSopenharmony_ci    if (skip0 < 0)
757cabdff1aSopenharmony_ci        return skip0;
758cabdff1aSopenharmony_ci    if (op_size1 > max_op_size1)
759cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
760cabdff1aSopenharmony_ci    skip1 = dxv_decompress_opcodes(gb, op_data1, op_size1);
761cabdff1aSopenharmony_ci    if (skip1 < 0)
762cabdff1aSopenharmony_ci        return skip1;
763cabdff1aSopenharmony_ci    bytestream2_seek(gb, data_start, SEEK_SET);
764cabdff1aSopenharmony_ci
765cabdff1aSopenharmony_ci    AV_WL32(dst, bytestream2_get_le32(gb));
766cabdff1aSopenharmony_ci    AV_WL32(dst + 4, bytestream2_get_le32(gb));
767cabdff1aSopenharmony_ci    AV_WL32(dst + 8, bytestream2_get_le32(gb));
768cabdff1aSopenharmony_ci    AV_WL32(dst + 12, bytestream2_get_le32(gb));
769cabdff1aSopenharmony_ci
770cabdff1aSopenharmony_ci    tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst;
771cabdff1aSopenharmony_ci    tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFF) >> 24] = dst + 2;
772cabdff1aSopenharmony_ci    tab2[0x9E3779B1 * AV_RL16(dst + 8) >> 24] = dst + 8;
773cabdff1aSopenharmony_ci    tab3[0x9E3779B1 * (AV_RL32(dst + 10) & 0xFFFFFF) >> 24] = dst + 10;
774cabdff1aSopenharmony_ci    dst += 16;
775cabdff1aSopenharmony_ci    while (dst + 10 < tex_data + tex_size) {
776cabdff1aSopenharmony_ci        ret = dxv_decompress_cgo(ctx, gb, tex_data, tex_size, op_data0, &oi0, op_size0,
777cabdff1aSopenharmony_ci                                 &dst, &state0, tab0, tab1, 8);
778cabdff1aSopenharmony_ci        if (ret < 0)
779cabdff1aSopenharmony_ci            return ret;
780cabdff1aSopenharmony_ci        ret = dxv_decompress_cgo(ctx, gb, tex_data, tex_size, op_data1, &oi1, op_size1,
781cabdff1aSopenharmony_ci                                 &dst, &state1, tab2, tab3, 8);
782cabdff1aSopenharmony_ci        if (ret < 0)
783cabdff1aSopenharmony_ci            return ret;
784cabdff1aSopenharmony_ci    }
785cabdff1aSopenharmony_ci
786cabdff1aSopenharmony_ci    bytestream2_seek(gb, data_start - 12 + op_offset + skip0 + skip1, SEEK_SET);
787cabdff1aSopenharmony_ci
788cabdff1aSopenharmony_ci    return 0;
789cabdff1aSopenharmony_ci}
790cabdff1aSopenharmony_ci
791cabdff1aSopenharmony_cistatic int dxv_decompress_yo(DXVContext *ctx, GetByteContext *gb,
792cabdff1aSopenharmony_ci                             uint8_t *tex_data, int tex_size,
793cabdff1aSopenharmony_ci                             uint8_t *op_data, int max_op_size)
794cabdff1aSopenharmony_ci{
795cabdff1aSopenharmony_ci    int op_offset = bytestream2_get_le32(gb);
796cabdff1aSopenharmony_ci    unsigned op_size = bytestream2_get_le32(gb);
797cabdff1aSopenharmony_ci    int data_start = bytestream2_tell(gb);
798cabdff1aSopenharmony_ci    uint8_t *dst, *table0[256] = { 0 }, *table1[256] = { 0 };
799cabdff1aSopenharmony_ci    int ret, state = 0, skip, oi = 0, v, vv;
800cabdff1aSopenharmony_ci
801cabdff1aSopenharmony_ci    if (op_offset < 8 || op_offset - 8 > bytestream2_get_bytes_left(gb))
802cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
803cabdff1aSopenharmony_ci
804cabdff1aSopenharmony_ci    dst = tex_data;
805cabdff1aSopenharmony_ci    bytestream2_skip(gb, op_offset - 8);
806cabdff1aSopenharmony_ci    if (op_size > max_op_size)
807cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
808cabdff1aSopenharmony_ci    skip = dxv_decompress_opcodes(gb, op_data, op_size);
809cabdff1aSopenharmony_ci    if (skip < 0)
810cabdff1aSopenharmony_ci        return skip;
811cabdff1aSopenharmony_ci    bytestream2_seek(gb, data_start, SEEK_SET);
812cabdff1aSopenharmony_ci
813cabdff1aSopenharmony_ci    v = bytestream2_get_le32(gb);
814cabdff1aSopenharmony_ci    AV_WL32(dst, v);
815cabdff1aSopenharmony_ci    vv = bytestream2_get_le32(gb);
816cabdff1aSopenharmony_ci    table0[0x9E3779B1 * (uint16_t)v >> 24] = dst;
817cabdff1aSopenharmony_ci    AV_WL32(dst + 4, vv);
818cabdff1aSopenharmony_ci    table1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFF) >> 24] = dst + 2;
819cabdff1aSopenharmony_ci    dst += 8;
820cabdff1aSopenharmony_ci
821cabdff1aSopenharmony_ci    while (dst < tex_data + tex_size) {
822cabdff1aSopenharmony_ci        ret = dxv_decompress_cgo(ctx, gb, tex_data, tex_size, op_data, &oi, op_size,
823cabdff1aSopenharmony_ci                                 &dst, &state, table0, table1, 0);
824cabdff1aSopenharmony_ci        if (ret < 0)
825cabdff1aSopenharmony_ci            return ret;
826cabdff1aSopenharmony_ci    }
827cabdff1aSopenharmony_ci
828cabdff1aSopenharmony_ci    bytestream2_seek(gb, data_start + op_offset + skip - 8, SEEK_SET);
829cabdff1aSopenharmony_ci
830cabdff1aSopenharmony_ci    return 0;
831cabdff1aSopenharmony_ci}
832cabdff1aSopenharmony_ci
833cabdff1aSopenharmony_cistatic int dxv_decompress_ycg6(AVCodecContext *avctx)
834cabdff1aSopenharmony_ci{
835cabdff1aSopenharmony_ci    DXVContext *ctx = avctx->priv_data;
836cabdff1aSopenharmony_ci    GetByteContext *gb = &ctx->gbc;
837cabdff1aSopenharmony_ci    int ret;
838cabdff1aSopenharmony_ci
839cabdff1aSopenharmony_ci    ret = dxv_decompress_yo(ctx, gb, ctx->tex_data, ctx->tex_size,
840cabdff1aSopenharmony_ci                            ctx->op_data[0], ctx->op_size[0]);
841cabdff1aSopenharmony_ci    if (ret < 0)
842cabdff1aSopenharmony_ci        return ret;
843cabdff1aSopenharmony_ci
844cabdff1aSopenharmony_ci    return dxv_decompress_cocg(ctx, gb, ctx->ctex_data, ctx->ctex_size,
845cabdff1aSopenharmony_ci                               ctx->op_data[1], ctx->op_data[2],
846cabdff1aSopenharmony_ci                               ctx->op_size[1], ctx->op_size[2]);
847cabdff1aSopenharmony_ci}
848cabdff1aSopenharmony_ci
849cabdff1aSopenharmony_cistatic int dxv_decompress_yg10(AVCodecContext *avctx)
850cabdff1aSopenharmony_ci{
851cabdff1aSopenharmony_ci    DXVContext *ctx = avctx->priv_data;
852cabdff1aSopenharmony_ci    GetByteContext *gb = &ctx->gbc;
853cabdff1aSopenharmony_ci    int ret;
854cabdff1aSopenharmony_ci
855cabdff1aSopenharmony_ci    ret = dxv_decompress_cocg(ctx, gb, ctx->tex_data, ctx->tex_size,
856cabdff1aSopenharmony_ci                              ctx->op_data[0], ctx->op_data[3],
857cabdff1aSopenharmony_ci                              ctx->op_size[0], ctx->op_size[3]);
858cabdff1aSopenharmony_ci    if (ret < 0)
859cabdff1aSopenharmony_ci        return ret;
860cabdff1aSopenharmony_ci
861cabdff1aSopenharmony_ci    return dxv_decompress_cocg(ctx, gb, ctx->ctex_data, ctx->ctex_size,
862cabdff1aSopenharmony_ci                               ctx->op_data[1], ctx->op_data[2],
863cabdff1aSopenharmony_ci                               ctx->op_size[1], ctx->op_size[2]);
864cabdff1aSopenharmony_ci}
865cabdff1aSopenharmony_ci
866cabdff1aSopenharmony_cistatic int dxv_decompress_dxt5(AVCodecContext *avctx)
867cabdff1aSopenharmony_ci{
868cabdff1aSopenharmony_ci    DXVContext *ctx = avctx->priv_data;
869cabdff1aSopenharmony_ci    GetByteContext *gbc = &ctx->gbc;
870cabdff1aSopenharmony_ci    uint32_t value, op, prev;
871cabdff1aSopenharmony_ci    int idx, state = 0;
872cabdff1aSopenharmony_ci    int pos = 4;
873cabdff1aSopenharmony_ci    int run = 0;
874cabdff1aSopenharmony_ci    int probe, check;
875cabdff1aSopenharmony_ci
876cabdff1aSopenharmony_ci    /* Copy the first four elements */
877cabdff1aSopenharmony_ci    AV_WL32(ctx->tex_data +  0, bytestream2_get_le32(gbc));
878cabdff1aSopenharmony_ci    AV_WL32(ctx->tex_data +  4, bytestream2_get_le32(gbc));
879cabdff1aSopenharmony_ci    AV_WL32(ctx->tex_data +  8, bytestream2_get_le32(gbc));
880cabdff1aSopenharmony_ci    AV_WL32(ctx->tex_data + 12, bytestream2_get_le32(gbc));
881cabdff1aSopenharmony_ci
882cabdff1aSopenharmony_ci    /* Process input until the whole texture has been filled */
883cabdff1aSopenharmony_ci    while (pos + 2 <= ctx->tex_size / 4) {
884cabdff1aSopenharmony_ci        if (run) {
885cabdff1aSopenharmony_ci            run--;
886cabdff1aSopenharmony_ci
887cabdff1aSopenharmony_ci            prev = AV_RL32(ctx->tex_data + 4 * (pos - 4));
888cabdff1aSopenharmony_ci            AV_WL32(ctx->tex_data + 4 * pos, prev);
889cabdff1aSopenharmony_ci            pos++;
890cabdff1aSopenharmony_ci            prev = AV_RL32(ctx->tex_data + 4 * (pos - 4));
891cabdff1aSopenharmony_ci            AV_WL32(ctx->tex_data + 4 * pos, prev);
892cabdff1aSopenharmony_ci            pos++;
893cabdff1aSopenharmony_ci        } else {
894cabdff1aSopenharmony_ci            if (bytestream2_get_bytes_left(gbc) < 1)
895cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
896cabdff1aSopenharmony_ci            if (state == 0) {
897cabdff1aSopenharmony_ci                value = bytestream2_get_le32(gbc);
898cabdff1aSopenharmony_ci                state = 16;
899cabdff1aSopenharmony_ci            }
900cabdff1aSopenharmony_ci            op = value & 0x3;
901cabdff1aSopenharmony_ci            value >>= 2;
902cabdff1aSopenharmony_ci            state--;
903cabdff1aSopenharmony_ci
904cabdff1aSopenharmony_ci            switch (op) {
905cabdff1aSopenharmony_ci            case 0:
906cabdff1aSopenharmony_ci                /* Long copy */
907cabdff1aSopenharmony_ci                check = bytestream2_get_byte(gbc) + 1;
908cabdff1aSopenharmony_ci                if (check == 256) {
909cabdff1aSopenharmony_ci                    do {
910cabdff1aSopenharmony_ci                        probe = bytestream2_get_le16(gbc);
911cabdff1aSopenharmony_ci                        check += probe;
912cabdff1aSopenharmony_ci                    } while (probe == 0xFFFF);
913cabdff1aSopenharmony_ci                }
914cabdff1aSopenharmony_ci                while (check && pos + 4 <= ctx->tex_size / 4) {
915cabdff1aSopenharmony_ci                    prev = AV_RL32(ctx->tex_data + 4 * (pos - 4));
916cabdff1aSopenharmony_ci                    AV_WL32(ctx->tex_data + 4 * pos, prev);
917cabdff1aSopenharmony_ci                    pos++;
918cabdff1aSopenharmony_ci
919cabdff1aSopenharmony_ci                    prev = AV_RL32(ctx->tex_data + 4 * (pos - 4));
920cabdff1aSopenharmony_ci                    AV_WL32(ctx->tex_data + 4 * pos, prev);
921cabdff1aSopenharmony_ci                    pos++;
922cabdff1aSopenharmony_ci
923cabdff1aSopenharmony_ci                    prev = AV_RL32(ctx->tex_data + 4 * (pos - 4));
924cabdff1aSopenharmony_ci                    AV_WL32(ctx->tex_data + 4 * pos, prev);
925cabdff1aSopenharmony_ci                    pos++;
926cabdff1aSopenharmony_ci
927cabdff1aSopenharmony_ci                    prev = AV_RL32(ctx->tex_data + 4 * (pos - 4));
928cabdff1aSopenharmony_ci                    AV_WL32(ctx->tex_data + 4 * pos, prev);
929cabdff1aSopenharmony_ci                    pos++;
930cabdff1aSopenharmony_ci
931cabdff1aSopenharmony_ci                    check--;
932cabdff1aSopenharmony_ci                }
933cabdff1aSopenharmony_ci
934cabdff1aSopenharmony_ci                /* Restart (or exit) the loop */
935cabdff1aSopenharmony_ci                continue;
936cabdff1aSopenharmony_ci                break;
937cabdff1aSopenharmony_ci            case 1:
938cabdff1aSopenharmony_ci                /* Load new run value */
939cabdff1aSopenharmony_ci                run = bytestream2_get_byte(gbc);
940cabdff1aSopenharmony_ci                if (run == 255) {
941cabdff1aSopenharmony_ci                    do {
942cabdff1aSopenharmony_ci                        probe = bytestream2_get_le16(gbc);
943cabdff1aSopenharmony_ci                        run += probe;
944cabdff1aSopenharmony_ci                    } while (probe == 0xFFFF);
945cabdff1aSopenharmony_ci                }
946cabdff1aSopenharmony_ci
947cabdff1aSopenharmony_ci                /* Copy two dwords from previous data */
948cabdff1aSopenharmony_ci                prev = AV_RL32(ctx->tex_data + 4 * (pos - 4));
949cabdff1aSopenharmony_ci                AV_WL32(ctx->tex_data + 4 * pos, prev);
950cabdff1aSopenharmony_ci                pos++;
951cabdff1aSopenharmony_ci
952cabdff1aSopenharmony_ci                prev = AV_RL32(ctx->tex_data + 4 * (pos - 4));
953cabdff1aSopenharmony_ci                AV_WL32(ctx->tex_data + 4 * pos, prev);
954cabdff1aSopenharmony_ci                pos++;
955cabdff1aSopenharmony_ci                break;
956cabdff1aSopenharmony_ci            case 2:
957cabdff1aSopenharmony_ci                /* Copy two dwords from a previous index */
958cabdff1aSopenharmony_ci                idx = 8 + bytestream2_get_le16(gbc);
959cabdff1aSopenharmony_ci                if (idx > pos || (unsigned int)(pos - idx) + 2 > ctx->tex_size / 4)
960cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
961cabdff1aSopenharmony_ci                prev = AV_RL32(ctx->tex_data + 4 * (pos - idx));
962cabdff1aSopenharmony_ci                AV_WL32(ctx->tex_data + 4 * pos, prev);
963cabdff1aSopenharmony_ci                pos++;
964cabdff1aSopenharmony_ci
965cabdff1aSopenharmony_ci                prev = AV_RL32(ctx->tex_data + 4 * (pos - idx));
966cabdff1aSopenharmony_ci                AV_WL32(ctx->tex_data + 4 * pos, prev);
967cabdff1aSopenharmony_ci                pos++;
968cabdff1aSopenharmony_ci                break;
969cabdff1aSopenharmony_ci            case 3:
970cabdff1aSopenharmony_ci                /* Copy two dwords from input */
971cabdff1aSopenharmony_ci                prev = bytestream2_get_le32(gbc);
972cabdff1aSopenharmony_ci                AV_WL32(ctx->tex_data + 4 * pos, prev);
973cabdff1aSopenharmony_ci                pos++;
974cabdff1aSopenharmony_ci
975cabdff1aSopenharmony_ci                prev = bytestream2_get_le32(gbc);
976cabdff1aSopenharmony_ci                AV_WL32(ctx->tex_data + 4 * pos, prev);
977cabdff1aSopenharmony_ci                pos++;
978cabdff1aSopenharmony_ci                break;
979cabdff1aSopenharmony_ci            }
980cabdff1aSopenharmony_ci        }
981cabdff1aSopenharmony_ci
982cabdff1aSopenharmony_ci        CHECKPOINT(4);
983cabdff1aSopenharmony_ci        if (pos + 2 > ctx->tex_size / 4)
984cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
985cabdff1aSopenharmony_ci
986cabdff1aSopenharmony_ci        /* Copy two elements from a previous offset or from the input buffer */
987cabdff1aSopenharmony_ci        if (op) {
988cabdff1aSopenharmony_ci            if (idx > pos || (unsigned int)(pos - idx) + 2 > ctx->tex_size / 4)
989cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
990cabdff1aSopenharmony_ci            prev = AV_RL32(ctx->tex_data + 4 * (pos - idx));
991cabdff1aSopenharmony_ci            AV_WL32(ctx->tex_data + 4 * pos, prev);
992cabdff1aSopenharmony_ci            pos++;
993cabdff1aSopenharmony_ci
994cabdff1aSopenharmony_ci            prev = AV_RL32(ctx->tex_data + 4 * (pos - idx));
995cabdff1aSopenharmony_ci            AV_WL32(ctx->tex_data + 4 * pos, prev);
996cabdff1aSopenharmony_ci            pos++;
997cabdff1aSopenharmony_ci        } else {
998cabdff1aSopenharmony_ci            CHECKPOINT(4);
999cabdff1aSopenharmony_ci
1000cabdff1aSopenharmony_ci            if (op && (idx > pos || (unsigned int)(pos - idx) + 2 > ctx->tex_size / 4))
1001cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
1002cabdff1aSopenharmony_ci            if (op)
1003cabdff1aSopenharmony_ci                prev = AV_RL32(ctx->tex_data + 4 * (pos - idx));
1004cabdff1aSopenharmony_ci            else
1005cabdff1aSopenharmony_ci                prev = bytestream2_get_le32(gbc);
1006cabdff1aSopenharmony_ci            AV_WL32(ctx->tex_data + 4 * pos, prev);
1007cabdff1aSopenharmony_ci            pos++;
1008cabdff1aSopenharmony_ci
1009cabdff1aSopenharmony_ci            CHECKPOINT(4);
1010cabdff1aSopenharmony_ci
1011cabdff1aSopenharmony_ci            if (op)
1012cabdff1aSopenharmony_ci                prev = AV_RL32(ctx->tex_data + 4 * (pos - idx));
1013cabdff1aSopenharmony_ci            else
1014cabdff1aSopenharmony_ci                prev = bytestream2_get_le32(gbc);
1015cabdff1aSopenharmony_ci            AV_WL32(ctx->tex_data + 4 * pos, prev);
1016cabdff1aSopenharmony_ci            pos++;
1017cabdff1aSopenharmony_ci        }
1018cabdff1aSopenharmony_ci    }
1019cabdff1aSopenharmony_ci
1020cabdff1aSopenharmony_ci    return 0;
1021cabdff1aSopenharmony_ci}
1022cabdff1aSopenharmony_ci
1023cabdff1aSopenharmony_cistatic int dxv_decompress_lzf(AVCodecContext *avctx)
1024cabdff1aSopenharmony_ci{
1025cabdff1aSopenharmony_ci    DXVContext *ctx = avctx->priv_data;
1026cabdff1aSopenharmony_ci    return ff_lzf_uncompress(&ctx->gbc, &ctx->tex_data, &ctx->tex_size);
1027cabdff1aSopenharmony_ci}
1028cabdff1aSopenharmony_ci
1029cabdff1aSopenharmony_cistatic int dxv_decompress_raw(AVCodecContext *avctx)
1030cabdff1aSopenharmony_ci{
1031cabdff1aSopenharmony_ci    DXVContext *ctx = avctx->priv_data;
1032cabdff1aSopenharmony_ci    GetByteContext *gbc = &ctx->gbc;
1033cabdff1aSopenharmony_ci
1034cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gbc) < ctx->tex_size)
1035cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1036cabdff1aSopenharmony_ci
1037cabdff1aSopenharmony_ci    bytestream2_get_buffer(gbc, ctx->tex_data, ctx->tex_size);
1038cabdff1aSopenharmony_ci    return 0;
1039cabdff1aSopenharmony_ci}
1040cabdff1aSopenharmony_ci
1041cabdff1aSopenharmony_cistatic int dxv_decode(AVCodecContext *avctx, AVFrame *frame,
1042cabdff1aSopenharmony_ci                      int *got_frame, AVPacket *avpkt)
1043cabdff1aSopenharmony_ci{
1044cabdff1aSopenharmony_ci    DXVContext *ctx = avctx->priv_data;
1045cabdff1aSopenharmony_ci    GetByteContext *gbc = &ctx->gbc;
1046cabdff1aSopenharmony_ci    int (*decompress_tex)(AVCodecContext *avctx);
1047cabdff1aSopenharmony_ci    const char *msgcomp, *msgtext;
1048cabdff1aSopenharmony_ci    uint32_t tag;
1049cabdff1aSopenharmony_ci    int version_major, version_minor = 0;
1050cabdff1aSopenharmony_ci    int size = 0, old_type = 0;
1051cabdff1aSopenharmony_ci    int ret;
1052cabdff1aSopenharmony_ci
1053cabdff1aSopenharmony_ci    bytestream2_init(gbc, avpkt->data, avpkt->size);
1054cabdff1aSopenharmony_ci
1055cabdff1aSopenharmony_ci    ctx->texture_block_h = 4;
1056cabdff1aSopenharmony_ci    ctx->texture_block_w = 4;
1057cabdff1aSopenharmony_ci
1058cabdff1aSopenharmony_ci    avctx->pix_fmt = AV_PIX_FMT_RGBA;
1059cabdff1aSopenharmony_ci    avctx->colorspace = AVCOL_SPC_RGB;
1060cabdff1aSopenharmony_ci
1061cabdff1aSopenharmony_ci    ctx->tex_funct = NULL;
1062cabdff1aSopenharmony_ci    ctx->tex_funct_planar[0] = NULL;
1063cabdff1aSopenharmony_ci    ctx->tex_funct_planar[1] = NULL;
1064cabdff1aSopenharmony_ci
1065cabdff1aSopenharmony_ci    tag = bytestream2_get_le32(gbc);
1066cabdff1aSopenharmony_ci    switch (tag) {
1067cabdff1aSopenharmony_ci    case MKBETAG('D', 'X', 'T', '1'):
1068cabdff1aSopenharmony_ci        decompress_tex = dxv_decompress_dxt1;
1069cabdff1aSopenharmony_ci        ctx->tex_funct = ctx->texdsp.dxt1_block;
1070cabdff1aSopenharmony_ci        ctx->tex_rat   = 8;
1071cabdff1aSopenharmony_ci        ctx->tex_step  = 8;
1072cabdff1aSopenharmony_ci        msgcomp = "DXTR1";
1073cabdff1aSopenharmony_ci        msgtext = "DXT1";
1074cabdff1aSopenharmony_ci        break;
1075cabdff1aSopenharmony_ci    case MKBETAG('D', 'X', 'T', '5'):
1076cabdff1aSopenharmony_ci        decompress_tex = dxv_decompress_dxt5;
1077cabdff1aSopenharmony_ci        ctx->tex_funct = ctx->texdsp.dxt5_block;
1078cabdff1aSopenharmony_ci        ctx->tex_rat   = 4;
1079cabdff1aSopenharmony_ci        ctx->tex_step  = 16;
1080cabdff1aSopenharmony_ci        msgcomp = "DXTR5";
1081cabdff1aSopenharmony_ci        msgtext = "DXT5";
1082cabdff1aSopenharmony_ci        break;
1083cabdff1aSopenharmony_ci    case MKBETAG('Y', 'C', 'G', '6'):
1084cabdff1aSopenharmony_ci        decompress_tex = dxv_decompress_ycg6;
1085cabdff1aSopenharmony_ci        ctx->tex_funct_planar[0] = yo_block;
1086cabdff1aSopenharmony_ci        ctx->tex_funct_planar[1] = cocg_block;
1087cabdff1aSopenharmony_ci        ctx->tex_rat   = 8;
1088cabdff1aSopenharmony_ci        ctx->tex_step  = 32;
1089cabdff1aSopenharmony_ci        ctx->ctex_step = 16;
1090cabdff1aSopenharmony_ci        msgcomp = "YOCOCG6";
1091cabdff1aSopenharmony_ci        msgtext = "YCG6";
1092cabdff1aSopenharmony_ci        ctx->ctex_size = avctx->coded_width * avctx->coded_height / 4;
1093cabdff1aSopenharmony_ci        ctx->texture_block_h = 4;
1094cabdff1aSopenharmony_ci        ctx->texture_block_w = 16;
1095cabdff1aSopenharmony_ci        ctx->ctexture_block_h = 4;
1096cabdff1aSopenharmony_ci        ctx->ctexture_block_w = 4;
1097cabdff1aSopenharmony_ci        avctx->pix_fmt = AV_PIX_FMT_YUV420P;
1098cabdff1aSopenharmony_ci        avctx->colorspace = AVCOL_SPC_YCOCG;
1099cabdff1aSopenharmony_ci        break;
1100cabdff1aSopenharmony_ci    case MKBETAG('Y', 'G', '1', '0'):
1101cabdff1aSopenharmony_ci        decompress_tex = dxv_decompress_yg10;
1102cabdff1aSopenharmony_ci        ctx->tex_funct_planar[0] = yao_block;
1103cabdff1aSopenharmony_ci        ctx->tex_funct_planar[1] = cocg_block;
1104cabdff1aSopenharmony_ci        ctx->tex_rat   = 4;
1105cabdff1aSopenharmony_ci        ctx->tex_step  = 64;
1106cabdff1aSopenharmony_ci        ctx->ctex_step = 16;
1107cabdff1aSopenharmony_ci        msgcomp = "YAOCOCG10";
1108cabdff1aSopenharmony_ci        msgtext = "YG10";
1109cabdff1aSopenharmony_ci        ctx->ctex_size = avctx->coded_width * avctx->coded_height / 4;
1110cabdff1aSopenharmony_ci        ctx->texture_block_h = 4;
1111cabdff1aSopenharmony_ci        ctx->texture_block_w = 16;
1112cabdff1aSopenharmony_ci        ctx->ctexture_block_h = 4;
1113cabdff1aSopenharmony_ci        ctx->ctexture_block_w = 4;
1114cabdff1aSopenharmony_ci        avctx->pix_fmt = AV_PIX_FMT_YUVA420P;
1115cabdff1aSopenharmony_ci        avctx->colorspace = AVCOL_SPC_YCOCG;
1116cabdff1aSopenharmony_ci        break;
1117cabdff1aSopenharmony_ci    default:
1118cabdff1aSopenharmony_ci        /* Old version does not have a real header, just size and type. */
1119cabdff1aSopenharmony_ci        size = tag & 0x00FFFFFF;
1120cabdff1aSopenharmony_ci        old_type = tag >> 24;
1121cabdff1aSopenharmony_ci        version_major = (old_type & 0x0F) - 1;
1122cabdff1aSopenharmony_ci
1123cabdff1aSopenharmony_ci        if (old_type & 0x80) {
1124cabdff1aSopenharmony_ci            msgcomp = "RAW";
1125cabdff1aSopenharmony_ci            decompress_tex = dxv_decompress_raw;
1126cabdff1aSopenharmony_ci        } else {
1127cabdff1aSopenharmony_ci            msgcomp = "LZF";
1128cabdff1aSopenharmony_ci            decompress_tex = dxv_decompress_lzf;
1129cabdff1aSopenharmony_ci        }
1130cabdff1aSopenharmony_ci
1131cabdff1aSopenharmony_ci        if (old_type & 0x40) {
1132cabdff1aSopenharmony_ci            msgtext = "DXT5";
1133cabdff1aSopenharmony_ci
1134cabdff1aSopenharmony_ci            ctx->tex_funct = ctx->texdsp.dxt5_block;
1135cabdff1aSopenharmony_ci            ctx->tex_step  = 16;
1136cabdff1aSopenharmony_ci        } else if (old_type & 0x20 || version_major == 1) {
1137cabdff1aSopenharmony_ci            msgtext = "DXT1";
1138cabdff1aSopenharmony_ci
1139cabdff1aSopenharmony_ci            ctx->tex_funct = ctx->texdsp.dxt1_block;
1140cabdff1aSopenharmony_ci            ctx->tex_step  = 8;
1141cabdff1aSopenharmony_ci        } else {
1142cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unsupported header (0x%08"PRIX32")\n.", tag);
1143cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1144cabdff1aSopenharmony_ci        }
1145cabdff1aSopenharmony_ci        ctx->tex_rat = 1;
1146cabdff1aSopenharmony_ci        break;
1147cabdff1aSopenharmony_ci    }
1148cabdff1aSopenharmony_ci
1149cabdff1aSopenharmony_ci    ctx->slice_count = av_clip(avctx->thread_count, 1,
1150cabdff1aSopenharmony_ci                               avctx->coded_height / FFMAX(ctx->texture_block_h,
1151cabdff1aSopenharmony_ci                                                           ctx->ctexture_block_h));
1152cabdff1aSopenharmony_ci
1153cabdff1aSopenharmony_ci    /* New header is 12 bytes long. */
1154cabdff1aSopenharmony_ci    if (!old_type) {
1155cabdff1aSopenharmony_ci        version_major = bytestream2_get_byte(gbc) - 1;
1156cabdff1aSopenharmony_ci        version_minor = bytestream2_get_byte(gbc);
1157cabdff1aSopenharmony_ci
1158cabdff1aSopenharmony_ci        /* Encoder copies texture data when compression is not advantageous. */
1159cabdff1aSopenharmony_ci        if (bytestream2_get_byte(gbc)) {
1160cabdff1aSopenharmony_ci            msgcomp = "RAW";
1161cabdff1aSopenharmony_ci            ctx->tex_rat = 1;
1162cabdff1aSopenharmony_ci            decompress_tex = dxv_decompress_raw;
1163cabdff1aSopenharmony_ci        }
1164cabdff1aSopenharmony_ci
1165cabdff1aSopenharmony_ci        bytestream2_skip(gbc, 1); // unknown
1166cabdff1aSopenharmony_ci        size = bytestream2_get_le32(gbc);
1167cabdff1aSopenharmony_ci    }
1168cabdff1aSopenharmony_ci    av_log(avctx, AV_LOG_DEBUG,
1169cabdff1aSopenharmony_ci           "%s compression with %s texture (version %d.%d)\n",
1170cabdff1aSopenharmony_ci           msgcomp, msgtext, version_major, version_minor);
1171cabdff1aSopenharmony_ci
1172cabdff1aSopenharmony_ci    if (size != bytestream2_get_bytes_left(gbc)) {
1173cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
1174cabdff1aSopenharmony_ci               "Incomplete or invalid file (header %d, left %u).\n",
1175cabdff1aSopenharmony_ci               size, bytestream2_get_bytes_left(gbc));
1176cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1177cabdff1aSopenharmony_ci    }
1178cabdff1aSopenharmony_ci
1179cabdff1aSopenharmony_ci    ctx->tex_size = avctx->coded_width * avctx->coded_height * 4 / ctx->tex_rat;
1180cabdff1aSopenharmony_ci    ret = av_reallocp(&ctx->tex_data, ctx->tex_size + AV_INPUT_BUFFER_PADDING_SIZE);
1181cabdff1aSopenharmony_ci    if (ret < 0)
1182cabdff1aSopenharmony_ci        return ret;
1183cabdff1aSopenharmony_ci
1184cabdff1aSopenharmony_ci    if (ctx->ctex_size) {
1185cabdff1aSopenharmony_ci        int i;
1186cabdff1aSopenharmony_ci
1187cabdff1aSopenharmony_ci        ctx->op_size[0] = avctx->coded_width * avctx->coded_height / 16;
1188cabdff1aSopenharmony_ci        ctx->op_size[1] = avctx->coded_width * avctx->coded_height / 32;
1189cabdff1aSopenharmony_ci        ctx->op_size[2] = avctx->coded_width * avctx->coded_height / 32;
1190cabdff1aSopenharmony_ci        ctx->op_size[3] = avctx->coded_width * avctx->coded_height / 16;
1191cabdff1aSopenharmony_ci
1192cabdff1aSopenharmony_ci        ret = av_reallocp(&ctx->ctex_data, ctx->ctex_size + AV_INPUT_BUFFER_PADDING_SIZE);
1193cabdff1aSopenharmony_ci        if (ret < 0)
1194cabdff1aSopenharmony_ci            return ret;
1195cabdff1aSopenharmony_ci        for (i = 0; i < 4; i++) {
1196cabdff1aSopenharmony_ci            ret = av_reallocp(&ctx->op_data[i], ctx->op_size[i]);
1197cabdff1aSopenharmony_ci            if (ret < 0)
1198cabdff1aSopenharmony_ci                return ret;
1199cabdff1aSopenharmony_ci        }
1200cabdff1aSopenharmony_ci    }
1201cabdff1aSopenharmony_ci
1202cabdff1aSopenharmony_ci    /* Decompress texture out of the intermediate compression. */
1203cabdff1aSopenharmony_ci    ret = decompress_tex(avctx);
1204cabdff1aSopenharmony_ci    if (ret < 0)
1205cabdff1aSopenharmony_ci        return ret;
1206cabdff1aSopenharmony_ci    {
1207cabdff1aSopenharmony_ci        int w_block = avctx->coded_width / ctx->texture_block_w;
1208cabdff1aSopenharmony_ci        int h_block = avctx->coded_height / ctx->texture_block_h;
1209cabdff1aSopenharmony_ci        if (w_block * h_block * ctx->tex_step > ctx->tex_size * 8LL)
1210cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1211cabdff1aSopenharmony_ci    }
1212cabdff1aSopenharmony_ci
1213cabdff1aSopenharmony_ci    ret = ff_thread_get_buffer(avctx, frame, 0);
1214cabdff1aSopenharmony_ci    if (ret < 0)
1215cabdff1aSopenharmony_ci        return ret;
1216cabdff1aSopenharmony_ci
1217cabdff1aSopenharmony_ci    /* Now decompress the texture with the standard functions. */
1218cabdff1aSopenharmony_ci    avctx->execute2(avctx, decompress_texture_thread,
1219cabdff1aSopenharmony_ci                    frame, NULL, ctx->slice_count);
1220cabdff1aSopenharmony_ci
1221cabdff1aSopenharmony_ci    /* Frame is ready to be output. */
1222cabdff1aSopenharmony_ci    frame->pict_type = AV_PICTURE_TYPE_I;
1223cabdff1aSopenharmony_ci    frame->key_frame = 1;
1224cabdff1aSopenharmony_ci    *got_frame = 1;
1225cabdff1aSopenharmony_ci
1226cabdff1aSopenharmony_ci    return avpkt->size;
1227cabdff1aSopenharmony_ci}
1228cabdff1aSopenharmony_ci
1229cabdff1aSopenharmony_cistatic int dxv_init(AVCodecContext *avctx)
1230cabdff1aSopenharmony_ci{
1231cabdff1aSopenharmony_ci    DXVContext *ctx = avctx->priv_data;
1232cabdff1aSopenharmony_ci    int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
1233cabdff1aSopenharmony_ci
1234cabdff1aSopenharmony_ci    if (ret < 0) {
1235cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
1236cabdff1aSopenharmony_ci               avctx->width, avctx->height);
1237cabdff1aSopenharmony_ci        return ret;
1238cabdff1aSopenharmony_ci    }
1239cabdff1aSopenharmony_ci
1240cabdff1aSopenharmony_ci    /* Codec requires 16x16 alignment. */
1241cabdff1aSopenharmony_ci    avctx->coded_width  = FFALIGN(avctx->width,  16);
1242cabdff1aSopenharmony_ci    avctx->coded_height = FFALIGN(avctx->height, 16);
1243cabdff1aSopenharmony_ci
1244cabdff1aSopenharmony_ci    ff_texturedsp_init(&ctx->texdsp);
1245cabdff1aSopenharmony_ci
1246cabdff1aSopenharmony_ci    return 0;
1247cabdff1aSopenharmony_ci}
1248cabdff1aSopenharmony_ci
1249cabdff1aSopenharmony_cistatic int dxv_close(AVCodecContext *avctx)
1250cabdff1aSopenharmony_ci{
1251cabdff1aSopenharmony_ci    DXVContext *ctx = avctx->priv_data;
1252cabdff1aSopenharmony_ci
1253cabdff1aSopenharmony_ci    av_freep(&ctx->tex_data);
1254cabdff1aSopenharmony_ci    av_freep(&ctx->ctex_data);
1255cabdff1aSopenharmony_ci    av_freep(&ctx->op_data[0]);
1256cabdff1aSopenharmony_ci    av_freep(&ctx->op_data[1]);
1257cabdff1aSopenharmony_ci    av_freep(&ctx->op_data[2]);
1258cabdff1aSopenharmony_ci    av_freep(&ctx->op_data[3]);
1259cabdff1aSopenharmony_ci
1260cabdff1aSopenharmony_ci    return 0;
1261cabdff1aSopenharmony_ci}
1262cabdff1aSopenharmony_ci
1263cabdff1aSopenharmony_ciconst FFCodec ff_dxv_decoder = {
1264cabdff1aSopenharmony_ci    .p.name         = "dxv",
1265cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Resolume DXV"),
1266cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
1267cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_DXV,
1268cabdff1aSopenharmony_ci    .init           = dxv_init,
1269cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(dxv_decode),
1270cabdff1aSopenharmony_ci    .close          = dxv_close,
1271cabdff1aSopenharmony_ci    .priv_data_size = sizeof(DXVContext),
1272cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1 |
1273cabdff1aSopenharmony_ci                      AV_CODEC_CAP_SLICE_THREADS |
1274cabdff1aSopenharmony_ci                      AV_CODEC_CAP_FRAME_THREADS,
1275cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
1276cabdff1aSopenharmony_ci                      FF_CODEC_CAP_INIT_CLEANUP,
1277cabdff1aSopenharmony_ci};
1278