]> git.sesse.net Git - ffmpeg/blob - libavcodec/txd.c
Check available size before writing in decode_frame()
[ffmpeg] / libavcodec / txd.c
1 /*
2  * Renderware TeXture Dictionary (.txd) image decoder
3  * Copyright (c) 2007 Ivo van Poorten
4  *
5  * See also: http://wiki.multimedia.cx/index.php?title=TXD
6  *
7  * This file is part of FFmpeg.
8  *
9  * FFmpeg is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with FFmpeg; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23
24 #include "avcodec.h"
25 #include "s3tc.h"
26
27 typedef struct TXDContext {
28     AVFrame picture;
29 } TXDContext;
30
31 static av_cold int txd_init(AVCodecContext *avctx) {
32     TXDContext *s = avctx->priv_data;
33
34     avcodec_get_frame_defaults(&s->picture);
35     avctx->coded_frame = &s->picture;
36
37     return 0;
38 }
39
40 static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
41                             const uint8_t *buf, int buf_size) {
42     TXDContext * const s = avctx->priv_data;
43     AVFrame *picture = data;
44     AVFrame * const p = &s->picture;
45     unsigned int version, w, h, d3d_format, depth, stride, mipmap_count, flags;
46     unsigned int y, v;
47     uint8_t *ptr;
48     const uint8_t *cur = buf;
49     const uint32_t *palette = (const uint32_t *)(cur + 88);
50     uint32_t *pal;
51
52     version         = AV_RL32(cur);
53     d3d_format      = AV_RL32(cur+76);
54     w               = AV_RL16(cur+80);
55     h               = AV_RL16(cur+82);
56     depth           = AV_RL8 (cur+84);
57     mipmap_count    = AV_RL8 (cur+85);
58     flags           = AV_RL8 (cur+87);
59     cur            += 92;
60
61     if (version < 8 || version > 9) {
62         av_log(avctx, AV_LOG_ERROR, "texture data version %i is unsupported\n",
63                                                                     version);
64         return -1;
65     }
66
67     if (depth == 8) {
68         avctx->pix_fmt = PIX_FMT_PAL8;
69         cur += 1024;
70     } else if (depth == 16 || depth == 32)
71         avctx->pix_fmt = PIX_FMT_RGB32;
72     else {
73         av_log(avctx, AV_LOG_ERROR, "depth of %i is unsupported\n", depth);
74         return -1;
75     }
76
77     if (p->data[0])
78         avctx->release_buffer(avctx, p);
79
80     if (avcodec_check_dimensions(avctx, w, h))
81         return -1;
82     if (w != avctx->width || h != avctx->height)
83         avcodec_set_dimensions(avctx, w, h);
84     if (avctx->get_buffer(avctx, p) < 0) {
85         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
86         return -1;
87     }
88
89     p->pict_type = FF_I_TYPE;
90
91     ptr    = p->data[0];
92     stride = p->linesize[0];
93
94     if (depth == 8) {
95         pal = (uint32_t *) p->data[1];
96         for (y=0; y<256; y++) {
97             v = AV_RB32(palette+y);
98             pal[y] = (v>>8) + (v<<24);
99         }
100         for (y=0; y<h; y++) {
101             memcpy(ptr, cur, w);
102             ptr += stride;
103             cur += w;
104         }
105     } else if (depth == 16) {
106         switch (d3d_format) {
107         case 0:
108             if (!flags&1) goto unsupported;
109         case FF_S3TC_DXT1:
110             ff_decode_dxt1(cur, ptr, w, h, stride);
111             break;
112         case FF_S3TC_DXT3:
113             ff_decode_dxt3(cur, ptr, w, h, stride);
114             break;
115         default:
116             goto unsupported;
117         }
118     } else if (depth == 32) {
119         switch (d3d_format) {
120         case 0x15:
121         case 0x16:
122             for (y=0; y<h; y++) {
123                 memcpy(ptr, cur, w*4);
124                 ptr += stride;
125                 cur += w*4;
126             }
127             break;
128         default:
129             goto unsupported;
130         }
131     }
132
133     for (; mipmap_count > 1; mipmap_count--)
134         cur += AV_RL32(cur) + 4;
135
136     *picture   = s->picture;
137     *data_size = sizeof(AVPicture);
138
139     return cur - buf;
140
141 unsupported:
142     av_log(avctx, AV_LOG_ERROR, "unsupported d3d format (%08x)\n", d3d_format);
143     return -1;
144 }
145
146 static av_cold int txd_end(AVCodecContext *avctx) {
147     TXDContext *s = avctx->priv_data;
148
149     if (s->picture.data[0])
150         avctx->release_buffer(avctx, &s->picture);
151
152     return 0;
153 }
154
155 AVCodec txd_decoder = {
156     "txd",
157     CODEC_TYPE_VIDEO,
158     CODEC_ID_TXD,
159     sizeof(TXDContext),
160     txd_init,
161     NULL,
162     txd_end,
163     txd_decode_frame,
164     0,
165     NULL,
166     .long_name = NULL_IF_CONFIG_SMALL("Renderware TXD (TeXture Dictionary) image"),
167 };