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 <string.h>
74 
75 #include "libavutil/intreadwrite.h"
76 #include "libavutil/mem.h"
77 #include "avcodec.h"
78 #include "bytestream.h"
79 #include "codec_internal.h"
80 #include "decode.h"
81 
82 #define PALETTE_COUNT 256
83 #define VQA_HEADER_SIZE 0x2A
84 
85 /* allocate the maximum vector space, regardless of the file version:
86  * (0xFF00 codebook vectors + 0x100 solid pixel vectors) * (4x4 pixels/block) */
87 #define MAX_CODEBOOK_VECTORS 0xFF00
88 #define SOLID_PIXEL_VECTORS 0x100
89 #define MAX_VECTORS (MAX_CODEBOOK_VECTORS + SOLID_PIXEL_VECTORS)
90 #define MAX_CODEBOOK_SIZE (MAX_VECTORS * 4 * 4 * sizeof(uint16_t))
91 
92 #define CBF0_TAG MKBETAG('C', 'B', 'F', '0')
93 #define CBFZ_TAG MKBETAG('C', 'B', 'F', 'Z')
94 #define CBP0_TAG MKBETAG('C', 'B', 'P', '0')
95 #define CBPZ_TAG MKBETAG('C', 'B', 'P', 'Z')
96 #define CPL0_TAG MKBETAG('C', 'P', 'L', '0')
97 #define CPLZ_TAG MKBETAG('C', 'P', 'L', 'Z')
98 #define VPTZ_TAG MKBETAG('V', 'P', 'T', 'Z')
99 #define VPTR_TAG MKBETAG('V', 'P', 'T', 'R')
100 #define VPRZ_TAG MKBETAG('V', 'P', 'R', 'Z')
101 
102 typedef struct VqaContext {
106 
108 
109  int width; /* width of a frame */
110  int height; /* height of a frame */
111  int vector_width; /* width of individual vector */
112  int vector_height; /* height of individual vector */
113  int vqa_version; /* this should be either 1, 2 or 3 */
114 
115  unsigned char *codebook; /* the current codebook */
117  unsigned char *next_codebook_buffer; /* accumulator for next codebook */
119 
120  unsigned char *decode_buffer;
122 
123  /* number of frames to go before replacing codebook */
126 } VqaContext;
127 
129 {
130  VqaContext *s = avctx->priv_data;
131  int i, j, codebook_index, ret;
132  int colors;
133 
134  s->avctx = avctx;
135 
136  /* make sure the extradata made it */
137  if (s->avctx->extradata_size != VQA_HEADER_SIZE) {
138  av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n", VQA_HEADER_SIZE);
139  return AVERROR(EINVAL);
140  }
141 
142  /* load up the VQA parameters from the header */
143  s->vqa_version = s->avctx->extradata[0];
144 
145  if (s->vqa_version < 1 || s->vqa_version > 3) {
146  avpriv_request_sample(avctx, "VQA Version %i", s->vqa_version);
147  return AVERROR_INVALIDDATA;
148  }
149 
150  s->width = AV_RL16(&s->avctx->extradata[6]);
151  s->height = AV_RL16(&s->avctx->extradata[8]);
152  if ((ret = ff_set_dimensions(avctx, s->width, s->height)) < 0) {
153  s->width= s->height= 0;
154  return ret;
155  }
156  s->vector_width = s->avctx->extradata[10];
157  s->vector_height = s->avctx->extradata[11];
158  s->partial_count = s->partial_countdown = s->avctx->extradata[13];
159 
160  colors = (s->avctx->extradata[14] << 8) | s->avctx->extradata[15];
161 
162  if (colors > 0) {
163  avctx->pix_fmt = AV_PIX_FMT_PAL8;
164  } else {
165  avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
166  }
167 
168  /* the vector dimensions have to meet very stringent requirements */
169  if ((s->vector_width != 4) ||
170  ((s->vector_height != 2) && (s->vector_height != 4))) {
171  /* return without further initialization */
172  return AVERROR_INVALIDDATA;
173  }
174 
175  if (s->width % s->vector_width || s->height % s->vector_height) {
176  av_log(avctx, AV_LOG_ERROR, "Image size not multiple of block size\n");
177  return AVERROR_INVALIDDATA;
178  }
179 
180  s->frame = av_frame_alloc();
181  if (!s->frame)
182  return AVERROR(ENOMEM);
183 
184  /* allocate codebooks */
185  s->codebook_size = MAX_CODEBOOK_SIZE;
186  s->codebook = av_malloc(s->codebook_size);
187  if (!s->codebook)
188  return AVERROR(ENOMEM);
189  s->next_codebook_buffer = av_malloc(s->codebook_size);
190  if (!s->next_codebook_buffer)
191  return AVERROR(ENOMEM);
192 
193  /* allocate decode buffer */
194  s->decode_buffer_size = (s->width / s->vector_width) *
195  (s->height / s->vector_height) * 2;
196  s->decode_buffer = av_mallocz(s->decode_buffer_size);
197  if (!s->decode_buffer)
198  return AVERROR(ENOMEM);
199 
200  /* initialize the solid-color vectors */
201  if (s->vector_height == 4) {
202  codebook_index = 0xFF00 * 16;
203  for (i = 0; i < 256; i++)
204  for (j = 0; j < 16; j++)
205  s->codebook[codebook_index++] = i;
206  } else {
207  codebook_index = 0xF00 * 8;
208  for (i = 0; i < 256; i++)
209  for (j = 0; j < 8; j++)
210  s->codebook[codebook_index++] = i;
211  }
212  s->next_codebook_buffer_index = 0;
213 
214  return 0;
215 }
216 
217 #define CHECK_COUNT() \
218  if (dest_index + count > dest_size) { \
219  av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \
220  av_log(s->avctx, AV_LOG_ERROR, "current dest_index = %d, count = %d, dest_size = %d\n", \
221  dest_index, count, dest_size); \
222  return AVERROR_INVALIDDATA; \
223  }
224 
225 #define CHECK_COPY(idx) \
226  if (idx < 0 || idx + count > dest_size) { \
227  av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \
228  av_log(s->avctx, AV_LOG_ERROR, "current src_pos = %d, count = %d, dest_size = %d\n", \
229  src_pos, count, dest_size); \
230  return AVERROR_INVALIDDATA; \
231  }
232 
233 
234 static int decode_format80(VqaContext *s, int src_size,
235  unsigned char *dest, int dest_size, int check_size) {
236 
237  int dest_index = 0;
238  int count, opcode, start;
239  int src_pos;
240  unsigned char color;
241  int i;
242  int relative = 0;
243 
244  if (src_size < 0 || src_size > bytestream2_get_bytes_left(&s->gb)) {
245  av_log(s->avctx, AV_LOG_ERROR, "Chunk size %d is out of range\n",
246  src_size);
247  return AVERROR_INVALIDDATA;
248  }
249 
250  /* the "new" scheme makes references relative to destination pointer */
251  if (bytestream2_peek_byte(&s->gb) == 0x00) {
252  relative = 1;
253  bytestream2_get_byte(&s->gb);
254  ff_tlog(s->avctx, "found new format stream ");
255  }
256 
257  start = bytestream2_tell(&s->gb);
258  while (bytestream2_tell(&s->gb) - start < src_size) {
259  opcode = bytestream2_get_byte(&s->gb);
260  ff_tlog(s->avctx, "opcode %02X: ", opcode);
261 
262  /* 0x80 means that frame is finished */
263  if (opcode == 0x80)
264  break;
265 
266  if (dest_index >= dest_size) {
267  av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n",
268  dest_index, dest_size);
269  return AVERROR_INVALIDDATA;
270  }
271 
272  if (opcode == 0xFF) {
273 
274  count = bytestream2_get_le16(&s->gb);
275  src_pos = bytestream2_get_le16(&s->gb);
276  if (relative)
277  src_pos = dest_index - src_pos;
278  ff_tlog(s->avctx, "(1) copy %X bytes from pos %X\n", count, src_pos);
279  CHECK_COUNT();
280  CHECK_COPY(src_pos);
281  for (i = 0; i < count; i++)
282  dest[dest_index + i] = dest[src_pos + i];
283  dest_index += count;
284 
285  } else if (opcode == 0xFE) {
286 
287  count = bytestream2_get_le16(&s->gb);
288  color = bytestream2_get_byte(&s->gb);
289  ff_tlog(s->avctx, "(2) set %X bytes to %02X\n", count, color);
290  CHECK_COUNT();
291  memset(&dest[dest_index], color, count);
292  dest_index += count;
293 
294  } else if ((opcode & 0xC0) == 0xC0) {
295 
296  count = (opcode & 0x3F) + 3;
297  src_pos = bytestream2_get_le16(&s->gb);
298  if (relative)
299  src_pos = dest_index - src_pos;
300  ff_tlog(s->avctx, "(3) copy %X bytes from pos %X\n", count, src_pos);
301  CHECK_COUNT();
302  CHECK_COPY(src_pos);
303  for (i = 0; i < count; i++)
304  dest[dest_index + i] = dest[src_pos + i];
305  dest_index += count;
306 
307  } else if (opcode > 0x80) {
308 
309  count = opcode & 0x3F;
310  ff_tlog(s->avctx, "(4) copy %X bytes from source to dest\n", count);
311  CHECK_COUNT();
312  bytestream2_get_buffer(&s->gb, &dest[dest_index], count);
313  dest_index += count;
314 
315  } else {
316 
317  count = ((opcode & 0x70) >> 4) + 3;
318  src_pos = bytestream2_get_byte(&s->gb) | ((opcode & 0x0F) << 8);
319  ff_tlog(s->avctx, "(5) copy %X bytes from relpos %X\n", count, src_pos);
320  CHECK_COUNT();
321  CHECK_COPY(dest_index - src_pos);
322  for (i = 0; i < count; i++)
323  dest[dest_index + i] = dest[dest_index - src_pos + i];
324  dest_index += count;
325  }
326  }
327 
328  /* validate that the entire destination buffer was filled; this is
329  * important for decoding frame maps since each vector needs to have a
330  * codebook entry; it is not important for compressed codebooks because
331  * not every entry needs to be filled */
332  if (check_size)
333  if (dest_index < dest_size) {
334  av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",
335  dest_index, dest_size);
336  memset(dest + dest_index, 0, dest_size - dest_index);
337  }
338 
339  return 0; // let's display what we decoded anyway
340 }
341 
343 {
344  unsigned int chunk_type;
345  unsigned int chunk_size;
346  int byte_skip;
347  unsigned int index = 0;
348  int i;
349  unsigned char r, g, b;
350  int index_shift;
351  int res;
352 
353  int cbf0_chunk = -1;
354  int cbfz_chunk = -1;
355  int cbp0_chunk = -1;
356  int cbpz_chunk = -1;
357  int cpl0_chunk = -1;
358  int cplz_chunk = -1;
359  int vptz_chunk = -1;
360 
361  int x, y;
362  int lines = 0;
363  int pixel_ptr;
364  int vector_index = 0;
365  int lobyte = 0;
366  int hibyte = 0;
367  int lobytes = 0;
368  int hibytes = s->decode_buffer_size / 2;
369 
370  /* first, traverse through the frame and find the subchunks */
371  while (bytestream2_get_bytes_left(&s->gb) >= 8) {
372 
373  chunk_type = bytestream2_get_be32u(&s->gb);
374  index = bytestream2_tell(&s->gb);
375  chunk_size = bytestream2_get_be32u(&s->gb);
376 
377  switch (chunk_type) {
378 
379  case CBF0_TAG:
380  cbf0_chunk = index;
381  break;
382 
383  case CBFZ_TAG:
384  cbfz_chunk = index;
385  break;
386 
387  case CBP0_TAG:
388  cbp0_chunk = index;
389  break;
390 
391  case CBPZ_TAG:
392  cbpz_chunk = index;
393  break;
394 
395  case CPL0_TAG:
396  cpl0_chunk = index;
397  break;
398 
399  case CPLZ_TAG:
400  cplz_chunk = index;
401  break;
402 
403  case VPTZ_TAG:
404  vptz_chunk = index;
405  break;
406 
407  default:
408  av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %s (%08X)\n",
409  av_fourcc2str(av_bswap32(chunk_type)), chunk_type);
410  break;
411  }
412 
413  byte_skip = chunk_size & 0x01;
414  bytestream2_skip(&s->gb, chunk_size + byte_skip);
415  }
416 
417  /* next, deal with the palette */
418  if ((cpl0_chunk != -1) && (cplz_chunk != -1)) {
419 
420  /* a chunk should not have both chunk types */
421  av_log(s->avctx, AV_LOG_ERROR, "problem: found both CPL0 and CPLZ chunks\n");
422  return AVERROR_INVALIDDATA;
423  }
424 
425  /* decompress the palette chunk */
426  if (cplz_chunk != -1) {
427 
428 /* yet to be handled */
429 
430  }
431 
432  /* convert the RGB palette into the machine's endian format */
433  if (cpl0_chunk != -1) {
434 
435  bytestream2_seek(&s->gb, cpl0_chunk, SEEK_SET);
436  chunk_size = bytestream2_get_be32(&s->gb);
437  /* sanity check the palette size */
438  if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) {
439  av_log(s->avctx, AV_LOG_ERROR, "problem: found a palette chunk with %d colors\n",
440  chunk_size / 3);
441  return AVERROR_INVALIDDATA;
442  }
443  for (i = 0; i < chunk_size / 3; i++) {
444  /* scale by 4 to transform 6-bit palette -> 8-bit */
445  r = bytestream2_get_byteu(&s->gb) * 4;
446  g = bytestream2_get_byteu(&s->gb) * 4;
447  b = bytestream2_get_byteu(&s->gb) * 4;
448  s->palette[i] = 0xFFU << 24 | r << 16 | g << 8 | b;
449  s->palette[i] |= s->palette[i] >> 6 & 0x30303;
450  }
451  }
452 
453  /* next, look for a full codebook */
454  if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) {
455 
456  /* a chunk should not have both chunk types */
457  av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n");
458  return AVERROR_INVALIDDATA;
459  }
460 
461  /* decompress the full codebook chunk */
462  if (cbfz_chunk != -1) {
463 
464  bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET);
465  chunk_size = bytestream2_get_be32(&s->gb);
466  if ((res = decode_format80(s, chunk_size, s->codebook,
467  s->codebook_size, 0)) < 0)
468  return res;
469  }
470 
471  /* copy a full codebook */
472  if (cbf0_chunk != -1) {
473 
474  bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET);
475  chunk_size = bytestream2_get_be32(&s->gb);
476  /* sanity check the full codebook size */
477  if (chunk_size > MAX_CODEBOOK_SIZE) {
478  av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n",
479  chunk_size);
480  return AVERROR_INVALIDDATA;
481  }
482 
483  bytestream2_get_buffer(&s->gb, s->codebook, chunk_size);
484  }
485 
486  /* decode the frame */
487  if (vptz_chunk == -1) {
488 
489  /* something is wrong if there is no VPTZ chunk */
490  av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ chunk found\n");
491  return AVERROR_INVALIDDATA;
492  }
493 
494  bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET);
495  chunk_size = bytestream2_get_be32(&s->gb);
496  if ((res = decode_format80(s, chunk_size,
497  s->decode_buffer, s->decode_buffer_size, 1)) < 0)
498  return res;
499 
500  /* render the final PAL8 frame */
501  if (s->vector_height == 4)
502  index_shift = 4;
503  else
504  index_shift = 3;
505  for (y = 0; y < s->height; y += s->vector_height) {
506  for (x = 0; x < s->width; x += 4, lobytes++, hibytes++) {
507  pixel_ptr = y * frame->linesize[0] + x;
508 
509  /* get the vector index, the method for which varies according to
510  * VQA file version */
511  switch (s->vqa_version) {
512 
513  case 1:
514  lobyte = s->decode_buffer[lobytes * 2];
515  hibyte = s->decode_buffer[(lobytes * 2) + 1];
516  vector_index = ((hibyte << 8) | lobyte) >> 3;
517  vector_index <<= index_shift;
518  lines = s->vector_height;
519  /* uniform color fill - a quick hack */
520  if (hibyte == 0xFF) {
521  while (lines--) {
522  frame->data[0][pixel_ptr + 0] = 255 - lobyte;
523  frame->data[0][pixel_ptr + 1] = 255 - lobyte;
524  frame->data[0][pixel_ptr + 2] = 255 - lobyte;
525  frame->data[0][pixel_ptr + 3] = 255 - lobyte;
526  pixel_ptr += frame->linesize[0];
527  }
528  lines=0;
529  }
530  break;
531 
532  case 2:
533  lobyte = s->decode_buffer[lobytes];
534  hibyte = s->decode_buffer[hibytes];
535  vector_index = (hibyte << 8) | lobyte;
536  vector_index <<= index_shift;
537  lines = s->vector_height;
538  break;
539 
540  case 3:
541  av_log(s->avctx, AV_LOG_ERROR, "VQA3 shouldn't have a color palette");
542  return AVERROR_INVALIDDATA;
543  }
544 
545  while (lines--) {
546  frame->data[0][pixel_ptr + 0] = s->codebook[vector_index++];
547  frame->data[0][pixel_ptr + 1] = s->codebook[vector_index++];
548  frame->data[0][pixel_ptr + 2] = s->codebook[vector_index++];
549  frame->data[0][pixel_ptr + 3] = s->codebook[vector_index++];
550  pixel_ptr += frame->linesize[0];
551  }
552  }
553  }
554 
555  /* handle partial codebook */
556  if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) {
557  /* a chunk should not have both chunk types */
558  av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBP0 and CBPZ chunks\n");
559  return AVERROR_INVALIDDATA;
560  }
561 
562  if (cbp0_chunk != -1) {
563 
564  bytestream2_seek(&s->gb, cbp0_chunk, SEEK_SET);
565  chunk_size = bytestream2_get_be32(&s->gb);
566 
567  if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) {
568  av_log(s->avctx, AV_LOG_ERROR, "cbp0 chunk too large (%u bytes)\n",
569  chunk_size);
570  return AVERROR_INVALIDDATA;
571  }
572 
573  /* accumulate partial codebook */
574  bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index],
575  chunk_size);
576  s->next_codebook_buffer_index += chunk_size;
577 
578  s->partial_countdown--;
579  if (s->partial_countdown <= 0) {
580 
581  /* time to replace codebook */
582  memcpy(s->codebook, s->next_codebook_buffer,
583  s->next_codebook_buffer_index);
584 
585  /* reset accounting */
586  s->next_codebook_buffer_index = 0;
587  s->partial_countdown = s->partial_count;
588  }
589  }
590 
591  if (cbpz_chunk != -1) {
592 
593  bytestream2_seek(&s->gb, cbpz_chunk, SEEK_SET);
594  chunk_size = bytestream2_get_be32(&s->gb);
595 
596  if (chunk_size > MAX_CODEBOOK_SIZE - s->next_codebook_buffer_index) {
597  av_log(s->avctx, AV_LOG_ERROR, "cbpz chunk too large (%u bytes)\n",
598  chunk_size);
599  return AVERROR_INVALIDDATA;
600  }
601 
602  /* accumulate partial codebook */
603  bytestream2_get_buffer(&s->gb, &s->next_codebook_buffer[s->next_codebook_buffer_index],
604  chunk_size);
605  s->next_codebook_buffer_index += chunk_size;
606 
607  s->partial_countdown--;
608  if (s->partial_countdown <= 0) {
609  bytestream2_init(&s->gb, s->next_codebook_buffer, s->next_codebook_buffer_index);
610  /* decompress codebook */
611  res = decode_format80(s, s->next_codebook_buffer_index,
612  s->codebook, s->codebook_size, 0);
613 
614  /* reset accounting */
615  s->next_codebook_buffer_index = 0;
616  s->partial_countdown = s->partial_count;
617  if (res < 0)
618  return res;
619  }
620  }
621 
622  return 0;
623 }
624 
626 {
627  unsigned int chunk_type;
628  unsigned int chunk_size;
629  unsigned int index = 0;
630  int res;
631 
632  int cbf0_chunk = -1;
633  int cbfz_chunk = -1;
634  int vptr_chunk = -1;
635  int vprz_chunk = -1;
636 
637  GetByteContext gb_stream;
638 
639  while (bytestream2_get_bytes_left(&s->gb) >= 8) {
640  chunk_type = bytestream2_get_be32u(&s->gb);
641  index = bytestream2_tell(&s->gb);
642  chunk_size = bytestream2_get_be32u(&s->gb);
643 
644  switch (chunk_type) {
645  case CBF0_TAG:
646  cbf0_chunk = index;
647  break;
648  case CBFZ_TAG:
649  cbfz_chunk = index;
650  break;
651  case VPTR_TAG:
652  vptr_chunk = index;
653  break;
654  case VPRZ_TAG:
655  vprz_chunk = index;
656  break;
657  default:
658  av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %s (%08X)\n",
659  av_fourcc2str(av_bswap32(chunk_type)), chunk_type);
660  break;
661  }
662 
663  bytestream2_skip(&s->gb, chunk_size + (chunk_size & 0x01));
664  }
665 
666  /* next, look for a full codebook */
667  if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) {
668  /* a chunk should not have both chunk types */
669  av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n");
670  return AVERROR_INVALIDDATA;
671  }
672 
673  /* decompress the full codebook chunk */
674  if (cbfz_chunk != -1) {
675  bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET);
676  chunk_size = bytestream2_get_be32(&s->gb);
677  if ((res = decode_format80(s, chunk_size, s->codebook,
678  s->codebook_size, 0)) < 0)
679  return res;
680  }
681 
682  /* copy a full codebook */
683  if (cbf0_chunk != -1) {
684  bytestream2_seek(&s->gb, cbf0_chunk, SEEK_SET);
685  chunk_size = bytestream2_get_be32(&s->gb);
686  /* sanity check the full codebook size */
687  if (chunk_size > MAX_CODEBOOK_SIZE) {
688  av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n",
689  chunk_size);
690  return AVERROR_INVALIDDATA;
691  }
692 
693  bytestream2_get_buffer(&s->gb, s->codebook, chunk_size);
694  }
695 
696  /* decode the frame */
697 
698  if (vptr_chunk != -1) {
699  /* copy uncompressed tile data */
700  bytestream2_seek(&s->gb, vptr_chunk, SEEK_SET);
701  chunk_size = bytestream2_get_be32(&s->gb);
702  if (chunk_size > s->decode_buffer_size) {
703  av_log(s->avctx, AV_LOG_ERROR, "VPTR chunk didn't fit in decode buffer");
704  return AVERROR_INVALIDDATA;
705  }
706  bytestream2_get_buffer(&s->gb, s->decode_buffer, chunk_size);
707  } else if (vprz_chunk != -1) {
708  /* decompress the tile data */
709  bytestream2_seek(&s->gb, vprz_chunk, SEEK_SET);
710 
711  chunk_size = bytestream2_get_be32(&s->gb);
712  if ((res = decode_format80(s, chunk_size, s->decode_buffer, s->decode_buffer_size, 0)) < 0)
713  return res;
714  } else {
715  av_log(s->avctx, AV_LOG_ERROR, "frame has no block data\n");
716  return AVERROR_INVALIDDATA;
717  }
718 
719  /* now uncompress the per-row RLE of the decode buffer and draw the blocks in framebuffer */
720 
721  bytestream2_init(&gb_stream, s->decode_buffer, s->decode_buffer_size);
722 
723  for (int y_pos = 0; y_pos < s->height; y_pos += s->vector_height) {
724  int x_pos = 0;
725 
726  while (x_pos < s->width) {
727  int vector_index = 0;
728  int count = 0;
729  uint16_t code;
730  int type;
731 
732  if (bytestream2_get_bytes_left(&gb_stream) < 2)
733  return AVERROR_INVALIDDATA;
734 
735  code = bytestream2_get_le16(&gb_stream);
736 
737  type = code >> 13;
738  code &= 0x1fff;
739 
740  if (type == 0) {
741  x_pos += 4 * code;
742  continue;
743  } else if (type < 3) {
744  vector_index = code & 0xff;
745  count = ((code & 0x1f00) >> 7) + 1 + type;
746  } else if (type < 5) {
747  vector_index = code;
748  count = 1;
749  } else if (type < 7) {
750  vector_index = code;
751  count = bytestream2_get_byte(&gb_stream);
752  } else {
753  av_log(s->avctx, AV_LOG_ERROR, " unknown type in VPTR chunk (%d)\n",type);
754  return AVERROR_INVALIDDATA;
755  }
756 
757  if (count < 0 || count > (s->width - x_pos) / s->vector_width) {
758  av_log(s->avctx, AV_LOG_ERROR, "invalid count: %d\n", count);
759  return AVERROR_INVALIDDATA;
760  }
761 
762  while (count-- && x_pos < s->width) {
763  const int bytes_per_vector = 4 * s->vector_height * sizeof(uint16_t);
764  unsigned char *src = s->codebook + vector_index * bytes_per_vector;
765  unsigned char *dst = s->frame->data[0] + y_pos * s->frame->linesize[0]
766  + sizeof(uint16_t) * x_pos;
767 
768  if (vector_index >= MAX_VECTORS)
769  return AVERROR_INVALIDDATA;
770 
771  for (int y = 0; y < s->vector_height; y++) {
772  int size = 4 * sizeof(uint16_t);
773  memcpy(dst, src, size);
774  dst += s->frame->linesize[0];
775  src += size;
776  }
777 
778  /* we might want to read the next block index from stream */
779  if ((type == 2) && count > 0) {
780  vector_index = bytestream2_get_byte(&gb_stream);
781  }
782 
783  x_pos += 4;
784  }
785 
786  if (count > 0) {
787  av_log(s->avctx, AV_LOG_ERROR, "had %d leftover vectors\n", count);
788  return AVERROR_BUG;
789  }
790  }
791  }
792 
793  return 0;
794 }
795 
796 static int vqa_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
797  int *got_frame, AVPacket *avpkt)
798 {
799  VqaContext *s = avctx->priv_data;
800  int res;
801 
802  if ((res = ff_reget_buffer(avctx, s->frame, 0)) < 0)
803  return res;
804 
805  bytestream2_init(&s->gb, avpkt->data, avpkt->size);
806 
807  if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
808  if ((res = vqa_decode_frame_pal8(s, s->frame)) < 0)
809  return res;
810 
811  /* make the palette available on the way out */
812  memcpy(s->frame->data[1], s->palette, PALETTE_COUNT * 4);
813 #if FF_API_PALETTE_HAS_CHANGED
815  s->frame->palette_has_changed = 1;
817 #endif
818  } else if (avctx->pix_fmt == AV_PIX_FMT_RGB555LE) {
819  if ((res = vqa_decode_frame_hicolor(s, s->frame)) < 0)
820  return res;
821  } else {
822  av_log(s->avctx, AV_LOG_ERROR, "unsupported pixel format\n");
823  return AVERROR_BUG;
824  }
825 
826  if ((res = av_frame_ref(rframe, s->frame)) < 0)
827  return res;
828 
829  *got_frame = 1;
830 
831  /* report that the buffer was completely consumed */
832  return avpkt->size;
833 }
834 
836 {
837  VqaContext *s = avctx->priv_data;
838 
839  av_frame_free(&s->frame);
840  av_freep(&s->codebook);
841  av_freep(&s->next_codebook_buffer);
842  av_freep(&s->decode_buffer);
843 
844  return 0;
845 }
846 
847 static const FFCodecDefault vqa_defaults[] = {
848  { "max_pixels", "640*480" },
849  { NULL },
850 };
851 
853  .p.name = "vqavideo",
854  CODEC_LONG_NAME("Westwood Studios VQA (Vector Quantized Animation) video"),
855  .p.type = AVMEDIA_TYPE_VIDEO,
856  .p.id = AV_CODEC_ID_WS_VQA,
857  .priv_data_size = sizeof(VqaContext),
859  .close = vqa_decode_end,
861  .p.capabilities = AV_CODEC_CAP_DR1,
862  .defaults = vqa_defaults,
863  .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
864 };
FF_ENABLE_DEPRECATION_WARNINGS
#define FF_ENABLE_DEPRECATION_WARNINGS
Definition: internal.h:73
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:121
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:42
r
const char * r
Definition: vf_curves.c:127
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:512
GetByteContext
Definition: bytestream.h:33
VqaContext::next_codebook_buffer
unsigned char * next_codebook_buffer
Definition: vqavideo.c:117
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:160
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:374
AVPacket::data
uint8_t * data
Definition: packet.h:524
VqaContext::codebook_size
int codebook_size
Definition: vqavideo.c:116
b
#define b
Definition: input.c:41
FFCodec
Definition: codec_internal.h:126
CHECK_COUNT
#define CHECK_COUNT()
Definition: vqavideo.c:217
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:94
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
PALETTE_COUNT
#define PALETTE_COUNT
Definition: vqavideo.c:82
VqaContext
Definition: vqavideo.c:102
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
FFCodecDefault
Definition: codec_internal.h:96
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:130
VqaContext::width
int width
Definition: vqavideo.c:109
VqaContext::partial_count
int partial_count
Definition: vqavideo.c:125
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:148
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:111
width
#define width
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:286
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
vqa_decode_init
static av_cold int vqa_decode_init(AVCodecContext *avctx)
Definition: vqavideo.c:128
VqaContext::decode_buffer
unsigned char * decode_buffer
Definition: vqavideo.c:120
g
const char * g
Definition: vf_curves.c:128
VPRZ_TAG
#define VPRZ_TAG
Definition: vqavideo.c:100
AV_CODEC_ID_WS_VQA
@ AV_CODEC_ID_WS_VQA
Definition: codec_id.h:96
CBFZ_TAG
#define CBFZ_TAG
Definition: vqavideo.c:93
decode.h
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
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:271
if
if(ret)
Definition: filter_design.txt:179
NULL
#define NULL
Definition: coverity.c:32
CBP0_TAG
#define CBP0_TAG
Definition: vqavideo.c:94
VqaContext::avctx
AVCodecContext * avctx
Definition: vqavideo.c:104
MAX_CODEBOOK_SIZE
#define MAX_CODEBOOK_SIZE
Definition: vqavideo.c:90
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:107
vqa_defaults
static const FFCodecDefault vqa_defaults[]
Definition: vqavideo.c:847
MAX_VECTORS
#define MAX_VECTORS
Definition: vqavideo.c:89
decode_format80
static int decode_format80(VqaContext *s, int src_size, unsigned char *dest, int dest_size, int check_size)
Definition: vqavideo.c:234
index
int index
Definition: gxfenc.c:90
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
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:366
vqa_decode_frame_pal8
static int vqa_decode_frame_pal8(VqaContext *s, AVFrame *frame)
Definition: vqavideo.c:342
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:796
AVPacket::size
int size
Definition: packet.h:525
CPL0_TAG
#define CPL0_TAG
Definition: vqavideo.c:96
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:384
codec_internal.h
VqaContext::height
int height
Definition: vqavideo.c:110
av_bswap32
#define av_bswap32
Definition: bswap.h:28
ff_vqa_decoder
const FFCodec ff_vqa_decoder
Definition: vqavideo.c:852
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:103
CPLZ_TAG
#define CPLZ_TAG
Definition: vqavideo.c:97
VqaContext::next_codebook_buffer_index
int next_codebook_buffer_index
Definition: vqavideo.c:118
vqa_decode_end
static av_cold int vqa_decode_end(AVCodecContext *avctx)
Definition: vqavideo.c:835
vqa_decode_frame_hicolor
static int vqa_decode_frame_hicolor(VqaContext *s, AVFrame *frame)
Definition: vqavideo.c:625
CHECK_COPY
#define CHECK_COPY(idx)
Definition: vqavideo.c:225
VqaContext::partial_countdown
int partial_countdown
Definition: vqavideo.c:124
VqaContext::vqa_version
int vqa_version
Definition: vqavideo.c:113
VPTZ_TAG
#define VPTZ_TAG
Definition: vqavideo.c:98
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:115
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
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:99
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:256
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:657
VqaContext::vector_height
int vector_height
Definition: vqavideo.c:112
avcodec.h
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:84
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:1665
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:445
CBF0_TAG
#define CBF0_TAG
Definition: vqavideo.c:92
FF_DISABLE_DEPRECATION_WARNINGS
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition: internal.h:72
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
mem.h
avpriv_request_sample
#define avpriv_request_sample(...)
Definition: tableprint_vlc.h:36
ff_tlog
#define ff_tlog(ctx,...)
Definition: internal.h:141
AVPacket
This structure stores compressed data.
Definition: packet.h:501
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:472
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
bytestream.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:115
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:83
VqaContext::gb
GetByteContext gb
Definition: vqavideo.c:105
CBPZ_TAG
#define CBPZ_TAG
Definition: vqavideo.c:95
av_fourcc2str
#define av_fourcc2str(fourcc)
Definition: avutil.h:345