FFmpeg
Loading...
Searching...
No Matches
vmixdec.c
Go to the documentation of this file.
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
27#include "libavutil/mem.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
38typedef struct SliceContext {
39 const uint8_t *dc_ptr;
40 const uint8_t *ac_ptr;
41 unsigned dc_size;
42 unsigned ac_size;
44
45typedef struct VMIXContext {
47 int lshift;
48
49 int16_t factors[64];
50 uint8_t scan[64];
51
53 unsigned int slices_size;
54
57
58static 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
71static 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
83{
84 VMIXContext *s = avctx->priv_data;
85
86 avctx->bits_per_raw_sample = 8;
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);
94 s->idsp.idct_permutation);
95 return 0;
96}
97
98static 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
105static 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
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
206static 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
220static 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
298{
299 VMIXContext *s = avctx->priv_data;
300 av_freep(&s->slices);
301 return 0;
302}
303
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,
313 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS |
315};
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_vmix_decoder
Definition vmixdec.c:304
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 NULL
Definition coverity.c:32
static int16_t block[64]
Definition dct.c:125
static AVFrame * frame
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
static int decode_slices(AVCodecContext *avctx, RangeCoder c, AVPacket *avpkt)
Definition ffv1dec.c:791
bitstream reader API header.
static int get_bits_left(GetBitContext *gb)
Definition get_bits.h:688
static int init_get_bits8(GetBitContext *s, const uint8_t *buffer, int byte_size)
Initialize GetBitContext.
Definition get_bits.h:544
static const uint8_t * align_get_bits(GetBitContext *s)
Definition get_bits.h:560
exp golomb vlc stuff
static unsigned get_ue_golomb_long(GetBitContext *gb)
Read an unsigned Exp-Golomb code in the range 0 to UINT32_MAX-1.
Definition golomb.h:104
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition codec.h:49
#define AV_CODEC_CAP_SLICE_THREADS
Codec supports slice-based (or partition-based) multithreading.
Definition codec.h:102
#define AV_CODEC_CAP_FRAME_THREADS
Codec supports frame-level multithreading.
Definition codec.h:98
@ AV_CODEC_ID_VMIX
Definition codec_id.h:318
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
Allocate and clear a buffer, reusing the given one if large enough.
Definition mem.c:560
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
#define AV_RL32(p)
unsigned offset
Definition libaomenc.c:763
static av_cold int decode_init(AVCodecContext *avctx)
Definition 4xm.c:998
static av_cold int decode_end(AVCodecContext *avctx)
Definition 4xm.c:980
static int decode_frame(AVCodecContext *avctx, AVFrame *picture, int *got_frame, AVPacket *avpkt)
Definition 4xm.c:837
av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx)
Definition idctdsp.c:228
av_cold void ff_permute_scantable(uint8_t dst[64], const uint8_t src[64], const uint8_t permutation[64])
Definition idctdsp.c:30
const char * arg
Definition jacosubdec.c:65
Multithreading API for decoders.
#define av_cold
Definition attributes.h:117
#define FFMIN(a, b)
Definition macros.h:49
#define FFALIGN(x, a)
Definition macros.h:78
const uint8_t ff_zigzag_direct[64]
Definition mathtables.c:137
Memory handling functions.
#define LOCAL_ALIGNED_32(t, v,...)
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:77
int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f, int flags)
Wrapper around get_buffer() for frame-multithreaded codecs.
#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
int bits_per_raw_sample
Bits per sample/pixel of internal libavcodec pixel/sample format.
Definition avcodec.h:1571
int(* execute2)(struct AVCodecContext *c, int(*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count)
The codec may call this to execute several independent things.
Definition avcodec.h:1628
int coded_width
Bitstream width / height, may be different from width/height e.g.
Definition avcodec.h:619
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
unsigned ac_size
Definition vmixdec.c:42
const uint8_t * dc_ptr
Definition vmixdec.c:39
const uint8_t * ac_ptr
Definition vmixdec.c:40
unsigned dc_size
Definition vmixdec.c:41
IDCTDSPContext idsp
Definition vmixdec.c:55
SliceContext * slices
Definition vmixdec.c:52
int nb_slices
Definition vmixdec.c:46
int lshift
Definition vmixdec.c:47
int16_t factors[64]
Definition vmixdec.c:49
unsigned int slices_size
Definition vmixdec.c:53
uint8_t scan[64]
Definition vmixdec.c:50
#define av_freep(p)
#define width
Definition dsp.h:89
static int decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt)
Definition vmixdec.c:220
static int decode_slices(AVCodecContext *avctx, void *arg, int n, int thread_nb)
Definition vmixdec.c:206
static av_cold int decode_init(AVCodecContext *avctx)
Definition vmixdec.c:82
static int decode_dcac(AVCodecContext *avctx, GetBitContext *dc_gb, GetBitContext *ac_gb, unsigned *dcrun, unsigned *acrun, AVFrame *frame, int width, int by, int plane)
Definition vmixdec.c:105
static av_cold int decode_end(AVCodecContext *avctx)
Definition vmixdec.c:297
static const uint8_t quant[64]
Definition vmixdec.c:71
static const uint8_t quality[]
Definition vmixdec.c:58
static int get_se_golomb_vmix(GetBitContext *gb)
Definition vmixdec.c:98
static int decode_slice(AVCodecContext *avctx, AVFrame *frame, const uint8_t *dc_src, unsigned dc_slice_size, const uint8_t *ac_src, unsigned ac_slice_size, int by)
Definition vmixdec.c:164