* [FFmpeg-devel] [PATCH] avcodec: add VMX1 decoder
@ 2023-06-08 17:39 Paul B Mahol
2023-06-09 5:56 ` Jean-Baptiste Kempf
2023-06-10 10:24 ` Andreas Rheinhardt
0 siblings, 2 replies; 5+ messages in thread
From: Paul B Mahol @ 2023-06-08 17:39 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1: Type: text/plain, Size: 10 bytes --]
Attached.
[-- Attachment #2: 0001-avcodec-add-VMX1-decoder.patch --]
[-- Type: text/x-patch, Size: 12009 bytes --]
From 2e0bbbc73afeac43e8cb7e2d5c78647725c764ba Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda@gmail.com>
Date: Sun, 4 Jun 2023 20:30:59 +0200
Subject: [PATCH] avcodec: add VMX1 decoder
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
libavcodec/Makefile | 1 +
libavcodec/allcodecs.c | 1 +
libavcodec/codec_desc.c | 7 +
libavcodec/codec_id.h | 1 +
libavcodec/vmixdec.c | 288 ++++++++++++++++++++++++++++++++++++++++
libavformat/riff.c | 1 +
6 files changed, 299 insertions(+)
create mode 100644 libavcodec/vmixdec.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 87a8b90037..2efab60d7d 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -753,6 +753,7 @@ OBJS-$(CONFIG_VC2_ENCODER) += vc2enc.o vc2enc_dwt.o diractab.o
OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o
OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdaudio.o
OBJS-$(CONFIG_VMDVIDEO_DECODER) += vmdvideo.o
+OBJS-$(CONFIG_VMIX_DECODER) += vmixdec.o
OBJS-$(CONFIG_VMNC_DECODER) += vmnc.o
OBJS-$(CONFIG_VNULL_DECODER) += null.o
OBJS-$(CONFIG_VNULL_ENCODER) += null.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index a98c300da4..11c136ef59 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -370,6 +370,7 @@ extern const FFCodec ff_vc1_v4l2m2m_decoder;
extern const FFCodec ff_vc2_encoder;
extern const FFCodec ff_vcr1_decoder;
extern const FFCodec ff_vmdvideo_decoder;
+extern const FFCodec ff_vmix_decoder;
extern const FFCodec ff_vmnc_decoder;
extern const FFCodec ff_vp3_decoder;
extern const FFCodec ff_vp4_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 41293a78dc..3e31a1eed6 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1953,6 +1953,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("RTV1 (RivaTuner Video)"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
},
+ {
+ .id = AV_CODEC_ID_VMIX,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "vmix",
+ .long_name = NULL_IF_CONFIG_SMALL("vMix Video"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ },
/* various PCM "codecs" */
{
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index 9a78cfabe2..d23549d7e0 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -323,6 +323,7 @@ enum AVCodecID {
AV_CODEC_ID_PDV,
AV_CODEC_ID_EVC,
AV_CODEC_ID_RTV1,
+ AV_CODEC_ID_VMIX,
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/vmixdec.c b/libavcodec/vmixdec.c
new file mode 100644
index 0000000000..a9cb704964
--- /dev/null
+++ b/libavcodec/vmixdec.c
@@ -0,0 +1,288 @@
+/*
+ * vMix decoder
+ * Copyright (c) 2023 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mem_internal.h"
+
+#include "avcodec.h"
+#include "codec_internal.h"
+#include "decode.h"
+#define CACHED_BITSTREAM_READER !ARCH_X86_32
+#include "golomb.h"
+#include "get_bits.h"
+#include "idctdsp.h"
+#include "thread.h"
+
+typedef struct SliceContext {
+ const uint8_t *dc_ptr;
+ const uint8_t *ac_ptr;
+ unsigned dc_size;
+ unsigned ac_size;
+} SliceContext;
+
+typedef struct VMIXContext {
+ int nb_slices;
+
+ int16_t factors[64];
+ uint8_t scan[64];
+
+ SliceContext slices[255];
+
+ IDCTDSPContext idsp;
+} VMIXContext;
+
+static const uint8_t quality[25] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16,
+ 18, 20, 22, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64,
+};
+
+static const uint8_t quant[64] = {
+ 16, 16, 19, 22, 22, 26, 26, 27,
+ 16, 16, 22, 22, 26, 27, 27, 29,
+ 19, 22, 26, 26, 27, 29, 29, 35,
+ 22, 24, 27, 27, 29, 32, 34, 38,
+ 26, 27, 29, 29, 32, 35, 38, 46,
+ 27, 29, 34, 34, 35, 40, 46, 56,
+ 29, 34, 34, 37, 40, 48, 56, 69,
+ 34, 37, 38, 40, 48, 58, 69, 83,
+};
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ VMIXContext *s = avctx->priv_data;
+
+ avctx->bits_per_raw_sample = 8;
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+
+ avctx->coded_width = FFALIGN(avctx->width, 16);
+ avctx->coded_height = FFALIGN(avctx->height, 16);
+
+ ff_idctdsp_init(&s->idsp, avctx);
+ ff_permute_scantable(s->scan, ff_zigzag_direct,
+ s->idsp.idct_permutation);
+ return 0;
+}
+
+static inline int get_se_golomb_vmix(GetBitContext *gb)
+{
+ unsigned int buf = get_ue_golomb_long(gb);
+ int sign = (buf & 1) - 1;
+ return ((buf >> 1) ^ (~sign));
+}
+
+static int decode_dcac(AVCodecContext *avctx,
+ GetBitContext *dc_gb, GetBitContext *ac_gb,
+ unsigned *dcrun, unsigned *acrun,
+ AVFrame *frame, int width, int by, int plane)
+{
+ const ptrdiff_t linesize = frame->linesize[plane];
+ uint8_t *dst = frame->data[plane] + by * linesize;
+ unsigned dc_run = *dcrun, ac_run = *acrun;
+ LOCAL_ALIGNED_32(int16_t, block, [64]);
+ VMIXContext *s = avctx->priv_data;
+ const int16_t *factors = s->factors;
+ const uint8_t *scan = s->scan;
+ const int add = plane ? 0 : 1024;
+ int i, dc_v = 0, ac_v = 0, dc = 0;
+
+ for (int y = 0; y < 2; y++) {
+ for (int x = 0; x < width; x += 8) {
+ memset(block, 0, sizeof(*block)*64);
+
+ if (dc_run > 0) {
+ dc_run--;
+ } else {
+ dc_v = get_se_golomb_vmix(dc_gb);
+ dc += dc_v;
+ if (!dc_v)
+ dc_run = get_ue_golomb_long(dc_gb);
+ }
+
+ for (int n = 0; n < 64; n++) {
+ if (ac_run > 0) {
+ ac_run--;
+ continue;
+ }
+
+ ac_v = get_se_golomb_vmix(ac_gb);
+ i = scan[n];
+ block[i] = (ac_v * factors[i]) >> 4;
+ if (!ac_v)
+ ac_run = get_ue_golomb_long(ac_gb);
+ }
+
+ block[0] = ((dc + add) * 16) >> 4;
+ s->idsp.idct_put(dst + x, linesize, block);
+ }
+
+ dst += 8 * linesize;
+ }
+
+ *dcrun = dc_run;
+ *acrun = ac_run;
+
+ return 0;
+}
+
+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)
+{
+ unsigned dc_run = 0, ac_run = 0;
+ GetBitContext dc_gb, ac_gb;
+ int ret;
+
+ ret = init_get_bits8(&dc_gb, dc_src, dc_slice_size);
+ if (ret < 0)
+ return ret;
+
+ ret = init_get_bits8(&ac_gb, ac_src, ac_slice_size);
+ if (ret < 0)
+ return ret;
+
+ for (int p = 0; p < 3; p++) {
+ const int rshift = !!p;
+ ret = decode_dcac(avctx, &dc_gb, &ac_gb,
+ &dc_run, &ac_run, frame,
+ frame->width >> rshift, by, p);
+ if (ret < 0)
+ return ret;
+
+ if (get_bits_left(&dc_gb) < 0)
+ return AVERROR_INVALIDDATA;
+ if (get_bits_left(&ac_gb) < 0)
+ return AVERROR_INVALIDDATA;
+
+ align_get_bits(&dc_gb);
+ align_get_bits(&ac_gb);
+ }
+
+ if (get_bits_left(&dc_gb) > 0)
+ return AVERROR_INVALIDDATA;
+ if (get_bits_left(&ac_gb) > 0)
+ return AVERROR_INVALIDDATA;
+
+ return 0;
+}
+
+static int decode_slices(AVCodecContext *avctx, void *arg,
+ int n, int thread_nb)
+{
+ VMIXContext *s = avctx->priv_data;
+ const uint8_t *dc_slice_ptr = s->slices[n].dc_ptr;
+ const uint8_t *ac_slice_ptr = s->slices[n].ac_ptr;
+ unsigned dc_slice_size = s->slices[n].dc_size;
+ unsigned ac_slice_size = s->slices[n].ac_size;
+ AVFrame *frame = arg;
+
+ return decode_slice(avctx, frame, dc_slice_ptr, dc_slice_size,
+ ac_slice_ptr, ac_slice_size, n * 16);
+}
+
+static int decode_frame(AVCodecContext *avctx,
+ AVFrame *frame, int *got_frame,
+ AVPacket *avpkt)
+{
+ VMIXContext *s = avctx->priv_data;
+ unsigned offset = 3, q;
+ int ret;
+
+ if (avpkt->size <= 7)
+ return AVERROR_INVALIDDATA;
+
+ if (avpkt->data[0] != 0x01)
+ return AVERROR_INVALIDDATA;
+
+ q = av_clip(99 - av_clip(avpkt->data[1], 0, 99), 0, FF_ARRAY_ELEMS(quality) - 1);
+ for (int n = 0; n < 64; n++)
+ s->factors[n] = quant[n] * quality[q];
+
+ s->nb_slices = avpkt->data[2];
+ if (!s->nb_slices || s->nb_slices > (avctx->height + 15) / 16)
+ return AVERROR_INVALIDDATA;
+
+ ret = ff_thread_get_buffer(avctx, frame, 0);
+ if (ret < 0)
+ return ret;
+
+ for (int n = 0; n < s->nb_slices; n++) {
+ unsigned slice_size;
+
+ if (offset + 4 > avpkt->size)
+ return AVERROR_INVALIDDATA;
+
+ slice_size = AV_RL32(avpkt->data + offset);
+ if (slice_size > avpkt->size)
+ return AVERROR_INVALIDDATA;
+
+ if (avpkt->size - slice_size - 4LL < offset)
+ return AVERROR_INVALIDDATA;
+
+ s->slices[n].dc_size = slice_size;
+ s->slices[n].dc_ptr = avpkt->data + offset + 4;
+ offset += slice_size + 4;
+ }
+
+ for (int n = 0; n < s->nb_slices; n++) {
+ unsigned slice_size;
+
+ if (offset + 4 > avpkt->size)
+ return AVERROR_INVALIDDATA;
+
+ slice_size = AV_RL32(avpkt->data + offset);
+ if (slice_size > avpkt->size)
+ return AVERROR_INVALIDDATA;
+
+ if (avpkt->size - slice_size - 4LL < offset)
+ return AVERROR_INVALIDDATA;
+
+ s->slices[n].ac_size = slice_size;
+ s->slices[n].ac_ptr = avpkt->data + offset + 4;
+ offset += slice_size + 4;
+ }
+
+ avctx->execute2(avctx, decode_slices, frame, NULL, s->nb_slices);
+
+ frame->pict_type = AV_PICTURE_TYPE_I;
+ frame->flags |= AV_FRAME_FLAG_KEY;
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+const FFCodec ff_vmix_decoder = {
+ .p.name = "vmix",
+ CODEC_LONG_NAME("vMix Video"),
+ .p.type = AVMEDIA_TYPE_VIDEO,
+ .p.id = AV_CODEC_ID_VMIX,
+ .priv_data_size = sizeof(VMIXContext),
+ .init = decode_init,
+ FF_CODEC_DECODE_CB(decode_frame),
+ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS |
+ AV_CODEC_CAP_SLICE_THREADS,
+};
diff --git a/libavformat/riff.c b/libavformat/riff.c
index 4279071159..97708df6e3 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -502,6 +502,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_VQC, MKTAG('V', 'Q', 'C', '1') },
{ AV_CODEC_ID_VQC, MKTAG('V', 'Q', 'C', '2') },
{ AV_CODEC_ID_RTV1, MKTAG('R', 'T', 'V', '1') },
+ { AV_CODEC_ID_VMIX, MKTAG('V', 'M', 'X', '1') },
{ AV_CODEC_ID_NONE, 0 }
};
--
2.39.1
[-- Attachment #3: Type: text/plain, Size: 251 bytes --]
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avcodec: add VMX1 decoder
2023-06-08 17:39 [FFmpeg-devel] [PATCH] avcodec: add VMX1 decoder Paul B Mahol
@ 2023-06-09 5:56 ` Jean-Baptiste Kempf
2023-06-09 9:20 ` Paul B Mahol
2023-06-10 10:24 ` Andreas Rheinhardt
1 sibling, 1 reply; 5+ messages in thread
From: Jean-Baptiste Kempf @ 2023-06-09 5:56 UTC (permalink / raw)
To: ffmpeg-devel
On Thu, 8 Jun 2023, at 19:39, Paul B Mahol wrote:
> Attached.
Missing version bumping?
--
Jean-Baptiste Kempf - President
+33 672 704 734
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avcodec: add VMX1 decoder
2023-06-09 5:56 ` Jean-Baptiste Kempf
@ 2023-06-09 9:20 ` Paul B Mahol
0 siblings, 0 replies; 5+ messages in thread
From: Paul B Mahol @ 2023-06-09 9:20 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Fri, Jun 9, 2023 at 7:57 AM Jean-Baptiste Kempf <jb@videolan.org> wrote:
> On Thu, 8 Jun 2023, at 19:39, Paul B Mahol wrote:
> > Attached.
>
> Missing version bumping?
>
That is done when committing.
To prevent potential need for rebase if in meantime someone changes version.
> --
> Jean-Baptiste Kempf - President
> +33 672 704 734
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avcodec: add VMX1 decoder
2023-06-08 17:39 [FFmpeg-devel] [PATCH] avcodec: add VMX1 decoder Paul B Mahol
2023-06-09 5:56 ` Jean-Baptiste Kempf
@ 2023-06-10 10:24 ` Andreas Rheinhardt
2023-06-12 15:39 ` Paul B Mahol
1 sibling, 1 reply; 5+ messages in thread
From: Andreas Rheinhardt @ 2023-06-10 10:24 UTC (permalink / raw)
To: ffmpeg-devel
Paul B Mahol:
> +static av_cold int decode_init(AVCodecContext *avctx)
> +{
> + VMIXContext *s = avctx->priv_data;
> +
> + avctx->bits_per_raw_sample = 8;
> + avctx->pix_fmt = AV_PIX_FMT_YUV422P;
> +
> + avctx->coded_width = FFALIGN(avctx->width, 16);
> + avctx->coded_height = FFALIGN(avctx->height, 16);
> +
> + ff_idctdsp_init(&s->idsp, avctx);
Missing idctdsp configure dependency.
> + ff_permute_scantable(s->scan, ff_zigzag_direct,
> + s->idsp.idct_permutation);
> + return 0;
> +}
> +
> +static inline int get_se_golomb_vmix(GetBitContext *gb)
> +{
> + unsigned int buf = get_ue_golomb_long(gb);
> + int sign = (buf & 1) - 1;
> + return ((buf >> 1) ^ (~sign));
> +}
> +
> +static int decode_dcac(AVCodecContext *avctx,
> + GetBitContext *dc_gb, GetBitContext *ac_gb,
> + unsigned *dcrun, unsigned *acrun,
> + AVFrame *frame, int width, int by, int plane)
> +{
> + const ptrdiff_t linesize = frame->linesize[plane];
> + uint8_t *dst = frame->data[plane] + by * linesize;
> + unsigned dc_run = *dcrun, ac_run = *acrun;
> + LOCAL_ALIGNED_32(int16_t, block, [64]);
> + VMIXContext *s = avctx->priv_data;
> + const int16_t *factors = s->factors;
> + const uint8_t *scan = s->scan;
> + const int add = plane ? 0 : 1024;
> + int i, dc_v = 0, ac_v = 0, dc = 0;
> +
> + for (int y = 0; y < 2; y++) {
> + for (int x = 0; x < width; x += 8) {
> + memset(block, 0, sizeof(*block)*64);
> +
> + if (dc_run > 0) {
> + dc_run--;
> + } else {
> + dc_v = get_se_golomb_vmix(dc_gb);
> + dc += dc_v;
> + if (!dc_v)
> + dc_run = get_ue_golomb_long(dc_gb);
> + }
> +
> + for (int n = 0; n < 64; n++) {
> + if (ac_run > 0) {
> + ac_run--;
> + continue;
> + }
> +
> + ac_v = get_se_golomb_vmix(ac_gb);
> + i = scan[n];
> + block[i] = (ac_v * factors[i]) >> 4;
> + if (!ac_v)
> + ac_run = get_ue_golomb_long(ac_gb);
> + }
> +
> + block[0] = ((dc + add) * 16) >> 4;
> + s->idsp.idct_put(dst + x, linesize, block);
> + }
> +
> + dst += 8 * linesize;
> + }
> +
> + *dcrun = dc_run;
> + *acrun = ac_run;
> +
> + return 0;
> +}
> +
> +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)
> +{
> + unsigned dc_run = 0, ac_run = 0;
> + GetBitContext dc_gb, ac_gb;
> + int ret;
> +
> + ret = init_get_bits8(&dc_gb, dc_src, dc_slice_size);
> + if (ret < 0)
> + return ret;
> +
> + ret = init_get_bits8(&ac_gb, ac_src, ac_slice_size);
> + if (ret < 0)
> + return ret;
> +
> + for (int p = 0; p < 3; p++) {
> + const int rshift = !!p;
> + ret = decode_dcac(avctx, &dc_gb, &ac_gb,
> + &dc_run, &ac_run, frame,
> + frame->width >> rshift, by, p);
> + if (ret < 0)
> + return ret;
> +
> + if (get_bits_left(&dc_gb) < 0)
> + return AVERROR_INVALIDDATA;
> + if (get_bits_left(&ac_gb) < 0)
> + return AVERROR_INVALIDDATA;
> +
> + align_get_bits(&dc_gb);
> + align_get_bits(&ac_gb);
> + }
> +
> + if (get_bits_left(&dc_gb) > 0)
> + return AVERROR_INVALIDDATA;
> + if (get_bits_left(&ac_gb) > 0)
> + return AVERROR_INVALIDDATA;
> +
> + return 0;
> +}
> +
> +static int decode_slices(AVCodecContext *avctx, void *arg,
> + int n, int thread_nb)
> +{
> + VMIXContext *s = avctx->priv_data;
> + const uint8_t *dc_slice_ptr = s->slices[n].dc_ptr;
> + const uint8_t *ac_slice_ptr = s->slices[n].ac_ptr;
> + unsigned dc_slice_size = s->slices[n].dc_size;
> + unsigned ac_slice_size = s->slices[n].ac_size;
> + AVFrame *frame = arg;
> +
> + return decode_slice(avctx, frame, dc_slice_ptr, dc_slice_size,
> + ac_slice_ptr, ac_slice_size, n * 16);
> +}
> +
> +static int decode_frame(AVCodecContext *avctx,
> + AVFrame *frame, int *got_frame,
> + AVPacket *avpkt)
> +{
> + VMIXContext *s = avctx->priv_data;
> + unsigned offset = 3, q;
> + int ret;
> +
> + if (avpkt->size <= 7)
> + return AVERROR_INVALIDDATA;
> +
> + if (avpkt->data[0] != 0x01)
> + return AVERROR_INVALIDDATA;
> +
> + q = av_clip(99 - av_clip(avpkt->data[1], 0, 99), 0, FF_ARRAY_ELEMS(quality) - 1);
The inner av_clip() is redundant.
> + for (int n = 0; n < 64; n++)
> + s->factors[n] = quant[n] * quality[q];
> +
> + s->nb_slices = avpkt->data[2];
> + if (!s->nb_slices || s->nb_slices > (avctx->height + 15) / 16)
> + return AVERROR_INVALIDDATA;
> +
> + ret = ff_thread_get_buffer(avctx, frame, 0);
This should be moved after the loops below in order to avoid an
allocation in case of invalid input.
> + if (ret < 0)
> + return ret;
> +
> + for (int n = 0; n < s->nb_slices; n++) {
> + unsigned slice_size;
> +
> + if (offset + 4 > avpkt->size)
> + return AVERROR_INVALIDDATA;
> +
> + slice_size = AV_RL32(avpkt->data + offset);
> + if (slice_size > avpkt->size)
> + return AVERROR_INVALIDDATA;
> +
> + if (avpkt->size - slice_size - 4LL < offset)
> + return AVERROR_INVALIDDATA;
> +
> + s->slices[n].dc_size = slice_size;
> + s->slices[n].dc_ptr = avpkt->data + offset + 4;
> + offset += slice_size + 4;
> + }
> +
> + for (int n = 0; n < s->nb_slices; n++) {
> + unsigned slice_size;
> +
> + if (offset + 4 > avpkt->size)
> + return AVERROR_INVALIDDATA;
> +
> + slice_size = AV_RL32(avpkt->data + offset);
> + if (slice_size > avpkt->size)
> + return AVERROR_INVALIDDATA;
> +
> + if (avpkt->size - slice_size - 4LL < offset)
> + return AVERROR_INVALIDDATA;
> +
> + s->slices[n].ac_size = slice_size;
> + s->slices[n].ac_ptr = avpkt->data + offset + 4;
> + offset += slice_size + 4;
> + }
These loops could be combined if you modified the way you stored the
data by putting the dc information into slices[n] and the corresponding
ac information into slices[n + nb_slices]. In this case, you would need
to unpack this in decode_slices.
If you don't do this, then there is no need to put nb_slices in the
context. It can be local to this function.
> +
> + avctx->execute2(avctx, decode_slices, frame, NULL, s->nb_slices);
> +
> + frame->pict_type = AV_PICTURE_TYPE_I;
> + frame->flags |= AV_FRAME_FLAG_KEY;
> +
> + *got_frame = 1;
> +
> + return avpkt->size;
> +}
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avcodec: add VMX1 decoder
2023-06-10 10:24 ` Andreas Rheinhardt
@ 2023-06-12 15:39 ` Paul B Mahol
0 siblings, 0 replies; 5+ messages in thread
From: Paul B Mahol @ 2023-06-12 15:39 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Sat, Jun 10, 2023 at 12:24 PM Andreas Rheinhardt <
andreas.rheinhardt@outlook.com> wrote:
> Paul B Mahol:
> > +static av_cold int decode_init(AVCodecContext *avctx)
> > +{
> > + VMIXContext *s = avctx->priv_data;
> > +
> > + avctx->bits_per_raw_sample = 8;
> > + avctx->pix_fmt = AV_PIX_FMT_YUV422P;
> > +
> > + avctx->coded_width = FFALIGN(avctx->width, 16);
> > + avctx->coded_height = FFALIGN(avctx->height, 16);
> > +
> > + ff_idctdsp_init(&s->idsp, avctx);
>
> Missing idctdsp configure dependency.
>
Added.
>
> > + ff_permute_scantable(s->scan, ff_zigzag_direct,
> > + s->idsp.idct_permutation);
> > + return 0;
> > +}
> > +
> > +static inline int get_se_golomb_vmix(GetBitContext *gb)
> > +{
> > + unsigned int buf = get_ue_golomb_long(gb);
> > + int sign = (buf & 1) - 1;
> > + return ((buf >> 1) ^ (~sign));
> > +}
> > +
> > +static int decode_dcac(AVCodecContext *avctx,
> > + GetBitContext *dc_gb, GetBitContext *ac_gb,
> > + unsigned *dcrun, unsigned *acrun,
> > + AVFrame *frame, int width, int by, int plane)
> > +{
> > + const ptrdiff_t linesize = frame->linesize[plane];
> > + uint8_t *dst = frame->data[plane] + by * linesize;
> > + unsigned dc_run = *dcrun, ac_run = *acrun;
> > + LOCAL_ALIGNED_32(int16_t, block, [64]);
> > + VMIXContext *s = avctx->priv_data;
> > + const int16_t *factors = s->factors;
> > + const uint8_t *scan = s->scan;
> > + const int add = plane ? 0 : 1024;
> > + int i, dc_v = 0, ac_v = 0, dc = 0;
> > +
> > + for (int y = 0; y < 2; y++) {
> > + for (int x = 0; x < width; x += 8) {
> > + memset(block, 0, sizeof(*block)*64);
> > +
> > + if (dc_run > 0) {
> > + dc_run--;
> > + } else {
> > + dc_v = get_se_golomb_vmix(dc_gb);
> > + dc += dc_v;
> > + if (!dc_v)
> > + dc_run = get_ue_golomb_long(dc_gb);
> > + }
> > +
> > + for (int n = 0; n < 64; n++) {
> > + if (ac_run > 0) {
> > + ac_run--;
> > + continue;
> > + }
> > +
> > + ac_v = get_se_golomb_vmix(ac_gb);
> > + i = scan[n];
> > + block[i] = (ac_v * factors[i]) >> 4;
> > + if (!ac_v)
> > + ac_run = get_ue_golomb_long(ac_gb);
> > + }
> > +
> > + block[0] = ((dc + add) * 16) >> 4;
> > + s->idsp.idct_put(dst + x, linesize, block);
> > + }
> > +
> > + dst += 8 * linesize;
> > + }
> > +
> > + *dcrun = dc_run;
> > + *acrun = ac_run;
> > +
> > + return 0;
> > +}
> > +
> > +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)
> > +{
> > + unsigned dc_run = 0, ac_run = 0;
> > + GetBitContext dc_gb, ac_gb;
> > + int ret;
> > +
> > + ret = init_get_bits8(&dc_gb, dc_src, dc_slice_size);
> > + if (ret < 0)
> > + return ret;
> > +
> > + ret = init_get_bits8(&ac_gb, ac_src, ac_slice_size);
> > + if (ret < 0)
> > + return ret;
> > +
> > + for (int p = 0; p < 3; p++) {
> > + const int rshift = !!p;
> > + ret = decode_dcac(avctx, &dc_gb, &ac_gb,
> > + &dc_run, &ac_run, frame,
> > + frame->width >> rshift, by, p);
> > + if (ret < 0)
> > + return ret;
> > +
> > + if (get_bits_left(&dc_gb) < 0)
> > + return AVERROR_INVALIDDATA;
> > + if (get_bits_left(&ac_gb) < 0)
> > + return AVERROR_INVALIDDATA;
> > +
> > + align_get_bits(&dc_gb);
> > + align_get_bits(&ac_gb);
> > + }
> > +
> > + if (get_bits_left(&dc_gb) > 0)
> > + return AVERROR_INVALIDDATA;
> > + if (get_bits_left(&ac_gb) > 0)
> > + return AVERROR_INVALIDDATA;
> > +
> > + return 0;
> > +}
> > +
> > +static int decode_slices(AVCodecContext *avctx, void *arg,
> > + int n, int thread_nb)
> > +{
> > + VMIXContext *s = avctx->priv_data;
> > + const uint8_t *dc_slice_ptr = s->slices[n].dc_ptr;
> > + const uint8_t *ac_slice_ptr = s->slices[n].ac_ptr;
> > + unsigned dc_slice_size = s->slices[n].dc_size;
> > + unsigned ac_slice_size = s->slices[n].ac_size;
> > + AVFrame *frame = arg;
> > +
> > + return decode_slice(avctx, frame, dc_slice_ptr, dc_slice_size,
> > + ac_slice_ptr, ac_slice_size, n * 16);
> > +}
> > +
> > +static int decode_frame(AVCodecContext *avctx,
> > + AVFrame *frame, int *got_frame,
> > + AVPacket *avpkt)
> > +{
> > + VMIXContext *s = avctx->priv_data;
> > + unsigned offset = 3, q;
> > + int ret;
> > +
> > + if (avpkt->size <= 7)
> > + return AVERROR_INVALIDDATA;
> > +
> > + if (avpkt->data[0] != 0x01)
> > + return AVERROR_INVALIDDATA;
> > +
> > + q = av_clip(99 - av_clip(avpkt->data[1], 0, 99), 0,
> FF_ARRAY_ELEMS(quality) - 1);
>
> The inner av_clip() is redundant.
>
That is not very critical.
>
> > + for (int n = 0; n < 64; n++)
> > + s->factors[n] = quant[n] * quality[q];
> > +
> > + s->nb_slices = avpkt->data[2];
> > + if (!s->nb_slices || s->nb_slices > (avctx->height + 15) / 16)
> > + return AVERROR_INVALIDDATA;
> > +
> > + ret = ff_thread_get_buffer(avctx, frame, 0);
>
> This should be moved after the loops below in order to avoid an
> allocation in case of invalid input.
>
Moved.
>
> > + if (ret < 0)
> > + return ret;
> > +
> > + for (int n = 0; n < s->nb_slices; n++) {
> > + unsigned slice_size;
> > +
> > + if (offset + 4 > avpkt->size)
> > + return AVERROR_INVALIDDATA;
> > +
> > + slice_size = AV_RL32(avpkt->data + offset);
> > + if (slice_size > avpkt->size)
> > + return AVERROR_INVALIDDATA;
> > +
> > + if (avpkt->size - slice_size - 4LL < offset)
> > + return AVERROR_INVALIDDATA;
> > +
> > + s->slices[n].dc_size = slice_size;
> > + s->slices[n].dc_ptr = avpkt->data + offset + 4;
> > + offset += slice_size + 4;
> > + }
> > +
> > + for (int n = 0; n < s->nb_slices; n++) {
> > + unsigned slice_size;
> > +
> > + if (offset + 4 > avpkt->size)
> > + return AVERROR_INVALIDDATA;
> > +
> > + slice_size = AV_RL32(avpkt->data + offset);
> > + if (slice_size > avpkt->size)
> > + return AVERROR_INVALIDDATA;
> > +
> > + if (avpkt->size - slice_size - 4LL < offset)
> > + return AVERROR_INVALIDDATA;
> > +
> > + s->slices[n].ac_size = slice_size;
> > + s->slices[n].ac_ptr = avpkt->data + offset + 4;
> > + offset += slice_size + 4;
> > + }
>
> These loops could be combined if you modified the way you stored the
> data by putting the dc information into slices[n] and the corresponding
> ac information into slices[n + nb_slices]. In this case, you would need
> to unpack this in decode_slices.
> If you don't do this, then there is no need to put nb_slices in the
> context. It can be local to this function.
>
Not very critical.
>
> > +
> > + avctx->execute2(avctx, decode_slices, frame, NULL, s->nb_slices);
> > +
> > + frame->pict_type = AV_PICTURE_TYPE_I;
> > + frame->flags |= AV_FRAME_FLAG_KEY;
> > +
> > + *got_frame = 1;
> > +
> > + return avpkt->size;
> > +}
>
>
Will apply with local changes soon.
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-06-12 15:40 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-08 17:39 [FFmpeg-devel] [PATCH] avcodec: add VMX1 decoder Paul B Mahol
2023-06-09 5:56 ` Jean-Baptiste Kempf
2023-06-09 9:20 ` Paul B Mahol
2023-06-10 10:24 ` Andreas Rheinhardt
2023-06-12 15:39 ` Paul B Mahol
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git