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