xref: /third_party/ffmpeg/libavcodec/dxtory.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Dxtory decoder
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * Copyright (c) 2011 Konstantin Shishkov
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 <inttypes.h>
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ci#include "libavutil/common.h"
26cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#define BITSTREAM_READER_LE
29cabdff1aSopenharmony_ci#include "avcodec.h"
30cabdff1aSopenharmony_ci#include "bytestream.h"
31cabdff1aSopenharmony_ci#include "codec_internal.h"
32cabdff1aSopenharmony_ci#include "get_bits.h"
33cabdff1aSopenharmony_ci#include "unary.h"
34cabdff1aSopenharmony_ci#include "thread.h"
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_cistatic int64_t get_raw_size(enum AVPixelFormat fmt, int width, int height)
37cabdff1aSopenharmony_ci{
38cabdff1aSopenharmony_ci    switch (fmt) {
39cabdff1aSopenharmony_ci    case AV_PIX_FMT_RGB555LE:
40cabdff1aSopenharmony_ci    case AV_PIX_FMT_RGB565LE:
41cabdff1aSopenharmony_ci        return width * height * 2LL;
42cabdff1aSopenharmony_ci    case AV_PIX_FMT_RGB24:
43cabdff1aSopenharmony_ci    case AV_PIX_FMT_BGR24:
44cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV444P:
45cabdff1aSopenharmony_ci        return width * height * 3LL;
46cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV420P:
47cabdff1aSopenharmony_ci        return (int64_t)(width * height) + 2 * AV_CEIL_RSHIFT(width, 1) * AV_CEIL_RSHIFT(height, 1);
48cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV410P:
49cabdff1aSopenharmony_ci        return (int64_t)(width * height) + 2 * AV_CEIL_RSHIFT(width, 2) * AV_CEIL_RSHIFT(height, 2);
50cabdff1aSopenharmony_ci    }
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_ci    return 0;
53cabdff1aSopenharmony_ci}
54cabdff1aSopenharmony_ci
55cabdff1aSopenharmony_cistatic void do_vflip(AVCodecContext *avctx, AVFrame *pic, int vflip)
56cabdff1aSopenharmony_ci{
57cabdff1aSopenharmony_ci    if (!vflip)
58cabdff1aSopenharmony_ci        return;
59cabdff1aSopenharmony_ci
60cabdff1aSopenharmony_ci    switch (pic->format) {
61cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV444P:
62cabdff1aSopenharmony_ci        pic->data[1] += (avctx->height - 1) * pic->linesize[1];
63cabdff1aSopenharmony_ci        pic->linesize[1] = -pic->linesize[1];
64cabdff1aSopenharmony_ci        pic->data[2] += (avctx->height - 1) * pic->linesize[2];
65cabdff1aSopenharmony_ci        pic->linesize[2] = -pic->linesize[2];
66cabdff1aSopenharmony_ci    case AV_PIX_FMT_RGB555LE:
67cabdff1aSopenharmony_ci    case AV_PIX_FMT_RGB565LE:
68cabdff1aSopenharmony_ci    case AV_PIX_FMT_BGR24:
69cabdff1aSopenharmony_ci    case AV_PIX_FMT_RGB24:
70cabdff1aSopenharmony_ci        pic->data[0] += (avctx->height - 1) * pic->linesize[0];
71cabdff1aSopenharmony_ci        pic->linesize[0] = -pic->linesize[0];
72cabdff1aSopenharmony_ci        break;
73cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV410P:
74cabdff1aSopenharmony_ci        pic->data[0] += (avctx->height - 1) * pic->linesize[0];
75cabdff1aSopenharmony_ci        pic->linesize[0] = -pic->linesize[0];
76cabdff1aSopenharmony_ci        pic->data[1] += (AV_CEIL_RSHIFT(avctx->height, 2) - 1) * pic->linesize[1];
77cabdff1aSopenharmony_ci        pic->linesize[1] = -pic->linesize[1];
78cabdff1aSopenharmony_ci        pic->data[2] += (AV_CEIL_RSHIFT(avctx->height, 2) - 1) * pic->linesize[2];
79cabdff1aSopenharmony_ci        pic->linesize[2] = -pic->linesize[2];
80cabdff1aSopenharmony_ci        break;
81cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV420P:
82cabdff1aSopenharmony_ci        pic->data[0] += (avctx->height - 1) * pic->linesize[0];
83cabdff1aSopenharmony_ci        pic->linesize[0] = -pic->linesize[0];
84cabdff1aSopenharmony_ci        pic->data[1] += (AV_CEIL_RSHIFT(avctx->height, 1) - 1) * pic->linesize[1];
85cabdff1aSopenharmony_ci        pic->linesize[1] = -pic->linesize[1];
86cabdff1aSopenharmony_ci        pic->data[2] += (AV_CEIL_RSHIFT(avctx->height, 1) - 1) * pic->linesize[2];
87cabdff1aSopenharmony_ci        pic->linesize[2] = -pic->linesize[2];
88cabdff1aSopenharmony_ci        break;
89cabdff1aSopenharmony_ci    }
90cabdff1aSopenharmony_ci}
91cabdff1aSopenharmony_ci
92cabdff1aSopenharmony_cistatic int dxtory_decode_v1_rgb(AVCodecContext *avctx, AVFrame *pic,
93cabdff1aSopenharmony_ci                                const uint8_t *src, int src_size,
94cabdff1aSopenharmony_ci                                int id, int bpp, uint32_t vflipped)
95cabdff1aSopenharmony_ci{
96cabdff1aSopenharmony_ci    int h;
97cabdff1aSopenharmony_ci    uint8_t *dst;
98cabdff1aSopenharmony_ci    int ret;
99cabdff1aSopenharmony_ci
100cabdff1aSopenharmony_ci    if (src_size < get_raw_size(id, avctx->width, avctx->height)) {
101cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "packet too small\n");
102cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
103cabdff1aSopenharmony_ci    }
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci    avctx->pix_fmt = id;
106cabdff1aSopenharmony_ci    if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0)
107cabdff1aSopenharmony_ci        return ret;
108cabdff1aSopenharmony_ci
109cabdff1aSopenharmony_ci    do_vflip(avctx, pic, vflipped);
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci    dst = pic->data[0];
112cabdff1aSopenharmony_ci    for (h = 0; h < avctx->height; h++) {
113cabdff1aSopenharmony_ci        memcpy(dst, src, avctx->width * bpp);
114cabdff1aSopenharmony_ci        src += avctx->width * bpp;
115cabdff1aSopenharmony_ci        dst += pic->linesize[0];
116cabdff1aSopenharmony_ci    }
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci    do_vflip(avctx, pic, vflipped);
119cabdff1aSopenharmony_ci
120cabdff1aSopenharmony_ci    return 0;
121cabdff1aSopenharmony_ci}
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_cistatic int dxtory_decode_v1_410(AVCodecContext *avctx, AVFrame *pic,
124cabdff1aSopenharmony_ci                                const uint8_t *src, int src_size,
125cabdff1aSopenharmony_ci                                uint32_t vflipped)
126cabdff1aSopenharmony_ci{
127cabdff1aSopenharmony_ci    int h, w;
128cabdff1aSopenharmony_ci    uint8_t *Y1, *Y2, *Y3, *Y4, *U, *V;
129cabdff1aSopenharmony_ci    int height, width, hmargin, vmargin;
130cabdff1aSopenharmony_ci    int huvborder;
131cabdff1aSopenharmony_ci    int ret;
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_ci    if (src_size < get_raw_size(AV_PIX_FMT_YUV410P, avctx->width, avctx->height)) {
134cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "packet too small\n");
135cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
136cabdff1aSopenharmony_ci    }
137cabdff1aSopenharmony_ci
138cabdff1aSopenharmony_ci    avctx->pix_fmt = AV_PIX_FMT_YUV410P;
139cabdff1aSopenharmony_ci    if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0)
140cabdff1aSopenharmony_ci        return ret;
141cabdff1aSopenharmony_ci
142cabdff1aSopenharmony_ci    do_vflip(avctx, pic, vflipped);
143cabdff1aSopenharmony_ci
144cabdff1aSopenharmony_ci    height = avctx->height & ~3;
145cabdff1aSopenharmony_ci    width  = avctx->width  & ~3;
146cabdff1aSopenharmony_ci    hmargin = avctx->width  - width;
147cabdff1aSopenharmony_ci    vmargin = avctx->height - height;
148cabdff1aSopenharmony_ci    huvborder = AV_CEIL_RSHIFT(avctx->width, 2) - 1;
149cabdff1aSopenharmony_ci
150cabdff1aSopenharmony_ci    Y1 = pic->data[0];
151cabdff1aSopenharmony_ci    Y2 = pic->data[0] + pic->linesize[0];
152cabdff1aSopenharmony_ci    Y3 = pic->data[0] + pic->linesize[0] * 2;
153cabdff1aSopenharmony_ci    Y4 = pic->data[0] + pic->linesize[0] * 3;
154cabdff1aSopenharmony_ci    U  = pic->data[1];
155cabdff1aSopenharmony_ci    V  = pic->data[2];
156cabdff1aSopenharmony_ci    for (h = 0; h < height; h += 4) {
157cabdff1aSopenharmony_ci        for (w = 0; w < width; w += 4) {
158cabdff1aSopenharmony_ci            AV_COPY32U(Y1 + w, src);
159cabdff1aSopenharmony_ci            AV_COPY32U(Y2 + w, src + 4);
160cabdff1aSopenharmony_ci            AV_COPY32U(Y3 + w, src + 8);
161cabdff1aSopenharmony_ci            AV_COPY32U(Y4 + w, src + 12);
162cabdff1aSopenharmony_ci            U[w >> 2] = src[16] + 0x80;
163cabdff1aSopenharmony_ci            V[w >> 2] = src[17] + 0x80;
164cabdff1aSopenharmony_ci            src += 18;
165cabdff1aSopenharmony_ci        }
166cabdff1aSopenharmony_ci        if (hmargin) {
167cabdff1aSopenharmony_ci            for (w = 0; w < hmargin; w++) {
168cabdff1aSopenharmony_ci                Y1[width + w] = src[w];
169cabdff1aSopenharmony_ci                Y2[width + w] = src[w + hmargin * 1];
170cabdff1aSopenharmony_ci                Y3[width + w] = src[w + hmargin * 2];
171cabdff1aSopenharmony_ci                Y4[width + w] = src[w + hmargin * 3];
172cabdff1aSopenharmony_ci            }
173cabdff1aSopenharmony_ci            src += 4 * hmargin;
174cabdff1aSopenharmony_ci            U[huvborder] = src[0] + 0x80;
175cabdff1aSopenharmony_ci            V[huvborder] = src[1] + 0x80;
176cabdff1aSopenharmony_ci            src += 2;
177cabdff1aSopenharmony_ci        }
178cabdff1aSopenharmony_ci        Y1 += pic->linesize[0] * 4;
179cabdff1aSopenharmony_ci        Y2 += pic->linesize[0] * 4;
180cabdff1aSopenharmony_ci        Y3 += pic->linesize[0] * 4;
181cabdff1aSopenharmony_ci        Y4 += pic->linesize[0] * 4;
182cabdff1aSopenharmony_ci        U  += pic->linesize[1];
183cabdff1aSopenharmony_ci        V  += pic->linesize[2];
184cabdff1aSopenharmony_ci    }
185cabdff1aSopenharmony_ci
186cabdff1aSopenharmony_ci    if (vmargin) {
187cabdff1aSopenharmony_ci        for (w = 0; w < width; w += 4) {
188cabdff1aSopenharmony_ci            AV_COPY32U(Y1 + w, src);
189cabdff1aSopenharmony_ci            if (vmargin > 1)
190cabdff1aSopenharmony_ci                AV_COPY32U(Y2 + w, src + 4);
191cabdff1aSopenharmony_ci            if (vmargin > 2)
192cabdff1aSopenharmony_ci                AV_COPY32U(Y3 + w, src + 8);
193cabdff1aSopenharmony_ci            src += 4 * vmargin;
194cabdff1aSopenharmony_ci            U[w >> 2] = src[0] + 0x80;
195cabdff1aSopenharmony_ci            V[w >> 2] = src[1] + 0x80;
196cabdff1aSopenharmony_ci            src += 2;
197cabdff1aSopenharmony_ci        }
198cabdff1aSopenharmony_ci        if (hmargin) {
199cabdff1aSopenharmony_ci            for (w = 0; w < hmargin; w++) {
200cabdff1aSopenharmony_ci                AV_COPY32U(Y1 + w, src);
201cabdff1aSopenharmony_ci                if (vmargin > 1)
202cabdff1aSopenharmony_ci                    AV_COPY32U(Y2 + w, src + 4);
203cabdff1aSopenharmony_ci                if (vmargin > 2)
204cabdff1aSopenharmony_ci                    AV_COPY32U(Y3 + w, src + 8);
205cabdff1aSopenharmony_ci                src += 4 * vmargin;
206cabdff1aSopenharmony_ci            }
207cabdff1aSopenharmony_ci            U[huvborder] = src[0] + 0x80;
208cabdff1aSopenharmony_ci            V[huvborder] = src[1] + 0x80;
209cabdff1aSopenharmony_ci            src += 2;
210cabdff1aSopenharmony_ci        }
211cabdff1aSopenharmony_ci    }
212cabdff1aSopenharmony_ci
213cabdff1aSopenharmony_ci    do_vflip(avctx, pic, vflipped);
214cabdff1aSopenharmony_ci
215cabdff1aSopenharmony_ci    return 0;
216cabdff1aSopenharmony_ci}
217cabdff1aSopenharmony_ci
218cabdff1aSopenharmony_cistatic int dxtory_decode_v1_420(AVCodecContext *avctx, AVFrame *pic,
219cabdff1aSopenharmony_ci                                const uint8_t *src, int src_size,
220cabdff1aSopenharmony_ci                                uint32_t vflipped)
221cabdff1aSopenharmony_ci{
222cabdff1aSopenharmony_ci    int h, w;
223cabdff1aSopenharmony_ci    uint8_t *Y1, *Y2, *U, *V;
224cabdff1aSopenharmony_ci    int height, width, hmargin, vmargin;
225cabdff1aSopenharmony_ci    int huvborder;
226cabdff1aSopenharmony_ci    int ret;
227cabdff1aSopenharmony_ci
228cabdff1aSopenharmony_ci    if (src_size < get_raw_size(AV_PIX_FMT_YUV420P, avctx->width, avctx->height)) {
229cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "packet too small\n");
230cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
231cabdff1aSopenharmony_ci    }
232cabdff1aSopenharmony_ci
233cabdff1aSopenharmony_ci    avctx->pix_fmt = AV_PIX_FMT_YUV420P;
234cabdff1aSopenharmony_ci    if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0)
235cabdff1aSopenharmony_ci        return ret;
236cabdff1aSopenharmony_ci
237cabdff1aSopenharmony_ci    do_vflip(avctx, pic, vflipped);
238cabdff1aSopenharmony_ci
239cabdff1aSopenharmony_ci    height = avctx->height & ~1;
240cabdff1aSopenharmony_ci    width  = avctx->width  & ~1;
241cabdff1aSopenharmony_ci    hmargin = avctx->width  - width;
242cabdff1aSopenharmony_ci    vmargin = avctx->height - height;
243cabdff1aSopenharmony_ci    huvborder = AV_CEIL_RSHIFT(avctx->width, 1) - 1;
244cabdff1aSopenharmony_ci
245cabdff1aSopenharmony_ci    Y1 = pic->data[0];
246cabdff1aSopenharmony_ci    Y2 = pic->data[0] + pic->linesize[0];
247cabdff1aSopenharmony_ci    U  = pic->data[1];
248cabdff1aSopenharmony_ci    V  = pic->data[2];
249cabdff1aSopenharmony_ci    for (h = 0; h < height; h += 2) {
250cabdff1aSopenharmony_ci        for (w = 0; w < width; w += 2) {
251cabdff1aSopenharmony_ci            AV_COPY16(Y1 + w, src);
252cabdff1aSopenharmony_ci            AV_COPY16(Y2 + w, src + 2);
253cabdff1aSopenharmony_ci            U[w >> 1] = src[4] + 0x80;
254cabdff1aSopenharmony_ci            V[w >> 1] = src[5] + 0x80;
255cabdff1aSopenharmony_ci            src += 6;
256cabdff1aSopenharmony_ci        }
257cabdff1aSopenharmony_ci        if (hmargin) {
258cabdff1aSopenharmony_ci            Y1[width + 1] = src[0];
259cabdff1aSopenharmony_ci            Y2[width + 1] = src[1];
260cabdff1aSopenharmony_ci            U[huvborder] = src[2] + 0x80;
261cabdff1aSopenharmony_ci            V[huvborder] = src[3] + 0x80;
262cabdff1aSopenharmony_ci            src += 4;
263cabdff1aSopenharmony_ci        }
264cabdff1aSopenharmony_ci        Y1 += pic->linesize[0] * 2;
265cabdff1aSopenharmony_ci        Y2 += pic->linesize[0] * 2;
266cabdff1aSopenharmony_ci        U  += pic->linesize[1];
267cabdff1aSopenharmony_ci        V  += pic->linesize[2];
268cabdff1aSopenharmony_ci    }
269cabdff1aSopenharmony_ci
270cabdff1aSopenharmony_ci    if (vmargin) {
271cabdff1aSopenharmony_ci        for (w = 0; w < width; w += 2) {
272cabdff1aSopenharmony_ci            AV_COPY16U(Y1 + w, src);
273cabdff1aSopenharmony_ci            U[w >> 1] = src[0] + 0x80;
274cabdff1aSopenharmony_ci            V[w >> 1] = src[1] + 0x80;
275cabdff1aSopenharmony_ci            src += 4;
276cabdff1aSopenharmony_ci        }
277cabdff1aSopenharmony_ci        if (hmargin) {
278cabdff1aSopenharmony_ci            Y1[w] = src[0];
279cabdff1aSopenharmony_ci            U[huvborder] = src[1] + 0x80;
280cabdff1aSopenharmony_ci            V[huvborder] = src[2] + 0x80;
281cabdff1aSopenharmony_ci            src += 3;
282cabdff1aSopenharmony_ci        }
283cabdff1aSopenharmony_ci    }
284cabdff1aSopenharmony_ci
285cabdff1aSopenharmony_ci    do_vflip(avctx, pic, vflipped);
286cabdff1aSopenharmony_ci
287cabdff1aSopenharmony_ci    return 0;
288cabdff1aSopenharmony_ci}
289cabdff1aSopenharmony_ci
290cabdff1aSopenharmony_cistatic int dxtory_decode_v1_444(AVCodecContext *avctx, AVFrame *pic,
291cabdff1aSopenharmony_ci                                const uint8_t *src, int src_size,
292cabdff1aSopenharmony_ci                                uint32_t vflipped)
293cabdff1aSopenharmony_ci{
294cabdff1aSopenharmony_ci    int h, w;
295cabdff1aSopenharmony_ci    uint8_t *Y, *U, *V;
296cabdff1aSopenharmony_ci    int ret;
297cabdff1aSopenharmony_ci
298cabdff1aSopenharmony_ci    if (src_size < get_raw_size(AV_PIX_FMT_YUV444P, avctx->width, avctx->height)) {
299cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "packet too small\n");
300cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
301cabdff1aSopenharmony_ci    }
302cabdff1aSopenharmony_ci
303cabdff1aSopenharmony_ci    avctx->pix_fmt = AV_PIX_FMT_YUV444P;
304cabdff1aSopenharmony_ci    if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0)
305cabdff1aSopenharmony_ci        return ret;
306cabdff1aSopenharmony_ci
307cabdff1aSopenharmony_ci    do_vflip(avctx, pic, vflipped);
308cabdff1aSopenharmony_ci
309cabdff1aSopenharmony_ci    Y = pic->data[0];
310cabdff1aSopenharmony_ci    U = pic->data[1];
311cabdff1aSopenharmony_ci    V = pic->data[2];
312cabdff1aSopenharmony_ci    for (h = 0; h < avctx->height; h++) {
313cabdff1aSopenharmony_ci        for (w = 0; w < avctx->width; w++) {
314cabdff1aSopenharmony_ci            Y[w] = *src++;
315cabdff1aSopenharmony_ci            U[w] = *src++ ^ 0x80;
316cabdff1aSopenharmony_ci            V[w] = *src++ ^ 0x80;
317cabdff1aSopenharmony_ci        }
318cabdff1aSopenharmony_ci        Y += pic->linesize[0];
319cabdff1aSopenharmony_ci        U += pic->linesize[1];
320cabdff1aSopenharmony_ci        V += pic->linesize[2];
321cabdff1aSopenharmony_ci    }
322cabdff1aSopenharmony_ci
323cabdff1aSopenharmony_ci    do_vflip(avctx, pic, vflipped);
324cabdff1aSopenharmony_ci
325cabdff1aSopenharmony_ci    return 0;
326cabdff1aSopenharmony_ci}
327cabdff1aSopenharmony_ci
328cabdff1aSopenharmony_cistatic const uint8_t def_lru[8] = { 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xFF };
329cabdff1aSopenharmony_cistatic const uint8_t def_lru_555[8] = { 0x00, 0x08, 0x10, 0x18, 0x1F };
330cabdff1aSopenharmony_cistatic const uint8_t def_lru_565[8] = { 0x00, 0x08, 0x10, 0x20, 0x30, 0x3F };
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_cistatic inline uint8_t decode_sym(GetBitContext *gb, uint8_t lru[8])
333cabdff1aSopenharmony_ci{
334cabdff1aSopenharmony_ci    uint8_t c, val;
335cabdff1aSopenharmony_ci
336cabdff1aSopenharmony_ci    c = get_unary(gb, 0, 8);
337cabdff1aSopenharmony_ci    if (!c) {
338cabdff1aSopenharmony_ci        val = get_bits(gb, 8);
339cabdff1aSopenharmony_ci        memmove(lru + 1, lru, sizeof(*lru) * (8 - 1));
340cabdff1aSopenharmony_ci    } else {
341cabdff1aSopenharmony_ci        val = lru[c - 1];
342cabdff1aSopenharmony_ci        memmove(lru + 1, lru, sizeof(*lru) * (c - 1));
343cabdff1aSopenharmony_ci    }
344cabdff1aSopenharmony_ci    lru[0] = val;
345cabdff1aSopenharmony_ci
346cabdff1aSopenharmony_ci    return val;
347cabdff1aSopenharmony_ci}
348cabdff1aSopenharmony_ci
349cabdff1aSopenharmony_cistatic int check_slice_size(AVCodecContext *avctx,
350cabdff1aSopenharmony_ci                            const uint8_t *src, int src_size,
351cabdff1aSopenharmony_ci                            int slice_size, int off)
352cabdff1aSopenharmony_ci{
353cabdff1aSopenharmony_ci    int cur_slice_size;
354cabdff1aSopenharmony_ci
355cabdff1aSopenharmony_ci    if (slice_size > src_size - off) {
356cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
357cabdff1aSopenharmony_ci               "invalid slice size %d (only %d bytes left)\n",
358cabdff1aSopenharmony_ci               slice_size, src_size - off);
359cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
360cabdff1aSopenharmony_ci    }
361cabdff1aSopenharmony_ci    if (slice_size <= 16) {
362cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "invalid slice size %d\n",
363cabdff1aSopenharmony_ci               slice_size);
364cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
365cabdff1aSopenharmony_ci    }
366cabdff1aSopenharmony_ci
367cabdff1aSopenharmony_ci    cur_slice_size = AV_RL32(src + off);
368cabdff1aSopenharmony_ci    if (cur_slice_size != slice_size - 16) {
369cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
370cabdff1aSopenharmony_ci               "Slice sizes mismatch: got %d instead of %d\n",
371cabdff1aSopenharmony_ci               cur_slice_size, slice_size - 16);
372cabdff1aSopenharmony_ci    }
373cabdff1aSopenharmony_ci
374cabdff1aSopenharmony_ci    return 0;
375cabdff1aSopenharmony_ci}
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_cistatic int load_buffer(AVCodecContext *avctx,
378cabdff1aSopenharmony_ci                       const uint8_t *src, int src_size,
379cabdff1aSopenharmony_ci                       GetByteContext *gb,
380cabdff1aSopenharmony_ci                       int *nslices, int *off)
381cabdff1aSopenharmony_ci{
382cabdff1aSopenharmony_ci    bytestream2_init(gb, src, src_size);
383cabdff1aSopenharmony_ci    *nslices = bytestream2_get_le16(gb);
384cabdff1aSopenharmony_ci    *off = FFALIGN(*nslices * 4 + 2, 16);
385cabdff1aSopenharmony_ci    if (src_size < *off) {
386cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "no slice data\n");
387cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
388cabdff1aSopenharmony_ci    }
389cabdff1aSopenharmony_ci
390cabdff1aSopenharmony_ci    if (!*nslices) {
391cabdff1aSopenharmony_ci        avpriv_request_sample(avctx, "%d slices for %dx%d", *nslices,
392cabdff1aSopenharmony_ci                              avctx->width, avctx->height);
393cabdff1aSopenharmony_ci        return AVERROR_PATCHWELCOME;
394cabdff1aSopenharmony_ci    }
395cabdff1aSopenharmony_ci
396cabdff1aSopenharmony_ci    return 0;
397cabdff1aSopenharmony_ci}
398cabdff1aSopenharmony_ci
399cabdff1aSopenharmony_cistatic inline uint8_t decode_sym_565(GetBitContext *gb, uint8_t lru[8],
400cabdff1aSopenharmony_ci                                     int bits)
401cabdff1aSopenharmony_ci{
402cabdff1aSopenharmony_ci    uint8_t c, val;
403cabdff1aSopenharmony_ci
404cabdff1aSopenharmony_ci    c = get_unary(gb, 0, bits);
405cabdff1aSopenharmony_ci    if (!c) {
406cabdff1aSopenharmony_ci        val = get_bits(gb, bits);
407cabdff1aSopenharmony_ci        memmove(lru + 1, lru, sizeof(*lru) * (6 - 1));
408cabdff1aSopenharmony_ci    } else {
409cabdff1aSopenharmony_ci        val = lru[c - 1];
410cabdff1aSopenharmony_ci        memmove(lru + 1, lru, sizeof(*lru) * (c - 1));
411cabdff1aSopenharmony_ci    }
412cabdff1aSopenharmony_ci    lru[0] = val;
413cabdff1aSopenharmony_ci
414cabdff1aSopenharmony_ci    return val;
415cabdff1aSopenharmony_ci}
416cabdff1aSopenharmony_ci
417cabdff1aSopenharmony_citypedef int (*decode_slice_func)(GetBitContext *gb, AVFrame *frame,
418cabdff1aSopenharmony_ci                                 int line, int height, uint8_t lru[3][8]);
419cabdff1aSopenharmony_ci
420cabdff1aSopenharmony_citypedef void (*setup_lru_func)(uint8_t lru[3][8]);
421cabdff1aSopenharmony_ci
422cabdff1aSopenharmony_cistatic int dxtory_decode_v2(AVCodecContext *avctx, AVFrame *pic,
423cabdff1aSopenharmony_ci                            const uint8_t *src, int src_size,
424cabdff1aSopenharmony_ci                            decode_slice_func decode_slice,
425cabdff1aSopenharmony_ci                            setup_lru_func setup_lru,
426cabdff1aSopenharmony_ci                            enum AVPixelFormat fmt,
427cabdff1aSopenharmony_ci                            uint32_t vflipped)
428cabdff1aSopenharmony_ci{
429cabdff1aSopenharmony_ci    GetByteContext gb, gb_check;
430cabdff1aSopenharmony_ci    GetBitContext  gb2;
431cabdff1aSopenharmony_ci    int nslices, slice, line = 0;
432cabdff1aSopenharmony_ci    uint32_t off, slice_size;
433cabdff1aSopenharmony_ci    uint64_t off_check;
434cabdff1aSopenharmony_ci    uint8_t lru[3][8];
435cabdff1aSopenharmony_ci    int ret;
436cabdff1aSopenharmony_ci
437cabdff1aSopenharmony_ci    ret = load_buffer(avctx, src, src_size, &gb, &nslices, &off);
438cabdff1aSopenharmony_ci    if (ret < 0)
439cabdff1aSopenharmony_ci        return ret;
440cabdff1aSopenharmony_ci
441cabdff1aSopenharmony_ci    off_check = off;
442cabdff1aSopenharmony_ci    gb_check = gb;
443cabdff1aSopenharmony_ci    for (slice = 0; slice < nslices; slice++) {
444cabdff1aSopenharmony_ci        slice_size = bytestream2_get_le32(&gb_check);
445cabdff1aSopenharmony_ci
446cabdff1aSopenharmony_ci        if (slice_size <= 16 + (avctx->height * avctx->width / (8 * nslices)))
447cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
448cabdff1aSopenharmony_ci        off_check += slice_size;
449cabdff1aSopenharmony_ci    }
450cabdff1aSopenharmony_ci
451cabdff1aSopenharmony_ci    if (off_check - avctx->discard_damaged_percentage*off_check/100 > src_size)
452cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
453cabdff1aSopenharmony_ci
454cabdff1aSopenharmony_ci    avctx->pix_fmt = fmt;
455cabdff1aSopenharmony_ci    if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0)
456cabdff1aSopenharmony_ci        return ret;
457cabdff1aSopenharmony_ci
458cabdff1aSopenharmony_ci    do_vflip(avctx, pic, vflipped);
459cabdff1aSopenharmony_ci
460cabdff1aSopenharmony_ci    for (slice = 0; slice < nslices; slice++) {
461cabdff1aSopenharmony_ci        slice_size = bytestream2_get_le32(&gb);
462cabdff1aSopenharmony_ci
463cabdff1aSopenharmony_ci        setup_lru(lru);
464cabdff1aSopenharmony_ci
465cabdff1aSopenharmony_ci        ret = check_slice_size(avctx, src, src_size, slice_size, off);
466cabdff1aSopenharmony_ci        if (ret < 0)
467cabdff1aSopenharmony_ci            return ret;
468cabdff1aSopenharmony_ci
469cabdff1aSopenharmony_ci        if ((ret = init_get_bits8(&gb2, src + off + 16, slice_size - 16)) < 0)
470cabdff1aSopenharmony_ci            return ret;
471cabdff1aSopenharmony_ci
472cabdff1aSopenharmony_ci        line += decode_slice(&gb2, pic, line, avctx->height - line, lru);
473cabdff1aSopenharmony_ci
474cabdff1aSopenharmony_ci        off += slice_size;
475cabdff1aSopenharmony_ci    }
476cabdff1aSopenharmony_ci
477cabdff1aSopenharmony_ci    if (avctx->height - line) {
478cabdff1aSopenharmony_ci        avpriv_request_sample(avctx, "Not enough slice data available");
479cabdff1aSopenharmony_ci    }
480cabdff1aSopenharmony_ci
481cabdff1aSopenharmony_ci    do_vflip(avctx, pic, vflipped);
482cabdff1aSopenharmony_ci
483cabdff1aSopenharmony_ci    return 0;
484cabdff1aSopenharmony_ci}
485cabdff1aSopenharmony_ci
486cabdff1aSopenharmony_ciav_always_inline
487cabdff1aSopenharmony_cistatic int dx2_decode_slice_5x5(GetBitContext *gb, AVFrame *frame,
488cabdff1aSopenharmony_ci                                int line, int left, uint8_t lru[3][8],
489cabdff1aSopenharmony_ci                                int is_565)
490cabdff1aSopenharmony_ci{
491cabdff1aSopenharmony_ci    int x, y;
492cabdff1aSopenharmony_ci    int r, g, b;
493cabdff1aSopenharmony_ci    int width    = frame->width;
494cabdff1aSopenharmony_ci    int stride   = frame->linesize[0];
495cabdff1aSopenharmony_ci    uint8_t *dst = frame->data[0] + stride * line;
496cabdff1aSopenharmony_ci
497cabdff1aSopenharmony_ci    for (y = 0; y < left && get_bits_left(gb) >= 3 * width; y++) {
498cabdff1aSopenharmony_ci        for (x = 0; x < width; x++) {
499cabdff1aSopenharmony_ci            b = decode_sym_565(gb, lru[0], 5);
500cabdff1aSopenharmony_ci            g = decode_sym_565(gb, lru[1], is_565 ? 6 : 5);
501cabdff1aSopenharmony_ci            r = decode_sym_565(gb, lru[2], 5);
502cabdff1aSopenharmony_ci            dst[x * 3 + 0] = (r << 3) | (r >> 2);
503cabdff1aSopenharmony_ci            dst[x * 3 + 1] = is_565 ? (g << 2) | (g >> 4) : (g << 3) | (g >> 2);
504cabdff1aSopenharmony_ci            dst[x * 3 + 2] = (b << 3) | (b >> 2);
505cabdff1aSopenharmony_ci        }
506cabdff1aSopenharmony_ci
507cabdff1aSopenharmony_ci        dst += stride;
508cabdff1aSopenharmony_ci    }
509cabdff1aSopenharmony_ci
510cabdff1aSopenharmony_ci    return y;
511cabdff1aSopenharmony_ci}
512cabdff1aSopenharmony_ci
513cabdff1aSopenharmony_cistatic void setup_lru_555(uint8_t lru[3][8])
514cabdff1aSopenharmony_ci{
515cabdff1aSopenharmony_ci    memcpy(lru[0], def_lru_555, 8 * sizeof(*def_lru));
516cabdff1aSopenharmony_ci    memcpy(lru[1], def_lru_555, 8 * sizeof(*def_lru));
517cabdff1aSopenharmony_ci    memcpy(lru[2], def_lru_555, 8 * sizeof(*def_lru));
518cabdff1aSopenharmony_ci}
519cabdff1aSopenharmony_ci
520cabdff1aSopenharmony_cistatic void setup_lru_565(uint8_t lru[3][8])
521cabdff1aSopenharmony_ci{
522cabdff1aSopenharmony_ci    memcpy(lru[0], def_lru_555, 8 * sizeof(*def_lru));
523cabdff1aSopenharmony_ci    memcpy(lru[1], def_lru_565, 8 * sizeof(*def_lru));
524cabdff1aSopenharmony_ci    memcpy(lru[2], def_lru_555, 8 * sizeof(*def_lru));
525cabdff1aSopenharmony_ci}
526cabdff1aSopenharmony_ci
527cabdff1aSopenharmony_cistatic int dx2_decode_slice_555(GetBitContext *gb, AVFrame *frame,
528cabdff1aSopenharmony_ci                                int line, int left, uint8_t lru[3][8])
529cabdff1aSopenharmony_ci{
530cabdff1aSopenharmony_ci    return dx2_decode_slice_5x5(gb, frame, line, left, lru, 0);
531cabdff1aSopenharmony_ci}
532cabdff1aSopenharmony_ci
533cabdff1aSopenharmony_cistatic int dx2_decode_slice_565(GetBitContext *gb, AVFrame *frame,
534cabdff1aSopenharmony_ci                                int line, int left, uint8_t lru[3][8])
535cabdff1aSopenharmony_ci{
536cabdff1aSopenharmony_ci    return dx2_decode_slice_5x5(gb, frame, line, left, lru, 1);
537cabdff1aSopenharmony_ci}
538cabdff1aSopenharmony_ci
539cabdff1aSopenharmony_cistatic int dxtory_decode_v2_565(AVCodecContext *avctx, AVFrame *pic,
540cabdff1aSopenharmony_ci                                const uint8_t *src, int src_size, int is_565,
541cabdff1aSopenharmony_ci                                uint32_t vflipped)
542cabdff1aSopenharmony_ci{
543cabdff1aSopenharmony_ci    enum AVPixelFormat fmt = AV_PIX_FMT_RGB24;
544cabdff1aSopenharmony_ci    if (is_565)
545cabdff1aSopenharmony_ci        return dxtory_decode_v2(avctx, pic, src, src_size,
546cabdff1aSopenharmony_ci                                dx2_decode_slice_565,
547cabdff1aSopenharmony_ci                                setup_lru_565,
548cabdff1aSopenharmony_ci                                fmt, vflipped);
549cabdff1aSopenharmony_ci    else
550cabdff1aSopenharmony_ci        return dxtory_decode_v2(avctx, pic, src, src_size,
551cabdff1aSopenharmony_ci                                dx2_decode_slice_555,
552cabdff1aSopenharmony_ci                                setup_lru_555,
553cabdff1aSopenharmony_ci                                fmt, vflipped);
554cabdff1aSopenharmony_ci}
555cabdff1aSopenharmony_ci
556cabdff1aSopenharmony_cistatic int dx2_decode_slice_rgb(GetBitContext *gb, AVFrame *frame,
557cabdff1aSopenharmony_ci                                int line, int left, uint8_t lru[3][8])
558cabdff1aSopenharmony_ci{
559cabdff1aSopenharmony_ci    int x, y;
560cabdff1aSopenharmony_ci    int width    = frame->width;
561cabdff1aSopenharmony_ci    int stride   = frame->linesize[0];
562cabdff1aSopenharmony_ci    uint8_t *dst = frame->data[0] + stride * line;
563cabdff1aSopenharmony_ci
564cabdff1aSopenharmony_ci    for (y = 0; y < left && get_bits_left(gb) >= 3 * width; y++) {
565cabdff1aSopenharmony_ci        for (x = 0; x < width; x++) {
566cabdff1aSopenharmony_ci            dst[x * 3 + 0] = decode_sym(gb, lru[0]);
567cabdff1aSopenharmony_ci            dst[x * 3 + 1] = decode_sym(gb, lru[1]);
568cabdff1aSopenharmony_ci            dst[x * 3 + 2] = decode_sym(gb, lru[2]);
569cabdff1aSopenharmony_ci        }
570cabdff1aSopenharmony_ci
571cabdff1aSopenharmony_ci        dst += stride;
572cabdff1aSopenharmony_ci    }
573cabdff1aSopenharmony_ci
574cabdff1aSopenharmony_ci    return y;
575cabdff1aSopenharmony_ci}
576cabdff1aSopenharmony_ci
577cabdff1aSopenharmony_cistatic void default_setup_lru(uint8_t lru[3][8])
578cabdff1aSopenharmony_ci{
579cabdff1aSopenharmony_ci    int i;
580cabdff1aSopenharmony_ci
581cabdff1aSopenharmony_ci    for (i = 0; i < 3; i++)
582cabdff1aSopenharmony_ci        memcpy(lru[i], def_lru, 8 * sizeof(*def_lru));
583cabdff1aSopenharmony_ci}
584cabdff1aSopenharmony_ci
585cabdff1aSopenharmony_cistatic int dxtory_decode_v2_rgb(AVCodecContext *avctx, AVFrame *pic,
586cabdff1aSopenharmony_ci                                const uint8_t *src, int src_size,
587cabdff1aSopenharmony_ci                                uint32_t vflipped)
588cabdff1aSopenharmony_ci{
589cabdff1aSopenharmony_ci    return dxtory_decode_v2(avctx, pic, src, src_size,
590cabdff1aSopenharmony_ci                            dx2_decode_slice_rgb,
591cabdff1aSopenharmony_ci                            default_setup_lru,
592cabdff1aSopenharmony_ci                            AV_PIX_FMT_BGR24, vflipped);
593cabdff1aSopenharmony_ci}
594cabdff1aSopenharmony_ci
595cabdff1aSopenharmony_cistatic int dx2_decode_slice_410(GetBitContext *gb, AVFrame *frame,
596cabdff1aSopenharmony_ci                                int line, int left,
597cabdff1aSopenharmony_ci                                uint8_t lru[3][8])
598cabdff1aSopenharmony_ci{
599cabdff1aSopenharmony_ci    int x, y, i, j;
600cabdff1aSopenharmony_ci    int width   = frame->width;
601cabdff1aSopenharmony_ci
602cabdff1aSopenharmony_ci    int ystride = frame->linesize[0];
603cabdff1aSopenharmony_ci    int ustride = frame->linesize[1];
604cabdff1aSopenharmony_ci    int vstride = frame->linesize[2];
605cabdff1aSopenharmony_ci
606cabdff1aSopenharmony_ci    uint8_t *Y  = frame->data[0] + ystride * line;
607cabdff1aSopenharmony_ci    uint8_t *U  = frame->data[1] + (ustride >> 2) * line;
608cabdff1aSopenharmony_ci    uint8_t *V  = frame->data[2] + (vstride >> 2) * line;
609cabdff1aSopenharmony_ci
610cabdff1aSopenharmony_ci    int h, w, hmargin, vmargin;
611cabdff1aSopenharmony_ci    int huvborder;
612cabdff1aSopenharmony_ci
613cabdff1aSopenharmony_ci    h = frame->height & ~3;
614cabdff1aSopenharmony_ci    w = frame->width  & ~3;
615cabdff1aSopenharmony_ci    hmargin = frame->width  - w;
616cabdff1aSopenharmony_ci    vmargin = frame->height - h;
617cabdff1aSopenharmony_ci    huvborder = AV_CEIL_RSHIFT(frame->width, 2) - 1;
618cabdff1aSopenharmony_ci
619cabdff1aSopenharmony_ci    for (y = 0; y < left - 3 && get_bits_left(gb) >= 18 * w / 4 + hmargin * 4 + (!!hmargin * 2); y += 4) {
620cabdff1aSopenharmony_ci        for (x = 0; x < w; x += 4) {
621cabdff1aSopenharmony_ci            for (j = 0; j < 4; j++)
622cabdff1aSopenharmony_ci                for (i = 0; i < 4; i++)
623cabdff1aSopenharmony_ci                    Y[x + i + j * ystride] = decode_sym(gb, lru[0]);
624cabdff1aSopenharmony_ci            U[x >> 2] = decode_sym(gb, lru[1]) ^ 0x80;
625cabdff1aSopenharmony_ci            V[x >> 2] = decode_sym(gb, lru[2]) ^ 0x80;
626cabdff1aSopenharmony_ci        }
627cabdff1aSopenharmony_ci        if (hmargin) {
628cabdff1aSopenharmony_ci            for (j = 0; j < 4; j++)
629cabdff1aSopenharmony_ci                for (i = 0; i < hmargin; i++)
630cabdff1aSopenharmony_ci                    Y[x + i + j * ystride] = decode_sym(gb, lru[0]);
631cabdff1aSopenharmony_ci            U[huvborder] = decode_sym(gb, lru[1]) ^ 0x80;
632cabdff1aSopenharmony_ci            V[huvborder] = decode_sym(gb, lru[2]) ^ 0x80;
633cabdff1aSopenharmony_ci        }
634cabdff1aSopenharmony_ci
635cabdff1aSopenharmony_ci        Y += ystride * 4;
636cabdff1aSopenharmony_ci        U += ustride;
637cabdff1aSopenharmony_ci        V += vstride;
638cabdff1aSopenharmony_ci    }
639cabdff1aSopenharmony_ci
640cabdff1aSopenharmony_ci    if (vmargin && y + vmargin == left) {
641cabdff1aSopenharmony_ci        for (x = 0; x < width; x += 4) {
642cabdff1aSopenharmony_ci            for (j = 0; j < vmargin; j++)
643cabdff1aSopenharmony_ci                for (i = 0; i < 4; i++)
644cabdff1aSopenharmony_ci                    Y[x + i + j * ystride] = decode_sym(gb, lru[0]);
645cabdff1aSopenharmony_ci            U[x >> 2] = decode_sym(gb, lru[1]) ^ 0x80;
646cabdff1aSopenharmony_ci            V[x >> 2] = decode_sym(gb, lru[2]) ^ 0x80;
647cabdff1aSopenharmony_ci        }
648cabdff1aSopenharmony_ci        if (hmargin) {
649cabdff1aSopenharmony_ci            for (j = 0; j < vmargin; j++) {
650cabdff1aSopenharmony_ci                for (i = 0; i < hmargin; i++)
651cabdff1aSopenharmony_ci                    Y[x + i + j * ystride] = decode_sym(gb, lru[0]);
652cabdff1aSopenharmony_ci            }
653cabdff1aSopenharmony_ci            U[huvborder] = decode_sym(gb, lru[1]) ^ 0x80;
654cabdff1aSopenharmony_ci            V[huvborder] = decode_sym(gb, lru[2]) ^ 0x80;
655cabdff1aSopenharmony_ci        }
656cabdff1aSopenharmony_ci
657cabdff1aSopenharmony_ci        y += vmargin;
658cabdff1aSopenharmony_ci    }
659cabdff1aSopenharmony_ci
660cabdff1aSopenharmony_ci    return y;
661cabdff1aSopenharmony_ci}
662cabdff1aSopenharmony_ci
663cabdff1aSopenharmony_ci
664cabdff1aSopenharmony_cistatic int dxtory_decode_v2_410(AVCodecContext *avctx, AVFrame *pic,
665cabdff1aSopenharmony_ci                                const uint8_t *src, int src_size,
666cabdff1aSopenharmony_ci                                uint32_t vflipped)
667cabdff1aSopenharmony_ci{
668cabdff1aSopenharmony_ci    return dxtory_decode_v2(avctx, pic, src, src_size,
669cabdff1aSopenharmony_ci                            dx2_decode_slice_410,
670cabdff1aSopenharmony_ci                            default_setup_lru,
671cabdff1aSopenharmony_ci                            AV_PIX_FMT_YUV410P, vflipped);
672cabdff1aSopenharmony_ci}
673cabdff1aSopenharmony_ci
674cabdff1aSopenharmony_cistatic int dx2_decode_slice_420(GetBitContext *gb, AVFrame *frame,
675cabdff1aSopenharmony_ci                                int line, int left,
676cabdff1aSopenharmony_ci                                uint8_t lru[3][8])
677cabdff1aSopenharmony_ci{
678cabdff1aSopenharmony_ci    int x, y;
679cabdff1aSopenharmony_ci
680cabdff1aSopenharmony_ci    int width    = frame->width;
681cabdff1aSopenharmony_ci
682cabdff1aSopenharmony_ci    int ystride = frame->linesize[0];
683cabdff1aSopenharmony_ci    int ustride = frame->linesize[1];
684cabdff1aSopenharmony_ci    int vstride = frame->linesize[2];
685cabdff1aSopenharmony_ci
686cabdff1aSopenharmony_ci    uint8_t *Y  = frame->data[0] + ystride * line;
687cabdff1aSopenharmony_ci    uint8_t *U  = frame->data[1] + (ustride >> 1) * line;
688cabdff1aSopenharmony_ci    uint8_t *V  = frame->data[2] + (vstride >> 1) * line;
689cabdff1aSopenharmony_ci
690cabdff1aSopenharmony_ci    int h, w, hmargin, vmargin;
691cabdff1aSopenharmony_ci    int huvborder;
692cabdff1aSopenharmony_ci
693cabdff1aSopenharmony_ci    h = frame->height & ~1;
694cabdff1aSopenharmony_ci    w = frame->width  & ~1;
695cabdff1aSopenharmony_ci    hmargin = frame->width  - w;
696cabdff1aSopenharmony_ci    vmargin = frame->height - h;
697cabdff1aSopenharmony_ci    huvborder = AV_CEIL_RSHIFT(frame->width, 1) - 1;
698cabdff1aSopenharmony_ci
699cabdff1aSopenharmony_ci    for (y = 0; y < left - 1 && get_bits_left(gb) >= 3 * w + hmargin * 4; y += 2) {
700cabdff1aSopenharmony_ci        for (x = 0; x < w; x += 2) {
701cabdff1aSopenharmony_ci            Y[x + 0 + 0 * ystride] = decode_sym(gb, lru[0]);
702cabdff1aSopenharmony_ci            Y[x + 1 + 0 * ystride] = decode_sym(gb, lru[0]);
703cabdff1aSopenharmony_ci            Y[x + 0 + 1 * ystride] = decode_sym(gb, lru[0]);
704cabdff1aSopenharmony_ci            Y[x + 1 + 1 * ystride] = decode_sym(gb, lru[0]);
705cabdff1aSopenharmony_ci            U[x >> 1] = decode_sym(gb, lru[1]) ^ 0x80;
706cabdff1aSopenharmony_ci            V[x >> 1] = decode_sym(gb, lru[2]) ^ 0x80;
707cabdff1aSopenharmony_ci        }
708cabdff1aSopenharmony_ci        if (hmargin) {
709cabdff1aSopenharmony_ci            Y[x + 0 * ystride] = decode_sym(gb, lru[0]);
710cabdff1aSopenharmony_ci            Y[x + 1 * ystride] = decode_sym(gb, lru[0]);
711cabdff1aSopenharmony_ci            U[huvborder] = decode_sym(gb, lru[1]) ^ 0x80;
712cabdff1aSopenharmony_ci            V[huvborder] = decode_sym(gb, lru[2]) ^ 0x80;
713cabdff1aSopenharmony_ci        }
714cabdff1aSopenharmony_ci
715cabdff1aSopenharmony_ci        Y += ystride * 2;
716cabdff1aSopenharmony_ci        U += ustride;
717cabdff1aSopenharmony_ci        V += vstride;
718cabdff1aSopenharmony_ci    }
719cabdff1aSopenharmony_ci
720cabdff1aSopenharmony_ci    if (vmargin) {
721cabdff1aSopenharmony_ci        for (x = 0; x < width; x += 2) {
722cabdff1aSopenharmony_ci            Y[x + 0]  = decode_sym(gb, lru[0]);
723cabdff1aSopenharmony_ci            U[x >> 1] = decode_sym(gb, lru[1]) ^ 0x80;
724cabdff1aSopenharmony_ci            V[x >> 1] = decode_sym(gb, lru[2]) ^ 0x80;
725cabdff1aSopenharmony_ci        }
726cabdff1aSopenharmony_ci        if (hmargin) {
727cabdff1aSopenharmony_ci            Y[x]         = decode_sym(gb, lru[0]);
728cabdff1aSopenharmony_ci            U[huvborder] = decode_sym(gb, lru[1]) ^ 0x80;
729cabdff1aSopenharmony_ci            V[huvborder] = decode_sym(gb, lru[2]) ^ 0x80;
730cabdff1aSopenharmony_ci        }
731cabdff1aSopenharmony_ci    }
732cabdff1aSopenharmony_ci
733cabdff1aSopenharmony_ci    return y;
734cabdff1aSopenharmony_ci}
735cabdff1aSopenharmony_ci
736cabdff1aSopenharmony_cistatic int dxtory_decode_v2_420(AVCodecContext *avctx, AVFrame *pic,
737cabdff1aSopenharmony_ci                                const uint8_t *src, int src_size,
738cabdff1aSopenharmony_ci                                uint32_t vflipped)
739cabdff1aSopenharmony_ci{
740cabdff1aSopenharmony_ci    return dxtory_decode_v2(avctx, pic, src, src_size,
741cabdff1aSopenharmony_ci                            dx2_decode_slice_420,
742cabdff1aSopenharmony_ci                            default_setup_lru,
743cabdff1aSopenharmony_ci                            AV_PIX_FMT_YUV420P, vflipped);
744cabdff1aSopenharmony_ci}
745cabdff1aSopenharmony_ci
746cabdff1aSopenharmony_cistatic int dx2_decode_slice_444(GetBitContext *gb, AVFrame *frame,
747cabdff1aSopenharmony_ci                                int line, int left,
748cabdff1aSopenharmony_ci                                uint8_t lru[3][8])
749cabdff1aSopenharmony_ci{
750cabdff1aSopenharmony_ci    int x, y;
751cabdff1aSopenharmony_ci
752cabdff1aSopenharmony_ci    int width   = frame->width;
753cabdff1aSopenharmony_ci
754cabdff1aSopenharmony_ci    int ystride = frame->linesize[0];
755cabdff1aSopenharmony_ci    int ustride = frame->linesize[1];
756cabdff1aSopenharmony_ci    int vstride = frame->linesize[2];
757cabdff1aSopenharmony_ci
758cabdff1aSopenharmony_ci    uint8_t *Y  = frame->data[0] + ystride * line;
759cabdff1aSopenharmony_ci    uint8_t *U  = frame->data[1] + ustride * line;
760cabdff1aSopenharmony_ci    uint8_t *V  = frame->data[2] + vstride * line;
761cabdff1aSopenharmony_ci
762cabdff1aSopenharmony_ci    for (y = 0; y < left && get_bits_left(gb) >= 3 * width; y++) {
763cabdff1aSopenharmony_ci        for (x = 0; x < width; x++) {
764cabdff1aSopenharmony_ci            Y[x] = decode_sym(gb, lru[0]);
765cabdff1aSopenharmony_ci            U[x] = decode_sym(gb, lru[1]) ^ 0x80;
766cabdff1aSopenharmony_ci            V[x] = decode_sym(gb, lru[2]) ^ 0x80;
767cabdff1aSopenharmony_ci        }
768cabdff1aSopenharmony_ci
769cabdff1aSopenharmony_ci        Y += ystride;
770cabdff1aSopenharmony_ci        U += ustride;
771cabdff1aSopenharmony_ci        V += vstride;
772cabdff1aSopenharmony_ci    }
773cabdff1aSopenharmony_ci
774cabdff1aSopenharmony_ci    return y;
775cabdff1aSopenharmony_ci}
776cabdff1aSopenharmony_ci
777cabdff1aSopenharmony_cistatic int dxtory_decode_v2_444(AVCodecContext *avctx, AVFrame *pic,
778cabdff1aSopenharmony_ci                                const uint8_t *src, int src_size,
779cabdff1aSopenharmony_ci                                uint32_t vflipped)
780cabdff1aSopenharmony_ci{
781cabdff1aSopenharmony_ci    return dxtory_decode_v2(avctx, pic, src, src_size,
782cabdff1aSopenharmony_ci                            dx2_decode_slice_444,
783cabdff1aSopenharmony_ci                            default_setup_lru,
784cabdff1aSopenharmony_ci                            AV_PIX_FMT_YUV444P, vflipped);
785cabdff1aSopenharmony_ci}
786cabdff1aSopenharmony_ci
787cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *pic,
788cabdff1aSopenharmony_ci                        int *got_frame, AVPacket *avpkt)
789cabdff1aSopenharmony_ci{
790cabdff1aSopenharmony_ci    const uint8_t *src = avpkt->data;
791cabdff1aSopenharmony_ci    uint32_t type;
792cabdff1aSopenharmony_ci    int vflipped, ret;
793cabdff1aSopenharmony_ci
794cabdff1aSopenharmony_ci    if (avpkt->size < 16) {
795cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "packet too small\n");
796cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
797cabdff1aSopenharmony_ci    }
798cabdff1aSopenharmony_ci
799cabdff1aSopenharmony_ci    type = AV_RB32(src);
800cabdff1aSopenharmony_ci    vflipped = !!(type & 0x20);
801cabdff1aSopenharmony_ci
802cabdff1aSopenharmony_ci    switch (type) {
803cabdff1aSopenharmony_ci    case 0x01000021:
804cabdff1aSopenharmony_ci    case 0x01000001:
805cabdff1aSopenharmony_ci        ret = dxtory_decode_v1_rgb(avctx, pic, src + 16, avpkt->size - 16,
806cabdff1aSopenharmony_ci                                   AV_PIX_FMT_BGR24, 3, vflipped);
807cabdff1aSopenharmony_ci        break;
808cabdff1aSopenharmony_ci    case 0x01000029:
809cabdff1aSopenharmony_ci    case 0x01000009:
810cabdff1aSopenharmony_ci        ret = dxtory_decode_v2_rgb(avctx, pic, src + 16, avpkt->size - 16, vflipped);
811cabdff1aSopenharmony_ci        break;
812cabdff1aSopenharmony_ci    case 0x02000021:
813cabdff1aSopenharmony_ci    case 0x02000001:
814cabdff1aSopenharmony_ci        ret = dxtory_decode_v1_420(avctx, pic, src + 16, avpkt->size - 16, vflipped);
815cabdff1aSopenharmony_ci        break;
816cabdff1aSopenharmony_ci    case 0x02000029:
817cabdff1aSopenharmony_ci    case 0x02000009:
818cabdff1aSopenharmony_ci        ret = dxtory_decode_v2_420(avctx, pic, src + 16, avpkt->size - 16, vflipped);
819cabdff1aSopenharmony_ci        break;
820cabdff1aSopenharmony_ci    case 0x03000021:
821cabdff1aSopenharmony_ci    case 0x03000001:
822cabdff1aSopenharmony_ci        ret = dxtory_decode_v1_410(avctx, pic, src + 16, avpkt->size - 16, vflipped);
823cabdff1aSopenharmony_ci        break;
824cabdff1aSopenharmony_ci    case 0x03000029:
825cabdff1aSopenharmony_ci    case 0x03000009:
826cabdff1aSopenharmony_ci        ret = dxtory_decode_v2_410(avctx, pic, src + 16, avpkt->size - 16, vflipped);
827cabdff1aSopenharmony_ci        break;
828cabdff1aSopenharmony_ci    case 0x04000021:
829cabdff1aSopenharmony_ci    case 0x04000001:
830cabdff1aSopenharmony_ci        ret = dxtory_decode_v1_444(avctx, pic, src + 16, avpkt->size - 16, vflipped);
831cabdff1aSopenharmony_ci        break;
832cabdff1aSopenharmony_ci    case 0x04000029:
833cabdff1aSopenharmony_ci    case 0x04000009:
834cabdff1aSopenharmony_ci        ret = dxtory_decode_v2_444(avctx, pic, src + 16, avpkt->size - 16, vflipped);
835cabdff1aSopenharmony_ci        break;
836cabdff1aSopenharmony_ci    case 0x17000021:
837cabdff1aSopenharmony_ci    case 0x17000001:
838cabdff1aSopenharmony_ci        ret = dxtory_decode_v1_rgb(avctx, pic, src + 16, avpkt->size - 16,
839cabdff1aSopenharmony_ci                                   AV_PIX_FMT_RGB565LE, 2, vflipped);
840cabdff1aSopenharmony_ci        break;
841cabdff1aSopenharmony_ci    case 0x17000029:
842cabdff1aSopenharmony_ci    case 0x17000009:
843cabdff1aSopenharmony_ci        ret = dxtory_decode_v2_565(avctx, pic, src + 16, avpkt->size - 16, 1, vflipped);
844cabdff1aSopenharmony_ci        break;
845cabdff1aSopenharmony_ci    case 0x18000021:
846cabdff1aSopenharmony_ci    case 0x19000021:
847cabdff1aSopenharmony_ci    case 0x18000001:
848cabdff1aSopenharmony_ci    case 0x19000001:
849cabdff1aSopenharmony_ci        ret = dxtory_decode_v1_rgb(avctx, pic, src + 16, avpkt->size - 16,
850cabdff1aSopenharmony_ci                                   AV_PIX_FMT_RGB555LE, 2, vflipped);
851cabdff1aSopenharmony_ci        break;
852cabdff1aSopenharmony_ci    case 0x18000029:
853cabdff1aSopenharmony_ci    case 0x19000029:
854cabdff1aSopenharmony_ci    case 0x18000009:
855cabdff1aSopenharmony_ci    case 0x19000009:
856cabdff1aSopenharmony_ci        ret = dxtory_decode_v2_565(avctx, pic, src + 16, avpkt->size - 16, 0, vflipped);
857cabdff1aSopenharmony_ci        break;
858cabdff1aSopenharmony_ci    default:
859cabdff1aSopenharmony_ci        avpriv_request_sample(avctx, "Frame header %"PRIX32, type);
860cabdff1aSopenharmony_ci        return AVERROR_PATCHWELCOME;
861cabdff1aSopenharmony_ci    }
862cabdff1aSopenharmony_ci
863cabdff1aSopenharmony_ci    if (ret)
864cabdff1aSopenharmony_ci        return ret;
865cabdff1aSopenharmony_ci
866cabdff1aSopenharmony_ci    pic->pict_type = AV_PICTURE_TYPE_I;
867cabdff1aSopenharmony_ci    pic->key_frame = 1;
868cabdff1aSopenharmony_ci    *got_frame = 1;
869cabdff1aSopenharmony_ci
870cabdff1aSopenharmony_ci    return avpkt->size;
871cabdff1aSopenharmony_ci}
872cabdff1aSopenharmony_ci
873cabdff1aSopenharmony_ciconst FFCodec ff_dxtory_decoder = {
874cabdff1aSopenharmony_ci    .p.name         = "dxtory",
875cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Dxtory"),
876cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
877cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_DXTORY,
878cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(decode_frame),
879cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
880cabdff1aSopenharmony_ci};
881