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