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 "avcodec.h"
00025 #include "s3tc.h"
00026
00027 typedef struct TXDContext {
00028 AVFrame picture;
00029 } TXDContext;
00030
00031 static int txd_init(AVCodecContext *avctx) {
00032 TXDContext *s = avctx->priv_data;
00033
00034 avcodec_get_frame_defaults(&s->picture);
00035 avctx->coded_frame = &s->picture;
00036 s->picture.data[0] = NULL;
00037
00038 return 0;
00039 }
00040
00041 static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
00042 uint8_t *buf, int buf_size) {
00043 TXDContext * const s = avctx->priv_data;
00044 AVFrame *picture = data;
00045 AVFrame * const p = &s->picture;
00046 unsigned int version, w, h, d3d_format, depth, stride, mipmap_count, flags;
00047 unsigned int y, v;
00048 uint8_t *ptr, *cur = buf;
00049 uint32_t *palette = (uint32_t *)(cur + 88), *pal;
00050
00051 version = AV_RL32(cur);
00052 d3d_format = AV_RL32(cur+76);
00053 w = AV_RL16(cur+80);
00054 h = AV_RL16(cur+82);
00055 depth = AV_RL8 (cur+84);
00056 mipmap_count = AV_RL8 (cur+85);
00057 flags = AV_RL8 (cur+87);
00058 cur += 92;
00059
00060 if (version < 8 || version > 9) {
00061 av_log(avctx, AV_LOG_ERROR, "texture data version %i is unsupported\n",
00062 version);
00063 return -1;
00064 }
00065
00066 if (depth == 8) {
00067 avctx->pix_fmt = PIX_FMT_PAL8;
00068 cur += 1024;
00069 } else if (depth == 16 || depth == 32)
00070 avctx->pix_fmt = PIX_FMT_RGB32;
00071 else {
00072 av_log(avctx, AV_LOG_ERROR, "depth of %i is unsupported\n", depth);
00073 return -1;
00074 }
00075
00076 if (p->data[0])
00077 avctx->release_buffer(avctx, p);
00078
00079 if (avcodec_check_dimensions(avctx, w, h))
00080 return -1;
00081 if (w != avctx->width || h != avctx->height)
00082 avcodec_set_dimensions(avctx, w, h);
00083 if (avctx->get_buffer(avctx, p) < 0) {
00084 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00085 return -1;
00086 }
00087
00088 p->pict_type = FF_I_TYPE;
00089
00090 ptr = p->data[0];
00091 stride = p->linesize[0];
00092
00093 if (depth == 8) {
00094 pal = (uint32_t *) p->data[1];
00095 for (y=0; y<256; y++) {
00096 v = AV_RB32(palette+y);
00097 pal[y] = (v>>8) + (v<<24);
00098 }
00099 for (y=0; y<h; y++) {
00100 memcpy(ptr, cur, w);
00101 ptr += stride;
00102 cur += w;
00103 }
00104 } else if (depth == 16) {
00105 switch (d3d_format) {
00106 case 0:
00107 if (!flags&1) goto unsupported;
00108 case FF_S3TC_DXT1:
00109 ff_decode_dxt1(cur, ptr, w, h, stride);
00110 break;
00111 case FF_S3TC_DXT3:
00112 ff_decode_dxt3(cur, ptr, w, h, stride);
00113 break;
00114 default:
00115 goto unsupported;
00116 }
00117 } else if (depth == 32) {
00118 switch (d3d_format) {
00119 case 0x15:
00120 case 0x16:
00121 for (y=0; y<h; y++) {
00122 memcpy(ptr, cur, w*4);
00123 ptr += stride;
00124 cur += w*4;
00125 }
00126 break;
00127 default:
00128 goto unsupported;
00129 }
00130 }
00131
00132 for (; mipmap_count > 1; mipmap_count--)
00133 cur += AV_RL32(cur) + 4;
00134
00135 *picture = s->picture;
00136 *data_size = sizeof(AVPicture);
00137
00138 return cur - buf;
00139
00140 unsupported:
00141 av_log(avctx, AV_LOG_ERROR, "unsupported d3d format (%08x)\n", d3d_format);
00142 return -1;
00143 }
00144
00145 static int txd_end(AVCodecContext *avctx) {
00146 TXDContext *s = avctx->priv_data;
00147
00148 if (s->picture.data[0])
00149 avctx->release_buffer(avctx, &s->picture);
00150
00151 return 0;
00152 }
00153
00154 AVCodec txd_decoder = {
00155 "txd",
00156 CODEC_TYPE_VIDEO,
00157 CODEC_ID_TXD,
00158 sizeof(TXDContext),
00159 txd_init,
00160 NULL,
00161 txd_end,
00162 txd_decode_frame,
00163 0,
00164 NULL
00165 };