FFmpeg
vqavideo.c
Go to the documentation of this file.
1 /*
2  * Westwood Studios VQA Video Decoder
3  * Copyright (c) 2003 Mike Melanson <melanson@pcisys.net>
4  * Copyright (c) 2021 Pekka Väänänen <pekka.vaananen@iki.fi>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /**
24  * @file
25  * VQA Video Decoder
26  * @author Mike Melanson (melanson@pcisys.net)
27  * @see http://wiki.multimedia.cx/index.php?title=VQA
28  *
29  * The VQA video decoder outputs PAL8 or RGB555 colorspace data, depending
30  * on the type of data in the file.
31  *
32  * This decoder needs the 42-byte VQHD header from the beginning
33  * of the VQA file passed through the extradata field. The VQHD header
34  * is laid out as:
35  *
36  * bytes 0-3 chunk fourcc: 'VQHD'
37  * bytes 4-7 chunk size in big-endian format, should be 0x0000002A
38  * bytes 8-49 VQHD chunk data
39  *
40  * Bytes 8-49 are what this decoder expects to see.
41  *
42  * Briefly, VQA is a vector quantized animation format that operates in a
43  * VGA palettized colorspace. It operates on pixel vectors (blocks)
44  * of either 4x2 or 4x4 in size. Compressed VQA chunks can contain vector
45  * codebooks, palette information, and code maps for rendering vectors onto
46  * frames. Any of these components can also be compressed with a run-length
47  * encoding (RLE) algorithm commonly referred to as "format80".
48  *
49  * VQA takes a novel approach to rate control. Each group of n frames
50  * (usually, n = 8) relies on a different vector codebook. Rather than
51  * transporting an entire codebook every 8th frame, the new codebook is
52  * broken up into 8 pieces and sent along with the compressed video chunks
53  * for each of the 8 frames preceding the 8 frames which require the
54  * codebook. A full codebook is also sent on the very first frame of a
55  * file. This is an interesting technique, although it makes random file
56  * seeking difficult despite the fact that the frames are all intracoded.
57  *
58  * V1,2 VQA uses 12-bit codebook indexes. If the 12-bit indexes were
59  * packed into bytes and then RLE compressed, bytewise, the results would
60  * be poor. That is why the coding method divides each index into 2 parts,
61  * the top 4 bits and the bottom 8 bits, then RL encodes the 4-bit pieces
62  * together and the 8-bit pieces together. If most of the vectors are
63  * clustered into one group of 256 vectors, most of the 4-bit index pieces
64  * should be the same.
65  *
66  * VQA3 introduces a 15-bit high color codebook, delta coding, replaces
67  * the above "split byte" scheme with RLE compression, and extends the
68  * "format80" compression with relative references. In VQA3 the whole
69  * codebook is always updated as a whole without splitting it into pieces.
70  */
71 
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 
76 #include "libavutil/intreadwrite.h"
77 #include "libavutil/imgutils.h"
78 #include "avcodec.h"
79 #include "bytestream.h"
80 #include "codec_internal.h"
81 #include "internal.h"
82 
83 #define PALETTE_COUNT 256
84 #define VQA_HEADER_SIZE 0x2A
85 
86 /* allocate the maximum vector space, regardless of the file version:
87  * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */
88 #define MAX_CODEBOOK_VECTORS 0xFF00
89 #define SOLID_PIXEL_VECTORS 0x100
90 #define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS)
91 #define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4 * sizeof(uint16_t))
92 
93 #define CBF0_TAG MKBETAG('C', 'B', 'F', '0')
94 #define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z')
95 #define CBP0_TAG MKBETAG('C', 'B', 'P', '0')
96 #define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z')
97 #define CPL0_TAG MKBETAG('C', 'P', 'L', '0')
98 #define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z')
99 #define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z')
100 #define VPTR_TAG MKBETAG('V', 'P', 'T', 'R')
101 #define VPRZ_TAG MKBETAG('V', 'P', 'R', 'Z')
102 
103 typedef struct VqaContext {
107 
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 */
118  unsigned char *next_codebook_buffer; /* accumulator for next codebook */
120 
121  unsigned char *decode_buffer;
123 
124  /* number of frames to go before replacing codebook */
127 } VqaContext;
128 
130 {
131  VqaContext *s = avctx->priv_data;
132  int i, j, codebook_index, ret;
133  int colors;
134 
135  s->avctx = avctx;
136 
137  /* make sure the extradata made it */
138  if (s->avctx->extradata_size != VQA_HEADER_SIZE) {
139  av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n", VQA_HEADER_SIZE);
140  return AVERROR(EINVAL);
141  }
142 
143  /* load up the VQA parameters from the header */
144  s->vqa_version = s->avctx->extradata[0];
145 
146  if (s->vqa_version < 1 || s->vqa_version > 3) {
147  avpriv_request_sample(avctx, "VQA Version %i", s->vqa_version);
148  return AVERROR_INVALIDDATA;
149  }
150 
151  s->width = AV_RL16(&s->avctx->extradata[6]);
152  s->height = AV_RL16(&s->avctx->extradata[8]);
153  if ((ret = ff_set_dimensions(avctx, s->width, s->height)) < 0) {
154  s->width= s->height= 0;
155  return ret;
156  }
157  s->vector_width = s->avctx->extradata[10];
158  s->vector_height = s->avctx->extradata[11];
159  s->partial_count = s->partial_countdown = s->avctx->extradata[13];
160 
161  colors = (s->avctx->extradata[14] << 8) | s->avctx->extradata[15];
162 
163  if (colors > 0) {
164  avctx->pix_fmt = AV_PIX_FMT_PAL8;
165  } else {
166  avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
167  }
168 
169  /* the vector dimensions have to meet very stringent requirements */
170  if ((s->vector_width != 4) ||
171  ((s->vector_height != 2) && (s->vector_height != 4))) {
172  /* return without further initialization */
173  return AVERROR_INVALIDDATA;
174  }
175 
176  if (s->width % s->vector_width || s->height % s->vector_height) {
177  av_log(avctx, AV_LOG_ERROR, "Image size not multiple of block size\n");
178  return AVERROR_INVALIDDATA;
179  }
180 
181  s->frame = av_frame_alloc();
182  if (!s->frame)
183  return AVERROR(ENOMEM);
184 
185  /* allocate codebooks */
186  s->codebook_size = MAX_CODEBOOK_SIZE;
187  s->codebook = av_malloc(s->codebook_size);
188  if (!s->codebook)
189  return AVERROR(ENOMEM);
190  s->next_codebook_buffer = av_malloc(s->codebook_size);
191  if (!s->next_codebook_buffer)
192  return AVERROR(ENOMEM);
193 
194  /* allocate decode buffer */
195  s->decode_buffer_size = (s->width / s->vector_width) *
196  (s->height / s->vector_height) * 2;
197  s->decode_buffer = av_mallocz(s->decode_buffer_size);
198  if (!s->decode_buffer)
199  return AVERROR(ENOMEM);
200 
201  /* initialize the solid-color vectors */
202  if (s->vector_height == 4) {
203  codebook_index = 0xFF00 * 16;
204  for (i = 0; i < 256; i++)
205  for (j = 0; j < 16; j++)
206  s->codebook[codebook_index++] = i;
207  } else {
208  codebook_index = 0xF00 * 8;
209  for (i = 0; i < 256; i++)
210  for (j = 0; j < 8; j++)
211  s->codebook[codebook_index++] = i;
212  }
213  s->next_codebook_buffer_index = 0;
214 
215  return 0;
216 }
217 
218 #define CHECK_COUNT() \
219  if (dest_index + count > dest_size) { \
220  av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \
221  av_log(s->avctx, AV_LOG_ERROR, "current dest_index = %d, count = %d, dest_size = %d\n", \
222  dest_index, count, dest_size); \
223  return AVERROR_INVALIDDATA; \
224  }
225 
226 #define CHECK_COPY(idx) \
227  if (idx < 0 || idx + count > dest_size) { \
228  av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \
229  av_log(s->avctx, AV_LOG_ERROR, "current src_pos = %d, count = %d, dest_size = %d\n", \
230  src_pos, count, dest_size); \
231  return AVERROR_INVALIDDATA; \
232  }
233 
234 
235 static int decode_format80(VqaContext *s, int src_size,
236  unsigned char *dest, int dest_size, int check_size) {
237 
238  int dest_index = 0;
239  int count, opcode, start;
240  int src_pos;
241  unsigned char color;
242  int i;
243  int relative = 0;
244 
245  if (src_size < 0 || src_size > bytestream2_get_bytes_left(&s->gb)) {
246  av_log(s->avctx, AV_LOG_ERROR, "Chunk size %d is out of range\n",
247  src_size);
248  return AVERROR_INVALIDDATA;
249  }
250 
251  /* the "new" scheme makes references relative to destination pointer */
252  if (bytestream2_peek_byte(&s->gb) == 0x00) {
253  relative = 1;
254  bytestream2_get_byte(&s->gb);
255  ff_tlog(s->avctx, "found new format stream ");
256  }
257 
258  start = bytestream2_tell(&s->gb);
259  while (bytestream2_tell(&s->gb) - start < src_size) {
260  opcode = bytestream2_get_byte(&s->gb);
261  ff_tlog(s->avctx, "opcode %02X: ", opcode);
262 
263  /* 0x80 means that frame is finished */
264  if (opcode == 0x80)
265  break;
266 
267  if (dest_index >= dest_size) {
268  av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n",
269  dest_index, dest_size);
270  return AVERROR_INVALIDDATA;
271  }
272 
273  if (opcode == 0xFF) {
274 
275  count = bytestream2_get_le16(&s->gb);
276  src_pos = bytestream2_get_le16(&s->gb);
277  if (relative)
278  src_pos = dest_index - src_pos;
279  ff_tlog(s->avctx, "(1) copy %X bytes from pos %X\n", count, src_pos);
280  CHECK_COUNT();
281  CHECK_COPY(src_pos);
282  for (i = 0; i < count; i++)
283  dest[dest_index + i] = dest[src_pos + i];
284  dest_index += count;
285 
286  } else if (opcode == 0xFE) {
287 
288  count = bytestream2_get_le16(&s->gb);
289  color = bytestream2_get_byte(&s->gb);
290  ff_tlog(s->avctx, "(2) set %X bytes to %02X\n", count, color);
291  CHECK_COUNT();
292  memset(&dest[dest_index], color, count);
293  dest_index += count;
294 
295  } else if ((opcode & 0xC0) == 0xC0) {
296 
297  count = (opcode & 0x3F) + 3;
298  src_pos = bytestream2_get_le16(&s->gb);
299  if (relative)
300  src_pos = dest_index - src_pos;
301  ff_tlog(s->avctx, "(3) copy %X bytes from pos %X\n", count, src_pos);
302  CHECK_COUNT();
303  CHECK_COPY(src_pos);
304  for (i = 0; i < count; i++)
305  dest[dest_index + i] = dest[src_pos + i];
306  dest_index += count;
307 
308  } else if (opcode > 0x80) {
309 
310  count = opcode & 0x3F;
311  ff_tlog(s->avctx, "(4) copy %X bytes from source to dest\n", count);
312  CHECK_COUNT();
313  bytestream2_get_buffer(&s->gb, &dest[dest_index], count);
314  dest_index += count;
315 
316  } else {
317 
318  count = ((opcode & 0x70) >> 4) + 3;
319  src_pos = bytestream2_get_byte(&s->gb) | ((opcode & 0x0F) << 8);
320  ff_tlog(s->avctx, "(5) copy %X bytes from relpos %X\n", count, src_pos);
321  CHECK_COUNT();
322  CHECK_COPY(dest_index - src_pos);
323  for (i = 0; i < count; i++)
324  dest[dest_index + i] = dest[dest_index - src_pos + i];
325  dest_index += count;
326  }
327  }
328 
329  /* validate that the entire destination buffer was filled; this is
330  * important for decoding frame maps since each vector needs to have a
331  * codebook entry; it is not important for compressed codebooks because
332  * not every entry needs to be filled */
333  if (check_size)
334  if (dest_index < dest_size) {
335  av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",
336  dest_index, dest_size);
337  memset(dest + dest_index, 0, dest_size - dest_index);
338  }
339 
340  return 0; // let's display what we decoded anyway
341 }
342 
344 {
345  unsigned int chunk_type;
346  unsigned int chunk_size;
347  int byte_skip;
348  unsigned int index = 0;
349  int i;
350  unsigned char r, g, b;
351  int index_shift;
352  int res;
353 
354  int cbf0_chunk = -1;
355  int cbfz_chunk = -1;
356  int cbp0_chunk = -1;
357  int cbpz_chunk = -1;
358  int cpl0_chunk = -1;
359  int cplz_chunk = -1;
360  int vptz_chunk = -1;
361 
362  int x, y;
363  int lines = 0;
364  int pixel_ptr;
365  int vector_index = 0;
366  int lobyte = 0;
367  int hibyte = 0;
368  int lobytes = 0;
369  int hibytes = s->decode_buffer_size / 2;
370 
371  /* first, traverse through the frame and find the subchunks */
372  while (bytestream2_get_bytes_left(&s->gb) >= 8) {
373 
374  chunk_type = bytestream2_get_be32u(&s->gb);
375  index = bytestream2_tell(&s->gb);
376  chunk_size = bytestream2_get_be32u(&s->gb);
377 
378  switch (chunk_type) {
379 
380  case CBF0_TAG:
381  cbf0_chunk = index;
382  break;
383 
384  case CBFZ_TAG:
385  cbfz_chunk = index;
386  break;
387 
388  case CBP0_TAG:
389  cbp0_chunk = index;
390  break;
391 
392  case CBPZ_TAG:
393  cbpz_chunk = index;
394  break;
395 
396  case CPL0_TAG:
397  cpl0_chunk = index;
398  break;
399 
400  case CPLZ_TAG:
401  cplz_chunk = index;
402  break;
403 
404  case VPTZ_TAG:
405  vptz_chunk = index;
406  break;
407 
408  default:
409  av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %s (%08X)\n",
410  av_fourcc2str(av_bswap32(chunk_type)), chunk_type);
411  break;
412  }
413 
414  byte_skip = chunk_size & 0x01;
415  bytestream2_skip(&s->gb, chunk_size + byte_skip);
416  }
417 
418  /* next, deal with the palette */
419  if ((cpl0_chunk != -1) && (cplz_chunk != -1)) {
420 
421  /* a chunk should not have both chunk types */
422  av_log(s->avctx, AV_LOG_ERROR, "problem: found both CPL0 and CPLZ chunks\n");
423  return AVERROR_INVALIDDATA;
424  }
425 
426  /* decompress the palette chunk */
427  if (cplz_chunk != -1) {
428 
429 /* yet to be handled */
430 
431  }
432 
433  /* convert the RGB palette into the machine's endian format */
434  if (cpl0_chunk != -1) {
435 
436  bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET);
437  chunk_size = bytestream2_get_be32(&s->gb);
438  /* sanity check the palette size */
439  if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) {
440  av_log(s->avctx, AV_LOG_ERROR, "problem: found a palette chunk with %d colors\n",
441  chunk_size / 3);
442  return AVERROR_INVALIDDATA;
443  }
444  for (i = 0; i < chunk_size / 3; i++) {
445  /* scale by 4 to transform 6-bit palette -> 8-bit */
446  r = bytestream2_get_byteu(&s->gb) * 4;
447  g = bytestream2_get_byteu(&s->gb) * 4;
448  b = bytestream2_get_byteu(&s->gb) * 4;
449  s->palette[i] = 0xFFU << 24 | r << 16 | g << 8 | b;
450  s->palette[i] |= s->palette[i] >> 6 & 0x30303;
451  }
452  }
453 
454  /* next, look for a full codebook */
455  if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) {
456 
457  /* a chunk should not have both chunk types */
458  av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n");
459  return AVERROR_INVALIDDATA;
460  }
461 
462  /* decompress the full codebook chunk */
463  if (cbfz_chunk != -1) {
464 
465  bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET);
466  chunk_size = bytestream2_get_be32(&s->gb);
467  if ((res = decode_format80(s, chunk_size, s->codebook,
468  s->codebook_size, 0)) < 0)
469  return res;
470  }
471 
472  /* copy a full codebook */
473  if (cbf0_chunk != -1) {
474 
475  bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET);
476  chunk_size = bytestream2_get_be32(&s->gb);
477  /* sanity check the full codebook size */
478  if (chunk_size > MAX_CODEBOOK_SIZE) {
479  av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n",
480  chunk_size);
481  return AVERROR_INVALIDDATA;
482  }
483 
484  bytestream2_get_buffer(&s->gb, s->codebook, chunk_size);
485  }
486 
487  /* decode the frame */
488  if (vptz_chunk == -1) {
489 
490  /* something is wrong if there is no VPTZ chunk */
491  av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ chunk found\n");
492  return AVERROR_INVALIDDATA;
493  }
494 
495  bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET);
496  chunk_size = bytestream2_get_be32(&s->gb);
497  if ((res = decode_format80(s, chunk_size,
498  s->decode_buffer, s->decode_buffer_size, 1)) < 0)
499  return res;
500 
501  /* render the final PAL8 frame */
502  if (s->vector_height == 4)
503  index_shift = 4;
504  else
505  index_shift = 3;
506  for (y = 0; y < s->height; y += s->vector_height) {
507  for (x = 0; x < s->width; x += 4, lobytes++, hibytes++) {
508  pixel_ptr = y * frame->linesize[0] + x;
509 
510  /* get the vector index, the method for which varies according to
511  * VQA file version */
512  switch (s->vqa_version) {
513 
514  case 1:
515  lobyte = s->decode_buffer[lobytes * 2];
516  hibyte = s->decode_buffer[(lobytes * 2) + 1];
517  vector_index = ((hibyte << 8) | lobyte) >> 3;
518  vector_index <<= index_shift;
519  lines = s->vector_height;
520  /* uniform color fill - a quick hack */
521  if (hibyte == 0xFF) {
522  while (lines--) {
523  frame->data[0][pixel_ptr + 0] = 255 - lobyte;
524  frame->data[0][pixel_ptr + 1] = 255 - lobyte;
525  frame->data[0][pixel_ptr + 2] = 255 - lobyte;
526  frame->data[0][pixel_ptr + 3] = 255 - lobyte;
527  pixel_ptr += frame->linesize[0];
528  }
529  lines=0;
530  }
531  break;
532 
533  case 2:
534  lobyte = s->decode_buffer[lobytes];
535  hibyte = s->decode_buffer[hibytes];
536  vector_index = (hibyte << 8) | lobyte;
537  vector_index <<= index_shift;
538  lines = s->vector_height;
539  break;
540 
541  case 3:
542  av_log(s->avctx, AV_LOG_ERROR, "VQA3 shouldn't have a color palette");
543  return AVERROR_INVALIDDATA;
544  }
545 
546  while (lines--) {
547  frame->data[0][pixel_ptr + 0] = s->codebook[vector_index++];
548  frame->data[0][pixel_ptr + 1] = s->codebook[vector_index++];
549  frame->data[0][pixel_ptr + 2] = s->codebook[vector_index++];
550  frame->data[0][pixel_ptr + 3] = s->codebook[vector_index++];
551  pixel_ptr += frame->linesize[0];
552  }
553  }
554  }
555 
556  /* handle partial codebook */
557  if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) {
558  /* a chunk should not have both chunk types */
559  av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBP0 and CBPZ chunks\n");
560  return AVERROR_INVALIDDATA;
561  }
562 
563  if (cbp0_chunk != -1) {
564 
565  bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET);
566  chunk_size = bytestream2_get_be32(&s->gb);
567 
568  if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) {
569  av_log(s->avctx, AV_LOG_ERROR, "cbp0 chunk too large (%u bytes)\n",
570  chunk_size);
571  return AVERROR_INVALIDDATA;
572  }
573 
574  /* accumulate partial codebook */
575  bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index],
576  chunk_size);
577  s->next_codebook_buffer_index += chunk_size;
578 
579  s->partial_countdown--;
580  if (s->partial_countdown <= 0) {
581 
582  /* time to replace codebook */
583  memcpy(s->codebook, s->next_codebook_buffer,
584  s->next_codebook_buffer_index);
585 
586  /* reset accounting */
587  s->next_codebook_buffer_index = 0;
588  s->partial_countdown = s->partial_count;
589  }
590  }
591 
592  if (cbpz_chunk != -1) {
593 
594  bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET);
595  chunk_size = bytestream2_get_be32(&s->gb);
596 
597  if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) {
598  av_log(s->avctx, AV_LOG_ERROR, "cbpz chunk too large (%u bytes)\n",
599  chunk_size);
600  return AVERROR_INVALIDDATA;
601  }
602 
603  /* accumulate partial codebook */
604  bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index],
605  chunk_size);
606  s->next_codebook_buffer_index += chunk_size;
607 
608  s->partial_countdown--;
609  if (s->partial_countdown <= 0) {
610  bytestream2_init(&s->gb, s->next_codebook_buffer, s->next_codebook_buffer_index);
611  /* decompress codebook */
612  res = decode_format80(s, s->next_codebook_buffer_index,
613  s->codebook, s->codebook_size, 0);
614 
615  /* reset accounting */
616  s->next_codebook_buffer_index = 0;
617  s->partial_countdown = s->partial_count;
618  if (res < 0)
619  return res;
620  }
621  }
622 
623  return 0;
624 }
625 
627 {
628  unsigned int chunk_type;
629  unsigned int chunk_size;
630  unsigned int index = 0;
631  int res;
632 
633  int cbf0_chunk = -1;
634  int cbfz_chunk = -1;
635  int vptr_chunk = -1;
636  int vprz_chunk = -1;
637 
638  GetByteContext gb_stream;
639 
640  while (bytestream2_get_bytes_left(&s->gb) >= 8) {
641  chunk_type = bytestream2_get_be32u(&s->gb);
642  index = bytestream2_tell(&s->gb);
643  chunk_size = bytestream2_get_be32u(&s->gb);
644 
645  switch (chunk_type) {
646  case CBF0_TAG:
647  cbf0_chunk = index;
648  break;
649  case CBFZ_TAG:
650  cbfz_chunk = index;
651  break;
652  case VPTR_TAG:
653  vptr_chunk = index;
654  break;
655  case VPRZ_TAG:
656  vprz_chunk = index;
657  break;
658  default:
659  av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %s (%08X)\n",
660  av_fourcc2str(av_bswap32(chunk_type)), chunk_type);
661  break;
662  }
663 
664  bytestream2_skip(&s->gb, chunk_size + (chunk_size & 0x01));
665  }
666 
667  /* next, look for a full codebook */
668  if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) {
669  /* a chunk should not have both chunk types */
670  av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n");
671  return AVERROR_INVALIDDATA;
672  }
673 
674  /* decompress the full codebook chunk */
675  if (cbfz_chunk != -1) {
676  bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET);
677  chunk_size = bytestream2_get_be32(&s->gb);
678  if ((res = decode_format80(s, chunk_size, s->codebook,
679  s->codebook_size, 0)) < 0)
680  return res;
681  }
682 
683  /* copy a full codebook */
684  if (cbf0_chunk != -1) {
685  bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET);
686  chunk_size = bytestream2_get_be32(&s->gb);
687  /* sanity check the full codebook size */
688  if (chunk_size > MAX_CODEBOOK_SIZE) {
689  av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n",
690  chunk_size);
691  return AVERROR_INVALIDDATA;
692  }
693 
694  bytestream2_get_buffer(&s->gb, s->codebook, chunk_size);
695  }
696 
697  /* decode the frame */
698 
699  if (vptr_chunk != -1) {
700  /* copy uncompressed tile data */
701  bytestream2_seek(&s->gb, vptr_chunk, SEEK_SET);
702  chunk_size = bytestream2_get_be32(&s->gb);
703  if (chunk_size > s->decode_buffer_size) {
704  av_log(s->avctx, AV_LOG_ERROR, "VPTR chunk didn't fit in decode buffer");
705  return AVERROR_INVALIDDATA;
706  }
707  bytestream2_get_buffer(&s->gb, s->decode_buffer, chunk_size);
708  } else if (vprz_chunk != -1) {
709  /* decompress the tile data */
710  bytestream2_seek(&s->gb, vprz_chunk, SEEK_SET);
711 
712  chunk_size = bytestream2_get_be32(&s->gb);
713  if ((res = decode_format80(s, chunk_size, s->decode_buffer, s->decode_buffer_size, 0)) < 0)
714  return res;
715  } else {
716  av_log(s->avctx, AV_LOG_ERROR, "frame has no block data\n");
717  return AVERROR_INVALIDDATA;
718  }
719 
720  /* now uncompress the per-row RLE of the decode buffer and draw the blocks in framebuffer */
721 
722  bytestream2_init(&gb_stream, s->decode_buffer, s->decode_buffer_size);
723 
724  for (int y_pos = 0; y_pos < s->height; y_pos += s->vector_height) {
725  int x_pos = 0;
726 
727  while (x_pos < s->width) {
728  int vector_index = 0;
729  int count = 0;
730  uint16_t code;
731  int type;
732 
733  if (bytestream2_get_bytes_left(&gb_stream) < 2)
734  return AVERROR_INVALIDDATA;
735 
736  code = bytestream2_get_le16(&gb_stream);
737 
738  type = code >> 13;
739  code &= 0x1fff;
740 
741  if (type == 0) {
742  x_pos += 4 * code;
743  continue;
744  } else if (type < 3) {
745  vector_index = code & 0xff;
746  count = ((code & 0x1f00) >> 7) + 1 + type;
747  } else if (type < 5) {
748  vector_index = code;
749  count = 1;
750  } else if (type < 7) {
751  vector_index = code;
752  count = bytestream2_get_byte(&gb_stream);
753  } else {
754  av_log(s->avctx, AV_LOG_ERROR, " unknown type in VPTR chunk (%d)\n",type);
755  return AVERROR_INVALIDDATA;
756  }
757 
758  if (count < 0 || count > (s->width - x_pos) / s->vector_width) {
759  av_log(s->avctx, AV_LOG_ERROR, "invalid count: %d\n", count);
760  return AVERROR_INVALIDDATA;
761  }
762 
763  while (count-- && x_pos < s->width) {
764  const int bytes_per_vector = 4 * s->vector_height * sizeof(uint16_t);
765  unsigned char *src = s->codebook + vector_index * bytes_per_vector;
766  unsigned char *dst = s->frame->data[0] + y_pos * s->frame->linesize[0]
767  + sizeof(uint16_t) * x_pos;
768 
769  if (vector_index >= MAX_VECTORS)
770  return AVERROR_INVALIDDATA;
771 
772  for (int y = 0; y < s->vector_height; y++) {
773  int size = 4 * sizeof(uint16_t);
774  memcpy(dst, src, size);
775  dst += s->frame->linesize[0];
776  src += size;
777  }
778 
779  /* we might want to read the next block index from stream */
780  if ((type == 2) && count > 0) {
781  vector_index = bytestream2_get_byte(&gb_stream);
782  }
783 
784  x_pos += 4;
785  }
786 
787  if (count > 0) {
788  av_log(s->avctx, AV_LOG_ERROR, "had %d leftover vectors\n", count);
789  return AVERROR_BUG;
790  }
791  }
792  }
793 
794  return 0;
795 }
796 
797 static int vqa_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
798  int *got_frame, AVPacket *avpkt)
799 {
800  VqaContext *s = avctx->priv_data;
801  int res;
802 
803  if ((res = ff_reget_buffer(avctx, s->frame, 0)) < 0)
804  return res;
805 
806  bytestream2_init(&s->gb, avpkt->data, avpkt->size);
807 
808  if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
809  if ((res = vqa_decode_frame_pal8(s, s->frame)) < 0)
810  return res;
811 
812  /* make the palette available on the way out */
813  memcpy(s->frame->data[1], s->palette, PALETTE_COUNT * 4);
814  s->frame->palette_has_changed = 1;
815  } else if (avctx->pix_fmt == AV_PIX_FMT_RGB555LE) {
816  if ((res = vqa_decode_frame_hicolor(s, s->frame)) < 0)
817  return res;
818  } else {
819  av_log(s->avctx, AV_LOG_ERROR, "unsupported pixel format\n");
820  return AVERROR_BUG;
821  }
822 
823  if ((res = av_frame_ref(rframe, s->frame)) < 0)
824  return res;
825 
826  *got_frame = 1;
827 
828  /* report that the buffer was completely consumed */
829  return avpkt->size;
830 }
831 
833 {
834  VqaContext *s = avctx->priv_data;
835 
836  av_frame_free(&s->frame);
837  av_freep(&s->codebook);
838  av_freep(&s->next_codebook_buffer);
839  av_freep(&s->decode_buffer);
840 
841  return 0;
842 }
843 
844 static const FFCodecDefault vqa_defaults[] = {
845  { "max_pixels", "640*480" },
846  { NULL },
847 };
848 
850  .p.name = "vqavideo",
851  .p.long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"),
852  .p.type = AVMEDIA_TYPE_VIDEO,
853  .p.id = AV_CODEC_ID_WS_VQA,
854  .priv_data_size = sizeof(VqaContext),
856  .close = vqa_decode_end,
858  .p.capabilities = AV_CODEC_CAP_DR1,
859  .defaults = vqa_defaults,
860  .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
861 };
check_size
static int check_size(TiffEncoderContext *s, uint64_t need)
Check free space in buffer.
Definition: tiffenc.c:89
VqaContext::decode_buffer_size
int decode_buffer_size
Definition: vqavideo.c:122
FF_CODEC_CAP_INIT_CLEANUP
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
Definition: codec_internal.h:41
r
const char * r
Definition: vf_curves.c:116
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
color
Definition: vf_paletteuse.c:600
GetByteContext
Definition: bytestream.h:33
VqaContext::next_codebook_buffer
unsigned char * next_codebook_buffer
Definition: vqavideo.c:118
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:116
bytestream2_seek
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:212
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:374
VqaContext::codebook_size
int codebook_size
Definition: vqavideo.c:117
b
#define b
Definition: input.c:34
FFCodec
Definition: codec_internal.h:118
CHECK_COUNT
#define CHECK_COUNT()
Definition: vqavideo.c:218
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
init
static int init
Definition: av_tx.c:47
PALETTE_COUNT
#define PALETTE_COUNT
Definition: vqavideo.c:83
VqaContext
Definition: vqavideo.c:103
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
FFCodecDefault
Definition: codec_internal.h:88
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:122
VqaContext::width
int width
Definition: vqavideo.c:110
VqaContext::partial_count
int partial_count
Definition: vqavideo.c:126
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:104
av_bswap32
#define av_bswap32
Definition: bswap.h:33
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
VqaContext::vector_width
int vector_width
Definition: vqavideo.c:112
width
#define width
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:260
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:256
vqa_decode_init
static av_cold int vqa_decode_init(AVCodecContext *avctx)
Definition: vqavideo.c:129
VqaContext::decode_buffer
unsigned char * decode_buffer
Definition: vqavideo.c:121
g
const char * g
Definition: vf_curves.c:117
VPRZ_TAG
#define VPRZ_TAG
Definition: vqavideo.c:101
AV_CODEC_ID_WS_VQA
@ AV_CODEC_ID_WS_VQA
Definition: codec_id.h:94
CBFZ_TAG
#define CBFZ_TAG
Definition: vqavideo.c:94
AV_RL16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_RL16
Definition: bytestream.h:94
if
if(ret)
Definition: filter_design.txt:179
NULL
#define NULL
Definition: coverity.c:32
CBP0_TAG
#define CBP0_TAG
Definition: vqavideo.c:95
VqaContext::avctx
AVCodecContext * avctx
Definition: vqavideo.c:105
MAX_CODEBOOK_SIZE
#define MAX_CODEBOOK_SIZE
Definition: vqavideo.c:91
bytestream2_get_buffer
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:267
VqaContext::palette
uint32_t palette[PALETTE_COUNT]
Definition: vqavideo.c:108
vqa_defaults
static const FFCodecDefault vqa_defaults[]
Definition: vqavideo.c:844
MAX_VECTORS
#define MAX_VECTORS
Definition: vqavideo.c:90
decode_format80
static int decode_format80(VqaContext *s, int src_size, unsigned char *dest, int dest_size, int check_size)
Definition: vqavideo.c:235
index
int index
Definition: gxfenc.c:89
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:158
bytestream2_tell
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:192
vqa_decode_frame_pal8
static int vqa_decode_frame_pal8(VqaContext *s, AVFrame *frame)
Definition: vqavideo.c:343
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
vqa_decode_frame
static int vqa_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, AVPacket *avpkt)
Definition: vqavideo.c:797
AVPacket::size
int size
Definition: packet.h:375
CPL0_TAG
#define CPL0_TAG
Definition: vqavideo.c:97
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
av_frame_ref
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
Definition: frame.c:353
codec_internal.h
VqaContext::height
int height
Definition: vqavideo.c:111
ff_vqa_decoder
const FFCodec ff_vqa_decoder
Definition: vqavideo.c:849
size
int size
Definition: twinvq_data.h:10344
color
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:94
VqaContext::frame
AVFrame * frame
Definition: vqavideo.c:104
CPLZ_TAG
#define CPLZ_TAG
Definition: vqavideo.c:98
VqaContext::next_codebook_buffer_index
int next_codebook_buffer_index
Definition: vqavideo.c:119
vqa_decode_end
static av_cold int vqa_decode_end(AVCodecContext *avctx)
Definition: vqavideo.c:832
vqa_decode_frame_hicolor
static int vqa_decode_frame_hicolor(VqaContext *s, AVFrame *frame)
Definition: vqavideo.c:626
CHECK_COPY
#define CHECK_COPY(idx)
Definition: vqavideo.c:226
VqaContext::partial_countdown
int partial_countdown
Definition: vqavideo.c:125
VqaContext::vqa_version
int vqa_version
Definition: vqavideo.c:114
VPTZ_TAG
#define VPTZ_TAG
Definition: vqavideo.c:99
AV_PIX_FMT_RGB555LE
@ AV_PIX_FMT_RGB555LE
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined
Definition: pixfmt.h:108
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
code
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some it can consider them to be part of the FIFO and delay acknowledging a status change accordingly Example code
Definition: filter_design.txt:178
VPTR_TAG
#define VPTR_TAG
Definition: vqavideo.c:100
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:264
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:211
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:608
VqaContext::vector_height
int vector_height
Definition: vqavideo.c:113
avcodec.h
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
ff_reget_buffer
int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Identical in function to ff_get_buffer(), except it reuses the existing buffer if available.
Definition: decode.c:1580
ret
ret
Definition: filter_design.txt:187
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
U
#define U(x)
Definition: vpx_arith.h:37
AVCodecContext
main external API structure.
Definition: avcodec.h:398
CBF0_TAG
#define CBF0_TAG
Definition: vqavideo.c:93
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
ff_set_dimensions
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
Definition: utils.c:90
avpriv_request_sample
#define avpriv_request_sample(...)
Definition: tableprint_vlc.h:36
ff_tlog
#define ff_tlog(ctx,...)
Definition: internal.h:207
AVPacket
This structure stores compressed data.
Definition: packet.h:351
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:425
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
bytestream.h
imgutils.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
VqaContext::codebook
unsigned char * codebook
Definition: vqavideo.c:116
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
VQA_HEADER_SIZE
#define VQA_HEADER_SIZE
Definition: vqavideo.c:84
VqaContext::gb
GetByteContext gb
Definition: vqavideo.c:106
CBPZ_TAG
#define CBPZ_TAG
Definition: vqavideo.c:96
av_fourcc2str
#define av_fourcc2str(fourcc)
Definition: avutil.h:354