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