History

avcodec: add VMX1 decoder

Paul B Mahol committed 3 years ago

Commit 2d59ca01 parent 3b0ed239 files · +302 −1Browse files

Unified · Split

9 files
  1. Changelog +1 −0
  2. configure +1 −0
  3. libavcodec/Makefile +1 −0
  4. libavcodec/allcodecs.c +1 −0
  5. libavcodec/codec_desc.c +7 −0
  6. libavcodec/codec_id.h +1 −0
  7. libavcodec/version.h +1 −1
  8. libavcodec/vmixdec.c +288 −0
  9. libavformat/riff.c +1 −0
Changelog+1−0
@@ -16,6 +16,7 @@ version <next>: · 15 unmodified lines
1616 - nlmeans_vulkan filter
1717 - RivaTuner video decoder
1818 - xfade_vulkan filter
19+- vMix video decoder
1920
2021 version 6.0:
2122 - Radiance HDR image support
configure+1−0
@@ -3006,6 +3006,7 @@ utvideo_encoder_select="bswapdsp huffman llvidencdsp" · 3005 unmodified lines
30063006 vble_decoder_select="llviddsp"
30073007 vbn_decoder_select="texturedsp"
30083008 vbn_encoder_select="texturedspenc"
3009+vmix_decoder_select="idctdsp"
30093010 vc1_decoder_select="blockdsp h264qpel intrax8 mpegvideodec qpeldsp vc1dsp"
30103011 vc1image_decoder_select="vc1_decoder"
30113012 vorbis_encoder_select="audio_frame_queue"
libavcodec/Makefile+1−0
@@ -753,6 +753,7 @@ OBJS-$(CONFIG_VC2_ENCODER) += vc2enc.o vc2enc_dwt.o diractab.o · 752 unmodified lines
753753 OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o
754754 OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdaudio.o
755755 OBJS-$(CONFIG_VMDVIDEO_DECODER) += vmdvideo.o
756+OBJS-$(CONFIG_VMIX_DECODER) += vmixdec.o
756757 OBJS-$(CONFIG_VMNC_DECODER) += vmnc.o
757758 OBJS-$(CONFIG_VNULL_DECODER) += null.o
758759 OBJS-$(CONFIG_VNULL_ENCODER) += null.o
libavcodec/allcodecs.c+1−0
@@ -370,6 +370,7 @@ extern const FFCodec ff_vc1_v4l2m2m_decoder; · 369 unmodified lines
370370 extern const FFCodec ff_vc2_encoder;
371371 extern const FFCodec ff_vcr1_decoder;
372372 extern const FFCodec ff_vmdvideo_decoder;
373+extern const FFCodec ff_vmix_decoder;
373374 extern const FFCodec ff_vmnc_decoder;
374375 extern const FFCodec ff_vp3_decoder;
375376 extern const FFCodec ff_vp4_decoder;
libavcodec/codec_desc.c+7−0
@@ -1953,6 +1953,13 @@ static const AVCodecDescriptor codec_descriptors[] = { · 1952 unmodified lines
19531953 .long_name = NULL_IF_CONFIG_SMALL("RTV1 (RivaTuner Video)"),
19541954 .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
19551955 },
1956+ {
1957+ .id = AV_CODEC_ID_VMIX,
1958+ .type = AVMEDIA_TYPE_VIDEO,
1959+ .name = "vmix",
1960+ .long_name = NULL_IF_CONFIG_SMALL("vMix Video"),
1961+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
1962+ },
19561963
19571964 /* various PCM "codecs" */
19581965 {
libavcodec/codec_id.h+1−0
@@ -323,6 +323,7 @@ enum AVCodecID { · 322 unmodified lines
323323 AV_CODEC_ID_PDV,
324324 AV_CODEC_ID_EVC,
325325 AV_CODEC_ID_RTV1,
326+ AV_CODEC_ID_VMIX,
326327
327328 /* various PCM "codecs" */
328329 AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
libavcodec/version.h+1−1
@@ -29,7 +29,7 @@ · 28 unmodified lines
2929
3030 #include "version_major.h"
3131
32−#define LIBAVCODEC_VERSION_MINOR 17
32+#define LIBAVCODEC_VERSION_MINOR 18
3333 #define LIBAVCODEC_VERSION_MICRO 100
3434
3535 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
libavcodec/vmixdec.c+288−0
@@ -0,0 +1,288 @@
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/avassert.h"
27+#include "libavutil/intreadwrite.h"
28+#include "libavutil/mem_internal.h"
29+
30+#include "avcodec.h"
31+#include "codec_internal.h"
32+#include "decode.h"
33+#define CACHED_BITSTREAM_READER !ARCH_X86_32
34+#include "golomb.h"
35+#include "get_bits.h"
36+#include "idctdsp.h"
37+#include "thread.h"
38+
39+typedef struct SliceContext {
40+ const uint8_t *dc_ptr;
41+ const uint8_t *ac_ptr;
42+ unsigned dc_size;
43+ unsigned ac_size;
44+} SliceContext;
45+
46+typedef struct VMIXContext {
47+ int nb_slices;
48+
49+ int16_t factors[64];
50+ uint8_t scan[64];
51+
52+ SliceContext slices[255];
53+
54+ IDCTDSPContext idsp;
55+} VMIXContext;
56+
57+static const uint8_t quality[25] = {
58+ 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16,
59+ 18, 20, 22, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64,
60+};
61+
62+static const uint8_t quant[64] = {
63+ 16, 16, 19, 22, 22, 26, 26, 27,
64+ 16, 16, 22, 22, 26, 27, 27, 29,
65+ 19, 22, 26, 26, 27, 29, 29, 35,
66+ 22, 24, 27, 27, 29, 32, 34, 38,
67+ 26, 27, 29, 29, 32, 35, 38, 46,
68+ 27, 29, 34, 34, 35, 40, 46, 56,
69+ 29, 34, 34, 37, 40, 48, 56, 69,
70+ 34, 37, 38, 40, 48, 58, 69, 83,
71+};
72+
73+static av_cold int decode_init(AVCodecContext *avctx)
74+{
75+ VMIXContext *s = avctx->priv_data;
76+
77+ avctx->bits_per_raw_sample = 8;
78+ avctx->pix_fmt = AV_PIX_FMT_YUV422P;
79+
80+ avctx->coded_width = FFALIGN(avctx->width, 16);
81+ avctx->coded_height = FFALIGN(avctx->height, 16);
82+
83+ ff_idctdsp_init(&s->idsp, avctx);
84+ ff_permute_scantable(s->scan, ff_zigzag_direct,
85+ s->idsp.idct_permutation);
86+ return 0;
87+}
88+
89+static inline int get_se_golomb_vmix(GetBitContext *gb)
90+{
91+ unsigned int buf = get_ue_golomb_long(gb);
92+ int sign = (buf & 1) - 1;
93+ return ((buf >> 1) ^ (~sign));
94+}
95+
96+static int decode_dcac(AVCodecContext *avctx,
97+ GetBitContext *dc_gb, GetBitContext *ac_gb,
98+ unsigned *dcrun, unsigned *acrun,
99+ AVFrame *frame, int width, int by, int plane)
100+{
101+ const ptrdiff_t linesize = frame->linesize[plane];
102+ uint8_t *dst = frame->data[plane] + by * linesize;
103+ unsigned dc_run = *dcrun, ac_run = *acrun;
104+ LOCAL_ALIGNED_32(int16_t, block, [64]);
105+ VMIXContext *s = avctx->priv_data;
106+ const int16_t *factors = s->factors;
107+ const uint8_t *scan = s->scan;
108+ const int add = plane ? 0 : 1024;
109+ int i, dc_v = 0, ac_v = 0, dc = 0;
110+
111+ for (int y = 0; y < 2; y++) {
112+ for (int x = 0; x < width; x += 8) {
113+ memset(block, 0, sizeof(*block)*64);
114+
115+ if (dc_run > 0) {
116+ dc_run--;
117+ } else {
118+ dc_v = get_se_golomb_vmix(dc_gb);
119+ dc += dc_v;
120+ if (!dc_v)
121+ dc_run = get_ue_golomb_long(dc_gb);
122+ }
123+
124+ for (int n = 0; n < 64; n++) {
125+ if (ac_run > 0) {
126+ ac_run--;
127+ continue;
128+ }
129+
130+ ac_v = get_se_golomb_vmix(ac_gb);
131+ i = scan[n];
132+ block[i] = (ac_v * factors[i]) >> 4;
133+ if (!ac_v)
134+ ac_run = get_ue_golomb_long(ac_gb);
135+ }
136+
137+ block[0] = ((dc + add) * 16) >> 4;
138+ s->idsp.idct_put(dst + x, linesize, block);
139+ }
140+
141+ dst += 8 * linesize;
142+ }
143+
144+ *dcrun = dc_run;
145+ *acrun = ac_run;
146+
147+ return 0;
148+}
149+
150+static int decode_slice(AVCodecContext *avctx, AVFrame *frame,
151+ const uint8_t *dc_src, unsigned dc_slice_size,
152+ const uint8_t *ac_src, unsigned ac_slice_size,
153+ int by)
154+{
155+ unsigned dc_run = 0, ac_run = 0;
156+ GetBitContext dc_gb, ac_gb;
157+ int ret;
158+
159+ ret = init_get_bits8(&dc_gb, dc_src, dc_slice_size);
160+ if (ret < 0)
161+ return ret;
162+
163+ ret = init_get_bits8(&ac_gb, ac_src, ac_slice_size);
164+ if (ret < 0)
165+ return ret;
166+
167+ for (int p = 0; p < 3; p++) {
168+ const int rshift = !!p;
169+ ret = decode_dcac(avctx, &dc_gb, &ac_gb,
170+ &dc_run, &ac_run, frame,
171+ frame->width >> rshift, by, p);
172+ if (ret < 0)
173+ return ret;
174+
175+ if (get_bits_left(&dc_gb) < 0)
176+ return AVERROR_INVALIDDATA;
177+ if (get_bits_left(&ac_gb) < 0)
178+ return AVERROR_INVALIDDATA;
179+
180+ align_get_bits(&dc_gb);
181+ align_get_bits(&ac_gb);
182+ }
183+
184+ if (get_bits_left(&dc_gb) > 0)
185+ return AVERROR_INVALIDDATA;
186+ if (get_bits_left(&ac_gb) > 0)
187+ return AVERROR_INVALIDDATA;
188+
189+ return 0;
190+}
191+
192+static int decode_slices(AVCodecContext *avctx, void *arg,
193+ int n, int thread_nb)
194+{
195+ VMIXContext *s = avctx->priv_data;
196+ const uint8_t *dc_slice_ptr = s->slices[n].dc_ptr;
197+ const uint8_t *ac_slice_ptr = s->slices[n].ac_ptr;
198+ unsigned dc_slice_size = s->slices[n].dc_size;
199+ unsigned ac_slice_size = s->slices[n].ac_size;
200+ AVFrame *frame = arg;
201+
202+ return decode_slice(avctx, frame, dc_slice_ptr, dc_slice_size,
203+ ac_slice_ptr, ac_slice_size, n * 16);
204+}
205+
206+static int decode_frame(AVCodecContext *avctx,
207+ AVFrame *frame, int *got_frame,
208+ AVPacket *avpkt)
209+{
210+ VMIXContext *s = avctx->priv_data;
211+ unsigned offset = 3, q;
212+ int ret;
213+
214+ if (avpkt->size <= 7)
215+ return AVERROR_INVALIDDATA;
216+
217+ if (avpkt->data[0] != 0x01)
218+ return AVERROR_INVALIDDATA;
219+
220+ q = av_clip(99 - av_clip(avpkt->data[1], 0, 99), 0, FF_ARRAY_ELEMS(quality) - 1);
221+ for (int n = 0; n < 64; n++)
222+ s->factors[n] = quant[n] * quality[q];
223+
224+ s->nb_slices = avpkt->data[2];
225+ if (!s->nb_slices || s->nb_slices > (avctx->height + 15) / 16)
226+ return AVERROR_INVALIDDATA;
227+
228+ for (int n = 0; n < s->nb_slices; n++) {
229+ unsigned slice_size;
230+
231+ if (offset + 4 > avpkt->size)
232+ return AVERROR_INVALIDDATA;
233+
234+ slice_size = AV_RL32(avpkt->data + offset);
235+ if (slice_size > avpkt->size)
236+ return AVERROR_INVALIDDATA;
237+
238+ if (avpkt->size - slice_size - 4LL < offset)
239+ return AVERROR_INVALIDDATA;
240+
241+ s->slices[n].dc_size = slice_size;
242+ s->slices[n].dc_ptr = avpkt->data + offset + 4;
243+ offset += slice_size + 4;
244+ }
245+
246+ for (int n = 0; n < s->nb_slices; n++) {
247+ unsigned slice_size;
248+
249+ if (offset + 4 > avpkt->size)
250+ return AVERROR_INVALIDDATA;
251+
252+ slice_size = AV_RL32(avpkt->data + offset);
253+ if (slice_size > avpkt->size)
254+ return AVERROR_INVALIDDATA;
255+
256+ if (avpkt->size - slice_size - 4LL < offset)
257+ return AVERROR_INVALIDDATA;
258+
259+ s->slices[n].ac_size = slice_size;
260+ s->slices[n].ac_ptr = avpkt->data + offset + 4;
261+ offset += slice_size + 4;
262+ }
263+
264+ ret = ff_thread_get_buffer(avctx, frame, 0);
265+ if (ret < 0)
266+ return ret;
267+
268+ avctx->execute2(avctx, decode_slices, frame, NULL, s->nb_slices);
269+
270+ frame->pict_type = AV_PICTURE_TYPE_I;
271+ frame->flags |= AV_FRAME_FLAG_KEY;
272+
273+ *got_frame = 1;
274+
275+ return avpkt->size;
276+}
277+
278+const FFCodec ff_vmix_decoder = {
279+ .p.name = "vmix",
280+ CODEC_LONG_NAME("vMix Video"),
281+ .p.type = AVMEDIA_TYPE_VIDEO,
282+ .p.id = AV_CODEC_ID_VMIX,
283+ .priv_data_size = sizeof(VMIXContext),
284+ .init = decode_init,
285+ FF_CODEC_DECODE_CB(decode_frame),
286+ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS |
287+ AV_CODEC_CAP_SLICE_THREADS,
288+};
libavformat/riff.c+1−0
@@ -502,6 +502,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { · 501 unmodified lines
502502 { AV_CODEC_ID_VQC, MKTAG('V', 'Q', 'C', '1') },
503503 { AV_CODEC_ID_VQC, MKTAG('V', 'Q', 'C', '2') },
504504 { AV_CODEC_ID_RTV1, MKTAG('R', 'T', 'V', '1') },
505+ { AV_CODEC_ID_VMIX, MKTAG('V', 'M', 'X', '1') },
505506 { AV_CODEC_ID_NONE, 0 }
506507 };
507508

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t