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))
00120 goto unsupported;
00121 case FF_S3TC_DXT1:
00122 if (buf_end - cur < (w/4) * (h/4) * 8)
00123 return AVERROR_INVALIDDATA;
00124 ff_decode_dxt1(cur, ptr, w, h, stride);
00125 break;
00126 case FF_S3TC_DXT3:
00127 if (buf_end - cur < (w/4) * (h/4) * 16)
00128 return AVERROR_INVALIDDATA;
00129 ff_decode_dxt3(cur, ptr, w, h, stride);
00130 break;
00131 default:
00132 goto unsupported;
00133 }
00134 } else if (depth == 32) {
00135 switch (d3d_format) {
00136 case 0x15:
00137 case 0x16:
00138 if (buf_end - cur < h * w * 4)
00139 return AVERROR_INVALIDDATA;
00140 for (y=0; y<h; y++) {
00141 memcpy(ptr, cur, w*4);
00142 ptr += stride;
00143 cur += w*4;
00144 }
00145 break;
00146 default:
00147 goto unsupported;
00148 }
00149 }
00150
00151 for (; mipmap_count > 1 && buf_end - cur >= 4; mipmap_count--) {
00152 uint32_t length = bytestream_get_le32(&cur);
00153 if (buf_end - cur < length)
00154 break;
00155 cur += length;
00156 }
00157
00158 *picture = s->picture;
00159 *data_size = sizeof(AVPicture);
00160
00161 return cur - buf;
00162
00163 unsupported:
00164 av_log(avctx, AV_LOG_ERROR, "unsupported d3d format (%08x)\n", d3d_format);
00165 return -1;
00166 }
00167
00168 static av_cold int txd_end(AVCodecContext *avctx) {
00169 TXDContext *s = avctx->priv_data;
00170
00171 if (s->picture.data[0])
00172 avctx->release_buffer(avctx, &s->picture);
00173
00174 return 0;
00175 }
00176
00177 AVCodec ff_txd_decoder = {
00178 .name = "txd",
00179 .type = AVMEDIA_TYPE_VIDEO,
00180 .id = CODEC_ID_TXD,
00181 .priv_data_size = sizeof(TXDContext),
00182 .init = txd_init,
00183 .close = txd_end,
00184 .decode = txd_decode_frame,
00185 .capabilities = CODEC_CAP_DR1,
00186 .long_name = NULL_IF_CONFIG_SMALL("Renderware TXD (TeXture Dictionary) image"),
00187 };