FFmpeg
Loading...
Searching...
No Matches
vqcdec.c
Go to the documentation of this file.
1/*
2 * ViewQuest VQC decoder
3 * Copyright (C) 2022 Peter Ross
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
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
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "avcodec.h"
23#include "get_bits.h"
24#include "codec_internal.h"
25#include "decode.h"
26#include "libavutil/mem.h"
27#include "libavutil/thread.h"
28
29#define VECTOR_VLC_BITS 6
30
31static const uint8_t vector_nbits[] = {
32 2, 4, 4, 4, 4, 2, 4, 4,
33 6, 6, 6, 6, 6, 6, 6, 6
34};
35
36enum {
37 SKIP_3 = 0x10,
44};
45
46/* vector symbols are signed, but returned unsigned by get_vlc2()
47 codebook indexes are cast as uint8_t in seed_codebook() to compensate */
48static const int8_t vector_symbols[] = {
49 0, SKIP_3, SKIP_4, SKIP_5, SKIP_6, STOP_RUN, 1, -1,
50 2, 3, 4, SIGNED_8BIT, -2, -3, -4, SIGNED_6BIT
51};
52
54
63
64typedef struct VqcContext {
66 uint8_t * vectors;
67 int16_t * coeff, *tmp1, *tmp2;
68 int16_t codebook[4][256];
70
72{
73 static AVOnce init_static_once = AV_ONCE_INIT;
74 VqcContext *s = avctx->priv_data;
75
76 if (avctx->width & 15)
78
79 s->vectors = av_malloc((avctx->width * avctx->height * 3) / 2);
80 if (!s->vectors)
81 return AVERROR(ENOMEM);
82
83 s->coeff = av_malloc_array(2 * avctx->width, sizeof(s->coeff[0]));
84 if (!s->coeff)
85 return AVERROR(ENOMEM);
86
87 s->tmp1 = av_malloc_array(avctx->width / 2, sizeof(s->tmp1[0]));
88 if (!s->tmp1)
89 return AVERROR(ENOMEM);
90
91 s->tmp2 = av_malloc_array(avctx->width / 2, sizeof(s->tmp2[0]));
92 if (!s->tmp2)
93 return AVERROR(ENOMEM);
94
96 s->frame = av_frame_alloc();
97 if (!s->frame)
98 return AVERROR(ENOMEM);
99
100 ff_thread_once(&init_static_once, vqc_init_static_data);
101
102 return 0;
103}
104
105static int seed_pow1(int x)
106{
107 return x >= 1 && x <= 5 ? 1 << x : 0;
108}
109
110static int seed_pow2(int x)
111{
112 return x >= 1 && x <= 4 ? 1 << x : 1;
113}
114
115static int bias(int x, int c)
116{
117 if (x < 0)
118 return x - c;
119 else if (x > 0)
120 return x + c;
121 else
122 return 0;
123}
124
125static void seed_codebooks(VqcContext * s, const int * seed)
126{
127 int book1 = -256 * seed[3];
128 int book2 = -128 * seed[4];
129 int book3 = -128 * seed[5];
130 int book4 = -128 * seed[6];
131
132 for (int i = -128; i < 128; i++) {
133 s->codebook[0][(uint8_t)i] = book1;
134 s->codebook[1][(uint8_t)i] = bias(book2, seed[0]);
135 s->codebook[2][(uint8_t)i] = bias(book3, seed[1]);
136 s->codebook[3][(uint8_t)i] = bias(book4, seed[2]);
137
138 book1 += 2 * seed[3];
139 book2 += seed[4];
140 book3 += seed[5];
141 book4 += seed[6];
142 }
143}
144
145static int decode_vectors(VqcContext * s, const uint8_t * buf, int size, int width, int height)
146{
147 GetBitContext gb;
148 uint8_t * vectors = s->vectors;
149 uint8_t * vectors_end = s->vectors + (width * height * 3) / 2;
150 int ret;
151
152 memset(vectors, 0, 3 * width * height / 2);
153
154 ret = init_get_bits8(&gb, buf, size);
155 if (ret < 0)
156 return ret;
157
158 for (int i = 0; i < 3 * width * height / 2 / 32; i++) {
159 uint8_t * dst = vectors;
160 int symbol;
161
162 *dst++ = get_bits(&gb, 8);
163 *dst++ = get_bits(&gb, 8);
164
165 while (show_bits(&gb, 2) != 2) {
166 if (dst >= vectors_end - 1)
167 return 0;
168
169 if (get_bits_left(&gb) < 4)
170 return AVERROR_INVALIDDATA;
171
172 if (!show_bits(&gb, 4)) {
173 *dst++ = 0;
174 *dst++ = 0;
175 skip_bits(&gb, 4);
176 continue;
177 }
178
179 symbol = get_vlc2(&gb, vector_vlc, VECTOR_VLC_BITS, 1);
180 switch(symbol) {
181 case SKIP_3: dst += 3; break;
182 case SKIP_4: dst += 4; break;
183 case SKIP_5: dst += 5; break;
184 case SKIP_6: dst += 6; break;
185 case SIGNED_8BIT: *dst++ = get_sbits(&gb, 8); break;
186 case SIGNED_6BIT: *dst++ = get_sbits(&gb, 6); break;
187 default:
188 *dst++ = symbol;
189 }
190 }
191
192 skip_bits(&gb, 2);
193 vectors += 32;
194 }
195
196 return 0;
197}
198
199static void load_coeffs(VqcContext * s, const uint8_t * v, int width, int coeff_width)
200{
201 int16_t * c0 = s->coeff;
202 int16_t * c1 = s->coeff + coeff_width;
203 int16_t * c0_125 = s->coeff + (coeff_width >> 3);
204 int16_t * c1_125 = s->coeff + coeff_width + (coeff_width >> 3);
205 int16_t * c0_25 = s->coeff + (coeff_width >> 2);
206 int16_t * c1_25 = s->coeff + coeff_width + (coeff_width >> 2);
207 int16_t * c0_5 = s->coeff + (coeff_width >> 1);
208 int16_t * c1_5 = s->coeff + coeff_width + (coeff_width >> 1);
209
210 for (int i = 0; i < width; i++) {
211 c0[0] = s->codebook[0][v[0]];
212 c0[1] = s->codebook[0][v[1]];
213 c0 += 2;
214
215 c1[0] = s->codebook[0][v[2]];
216 c1[1] = s->codebook[0][v[3]];
217 c1 += 2;
218
219 c0_125[0] = s->codebook[1][v[4]];
220 c0_125[1] = s->codebook[1][v[5]];
221 c0_125 += 2;
222
223 c1_125[0] = s->codebook[1][v[6]];
224 c1_125[1] = s->codebook[1][v[7]];
225 c1_125 += 2;
226
227 c0_25[0] = s->codebook[2][v[8]];
228 c0_25[1] = s->codebook[2][v[9]];
229 c0_25[2] = s->codebook[2][v[10]];
230 c0_25[3] = s->codebook[2][v[11]];
231 c0_25 += 4;
232
233 c1_25[0] = s->codebook[2][v[12]];
234 c1_25[1] = s->codebook[2][v[13]];
235 c1_25[2] = s->codebook[2][v[14]];
236 c1_25[3] = s->codebook[2][v[15]];
237 c1_25 += 4;
238
239 if (v[16] | v[17] | v[18] | v[19]) {
240 c0_5[0] = s->codebook[3][v[16]];
241 c0_5[1] = s->codebook[3][v[17]];
242 c0_5[2] = s->codebook[3][v[18]];
243 c0_5[3] = s->codebook[3][v[19]];
244 } else {
245 c0_5[0] = c0_5[1] = c0_5[2] = c0_5[3] = 0;
246 }
247
248 if (v[20] | v[21] | v[22] | v[23]) {
249 c0_5[4] = s->codebook[3][v[20]];
250 c0_5[5] = s->codebook[3][v[21]];
251 c0_5[6] = s->codebook[3][v[22]];
252 c0_5[7] = s->codebook[3][v[23]];
253 } else {
254 c0_5[4] = c0_5[5] = c0_5[6] = c0_5[7] = 0;
255 }
256 c0_5 += 8;
257
258 if (v[24] | v[25] | v[26] | v[27]) {
259 c1_5[0] = s->codebook[3][v[24]];
260 c1_5[1] = s->codebook[3][v[25]];
261 c1_5[2] = s->codebook[3][v[26]];
262 c1_5[3] = s->codebook[3][v[27]];
263 } else {
264 c1_5[0] = c1_5[1] = c1_5[2] = c1_5[3] = 0;
265 }
266
267 if (v[28] | v[29] | v[30] | v[31]) {
268 c1_5[4] = s->codebook[3][v[28]];
269 c1_5[5] = s->codebook[3][v[29]];
270 c1_5[6] = s->codebook[3][v[30]];
271 c1_5[7] = s->codebook[3][v[31]];
272 } else {
273 c1_5[4] = c1_5[5] = c1_5[6] = c1_5[7] = 0;
274 }
275 c1_5 += 8;
276
277 v += 32;
278 }
279}
280
281static void transform1(const int16_t * a, const int16_t * b, int16_t * dst, int width)
282{
283 int s0 = a[0] + (b[0] >> 1);
284
285 for (int i = 0; i < width / 2 - 1; i++) {
286 dst[i * 2] = s0;
287 s0 = a[i + 1] + ((b[i] + b[i + 1]) >> 1);
288 dst[i * 2 + 1] = ((dst[i * 2] + s0) >> 1) - 2 * b[i];
289 }
290
291 dst[width - 2] = s0;
292 dst[width - 1] = a[width / 2 - 1] + ((b[width / 2 - 2] - 2 * b[width / 2 - 1]) >> 2) - b[width / 2 - 1];
293}
294
295static uint8_t clip(int x)
296{
297 return x >= -128 ? x <= 127 ? x + 0x80 : 0x00 : 0xFF;
298}
299
300static void transform2(const int16_t * a, const int16_t * b, uint8_t * dst, int width)
301{
302 int s0 = a[0] + (b[0] >> 1);
303 int tmp;
304
305 for (int i = 0; i < width / 2 - 1; i++) {
306 dst[i * 2] = av_clip_uint8(s0 + 0x80);
307 tmp = a[i + 1] + ((b[i] + b[i + 1]) >> 1);
308 dst[i * 2 + 1] = av_clip_uint8(((tmp + s0) >> 1) - 2 * b[i] + 0x80);
309 s0 = tmp;
310 }
311
312 dst[width - 2] = clip(s0);
313 dst[width - 1] = clip(a[width / 2 - 1] + ((b[width / 2 - 2] - 2 * b[width / 2 - 1]) >> 2) - b[width / 2 - 1]);
314}
315
316static void decode_strip(VqcContext * s, uint8_t * dst, int stride, int width)
317{
318 const int16_t * coeff;
319
320 for (int i = 0; i < width; i++) {
321 int v0 = s->coeff[i];
322 int v1 = s->coeff[width + i];
323 s->coeff[i] = v0 - v1;
324 s->coeff[width + i] = v0 + v1;
325 }
326
327 coeff = s->coeff;
328
329 transform1(coeff, coeff + width / 8, s->tmp1, width / 4);
330 transform1(s->tmp1, coeff + width / 4, s->tmp2, width / 2);
331 transform2(s->tmp2, coeff + width / 2, dst, width);
332
333 coeff += width;
334 dst += stride;
335
336 transform1(coeff, coeff + width / 8, s->tmp1, width / 4);
337 transform1(s->tmp1, coeff + width / 4, s->tmp2, width / 2);
338 transform2(s->tmp2, coeff + width / 2, dst, width);
339}
340
341static void decode_frame(VqcContext * s, int width, int height)
342{
343 uint8_t * vectors = s->vectors;
344 uint8_t * y = s->frame->data[0];
345 uint8_t * u = s->frame->data[1];
346 uint8_t * v = s->frame->data[2];
347
348 for (int j = 0; j < height / 4; j++) {
349 load_coeffs(s, vectors, width / 16, width);
350 decode_strip(s, y, s->frame->linesize[0], width);
351 vectors += 2 * width;
352 y += 2 * s->frame->linesize[0];
353
354 load_coeffs(s, vectors, width / 32, width / 2);
355 decode_strip(s, u, s->frame->linesize[1], width / 2);
356 vectors += width;
357 u += 2 * s->frame->linesize[1];
358
359 load_coeffs(s, vectors, width / 16, width);
360 decode_strip(s, y, s->frame->linesize[0], width);
361 vectors += 2 * width;
362 y += 2 * s->frame->linesize[0];
363
364 load_coeffs(s, vectors, width / 32, width / 2);
365 decode_strip(s, v, s->frame->linesize[2], width / 2);
366 vectors += width;
367 v += 2 * s->frame->linesize[2];
368 }
369}
370
371static int vqc_decode_frame(AVCodecContext *avctx, AVFrame * rframe,
372 int * got_frame, AVPacket * avpkt)
373{
374 VqcContext *s = avctx->priv_data;
375 int ret;
376 const uint8_t * buf = avpkt->data;
377 int cache, seed[7], gamma, contrast;
378
379 if (avpkt->size < 7)
380 return AVERROR_INVALIDDATA;
381
382 if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
383 return ret;
384
385 av_log(avctx, AV_LOG_DEBUG, "VQC%d format\n", (buf[2] & 1) + 1);
386
387 if (((buf[0] >> 1) & 7) != 5) {
388 avpriv_request_sample(avctx, "subversion != 5\n");
390 }
391
392 cache = AV_RL24(buf + 4);
393 seed[2] = seed_pow1((cache >> 1) & 7);
394 seed[1] = seed_pow1((cache >> 4) & 7);
395 seed[0] = seed_pow1((cache >> 7) & 7);
396 seed[6] = seed_pow2((cache >> 10) & 7);
397 seed[5] = seed_pow2((cache >> 13) & 7);
398 seed[4] = seed_pow2((cache >> 16) & 7);
399 seed[3] = seed_pow2((cache >> 19) & 7);
400
401 gamma = buf[0] >> 4;
402 contrast = AV_RL16(buf + 2) >> 1;
403 if (gamma || contrast)
404 avpriv_request_sample(avctx, "gamma=0x%x, contrast=0x%x\n", gamma, contrast);
405
407 ret = decode_vectors(s, buf + 7, avpkt->size - 7, avctx->width, avctx->height);
408 if (ret < 0)
409 return ret;
410 decode_frame(s, avctx->width, avctx->height);
411
412 if ((ret = av_frame_ref(rframe, s->frame)) < 0)
413 return ret;
414
415 *got_frame = 1;
416
417 return avpkt->size;
418}
419
421{
422 VqcContext *s = avctx->priv_data;
423
424 av_freep(&s->vectors);
425 av_freep(&s->coeff);
426 av_freep(&s->tmp1);
427 av_freep(&s->tmp2);
428 av_frame_free(&s->frame);
429
430 return 0;
431}
432
434 .p.name = "vqc",
435 CODEC_LONG_NAME("ViewQuest VQC"),
436 .p.type = AVMEDIA_TYPE_VIDEO,
437 .p.id = AV_CODEC_ID_VQC,
438 .priv_data_size = sizeof(VqcContext),
442 .p.capabilities = AV_CODEC_CAP_DR1,
443 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
444};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
const FFCodec ff_vqc_decoder
Definition vqcdec.c:433
static av_cold void close(AVCodecParserContext *s)
Definition apv_parser.c:197
Libavcodec external API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define FF_CODEC_DECODE_CB(func)
#define CODEC_LONG_NAME(str)
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
#define av_clip_uint8
Definition common.h:106
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:1906
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
bitstream reader API header.
static av_always_inline int get_vlc2(GetBitContext *s, const VLCElem *table, int bits, int max_depth)
Parse a vlc code.
Definition get_bits.h:645
static int get_sbits(GetBitContext *s, int n)
Definition get_bits.h:322
static int get_bits_left(GetBitContext *gb)
Definition get_bits.h:688
static void skip_bits(GetBitContext *s, int n)
Definition get_bits.h:383
static int init_get_bits8(GetBitContext *s, const uint8_t *buffer, int byte_size)
Initialize GetBitContext.
Definition get_bits.h:544
static unsigned int get_bits(GetBitContext *s, int n)
Read 1-25 bits.
Definition get_bits.h:337
static unsigned int show_bits(GetBitContext *s, int n)
Show 1-25 bits.
Definition get_bits.h:373
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition codec.h:49
@ AV_CODEC_ID_VQC
Definition codec_id.h:314
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition error.h:64
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
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:278
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
int a
#define b
Definition input.c:43
#define AV_RL24(x)
#define AV_RL16(p)
#define u(width, name, range_min, range_max)
Definition cbs_apv.c:68
#define av_cold
Definition attributes.h:117
#define AVOnce
Definition thread.h:202
static int ff_thread_once(char *control, void(*routine)(void))
Definition thread.h:205
#define AV_ONCE_INIT
Definition thread.h:203
Memory handling functions.
static const uint64_t c1
Definition murmur3.c:52
#define av_malloc(s)
Definition ops_static.c:52
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
#define FF_ARRAY_ELEMS(a)
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
int width
picture width / height.
Definition avcodec.h:604
void * priv_data
Definition avcodec.h:470
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
This structure stores compressed data.
Definition packet.h:580
int size
Definition packet.h:604
uint8_t * data
Definition packet.h:603
Definition vlc.h:32
int16_t * tmp1
Definition vqcdec.c:67
int16_t * tmp2
Definition vqcdec.c:67
int16_t * coeff
Definition vqcdec.c:67
uint8_t * vectors
Definition vqcdec.c:66
AVFrame * frame
Definition vqcdec.c:65
int16_t codebook[4][256]
Definition vqcdec.c:68
#define stride
#define av_malloc_array(a, b)
#define avpriv_request_sample(...)
#define av_freep(p)
#define av_log(a,...)
static uint8_t tmp[40]
Definition aes_ctr.c:52
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89
int size
static const double coeff[2][5]
static unsigned int seed
Definition videogen.c:78
#define VLC_INIT_STATIC_TABLE_FROM_LENGTHS(vlc_table, nb_bits, nb_codes, lens, lens_wrap, syms, syms_wrap, syms_size, offset, flags)
Definition vlc.h:288
static VLCElem vector_vlc[1<< VECTOR_VLC_BITS]
Definition vqcdec.c:53
static void load_coeffs(VqcContext *s, const uint8_t *v, int width, int coeff_width)
Definition vqcdec.c:199
static int bias(int x, int c)
Definition vqcdec.c:115
static void decode_frame(VqcContext *s, int width, int height)
Definition vqcdec.c:341
static const int8_t vector_symbols[]
Definition vqcdec.c:48
static int vqc_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, AVPacket *avpkt)
Definition vqcdec.c:371
static const uint8_t vector_nbits[]
Definition vqcdec.c:31
static av_cold int vqc_decode_init(AVCodecContext *avctx)
Definition vqcdec.c:71
#define VECTOR_VLC_BITS
Definition vqcdec.c:29
static void transform1(const int16_t *a, const int16_t *b, int16_t *dst, int width)
Definition vqcdec.c:281
static int decode_vectors(VqcContext *s, const uint8_t *buf, int size, int width, int height)
Definition vqcdec.c:145
static av_cold void vqc_init_static_data(void)
Definition vqcdec.c:55
static int seed_pow1(int x)
Definition vqcdec.c:105
@ SKIP_3
Definition vqcdec.c:37
@ SIGNED_8BIT
Definition vqcdec.c:42
@ SKIP_4
Definition vqcdec.c:38
@ STOP_RUN
Definition vqcdec.c:41
@ SKIP_5
Definition vqcdec.c:39
@ SKIP_6
Definition vqcdec.c:40
@ SIGNED_6BIT
Definition vqcdec.c:43
static av_cold int vqc_decode_end(AVCodecContext *avctx)
Definition vqcdec.c:420
static void transform2(const int16_t *a, const int16_t *b, uint8_t *dst, int width)
Definition vqcdec.c:300
static int seed_pow2(int x)
Definition vqcdec.c:110
static void decode_strip(VqcContext *s, uint8_t *dst, int stride, int width)
Definition vqcdec.c:316
static void seed_codebooks(VqcContext *s, const int *seed)
Definition vqcdec.c:125
static double c[64]