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 "bytestream.h"
00029 #include "s3tc.h"
00030
00031 typedef struct TXDContext {
00032 AVFrame picture;
00033 } TXDContext;
00034
00035 static av_cold int txd_init(AVCodecContext *avctx) {
00036 TXDContext *s = avctx->priv_data;
00037
00038 avcodec_get_frame_defaults(&s->picture);
00039 avctx->coded_frame = &s->picture;
00040
00041 return 0;
00042 }
00043
00044 static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
00045 AVPacket *avpkt) {
00046 TXDContext * const s = avctx->priv_data;
00047 GetByteContext gb;
00048 AVFrame *picture = data;
00049 AVFrame * const p = &s->picture;
00050 unsigned int version, w, h, d3d_format, depth, stride, flags;
00051 unsigned int y, v;
00052 uint8_t *ptr;
00053 uint32_t *pal;
00054
00055 bytestream2_init(&gb, avpkt->data, avpkt->size);
00056 version = bytestream2_get_le32(&gb);
00057 bytestream2_skip(&gb, 72);
00058 d3d_format = bytestream2_get_le32(&gb);
00059 w = bytestream2_get_le16(&gb);
00060 h = bytestream2_get_le16(&gb);
00061 depth = bytestream2_get_byte(&gb);
00062 bytestream2_skip(&gb, 2);
00063 flags = bytestream2_get_byte(&gb);
00064
00065 if (version < 8 || version > 9) {
00066 av_log(avctx, AV_LOG_ERROR, "texture data version %i is unsupported\n",
00067 version);
00068 return -1;
00069 }
00070
00071 if (depth == 8) {
00072 avctx->pix_fmt = PIX_FMT_PAL8;
00073 } else if (depth == 16 || depth == 32) {
00074 avctx->pix_fmt = PIX_FMT_RGB32;
00075 } else {
00076 av_log(avctx, AV_LOG_ERROR, "depth of %i is unsupported\n", depth);
00077 return -1;
00078 }
00079
00080 if (p->data[0])
00081 avctx->release_buffer(avctx, p);
00082
00083 if (av_image_check_size(w, h, 0, avctx))
00084 return -1;
00085 if (w != avctx->width || h != avctx->height)
00086 avcodec_set_dimensions(avctx, w, h);
00087 if (avctx->get_buffer(avctx, p) < 0) {
00088 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00089 return -1;
00090 }
00091
00092 p->pict_type = AV_PICTURE_TYPE_I;
00093
00094 ptr = p->data[0];
00095 stride = p->linesize[0];
00096
00097 if (depth == 8) {
00098 pal = (uint32_t *) p->data[1];
00099 for (y = 0; y < 256; y++) {
00100 v = bytestream2_get_be32(&gb);
00101 pal[y] = (v >> 8) + (v << 24);
00102 }
00103 if (bytestream2_get_bytes_left(&gb) < w * h)
00104 return AVERROR_INVALIDDATA;
00105 bytestream2_skip(&gb, 4);
00106 for (y=0; y<h; y++) {
00107 bytestream2_get_buffer(&gb, ptr, w);
00108 ptr += stride;
00109 }
00110 } else if (depth == 16) {
00111 bytestream2_skip(&gb, 4);
00112 switch (d3d_format) {
00113 case 0:
00114 if (!(flags & 1))
00115 goto unsupported;
00116 case FF_S3TC_DXT1:
00117 if (bytestream2_get_bytes_left(&gb) < (w/4) * (h/4) * 8)
00118 return AVERROR_INVALIDDATA;
00119 ff_decode_dxt1(&gb, ptr, w, h, stride);
00120 break;
00121 case FF_S3TC_DXT3:
00122 if (bytestream2_get_bytes_left(&gb) < (w/4) * (h/4) * 16)
00123 return AVERROR_INVALIDDATA;
00124 ff_decode_dxt3(&gb, ptr, w, h, stride);
00125 break;
00126 default:
00127 goto unsupported;
00128 }
00129 } else if (depth == 32) {
00130 switch (d3d_format) {
00131 case 0x15:
00132 case 0x16:
00133 if (bytestream2_get_bytes_left(&gb) < h * w * 4)
00134 return AVERROR_INVALIDDATA;
00135 for (y=0; y<h; y++) {
00136 bytestream2_get_buffer(&gb, ptr, w * 4);
00137 ptr += stride;
00138 }
00139 break;
00140 default:
00141 goto unsupported;
00142 }
00143 }
00144
00145 *picture = s->picture;
00146 *data_size = sizeof(AVPicture);
00147
00148 return avpkt->size;
00149
00150 unsupported:
00151 av_log(avctx, AV_LOG_ERROR, "unsupported d3d format (%08x)\n", d3d_format);
00152 return -1;
00153 }
00154
00155 static av_cold int txd_end(AVCodecContext *avctx) {
00156 TXDContext *s = avctx->priv_data;
00157
00158 if (s->picture.data[0])
00159 avctx->release_buffer(avctx, &s->picture);
00160
00161 return 0;
00162 }
00163
00164 AVCodec ff_txd_decoder = {
00165 .name = "txd",
00166 .type = AVMEDIA_TYPE_VIDEO,
00167 .id = AV_CODEC_ID_TXD,
00168 .priv_data_size = sizeof(TXDContext),
00169 .init = txd_init,
00170 .close = txd_end,
00171 .decode = txd_decode_frame,
00172 .capabilities = CODEC_CAP_DR1,
00173 .long_name = NULL_IF_CONFIG_SMALL("Renderware TXD (TeXture Dictionary) image"),
00174 };