xref: /third_party/ffmpeg/libavcodec/dds.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * DirectDraw Surface image decoder
3cabdff1aSopenharmony_ci * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/**
23cabdff1aSopenharmony_ci * @file
24cabdff1aSopenharmony_ci * DDS decoder
25cabdff1aSopenharmony_ci *
26cabdff1aSopenharmony_ci * https://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx
27cabdff1aSopenharmony_ci */
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci#include <stdint.h>
30cabdff1aSopenharmony_ci
31cabdff1aSopenharmony_ci#include "libavutil/libm.h"
32cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_ci#include "avcodec.h"
35cabdff1aSopenharmony_ci#include "bytestream.h"
36cabdff1aSopenharmony_ci#include "codec_internal.h"
37cabdff1aSopenharmony_ci#include "internal.h"
38cabdff1aSopenharmony_ci#include "texturedsp.h"
39cabdff1aSopenharmony_ci#include "thread.h"
40cabdff1aSopenharmony_ci
41cabdff1aSopenharmony_ci#define DDPF_FOURCC    (1 <<  2)
42cabdff1aSopenharmony_ci#define DDPF_PALETTE   (1 <<  5)
43cabdff1aSopenharmony_ci#define DDPF_NORMALMAP (1U << 31)
44cabdff1aSopenharmony_ci
45cabdff1aSopenharmony_cienum DDSPostProc {
46cabdff1aSopenharmony_ci    DDS_NONE = 0,
47cabdff1aSopenharmony_ci    DDS_ALPHA_EXP,
48cabdff1aSopenharmony_ci    DDS_NORMAL_MAP,
49cabdff1aSopenharmony_ci    DDS_RAW_YCOCG,
50cabdff1aSopenharmony_ci    DDS_SWAP_ALPHA,
51cabdff1aSopenharmony_ci    DDS_SWIZZLE_A2XY,
52cabdff1aSopenharmony_ci    DDS_SWIZZLE_RBXG,
53cabdff1aSopenharmony_ci    DDS_SWIZZLE_RGXB,
54cabdff1aSopenharmony_ci    DDS_SWIZZLE_RXBG,
55cabdff1aSopenharmony_ci    DDS_SWIZZLE_RXGB,
56cabdff1aSopenharmony_ci    DDS_SWIZZLE_XGBR,
57cabdff1aSopenharmony_ci    DDS_SWIZZLE_XRBG,
58cabdff1aSopenharmony_ci    DDS_SWIZZLE_XGXR,
59cabdff1aSopenharmony_ci};
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_cienum DDSDXGIFormat {
62cabdff1aSopenharmony_ci    DXGI_FORMAT_R16G16B16A16_TYPELESS       =  9,
63cabdff1aSopenharmony_ci    DXGI_FORMAT_R16G16B16A16_FLOAT          = 10,
64cabdff1aSopenharmony_ci    DXGI_FORMAT_R16G16B16A16_UNORM          = 11,
65cabdff1aSopenharmony_ci    DXGI_FORMAT_R16G16B16A16_UINT           = 12,
66cabdff1aSopenharmony_ci    DXGI_FORMAT_R16G16B16A16_SNORM          = 13,
67cabdff1aSopenharmony_ci    DXGI_FORMAT_R16G16B16A16_SINT           = 14,
68cabdff1aSopenharmony_ci
69cabdff1aSopenharmony_ci    DXGI_FORMAT_R8G8B8A8_TYPELESS           = 27,
70cabdff1aSopenharmony_ci    DXGI_FORMAT_R8G8B8A8_UNORM              = 28,
71cabdff1aSopenharmony_ci    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB         = 29,
72cabdff1aSopenharmony_ci    DXGI_FORMAT_R8G8B8A8_UINT               = 30,
73cabdff1aSopenharmony_ci    DXGI_FORMAT_R8G8B8A8_SNORM              = 31,
74cabdff1aSopenharmony_ci    DXGI_FORMAT_R8G8B8A8_SINT               = 32,
75cabdff1aSopenharmony_ci
76cabdff1aSopenharmony_ci    DXGI_FORMAT_BC1_TYPELESS                = 70,
77cabdff1aSopenharmony_ci    DXGI_FORMAT_BC1_UNORM                   = 71,
78cabdff1aSopenharmony_ci    DXGI_FORMAT_BC1_UNORM_SRGB              = 72,
79cabdff1aSopenharmony_ci    DXGI_FORMAT_BC2_TYPELESS                = 73,
80cabdff1aSopenharmony_ci    DXGI_FORMAT_BC2_UNORM                   = 74,
81cabdff1aSopenharmony_ci    DXGI_FORMAT_BC2_UNORM_SRGB              = 75,
82cabdff1aSopenharmony_ci    DXGI_FORMAT_BC3_TYPELESS                = 76,
83cabdff1aSopenharmony_ci    DXGI_FORMAT_BC3_UNORM                   = 77,
84cabdff1aSopenharmony_ci    DXGI_FORMAT_BC3_UNORM_SRGB              = 78,
85cabdff1aSopenharmony_ci    DXGI_FORMAT_BC4_TYPELESS                = 79,
86cabdff1aSopenharmony_ci    DXGI_FORMAT_BC4_UNORM                   = 80,
87cabdff1aSopenharmony_ci    DXGI_FORMAT_BC4_SNORM                   = 81,
88cabdff1aSopenharmony_ci    DXGI_FORMAT_BC5_TYPELESS                = 82,
89cabdff1aSopenharmony_ci    DXGI_FORMAT_BC5_UNORM                   = 83,
90cabdff1aSopenharmony_ci    DXGI_FORMAT_BC5_SNORM                   = 84,
91cabdff1aSopenharmony_ci    DXGI_FORMAT_B5G6R5_UNORM                = 85,
92cabdff1aSopenharmony_ci    DXGI_FORMAT_B8G8R8A8_UNORM              = 87,
93cabdff1aSopenharmony_ci    DXGI_FORMAT_B8G8R8X8_UNORM              = 88,
94cabdff1aSopenharmony_ci    DXGI_FORMAT_B8G8R8A8_TYPELESS           = 90,
95cabdff1aSopenharmony_ci    DXGI_FORMAT_B8G8R8A8_UNORM_SRGB         = 91,
96cabdff1aSopenharmony_ci    DXGI_FORMAT_B8G8R8X8_TYPELESS           = 92,
97cabdff1aSopenharmony_ci    DXGI_FORMAT_B8G8R8X8_UNORM_SRGB         = 93,
98cabdff1aSopenharmony_ci};
99cabdff1aSopenharmony_ci
100cabdff1aSopenharmony_citypedef struct DDSContext {
101cabdff1aSopenharmony_ci    TextureDSPContext texdsp;
102cabdff1aSopenharmony_ci    GetByteContext gbc;
103cabdff1aSopenharmony_ci
104cabdff1aSopenharmony_ci    int compressed;
105cabdff1aSopenharmony_ci    int paletted;
106cabdff1aSopenharmony_ci    int bpp;
107cabdff1aSopenharmony_ci    enum DDSPostProc postproc;
108cabdff1aSopenharmony_ci
109cabdff1aSopenharmony_ci    TextureDSPThreadContext dec;
110cabdff1aSopenharmony_ci} DDSContext;
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_cistatic int parse_pixel_format(AVCodecContext *avctx)
113cabdff1aSopenharmony_ci{
114cabdff1aSopenharmony_ci    DDSContext *ctx = avctx->priv_data;
115cabdff1aSopenharmony_ci    GetByteContext *gbc = &ctx->gbc;
116cabdff1aSopenharmony_ci    uint32_t flags, fourcc, gimp_tag;
117cabdff1aSopenharmony_ci    enum DDSDXGIFormat dxgi;
118cabdff1aSopenharmony_ci    int size, bpp, r, g, b, a;
119cabdff1aSopenharmony_ci    int alpha_exponent, ycocg_classic, ycocg_scaled, normal_map, array;
120cabdff1aSopenharmony_ci
121cabdff1aSopenharmony_ci    /* Alternative DDS implementations use reserved1 as custom header. */
122cabdff1aSopenharmony_ci    bytestream2_skip(gbc, 4 * 3);
123cabdff1aSopenharmony_ci    gimp_tag = bytestream2_get_le32(gbc);
124cabdff1aSopenharmony_ci    alpha_exponent = gimp_tag == MKTAG('A', 'E', 'X', 'P');
125cabdff1aSopenharmony_ci    ycocg_classic  = gimp_tag == MKTAG('Y', 'C', 'G', '1');
126cabdff1aSopenharmony_ci    ycocg_scaled   = gimp_tag == MKTAG('Y', 'C', 'G', '2');
127cabdff1aSopenharmony_ci    bytestream2_skip(gbc, 4 * 7);
128cabdff1aSopenharmony_ci
129cabdff1aSopenharmony_ci    /* Now the real DDPF starts. */
130cabdff1aSopenharmony_ci    size = bytestream2_get_le32(gbc);
131cabdff1aSopenharmony_ci    if (size != 32) {
132cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid pixel format header %d.\n", size);
133cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
134cabdff1aSopenharmony_ci    }
135cabdff1aSopenharmony_ci    flags = bytestream2_get_le32(gbc);
136cabdff1aSopenharmony_ci    ctx->compressed = flags & DDPF_FOURCC;
137cabdff1aSopenharmony_ci    ctx->paletted   = flags & DDPF_PALETTE;
138cabdff1aSopenharmony_ci    normal_map      = flags & DDPF_NORMALMAP;
139cabdff1aSopenharmony_ci    fourcc = bytestream2_get_le32(gbc);
140cabdff1aSopenharmony_ci
141cabdff1aSopenharmony_ci    if (ctx->compressed && ctx->paletted) {
142cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_WARNING,
143cabdff1aSopenharmony_ci               "Disabling invalid palette flag for compressed dds.\n");
144cabdff1aSopenharmony_ci        ctx->paletted = 0;
145cabdff1aSopenharmony_ci    }
146cabdff1aSopenharmony_ci
147cabdff1aSopenharmony_ci    bpp = ctx->bpp = bytestream2_get_le32(gbc); // rgbbitcount
148cabdff1aSopenharmony_ci    r   = bytestream2_get_le32(gbc); // rbitmask
149cabdff1aSopenharmony_ci    g   = bytestream2_get_le32(gbc); // gbitmask
150cabdff1aSopenharmony_ci    b   = bytestream2_get_le32(gbc); // bbitmask
151cabdff1aSopenharmony_ci    a   = bytestream2_get_le32(gbc); // abitmask
152cabdff1aSopenharmony_ci
153cabdff1aSopenharmony_ci    bytestream2_skip(gbc, 4); // caps
154cabdff1aSopenharmony_ci    bytestream2_skip(gbc, 4); // caps2
155cabdff1aSopenharmony_ci    bytestream2_skip(gbc, 4); // caps3
156cabdff1aSopenharmony_ci    bytestream2_skip(gbc, 4); // caps4
157cabdff1aSopenharmony_ci    bytestream2_skip(gbc, 4); // reserved2
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    av_log(avctx, AV_LOG_VERBOSE, "fourcc %s bpp %d "
160cabdff1aSopenharmony_ci           "r 0x%x g 0x%x b 0x%x a 0x%x\n", av_fourcc2str(fourcc), bpp, r, g, b, a);
161cabdff1aSopenharmony_ci    if (gimp_tag)
162cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "and GIMP-DDS tag %s\n", av_fourcc2str(gimp_tag));
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_ci    if (ctx->compressed)
165cabdff1aSopenharmony_ci        avctx->pix_fmt = AV_PIX_FMT_RGBA;
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_ci    if (ctx->compressed) {
168cabdff1aSopenharmony_ci        ctx->dec.raw_ratio = 16;
169cabdff1aSopenharmony_ci        switch (fourcc) {
170cabdff1aSopenharmony_ci        case MKTAG('D', 'X', 'T', '1'):
171cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 8;
172cabdff1aSopenharmony_ci            ctx->dec.tex_funct = ctx->texdsp.dxt1a_block;
173cabdff1aSopenharmony_ci            break;
174cabdff1aSopenharmony_ci        case MKTAG('D', 'X', 'T', '2'):
175cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 16;
176cabdff1aSopenharmony_ci            ctx->dec.tex_funct = ctx->texdsp.dxt2_block;
177cabdff1aSopenharmony_ci            break;
178cabdff1aSopenharmony_ci        case MKTAG('D', 'X', 'T', '3'):
179cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 16;
180cabdff1aSopenharmony_ci            ctx->dec.tex_funct = ctx->texdsp.dxt3_block;
181cabdff1aSopenharmony_ci            break;
182cabdff1aSopenharmony_ci        case MKTAG('D', 'X', 'T', '4'):
183cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 16;
184cabdff1aSopenharmony_ci            ctx->dec.tex_funct = ctx->texdsp.dxt4_block;
185cabdff1aSopenharmony_ci            break;
186cabdff1aSopenharmony_ci        case MKTAG('D', 'X', 'T', '5'):
187cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 16;
188cabdff1aSopenharmony_ci            if (ycocg_scaled)
189cabdff1aSopenharmony_ci                ctx->dec.tex_funct = ctx->texdsp.dxt5ys_block;
190cabdff1aSopenharmony_ci            else if (ycocg_classic)
191cabdff1aSopenharmony_ci                ctx->dec.tex_funct = ctx->texdsp.dxt5y_block;
192cabdff1aSopenharmony_ci            else
193cabdff1aSopenharmony_ci                ctx->dec.tex_funct = ctx->texdsp.dxt5_block;
194cabdff1aSopenharmony_ci            break;
195cabdff1aSopenharmony_ci        case MKTAG('R', 'X', 'G', 'B'):
196cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 16;
197cabdff1aSopenharmony_ci            ctx->dec.tex_funct = ctx->texdsp.dxt5_block;
198cabdff1aSopenharmony_ci            /* This format may be considered as a normal map,
199cabdff1aSopenharmony_ci             * but it is handled differently in a separate postproc. */
200cabdff1aSopenharmony_ci            ctx->postproc = DDS_SWIZZLE_RXGB;
201cabdff1aSopenharmony_ci            normal_map = 0;
202cabdff1aSopenharmony_ci            break;
203cabdff1aSopenharmony_ci        case MKTAG('A', 'T', 'I', '1'):
204cabdff1aSopenharmony_ci        case MKTAG('B', 'C', '4', 'U'):
205cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 8;
206cabdff1aSopenharmony_ci            ctx->dec.tex_funct = ctx->texdsp.rgtc1u_block;
207cabdff1aSopenharmony_ci            break;
208cabdff1aSopenharmony_ci        case MKTAG('B', 'C', '4', 'S'):
209cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 8;
210cabdff1aSopenharmony_ci            ctx->dec.tex_funct = ctx->texdsp.rgtc1s_block;
211cabdff1aSopenharmony_ci            break;
212cabdff1aSopenharmony_ci        case MKTAG('A', 'T', 'I', '2'):
213cabdff1aSopenharmony_ci            /* RGT2 variant with swapped R and G (3Dc)*/
214cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 16;
215cabdff1aSopenharmony_ci            ctx->dec.tex_funct = ctx->texdsp.dxn3dc_block;
216cabdff1aSopenharmony_ci            break;
217cabdff1aSopenharmony_ci        case MKTAG('B', 'C', '5', 'U'):
218cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 16;
219cabdff1aSopenharmony_ci            ctx->dec.tex_funct = ctx->texdsp.rgtc2u_block;
220cabdff1aSopenharmony_ci            break;
221cabdff1aSopenharmony_ci        case MKTAG('B', 'C', '5', 'S'):
222cabdff1aSopenharmony_ci            ctx->dec.tex_ratio = 16;
223cabdff1aSopenharmony_ci            ctx->dec.tex_funct = ctx->texdsp.rgtc2s_block;
224cabdff1aSopenharmony_ci            break;
225cabdff1aSopenharmony_ci        case MKTAG('U', 'Y', 'V', 'Y'):
226cabdff1aSopenharmony_ci            ctx->compressed = 0;
227cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_UYVY422;
228cabdff1aSopenharmony_ci            break;
229cabdff1aSopenharmony_ci        case MKTAG('Y', 'U', 'Y', '2'):
230cabdff1aSopenharmony_ci            ctx->compressed = 0;
231cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_YUYV422;
232cabdff1aSopenharmony_ci            break;
233cabdff1aSopenharmony_ci        case MKTAG('P', '8', ' ', ' '):
234cabdff1aSopenharmony_ci            /* ATI Palette8, same as normal palette */
235cabdff1aSopenharmony_ci            ctx->compressed = 0;
236cabdff1aSopenharmony_ci            ctx->paletted   = 1;
237cabdff1aSopenharmony_ci            avctx->pix_fmt  = AV_PIX_FMT_PAL8;
238cabdff1aSopenharmony_ci            break;
239cabdff1aSopenharmony_ci        case MKTAG('G', '1', ' ', ' '):
240cabdff1aSopenharmony_ci            ctx->compressed = 0;
241cabdff1aSopenharmony_ci            avctx->pix_fmt  = AV_PIX_FMT_MONOBLACK;
242cabdff1aSopenharmony_ci            break;
243cabdff1aSopenharmony_ci        case MKTAG('D', 'X', '1', '0'):
244cabdff1aSopenharmony_ci            /* DirectX 10 extra header */
245cabdff1aSopenharmony_ci            dxgi = bytestream2_get_le32(gbc);
246cabdff1aSopenharmony_ci            bytestream2_skip(gbc, 4); // resourceDimension
247cabdff1aSopenharmony_ci            bytestream2_skip(gbc, 4); // miscFlag
248cabdff1aSopenharmony_ci            array = bytestream2_get_le32(gbc);
249cabdff1aSopenharmony_ci            bytestream2_skip(gbc, 4); // miscFlag2
250cabdff1aSopenharmony_ci
251cabdff1aSopenharmony_ci            if (array != 0)
252cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_VERBOSE,
253cabdff1aSopenharmony_ci                       "Found array of size %d (ignored).\n", array);
254cabdff1aSopenharmony_ci
255cabdff1aSopenharmony_ci            /* Only BC[1-5] are actually compressed. */
256cabdff1aSopenharmony_ci            ctx->compressed = (dxgi >= 70) && (dxgi <= 84);
257cabdff1aSopenharmony_ci
258cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_VERBOSE, "DXGI format %d.\n", dxgi);
259cabdff1aSopenharmony_ci            switch (dxgi) {
260cabdff1aSopenharmony_ci            /* RGB types. */
261cabdff1aSopenharmony_ci            case DXGI_FORMAT_R16G16B16A16_TYPELESS:
262cabdff1aSopenharmony_ci            case DXGI_FORMAT_R16G16B16A16_FLOAT:
263cabdff1aSopenharmony_ci            case DXGI_FORMAT_R16G16B16A16_UNORM:
264cabdff1aSopenharmony_ci            case DXGI_FORMAT_R16G16B16A16_UINT:
265cabdff1aSopenharmony_ci            case DXGI_FORMAT_R16G16B16A16_SNORM:
266cabdff1aSopenharmony_ci            case DXGI_FORMAT_R16G16B16A16_SINT:
267cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_BGRA64;
268cabdff1aSopenharmony_ci                break;
269cabdff1aSopenharmony_ci            case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
270cabdff1aSopenharmony_ci                avctx->colorspace = AVCOL_SPC_RGB;
271cabdff1aSopenharmony_ci            case DXGI_FORMAT_R8G8B8A8_TYPELESS:
272cabdff1aSopenharmony_ci            case DXGI_FORMAT_R8G8B8A8_UNORM:
273cabdff1aSopenharmony_ci            case DXGI_FORMAT_R8G8B8A8_UINT:
274cabdff1aSopenharmony_ci            case DXGI_FORMAT_R8G8B8A8_SNORM:
275cabdff1aSopenharmony_ci            case DXGI_FORMAT_R8G8B8A8_SINT:
276cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_BGRA;
277cabdff1aSopenharmony_ci                break;
278cabdff1aSopenharmony_ci            case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
279cabdff1aSopenharmony_ci                avctx->colorspace = AVCOL_SPC_RGB;
280cabdff1aSopenharmony_ci            case DXGI_FORMAT_B8G8R8A8_TYPELESS:
281cabdff1aSopenharmony_ci            case DXGI_FORMAT_B8G8R8A8_UNORM:
282cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_RGBA;
283cabdff1aSopenharmony_ci                break;
284cabdff1aSopenharmony_ci            case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
285cabdff1aSopenharmony_ci                avctx->colorspace = AVCOL_SPC_RGB;
286cabdff1aSopenharmony_ci            case DXGI_FORMAT_B8G8R8X8_TYPELESS:
287cabdff1aSopenharmony_ci            case DXGI_FORMAT_B8G8R8X8_UNORM:
288cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_RGBA; // opaque
289cabdff1aSopenharmony_ci                break;
290cabdff1aSopenharmony_ci            case DXGI_FORMAT_B5G6R5_UNORM:
291cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_RGB565LE;
292cabdff1aSopenharmony_ci                break;
293cabdff1aSopenharmony_ci            /* Texture types. */
294cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC1_UNORM_SRGB:
295cabdff1aSopenharmony_ci                avctx->colorspace = AVCOL_SPC_RGB;
296cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC1_TYPELESS:
297cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC1_UNORM:
298cabdff1aSopenharmony_ci                ctx->dec.tex_ratio = 8;
299cabdff1aSopenharmony_ci                ctx->dec.tex_funct = ctx->texdsp.dxt1a_block;
300cabdff1aSopenharmony_ci                break;
301cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC2_UNORM_SRGB:
302cabdff1aSopenharmony_ci                avctx->colorspace = AVCOL_SPC_RGB;
303cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC2_TYPELESS:
304cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC2_UNORM:
305cabdff1aSopenharmony_ci                ctx->dec.tex_ratio = 16;
306cabdff1aSopenharmony_ci                ctx->dec.tex_funct = ctx->texdsp.dxt3_block;
307cabdff1aSopenharmony_ci                break;
308cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC3_UNORM_SRGB:
309cabdff1aSopenharmony_ci                avctx->colorspace = AVCOL_SPC_RGB;
310cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC3_TYPELESS:
311cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC3_UNORM:
312cabdff1aSopenharmony_ci                ctx->dec.tex_ratio = 16;
313cabdff1aSopenharmony_ci                ctx->dec.tex_funct = ctx->texdsp.dxt5_block;
314cabdff1aSopenharmony_ci                break;
315cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC4_TYPELESS:
316cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC4_UNORM:
317cabdff1aSopenharmony_ci                ctx->dec.tex_ratio = 8;
318cabdff1aSopenharmony_ci                ctx->dec.tex_funct = ctx->texdsp.rgtc1u_block;
319cabdff1aSopenharmony_ci                break;
320cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC4_SNORM:
321cabdff1aSopenharmony_ci                ctx->dec.tex_ratio = 8;
322cabdff1aSopenharmony_ci                ctx->dec.tex_funct = ctx->texdsp.rgtc1s_block;
323cabdff1aSopenharmony_ci                break;
324cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC5_TYPELESS:
325cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC5_UNORM:
326cabdff1aSopenharmony_ci                ctx->dec.tex_ratio = 16;
327cabdff1aSopenharmony_ci                ctx->dec.tex_funct = ctx->texdsp.rgtc2u_block;
328cabdff1aSopenharmony_ci                break;
329cabdff1aSopenharmony_ci            case DXGI_FORMAT_BC5_SNORM:
330cabdff1aSopenharmony_ci                ctx->dec.tex_ratio = 16;
331cabdff1aSopenharmony_ci                ctx->dec.tex_funct = ctx->texdsp.rgtc2s_block;
332cabdff1aSopenharmony_ci                break;
333cabdff1aSopenharmony_ci            default:
334cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR,
335cabdff1aSopenharmony_ci                       "Unsupported DXGI format %d.\n", dxgi);
336cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
337cabdff1aSopenharmony_ci            }
338cabdff1aSopenharmony_ci            break;
339cabdff1aSopenharmony_ci        default:
340cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unsupported %s fourcc.\n", av_fourcc2str(fourcc));
341cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
342cabdff1aSopenharmony_ci        }
343cabdff1aSopenharmony_ci    } else if (ctx->paletted) {
344cabdff1aSopenharmony_ci        if (bpp == 8) {
345cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_PAL8;
346cabdff1aSopenharmony_ci        } else {
347cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unsupported palette bpp %d.\n", bpp);
348cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
349cabdff1aSopenharmony_ci        }
350cabdff1aSopenharmony_ci    } else {
351cabdff1aSopenharmony_ci        /*  4 bpp */
352cabdff1aSopenharmony_ci        if (bpp == 4 && r == 0 && g == 0 && b == 0 && a == 0)
353cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_PAL8;
354cabdff1aSopenharmony_ci        /*  8 bpp */
355cabdff1aSopenharmony_ci        else if (bpp == 8 && r == 0xff && g == 0 && b == 0 && a == 0)
356cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_GRAY8;
357cabdff1aSopenharmony_ci        else if (bpp == 8 && r == 0 && g == 0 && b == 0 && a == 0xff)
358cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_GRAY8;
359cabdff1aSopenharmony_ci        /* 16 bpp */
360cabdff1aSopenharmony_ci        else if (bpp == 16 && r == 0xff && g == 0 && b == 0 && a == 0xff00)
361cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_YA8;
362cabdff1aSopenharmony_ci        else if (bpp == 16 && r == 0xff00 && g == 0 && b == 0 && a == 0xff) {
363cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_YA8;
364cabdff1aSopenharmony_ci            ctx->postproc = DDS_SWAP_ALPHA;
365cabdff1aSopenharmony_ci        }
366cabdff1aSopenharmony_ci        else if (bpp == 16 && r == 0xffff && g == 0 && b == 0 && a == 0)
367cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_GRAY16LE;
368cabdff1aSopenharmony_ci        else if (bpp == 16 && r == 0x7c00 && g == 0x3e0 && b == 0x1f && a == 0)
369cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
370cabdff1aSopenharmony_ci        else if (bpp == 16 && r == 0x7c00 && g == 0x3e0 && b == 0x1f && a == 0x8000)
371cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_RGB555LE; // alpha ignored
372cabdff1aSopenharmony_ci        else if (bpp == 16 && r == 0xf800 && g == 0x7e0 && b == 0x1f && a == 0)
373cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_RGB565LE;
374cabdff1aSopenharmony_ci        /* 24 bpp */
375cabdff1aSopenharmony_ci        else if (bpp == 24 && r == 0xff0000 && g == 0xff00 && b == 0xff && a == 0)
376cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_BGR24;
377cabdff1aSopenharmony_ci        /* 32 bpp */
378cabdff1aSopenharmony_ci        else if (bpp == 32 && r == 0xff0000 && g == 0xff00 && b == 0xff && a == 0)
379cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_BGR0; // opaque
380cabdff1aSopenharmony_ci        else if (bpp == 32 && r == 0xff && g == 0xff00 && b == 0xff0000 && a == 0)
381cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_RGB0; // opaque
382cabdff1aSopenharmony_ci        else if (bpp == 32 && r == 0xff0000 && g == 0xff00 && b == 0xff && a == 0xff000000)
383cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_BGRA;
384cabdff1aSopenharmony_ci        else if (bpp == 32 && r == 0xff && g == 0xff00 && b == 0xff0000 && a == 0xff000000)
385cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_RGBA;
386cabdff1aSopenharmony_ci        /* give up */
387cabdff1aSopenharmony_ci        else {
388cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unknown pixel format "
389cabdff1aSopenharmony_ci                   "[bpp %d r 0x%x g 0x%x b 0x%x a 0x%x].\n", bpp, r, g, b, a);
390cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
391cabdff1aSopenharmony_ci        }
392cabdff1aSopenharmony_ci    }
393cabdff1aSopenharmony_ci
394cabdff1aSopenharmony_ci    /* Set any remaining post-proc that should happen before frame is ready. */
395cabdff1aSopenharmony_ci    if (alpha_exponent)
396cabdff1aSopenharmony_ci        ctx->postproc = DDS_ALPHA_EXP;
397cabdff1aSopenharmony_ci    else if (normal_map)
398cabdff1aSopenharmony_ci        ctx->postproc = DDS_NORMAL_MAP;
399cabdff1aSopenharmony_ci    else if (ycocg_classic && !ctx->compressed)
400cabdff1aSopenharmony_ci        ctx->postproc = DDS_RAW_YCOCG;
401cabdff1aSopenharmony_ci
402cabdff1aSopenharmony_ci    /* ATI/NVidia variants sometimes add swizzling in bpp. */
403cabdff1aSopenharmony_ci    switch (bpp) {
404cabdff1aSopenharmony_ci    case MKTAG('A', '2', 'X', 'Y'):
405cabdff1aSopenharmony_ci        ctx->postproc = DDS_SWIZZLE_A2XY;
406cabdff1aSopenharmony_ci        break;
407cabdff1aSopenharmony_ci    case MKTAG('x', 'G', 'B', 'R'):
408cabdff1aSopenharmony_ci        ctx->postproc = DDS_SWIZZLE_XGBR;
409cabdff1aSopenharmony_ci        break;
410cabdff1aSopenharmony_ci    case MKTAG('x', 'R', 'B', 'G'):
411cabdff1aSopenharmony_ci        ctx->postproc = DDS_SWIZZLE_XRBG;
412cabdff1aSopenharmony_ci        break;
413cabdff1aSopenharmony_ci    case MKTAG('R', 'B', 'x', 'G'):
414cabdff1aSopenharmony_ci        ctx->postproc = DDS_SWIZZLE_RBXG;
415cabdff1aSopenharmony_ci        break;
416cabdff1aSopenharmony_ci    case MKTAG('R', 'G', 'x', 'B'):
417cabdff1aSopenharmony_ci        ctx->postproc = DDS_SWIZZLE_RGXB;
418cabdff1aSopenharmony_ci        break;
419cabdff1aSopenharmony_ci    case MKTAG('R', 'x', 'B', 'G'):
420cabdff1aSopenharmony_ci        ctx->postproc = DDS_SWIZZLE_RXBG;
421cabdff1aSopenharmony_ci        break;
422cabdff1aSopenharmony_ci    case MKTAG('x', 'G', 'x', 'R'):
423cabdff1aSopenharmony_ci        ctx->postproc = DDS_SWIZZLE_XGXR;
424cabdff1aSopenharmony_ci        break;
425cabdff1aSopenharmony_ci    case MKTAG('A', '2', 'D', '5'):
426cabdff1aSopenharmony_ci        ctx->postproc = DDS_NORMAL_MAP;
427cabdff1aSopenharmony_ci        break;
428cabdff1aSopenharmony_ci    }
429cabdff1aSopenharmony_ci
430cabdff1aSopenharmony_ci    return 0;
431cabdff1aSopenharmony_ci}
432cabdff1aSopenharmony_ci
433cabdff1aSopenharmony_cistatic void do_swizzle(AVFrame *frame, int x, int y)
434cabdff1aSopenharmony_ci{
435cabdff1aSopenharmony_ci    int i;
436cabdff1aSopenharmony_ci    for (i = 0; i < frame->linesize[0] * frame->height; i += 4) {
437cabdff1aSopenharmony_ci        uint8_t *src = frame->data[0] + i;
438cabdff1aSopenharmony_ci        FFSWAP(uint8_t, src[x], src[y]);
439cabdff1aSopenharmony_ci    }
440cabdff1aSopenharmony_ci}
441cabdff1aSopenharmony_ci
442cabdff1aSopenharmony_cistatic void run_postproc(AVCodecContext *avctx, AVFrame *frame)
443cabdff1aSopenharmony_ci{
444cabdff1aSopenharmony_ci    DDSContext *ctx = avctx->priv_data;
445cabdff1aSopenharmony_ci    int i, x_off;
446cabdff1aSopenharmony_ci
447cabdff1aSopenharmony_ci    switch (ctx->postproc) {
448cabdff1aSopenharmony_ci    case DDS_ALPHA_EXP:
449cabdff1aSopenharmony_ci        /* Alpha-exponential mode divides each channel by the maximum
450cabdff1aSopenharmony_ci         * R, G or B value, and stores the multiplying factor in the
451cabdff1aSopenharmony_ci         * alpha channel. */
452cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing alpha exponent.\n");
453cabdff1aSopenharmony_ci
454cabdff1aSopenharmony_ci        for (i = 0; i < frame->linesize[0] * frame->height; i += 4) {
455cabdff1aSopenharmony_ci            uint8_t *src = frame->data[0] + i;
456cabdff1aSopenharmony_ci            int r = src[0];
457cabdff1aSopenharmony_ci            int g = src[1];
458cabdff1aSopenharmony_ci            int b = src[2];
459cabdff1aSopenharmony_ci            int a = src[3];
460cabdff1aSopenharmony_ci
461cabdff1aSopenharmony_ci            src[0] = r * a / 255;
462cabdff1aSopenharmony_ci            src[1] = g * a / 255;
463cabdff1aSopenharmony_ci            src[2] = b * a / 255;
464cabdff1aSopenharmony_ci            src[3] = 255;
465cabdff1aSopenharmony_ci        }
466cabdff1aSopenharmony_ci        break;
467cabdff1aSopenharmony_ci    case DDS_NORMAL_MAP:
468cabdff1aSopenharmony_ci        /* Normal maps work in the XYZ color space and they encode
469cabdff1aSopenharmony_ci         * X in R or in A, depending on the texture type, Y in G and
470cabdff1aSopenharmony_ci         * derive Z with a square root of the distance.
471cabdff1aSopenharmony_ci         *
472cabdff1aSopenharmony_ci         * http://www.realtimecollisiondetection.net/blog/?p=28 */
473cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing normal map.\n");
474cabdff1aSopenharmony_ci
475cabdff1aSopenharmony_ci        x_off = ctx->dec.tex_ratio == 8 ? 0 : 3;
476cabdff1aSopenharmony_ci        for (i = 0; i < frame->linesize[0] * frame->height; i += 4) {
477cabdff1aSopenharmony_ci            uint8_t *src = frame->data[0] + i;
478cabdff1aSopenharmony_ci            int x = src[x_off];
479cabdff1aSopenharmony_ci            int y = src[1];
480cabdff1aSopenharmony_ci            int z = 127;
481cabdff1aSopenharmony_ci
482cabdff1aSopenharmony_ci            int d = (255 * 255 - x * x - y * y) / 2;
483cabdff1aSopenharmony_ci            if (d > 0)
484cabdff1aSopenharmony_ci                z = lrint(sqrtf(d));
485cabdff1aSopenharmony_ci
486cabdff1aSopenharmony_ci            src[0] = x;
487cabdff1aSopenharmony_ci            src[1] = y;
488cabdff1aSopenharmony_ci            src[2] = z;
489cabdff1aSopenharmony_ci            src[3] = 255;
490cabdff1aSopenharmony_ci        }
491cabdff1aSopenharmony_ci        break;
492cabdff1aSopenharmony_ci    case DDS_RAW_YCOCG:
493cabdff1aSopenharmony_ci        /* Data is Y-Co-Cg-A and not RGBA, but they are represented
494cabdff1aSopenharmony_ci         * with the same masks in the DDPF header. */
495cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing raw YCoCg.\n");
496cabdff1aSopenharmony_ci
497cabdff1aSopenharmony_ci        for (i = 0; i < frame->linesize[0] * frame->height; i += 4) {
498cabdff1aSopenharmony_ci            uint8_t *src = frame->data[0] + i;
499cabdff1aSopenharmony_ci            int a  = src[0];
500cabdff1aSopenharmony_ci            int cg = src[1] - 128;
501cabdff1aSopenharmony_ci            int co = src[2] - 128;
502cabdff1aSopenharmony_ci            int y  = src[3];
503cabdff1aSopenharmony_ci
504cabdff1aSopenharmony_ci            src[0] = av_clip_uint8(y + co - cg);
505cabdff1aSopenharmony_ci            src[1] = av_clip_uint8(y + cg);
506cabdff1aSopenharmony_ci            src[2] = av_clip_uint8(y - co - cg);
507cabdff1aSopenharmony_ci            src[3] = a;
508cabdff1aSopenharmony_ci        }
509cabdff1aSopenharmony_ci        break;
510cabdff1aSopenharmony_ci    case DDS_SWAP_ALPHA:
511cabdff1aSopenharmony_ci        /* Alpha and Luma are stored swapped. */
512cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing swapped Luma/Alpha.\n");
513cabdff1aSopenharmony_ci
514cabdff1aSopenharmony_ci        for (i = 0; i < frame->linesize[0] * frame->height; i += 2) {
515cabdff1aSopenharmony_ci            uint8_t *src = frame->data[0] + i;
516cabdff1aSopenharmony_ci            FFSWAP(uint8_t, src[0], src[1]);
517cabdff1aSopenharmony_ci        }
518cabdff1aSopenharmony_ci        break;
519cabdff1aSopenharmony_ci    case DDS_SWIZZLE_A2XY:
520cabdff1aSopenharmony_ci        /* Swap R and G, often used to restore a standard RGTC2. */
521cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing A2XY swizzle.\n");
522cabdff1aSopenharmony_ci        do_swizzle(frame, 0, 1);
523cabdff1aSopenharmony_ci        break;
524cabdff1aSopenharmony_ci    case DDS_SWIZZLE_RBXG:
525cabdff1aSopenharmony_ci        /* Swap G and A, then B and new A (G). */
526cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing RBXG swizzle.\n");
527cabdff1aSopenharmony_ci        do_swizzle(frame, 1, 3);
528cabdff1aSopenharmony_ci        do_swizzle(frame, 2, 3);
529cabdff1aSopenharmony_ci        break;
530cabdff1aSopenharmony_ci    case DDS_SWIZZLE_RGXB:
531cabdff1aSopenharmony_ci        /* Swap B and A. */
532cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing RGXB swizzle.\n");
533cabdff1aSopenharmony_ci        do_swizzle(frame, 2, 3);
534cabdff1aSopenharmony_ci        break;
535cabdff1aSopenharmony_ci    case DDS_SWIZZLE_RXBG:
536cabdff1aSopenharmony_ci        /* Swap G and A. */
537cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing RXBG swizzle.\n");
538cabdff1aSopenharmony_ci        do_swizzle(frame, 1, 3);
539cabdff1aSopenharmony_ci        break;
540cabdff1aSopenharmony_ci    case DDS_SWIZZLE_RXGB:
541cabdff1aSopenharmony_ci        /* Swap R and A (misleading name). */
542cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing RXGB swizzle.\n");
543cabdff1aSopenharmony_ci        do_swizzle(frame, 0, 3);
544cabdff1aSopenharmony_ci        break;
545cabdff1aSopenharmony_ci    case DDS_SWIZZLE_XGBR:
546cabdff1aSopenharmony_ci        /* Swap B and A, then R and new A (B). */
547cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing XGBR swizzle.\n");
548cabdff1aSopenharmony_ci        do_swizzle(frame, 2, 3);
549cabdff1aSopenharmony_ci        do_swizzle(frame, 0, 3);
550cabdff1aSopenharmony_ci        break;
551cabdff1aSopenharmony_ci    case DDS_SWIZZLE_XGXR:
552cabdff1aSopenharmony_ci        /* Swap G and A, then R and new A (G), then new R (G) and new G (A).
553cabdff1aSopenharmony_ci         * This variant does not store any B component. */
554cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing XGXR swizzle.\n");
555cabdff1aSopenharmony_ci        do_swizzle(frame, 1, 3);
556cabdff1aSopenharmony_ci        do_swizzle(frame, 0, 3);
557cabdff1aSopenharmony_ci        do_swizzle(frame, 0, 1);
558cabdff1aSopenharmony_ci        break;
559cabdff1aSopenharmony_ci    case DDS_SWIZZLE_XRBG:
560cabdff1aSopenharmony_ci        /* Swap G and A, then R and new A (G). */
561cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "Post-processing XRBG swizzle.\n");
562cabdff1aSopenharmony_ci        do_swizzle(frame, 1, 3);
563cabdff1aSopenharmony_ci        do_swizzle(frame, 0, 3);
564cabdff1aSopenharmony_ci        break;
565cabdff1aSopenharmony_ci    }
566cabdff1aSopenharmony_ci}
567cabdff1aSopenharmony_ci
568cabdff1aSopenharmony_cistatic int dds_decode(AVCodecContext *avctx, AVFrame *frame,
569cabdff1aSopenharmony_ci                      int *got_frame, AVPacket *avpkt)
570cabdff1aSopenharmony_ci{
571cabdff1aSopenharmony_ci    DDSContext *ctx = avctx->priv_data;
572cabdff1aSopenharmony_ci    GetByteContext *gbc = &ctx->gbc;
573cabdff1aSopenharmony_ci    int mipmap;
574cabdff1aSopenharmony_ci    int ret;
575cabdff1aSopenharmony_ci    int width, height;
576cabdff1aSopenharmony_ci
577cabdff1aSopenharmony_ci    ff_texturedsp_init(&ctx->texdsp);
578cabdff1aSopenharmony_ci    bytestream2_init(gbc, avpkt->data, avpkt->size);
579cabdff1aSopenharmony_ci
580cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gbc) < 128) {
581cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Frame is too small (%d).\n",
582cabdff1aSopenharmony_ci               bytestream2_get_bytes_left(gbc));
583cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
584cabdff1aSopenharmony_ci    }
585cabdff1aSopenharmony_ci
586cabdff1aSopenharmony_ci    if (bytestream2_get_le32(gbc) != MKTAG('D', 'D', 'S', ' ') ||
587cabdff1aSopenharmony_ci        bytestream2_get_le32(gbc) != 124) { // header size
588cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid DDS header.\n");
589cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
590cabdff1aSopenharmony_ci    }
591cabdff1aSopenharmony_ci
592cabdff1aSopenharmony_ci    bytestream2_skip(gbc, 4); // flags
593cabdff1aSopenharmony_ci
594cabdff1aSopenharmony_ci    height = bytestream2_get_le32(gbc);
595cabdff1aSopenharmony_ci    width  = bytestream2_get_le32(gbc);
596cabdff1aSopenharmony_ci    ret = ff_set_dimensions(avctx, width, height);
597cabdff1aSopenharmony_ci    if (ret < 0) {
598cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
599cabdff1aSopenharmony_ci               avctx->width, avctx->height);
600cabdff1aSopenharmony_ci        return ret;
601cabdff1aSopenharmony_ci    }
602cabdff1aSopenharmony_ci
603cabdff1aSopenharmony_ci    /* Since codec is based on 4x4 blocks, size is aligned to 4. */
604cabdff1aSopenharmony_ci    avctx->coded_width  = FFALIGN(avctx->width,  TEXTURE_BLOCK_W);
605cabdff1aSopenharmony_ci    avctx->coded_height = FFALIGN(avctx->height, TEXTURE_BLOCK_H);
606cabdff1aSopenharmony_ci
607cabdff1aSopenharmony_ci    bytestream2_skip(gbc, 4); // pitch
608cabdff1aSopenharmony_ci    bytestream2_skip(gbc, 4); // depth
609cabdff1aSopenharmony_ci    mipmap = bytestream2_get_le32(gbc);
610cabdff1aSopenharmony_ci    if (mipmap != 0)
611cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "Found %d mipmaps (ignored).\n", mipmap);
612cabdff1aSopenharmony_ci
613cabdff1aSopenharmony_ci    /* Extract pixel format information, considering additional elements
614cabdff1aSopenharmony_ci     * in reserved1 and reserved2. */
615cabdff1aSopenharmony_ci    ret = parse_pixel_format(avctx);
616cabdff1aSopenharmony_ci    if (ret < 0)
617cabdff1aSopenharmony_ci        return ret;
618cabdff1aSopenharmony_ci
619cabdff1aSopenharmony_ci    ret = ff_get_buffer(avctx, frame, 0);
620cabdff1aSopenharmony_ci    if (ret < 0)
621cabdff1aSopenharmony_ci        return ret;
622cabdff1aSopenharmony_ci
623cabdff1aSopenharmony_ci    if (ctx->compressed) {
624cabdff1aSopenharmony_ci        int size = (avctx->coded_height / TEXTURE_BLOCK_H) *
625cabdff1aSopenharmony_ci                   (avctx->coded_width / TEXTURE_BLOCK_W) * ctx->dec.tex_ratio;
626cabdff1aSopenharmony_ci        ctx->dec.slice_count = av_clip(avctx->thread_count, 1,
627cabdff1aSopenharmony_ci                                       avctx->coded_height / TEXTURE_BLOCK_H);
628cabdff1aSopenharmony_ci
629cabdff1aSopenharmony_ci        if (bytestream2_get_bytes_left(gbc) < size) {
630cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
631cabdff1aSopenharmony_ci                   "Compressed Buffer is too small (%d < %d).\n",
632cabdff1aSopenharmony_ci                   bytestream2_get_bytes_left(gbc), size);
633cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
634cabdff1aSopenharmony_ci        }
635cabdff1aSopenharmony_ci
636cabdff1aSopenharmony_ci        /* Use the decompress function on the texture, one block per thread. */
637cabdff1aSopenharmony_ci        ctx->dec.tex_data.in = gbc->buffer;
638cabdff1aSopenharmony_ci        ctx->dec.frame_data.out = frame->data[0];
639cabdff1aSopenharmony_ci        ctx->dec.stride = frame->linesize[0];
640cabdff1aSopenharmony_ci        avctx->execute2(avctx, ff_texturedsp_decompress_thread, &ctx->dec, NULL, ctx->dec.slice_count);
641cabdff1aSopenharmony_ci    } else if (!ctx->paletted && ctx->bpp == 4 && avctx->pix_fmt == AV_PIX_FMT_PAL8) {
642cabdff1aSopenharmony_ci        uint8_t *dst = frame->data[0];
643cabdff1aSopenharmony_ci        int x, y, i;
644cabdff1aSopenharmony_ci
645cabdff1aSopenharmony_ci        /* Use the first 64 bytes as palette, then copy the rest. */
646cabdff1aSopenharmony_ci        bytestream2_get_buffer(gbc, frame->data[1], 16 * 4);
647cabdff1aSopenharmony_ci        for (i = 0; i < 16; i++) {
648cabdff1aSopenharmony_ci            AV_WN32(frame->data[1] + i*4,
649cabdff1aSopenharmony_ci                    (frame->data[1][2+i*4]<<0)+
650cabdff1aSopenharmony_ci                    (frame->data[1][1+i*4]<<8)+
651cabdff1aSopenharmony_ci                    (frame->data[1][0+i*4]<<16)+
652cabdff1aSopenharmony_ci                    ((unsigned)frame->data[1][3+i*4]<<24)
653cabdff1aSopenharmony_ci            );
654cabdff1aSopenharmony_ci        }
655cabdff1aSopenharmony_ci        frame->palette_has_changed = 1;
656cabdff1aSopenharmony_ci
657cabdff1aSopenharmony_ci        if (bytestream2_get_bytes_left(gbc) < frame->height * frame->width / 2) {
658cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Buffer is too small (%d < %d).\n",
659cabdff1aSopenharmony_ci                   bytestream2_get_bytes_left(gbc), frame->height * frame->width / 2);
660cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
661cabdff1aSopenharmony_ci        }
662cabdff1aSopenharmony_ci
663cabdff1aSopenharmony_ci        for (y = 0; y < frame->height; y++) {
664cabdff1aSopenharmony_ci            for (x = 0; x < frame->width; x += 2) {
665cabdff1aSopenharmony_ci                uint8_t val = bytestream2_get_byte(gbc);
666cabdff1aSopenharmony_ci                dst[x    ] = val & 0xF;
667cabdff1aSopenharmony_ci                dst[x + 1] = val >> 4;
668cabdff1aSopenharmony_ci            }
669cabdff1aSopenharmony_ci            dst += frame->linesize[0];
670cabdff1aSopenharmony_ci        }
671cabdff1aSopenharmony_ci    } else {
672cabdff1aSopenharmony_ci        int linesize = av_image_get_linesize(avctx->pix_fmt, frame->width, 0);
673cabdff1aSopenharmony_ci
674cabdff1aSopenharmony_ci        if (ctx->paletted) {
675cabdff1aSopenharmony_ci            int i;
676cabdff1aSopenharmony_ci            /* Use the first 1024 bytes as palette, then copy the rest. */
677cabdff1aSopenharmony_ci            bytestream2_get_buffer(gbc, frame->data[1], 256 * 4);
678cabdff1aSopenharmony_ci            for (i = 0; i < 256; i++)
679cabdff1aSopenharmony_ci                AV_WN32(frame->data[1] + i*4,
680cabdff1aSopenharmony_ci                        (frame->data[1][2+i*4]<<0)+
681cabdff1aSopenharmony_ci                        (frame->data[1][1+i*4]<<8)+
682cabdff1aSopenharmony_ci                        (frame->data[1][0+i*4]<<16)+
683cabdff1aSopenharmony_ci                        ((unsigned)frame->data[1][3+i*4]<<24)
684cabdff1aSopenharmony_ci                );
685cabdff1aSopenharmony_ci
686cabdff1aSopenharmony_ci            frame->palette_has_changed = 1;
687cabdff1aSopenharmony_ci        }
688cabdff1aSopenharmony_ci
689cabdff1aSopenharmony_ci        if (bytestream2_get_bytes_left(gbc) < frame->height * linesize) {
690cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Buffer is too small (%d < %d).\n",
691cabdff1aSopenharmony_ci                   bytestream2_get_bytes_left(gbc), frame->height * linesize);
692cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
693cabdff1aSopenharmony_ci        }
694cabdff1aSopenharmony_ci
695cabdff1aSopenharmony_ci        av_image_copy_plane(frame->data[0], frame->linesize[0],
696cabdff1aSopenharmony_ci                            gbc->buffer, linesize,
697cabdff1aSopenharmony_ci                            linesize, frame->height);
698cabdff1aSopenharmony_ci    }
699cabdff1aSopenharmony_ci
700cabdff1aSopenharmony_ci    /* Run any post processing here if needed. */
701cabdff1aSopenharmony_ci    if (ctx->postproc != DDS_NONE)
702cabdff1aSopenharmony_ci        run_postproc(avctx, frame);
703cabdff1aSopenharmony_ci
704cabdff1aSopenharmony_ci    /* Frame is ready to be output. */
705cabdff1aSopenharmony_ci    frame->pict_type = AV_PICTURE_TYPE_I;
706cabdff1aSopenharmony_ci    frame->key_frame = 1;
707cabdff1aSopenharmony_ci    *got_frame = 1;
708cabdff1aSopenharmony_ci
709cabdff1aSopenharmony_ci    return avpkt->size;
710cabdff1aSopenharmony_ci}
711cabdff1aSopenharmony_ci
712cabdff1aSopenharmony_ciconst FFCodec ff_dds_decoder = {
713cabdff1aSopenharmony_ci    .p.name         = "dds",
714cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("DirectDraw Surface image decoder"),
715cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
716cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_DDS,
717cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(dds_decode),
718cabdff1aSopenharmony_ci    .priv_data_size = sizeof(DDSContext),
719cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS,
720cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE
721cabdff1aSopenharmony_ci};
722