Mercurial > libavcodec.hg
annotate vqavideo.c @ 6920:d02af7474bff libavcodec
Prevent 128*1<<trellis from becoming 0 and creating 0 sized arrays.
fixes CID84 RUN2
CID85 RUN2
CID86 RUN2
CID87 RUN2
CID88 RUN2
CID89 RUN2
CID90 RUN2
CID91 RUN2
CID92 RUN2
CID93 RUN2
CID94 RUN2
CID95 RUN2
CID96 RUN2
CID97 RUN2
CID98 RUN2
CID99 RUN2
CID100 RUN2
CID101 RUN2
CID102 RUN2
CID103 RUN2
CID104 RUN2
CID105 RUN2
CID106 RUN2
author | michael |
---|---|
date | Wed, 28 May 2008 11:59:41 +0000 |
parents | 0f63fc62ea8b |
children | e943e1409077 |
rev | line source |
---|---|
1496 | 1 /* |
2 * Westwood Studios VQA Video Decoder | |
3 * Copyright (C) 2003 the ffmpeg project | |
4 * | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3799
diff
changeset
|
5 * This file is part of FFmpeg. |
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3799
diff
changeset
|
6 * |
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3799
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
1496 | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3799
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
1496 | 11 * |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3799
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
1496 | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3799
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
3036
0b546eab515d
Update licensing information: The FSF changed postal address.
diego
parents:
2967
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
1496 | 20 */ |
21 | |
22 /** | |
23 * @file vqavideo.c | |
24 * VQA Video Decoder by Mike Melanson (melanson@pcisys.net) | |
4243 | 25 * For more information about the VQA format, visit: |
26 * http://wiki.multimedia.cx/index.php?title=VQA | |
1496 | 27 * |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
28 * The VQA video decoder outputs PAL8 or RGB555 colorspace data, depending |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
29 * on the type of data in the file. |
1496 | 30 * |
31 * This decoder needs the 42-byte VQHD header from the beginning | |
32 * of the VQA file passed through the extradata field. The VQHD header | |
33 * is laid out as: | |
34 * | |
35 * bytes 0-3 chunk fourcc: 'VQHD' | |
36 * bytes 4-7 chunk size in big-endian format, should be 0x0000002A | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
37 * bytes 8-49 VQHD chunk data |
1496 | 38 * |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
39 * Bytes 8-49 are what this decoder expects to see. |
1496 | 40 * |
41 * Briefly, VQA is a vector quantized animation format that operates in a | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
42 * VGA palettized colorspace. It operates on pixel vectors (blocks) |
1496 | 43 * of either 4x2 or 4x4 in size. Compressed VQA chunks can contain vector |
44 * codebooks, palette information, and code maps for rendering vectors onto | |
45 * frames. Any of these components can also be compressed with a run-length | |
46 * encoding (RLE) algorithm commonly referred to as "format80". | |
47 * | |
48 * VQA takes a novel approach to rate control. Each group of n frames | |
49 * (usually, n = 8) relies on a different vector codebook. Rather than | |
50 * transporting an entire codebook every 8th frame, the new codebook is | |
51 * broken up into 8 pieces and sent along with the compressed video chunks | |
52 * for each of the 8 frames preceding the 8 frames which require the | |
53 * codebook. A full codebook is also sent on the very first frame of a | |
54 * file. This is an interesting technique, although it makes random file | |
55 * seeking difficult despite the fact that the frames are all intracoded. | |
56 * | |
6903 | 57 * V1,2 VQA uses 12-bit codebook indexes. If the 12-bit indexes were |
1496 | 58 * packed into bytes and then RLE compressed, bytewise, the results would |
59 * be poor. That is why the coding method divides each index into 2 parts, | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
60 * the top 4 bits and the bottom 8 bits, then RL encodes the 4-bit pieces |
1496 | 61 * together and the 8-bit pieces together. If most of the vectors are |
62 * clustered into one group of 256 vectors, most of the 4-bit index pieces | |
63 * should be the same. | |
64 */ | |
65 | |
66 #include <stdio.h> | |
67 #include <stdlib.h> | |
68 #include <string.h> | |
69 #include <unistd.h> | |
70 | |
71 #include "avcodec.h" | |
72 | |
73 #define PALETTE_COUNT 256 | |
74 #define VQA_HEADER_SIZE 0x2A | |
75 #define CHUNK_PREAMBLE_SIZE 8 | |
76 | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
77 /* allocate the maximum vector space, regardless of the file version: |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
78 * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */ |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
79 #define MAX_CODEBOOK_VECTORS 0xFF00 |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
80 #define SOLID_PIXEL_VECTORS 0x100 |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
81 #define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
82 #define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4) |
1496 | 83 |
1881
39ad6cd5d4a6
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
1598
diff
changeset
|
84 #define CBF0_TAG MKBETAG('C', 'B', 'F', '0') |
39ad6cd5d4a6
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
1598
diff
changeset
|
85 #define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z') |
39ad6cd5d4a6
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
1598
diff
changeset
|
86 #define CBP0_TAG MKBETAG('C', 'B', 'P', '0') |
39ad6cd5d4a6
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
1598
diff
changeset
|
87 #define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z') |
39ad6cd5d4a6
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
1598
diff
changeset
|
88 #define CPL0_TAG MKBETAG('C', 'P', 'L', '0') |
39ad6cd5d4a6
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
1598
diff
changeset
|
89 #define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z') |
39ad6cd5d4a6
remove numerous definitions of BE_*/LE_* macros; convert FOURCC_TAG ->
melanson
parents:
1598
diff
changeset
|
90 #define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z') |
1496 | 91 |
92 #define VQA_DEBUG 0 | |
93 | |
94 #if VQA_DEBUG | |
95 #define vqa_debug printf | |
96 #else | |
97 static inline void vqa_debug(const char *format, ...) { } | |
98 #endif | |
99 | |
100 typedef struct VqaContext { | |
101 | |
102 AVCodecContext *avctx; | |
103 AVFrame frame; | |
104 | |
6295 | 105 const unsigned char *buf; |
1496 | 106 int size; |
107 | |
3799
81638b2fbeba
palette (if we memcpy it into AVFrame) must be uint32_t
michael
parents:
3036
diff
changeset
|
108 uint32_t palette[PALETTE_COUNT]; |
1496 | 109 |
110 int width; /* width of a frame */ | |
111 int height; /* height of a frame */ | |
112 int vector_width; /* width of individual vector */ | |
113 int vector_height; /* height of individual vector */ | |
114 int vqa_version; /* this should be either 1, 2 or 3 */ | |
115 | |
116 unsigned char *codebook; /* the current codebook */ | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
117 int codebook_size; |
1496 | 118 unsigned char *next_codebook_buffer; /* accumulator for next codebook */ |
119 int next_codebook_buffer_index; | |
120 | |
121 unsigned char *decode_buffer; | |
122 int decode_buffer_size; | |
123 | |
124 /* number of frames to go before replacing codebook */ | |
125 int partial_countdown; | |
126 int partial_count; | |
127 | |
128 } VqaContext; | |
129 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6484
diff
changeset
|
130 static av_cold int vqa_decode_init(AVCodecContext *avctx) |
1496 | 131 { |
4827 | 132 VqaContext *s = avctx->priv_data; |
1496 | 133 unsigned char *vqa_header; |
6377 | 134 int i, j, codebook_index; |
1496 | 135 |
136 s->avctx = avctx; | |
137 avctx->pix_fmt = PIX_FMT_PAL8; | |
138 | |
139 /* make sure the extradata made it */ | |
140 if (s->avctx->extradata_size != VQA_HEADER_SIZE) { | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
141 av_log(s->avctx, AV_LOG_ERROR, " VQA video: expected extradata size of %d\n", VQA_HEADER_SIZE); |
1496 | 142 return -1; |
143 } | |
144 | |
145 /* load up the VQA parameters from the header */ | |
146 vqa_header = (unsigned char *)s->avctx->extradata; | |
147 s->vqa_version = vqa_header[0]; | |
4364 | 148 s->width = AV_RL16(&vqa_header[6]); |
149 s->height = AV_RL16(&vqa_header[8]); | |
2422 | 150 if(avcodec_check_dimensions(avctx, s->width, s->height)){ |
151 s->width= s->height= 0; | |
152 return -1; | |
153 } | |
1496 | 154 s->vector_width = vqa_header[10]; |
155 s->vector_height = vqa_header[11]; | |
156 s->partial_count = s->partial_countdown = vqa_header[13]; | |
157 | |
158 /* the vector dimensions have to meet very stringent requirements */ | |
159 if ((s->vector_width != 4) || | |
160 ((s->vector_height != 2) && (s->vector_height != 4))) { | |
161 /* return without further initialization */ | |
162 return -1; | |
163 } | |
164 | |
165 /* allocate codebooks */ | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
166 s->codebook_size = MAX_CODEBOOK_SIZE; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
167 s->codebook = av_malloc(s->codebook_size); |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
168 s->next_codebook_buffer = av_malloc(s->codebook_size); |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
169 |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
170 /* initialize the solid-color vectors */ |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
171 if (s->vector_height == 4) { |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
172 codebook_index = 0xFF00 * 16; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
173 for (i = 0; i < 256; i++) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
174 for (j = 0; j < 16; j++) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
175 s->codebook[codebook_index++] = i; |
1496 | 176 } else { |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
177 codebook_index = 0xF00 * 8; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
178 for (i = 0; i < 256; i++) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
179 for (j = 0; j < 8; j++) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
180 s->codebook[codebook_index++] = i; |
1496 | 181 } |
182 s->next_codebook_buffer_index = 0; | |
183 | |
184 /* allocate decode buffer */ | |
185 s->decode_buffer_size = (s->width / s->vector_width) * | |
186 (s->height / s->vector_height) * 2; | |
187 s->decode_buffer = av_malloc(s->decode_buffer_size); | |
188 | |
189 s->frame.data[0] = NULL; | |
190 | |
191 return 0; | |
192 } | |
193 | |
194 #define CHECK_COUNT() \ | |
195 if (dest_index + count > dest_size) { \ | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
196 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \ |
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
197 av_log(NULL, AV_LOG_ERROR, " VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \ |
1496 | 198 dest_index, count, dest_size); \ |
199 return; \ | |
200 } | |
201 | |
6295 | 202 static void decode_format80(const unsigned char *src, int src_size, |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
203 unsigned char *dest, int dest_size, int check_size) { |
1496 | 204 |
205 int src_index = 0; | |
206 int dest_index = 0; | |
207 int count; | |
208 int src_pos; | |
209 unsigned char color; | |
210 int i; | |
211 | |
212 while (src_index < src_size) { | |
213 | |
214 vqa_debug(" opcode %02X: ", src[src_index]); | |
215 | |
216 /* 0x80 means that frame is finished */ | |
217 if (src[src_index] == 0x80) | |
218 return; | |
219 | |
220 if (dest_index >= dest_size) { | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
221 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n", |
1496 | 222 dest_index, dest_size); |
223 return; | |
224 } | |
225 | |
226 if (src[src_index] == 0xFF) { | |
227 | |
228 src_index++; | |
4364 | 229 count = AV_RL16(&src[src_index]); |
1496 | 230 src_index += 2; |
4364 | 231 src_pos = AV_RL16(&src[src_index]); |
1496 | 232 src_index += 2; |
233 vqa_debug("(1) copy %X bytes from absolute pos %X\n", count, src_pos); | |
234 CHECK_COUNT(); | |
235 for (i = 0; i < count; i++) | |
236 dest[dest_index + i] = dest[src_pos + i]; | |
237 dest_index += count; | |
238 | |
239 } else if (src[src_index] == 0xFE) { | |
240 | |
241 src_index++; | |
4364 | 242 count = AV_RL16(&src[src_index]); |
1496 | 243 src_index += 2; |
244 color = src[src_index++]; | |
245 vqa_debug("(2) set %X bytes to %02X\n", count, color); | |
246 CHECK_COUNT(); | |
247 memset(&dest[dest_index], color, count); | |
248 dest_index += count; | |
249 | |
250 } else if ((src[src_index] & 0xC0) == 0xC0) { | |
251 | |
252 count = (src[src_index++] & 0x3F) + 3; | |
4364 | 253 src_pos = AV_RL16(&src[src_index]); |
1496 | 254 src_index += 2; |
255 vqa_debug("(3) copy %X bytes from absolute pos %X\n", count, src_pos); | |
256 CHECK_COUNT(); | |
257 for (i = 0; i < count; i++) | |
258 dest[dest_index + i] = dest[src_pos + i]; | |
259 dest_index += count; | |
260 | |
261 } else if (src[src_index] > 0x80) { | |
262 | |
263 count = src[src_index++] & 0x3F; | |
264 vqa_debug("(4) copy %X bytes from source to dest\n", count); | |
265 CHECK_COUNT(); | |
266 memcpy(&dest[dest_index], &src[src_index], count); | |
267 src_index += count; | |
268 dest_index += count; | |
269 | |
270 } else { | |
271 | |
272 count = ((src[src_index] & 0x70) >> 4) + 3; | |
4364 | 273 src_pos = AV_RB16(&src[src_index]) & 0x0FFF; |
1496 | 274 src_index += 2; |
275 vqa_debug("(5) copy %X bytes from relpos %X\n", count, src_pos); | |
276 CHECK_COUNT(); | |
277 for (i = 0; i < count; i++) | |
278 dest[dest_index + i] = dest[dest_index - src_pos + i]; | |
279 dest_index += count; | |
280 } | |
281 } | |
282 | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
283 /* validate that the entire destination buffer was filled; this is |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
284 * important for decoding frame maps since each vector needs to have a |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
285 * codebook entry; it is not important for compressed codebooks because |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
286 * not every entry needs to be filled */ |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
287 if (check_size) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
288 if (dest_index < dest_size) |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
289 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n", |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
290 dest_index, dest_size); |
1496 | 291 } |
292 | |
293 static void vqa_decode_chunk(VqaContext *s) | |
294 { | |
295 unsigned int chunk_type; | |
296 unsigned int chunk_size; | |
297 int byte_skip; | |
298 unsigned int index = 0; | |
299 int i; | |
300 unsigned char r, g, b; | |
1506 | 301 int index_shift; |
1496 | 302 |
303 int cbf0_chunk = -1; | |
304 int cbfz_chunk = -1; | |
305 int cbp0_chunk = -1; | |
306 int cbpz_chunk = -1; | |
307 int cpl0_chunk = -1; | |
308 int cplz_chunk = -1; | |
309 int vptz_chunk = -1; | |
310 | |
311 int x, y; | |
312 int lines = 0; | |
313 int pixel_ptr; | |
314 int vector_index = 0; | |
315 int lobyte = 0; | |
316 int hibyte = 0; | |
317 int lobytes = 0; | |
318 int hibytes = s->decode_buffer_size / 2; | |
319 | |
320 /* first, traverse through the frame and find the subchunks */ | |
321 while (index < s->size) { | |
322 | |
4364 | 323 chunk_type = AV_RB32(&s->buf[index]); |
324 chunk_size = AV_RB32(&s->buf[index + 4]); | |
1496 | 325 |
326 switch (chunk_type) { | |
327 | |
328 case CBF0_TAG: | |
329 cbf0_chunk = index; | |
330 break; | |
331 | |
332 case CBFZ_TAG: | |
333 cbfz_chunk = index; | |
334 break; | |
335 | |
336 case CBP0_TAG: | |
337 cbp0_chunk = index; | |
338 break; | |
339 | |
340 case CBPZ_TAG: | |
341 cbpz_chunk = index; | |
342 break; | |
343 | |
344 case CPL0_TAG: | |
345 cpl0_chunk = index; | |
346 break; | |
347 | |
348 case CPLZ_TAG: | |
349 cplz_chunk = index; | |
350 break; | |
351 | |
352 case VPTZ_TAG: | |
353 vptz_chunk = index; | |
354 break; | |
355 | |
356 default: | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
357 av_log(s->avctx, AV_LOG_ERROR, " VQA video: Found unknown chunk type: %c%c%c%c (%08X)\n", |
1496 | 358 (chunk_type >> 24) & 0xFF, |
359 (chunk_type >> 16) & 0xFF, | |
360 (chunk_type >> 8) & 0xFF, | |
361 (chunk_type >> 0) & 0xFF, | |
362 chunk_type); | |
363 break; | |
364 } | |
365 | |
366 byte_skip = chunk_size & 0x01; | |
367 index += (CHUNK_PREAMBLE_SIZE + chunk_size + byte_skip); | |
368 } | |
369 | |
370 /* next, deal with the palette */ | |
371 if ((cpl0_chunk != -1) && (cplz_chunk != -1)) { | |
372 | |
373 /* a chunk should not have both chunk types */ | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
374 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CPL0 and CPLZ chunks\n"); |
1496 | 375 return; |
376 } | |
377 | |
378 /* decompress the palette chunk */ | |
379 if (cplz_chunk != -1) { | |
380 | |
381 /* yet to be handled */ | |
382 | |
383 } | |
384 | |
385 /* convert the RGB palette into the machine's endian format */ | |
386 if (cpl0_chunk != -1) { | |
387 | |
4364 | 388 chunk_size = AV_RB32(&s->buf[cpl0_chunk + 4]); |
1496 | 389 /* sanity check the palette size */ |
390 if (chunk_size / 3 > 256) { | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
391 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found a palette chunk with %d colors\n", |
1496 | 392 chunk_size / 3); |
393 return; | |
394 } | |
395 cpl0_chunk += CHUNK_PREAMBLE_SIZE; | |
396 for (i = 0; i < chunk_size / 3; i++) { | |
397 /* scale by 4 to transform 6-bit palette -> 8-bit */ | |
398 r = s->buf[cpl0_chunk++] * 4; | |
399 g = s->buf[cpl0_chunk++] * 4; | |
400 b = s->buf[cpl0_chunk++] * 4; | |
1585
6b224ca24033
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
1506
diff
changeset
|
401 s->palette[i] = (r << 16) | (g << 8) | (b); |
1496 | 402 } |
403 } | |
404 | |
405 /* next, look for a full codebook */ | |
406 if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) { | |
407 | |
408 /* a chunk should not have both chunk types */ | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
409 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBF0 and CBFZ chunks\n"); |
1496 | 410 return; |
411 } | |
412 | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
413 /* decompress the full codebook chunk */ |
1496 | 414 if (cbfz_chunk != -1) { |
415 | |
4364 | 416 chunk_size = AV_RB32(&s->buf[cbfz_chunk + 4]); |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
417 cbfz_chunk += CHUNK_PREAMBLE_SIZE; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
418 decode_format80(&s->buf[cbfz_chunk], chunk_size, |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
419 s->codebook, s->codebook_size, 0); |
1496 | 420 } |
421 | |
422 /* copy a full codebook */ | |
423 if (cbf0_chunk != -1) { | |
424 | |
4364 | 425 chunk_size = AV_RB32(&s->buf[cbf0_chunk + 4]); |
1496 | 426 /* sanity check the full codebook size */ |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
427 if (chunk_size > MAX_CODEBOOK_SIZE) { |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
428 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: CBF0 chunk too large (0x%X bytes)\n", |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
429 chunk_size); |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
430 return; |
1496 | 431 } |
432 cbf0_chunk += CHUNK_PREAMBLE_SIZE; | |
433 | |
434 memcpy(s->codebook, &s->buf[cbf0_chunk], chunk_size); | |
435 } | |
436 | |
437 /* decode the frame */ | |
438 if (vptz_chunk == -1) { | |
439 | |
440 /* something is wrong if there is no VPTZ chunk */ | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
441 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: no VPTZ chunk found\n"); |
1496 | 442 return; |
443 } | |
444 | |
4364 | 445 chunk_size = AV_RB32(&s->buf[vptz_chunk + 4]); |
1496 | 446 vptz_chunk += CHUNK_PREAMBLE_SIZE; |
447 decode_format80(&s->buf[vptz_chunk], chunk_size, | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
448 s->decode_buffer, s->decode_buffer_size, 1); |
1496 | 449 |
450 /* render the final PAL8 frame */ | |
1506 | 451 if (s->vector_height == 4) |
452 index_shift = 4; | |
453 else | |
454 index_shift = 3; | |
2967 | 455 for (y = 0; y < s->frame.linesize[0] * s->height; |
1496 | 456 y += s->frame.linesize[0] * s->vector_height) { |
457 | |
458 for (x = y; x < y + s->width; x += 4, lobytes++, hibytes++) { | |
459 pixel_ptr = x; | |
460 | |
461 /* get the vector index, the method for which varies according to | |
462 * VQA file version */ | |
463 switch (s->vqa_version) { | |
464 | |
465 case 1: | |
2967 | 466 /* still need sample media for this case (only one game, "Legend of |
1496 | 467 * Kyrandia III : Malcolm's Revenge", is known to use this version) */ |
4245 | 468 lobyte = s->decode_buffer[lobytes * 2]; |
469 hibyte = s->decode_buffer[(lobytes * 2) + 1]; | |
470 vector_index = ((hibyte << 8) | lobyte) >> 3; | |
471 vector_index <<= index_shift; | |
472 lines = s->vector_height; | |
473 /* uniform color fill - a quick hack */ | |
474 if (hibyte == 0xFF) { | |
475 while (lines--) { | |
476 s->frame.data[0][pixel_ptr + 0] = 255 - lobyte; | |
477 s->frame.data[0][pixel_ptr + 1] = 255 - lobyte; | |
478 s->frame.data[0][pixel_ptr + 2] = 255 - lobyte; | |
479 s->frame.data[0][pixel_ptr + 3] = 255 - lobyte; | |
480 pixel_ptr += s->frame.linesize[0]; | |
481 } | |
482 lines=0; | |
483 } | |
1496 | 484 break; |
485 | |
486 case 2: | |
487 lobyte = s->decode_buffer[lobytes]; | |
488 hibyte = s->decode_buffer[hibytes]; | |
489 vector_index = (hibyte << 8) | lobyte; | |
1506 | 490 vector_index <<= index_shift; |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
491 lines = s->vector_height; |
1496 | 492 break; |
493 | |
494 case 3: | |
495 /* not implemented yet */ | |
496 lines = 0; | |
497 break; | |
498 } | |
499 | |
500 while (lines--) { | |
501 s->frame.data[0][pixel_ptr + 0] = s->codebook[vector_index++]; | |
502 s->frame.data[0][pixel_ptr + 1] = s->codebook[vector_index++]; | |
503 s->frame.data[0][pixel_ptr + 2] = s->codebook[vector_index++]; | |
504 s->frame.data[0][pixel_ptr + 3] = s->codebook[vector_index++]; | |
505 pixel_ptr += s->frame.linesize[0]; | |
506 } | |
507 } | |
508 } | |
509 | |
510 /* handle partial codebook */ | |
511 if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) { | |
512 /* a chunk should not have both chunk types */ | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
513 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBP0 and CBPZ chunks\n"); |
1496 | 514 return; |
515 } | |
516 | |
517 if (cbp0_chunk != -1) { | |
518 | |
4364 | 519 chunk_size = AV_RB32(&s->buf[cbp0_chunk + 4]); |
1496 | 520 cbp0_chunk += CHUNK_PREAMBLE_SIZE; |
521 | |
522 /* accumulate partial codebook */ | |
523 memcpy(&s->next_codebook_buffer[s->next_codebook_buffer_index], | |
524 &s->buf[cbp0_chunk], chunk_size); | |
525 s->next_codebook_buffer_index += chunk_size; | |
526 | |
527 s->partial_countdown--; | |
528 if (s->partial_countdown == 0) { | |
529 | |
530 /* time to replace codebook */ | |
2967 | 531 memcpy(s->codebook, s->next_codebook_buffer, |
1496 | 532 s->next_codebook_buffer_index); |
533 | |
534 /* reset accounting */ | |
535 s->next_codebook_buffer_index = 0; | |
536 s->partial_countdown = s->partial_count; | |
537 } | |
538 } | |
539 | |
540 if (cbpz_chunk != -1) { | |
541 | |
4364 | 542 chunk_size = AV_RB32(&s->buf[cbpz_chunk + 4]); |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
543 cbpz_chunk += CHUNK_PREAMBLE_SIZE; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
544 |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
545 /* accumulate partial codebook */ |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
546 memcpy(&s->next_codebook_buffer[s->next_codebook_buffer_index], |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
547 &s->buf[cbpz_chunk], chunk_size); |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
548 s->next_codebook_buffer_index += chunk_size; |
1496 | 549 |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
550 s->partial_countdown--; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
551 if (s->partial_countdown == 0) { |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
552 |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
553 /* decompress codebook */ |
2967 | 554 decode_format80(s->next_codebook_buffer, |
555 s->next_codebook_buffer_index, | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
556 s->codebook, s->codebook_size, 0); |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
557 |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
558 /* reset accounting */ |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
559 s->next_codebook_buffer_index = 0; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
560 s->partial_countdown = s->partial_count; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
561 } |
1496 | 562 } |
563 } | |
564 | |
565 static int vqa_decode_frame(AVCodecContext *avctx, | |
566 void *data, int *data_size, | |
6295 | 567 const uint8_t *buf, int buf_size) |
1496 | 568 { |
4827 | 569 VqaContext *s = avctx->priv_data; |
1496 | 570 |
571 s->buf = buf; | |
572 s->size = buf_size; | |
573 | |
574 if (s->frame.data[0]) | |
575 avctx->release_buffer(avctx, &s->frame); | |
576 | |
577 if (avctx->get_buffer(avctx, &s->frame)) { | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
578 av_log(s->avctx, AV_LOG_ERROR, " VQA Video: get_buffer() failed\n"); |
1496 | 579 return -1; |
580 } | |
581 | |
582 vqa_decode_chunk(s); | |
583 | |
584 /* make the palette available on the way out */ | |
585 memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4); | |
1585
6b224ca24033
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
1506
diff
changeset
|
586 s->frame.palette_has_changed = 1; |
1496 | 587 |
588 *data_size = sizeof(AVFrame); | |
589 *(AVFrame*)data = s->frame; | |
590 | |
591 /* report that the buffer was completely consumed */ | |
592 return buf_size; | |
593 } | |
594 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6484
diff
changeset
|
595 static av_cold int vqa_decode_end(AVCodecContext *avctx) |
1496 | 596 { |
4827 | 597 VqaContext *s = avctx->priv_data; |
1496 | 598 |
599 av_free(s->codebook); | |
600 av_free(s->next_codebook_buffer); | |
601 av_free(s->decode_buffer); | |
602 | |
603 if (s->frame.data[0]) | |
604 avctx->release_buffer(avctx, &s->frame); | |
605 | |
606 return 0; | |
607 } | |
608 | |
609 AVCodec vqa_decoder = { | |
610 "vqavideo", | |
611 CODEC_TYPE_VIDEO, | |
612 CODEC_ID_WS_VQA, | |
613 sizeof(VqaContext), | |
614 vqa_decode_init, | |
615 NULL, | |
616 vqa_decode_end, | |
617 vqa_decode_frame, | |
618 CODEC_CAP_DR1, | |
6722 | 619 .long_name = "Westwood Studios VQA (Vector Quantized Animation) video", |
1496 | 620 }; |