00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "libavutil/intreadwrite.h"
00025 #include "libavutil/imgutils.h"
00026 #include "bytestream.h"
00027 #include "avcodec.h"
00028 #include "s3tc.h"
00029
00030 typedef struct TXDContext {
00031 AVFrame picture;
00032 } TXDContext;
00033
00034 static av_cold int txd_init(AVCodecContext *avctx) {
00035 TXDContext *s = avctx->priv_data;
00036
00037 avcodec_get_frame_defaults(&s->picture);
00038 avctx->coded_frame = &s->picture;
00039
00040 return 0;
00041 }
00042
00043 static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
00044 AVPacket *avpkt) {
00045 const uint8_t *buf = avpkt->data;
00046 const uint8_t *buf_end = avpkt->data + avpkt->size;
00047 TXDContext * const s = avctx->priv_data;
00048 AVFrame *picture = data;
00049 AVFrame * const p = &s->picture;
00050 unsigned int version, w, h, d3d_format, depth, stride, mipmap_count, flags;
00051 unsigned int y, v;
00052 uint8_t *ptr;
00053 const uint8_t *cur = buf;
00054 const uint32_t *palette = (const uint32_t *)(cur + 88);
00055 uint32_t *pal;
00056
00057 if (buf_end - cur < 92)
00058 return AVERROR_INVALIDDATA;
00059 version = AV_RL32(cur);
00060 d3d_format = AV_RL32(cur+76);
00061 w = AV_RL16(cur+80);
00062 h = AV_RL16(cur+82);
00063 depth = AV_RL8 (cur+84);
00064 mipmap_count = AV_RL8 (cur+85);
00065 flags = AV_RL8 (cur+87);
00066 cur += 92;
00067
00068 if (version < 8 || version > 9) {
00069 av_log(avctx, AV_LOG_ERROR, "texture data version %i is unsupported\n",
00070 version);
00071 return -1;
00072 }
00073
00074 if (depth == 8) {
00075 avctx->pix_fmt = PIX_FMT_PAL8;
00076 if (buf_end - cur < 1024)
00077 return AVERROR_INVALIDDATA;
00078 cur += 1024;
00079 } else if (depth == 16 || depth == 32)
00080 avctx->pix_fmt = PIX_FMT_RGB32;
00081 else {
00082 av_log(avctx, AV_LOG_ERROR, "depth of %i is unsupported\n", depth);
00083 return -1;
00084 }
00085
00086 if (p->data[0])
00087 avctx->release_buffer(avctx, p);
00088
00089 if (av_image_check_size(w, h, 0, avctx))
00090 return -1;
00091 if (w != avctx->width || h != avctx->height)
00092 avcodec_set_dimensions(avctx, w, h);
00093 if (avctx->get_buffer(avctx, p) < 0) {
00094 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00095 return -1;
00096 }
00097
00098 p->pict_type = AV_PICTURE_TYPE_I;
00099
00100 ptr = p->data[0];
00101 stride = p->linesize[0];
00102
00103 if (depth == 8) {
00104 pal = (uint32_t *) p->data[1];
00105 for (y=0; y<256; y++) {
00106 v = AV_RB32(palette+y);
00107 pal[y] = (v>>8) + (v<<24);
00108 }
00109 if (buf_end - cur < w * h)
00110 return AVERROR_INVALIDDATA;
00111 for (y=0; y<h; y++) {
00112 memcpy(ptr, cur, w);
00113 ptr += stride;
00114 cur += w;
00115 }
00116 } else if (depth == 16) {
00117 switch (d3d_format) {
00118 case 0:
00119 if (!flags&1) goto unsupported;
00120 case FF_S3TC_DXT1:
00121 if (buf_end - cur < (w/4) * (h/4) * 8)
00122 return AVERROR_INVALIDDATA;
00123 ff_decode_dxt1(cur, ptr, w, h, stride);
00124 break;
00125 case FF_S3TC_DXT3:
00126 if (buf_end - cur < (w/4) * (h/4) * 16)
00127 return AVERROR_INVALIDDATA;
00128 ff_decode_dxt3(cur, ptr, w, h, stride);
00129 break;
00130 default:
00131 goto unsupported;
00132 }
00133 } else if (depth == 32) {
00134 switch (d3d_format) {
00135 case 0x15:
00136 case 0x16:
00137 if (buf_end - cur < h * w * 4)
00138 return AVERROR_INVALIDDATA;
00139 for (y=0; y<h; y++) {
00140 memcpy(ptr, cur, w*4);
00141 ptr += stride;
00142 cur += w*4;
00143 }
00144 break;
00145 default:
00146 goto unsupported;
00147 }
00148 }
00149
00150 for (; mipmap_count > 1 && buf_end - cur >= 4; mipmap_count--) {
00151 uint32_t length = bytestream_get_le32(&cur);
00152 if (buf_end - cur < length)
00153 break;
00154 cur += length;
00155 }
00156
00157 *picture = s->picture;
00158 *data_size = sizeof(AVPicture);
00159
00160 return cur - buf;
00161
00162 unsupported:
00163 av_log(avctx, AV_LOG_ERROR, "unsupported d3d format (%08x)\n", d3d_format);
00164 return -1;
00165 }
00166
00167 static av_cold int txd_end(AVCodecContext *avctx) {
00168 TXDContext *s = avctx->priv_data;
00169
00170 if (s->picture.data[0])
00171 avctx->release_buffer(avctx, &s->picture);
00172
00173 return 0;
00174 }
00175
00176 AVCodec ff_txd_decoder = {
00177 "txd",
00178 AVMEDIA_TYPE_VIDEO,
00179 CODEC_ID_TXD,
00180 sizeof(TXDContext),
00181 txd_init,
00182 NULL,
00183 txd_end,
00184 txd_decode_frame,
00185 CODEC_CAP_DR1,
00186 NULL,
00187 .long_name = NULL_IF_CONFIG_SMALL("Renderware TXD (TeXture Dictionary) image"),
00188 };