1/* 2 * Renderware TeXture Dictionary (.txd) image decoder 3 * Copyright (c) 2007 Ivo van Poorten 4 * 5 * See also: http://wiki.multimedia.cx/index.php?title=TXD 6 * 7 * This file is part of FFmpeg. 8 * 9 * FFmpeg is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * FFmpeg is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with FFmpeg; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24#include "libavutil/intreadwrite.h" 25#include "libavutil/imgutils.h" 26#include "bytestream.h" 27#include "avcodec.h" 28#include "codec_internal.h" 29#include "internal.h" 30#include "texturedsp.h" 31 32#define TXD_DXT1 0x31545844 33#define TXD_DXT3 0x33545844 34 35static int txd_decode_frame(AVCodecContext *avctx, AVFrame *p, 36 int *got_frame, AVPacket *avpkt) 37{ 38 GetByteContext gb; 39 TextureDSPContext dxtc; 40 unsigned int version, w, h, d3d_format, depth, stride, flags; 41 unsigned int y, v; 42 uint8_t *ptr; 43 uint32_t *pal; 44 int i, j; 45 int ret; 46 47 if (avpkt->size < 88) 48 return AVERROR_INVALIDDATA; 49 50 ff_texturedsp_init(&dxtc); 51 52 bytestream2_init(&gb, avpkt->data, avpkt->size); 53 version = bytestream2_get_le32(&gb); 54 bytestream2_skip(&gb, 72); 55 d3d_format = bytestream2_get_le32(&gb); 56 w = bytestream2_get_le16(&gb); 57 h = bytestream2_get_le16(&gb); 58 depth = bytestream2_get_byte(&gb); 59 bytestream2_skip(&gb, 2); 60 flags = bytestream2_get_byte(&gb); 61 62 if (version < 8 || version > 9) { 63 avpriv_report_missing_feature(avctx, "Texture data version %u", version); 64 return AVERROR_PATCHWELCOME; 65 } 66 67 if (depth == 8) { 68 avctx->pix_fmt = AV_PIX_FMT_PAL8; 69 if (bytestream2_get_bytes_left(&gb) < w * h + 4 * 256) 70 return AVERROR_INVALIDDATA; 71 } else if (depth == 16) { 72 avctx->pix_fmt = AV_PIX_FMT_RGBA; 73 switch (d3d_format) { 74 case 0: 75 if (!(flags & 1)) 76 goto unsupported; 77 case TXD_DXT1: 78 if (bytestream2_get_bytes_left(&gb) < AV_CEIL_RSHIFT(w, 2) * AV_CEIL_RSHIFT(h, 2) * 8 + 4) 79 return AVERROR_INVALIDDATA; 80 break; 81 case TXD_DXT3: 82 if (bytestream2_get_bytes_left(&gb) < AV_CEIL_RSHIFT(w, 2) * AV_CEIL_RSHIFT(h, 2) * 16 + 4) 83 return AVERROR_INVALIDDATA; 84 } 85 } else if (depth == 32) { 86 avctx->pix_fmt = AV_PIX_FMT_RGBA; 87 if (bytestream2_get_bytes_left(&gb) < h * w * 4) 88 return AVERROR_INVALIDDATA; 89 } else { 90 avpriv_report_missing_feature(avctx, "Color depth of %u", depth); 91 return AVERROR_PATCHWELCOME; 92 } 93 94 if ((ret = ff_set_dimensions(avctx, w, h)) < 0) 95 return ret; 96 97 avctx->coded_width = FFALIGN(w, 4); 98 avctx->coded_height = FFALIGN(h, 4); 99 100 if ((ret = ff_get_buffer(avctx, p, 0)) < 0) 101 return ret; 102 103 p->pict_type = AV_PICTURE_TYPE_I; 104 105 ptr = p->data[0]; 106 stride = p->linesize[0]; 107 108 if (depth == 8) { 109 pal = (uint32_t *) p->data[1]; 110 for (y = 0; y < 256; y++) { 111 v = bytestream2_get_be32(&gb); 112 pal[y] = (v >> 8) + (v << 24); 113 } 114 bytestream2_skip(&gb, 4); 115 for (y=0; y<h; y++) { 116 bytestream2_get_buffer(&gb, ptr, w); 117 ptr += stride; 118 } 119 } else if (depth == 16) { 120 bytestream2_skip(&gb, 4); 121 switch (d3d_format) { 122 case 0: 123 case TXD_DXT1: 124 for (j = 0; j < avctx->height; j += 4) { 125 for (i = 0; i < avctx->width; i += 4) { 126 uint8_t *p = ptr + i * 4 + j * stride; 127 int step = dxtc.dxt1_block(p, stride, gb.buffer); 128 bytestream2_skip(&gb, step); 129 } 130 } 131 break; 132 case TXD_DXT3: 133 for (j = 0; j < avctx->height; j += 4) { 134 for (i = 0; i < avctx->width; i += 4) { 135 uint8_t *p = ptr + i * 4 + j * stride; 136 int step = dxtc.dxt3_block(p, stride, gb.buffer); 137 bytestream2_skip(&gb, step); 138 } 139 } 140 break; 141 default: 142 goto unsupported; 143 } 144 } else if (depth == 32) { 145 switch (d3d_format) { 146 case 0x15: 147 case 0x16: 148 for (y=0; y<h; y++) { 149 bytestream2_get_buffer(&gb, ptr, w * 4); 150 ptr += stride; 151 } 152 break; 153 default: 154 goto unsupported; 155 } 156 } 157 158 *got_frame = 1; 159 160 return avpkt->size; 161 162unsupported: 163 avpriv_report_missing_feature(avctx, "d3d format (%08x)", d3d_format); 164 return AVERROR_PATCHWELCOME; 165} 166 167const FFCodec ff_txd_decoder = { 168 .p.name = "txd", 169 .p.long_name = NULL_IF_CONFIG_SMALL("Renderware TXD (TeXture Dictionary) image"), 170 .p.type = AVMEDIA_TYPE_VIDEO, 171 .p.id = AV_CODEC_ID_TXD, 172 .p.capabilities = AV_CODEC_CAP_DR1, 173 FF_CODEC_DECODE_CB(txd_decode_frame), 174}; 175