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 "avcodec.h" 26#include "s3tc.h" 27 28typedef struct TXDContext { 29 AVFrame picture; 30} TXDContext; 31 32static av_cold int txd_init(AVCodecContext *avctx) { 33 TXDContext *s = avctx->priv_data; 34 35 avcodec_get_frame_defaults(&s->picture); 36 avctx->coded_frame = &s->picture; 37 38 return 0; 39} 40 41static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size, 42 AVPacket *avpkt) { 43 const uint8_t *buf = avpkt->data; 44 TXDContext * const s = avctx->priv_data; 45 AVFrame *picture = data; 46 AVFrame * const p = &s->picture; 47 unsigned int version, w, h, d3d_format, depth, stride, mipmap_count, flags; 48 unsigned int y, v; 49 uint8_t *ptr; 50 const uint8_t *cur = buf; 51 const uint32_t *palette = (const uint32_t *)(cur + 88); 52 uint32_t *pal; 53 54 version = AV_RL32(cur); 55 d3d_format = AV_RL32(cur+76); 56 w = AV_RL16(cur+80); 57 h = AV_RL16(cur+82); 58 depth = AV_RL8 (cur+84); 59 mipmap_count = AV_RL8 (cur+85); 60 flags = AV_RL8 (cur+87); 61 cur += 92; 62 63 if (version < 8 || version > 9) { 64 av_log(avctx, AV_LOG_ERROR, "texture data version %i is unsupported\n", 65 version); 66 return -1; 67 } 68 69 if (depth == 8) { 70 avctx->pix_fmt = PIX_FMT_PAL8; 71 cur += 1024; 72 } else if (depth == 16 || depth == 32) 73 avctx->pix_fmt = PIX_FMT_RGB32; 74 else { 75 av_log(avctx, AV_LOG_ERROR, "depth of %i is unsupported\n", depth); 76 return -1; 77 } 78 79 if (p->data[0]) 80 avctx->release_buffer(avctx, p); 81 82 if (avcodec_check_dimensions(avctx, w, h)) 83 return -1; 84 if (w != avctx->width || h != avctx->height) 85 avcodec_set_dimensions(avctx, w, h); 86 if (avctx->get_buffer(avctx, p) < 0) { 87 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 88 return -1; 89 } 90 91 p->pict_type = FF_I_TYPE; 92 93 ptr = p->data[0]; 94 stride = p->linesize[0]; 95 96 if (depth == 8) { 97 pal = (uint32_t *) p->data[1]; 98 for (y=0; y<256; y++) { 99 v = AV_RB32(palette+y); 100 pal[y] = (v>>8) + (v<<24); 101 } 102 for (y=0; y<h; y++) { 103 memcpy(ptr, cur, w); 104 ptr += stride; 105 cur += w; 106 } 107 } else if (depth == 16) { 108 switch (d3d_format) { 109 case 0: 110 if (!flags&1) goto unsupported; 111 case FF_S3TC_DXT1: 112 ff_decode_dxt1(cur, ptr, w, h, stride); 113 break; 114 case FF_S3TC_DXT3: 115 ff_decode_dxt3(cur, ptr, w, h, stride); 116 break; 117 default: 118 goto unsupported; 119 } 120 } else if (depth == 32) { 121 switch (d3d_format) { 122 case 0x15: 123 case 0x16: 124 for (y=0; y<h; y++) { 125 memcpy(ptr, cur, w*4); 126 ptr += stride; 127 cur += w*4; 128 } 129 break; 130 default: 131 goto unsupported; 132 } 133 } 134 135 for (; mipmap_count > 1; mipmap_count--) 136 cur += AV_RL32(cur) + 4; 137 138 *picture = s->picture; 139 *data_size = sizeof(AVPicture); 140 141 return cur - buf; 142 143unsupported: 144 av_log(avctx, AV_LOG_ERROR, "unsupported d3d format (%08x)\n", d3d_format); 145 return -1; 146} 147 148static av_cold int txd_end(AVCodecContext *avctx) { 149 TXDContext *s = avctx->priv_data; 150 151 if (s->picture.data[0]) 152 avctx->release_buffer(avctx, &s->picture); 153 154 return 0; 155} 156 157AVCodec txd_decoder = { 158 "txd", 159 AVMEDIA_TYPE_VIDEO, 160 CODEC_ID_TXD, 161 sizeof(TXDContext), 162 txd_init, 163 NULL, 164 txd_end, 165 txd_decode_frame, 166 CODEC_CAP_DR1, 167 NULL, 168 .long_name = NULL_IF_CONFIG_SMALL("Renderware TXD (TeXture Dictionary) image"), 169}; 170