Mercurial > libavcodec.hg
annotate vqavideo.c @ 9930:32e856bd5ded libavcodec
Check for CONFIG_LIBFOO_DECODER/CONFIG_LIBFOO_ENCODER instead of just
CONFIG_LIBFOO in the external libraries section.
This is more consistent with the rest of the Makefiles, it makes clearer what
is actually implemented and should be advantageous if we implement an external
library encoder where we previously just had the decoder and vice versa.
author | diego |
---|---|
date | Tue, 07 Jul 2009 09:33:08 +0000 |
parents | 54bc8a2727b0 |
children | 5da84f0d0a55 |
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 /** | |
8718
e9d9d946f213
Use full internal pathname in doxygen @file directives.
diego
parents:
8573
diff
changeset
|
23 * @file libavcodec/vqavideo.c |
1496 | 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 | |
8573
2acf0ae7b041
Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents:
7040
diff
changeset
|
71 #include "libavutil/intreadwrite.h" |
1496 | 72 #include "avcodec.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 AVFrame frame; | |
105 | |
6295 | 106 const unsigned char *buf; |
1496 | 107 int size; |
108 | |
3799
81638b2fbeba
palette (if we memcpy it into AVFrame) must be uint32_t
michael
parents:
3036
diff
changeset
|
109 uint32_t palette[PALETTE_COUNT]; |
1496 | 110 |
111 int width; /* width of a frame */ | |
112 int height; /* height of a frame */ | |
113 int vector_width; /* width of individual vector */ | |
114 int vector_height; /* height of individual vector */ | |
115 int vqa_version; /* this should be either 1, 2 or 3 */ | |
116 | |
117 unsigned char *codebook; /* the current codebook */ | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
118 int codebook_size; |
1496 | 119 unsigned char *next_codebook_buffer; /* accumulator for next codebook */ |
120 int next_codebook_buffer_index; | |
121 | |
122 unsigned char *decode_buffer; | |
123 int decode_buffer_size; | |
124 | |
125 /* number of frames to go before replacing codebook */ | |
126 int partial_countdown; | |
127 int partial_count; | |
128 | |
129 } VqaContext; | |
130 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6484
diff
changeset
|
131 static av_cold int vqa_decode_init(AVCodecContext *avctx) |
1496 | 132 { |
4827 | 133 VqaContext *s = avctx->priv_data; |
1496 | 134 unsigned char *vqa_header; |
6377 | 135 int i, j, codebook_index; |
1496 | 136 |
137 s->avctx = avctx; | |
138 avctx->pix_fmt = PIX_FMT_PAL8; | |
139 | |
140 /* make sure the extradata made it */ | |
141 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
|
142 av_log(s->avctx, AV_LOG_ERROR, " VQA video: expected extradata size of %d\n", VQA_HEADER_SIZE); |
1496 | 143 return -1; |
144 } | |
145 | |
146 /* load up the VQA parameters from the header */ | |
147 vqa_header = (unsigned char *)s->avctx->extradata; | |
148 s->vqa_version = vqa_header[0]; | |
4364 | 149 s->width = AV_RL16(&vqa_header[6]); |
150 s->height = AV_RL16(&vqa_header[8]); | |
2422 | 151 if(avcodec_check_dimensions(avctx, s->width, s->height)){ |
152 s->width= s->height= 0; | |
153 return -1; | |
154 } | |
1496 | 155 s->vector_width = vqa_header[10]; |
156 s->vector_height = vqa_header[11]; | |
157 s->partial_count = s->partial_countdown = vqa_header[13]; | |
158 | |
159 /* the vector dimensions have to meet very stringent requirements */ | |
160 if ((s->vector_width != 4) || | |
161 ((s->vector_height != 2) && (s->vector_height != 4))) { | |
162 /* return without further initialization */ | |
163 return -1; | |
164 } | |
165 | |
166 /* allocate codebooks */ | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
167 s->codebook_size = MAX_CODEBOOK_SIZE; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
168 s->codebook = av_malloc(s->codebook_size); |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
169 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
|
170 |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
171 /* initialize the solid-color vectors */ |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
172 if (s->vector_height == 4) { |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
173 codebook_index = 0xFF00 * 16; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
174 for (i = 0; i < 256; i++) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
175 for (j = 0; j < 16; j++) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
176 s->codebook[codebook_index++] = i; |
1496 | 177 } else { |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
178 codebook_index = 0xF00 * 8; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
179 for (i = 0; i < 256; i++) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
180 for (j = 0; j < 8; j++) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
181 s->codebook[codebook_index++] = i; |
1496 | 182 } |
183 s->next_codebook_buffer_index = 0; | |
184 | |
185 /* allocate decode buffer */ | |
186 s->decode_buffer_size = (s->width / s->vector_width) * | |
187 (s->height / s->vector_height) * 2; | |
188 s->decode_buffer = av_malloc(s->decode_buffer_size); | |
189 | |
190 s->frame.data[0] = NULL; | |
191 | |
192 return 0; | |
193 } | |
194 | |
195 #define CHECK_COUNT() \ | |
196 if (dest_index + count > dest_size) { \ | |
1598
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: 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
|
198 av_log(NULL, AV_LOG_ERROR, " VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \ |
1496 | 199 dest_index, count, dest_size); \ |
200 return; \ | |
201 } | |
202 | |
6295 | 203 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
|
204 unsigned char *dest, int dest_size, int check_size) { |
1496 | 205 |
206 int src_index = 0; | |
207 int dest_index = 0; | |
208 int count; | |
209 int src_pos; | |
210 unsigned char color; | |
211 int i; | |
212 | |
213 while (src_index < src_size) { | |
214 | |
215 vqa_debug(" opcode %02X: ", src[src_index]); | |
216 | |
217 /* 0x80 means that frame is finished */ | |
218 if (src[src_index] == 0x80) | |
219 return; | |
220 | |
221 if (dest_index >= dest_size) { | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
222 av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n", |
1496 | 223 dest_index, dest_size); |
224 return; | |
225 } | |
226 | |
227 if (src[src_index] == 0xFF) { | |
228 | |
229 src_index++; | |
4364 | 230 count = AV_RL16(&src[src_index]); |
1496 | 231 src_index += 2; |
4364 | 232 src_pos = AV_RL16(&src[src_index]); |
1496 | 233 src_index += 2; |
234 vqa_debug("(1) copy %X bytes from absolute pos %X\n", count, src_pos); | |
235 CHECK_COUNT(); | |
236 for (i = 0; i < count; i++) | |
237 dest[dest_index + i] = dest[src_pos + i]; | |
238 dest_index += count; | |
239 | |
240 } else if (src[src_index] == 0xFE) { | |
241 | |
242 src_index++; | |
4364 | 243 count = AV_RL16(&src[src_index]); |
1496 | 244 src_index += 2; |
245 color = src[src_index++]; | |
246 vqa_debug("(2) set %X bytes to %02X\n", count, color); | |
247 CHECK_COUNT(); | |
248 memset(&dest[dest_index], color, count); | |
249 dest_index += count; | |
250 | |
251 } else if ((src[src_index] & 0xC0) == 0xC0) { | |
252 | |
253 count = (src[src_index++] & 0x3F) + 3; | |
4364 | 254 src_pos = AV_RL16(&src[src_index]); |
1496 | 255 src_index += 2; |
256 vqa_debug("(3) copy %X bytes from absolute pos %X\n", count, src_pos); | |
257 CHECK_COUNT(); | |
258 for (i = 0; i < count; i++) | |
259 dest[dest_index + i] = dest[src_pos + i]; | |
260 dest_index += count; | |
261 | |
262 } else if (src[src_index] > 0x80) { | |
263 | |
264 count = src[src_index++] & 0x3F; | |
265 vqa_debug("(4) copy %X bytes from source to dest\n", count); | |
266 CHECK_COUNT(); | |
267 memcpy(&dest[dest_index], &src[src_index], count); | |
268 src_index += count; | |
269 dest_index += count; | |
270 | |
271 } else { | |
272 | |
273 count = ((src[src_index] & 0x70) >> 4) + 3; | |
4364 | 274 src_pos = AV_RB16(&src[src_index]) & 0x0FFF; |
1496 | 275 src_index += 2; |
276 vqa_debug("(5) copy %X bytes from relpos %X\n", count, src_pos); | |
277 CHECK_COUNT(); | |
278 for (i = 0; i < count; i++) | |
279 dest[dest_index + i] = dest[dest_index - src_pos + i]; | |
280 dest_index += count; | |
281 } | |
282 } | |
283 | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
284 /* 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
|
285 * 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
|
286 * 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
|
287 * not every entry needs to be filled */ |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
288 if (check_size) |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
289 if (dest_index < dest_size) |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
290 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
|
291 dest_index, dest_size); |
1496 | 292 } |
293 | |
294 static void vqa_decode_chunk(VqaContext *s) | |
295 { | |
296 unsigned int chunk_type; | |
297 unsigned int chunk_size; | |
298 int byte_skip; | |
299 unsigned int index = 0; | |
300 int i; | |
301 unsigned char r, g, b; | |
1506 | 302 int index_shift; |
1496 | 303 |
304 int cbf0_chunk = -1; | |
305 int cbfz_chunk = -1; | |
306 int cbp0_chunk = -1; | |
307 int cbpz_chunk = -1; | |
308 int cpl0_chunk = -1; | |
309 int cplz_chunk = -1; | |
310 int vptz_chunk = -1; | |
311 | |
312 int x, y; | |
313 int lines = 0; | |
314 int pixel_ptr; | |
315 int vector_index = 0; | |
316 int lobyte = 0; | |
317 int hibyte = 0; | |
318 int lobytes = 0; | |
319 int hibytes = s->decode_buffer_size / 2; | |
320 | |
321 /* first, traverse through the frame and find the subchunks */ | |
322 while (index < s->size) { | |
323 | |
4364 | 324 chunk_type = AV_RB32(&s->buf[index]); |
325 chunk_size = AV_RB32(&s->buf[index + 4]); | |
1496 | 326 |
327 switch (chunk_type) { | |
328 | |
329 case CBF0_TAG: | |
330 cbf0_chunk = index; | |
331 break; | |
332 | |
333 case CBFZ_TAG: | |
334 cbfz_chunk = index; | |
335 break; | |
336 | |
337 case CBP0_TAG: | |
338 cbp0_chunk = index; | |
339 break; | |
340 | |
341 case CBPZ_TAG: | |
342 cbpz_chunk = index; | |
343 break; | |
344 | |
345 case CPL0_TAG: | |
346 cpl0_chunk = index; | |
347 break; | |
348 | |
349 case CPLZ_TAG: | |
350 cplz_chunk = index; | |
351 break; | |
352 | |
353 case VPTZ_TAG: | |
354 vptz_chunk = index; | |
355 break; | |
356 | |
357 default: | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
358 av_log(s->avctx, AV_LOG_ERROR, " VQA video: Found unknown chunk type: %c%c%c%c (%08X)\n", |
1496 | 359 (chunk_type >> 24) & 0xFF, |
360 (chunk_type >> 16) & 0xFF, | |
361 (chunk_type >> 8) & 0xFF, | |
362 (chunk_type >> 0) & 0xFF, | |
363 chunk_type); | |
364 break; | |
365 } | |
366 | |
367 byte_skip = chunk_size & 0x01; | |
368 index += (CHUNK_PREAMBLE_SIZE + chunk_size + byte_skip); | |
369 } | |
370 | |
371 /* next, deal with the palette */ | |
372 if ((cpl0_chunk != -1) && (cplz_chunk != -1)) { | |
373 | |
374 /* 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
|
375 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CPL0 and CPLZ chunks\n"); |
1496 | 376 return; |
377 } | |
378 | |
379 /* decompress the palette chunk */ | |
380 if (cplz_chunk != -1) { | |
381 | |
382 /* yet to be handled */ | |
383 | |
384 } | |
385 | |
386 /* convert the RGB palette into the machine's endian format */ | |
387 if (cpl0_chunk != -1) { | |
388 | |
4364 | 389 chunk_size = AV_RB32(&s->buf[cpl0_chunk + 4]); |
1496 | 390 /* sanity check the palette size */ |
391 if (chunk_size / 3 > 256) { | |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
392 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found a palette chunk with %d colors\n", |
1496 | 393 chunk_size / 3); |
394 return; | |
395 } | |
396 cpl0_chunk += CHUNK_PREAMBLE_SIZE; | |
397 for (i = 0; i < chunk_size / 3; i++) { | |
398 /* scale by 4 to transform 6-bit palette -> 8-bit */ | |
399 r = s->buf[cpl0_chunk++] * 4; | |
400 g = s->buf[cpl0_chunk++] * 4; | |
401 b = s->buf[cpl0_chunk++] * 4; | |
1585
6b224ca24033
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
1506
diff
changeset
|
402 s->palette[i] = (r << 16) | (g << 8) | (b); |
1496 | 403 } |
404 } | |
405 | |
406 /* next, look for a full codebook */ | |
407 if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) { | |
408 | |
409 /* 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
|
410 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBF0 and CBFZ chunks\n"); |
1496 | 411 return; |
412 } | |
413 | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
414 /* decompress the full codebook chunk */ |
1496 | 415 if (cbfz_chunk != -1) { |
416 | |
4364 | 417 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
|
418 cbfz_chunk += CHUNK_PREAMBLE_SIZE; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
419 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
|
420 s->codebook, s->codebook_size, 0); |
1496 | 421 } |
422 | |
423 /* copy a full codebook */ | |
424 if (cbf0_chunk != -1) { | |
425 | |
4364 | 426 chunk_size = AV_RB32(&s->buf[cbf0_chunk + 4]); |
1496 | 427 /* sanity check the full codebook size */ |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
428 if (chunk_size > MAX_CODEBOOK_SIZE) { |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
429 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
|
430 chunk_size); |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
431 return; |
1496 | 432 } |
433 cbf0_chunk += CHUNK_PREAMBLE_SIZE; | |
434 | |
435 memcpy(s->codebook, &s->buf[cbf0_chunk], chunk_size); | |
436 } | |
437 | |
438 /* decode the frame */ | |
439 if (vptz_chunk == -1) { | |
440 | |
441 /* 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
|
442 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: no VPTZ chunk found\n"); |
1496 | 443 return; |
444 } | |
445 | |
4364 | 446 chunk_size = AV_RB32(&s->buf[vptz_chunk + 4]); |
1496 | 447 vptz_chunk += CHUNK_PREAMBLE_SIZE; |
448 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
|
449 s->decode_buffer, s->decode_buffer_size, 1); |
1496 | 450 |
451 /* render the final PAL8 frame */ | |
1506 | 452 if (s->vector_height == 4) |
453 index_shift = 4; | |
454 else | |
455 index_shift = 3; | |
2967 | 456 for (y = 0; y < s->frame.linesize[0] * s->height; |
1496 | 457 y += s->frame.linesize[0] * s->vector_height) { |
458 | |
459 for (x = y; x < y + s->width; x += 4, lobytes++, hibytes++) { | |
460 pixel_ptr = x; | |
461 | |
462 /* get the vector index, the method for which varies according to | |
463 * VQA file version */ | |
464 switch (s->vqa_version) { | |
465 | |
466 case 1: | |
2967 | 467 /* still need sample media for this case (only one game, "Legend of |
1496 | 468 * Kyrandia III : Malcolm's Revenge", is known to use this version) */ |
4245 | 469 lobyte = s->decode_buffer[lobytes * 2]; |
470 hibyte = s->decode_buffer[(lobytes * 2) + 1]; | |
471 vector_index = ((hibyte << 8) | lobyte) >> 3; | |
472 vector_index <<= index_shift; | |
473 lines = s->vector_height; | |
474 /* uniform color fill - a quick hack */ | |
475 if (hibyte == 0xFF) { | |
476 while (lines--) { | |
477 s->frame.data[0][pixel_ptr + 0] = 255 - lobyte; | |
478 s->frame.data[0][pixel_ptr + 1] = 255 - lobyte; | |
479 s->frame.data[0][pixel_ptr + 2] = 255 - lobyte; | |
480 s->frame.data[0][pixel_ptr + 3] = 255 - lobyte; | |
481 pixel_ptr += s->frame.linesize[0]; | |
482 } | |
483 lines=0; | |
484 } | |
1496 | 485 break; |
486 | |
487 case 2: | |
488 lobyte = s->decode_buffer[lobytes]; | |
489 hibyte = s->decode_buffer[hibytes]; | |
490 vector_index = (hibyte << 8) | lobyte; | |
1506 | 491 vector_index <<= index_shift; |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
492 lines = s->vector_height; |
1496 | 493 break; |
494 | |
495 case 3: | |
496 /* not implemented yet */ | |
497 lines = 0; | |
498 break; | |
499 } | |
500 | |
501 while (lines--) { | |
502 s->frame.data[0][pixel_ptr + 0] = s->codebook[vector_index++]; | |
503 s->frame.data[0][pixel_ptr + 1] = s->codebook[vector_index++]; | |
504 s->frame.data[0][pixel_ptr + 2] = s->codebook[vector_index++]; | |
505 s->frame.data[0][pixel_ptr + 3] = s->codebook[vector_index++]; | |
506 pixel_ptr += s->frame.linesize[0]; | |
507 } | |
508 } | |
509 } | |
510 | |
511 /* handle partial codebook */ | |
512 if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) { | |
513 /* 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
|
514 av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBP0 and CBPZ chunks\n"); |
1496 | 515 return; |
516 } | |
517 | |
518 if (cbp0_chunk != -1) { | |
519 | |
4364 | 520 chunk_size = AV_RB32(&s->buf[cbp0_chunk + 4]); |
1496 | 521 cbp0_chunk += CHUNK_PREAMBLE_SIZE; |
522 | |
523 /* accumulate partial codebook */ | |
524 memcpy(&s->next_codebook_buffer[s->next_codebook_buffer_index], | |
525 &s->buf[cbp0_chunk], chunk_size); | |
526 s->next_codebook_buffer_index += chunk_size; | |
527 | |
528 s->partial_countdown--; | |
529 if (s->partial_countdown == 0) { | |
530 | |
531 /* time to replace codebook */ | |
2967 | 532 memcpy(s->codebook, s->next_codebook_buffer, |
1496 | 533 s->next_codebook_buffer_index); |
534 | |
535 /* reset accounting */ | |
536 s->next_codebook_buffer_index = 0; | |
537 s->partial_countdown = s->partial_count; | |
538 } | |
539 } | |
540 | |
541 if (cbpz_chunk != -1) { | |
542 | |
4364 | 543 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
|
544 cbpz_chunk += CHUNK_PREAMBLE_SIZE; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
545 |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
546 /* accumulate partial codebook */ |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
547 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
|
548 &s->buf[cbpz_chunk], chunk_size); |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
549 s->next_codebook_buffer_index += chunk_size; |
1496 | 550 |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
551 s->partial_countdown--; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
552 if (s->partial_countdown == 0) { |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
553 |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
554 /* decompress codebook */ |
2967 | 555 decode_format80(s->next_codebook_buffer, |
556 s->next_codebook_buffer_index, | |
1501
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
557 s->codebook, s->codebook_size, 0); |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
558 |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
559 /* reset accounting */ |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
560 s->next_codebook_buffer_index = 0; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
561 s->partial_countdown = s->partial_count; |
dc6f46cd4a7b
added solid color vectors; basic PAL8, 4x2-vector video (as in
tmmm
parents:
1496
diff
changeset
|
562 } |
1496 | 563 } |
564 } | |
565 | |
566 static int vqa_decode_frame(AVCodecContext *avctx, | |
567 void *data, int *data_size, | |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8718
diff
changeset
|
568 AVPacket *avpkt) |
1496 | 569 { |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8718
diff
changeset
|
570 const uint8_t *buf = avpkt->data; |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8718
diff
changeset
|
571 int buf_size = avpkt->size; |
4827 | 572 VqaContext *s = avctx->priv_data; |
1496 | 573 |
574 s->buf = buf; | |
575 s->size = buf_size; | |
576 | |
577 if (s->frame.data[0]) | |
578 avctx->release_buffer(avctx, &s->frame); | |
579 | |
580 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
|
581 av_log(s->avctx, AV_LOG_ERROR, " VQA Video: get_buffer() failed\n"); |
1496 | 582 return -1; |
583 } | |
584 | |
585 vqa_decode_chunk(s); | |
586 | |
587 /* make the palette available on the way out */ | |
588 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
|
589 s->frame.palette_has_changed = 1; |
1496 | 590 |
591 *data_size = sizeof(AVFrame); | |
592 *(AVFrame*)data = s->frame; | |
593 | |
594 /* report that the buffer was completely consumed */ | |
595 return buf_size; | |
596 } | |
597 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6484
diff
changeset
|
598 static av_cold int vqa_decode_end(AVCodecContext *avctx) |
1496 | 599 { |
4827 | 600 VqaContext *s = avctx->priv_data; |
1496 | 601 |
602 av_free(s->codebook); | |
603 av_free(s->next_codebook_buffer); | |
604 av_free(s->decode_buffer); | |
605 | |
606 if (s->frame.data[0]) | |
607 avctx->release_buffer(avctx, &s->frame); | |
608 | |
609 return 0; | |
610 } | |
611 | |
612 AVCodec vqa_decoder = { | |
613 "vqavideo", | |
614 CODEC_TYPE_VIDEO, | |
615 CODEC_ID_WS_VQA, | |
616 sizeof(VqaContext), | |
617 vqa_decode_init, | |
618 NULL, | |
619 vqa_decode_end, | |
620 vqa_decode_frame, | |
621 CODEC_CAP_DR1, | |
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6903
diff
changeset
|
622 .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"), |
1496 | 623 }; |