FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vmixdec.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 0 137 0.0%
Functions: 0 7 0.0%
Branches: 0 66 0.0%

Line Branch Exec Source
1 /*
2 * vMix decoder
3 * Copyright (c) 2023 Paul B Mahol
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 <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "libavutil/intreadwrite.h"
27 #include "libavutil/mem.h"
28 #include "libavutil/mem_internal.h"
29
30 #include "avcodec.h"
31 #include "codec_internal.h"
32 #define CACHED_BITSTREAM_READER !ARCH_X86_32
33 #include "golomb.h"
34 #include "get_bits.h"
35 #include "idctdsp.h"
36 #include "thread.h"
37
38 typedef struct SliceContext {
39 const uint8_t *dc_ptr;
40 const uint8_t *ac_ptr;
41 unsigned dc_size;
42 unsigned ac_size;
43 } SliceContext;
44
45 typedef struct VMIXContext {
46 int nb_slices;
47 int lshift;
48
49 int16_t factors[64];
50 uint8_t scan[64];
51
52 SliceContext *slices;
53 unsigned int slices_size;
54
55 IDCTDSPContext idsp;
56 } VMIXContext;
57
58 static const uint8_t quality[] = {
59 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
60 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
61 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
62 1, 1, 1, 1, 1, 1,64,63,62,61,
63 60,59,58,57,56,55,54,53,52,51,
64 50,49,48,47,46,45,44,43,42,41,
65 40,39,38,37,36,35,34,33,32,31,
66 30,29,28,27,26,25,24,23,22,21,
67 20,19,18,17,16,15,14,13,12,11,
68 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
69 };
70
71 static const uint8_t quant[64] = {
72 16, 16, 19, 22, 22, 26, 26, 27,
73 16, 16, 22, 22, 26, 27, 27, 29,
74 19, 22, 26, 26, 27, 29, 29, 35,
75 22, 24, 27, 27, 29, 32, 34, 38,
76 26, 27, 29, 29, 32, 35, 38, 46,
77 27, 29, 34, 34, 35, 40, 46, 56,
78 29, 34, 34, 37, 40, 48, 56, 69,
79 34, 37, 38, 40, 48, 58, 69, 83,
80 };
81
82 static av_cold int decode_init(AVCodecContext *avctx)
83 {
84 VMIXContext *s = avctx->priv_data;
85
86 avctx->bits_per_raw_sample = 8;
87 avctx->pix_fmt = AV_PIX_FMT_YUV422P;
88
89 avctx->coded_width = FFALIGN(avctx->width, 16);
90 avctx->coded_height = FFALIGN(avctx->height, 16);
91
92 ff_idctdsp_init(&s->idsp, avctx);
93 ff_permute_scantable(s->scan, ff_zigzag_direct,
94 s->idsp.idct_permutation);
95 return 0;
96 }
97
98 static inline int get_se_golomb_vmix(GetBitContext *gb)
99 {
100 unsigned int buf = get_ue_golomb_long(gb);
101 int sign = (buf & 1) - 1;
102 return ((buf >> 1) ^ (~sign));
103 }
104
105 static int decode_dcac(AVCodecContext *avctx,
106 GetBitContext *dc_gb, GetBitContext *ac_gb,
107 unsigned *dcrun, unsigned *acrun,
108 AVFrame *frame, int width, int by, int plane)
109 {
110 const ptrdiff_t linesize = frame->linesize[plane];
111 uint8_t *dst = frame->data[plane] + by * linesize;
112 unsigned dc_run = *dcrun, ac_run = *acrun;
113 LOCAL_ALIGNED_32(int16_t, block, [64]);
114 VMIXContext *s = avctx->priv_data;
115 const int16_t *factors = s->factors;
116 const uint8_t *scan = s->scan;
117 const int add = plane ? 0 : 1024;
118 int i, dc_v = 0, ac_v = 0, dc = 0;
119 const int lshift = s->lshift;
120
121 for (int y = 0; y < 2; y++) {
122 for (int x = 0; x < width; x += 8) {
123 memset(block, 0, sizeof(*block)*64);
124
125 if (dc_run > 0) {
126 dc_run--;
127 } else {
128 if (get_bits_left(dc_gb) < 1)
129 return AVERROR_INVALIDDATA;
130 dc_v = get_se_golomb_vmix(dc_gb);
131 dc += (unsigned)dc_v;
132 if (!dc_v)
133 dc_run = get_ue_golomb_long(dc_gb);
134 }
135
136 for (int n = 0; n < 64; n++) {
137 if (ac_run > 0) {
138 ac_run--;
139 continue;
140 }
141
142 if (get_bits_left(ac_gb) < 1)
143 return AVERROR_INVALIDDATA;
144 ac_v = get_se_golomb_vmix(ac_gb);
145 i = scan[n];
146 block[i] = ((unsigned)ac_v * factors[i]) >> 4;
147 if (!ac_v)
148 ac_run = get_ue_golomb_long(ac_gb);
149 }
150
151 block[0] = ((unsigned)dc << lshift) + (unsigned)add;
152 s->idsp.idct_put(dst + x, linesize, block);
153 }
154
155 dst += 8 * linesize;
156 }
157
158 *dcrun = dc_run;
159 *acrun = ac_run;
160
161 return 0;
162 }
163
164 static int decode_slice(AVCodecContext *avctx, AVFrame *frame,
165 const uint8_t *dc_src, unsigned dc_slice_size,
166 const uint8_t *ac_src, unsigned ac_slice_size,
167 int by)
168 {
169 unsigned dc_run = 0, ac_run = 0;
170 GetBitContext dc_gb, ac_gb;
171 int ret;
172
173 ret = init_get_bits8(&dc_gb, dc_src, dc_slice_size);
174 if (ret < 0)
175 return ret;
176
177 ret = init_get_bits8(&ac_gb, ac_src, ac_slice_size);
178 if (ret < 0)
179 return ret;
180
181 for (int p = 0; p < 3; p++) {
182 const int rshift = !!p;
183 ret = decode_dcac(avctx, &dc_gb, &ac_gb,
184 &dc_run, &ac_run, frame,
185 frame->width >> rshift, by, p);
186 if (ret < 0)
187 return ret;
188
189 if (get_bits_left(&dc_gb) < 0)
190 return AVERROR_INVALIDDATA;
191 if (get_bits_left(&ac_gb) < 0)
192 return AVERROR_INVALIDDATA;
193
194 align_get_bits(&dc_gb);
195 align_get_bits(&ac_gb);
196 }
197
198 if (get_bits_left(&dc_gb) > 0)
199 return AVERROR_INVALIDDATA;
200 if (get_bits_left(&ac_gb) > 0)
201 return AVERROR_INVALIDDATA;
202
203 return 0;
204 }
205
206 static int decode_slices(AVCodecContext *avctx, void *arg,
207 int n, int thread_nb)
208 {
209 VMIXContext *s = avctx->priv_data;
210 const uint8_t *dc_slice_ptr = s->slices[n].dc_ptr;
211 const uint8_t *ac_slice_ptr = s->slices[n].ac_ptr;
212 unsigned dc_slice_size = s->slices[n].dc_size;
213 unsigned ac_slice_size = s->slices[n].ac_size;
214 AVFrame *frame = arg;
215
216 return decode_slice(avctx, frame, dc_slice_ptr, dc_slice_size,
217 ac_slice_ptr, ac_slice_size, n * 16);
218 }
219
220 static int decode_frame(AVCodecContext *avctx,
221 AVFrame *frame, int *got_frame,
222 AVPacket *avpkt)
223 {
224 VMIXContext *s = avctx->priv_data;
225 unsigned offset, q;
226 int ret;
227
228 if (avpkt->size <= 7)
229 return AVERROR_INVALIDDATA;
230
231 s->lshift = 0;
232 offset = 2 + avpkt->data[0];
233 if (offset == 5)
234 s->lshift = avpkt->data[1];
235 else if (offset != 3)
236 return AVERROR_INVALIDDATA;
237
238 if (s->lshift > 31)
239 return AVERROR_INVALIDDATA;
240
241 q = quality[FFMIN(avpkt->data[offset - 2], FF_ARRAY_ELEMS(quality)-1)];
242 for (int n = 0; n < 64; n++)
243 s->factors[n] = quant[n] * q;
244
245 s->nb_slices = (avctx->height + 15) / 16;
246 av_fast_mallocz(&s->slices, &s->slices_size, s->nb_slices * sizeof(*s->slices));
247 if (!s->slices)
248 return AVERROR(ENOMEM);
249
250 for (int n = 0; n < s->nb_slices; n++) {
251 unsigned slice_size;
252
253 if (offset + 4 > avpkt->size)
254 return AVERROR_INVALIDDATA;
255
256 slice_size = AV_RL32(avpkt->data + offset);
257 if (slice_size > avpkt->size)
258 return AVERROR_INVALIDDATA;
259
260 if (avpkt->size - slice_size - 4LL < offset)
261 return AVERROR_INVALIDDATA;
262
263 s->slices[n].dc_size = slice_size;
264 s->slices[n].dc_ptr = avpkt->data + offset + 4;
265 offset += slice_size + 4;
266 }
267
268 for (int n = 0; n < s->nb_slices; n++) {
269 unsigned slice_size;
270
271 if (offset + 4 > avpkt->size)
272 return AVERROR_INVALIDDATA;
273
274 slice_size = AV_RL32(avpkt->data + offset);
275 if (slice_size > avpkt->size)
276 return AVERROR_INVALIDDATA;
277
278 if (avpkt->size - slice_size - 4LL < offset)
279 return AVERROR_INVALIDDATA;
280
281 s->slices[n].ac_size = slice_size;
282 s->slices[n].ac_ptr = avpkt->data + offset + 4;
283 offset += slice_size + 4;
284 }
285
286 ret = ff_thread_get_buffer(avctx, frame, 0);
287 if (ret < 0)
288 return ret;
289
290 avctx->execute2(avctx, decode_slices, frame, NULL, s->nb_slices);
291
292 *got_frame = 1;
293
294 return avpkt->size;
295 }
296
297 static av_cold int decode_end(AVCodecContext *avctx)
298 {
299 VMIXContext *s = avctx->priv_data;
300 av_freep(&s->slices);
301 return 0;
302 }
303
304 const FFCodec ff_vmix_decoder = {
305 .p.name = "vmix",
306 CODEC_LONG_NAME("vMix Video"),
307 .p.type = AVMEDIA_TYPE_VIDEO,
308 .p.id = AV_CODEC_ID_VMIX,
309 .priv_data_size = sizeof(VMIXContext),
310 .init = decode_init,
311 .close = decode_end,
312 FF_CODEC_DECODE_CB(decode_frame),
313 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS |
314 AV_CODEC_CAP_SLICE_THREADS,
315 };
316