* [FFmpeg-devel] [PATCH 1/7] avcodec/svq3: Factor out decoding extradata
@ 2025-05-15 4:07 Andreas Rheinhardt
2025-05-18 14:19 ` Andreas Rheinhardt
0 siblings, 1 reply; 2+ messages in thread
From: Andreas Rheinhardt @ 2025-05-15 4:07 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1: Type: text/plain, Size: 29 bytes --]
Patches attached.
- Andreas
[-- Attachment #2: 0001-avcodec-svq3-Factor-out-decoding-extradata.patch --]
[-- Type: text/x-patch, Size: 9779 bytes --]
From 19d9f3cfc278a2b442923f1bea505ffb079fe3c1 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 15 May 2025 03:09:45 +0200
Subject: [PATCH 1/7] avcodec/svq3: Factor out decoding extradata
Reduces indentation and avoids an extra variable for whether
a sequence header has been found.
It also fixes potential undefined behaviour:
NULL + 0 is undefined and happens when no extradata is available.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/svq3.c | 259 +++++++++++++++++++++++-----------------------
1 file changed, 132 insertions(+), 127 deletions(-)
diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c
index 6319e9b021..f264140dbc 100644
--- a/libavcodec/svq3.c
+++ b/libavcodec/svq3.c
@@ -1114,14 +1114,139 @@ static void init_dequant4_coeff_table(SVQ3Context *s)
}
}
+static av_cold int svq3_decode_extradata(AVCodecContext *avctx, SVQ3Context *s,
+ int seqh_offset)
+{
+ const uint8_t *extradata = avctx->extradata + seqh_offset;
+ unsigned int size = AV_RB32(extradata + 4);
+ GetBitContext gb;
+ int ret;
+
+ if (size > avctx->extradata_size - seqh_offset - 8)
+ return AVERROR_INVALIDDATA;
+ extradata += 8;
+ init_get_bits(&gb, extradata, size * 8);
+
+ /* 'frame size code' and optional 'width, height' */
+ int frame_size_code = get_bits(&gb, 3);
+ int w, h;
+ switch (frame_size_code) {
+ case 0:
+ w = 160;
+ h = 120;
+ break;
+ case 1:
+ w = 128;
+ h = 96;
+ break;
+ case 2:
+ w = 176;
+ h = 144;
+ break;
+ case 3:
+ w = 352;
+ h = 288;
+ break;
+ case 4:
+ w = 704;
+ h = 576;
+ break;
+ case 5:
+ w = 240;
+ h = 180;
+ break;
+ case 6:
+ w = 320;
+ h = 240;
+ break;
+ case 7:
+ w = get_bits(&gb, 12);
+ h = get_bits(&gb, 12);
+ break;
+ }
+ ret = ff_set_dimensions(avctx, w, h);
+ if (ret < 0)
+ return ret;
+
+ s->halfpel_flag = get_bits1(&gb);
+ s->thirdpel_flag = get_bits1(&gb);
+
+ /* unknown fields */
+ int unk0 = get_bits1(&gb);
+ int unk1 = get_bits1(&gb);
+ int unk2 = get_bits1(&gb);
+ int unk3 = get_bits1(&gb);
+
+ s->low_delay = get_bits1(&gb);
+ avctx->has_b_frames = !s->low_delay;
+
+ /* unknown field */
+ int unk4 = get_bits1(&gb);
+
+ av_log(avctx, AV_LOG_DEBUG, "Unknown fields %d %d %d %d %d\n",
+ unk0, unk1, unk2, unk3, unk4);
+
+ if (skip_1stop_8data_bits(&gb) < 0)
+ return AVERROR_INVALIDDATA;
+
+ s->has_watermark = get_bits1(&gb);
+
+ if (!s->has_watermark)
+ return 0;
+
+#if CONFIG_ZLIB
+ unsigned watermark_width = get_interleaved_ue_golomb(&gb);
+ unsigned watermark_height = get_interleaved_ue_golomb(&gb);
+ int u1 = get_interleaved_ue_golomb(&gb);
+ int u2 = get_bits(&gb, 8);
+ int u3 = get_bits(&gb, 2);
+ int u4 = get_interleaved_ue_golomb(&gb);
+ unsigned long buf_len = watermark_width *
+ watermark_height * 4;
+ int offset = get_bits_count(&gb) + 7 >> 3;
+
+ if (watermark_height <= 0 ||
+ get_bits_left(&gb) <= 0 ||
+ (uint64_t)watermark_width * 4 > UINT_MAX / watermark_height)
+ return AVERROR_INVALIDDATA;
+
+ av_log(avctx, AV_LOG_DEBUG, "watermark size: %ux%u\n",
+ watermark_width, watermark_height);
+ av_log(avctx, AV_LOG_DEBUG,
+ "u1: %x u2: %x u3: %x compressed data size: %d offset: %d\n",
+ u1, u2, u3, u4, offset);
+
+ uint8_t *buf = av_malloc(buf_len);
+ if (!buf)
+ return AVERROR(ENOMEM);
+
+ if (uncompress(buf, &buf_len, extradata + offset,
+ size - offset) != Z_OK) {
+ av_log(avctx, AV_LOG_ERROR,
+ "could not uncompress watermark logo\n");
+ av_free(buf);
+ return -1;
+ }
+ s->watermark_key = av_bswap16(av_crc(av_crc_get_table(AV_CRC_16_CCITT), 0, buf, buf_len));
+
+ s->watermark_key = s->watermark_key << 16 | s->watermark_key;
+ av_log(avctx, AV_LOG_DEBUG,
+ "watermark key %#"PRIx32"\n", s->watermark_key);
+ av_free(buf);
+
+ return 0;
+#else
+ av_log(avctx, AV_LOG_ERROR,
+ "this svq3 file contains watermark which need zlib support compiled in\n");
+ return AVERROR(ENOSYS);
+#endif
+}
+
static av_cold int svq3_decode_init(AVCodecContext *avctx)
{
SVQ3Context *s = avctx->priv_data;
int m, x, y;
unsigned char *extradata;
- unsigned char *extradata_end;
- unsigned int size;
- int marker_found = 0;
int ret;
s->cur_pic = &s->frames[0];
@@ -1154,139 +1279,19 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
/* prowl for the "SEQH" marker in the extradata */
extradata = (unsigned char *)avctx->extradata;
- extradata_end = avctx->extradata + avctx->extradata_size;
if (extradata) {
for (m = 0; m + 8 < avctx->extradata_size; m++) {
if (!memcmp(extradata, "SEQH", 4)) {
- marker_found = 1;
+ /* if a match was found, parse the extra data */
+ ret = svq3_decode_extradata(avctx, s, m);
+ if (ret < 0)
+ return ret;
break;
}
extradata++;
}
}
- /* if a match was found, parse the extra data */
- if (marker_found) {
- GetBitContext gb;
- int frame_size_code;
- int unk0, unk1, unk2, unk3, unk4;
- int w,h;
-
- size = AV_RB32(&extradata[4]);
- if (size > extradata_end - extradata - 8)
- return AVERROR_INVALIDDATA;
- init_get_bits(&gb, extradata + 8, size * 8);
-
- /* 'frame size code' and optional 'width, height' */
- frame_size_code = get_bits(&gb, 3);
- switch (frame_size_code) {
- case 0:
- w = 160;
- h = 120;
- break;
- case 1:
- w = 128;
- h = 96;
- break;
- case 2:
- w = 176;
- h = 144;
- break;
- case 3:
- w = 352;
- h = 288;
- break;
- case 4:
- w = 704;
- h = 576;
- break;
- case 5:
- w = 240;
- h = 180;
- break;
- case 6:
- w = 320;
- h = 240;
- break;
- case 7:
- w = get_bits(&gb, 12);
- h = get_bits(&gb, 12);
- break;
- }
- ret = ff_set_dimensions(avctx, w, h);
- if (ret < 0)
- return ret;
-
- s->halfpel_flag = get_bits1(&gb);
- s->thirdpel_flag = get_bits1(&gb);
-
- /* unknown fields */
- unk0 = get_bits1(&gb);
- unk1 = get_bits1(&gb);
- unk2 = get_bits1(&gb);
- unk3 = get_bits1(&gb);
-
- s->low_delay = get_bits1(&gb);
-
- /* unknown field */
- unk4 = get_bits1(&gb);
-
- av_log(avctx, AV_LOG_DEBUG, "Unknown fields %d %d %d %d %d\n",
- unk0, unk1, unk2, unk3, unk4);
-
- if (skip_1stop_8data_bits(&gb) < 0)
- return AVERROR_INVALIDDATA;
-
- s->has_watermark = get_bits1(&gb);
- avctx->has_b_frames = !s->low_delay;
- if (s->has_watermark) {
-#if CONFIG_ZLIB
- unsigned watermark_width = get_interleaved_ue_golomb(&gb);
- unsigned watermark_height = get_interleaved_ue_golomb(&gb);
- int u1 = get_interleaved_ue_golomb(&gb);
- int u2 = get_bits(&gb, 8);
- int u3 = get_bits(&gb, 2);
- int u4 = get_interleaved_ue_golomb(&gb);
- unsigned long buf_len = watermark_width *
- watermark_height * 4;
- int offset = get_bits_count(&gb) + 7 >> 3;
- uint8_t *buf;
-
- if (watermark_height <= 0 ||
- get_bits_left(&gb) <= 0 ||
- (uint64_t)watermark_width * 4 > UINT_MAX / watermark_height)
- return AVERROR_INVALIDDATA;
-
- buf = av_malloc(buf_len);
- if (!buf)
- return AVERROR(ENOMEM);
-
- av_log(avctx, AV_LOG_DEBUG, "watermark size: %ux%u\n",
- watermark_width, watermark_height);
- av_log(avctx, AV_LOG_DEBUG,
- "u1: %x u2: %x u3: %x compressed data size: %d offset: %d\n",
- u1, u2, u3, u4, offset);
- if (uncompress(buf, &buf_len, extradata + 8 + offset,
- size - offset) != Z_OK) {
- av_log(avctx, AV_LOG_ERROR,
- "could not uncompress watermark logo\n");
- av_free(buf);
- return -1;
- }
- s->watermark_key = av_bswap16(av_crc(av_crc_get_table(AV_CRC_16_CCITT), 0, buf, buf_len));
-
- s->watermark_key = s->watermark_key << 16 | s->watermark_key;
- av_log(avctx, AV_LOG_DEBUG,
- "watermark key %#"PRIx32"\n", s->watermark_key);
- av_free(buf);
-#else
- av_log(avctx, AV_LOG_ERROR,
- "this svq3 file contains watermark which need zlib support compiled in\n");
- return AVERROR(ENOSYS);
-#endif
- }
- }
-
s->mb_width = (avctx->width + 15) / 16;
s->mb_height = (avctx->height + 15) / 16;
s->mb_stride = s->mb_width + 1;
--
2.45.2
[-- Attachment #3: 0002-avcodec-svq3-Improve-returned-error-codes.patch --]
[-- Type: text/x-patch, Size: 1908 bytes --]
From 8bd133619aa4369d69fc091d9cc9d9734ee0f419 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 15 May 2025 03:24:23 +0200
Subject: [PATCH 2/7] avcodec/svq3: Improve returned error codes
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/svq3.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c
index f264140dbc..b192eb6c02 100644
--- a/libavcodec/svq3.c
+++ b/libavcodec/svq3.c
@@ -1225,7 +1225,7 @@ static av_cold int svq3_decode_extradata(AVCodecContext *avctx, SVQ3Context *s,
av_log(avctx, AV_LOG_ERROR,
"could not uncompress watermark logo\n");
av_free(buf);
- return -1;
+ return AVERROR_EXTERNAL;
}
s->watermark_key = av_bswap16(av_crc(av_crc_get_table(AV_CRC_16_CCITT), 0, buf, buf_len));
@@ -1403,8 +1403,9 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
if (ret < 0)
return ret;
- if (svq3_decode_slice_header(avctx))
- return -1;
+ ret = svq3_decode_slice_header(avctx);
+ if (ret < 0)
+ return ret;
if (avpkt->size < s->mb_width * s->mb_height / 8)
return AVERROR_INVALIDDATA;
@@ -1517,8 +1518,9 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
if (((get_bits_count(&s->gb_slice) & 7) == 0 ||
show_bits(&s->gb_slice, get_bits_left(&s->gb_slice) & 7) == 0)) {
- if (svq3_decode_slice_header(avctx))
- return -1;
+ ret = svq3_decode_slice_header(avctx);
+ if (ret < 0)
+ return ret;
}
if (s->slice_type != s->pict_type) {
avpriv_request_sample(avctx, "non constant slice type");
--
2.45.2
[-- Attachment #4: 0003-avcodec-svq3-Deduplicate-allocating-dummy-frame.patch --]
[-- Type: text/x-patch, Size: 2819 bytes --]
From 71aa71acce5c00faf02c03a2ce6c35a112e4d520 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 15 May 2025 03:29:43 +0200
Subject: [PATCH 3/7] avcodec/svq3: Deduplicate allocating dummy frame
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/svq3.c | 35 +++++++++++++++++++----------------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c
index b192eb6c02..e1e65c4766 100644
--- a/libavcodec/svq3.c
+++ b/libavcodec/svq3.c
@@ -1377,6 +1377,23 @@ fail:
return ret;
}
+static av_cold int alloc_dummy_frame(AVCodecContext *avctx, SVQ3Frame *pic)
+{
+ av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n");
+ av_frame_unref(pic->f);
+ int ret = get_buffer(avctx, pic);
+ if (ret < 0)
+ return ret;
+
+ memset(pic->f->data[0], 0, avctx->height * pic->f->linesize[0]);
+ memset(pic->f->data[1], 0x80, (avctx->height / 2) *
+ pic->f->linesize[1]);
+ memset(pic->f->data[2], 0x80, (avctx->height / 2) *
+ pic->f->linesize[2]);
+
+ return 0;
+}
+
static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
int *got_frame, AVPacket *avpkt)
{
@@ -1441,29 +1458,15 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
if (s->pict_type != AV_PICTURE_TYPE_I) {
if (!s->last_pic->f->data[0]) {
- av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n");
- av_frame_unref(s->last_pic->f);
- ret = get_buffer(avctx, s->last_pic);
+ ret = alloc_dummy_frame(avctx, s->last_pic);
if (ret < 0)
return ret;
- memset(s->last_pic->f->data[0], 0, avctx->height * s->last_pic->f->linesize[0]);
- memset(s->last_pic->f->data[1], 0x80, (avctx->height / 2) *
- s->last_pic->f->linesize[1]);
- memset(s->last_pic->f->data[2], 0x80, (avctx->height / 2) *
- s->last_pic->f->linesize[2]);
}
if (s->pict_type == AV_PICTURE_TYPE_B && !s->next_pic->f->data[0]) {
- av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n");
- av_frame_unref(s->next_pic->f);
- ret = get_buffer(avctx, s->next_pic);
+ ret = alloc_dummy_frame(avctx, s->next_pic);
if (ret < 0)
return ret;
- memset(s->next_pic->f->data[0], 0, avctx->height * s->next_pic->f->linesize[0]);
- memset(s->next_pic->f->data[1], 0x80, (avctx->height / 2) *
- s->next_pic->f->linesize[1]);
- memset(s->next_pic->f->data[2], 0x80, (avctx->height / 2) *
- s->next_pic->f->linesize[2]);
}
}
--
2.45.2
[-- Attachment #5: 0004-avcodec-svq3-Allocate-motion_val-jointly.patch --]
[-- Type: text/x-patch, Size: 2248 bytes --]
From a2a84101c7d056b2d0219a5603ae90aeb3f4ce28 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 15 May 2025 03:42:06 +0200
Subject: [PATCH 4/7] avcodec/svq3: Allocate motion_val jointly
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/svq3.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c
index e1e65c4766..cdb2bd323b 100644
--- a/libavcodec/svq3.c
+++ b/libavcodec/svq3.c
@@ -74,7 +74,7 @@
typedef struct SVQ3Frame {
AVFrame *f;
- int16_t (*motion_val_buf[2])[2];
+ int16_t (*motion_val_buf)[2];
int16_t (*motion_val[2])[2];
uint32_t *mb_type_buf, *mb_type;
@@ -1323,10 +1323,7 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
static void free_picture(SVQ3Frame *pic)
{
- int i;
- for (i = 0; i < 2; i++) {
- av_freep(&pic->motion_val_buf[i]);
- }
+ av_freep(&pic->motion_val_buf);
av_freep(&pic->mb_type_buf);
av_frame_unref(pic->f);
@@ -1340,23 +1337,19 @@ static int get_buffer(AVCodecContext *avctx, SVQ3Frame *pic)
const int b4_array_size = b4_stride * s->mb_height * 4;
int ret;
- if (!pic->motion_val_buf[0]) {
- int i;
-
+ if (!pic->motion_val_buf) {
pic->mb_type_buf = av_calloc(big_mb_num + s->mb_stride, sizeof(uint32_t));
if (!pic->mb_type_buf)
return AVERROR(ENOMEM);
pic->mb_type = pic->mb_type_buf + 2 * s->mb_stride + 1;
- for (i = 0; i < 2; i++) {
- pic->motion_val_buf[i] = av_calloc(b4_array_size + 4, 2 * sizeof(int16_t));
- if (!pic->motion_val_buf[i]) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
-
- pic->motion_val[i] = pic->motion_val_buf[i] + 4;
+ pic->motion_val_buf = av_calloc(b4_array_size + 4, 2 * sizeof(*pic->motion_val[0]));
+ if (!pic->motion_val_buf) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
}
+ pic->motion_val[0] = pic->motion_val_buf + 4;
+ pic->motion_val[1] = pic->motion_val[0] + b4_array_size + 4;
}
ret = ff_get_buffer(avctx, pic->f,
--
2.45.2
[-- Attachment #6: 0005-avcodec-svq3-Allocate-picture-buffers-during-init.patch --]
[-- Type: text/x-patch, Size: 5012 bytes --]
From 99780f564486d7feab35f2f15a1a4c0a48145552 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 15 May 2025 04:28:03 +0200
Subject: [PATCH 5/7] avcodec/svq3: Allocate picture buffers during init
Also allocate them jointly.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/svq3.c | 83 ++++++++++++++++++++++++-----------------------
1 file changed, 42 insertions(+), 41 deletions(-)
diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c
index cdb2bd323b..c510d2fb38 100644
--- a/libavcodec/svq3.c
+++ b/libavcodec/svq3.c
@@ -71,13 +71,14 @@
* svq3 decoder.
*/
+#define NUM_PICS 3
+
typedef struct SVQ3Frame {
AVFrame *f;
- int16_t (*motion_val_buf)[2];
int16_t (*motion_val[2])[2];
- uint32_t *mb_type_buf, *mb_type;
+ uint32_t *mb_type;
} SVQ3Frame;
typedef struct SVQ3Context {
@@ -142,7 +143,10 @@ typedef struct SVQ3Context {
DECLARE_ALIGNED(8, uint8_t, non_zero_count_cache)[15 * 8];
uint32_t dequant4_coeff[QP_MAX_NUM + 1][16];
int block_offset[2 * (16 * 3)];
- SVQ3Frame frames[3];
+ SVQ3Frame frames[NUM_PICS];
+
+ uint32_t *mb_type_buf;
+ int16_t (*motion_val_buf)[2];
} SVQ3Context;
#define FULLPEL_MODE 1
@@ -1300,6 +1304,34 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
s->h_edge_pos = s->mb_width * 16;
s->v_edge_pos = s->mb_height * 16;
+ const unsigned big_mb_num = s->mb_stride * (s->mb_height + 2) + 1;
+
+ s->mb_type_buf = av_calloc(big_mb_num, NUM_PICS * sizeof(*s->mb_type_buf));
+ if (!s->mb_type_buf)
+ return AVERROR(ENOMEM);
+ uint32_t *mb_type_buf = s->mb_type_buf + 2 * s->mb_stride + 1;
+
+ const unsigned b4_stride = s->mb_width * 4 + 1;
+ const unsigned b4_array_size = b4_stride * s->mb_height * 4;
+ const unsigned motion_val_buf_size = b4_array_size + 4;
+
+ s->motion_val_buf = av_calloc(motion_val_buf_size,
+ NUM_PICS * 2 * sizeof(*s->motion_val_buf));
+ if (!s->motion_val_buf)
+ return AVERROR(ENOMEM);
+ int16_t (*motion_val_buf)[2] = s->motion_val_buf + 4;
+
+ for (size_t i = 0; i < NUM_PICS; ++i) {
+ SVQ3Frame *const pic = &s->frames[i];
+
+ pic->mb_type = mb_type_buf;
+ mb_type_buf += big_mb_num;
+ for (size_t j = 0; j < FF_ARRAY_ELEMS(pic->motion_val); ++j) {
+ pic->motion_val[j] = motion_val_buf;
+ motion_val_buf += motion_val_buf_size;
+ }
+ }
+
s->intra4x4_pred_mode = av_mallocz(s->mb_stride * 2 * 8);
if (!s->intra4x4_pred_mode)
return AVERROR(ENOMEM);
@@ -1321,42 +1353,14 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
return 0;
}
-static void free_picture(SVQ3Frame *pic)
-{
- av_freep(&pic->motion_val_buf);
- av_freep(&pic->mb_type_buf);
-
- av_frame_unref(pic->f);
-}
-
static int get_buffer(AVCodecContext *avctx, SVQ3Frame *pic)
{
SVQ3Context *s = avctx->priv_data;
- const int big_mb_num = s->mb_stride * (s->mb_height + 1) + 1;
- const int b4_stride = s->mb_width * 4 + 1;
- const int b4_array_size = b4_stride * s->mb_height * 4;
- int ret;
-
- if (!pic->motion_val_buf) {
- pic->mb_type_buf = av_calloc(big_mb_num + s->mb_stride, sizeof(uint32_t));
- if (!pic->mb_type_buf)
- return AVERROR(ENOMEM);
- pic->mb_type = pic->mb_type_buf + 2 * s->mb_stride + 1;
-
- pic->motion_val_buf = av_calloc(b4_array_size + 4, 2 * sizeof(*pic->motion_val[0]));
- if (!pic->motion_val_buf) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- pic->motion_val[0] = pic->motion_val_buf + 4;
- pic->motion_val[1] = pic->motion_val[0] + b4_array_size + 4;
- }
-
- ret = ff_get_buffer(avctx, pic->f,
- (s->pict_type != AV_PICTURE_TYPE_B) ?
- AV_GET_BUFFER_FLAG_REF : 0);
+ int ret = ff_get_buffer(avctx, pic->f,
+ (s->pict_type != AV_PICTURE_TYPE_B) ?
+ AV_GET_BUFFER_FLAG_REF : 0);
if (ret < 0)
- goto fail;
+ return ret;
if (!s->edge_emu_buffer) {
s->edge_emu_buffer = av_calloc(pic->f->linesize[0], 17);
@@ -1365,9 +1369,6 @@ static int get_buffer(AVCodecContext *avctx, SVQ3Frame *pic)
}
return 0;
-fail:
- free_picture(pic);
- return ret;
}
static av_cold int alloc_dummy_frame(AVCodecContext *avctx, SVQ3Frame *pic)
@@ -1586,10 +1587,10 @@ static av_cold int svq3_decode_end(AVCodecContext *avctx)
{
SVQ3Context *s = avctx->priv_data;
- for (int i = 0; i < FF_ARRAY_ELEMS(s->frames); i++) {
- free_picture(&s->frames[i]);
+ for (int i = 0; i < NUM_PICS; i++)
av_frame_free(&s->frames[i].f);
- }
+ av_freep(&s->motion_val_buf);
+ av_freep(&s->mb_type_buf);
av_freep(&s->slice_buf);
av_freep(&s->intra4x4_pred_mode);
av_freep(&s->edge_emu_buffer);
--
2.45.2
[-- Attachment #7: 0006-tests-fate-qt-Use-passthrough-fps_mode-for-svq3-wate.patch --]
[-- Type: text/x-patch, Size: 1815 bytes --]
From 853dc2c697d8004d6655b84ab9f28aaafc3c2b40 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 15 May 2025 04:42:46 +0200
Subject: [PATCH 6/7] tests/fate/qt: Use passthrough fps_mode for
svq3-watermark
The file has buggy timestamps (it uses B-frames, yet pts==dts)
and therefore the last frame is currently discarded by FFmpeg cli.
Using -fps_mode passthrough avoids this and provides coverage
of the SVQ3 draining logic.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
tests/fate/qt.mak | 2 +-
tests/ref/fate/svq3-watermark | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/tests/fate/qt.mak b/tests/fate/qt.mak
index 42e5fd9107..436da172f1 100644
--- a/tests/fate/qt.mak
+++ b/tests/fate/qt.mak
@@ -57,7 +57,7 @@ fate-svq3-1: CMD = framecrc -i $(TARGET_SAMPLES)/svq3/Vertical400kbit.sorenson3.
fate-svq3-2: CMD = framecrc -flags +bitexact -ignore_editlist 1 -i $(TARGET_SAMPLES)/svq3/svq3_decoding_regression.mov -an
FATE_SVQ3 += fate-svq3-watermark
-fate-svq3-watermark: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/svq3/svq3_watermark.mov
+fate-svq3-watermark: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/svq3/svq3_watermark.mov -fps_mode passthrough
FATE_QT-$(call FRAMECRC, MOV, SVQ3, ZLIB) += $(FATE_SVQ3)
fate-svq3: $(FATE_SVQ3)
diff --git a/tests/ref/fate/svq3-watermark b/tests/ref/fate/svq3-watermark
index f4068c612e..95d67e3da4 100644
--- a/tests/ref/fate/svq3-watermark
+++ b/tests/ref/fate/svq3-watermark
@@ -12,3 +12,4 @@
0, 7, 7, 1, 102240, 0x342bf32f
0, 8, 8, 1, 102240, 0x7b311bf1
0, 9, 9, 1, 102240, 0xf56e0cd3
+0, 9, 9, 1, 102240, 0xfb95c7d3
--
2.45.2
[-- Attachment #8: 0007-avcodec-svq3-Improve-returning-last-picture.patch --]
[-- Type: text/x-patch, Size: 1624 bytes --]
From b6cfeb10b2f269bb37ecd71338e19927b18f8549 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 15 May 2025 04:48:54 +0200
Subject: [PATCH 7/7] avcodec/svq3: Improve returning last picture
Use av_frame_move_ref() instead of av_frame_ref().
This allows to remove the separate variable for whether
we have already returned the delayed last pic. It also
makes stream looping work when looping multiple times;
previously the delayed pic was only output the first time,
because last_frame_output was never reset.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/svq3.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c
index c510d2fb38..4c4f3018c5 100644
--- a/libavcodec/svq3.c
+++ b/libavcodec/svq3.c
@@ -104,7 +104,6 @@ typedef struct SVQ3Context {
int adaptive_quant;
int h_edge_pos;
int v_edge_pos;
- int last_frame_output;
int slice_num;
int qscale;
int cbp;
@@ -1398,11 +1397,8 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
/* special case for last picture */
if (buf_size == 0) {
- if (s->next_pic->f->data[0] && !s->low_delay && !s->last_frame_output) {
- ret = av_frame_ref(rframe, s->next_pic->f);
- if (ret < 0)
- return ret;
- s->last_frame_output = 1;
+ if (s->next_pic->f->data[0] && !s->low_delay) {
+ av_frame_move_ref(rframe, s->next_pic->f);
*got_frame = 1;
}
return 0;
--
2.45.2
[-- Attachment #9: 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] 2+ messages in thread
* Re: [FFmpeg-devel] [PATCH 1/7] avcodec/svq3: Factor out decoding extradata
2025-05-15 4:07 [FFmpeg-devel] [PATCH 1/7] avcodec/svq3: Factor out decoding extradata Andreas Rheinhardt
@ 2025-05-18 14:19 ` Andreas Rheinhardt
0 siblings, 0 replies; 2+ messages in thread
From: Andreas Rheinhardt @ 2025-05-18 14:19 UTC (permalink / raw)
To: ffmpeg-devel
Andreas Rheinhardt:
> Patches attached.
>
> - Andreas
>
Will apply this patchset tomorrow unless there is an objection.
- Andreas
_______________________________________________
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] 2+ messages in thread
end of thread, other threads:[~2025-05-18 14:19 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-15 4:07 [FFmpeg-devel] [PATCH 1/7] avcodec/svq3: Factor out decoding extradata Andreas Rheinhardt
2025-05-18 14:19 ` Andreas Rheinhardt
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