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
16- nlmeans_vulkan filter16- nlmeans_vulkan filter
17- RivaTuner video decoder17- RivaTuner video decoder
18- xfade_vulkan filter18- xfade_vulkan filter
19- vMix video decoder
19 20
20version 6.0:21version 6.0:
21- Radiance HDR image support22- Radiance HDR image support
configure+1−0
@@ -3006,6 +3006,7 @@ utvideo_encoder_select="bswapdsp huffman llvidencdsp" · 3005 unmodified lines
3006vble_decoder_select="llviddsp"3006vble_decoder_select="llviddsp"
3007vbn_decoder_select="texturedsp"3007vbn_decoder_select="texturedsp"
3008vbn_encoder_select="texturedspenc"3008vbn_encoder_select="texturedspenc"
3009vmix_decoder_select="idctdsp"
3009vc1_decoder_select="blockdsp h264qpel intrax8 mpegvideodec qpeldsp vc1dsp"3010vc1_decoder_select="blockdsp h264qpel intrax8 mpegvideodec qpeldsp vc1dsp"
3010vc1image_decoder_select="vc1_decoder"3011vc1image_decoder_select="vc1_decoder"
3011vorbis_encoder_select="audio_frame_queue"3012vorbis_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
753OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o753OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o
754OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdaudio.o754OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdaudio.o
755OBJS-$(CONFIG_VMDVIDEO_DECODER) += vmdvideo.o755OBJS-$(CONFIG_VMDVIDEO_DECODER) += vmdvideo.o
756OBJS-$(CONFIG_VMIX_DECODER) += vmixdec.o
756OBJS-$(CONFIG_VMNC_DECODER) += vmnc.o757OBJS-$(CONFIG_VMNC_DECODER) += vmnc.o
757OBJS-$(CONFIG_VNULL_DECODER) += null.o758OBJS-$(CONFIG_VNULL_DECODER) += null.o
758OBJS-$(CONFIG_VNULL_ENCODER) += null.o759OBJS-$(CONFIG_VNULL_ENCODER) += null.o
libavcodec/allcodecs.c+1−0
@@ -370,6 +370,7 @@ extern const FFCodec ff_vc1_v4l2m2m_decoder; · 369 unmodified lines
370extern const FFCodec ff_vc2_encoder;370extern const FFCodec ff_vc2_encoder;
371extern const FFCodec ff_vcr1_decoder;371extern const FFCodec ff_vcr1_decoder;
372extern const FFCodec ff_vmdvideo_decoder;372extern const FFCodec ff_vmdvideo_decoder;
373extern const FFCodec ff_vmix_decoder;
373extern const FFCodec ff_vmnc_decoder;374extern const FFCodec ff_vmnc_decoder;
374extern const FFCodec ff_vp3_decoder;375extern const FFCodec ff_vp3_decoder;
375extern const FFCodec ff_vp4_decoder;376extern const FFCodec ff_vp4_decoder;
libavcodec/codec_desc.c+7−0
@@ -1953,6 +1953,13 @@ static const AVCodecDescriptor codec_descriptors[] = { · 1952 unmodified lines
1953 .long_name = NULL_IF_CONFIG_SMALL("RTV1 (RivaTuner Video)"),1953 .long_name = NULL_IF_CONFIG_SMALL("RTV1 (RivaTuner Video)"),
1954 .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,1954 .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
1955 },1955 },
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 },
1956 1963
1957 /* various PCM "codecs" */1964 /* various PCM "codecs" */
1958 {1965 {
libavcodec/codec_id.h+1−0
@@ -323,6 +323,7 @@ enum AVCodecID { · 322 unmodified lines
323 AV_CODEC_ID_PDV,323 AV_CODEC_ID_PDV,
324 AV_CODEC_ID_EVC,324 AV_CODEC_ID_EVC,
325 AV_CODEC_ID_RTV1,325 AV_CODEC_ID_RTV1,
326 AV_CODEC_ID_VMIX,
326 327
327 /* various PCM "codecs" */328 /* various PCM "codecs" */
328 AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs329 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
29 29
30#include "version_major.h"30#include "version_major.h"
31 31
32#define LIBAVCODEC_VERSION_MINOR 1732#define LIBAVCODEC_VERSION_MINOR 18
33#define LIBAVCODEC_VERSION_MICRO 10033#define LIBAVCODEC_VERSION_MICRO 100
34 34
35#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \35#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
39typedef 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
46typedef 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
57static 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
62static 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
73static 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
89static 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
96static 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
150static 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
192static 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
206static 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
278const 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
502 { AV_CODEC_ID_VQC, MKTAG('V', 'Q', 'C', '1') },502 { AV_CODEC_ID_VQC, MKTAG('V', 'Q', 'C', '1') },
503 { AV_CODEC_ID_VQC, MKTAG('V', 'Q', 'C', '2') },503 { AV_CODEC_ID_VQC, MKTAG('V', 'Q', 'C', '2') },
504 { AV_CODEC_ID_RTV1, MKTAG('R', 'T', 'V', '1') },504 { AV_CODEC_ID_RTV1, MKTAG('R', 'T', 'V', '1') },
505 { AV_CODEC_ID_VMIX, MKTAG('V', 'M', 'X', '1') },
505 { AV_CODEC_ID_NONE, 0 }506 { AV_CODEC_ID_NONE, 0 }
506};507};
507 508

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