Imported Upstream version 6.1
[platform/upstream/ffmpeg.git] / libavcodec / vqcdec.c
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/thread.h"
27
28 #define VECTOR_VLC_BITS 6
29
30 static const uint8_t vector_nbits[] = {
31     2, 4, 4, 4, 4, 2, 4, 4,
32     6, 6, 6, 6, 6, 6, 6, 6
33 };
34
35 enum {
36     SKIP_3 = 0x10,
37     SKIP_4,
38     SKIP_5,
39     SKIP_6,
40     STOP_RUN,
41     SIGNED_8BIT,
42     SIGNED_6BIT
43 };
44
45 /* vector symbols are signed, but returned unsigned by get_vlc2()
46    codebook indexes are cast as uint8_t in seed_codebook() to compensate */
47 static const int8_t vector_symbols[] = {
48     0, SKIP_3, SKIP_4, SKIP_5, SKIP_6, STOP_RUN, 1, -1,
49     2, 3, 4, SIGNED_8BIT, -2, -3, -4, SIGNED_6BIT
50 };
51
52 static VLC vector_vlc;
53
54 static av_cold void vqc_init_static_data(void)
55 {
56     VLC_INIT_STATIC_FROM_LENGTHS(&vector_vlc, VECTOR_VLC_BITS, FF_ARRAY_ELEMS(vector_nbits),
57                              vector_nbits, 1,
58                              vector_symbols, 1, 1,
59                              0, 0, 1 << VECTOR_VLC_BITS);
60 }
61
62 typedef struct VqcContext {
63     AVFrame *frame;
64     uint8_t * vectors;
65     int16_t * coeff, *tmp1, *tmp2;
66     int16_t codebook[4][256];
67 } VqcContext;
68
69 static av_cold int vqc_decode_init(AVCodecContext * avctx)
70 {
71     static AVOnce init_static_once = AV_ONCE_INIT;
72     VqcContext *s = avctx->priv_data;
73
74     if (avctx->width & 15)
75         return AVERROR_PATCHWELCOME;
76
77     s->vectors = av_malloc((avctx->width * avctx->height * 3) / 2);
78     if (!s->vectors)
79         return AVERROR(ENOMEM);
80
81     s->coeff = av_malloc_array(2 * avctx->width, sizeof(s->coeff[0]));
82     if (!s->coeff)
83         return AVERROR(ENOMEM);
84
85     s->tmp1 = av_malloc_array(avctx->width / 2, sizeof(s->tmp1[0]));
86     if (!s->tmp1)
87         return AVERROR(ENOMEM);
88
89     s->tmp2 = av_malloc_array(avctx->width / 2, sizeof(s->tmp2[0]));
90     if (!s->tmp2)
91         return AVERROR(ENOMEM);
92
93     avctx->pix_fmt = AV_PIX_FMT_YUV420P;
94     s->frame = av_frame_alloc();
95     if (!s->frame)
96         return AVERROR(ENOMEM);
97
98     ff_thread_once(&init_static_once, vqc_init_static_data);
99
100     return 0;
101 }
102
103 static int seed_pow1(int x)
104 {
105     return x >= 1 && x <= 5 ? 1 << x : 0;
106 }
107
108 static int seed_pow2(int x)
109 {
110     return x >= 1 && x <= 4 ? 1 << x : 1;
111 }
112
113 static int bias(int x, int c)
114 {
115     if (x < 0)
116         return x - c;
117     else if (x > 0)
118         return x + c;
119     else
120         return 0;
121 }
122
123 static void seed_codebooks(VqcContext * s, const int * seed)
124 {
125     int book1 = -256 * seed[3];
126     int book2 = -128 * seed[4];
127     int book3 = -128 * seed[5];
128     int book4 = -128 * seed[6];
129
130     for (int i = -128; i < 128; i++) {
131         s->codebook[0][(uint8_t)i] = book1;
132         s->codebook[1][(uint8_t)i] = bias(book2, seed[0]);
133         s->codebook[2][(uint8_t)i] = bias(book3, seed[1]);
134         s->codebook[3][(uint8_t)i] = bias(book4, seed[2]);
135
136         book1 += 2 * seed[3];
137         book2 += seed[4];
138         book3 += seed[5];
139         book4 += seed[6];
140     }
141 }
142
143 static int decode_vectors(VqcContext * s, const uint8_t * buf, int size, int width, int height)
144 {
145     GetBitContext gb;
146     uint8_t * vectors = s->vectors;
147     uint8_t * vectors_end = s->vectors + (width * height * 3) / 2;
148
149     memset(vectors, 0, 3 * width * height / 2);
150
151     init_get_bits8(&gb, buf, size);
152
153     for (int i = 0; i < 3 * width * height / 2 / 32; i++) {
154         uint8_t * dst = vectors;
155         int symbol;
156
157         *dst++ = get_bits(&gb, 8);
158         *dst++ = get_bits(&gb, 8);
159
160         while (show_bits(&gb, 2) != 2) {
161             if (dst >= vectors_end - 1)
162                 return 0;
163
164             if (get_bits_left(&gb) < 4)
165                 return AVERROR_INVALIDDATA;
166
167             if (!show_bits(&gb, 4)) {
168                 *dst++ = 0;
169                 *dst++ = 0;
170                 skip_bits(&gb, 4);
171                 continue;
172             }
173
174             symbol = get_vlc2(&gb, vector_vlc.table, VECTOR_VLC_BITS, 1);
175             switch(symbol) {
176             case SKIP_3: dst += 3; break;
177             case SKIP_4: dst += 4; break;
178             case SKIP_5: dst += 5; break;
179             case SKIP_6: dst += 6; break;
180             case SIGNED_8BIT: *dst++ = get_sbits(&gb, 8); break;
181             case SIGNED_6BIT: *dst++ = get_sbits(&gb, 6); break;
182             default:
183                 *dst++ = symbol;
184             }
185         }
186
187         skip_bits(&gb, 2);
188         vectors += 32;
189     }
190
191     return 0;
192 }
193
194 static void load_coeffs(VqcContext * s, const uint8_t * v, int width, int coeff_width)
195 {
196     int16_t * c0     = s->coeff;
197     int16_t * c1     = s->coeff + coeff_width;
198     int16_t * c0_125 = s->coeff + (coeff_width >> 3);
199     int16_t * c1_125 = s->coeff + coeff_width + (coeff_width >> 3);
200     int16_t * c0_25  = s->coeff + (coeff_width >> 2);
201     int16_t * c1_25 =  s->coeff + coeff_width + (coeff_width >> 2);
202     int16_t * c0_5  =  s->coeff + (coeff_width >> 1);
203     int16_t * c1_5  =  s->coeff + coeff_width + (coeff_width >> 1);
204
205     for (int i = 0; i < width; i++) {
206         c0[0] = s->codebook[0][v[0]];
207         c0[1] = s->codebook[0][v[1]];
208         c0 += 2;
209
210         c1[0] = s->codebook[0][v[2]];
211         c1[1] = s->codebook[0][v[3]];
212         c1 += 2;
213
214         c0_125[0] = s->codebook[1][v[4]];
215         c0_125[1] = s->codebook[1][v[5]];
216         c0_125 += 2;
217
218         c1_125[0] = s->codebook[1][v[6]];
219         c1_125[1] = s->codebook[1][v[7]];
220         c1_125 += 2;
221
222         c0_25[0] = s->codebook[2][v[8]];
223         c0_25[1] = s->codebook[2][v[9]];
224         c0_25[2] = s->codebook[2][v[10]];
225         c0_25[3] = s->codebook[2][v[11]];
226         c0_25 += 4;
227
228         c1_25[0] = s->codebook[2][v[12]];
229         c1_25[1] = s->codebook[2][v[13]];
230         c1_25[2] = s->codebook[2][v[14]];
231         c1_25[3] = s->codebook[2][v[15]];
232         c1_25 += 4;
233
234         if (v[16] | v[17] | v[18] | v[19]) {
235             c0_5[0] = s->codebook[3][v[16]];
236             c0_5[1] = s->codebook[3][v[17]];
237             c0_5[2] = s->codebook[3][v[18]];
238             c0_5[3] = s->codebook[3][v[19]];
239         } else {
240             c0_5[0] = c0_5[1] = c0_5[2] = c0_5[3] = 0;
241         }
242
243         if (v[20] | v[21] | v[22] | v[23]) {
244             c0_5[4] = s->codebook[3][v[20]];
245             c0_5[5] = s->codebook[3][v[21]];
246             c0_5[6] = s->codebook[3][v[22]];
247             c0_5[7] = s->codebook[3][v[23]];
248         } else {
249             c0_5[4] = c0_5[5] = c0_5[6] = c0_5[7] = 0;
250         }
251         c0_5 += 8;
252
253         if (v[24] | v[25] | v[26] | v[27]) {
254             c1_5[0] = s->codebook[3][v[24]];
255             c1_5[1] = s->codebook[3][v[25]];
256             c1_5[2] = s->codebook[3][v[26]];
257             c1_5[3] = s->codebook[3][v[27]];
258         } else {
259             c1_5[0] = c1_5[1] = c1_5[2] = c1_5[3] = 0;
260         }
261
262         if (v[28] | v[29] | v[30] | v[31]) {
263             c1_5[4] = s->codebook[3][v[28]];
264             c1_5[5] = s->codebook[3][v[29]];
265             c1_5[6] = s->codebook[3][v[30]];
266             c1_5[7] = s->codebook[3][v[31]];
267         } else {
268             c1_5[4] = c1_5[5] = c1_5[6] = c1_5[7] = 0;
269         }
270         c1_5 += 8;
271
272         v += 32;
273     }
274 }
275
276 static void transform1(const int16_t * a, const int16_t * b, int16_t * dst, int width)
277 {
278     int s0 = a[0] + (b[0] >> 1);
279
280     for (int i = 0; i < width / 2 - 1; i++) {
281         dst[i * 2] = s0;
282         s0 = a[i + 1] + ((b[i] + b[i + 1]) >> 1);
283         dst[i * 2 + 1] = ((dst[i * 2] + s0) >> 1) - 2 * b[i];
284     }
285
286     dst[width - 2] = s0;
287     dst[width - 1] = a[width / 2 - 1] + ((b[width / 2 - 2] - 2 * b[width / 2 - 1]) >> 2) - b[width / 2 - 1];
288 }
289
290 static uint8_t clip(int x)
291 {
292     return x >= -128 ? x <= 127 ? x + 0x80 : 0x00 : 0xFF;
293 }
294
295 static void transform2(const int16_t * a, const int16_t * b, uint8_t * dst, int width)
296 {
297     int s0 = a[0] + (b[0] >> 1);
298     int tmp;
299
300     for (int i = 0; i < width / 2 - 1; i++) {
301         dst[i * 2] = av_clip_uint8(s0 + 0x80);
302         tmp = a[i + 1] + ((b[i] + b[i + 1]) >> 1);
303         dst[i * 2 + 1] = av_clip_uint8(((tmp + s0) >> 1) - 2 * b[i] + 0x80);
304         s0 = tmp;
305     }
306
307     dst[width - 2] = clip(s0);
308     dst[width - 1] = clip(a[width / 2 - 1] + ((b[width / 2 - 2] - 2 * b[width / 2 - 1]) >> 2) - b[width / 2 - 1]);
309 }
310
311 static void decode_strip(VqcContext * s, uint8_t * dst, int stride, int width)
312 {
313     const int16_t * coeff;
314
315     for (int i = 0; i < width; i++) {
316         int v0 = s->coeff[i];
317         int v1 = s->coeff[width + i];
318         s->coeff[i] = v0 - v1;
319         s->coeff[width + i] = v0 + v1;
320     }
321
322     coeff = s->coeff;
323
324     transform1(coeff, coeff + width / 8, s->tmp1, width / 4);
325     transform1(s->tmp1, coeff + width / 4, s->tmp2, width / 2);
326     transform2(s->tmp2, coeff + width / 2, dst, width);
327
328     coeff += width;
329     dst += stride;
330
331     transform1(coeff, coeff + width / 8, s->tmp1, width / 4);
332     transform1(s->tmp1, coeff + width / 4, s->tmp2, width / 2);
333     transform2(s->tmp2, coeff + width / 2, dst, width);
334 }
335
336 static void decode_frame(VqcContext * s, int width, int height)
337 {
338     uint8_t * vectors = s->vectors;
339     uint8_t * y = s->frame->data[0];
340     uint8_t * u = s->frame->data[1];
341     uint8_t * v = s->frame->data[2];
342
343     for (int j = 0; j < height / 4; j++) {
344         load_coeffs(s, vectors, width / 16, width);
345         decode_strip(s, y, s->frame->linesize[0], width);
346         vectors += 2 * width;
347         y += 2 * s->frame->linesize[0];
348
349         load_coeffs(s, vectors, width / 32, width / 2);
350         decode_strip(s, u, s->frame->linesize[1], width / 2);
351         vectors += width;
352         u += 2 * s->frame->linesize[1];
353
354         load_coeffs(s, vectors, width / 16, width);
355         decode_strip(s, y, s->frame->linesize[0], width);
356         vectors += 2 * width;
357         y += 2 * s->frame->linesize[0];
358
359         load_coeffs(s, vectors, width / 32, width / 2);
360         decode_strip(s, v, s->frame->linesize[2], width / 2);
361         vectors += width;
362         v += 2 * s->frame->linesize[2];
363     }
364 }
365
366 static int vqc_decode_frame(AVCodecContext *avctx, AVFrame * rframe,
367                             int * got_frame, AVPacket * avpkt)
368 {
369     VqcContext *s = avctx->priv_data;
370     int ret;
371     const uint8_t * buf = avpkt->data;
372     int cache, seed[7], gamma, contrast;
373
374     if (avpkt->size < 7)
375         return AVERROR_INVALIDDATA;
376
377     if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
378         return ret;
379
380     av_log(avctx, AV_LOG_DEBUG, "VQC%d format\n", (buf[2] & 1) + 1);
381
382     if (((buf[0] >> 1) & 7) != 5) {
383         avpriv_request_sample(avctx, "subversion != 5\n");
384         return AVERROR_PATCHWELCOME;
385     }
386
387     cache = AV_RL24(buf + 4);
388     seed[2] = seed_pow1((cache >> 1) & 7);
389     seed[1] = seed_pow1((cache >> 4) & 7);
390     seed[0] = seed_pow1((cache >> 7) & 7);
391     seed[6] = seed_pow2((cache >> 10) & 7);
392     seed[5] = seed_pow2((cache >> 13) & 7);
393     seed[4] = seed_pow2((cache >> 16) & 7);
394     seed[3] = seed_pow2((cache >> 19) & 7);
395
396     gamma = buf[0] >> 4;
397     contrast = AV_RL16(buf + 2) >> 1;
398     if (gamma || contrast)
399         avpriv_request_sample(avctx, "gamma=0x%x, contrast=0x%x\n", gamma, contrast);
400
401     seed_codebooks(s, seed);
402     ret = decode_vectors(s, buf + 7, avpkt->size - 7, avctx->width, avctx->height);
403     if (ret < 0)
404         return ret;
405     decode_frame(s, avctx->width, avctx->height);
406
407     if ((ret = av_frame_ref(rframe, s->frame)) < 0)
408         return ret;
409
410     *got_frame = 1;
411
412     return avpkt->size;
413 }
414
415 static av_cold int vqc_decode_end(AVCodecContext * avctx)
416 {
417     VqcContext *s = avctx->priv_data;
418
419     av_freep(&s->vectors);
420     av_freep(&s->coeff);
421     av_freep(&s->tmp1);
422     av_freep(&s->tmp2);
423     av_frame_free(&s->frame);
424
425     return 0;
426 }
427
428 const FFCodec ff_vqc_decoder = {
429     .p.name         = "vqc",
430     CODEC_LONG_NAME("ViewQuest VQC"),
431     .p.type         = AVMEDIA_TYPE_VIDEO,
432     .p.id           = AV_CODEC_ID_VQC,
433     .priv_data_size = sizeof(VqcContext),
434     .init           = vqc_decode_init,
435     .close          = vqc_decode_end,
436     FF_CODEC_DECODE_CB(vqc_decode_frame),
437     .p.capabilities = AV_CODEC_CAP_DR1,
438     .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
439 };