ffmpeg-devel
Threads by month
- ----- 2026 -----
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
June 2026
- 35 participants
- 385 discussions
[PR] swscale/tests/sws_ops_aarch64: remove on-stack copy of const data (PR #23529)
by Ramiro Polla 18 Jun '26
by Ramiro Polla 18 Jun '26
18 Jun '26
PR #23529 opened by Ramiro Polla (ramiro)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23529
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23529.patch
It doesn't get modified, so there's no need to create a copy.
From 957ac3c4c0eaaa3230743b30c1393bbaaffc41aa Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Fri, 12 Jun 2026 01:04:49 +0200
Subject: [PATCH] swscale/tests/sws_ops_aarch64: remove on-stack copy of const
data
It doesn't get modified, so there's no need to create a copy.
---
libswscale/tests/sws_ops_aarch64.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/libswscale/tests/sws_ops_aarch64.c b/libswscale/tests/sws_ops_aarch64.c
index 3319af0536..2089a0f1b7 100644
--- a/libswscale/tests/sws_ops_aarch64.c
+++ b/libswscale/tests/sws_ops_aarch64.c
@@ -93,14 +93,12 @@ static int register_op(SwsContext *ctx, void *opaque, SwsOpList *ops)
}
}
- /* Make on-stack copy of `ops` to iterate over */
- SwsOpList rest = *ops;
/* Use at most two full vregs during the widest precision section */
int block_size = (ff_sws_op_list_max_size(ops) == 4) ? 8 : 16;
- for (int i = 0; i < rest.num_ops; i++) {
+ for (int i = 0; i < ops->num_ops; i++) {
SwsAArch64OpImplParams params = { 0 };
- ret = convert_to_aarch64_impl(ctx, &rest, i, block_size, ¶ms);
+ ret = convert_to_aarch64_impl(ctx, ops, i, block_size, ¶ms);
if (ret == AVERROR(ENOTSUP))
continue;
if (ret < 0)
--
2.52.0
1
0
[PR] swscale/uops: rename SwsOpTable/SwsOpEntry to SwsUOpTable/SwsUOpEntry (PR #23528)
by Ramiro Polla 18 Jun '26
by Ramiro Polla 18 Jun '26
18 Jun '26
PR #23528 opened by Ramiro Polla (ramiro)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23528
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23528.patch
These structs are only used through ff_sws_uop_lookup() and are not part
of the SwsOp dispatch path, so rename them to reflect their actual scope.
From 26170717a6fbb90b0699d10375eafb43d1a9470b Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Wed, 17 Jun 2026 23:04:02 +0200
Subject: [PATCH] swscale/uops: rename SwsOpTable/SwsOpEntry to
SwsUOpTable/SwsUOpEntry
These structs are only used through ff_sws_uop_lookup() and are not part
of the SwsOp dispatch path, so rename them to reflect their actual scope.
---
libswscale/ops_chain.c | 8 ++++----
libswscale/ops_chain.h | 16 ++++++++--------
libswscale/uops_backend.c | 4 ++--
libswscale/uops_tmpl.h | 4 ++--
libswscale/x86/ops.c | 30 +++++++++++++++---------------
5 files changed, 31 insertions(+), 31 deletions(-)
diff --git a/libswscale/ops_chain.c b/libswscale/ops_chain.c
index d60f7ccf28..c3884a67ad 100644
--- a/libswscale/ops_chain.c
+++ b/libswscale/ops_chain.c
@@ -113,12 +113,12 @@ int ff_sws_setup_clear(const SwsImplParams *params, SwsImplResult *out)
return 0;
}
-int ff_sws_uop_lookup(SwsContext *ctx, const SwsOpTable *const tables[],
+int ff_sws_uop_lookup(SwsContext *ctx, const SwsUOpTable *const tables[],
int num_tables, const SwsUOp *uop, const int block_size,
SwsOpChain *chain)
{
const unsigned cpu_flags = av_get_cpu_flags();
- const SwsOpEntry *match = NULL;
+ const SwsUOpEntry *match = NULL;
int ret;
SwsImplParams params = {
@@ -127,13 +127,13 @@ int ff_sws_uop_lookup(SwsContext *ctx, const SwsOpTable *const tables[],
};
for (int n = 0; !match && n < num_tables; n++) {
- const SwsOpTable *table = params.table = tables[n];
+ const SwsUOpTable *table = params.table = tables[n];
if (table->block_size && table->block_size != block_size ||
table->cpu_flags & ~cpu_flags)
continue;
for (int i = 0; table->entries[i]; i++) {
- const SwsOpEntry *entry = table->entries[i];
+ const SwsUOpEntry *entry = table->entries[i];
const SwsUOp entry_uop = {
.uop = entry->uop,
.type = entry->type,
diff --git a/libswscale/ops_chain.h b/libswscale/ops_chain.h
index abe4c545cd..3475790ff9 100644
--- a/libswscale/ops_chain.h
+++ b/libswscale/ops_chain.h
@@ -37,7 +37,7 @@
* that is an implementation detail of the specific backend.
*/
-typedef struct SwsOpTable SwsOpTable;
+typedef struct SwsUOpTable SwsUOpTable;
/**
* Private data for each kernel.
@@ -103,7 +103,7 @@ int ff_sws_op_chain_append(SwsOpChain *chain, SwsFuncPtr func,
void (*free)(SwsOpPriv *), const SwsOpPriv *priv);
typedef struct SwsImplParams {
- const SwsOpTable *table;
+ const SwsUOpTable *table;
union {
const SwsUOp *uop;
const SwsOp *op;
@@ -112,14 +112,14 @@ typedef struct SwsImplParams {
} SwsImplParams;
typedef struct SwsImplResult {
- SwsFuncPtr func; /* overrides `SwsOpEntry.func` if non-NULL */
+ SwsFuncPtr func; /* overrides `SwsUOpEntry.func` if non-NULL */
SwsOpPriv priv; /* private data for this implementation instance */
void (*free)(SwsOpPriv *priv); /* free function for `priv` */
int over_read[4]; /* implementation over-reads input by this many bytes */
int over_write[4]; /* implementation over-writes output by this many bytes */
} SwsImplResult;
-typedef struct SwsOpEntry {
+typedef struct SwsUOpEntry {
/* Kernel metadata; reduced size subset of SwsUOp (sans data) */
SwsUOpType uop;
SwsPixelType type;
@@ -130,7 +130,7 @@ typedef struct SwsOpEntry {
SwsFuncPtr func;
int (*setup)(const SwsImplParams *params, SwsImplResult *out); /* optional */
bool (*check)(const SwsImplParams *params); /* optional, return true if supported */
-} SwsOpEntry;
+} SwsUOpEntry;
/* Setup helpers for common/trivial operation types */
int ff_sws_setup_scale(const SwsImplParams *params, SwsImplResult *out);
@@ -151,10 +151,10 @@ static inline void ff_op_priv_unref(SwsOpPriv *priv)
av_refstruct_unref(&priv->ptr);
}
-struct SwsOpTable {
+struct SwsUOpTable {
unsigned cpu_flags; /* required CPU flags for this table */
int block_size; /* fixed block size of this table */
- const SwsOpEntry *entries[]; /* terminated by NULL */
+ const SwsUOpEntry *entries[]; /* terminated by NULL */
};
/**
@@ -163,7 +163,7 @@ struct SwsOpTable {
*
* Returns 0 or a negative error code.
*/
-int ff_sws_uop_lookup(SwsContext *ctx, const SwsOpTable *const tables[],
+int ff_sws_uop_lookup(SwsContext *ctx, const SwsUOpTable *const tables[],
int num_tables, const SwsUOp *uop, const int block_size,
SwsOpChain *chain);
diff --git a/libswscale/uops_backend.c b/libswscale/uops_backend.c
index 50f5302ca6..56176b1e50 100644
--- a/libswscale/uops_backend.c
+++ b/libswscale/uops_backend.c
@@ -93,7 +93,7 @@
SWS_FOR(TYPE, DITHER, REF_ENTRY) \
/* end of macro */
-static const SwsOpTable op_table = {
+static const SwsUOpTable uop_table = {
.block_size = SWS_BLOCK_SIZE,
.entries = {
REF_ALL_UOPS(U8)
@@ -154,7 +154,7 @@ static int compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
av_assert0(uops->num_ops > 0);
for (int i = 0; i < uops->num_ops; i++) {
- const SwsOpTable *table = &op_table;
+ const SwsUOpTable *table = &uop_table;
ret = ff_sws_uop_lookup(ctx, &table, 1, &uops->ops[i],
SWS_BLOCK_SIZE, chain);
if (ret < 0)
diff --git a/libswscale/uops_tmpl.h b/libswscale/uops_tmpl.h
index 176846ad14..9015f26dad 100644
--- a/libswscale/uops_tmpl.h
+++ b/libswscale/uops_tmpl.h
@@ -135,9 +135,9 @@ typedef struct SwsOpIter {
(pixel_t *) iter->out[0], (pixel_t *) iter->out[1], \
(pixel_t *) iter->out[2], (pixel_t *) iter->out[3])
-#define REF_ENTRY(DUMMY, NAME, ...) &op_##NAME,
+#define REF_ENTRY(DUMMY, NAME, ...) &uop_##NAME,
#define DECL_ENTRY(SETUP, NAME, ...) \
- static const SwsOpEntry op_##NAME = { \
+ static const SwsUOpEntry uop_##NAME = { \
.func = (SwsFuncPtr) NAME##_c, \
__VA_ARGS__, \
SETUP \
diff --git a/libswscale/x86/ops.c b/libswscale/x86/ops.c
index 15512db56d..b522ca06e3 100644
--- a/libswscale/x86/ops.c
+++ b/libswscale/x86/ops.c
@@ -297,10 +297,10 @@ static bool uop_is_type_invariant(const SwsUOpType uop)
}
}
-#define REF_ENTRY(EXT, NAME, ...) &op_##NAME##EXT,
+#define REF_ENTRY(EXT, NAME, ...) &uop_##NAME##EXT,
#define DECL_ENTRY(EXT, CHECK, SETUP, NAME, ...) \
void ff_##NAME##EXT(void); \
- static const SwsOpEntry op_##NAME##EXT = { \
+ static const SwsUOpEntry uop_##NAME##EXT = { \
.func = (SwsFuncPtr) ff_##NAME##EXT, \
.check = CHECK, \
.setup = SETUP, \
@@ -358,7 +358,7 @@ SWS_FOR_STRUCT(U8, READ_PLANAR, DECL_ENTRY, EXT, NULL, NULL)
SWS_FOR_STRUCT(U8, WRITE_PLANAR, DECL_ENTRY, EXT, NULL, NULL) \
SWS_FOR_STRUCT(U8, CLEAR, DECL_ENTRY, EXT, NULL, setup_clear) \
\
-static const SwsOpTable ops_u8##EXT = { \
+static const SwsUOpTable uops_u8##EXT = { \
.cpu_flags = AV_CPU_FLAG_##FLAG, \
.block_size = SIZE, \
.entries = { \
@@ -376,7 +376,7 @@ SWS_FOR_STRUCT(U8, TO_U16, DECL_ENTRY, EXT, NULL, NULL)
SWS_FOR_STRUCT(U16, TO_U8, DECL_ENTRY, EXT, NULL, NULL) \
SWS_FOR_STRUCT(U8, EXPAND_PAIR, DECL_ENTRY, EXT, NULL, NULL) \
\
-static const SwsOpTable ops_u16##EXT = { \
+static const SwsUOpTable uops_u16##EXT = { \
.cpu_flags = AV_CPU_FLAG_##FLAG, \
.block_size = SIZE, \
.entries = { \
@@ -396,7 +396,7 @@ SWS_FOR_STRUCT(U16, TO_U32, DECL_ENTRY, EXT, NULL, NULL)
SWS_FOR_STRUCT(U32, TO_U16, DECL_ENTRY, EXT, NULL, NULL) \
SWS_FOR_STRUCT(U8, EXPAND_QUAD, DECL_ENTRY, EXT, NULL, NULL) \
\
-static const SwsOpTable ops_u32##EXT = { \
+static const SwsUOpTable uops_u32##EXT = { \
.cpu_flags = AV_CPU_FLAG_##FLAG, \
.block_size = SIZE, \
.entries = { \
@@ -432,7 +432,7 @@ SWS_FOR_STRUCT(U8, READ_PLANAR_FV_FMA, DECL_ENTRY, EXT, NULL, setup_filter_v)
SWS_FOR_STRUCT(U16, READ_PLANAR_FV_FMA, DECL_ENTRY, EXT, NULL, setup_filter_v) \
SWS_FOR_STRUCT(F32, READ_PLANAR_FV_FMA, DECL_ENTRY, EXT, NULL, setup_filter_v) \
\
-static const SwsOpTable ops_f32##EXT = { \
+static const SwsUOpTable uops_f32##EXT = { \
.cpu_flags = AV_CPU_FLAG_##FLAG, \
.block_size = SIZE, \
.entries = { \
@@ -466,15 +466,15 @@ DECL_TABLE_U16(_m2_avx2, 32, AVX2)
DECL_TABLE_U32(_m2_avx2, 16, AVX2)
DECL_TABLE_F32(_m2_avx2, 16, AVX2)
-static const SwsOpTable *const tables[] = {
- &ops_u8_m1_sse4,
- &ops_u8_m1_avx2, /* order before _m2_sse4 */
- &ops_u8_m2_sse4,
- &ops_u8_m2_avx2,
- &ops_u16_m1_avx2,
- &ops_u16_m2_avx2,
- &ops_u32_m2_avx2,
- &ops_f32_m2_avx2,
+static const SwsUOpTable *const tables[] = {
+ &uops_u8_m1_sse4,
+ &uops_u8_m1_avx2, /* order before _m2_sse4 */
+ &uops_u8_m2_sse4,
+ &uops_u8_m2_avx2,
+ &uops_u16_m1_avx2,
+ &uops_u16_m2_avx2,
+ &uops_u32_m2_avx2,
+ &uops_f32_m2_avx2,
};
SWS_DECL_FUNC(ff_sws_process1_x86);
--
2.52.0
1
0
[PR] swscale/uops: generate more specific masks for unpack when translating (PR #23527)
by Ramiro Polla 18 Jun '26
by Ramiro Polla 18 Jun '26
18 Jun '26
PR #23527 opened by Ramiro Polla (ramiro)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23527
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23527.patch
Unused components weren't being taken into consideration.
Note this commit includes a hack to prevent checkasm from aborting,
since checkasm does {read, unpack, write} which doesn't properly mark
the unpacked components as unused.
From 48c9b38087b91800d3f6aa94419209cb0400a750 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Fri, 12 Jun 2026 02:41:09 +0200
Subject: [PATCH] swscale/uops: generate more specific masks for unpack when
translating
Unused components weren't being taken into consideration.
Note this commit includes a hack to prevent checkasm from aborting,
since checkasm does {read, unpack, write} which doesn't properly mark
the unpacked components as unused.
---
libswscale/uops.c | 14 +++++++++++++-
libswscale/uops_macros.h | 8 ++++++++
tests/ref/fate/sws-ops-list | 2 +-
3 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/libswscale/uops.c b/libswscale/uops.c
index 1bd3e2f763..a9dd0d41cf 100644
--- a/libswscale/uops.c
+++ b/libswscale/uops.c
@@ -799,7 +799,8 @@ static int translate_op(SwsContext *ctx, SwsUOpList *uops, SwsUOpFlags flags,
uop.mask = 0;
for (int i = 0; i < 4 && op->pack.pattern[i]; i++) {
uop.par.pack.pattern[i] = op->pack.pattern[i];
- uop.mask |= SWS_COMP(i);
+ if (op->op == SWS_OP_PACK || SWS_OP_NEEDED(op, i))
+ uop.mask |= SWS_COMP(i);
}
break;
case SWS_OP_LSHIFT:
@@ -1021,6 +1022,17 @@ int ff_sws_uops_macros_gen(char **out_str)
}
}
+ /* HACK: add some patterns for checkasm */
+ const SwsUOp extra_uops[] = {
+ { .type = SWS_PIXEL_U32, .uop = SWS_UOP_UNPACK, .mask = 0xf, .par.pack.pattern = {2, 10, 10, 10} },
+ { .type = SWS_PIXEL_U32, .uop = SWS_UOP_UNPACK, .mask = 0xf, .par.pack.pattern = {10, 10, 10, 2} },
+ };
+ for (int i = 0; i < FF_ARRAY_ELEMS(extra_uops); i++) {
+ ret = register_uop(&root, &extra_uops[i]);
+ if (ret < 0)
+ goto fail;
+ }
+
#define BPRINT_STR(str) av_bprint_append_data(bp, str, strlen(str))
BPRINT_STR(
"/**\n"
diff --git a/libswscale/uops_macros.h b/libswscale/uops_macros.h
index 3c4d6b6a3e..62743a8359 100644
--- a/libswscale/uops_macros.h
+++ b/libswscale/uops_macros.h
@@ -934,9 +934,17 @@
#define SWS_FOR_U32_MAX(MACRO, ...)
#define SWS_FOR_STRUCT_U32_MAX(MACRO, ...)
#define SWS_FOR_U32_UNPACK(MACRO, ...) \
+ MACRO(__VA_ARGS__, u32_unpack_y_aaa2 , SWS_PIXEL_U32, SWS_UOP_UNPACK , 0x2, 10, 10, 10, 2) \
+ MACRO(__VA_ARGS__, u32_unpack_z_2aaa , SWS_PIXEL_U32, SWS_UOP_UNPACK , 0x4, 2, 10, 10, 10) \
+ MACRO(__VA_ARGS__, u32_unpack_xyz_aaa2 , SWS_PIXEL_U32, SWS_UOP_UNPACK , 0x7, 10, 10, 10, 2) \
+ MACRO(__VA_ARGS__, u32_unpack_yzw_2aaa , SWS_PIXEL_U32, SWS_UOP_UNPACK , 0xe, 2, 10, 10, 10) \
MACRO(__VA_ARGS__, u32_unpack_xyzw_2aaa , SWS_PIXEL_U32, SWS_UOP_UNPACK , 0xf, 2, 10, 10, 10) \
MACRO(__VA_ARGS__, u32_unpack_xyzw_aaa2 , SWS_PIXEL_U32, SWS_UOP_UNPACK , 0xf, 10, 10, 10, 2)
#define SWS_FOR_STRUCT_U32_UNPACK(MACRO, ...) \
+ MACRO(__VA_ARGS__, u32_unpack_y_aaa2 , .type = SWS_PIXEL_U32, .uop = SWS_UOP_UNPACK , .mask = 0x2, .par.pack.pattern = {10, 10, 10, 2}) \
+ MACRO(__VA_ARGS__, u32_unpack_z_2aaa , .type = SWS_PIXEL_U32, .uop = SWS_UOP_UNPACK , .mask = 0x4, .par.pack.pattern = {2, 10, 10, 10}) \
+ MACRO(__VA_ARGS__, u32_unpack_xyz_aaa2 , .type = SWS_PIXEL_U32, .uop = SWS_UOP_UNPACK , .mask = 0x7, .par.pack.pattern = {10, 10, 10, 2}) \
+ MACRO(__VA_ARGS__, u32_unpack_yzw_2aaa , .type = SWS_PIXEL_U32, .uop = SWS_UOP_UNPACK , .mask = 0xe, .par.pack.pattern = {2, 10, 10, 10}) \
MACRO(__VA_ARGS__, u32_unpack_xyzw_2aaa , .type = SWS_PIXEL_U32, .uop = SWS_UOP_UNPACK , .mask = 0xf, .par.pack.pattern = {2, 10, 10, 10}) \
MACRO(__VA_ARGS__, u32_unpack_xyzw_aaa2 , .type = SWS_PIXEL_U32, .uop = SWS_UOP_UNPACK , .mask = 0xf, .par.pack.pattern = {10, 10, 10, 2})
#define SWS_FOR_U32_PACK(MACRO, ...) \
diff --git a/tests/ref/fate/sws-ops-list b/tests/ref/fate/sws-ops-list
index 6b4003121a..f3311b643f 100644
--- a/tests/ref/fate/sws-ops-list
+++ b/tests/ref/fate/sws-ops-list
@@ -1 +1 @@
-bbe27c8c324f08d933f6397f5fb96650
+2f427f7cbfaef38013a3fbefcb5e1e57
--
2.52.0
1
0
18 Jun '26
PR #23526 opened by mkver
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23526
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23526.patch
From a6a6ef962f93b8e66c62ec0be58ecdd1e73400db Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt(a)outlook.com>
Date: Thu, 18 Jun 2026 16:53:27 +0200
Subject: [PATCH] avcodec/liboapvenc: Use av_freep() where appropriate
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt(a)outlook.com>
---
libavcodec/liboapvenc.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/libavcodec/liboapvenc.c b/libavcodec/liboapvenc.c
index 51b4343c05..22a8ac4890 100644
--- a/libavcodec/liboapvenc.c
+++ b/libavcodec/liboapvenc.c
@@ -628,12 +628,9 @@ static av_cold int liboapve_close(AVCodecContext *avctx)
ApvEncContext *apv = avctx->priv_data;
for (unsigned int i = 0; i < apv->nb_payloads; i++) {
- if (apv->payloads[i].data) {
- av_free(apv->payloads[i].data);
- apv->payloads[i].data = NULL;
- }
+ av_freep(&apv->payloads[i].data);
}
- av_free(apv->payloads);
+ av_freep(&apv->payloads);
for (int i = 0; i < apv->ifrms.num_frms; i++) {
if (apv->ifrms.frm[i].imgb != NULL)
--
2.52.0
1
0
I’ve developed a set of patches that enable FFmpeg to be optionally given a single
JSON containing all commands and parameters.
This…
* makes building FFMPEG commands programmatically easier and more reliable
* avoids difficulties that come with very long FFMPEG command-line strings
* avoids the requirement to escape slashes and other common characters
(particularly useful when passing urls or presigned urls)
* makes it easier to save and modify ffmpeg “recipes” (taking a template,
modifying one or more parameters, saving as a new ffmpeg command)
The only slight caveat is that filter complexes must still be defined as a string.
I believe that this design is independent of any particular command-line parameters, and so it shouldn’t break when
commands or parameters are added or changed (so, it shouldn’t be a maintenance headache).
There is also a json_cmd_gen command that converts a FFMPEG command-line string into the equivalent JSON,
and a json_cmd_print command that converts a FFMPEG JSON into the equivalent command-line string.
Add -json_cmd option that reads ffmpeg parameters from a structured
JSON file. The JSON format supports global options, input/output file
specifications with per-file options, and loopback decoder definitions.
The implementation includes a self-contained JSON parser (no external
dependencies) and an argv builder that translates JSON key-value pairs
into the equivalent command-line arguments.
Option values support strings, booleans (true for flags, false to skip),
numbers, arrays (for repeated options like -map), and null (skip).
Keys starting with "/" use FFmpeg's file-loading syntax.
Signed-off-by: Tom Vaughan
---
fftools/Makefile | 1 +
fftools/ffmpeg.c | 14 +
fftools/ffmpeg_json.c | 831 ++++++++++++++++++++++++++++++++++++++++++
fftools/ffmpeg_json.h | 76 ++++
fftools/ffmpeg_opt.c | 12 +
5 files changed, 934 insertions(+)
create mode 100644 fftools/ffmpeg_json.c
create mode 100644 fftools/ffmpeg_json.h
diff --git a/fftools/Makefile b/fftools/Makefile
index 01b16fa8f4..e6eea056eb 100644
--- a/fftools/Makefile
+++ b/fftools/Makefile
@@ -17,6 +17,7 @@ OBJS-ffmpeg += \
fftools/ffmpeg_enc.o \
fftools/ffmpeg_filter.o \
fftools/ffmpeg_hw.o \
+ fftools/ffmpeg_json.o \
fftools/ffmpeg_mux.o \
fftools/ffmpeg_mux_init.o \
fftools/ffmpeg_opt.o \
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index b394243f59..5dcd641700 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -82,6 +82,7 @@
#include "compat/android/binder.h"
#endif
#include "ffmpeg.h"
+#include "ffmpeg_json.h"
#include "ffmpeg_sched.h"
#include "ffmpeg_utils.h"
#include "graph/graphprint.h"
@@ -984,6 +985,8 @@ int main(int argc, char **argv)
int ret;
BenchmarkTimeStamps ti;
+ int json_argc = 0;
+ char **json_argv = NULL;
init_dynload();
@@ -999,6 +1002,15 @@ int main(int argc, char **argv)
show_banner(argc, argv, options);
+ /* Handle -json_cmd <file>: parse JSON file into argc/argv */
+ if (argc == 3 && !strcmp(argv[1], "-json_cmd")) {
+ ret = ffmpeg_json_parse_file(argv[2], &json_argc, &json_argv);
+ if (ret < 0)
+ goto finish;
+ argc = json_argc;
+ argv = json_argv;
+ }
+
sch = sch_alloc();
if (!sch) {
ret = AVERROR(ENOMEM);
@@ -1051,6 +1063,8 @@ finish:
sch_free(&sch);
+ ffmpeg_json_free_argv(json_argc, &json_argv);
+
av_log(NULL, AV_LOG_VERBOSE, "\n");
av_log(NULL, AV_LOG_VERBOSE, "Exiting with exit code %d\n", ret);
diff --git a/fftools/ffmpeg_json.c b/fftools/ffmpeg_json.c
new file mode 100644
index 0000000000..3fdc1884e5
--- /dev/null
+++ b/fftools/ffmpeg_json.c
@@ -0,0 +1,831 @@
+/*
+ * JSON command file support for FFmpeg
+ *
+ * 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 <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libavutil/avstring.h"
+#include "libavutil/avutil.h"
+#include "libavutil/error.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
+
+#include "cmdutils.h"
+#include "ffmpeg.h"
+#include "ffmpeg_json.h"
+
+/* ------------------------------------------------------------------ */
+/* Minimal JSON parser */
+/* ------------------------------------------------------------------ */
+
+/** JSON value type tag. */
+typedef enum {
+ JSON_NULL,
+ JSON_BOOL,
+ JSON_NUMBER,
+ JSON_STRING,
+ JSON_ARRAY,
+ JSON_OBJECT,
+} JsonType;
+
+typedef struct JsonValue JsonValue;
+
+/** Single key/value pair in a JSON object. */
+typedef struct JsonObjectEntry {
+ char *key; /**< property name */
+ JsonValue *value; /**< property value */
+} JsonObjectEntry;
+
+/** Parsed JSON value node. */
+struct JsonValue {
+ JsonType type; /**< discriminator tag */
+ union {
+ int bool_val; /**< JSON_BOOL */
+ double num_val; /**< JSON_NUMBER */
+ char *str_val; /**< JSON_STRING */
+ struct { /**< JSON_ARRAY */
+ JsonValue **items; /**< array elements */
+ int nb_items; /**< element count */
+ } arr;
+ struct { /**< JSON_OBJECT */
+ JsonObjectEntry *entries; /**< key/value pairs */
+ int nb_entries; /**< pair count */
+ } obj;
+ } u;
+};
+
+/* Forward declarations */
+static JsonValue *json_parse_value(const char **p);
+static void json_free(JsonValue *v);
+
+static void skip_whitespace(const char **p)
+{
+ while (**p == ' ' || **p == '\t' || **p == '\n' || **p == '\r')
+ (*p)++;
+}
+
+static JsonValue *json_alloc(JsonType type)
+{
+ JsonValue *v = av_mallocz(sizeof(*v));
+ if (v)
+ v->type = type;
+ return v;
+}
+
+/**
+ * Parse a JSON string literal.
+ * The opening '"' must be the current character at @p *p.
+ *
+ * @param p pointer to the current parse position (advanced past
+ * the closing quote on success)
+ * @return heap-allocated string, or NULL on error
+ */
+static char *json_parse_string_raw(const char **p)
+{
+ const char *s;
+ char *out, *dst;
+ size_t len;
+
+ if (**p != '"')
+ return NULL;
+ (*p)++; /* skip opening quote */
+ s = *p;
+
+ /* First pass: find the closing quote and measure output length */
+ len = 0;
+ while (*s && *s != '"') {
+ if (*s == '\\') {
+ s++;
+ if (!*s)
+ return NULL;
+ if (*s == 'u') {
+ /* \uXXXX – simplified: just store as-is in UTF-8 later */
+ if (!s[1] || !s[2] || !s[3] || !s[4])
+ return NULL;
+ s += 4;
+ len += 4; /* conservative upper bound for UTF-8 */
+ }
+ }
+ len++;
+ s++;
+ }
+ if (*s != '"')
+ return NULL;
+
+ out = av_malloc(len + 1);
+ if (!out)
+ return NULL;
+
+ dst = out;
+ while (**p != '"') {
+ if (**p == '\\') {
+ (*p)++;
+ switch (**p) {
+ case '"': *dst++ = '"'; break;
+ case '\\': *dst++ = '\\'; break;
+ case '/': *dst++ = '/'; break;
+ case 'b': *dst++ = '\b'; break;
+ case 'f': *dst++ = '\f'; break;
+ case 'n': *dst++ = '\n'; break;
+ case 'r': *dst++ = '\r'; break;
+ case 't': *dst++ = '\t'; break;
+ case 'u': {
+ /* Simplified \uXXXX: decode to UTF-8 */
+ unsigned cp = 0;
+ int i;
+ for (i = 0; i < 4; i++) {
+ (*p)++;
+ cp <<= 4;
+ if (**p >= '0' && **p <= '9') cp |= **p - '0';
+ else if (**p >= 'a' && **p <= 'f') cp |= **p - 'a' + 10;
+ else if (**p >= 'A' && **p <= 'F') cp |= **p - 'A' + 10;
+ else { av_free(out); return NULL; }
+ }
+ if (cp < 0x80) {
+ *dst++ = (char)cp;
+ } else if (cp < 0x800) {
+ *dst++ = (char)(0xC0 | (cp >> 6));
+ *dst++ = (char)(0x80 | (cp & 0x3F));
+ } else {
+ *dst++ = (char)(0xE0 | (cp >> 12));
+ *dst++ = (char)(0x80 | ((cp >> 6) & 0x3F));
+ *dst++ = (char)(0x80 | (cp & 0x3F));
+ }
+ break;
+ }
+ default:
+ av_free(out);
+ return NULL;
+ }
+ } else {
+ *dst++ = **p;
+ }
+ (*p)++;
+ }
+ *dst = '\0';
+ (*p)++; /* skip closing quote */
+ return out;
+}
+
+/** Parse a JSON string and wrap it in a JsonValue. */
+static JsonValue *json_parse_string(const char **p)
+{
+ JsonValue *v;
+ char *s = json_parse_string_raw(p);
+ if (!s)
+ return NULL;
+ v = json_alloc(JSON_STRING);
+ if (!v) {
+ av_free(s);
+ return NULL;
+ }
+ v->u.str_val = s;
+ return v;
+}
+
+/** Parse a JSON number literal and return it as a JsonValue. */
+static JsonValue *json_parse_number(const char **p)
+{
+ JsonValue *v;
+ char *end;
+ double d;
+
+ d = strtod(*p, &end);
+ if (end == *p)
+ return NULL;
+ v = json_alloc(JSON_NUMBER);
+ if (!v)
+ return NULL;
+ v->u.num_val = d;
+ *p = end;
+ return v;
+}
+
+/** Parse a JSON array and return it as a JsonValue. */
+static JsonValue *json_parse_array(const char **p)
+{
+ JsonValue *v = json_alloc(JSON_ARRAY);
+ if (!v)
+ return NULL;
+
+ (*p)++; /* skip '[' */
+ skip_whitespace(p);
+
+ if (**p == ']') {
+ (*p)++;
+ return v;
+ }
+
+ for (;;) {
+ JsonValue *item;
+ JsonValue **new_items;
+
+ skip_whitespace(p);
+ item = json_parse_value(p);
+ if (!item)
+ goto fail;
+
+ new_items = av_realloc_array(v->u.arr.items,
+ v->u.arr.nb_items + 1,
+ sizeof(*v->u.arr.items));
+ if (!new_items) {
+ json_free(item);
+ goto fail;
+ }
+ v->u.arr.items = new_items;
+ v->u.arr.items[v->u.arr.nb_items++] = item;
+
+ skip_whitespace(p);
+ if (**p == ']') {
+ (*p)++;
+ return v;
+ }
+ if (**p != ',')
+ goto fail;
+ (*p)++;
+ }
+
+fail:
+ json_free(v);
+ return NULL;
+}
+
+/** Parse a JSON object and return it as a JsonValue. */
+static JsonValue *json_parse_object(const char **p)
+{
+ JsonValue *v = json_alloc(JSON_OBJECT);
+ if (!v)
+ return NULL;
+
+ (*p)++; /* skip '{' */
+ skip_whitespace(p);
+
+ if (**p == '}') {
+ (*p)++;
+ return v;
+ }
+
+ for (;;) {
+ char *key;
+ JsonValue *val;
+ JsonObjectEntry *new_entries;
+
+ skip_whitespace(p);
+ key = json_parse_string_raw(p);
+ if (!key)
+ goto fail;
+
+ skip_whitespace(p);
+ if (**p != ':') {
+ av_free(key);
+ goto fail;
+ }
+ (*p)++;
+
+ skip_whitespace(p);
+ val = json_parse_value(p);
+ if (!val) {
+ av_free(key);
+ goto fail;
+ }
+
+ new_entries = av_realloc_array(v->u.obj.entries,
+ v->u.obj.nb_entries + 1,
+ sizeof(*v->u.obj.entries));
+ if (!new_entries) {
+ av_free(key);
+ json_free(val);
+ goto fail;
+ }
+ v->u.obj.entries = new_entries;
+ v->u.obj.entries[v->u.obj.nb_entries].key = key;
+ v->u.obj.entries[v->u.obj.nb_entries].value = val;
+ v->u.obj.nb_entries++;
+
+ skip_whitespace(p);
+ if (**p == '}') {
+ (*p)++;
+ return v;
+ }
+ if (**p != ',')
+ goto fail;
+ (*p)++;
+ }
+
+fail:
+ json_free(v);
+ return NULL;
+}
+
+/** Dispatch to the appropriate parser based on the next character. */
+static JsonValue *json_parse_value(const char **p)
+{
+ skip_whitespace(p);
+
+ switch (**p) {
+ case '"':
+ return json_parse_string(p);
+ case '{':
+ return json_parse_object(p);
+ case '[':
+ return json_parse_array(p);
+ case 't':
+ if (strncmp(*p, "true", 4) == 0) {
+ JsonValue *v = json_alloc(JSON_BOOL);
+ if (v)
+ v->u.bool_val = 1;
+ *p += 4;
+ return v;
+ }
+ return NULL;
+ case 'f':
+ if (strncmp(*p, "false", 5) == 0) {
+ JsonValue *v = json_alloc(JSON_BOOL);
+ if (v)
+ v->u.bool_val = 0;
+ *p += 5;
+ return v;
+ }
+ return NULL;
+ case 'n':
+ if (strncmp(*p, "null", 4) == 0) {
+ JsonValue *v = json_alloc(JSON_NULL);
+ *p += 4;
+ return v;
+ }
+ return NULL;
+ default:
+ if (**p == '-' || (**p >= '0' && **p <= '9'))
+ return json_parse_number(p);
+ return NULL;
+ }
+}
+
+/** Recursively free a parsed JSON value tree. */
+static void json_free(JsonValue *v)
+{
+ int i;
+ if (!v)
+ return;
+ switch (v->type) {
+ case JSON_STRING:
+ av_free(v->u.str_val);
+ break;
+ case JSON_ARRAY:
+ for (i = 0; i < v->u.arr.nb_items; i++)
+ json_free(v->u.arr.items[i]);
+ av_free(v->u.arr.items);
+ break;
+ case JSON_OBJECT:
+ for (i = 0; i < v->u.obj.nb_entries; i++) {
+ av_free(v->u.obj.entries[i].key);
+ json_free(v->u.obj.entries[i].value);
+ }
+ av_free(v->u.obj.entries);
+ break;
+ default:
+ break;
+ }
+ av_free(v);
+}
+
+/** Look up a key in a JSON object, returning the value or NULL. */
+static JsonValue *json_object_get(const JsonValue *obj, const char *key)
+{
+ int i;
+ if (!obj || obj->type != JSON_OBJECT)
+ return NULL;
+ for (i = 0; i < obj->u.obj.nb_entries; i++) {
+ if (strcmp(obj->u.obj.entries[i].key, key) == 0)
+ return obj->u.obj.entries[i].value;
+ }
+ return NULL;
+}
+
+/* ------------------------------------------------------------------ */
+/* argv builder */
+/* ------------------------------------------------------------------ */
+
+/** Growable argument vector used while building argc/argv. */
+typedef struct ArgvBuilder {
+ char **args; /**< argument strings */
+ int nb_args; /**< current argument count */
+ int capacity; /**< allocated slots in @p args */
+} ArgvBuilder;
+
+/** Append a single argument string to the builder. */
+static int argv_add(ArgvBuilder *b, const char *arg)
+{
+ char **new_args;
+
+ if (b->nb_args >= b->capacity) {
+ int new_cap = b->capacity ? b->capacity * 2 : 32;
+ new_args = av_realloc_array(b->args, new_cap, sizeof(*b->args));
+ if (!new_args)
+ return AVERROR(ENOMEM);
+ b->args = new_args;
+ b->capacity = new_cap;
+ }
+ b->args[b->nb_args] = av_strdup(arg);
+ if (!b->args[b->nb_args])
+ return AVERROR(ENOMEM);
+ b->nb_args++;
+ return 0;
+}
+
+/** Free all strings and reset the builder to empty. */
+static void argv_builder_free(ArgvBuilder *b)
+{
+ int i;
+ for (i = 0; i < b->nb_args; i++)
+ av_free(b->args[i]);
+ av_free(b->args);
+ memset(b, 0, sizeof(*b));
+}
+
+/**
+ * Add a JSON value as a CLI argument string to the argv builder.
+ * Handles strings of any length (no fixed buffer for JSON_STRING).
+ */
+static int argv_add_json_value(ArgvBuilder *b, const JsonValue *v)
+{
+ char buf[64];
+ switch (v->type) {
+ case JSON_STRING:
+ return argv_add(b, v->u.str_val);
+ case JSON_NUMBER:
+ /* Print integers without decimal point where possible */
+ if (v->u.num_val == (int64_t)v->u.num_val)
+ snprintf(buf, sizeof(buf), "%" PRId64, (int64_t)v->u.num_val);
+ else
+ snprintf(buf, sizeof(buf), "%g", v->u.num_val);
+ return argv_add(b, buf);
+ case JSON_BOOL:
+ snprintf(buf, sizeof(buf), "%d", v->u.bool_val);
+ return argv_add(b, buf);
+ default:
+ return AVERROR(EINVAL);
+ }
+}
+
+/**
+ * Build an option key string for the argv builder.
+ *
+ * Keys starting with "/" use FFmpeg's file-loading syntax: -/option filename
+ * reads the option value from a file. In JSON this is represented as:
+ * "/filter_complex": "graph.txt" => -/filter_complex graph.txt
+ *
+ * All other keys are emitted as -key.
+ */
+static int argv_add_option_key(ArgvBuilder *b, const char *key)
+{
+ char buf[256];
+ if (key[0] == '/') {
+ /* File-loading syntax: -/option */
+ snprintf(buf, sizeof(buf), "-%s", key);
+ } else {
+ snprintf(buf, sizeof(buf), "-%s", key);
+ }
+ return argv_add(b, buf);
+}
+
+/**
+ * Emit the options from an object into the argv builder.
+ *
+ * Each key becomes "-key" and each value becomes the argument:
+ * "c:v": "libx264" => -c:v libx264
+ * "y": true => -y
+ * "an": false => (skipped; use "an": true to disable audio)
+ * "map": ["0:v","0:a"] => -map 0:v -map 0:a
+ * "/filter_complex": "f.txt" => -/filter_complex f.txt (load from file)
+ */
+static int emit_options(ArgvBuilder *b, const JsonValue *opts)
+{
+ int i, j, ret;
+
+ if (!opts)
+ return 0;
+ if (opts->type != JSON_OBJECT) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: \"options\" must be an object.\n");
+ return AVERROR(EINVAL);
+ }
+
+ for (i = 0; i < opts->u.obj.nb_entries; i++) {
+ const char *key = opts->u.obj.entries[i].key;
+ const JsonValue *val = opts->u.obj.entries[i].value;
+
+ if (val->type == JSON_BOOL) {
+ if (val->u.bool_val) {
+ /* -flag */
+ ret = argv_add_option_key(b, key);
+ if (ret < 0) return ret;
+ }
+ /* false booleans are intentionally skipped (no-op) */
+ continue;
+ }
+
+ if (val->type == JSON_ARRAY) {
+ /* Repeated option: -key elem0 -key elem1 ... */
+ for (j = 0; j < val->u.arr.nb_items; j++) {
+ ret = argv_add_option_key(b, key);
+ if (ret < 0) return ret;
+
+ ret = argv_add_json_value(b, val->u.arr.items[j]);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: unsupported type in array for option \"%s\".\n", key);
+ return ret;
+ }
+ }
+ continue;
+ }
+
+ if (val->type == JSON_NULL) {
+ continue;
+ }
+
+ /* Scalar: -key value */
+ ret = argv_add_option_key(b, key);
+ if (ret < 0) return ret;
+
+ ret = argv_add_json_value(b, val);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: unsupported value type for option \"%s\".\n", key);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* Public API */
+/* ------------------------------------------------------------------ */
+
+/** @sa ffmpeg_json_parse_file() in ffmpeg_json.h for full documentation. */
+int ffmpeg_json_parse_file(const char *filename, int *out_argc, char ***out_argv)
+{
+ FILE *f = NULL;
+ long fsize;
+ char *data = NULL;
+ const char *p;
+ JsonValue *root = NULL;
+ JsonValue *global_opts, *inputs, *outputs, *decoders;
+ ArgvBuilder b = { 0 };
+ int ret, i;
+
+ *out_argc = 0;
+ *out_argv = NULL;
+
+ /* Read file contents */
+ f = fopen(filename, "rb");
+ if (!f) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: cannot open file '%s': %s\n", filename, strerror(errno));
+ return AVERROR(errno);
+ }
+
+ if (fseek(f, 0, SEEK_END) < 0) {
+ ret = AVERROR(errno);
+ goto fail;
+ }
+ fsize = ftell(f);
+ if (fsize < 0 || fsize > 100 * 1024 * 1024) { /* 100 MB sanity limit */
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: file '%s' is too large or unreadable.\n", filename);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ if (fseek(f, 0, SEEK_SET) < 0) {
+ ret = AVERROR(errno);
+ goto fail;
+ }
+
+ data = av_malloc(fsize + 1);
+ if (!data) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ if (fread(data, 1, fsize, f) != (size_t)fsize) {
+ av_log(NULL, AV_LOG_ERROR, "JSON: failed to read '%s'.\n", filename);
+ ret = AVERROR(EIO);
+ goto fail;
+ }
+ data[fsize] = '\0';
+ fclose(f);
+ f = NULL;
+
+ /* Parse JSON */
+ p = data;
+ root = json_parse_value(&p);
+ if (!root || root->type != JSON_OBJECT) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: failed to parse '%s' – root must be an object.\n", filename);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ /* Verify there are no trailing non-whitespace characters */
+ skip_whitespace(&p);
+ if (*p != '\0') {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: trailing content after root object in '%s'.\n", filename);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ /* Build argv: start with program name */
+ ret = argv_add(&b, "ffmpeg");
+ if (ret < 0) goto fail;
+
+ /* 1. Global options */
+ global_opts = json_object_get(root, "global_options");
+ if (global_opts) {
+ ret = emit_options(&b, global_opts);
+ if (ret < 0) goto fail;
+ }
+
+ /* 2. Input files: options then -i url */
+ inputs = json_object_get(root, "inputs");
+ if (inputs) {
+ if (inputs->type != JSON_ARRAY) {
+ av_log(NULL, AV_LOG_ERROR, "JSON: \"inputs\" must be an array.\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ for (i = 0; i < inputs->u.arr.nb_items; i++) {
+ JsonValue *input = inputs->u.arr.items[i];
+ JsonValue *url, *opts;
+
+ if (input->type != JSON_OBJECT) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: each input must be an object.\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ url = json_object_get(input, "url");
+ if (!url || url->type != JSON_STRING) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: input %d missing \"url\" string.\n", i);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ /* Emit input options before -i */
+ opts = json_object_get(input, "options");
+ ret = emit_options(&b, opts);
+ if (ret < 0) goto fail;
+
+ ret = argv_add(&b, "-i");
+ if (ret < 0) goto fail;
+ ret = argv_add(&b, url->u.str_val);
+ if (ret < 0) goto fail;
+ }
+ }
+
+ /* 3. Output files: options then url */
+ outputs = json_object_get(root, "outputs");
+ if (outputs) {
+ if (outputs->type != JSON_ARRAY) {
+ av_log(NULL, AV_LOG_ERROR, "JSON: \"outputs\" must be an array.\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ for (i = 0; i < outputs->u.arr.nb_items; i++) {
+ JsonValue *output = outputs->u.arr.items[i];
+ JsonValue *url, *opts;
+
+ if (output->type != JSON_OBJECT) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: each output must be an object.\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ url = json_object_get(output, "url");
+ if (!url || url->type != JSON_STRING) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: output %d missing \"url\" string.\n", i);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ /* Emit output options before the output url */
+ opts = json_object_get(output, "options");
+ ret = emit_options(&b, opts);
+ if (ret < 0) goto fail;
+
+ ret = argv_add(&b, url->u.str_val);
+ if (ret < 0) goto fail;
+ }
+ }
+
+ /* 4. Loopback decoders: options then -dec name */
+ decoders = json_object_get(root, "decoders");
+ if (decoders) {
+ if (decoders->type != JSON_ARRAY) {
+ av_log(NULL, AV_LOG_ERROR, "JSON: \"decoders\" must be an array.\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ for (i = 0; i < decoders->u.arr.nb_items; i++) {
+ JsonValue *decoder = decoders->u.arr.items[i];
+ JsonValue *name, *opts;
+
+ if (decoder->type != JSON_OBJECT) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: each decoder must be an object.\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ name = json_object_get(decoder, "name");
+ if (!name || name->type != JSON_STRING) {
+ av_log(NULL, AV_LOG_ERROR,
+ "JSON: decoder %d missing \"name\" string.\n", i);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ /* Emit decoder options before -dec */
+ opts = json_object_get(decoder, "options");
+ ret = emit_options(&b, opts);
+ if (ret < 0) goto fail;
+
+ ret = argv_add(&b, "-dec");
+ if (ret < 0) goto fail;
+ ret = argv_add(&b, name->u.str_val);
+ if (ret < 0) goto fail;
+ }
+ }
+
+ /* Add NULL sentinel for execv-style usage */
+ if (b.nb_args >= b.capacity) {
+ char **new_args = av_realloc_array(b.args, b.nb_args + 1, sizeof(*b.args));
+ if (!new_args) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ b.args = new_args;
+ }
+ b.args[b.nb_args] = NULL;
+
+ *out_argc = b.nb_args;
+ *out_argv = b.args;
+
+ /* Log the constructed command line */
+ {
+ int k;
+ av_log(NULL, AV_LOG_INFO, "JSON: constructed command line:\n ");
+ for (k = 0; k < b.nb_args; k++)
+ av_log(NULL, AV_LOG_INFO, " %s", b.args[k]);
+ av_log(NULL, AV_LOG_INFO, "\n");
+ }
+
+ json_free(root);
+ av_free(data);
+ return 0;
+
+fail:
+ if (f)
+ fclose(f);
+ json_free(root);
+ av_free(data);
+ argv_builder_free(&b);
+ return ret;
+}
+
+/** @sa ffmpeg_json_free_argv() in ffmpeg_json.h for full documentation. */
+void ffmpeg_json_free_argv(int argc, char ***argv)
+{
+ int i;
+ if (!argv || !*argv)
+ return;
+ for (i = 0; i < argc; i++)
+ av_free((*argv)[i]);
+ av_free(*argv);
+ *argv = NULL;
+}
diff --git a/fftools/ffmpeg_json.h b/fftools/ffmpeg_json.h
new file mode 100644
index 0000000000..d509f142d7
--- /dev/null
+++ b/fftools/ffmpeg_json.h
@@ -0,0 +1,76 @@
+/*
+ * JSON command file support for FFmpeg
+ *
+ * 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
+ */
+
+#ifndef FFTOOLS_FFMPEG_JSON_H
+#define FFTOOLS_FFMPEG_JSON_H
+
+/**
+ * Parse a JSON command file and convert it to an argc/argv pair
+ * compatible with ffmpeg_parse_options().
+ *
+ * The JSON file should have the following structure:
+ * {
+ * "global_options": { "option_name": "value", ... },
+ * "inputs": [
+ * { "url": "input_file", "options": { "option_name": "value", ... } },
+ * ...
+ * ],
+ * "outputs": [
+ * { "url": "output_file", "options": { "option_name": "value", ... } },
+ * ...
+ * ],
+ * "decoders": [
+ * { "name": "decoder_name", "options": { ... } },
+ * ...
+ * ]
+ * }
+ *
+ * Option values can be:
+ * - string: added as -option value (no length limit)
+ * - true: added as -option (flag)
+ * - false: skipped (no-op); to negate a boolean, use the "no"-prefixed
+ * name with true, e.g. "noautorotate": true
+ * - number: converted to string and added as -option value
+ * - array: option is repeated for each element, e.g. "map": ["0:v","0:a"]
+ * becomes -map 0:v -map 0:a
+ * - null: skipped
+ *
+ * Keys starting with "/" use FFmpeg's file-loading syntax:
+ * "/filter_complex": "graph.txt" => -/filter_complex graph.txt
+ *
+ * All fields except the root object are optional.
+ *
+ * @param filename Path to the JSON file
+ * @param[out] argc Number of arguments in the constructed argv
+ * @param[out] argv Constructed argument vector (caller must free with
+ * ffmpeg_json_free_argv())
+ * @return 0 on success, negative AVERROR code on failure
+ */
+int ffmpeg_json_parse_file(const char *filename, int *argc, char ***argv);
+
+/**
+ * Free an argv array previously allocated by ffmpeg_json_parse_file().
+ *
+ * @param argc Number of arguments
+ * @param argv Pointer to the argument vector (set to NULL on return)
+ */
+void ffmpeg_json_free_argv(int argc, char ***argv);
+
+#endif /* FFTOOLS_FFMPEG_JSON_H */
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 48e6816c19..abdc81988c 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -1610,6 +1610,15 @@ static int opt_adrift_threshold(void *optctx, const char *opt, const char *arg)
}
#endif
+static int opt_json_cmd(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_ERROR,
+ "-json_cmd requires exactly one argument: the path to a JSON file\n"
+ "containing ffmpeg commands and parameters. No other options are allowed.\n"
+ "Usage: ffmpeg -json_cmd <file.json>\n");
+ return AVERROR(EINVAL);
+}
+
static const char *const alt_channel_layout[] = { "ch_layout", NULL};
static const char *const alt_codec[] = { "c", "acodec", "vcodec", "scodec", "dcodec", NULL };
static const char *const alt_filter[] = { "af", "vf", NULL };
@@ -1622,6 +1631,9 @@ static const char *const alt_tag[] = { "atag", "vtag", "stag", NULL }
const OptionDef options[] = {
/* main options */
CMDUTILS_COMMON_OPTIONS
+ { "json_cmd", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXIT,
+ { .func_arg = opt_json_cmd },
+ "read options from a JSON command file", "file" },
{ "f", OPT_TYPE_STRING, OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,
{ .off = OFFSET(format) },
"force container format (auto-detected otherwise)", "fmt" },
--
2.49.0
2
7
[PR] avdevice/pulse_audio_dec: validate sample spec before use (PR #23525)
by add-uos-ffmpeg 18 Jun '26
by add-uos-ffmpeg 18 Jun '26
18 Jun '26
PR #23525 opened by add-uos-ffmpeg
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23525
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23525.patch
ff_codec_id_to_pulse_format() returns PA_SAMPLE_INVALID for
unsupported codecs (e.g. AAC, FLAC, Opus). Without validation,
the invalid format propagates to pa_frame_size() and other PA
calls, causing assertion failures or division-by-zero.
Add pa_sample_spec_valid() check, matching the existing guard
in pulse_audio_enc.c.
Signed-off-by: zhanghongyuan <zhanghongyuan(a)uniontech.com>
# Summary of changes
Add pa_sample_spec_valid() check in pulse_read_header() to reject unsupported codecs with a clean error instead of crashing.
**1. unsupport acodec may crush**
`$ ffmpeg -hide_banner -loglevel verbose -f pulse -acodec aac -i default -t 0.5 -f null - 2>&1`
Assertion 'pa_sample_spec_valid(spec)' failed at ../src/pulse/sample.c:67, function pa_frame_size(). Aborting.
已放弃(核心已转储)
`$ coredumpctl list | grep ffmpeg`
Hint: You are currently not seeing messages from other users and the system.
Users in groups 'adm', 'systemd-journal' can see all messages.
Pass -q to turn off this notice.
Thu 2026-06-18 10:54:58 CST 113874 1000 1000 SIGABRT present /usr/bin/ffmpeg 10.0M
Thu 2026-06-18 10:59:41 CST 115966 1000 1000 SIGABRT present /usr/bin/ffmpeg 10.0M
Thu 2026-06-18 11:25:34 CST 126047 1000 1000 SIGABRT present /usr/bin/ffmpeg 10.0M
Thu 2026-06-18 13:28:16 CST 18830 1000 1000 SIGABRT present /usr/bin/ffmpeg 10.0M
Thu 2026-06-18 13:29:30 CST 18937 1000 1000 SIGABRT present /usr/bin/ffmpeg 10.0M
Thu 2026-06-18 13:50:29 CST 24446 1000 1000 SIGABRT present /usr/bin/ffmpeg 10.0M
**2. after fix**
`$ ffmpeg -hide_banner -f pulse -acodec aac -i default -t 0.5 -f null - 2>&1`
[in#0 @ 0x55bd82919a00] Invalid sample spec.
[in#0 @ 0x55bd82919700] Error opening input: Invalid argument
Error opening input file default.
Error opening input files: Invalid argument
Exiting with exit code -22
as same as 'pulse_audio_enc.c'
`$ ffmpeg -hide_banner -f lavfi -i anullsrc=r=48000:cl=stereo -acodec aac -t 0.5 -f pulse -y default 2>&1`
Input #0, lavfi, from 'anullsrc=r=48000:cl=stereo':
Duration: N/A, start: 0.000000, bitrate: 768 kb/s
Stream #0:0: Audio: pcm_u8, 48000 Hz, stereo, u8, 768 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (pcm_u8 (native) -> aac (native))
Press [q] to stop, [?] for help
[PulseAudio outdev @ 0x55b7ad2c0880] Invalid sample spec.
[out#0/pulse @ 0x55b7ad2c0500] Could not write header (incorrect codec parameters ?): Invalid argument
[af#0:0 @ 0x55b7ad2c1500] Error sending frames to consumers: Invalid argument
[af#0:0 @ 0x55b7ad2c1500] Task finished with error code: -22 (Invalid argument)
[af#0:0 @ 0x55b7ad2c1500] Terminating thread with return code -22 (Invalid argument)
[out#0/pulse @ 0x55b7ad2c0500] Nothing was written into output file, because at least one of its streams received no packets.
size= 0KiB time=N/A bitrate=N/A speed=N/A elapsed=0:00:00.00
[aac @ 0x55b7ad2c0fc0] Qavg: nan
Conversion failed!
From 98524b17a9fed0b1fc524457db2e9fa2f4073a1c Mon Sep 17 00:00:00 2001
From: zhanghongyuan <zhanghongyuan(a)uniontech.com>
Date: Thu, 18 Jun 2026 13:19:31 +0800
Subject: [PATCH] avdevice/pulse_audio_dec: validate sample spec before use
ff_codec_id_to_pulse_format() returns PA_SAMPLE_INVALID for
unsupported codecs (e.g. AAC, FLAC, Opus). Without validation,
the invalid format propagates to pa_frame_size() and other PA
calls, causing assertion failures or division-by-zero.
Add pa_sample_spec_valid() check, matching the existing guard
in pulse_audio_enc.c.
Signed-off-by: zhanghongyuan <zhanghongyuan(a)uniontech.com>
---
libavdevice/pulse_audio_dec.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libavdevice/pulse_audio_dec.c b/libavdevice/pulse_audio_dec.c
index 32be18e7dd..fe60d02b5d 100644
--- a/libavdevice/pulse_audio_dec.c
+++ b/libavdevice/pulse_audio_dec.c
@@ -156,6 +156,11 @@ static av_cold int pulse_read_header(AVFormatContext *s)
pa_channel_map_init_extend(&cmap, pd->channels, PA_CHANNEL_MAP_WAVEEX);
+ if (!pa_sample_spec_valid(&ss)) {
+ av_log(s, AV_LOG_ERROR, "Invalid sample spec.\n");
+ return AVERROR(EINVAL);
+ }
+
st = avformat_new_stream(s, NULL);
if (!st) {
--
2.52.0
1
0
PR #23524 opened by Ramiro Polla (ramiro)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23524
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23524.patch
`libswscale/aarch64/ops_entries.c` has diverged a bit since !22678 has stalled. This PR fixes the file, and I'll create another PR to make it run with fate.
From dea830187b189e9c9fe3c9034964c00bcde6b82d Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Tue, 16 Jun 2026 13:49:03 +0200
Subject: [PATCH 1/2] swscale/aarch64/ops: convert single-component packed
read/write to planar
b488ee55 relaxed the check and stopped taking the number of components
into account. This led to the generation of duplicate read/write
functions for single component packed/planar.
ops_entries.c wasn't regenerated to take this into account; instead
some conversions were no longer being supported for the neon backend.
---
libswscale/aarch64/ops_impl_conv.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/libswscale/aarch64/ops_impl_conv.c b/libswscale/aarch64/ops_impl_conv.c
index 98cb89edbc..479afbb3ab 100644
--- a/libswscale/aarch64/ops_impl_conv.c
+++ b/libswscale/aarch64/ops_impl_conv.c
@@ -88,9 +88,9 @@ static int convert_to_aarch64_impl(SwsContext *ctx, const SwsOpList *ops, int n,
out->op = AARCH64_SWS_OP_READ_NIBBLE;
else if (op->rw.frac == 3)
out->op = AARCH64_SWS_OP_READ_BIT;
- else if (op->rw.mode == SWS_RW_PACKED)
+ else if (op->rw.mode == SWS_RW_PACKED && op->rw.elems > 1)
out->op = AARCH64_SWS_OP_READ_PACKED;
- else if (op->rw.mode == SWS_RW_PLANAR)
+ else if (op->rw.mode == SWS_RW_PACKED || op->rw.mode == SWS_RW_PLANAR)
out->op = AARCH64_SWS_OP_READ_PLANAR;
else
return AVERROR(ENOTSUP);
@@ -106,9 +106,9 @@ static int convert_to_aarch64_impl(SwsContext *ctx, const SwsOpList *ops, int n,
out->op = AARCH64_SWS_OP_WRITE_NIBBLE;
else if (op->rw.frac == 3)
out->op = AARCH64_SWS_OP_WRITE_BIT;
- else if (op->rw.mode == SWS_RW_PACKED)
+ else if (op->rw.mode == SWS_RW_PACKED && op->rw.elems > 1)
out->op = AARCH64_SWS_OP_WRITE_PACKED;
- else if (op->rw.mode == SWS_RW_PLANAR)
+ else if (op->rw.mode == SWS_RW_PACKED || op->rw.mode == SWS_RW_PLANAR)
out->op = AARCH64_SWS_OP_WRITE_PLANAR;
else
return AVERROR(ENOTSUP);
--
2.52.0
From 7c50b687cbfb3368bc32ef1a0863ca2065152ce8 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Tue, 16 Jun 2026 14:24:50 +0200
Subject: [PATCH 2/2] swscale/aarch64/ops: skip filtering ops lists when
generating ops_entries.c
sws_ops_aarch64 would still register operations that came before the
filtering ops (which are unsupported).
---
libswscale/aarch64/ops_entries.c | 7 -------
libswscale/tests/sws_ops_aarch64.c | 16 ++++++++++++++++
2 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/libswscale/aarch64/ops_entries.c b/libswscale/aarch64/ops_entries.c
index 04a665a9f1..4b8e4bbae1 100644
--- a/libswscale/aarch64/ops_entries.c
+++ b/libswscale/aarch64/ops_entries.c
@@ -108,7 +108,6 @@
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0213, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1001 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0213, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1001 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0231, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1011 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0312, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1101 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0312, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1101 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0312, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1101 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0321, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
@@ -247,7 +246,6 @@
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 16, .type = AARCH64_PIXEL_U16, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 16, .type = AARCH64_PIXEL_U16, .mask = 0x0010 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 16, .type = AARCH64_PIXEL_U16, .mask = 0x1000 },
-{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U8, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U8, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U8, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0011 },
{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U8, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
@@ -256,8 +254,6 @@
{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U8, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U8, .block_size = 16, .type = AARCH64_PIXEL_U16, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U16, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U16, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0010 },
-{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U16, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0100 },
{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U16, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U16, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x1110 },
{ .op = AARCH64_SWS_OP_CONVERT, .to_type = AARCH64_PIXEL_U16, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
@@ -312,7 +308,6 @@
{ .op = AARCH64_SWS_OP_MAX, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0011 },
{ .op = AARCH64_SWS_OP_MAX, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_MAX, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1001 },
-{ .op = AARCH64_SWS_OP_MAX, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1110 },
{ .op = AARCH64_SWS_OP_MAX, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_SCALE, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_SCALE, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0111 },
@@ -372,11 +367,9 @@
{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0x3ff0, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1001 },
{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0x5023, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0x5032, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0x5203, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0x5230, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0x5ff0, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1001 },
{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0x5fff, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1000 },
-{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0xf000, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0xf023, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0xf032, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_DITHER, .dither.y_offset = 0xf203, .dither.size_log2 = 4, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
diff --git a/libswscale/tests/sws_ops_aarch64.c b/libswscale/tests/sws_ops_aarch64.c
index 4fa10c7bb0..3319af0536 100644
--- a/libswscale/tests/sws_ops_aarch64.c
+++ b/libswscale/tests/sws_ops_aarch64.c
@@ -77,6 +77,22 @@ static int register_op(SwsContext *ctx, void *opaque, SwsOpList *ops)
struct AVTreeNode **root = (struct AVTreeNode **) opaque;
int ret;
+ /* Skip ops lists which include filtering, since this is still not
+ * supported. */
+ for (int i = 0; i < ops->num_ops; i++) {
+ const SwsOp *op = &ops->ops[i];
+ switch (op->op) {
+ case SWS_OP_READ:
+ case SWS_OP_WRITE:
+ if (op->rw.filter.op)
+ return 0;
+ break;
+ case SWS_OP_FILTER_H:
+ case SWS_OP_FILTER_V:
+ return 0;
+ }
+ }
+
/* Make on-stack copy of `ops` to iterate over */
SwsOpList rest = *ops;
/* Use at most two full vregs during the widest precision section */
--
2.52.0
1
0
18 Jun '26
PR #23523 opened by Ramiro Polla (ramiro)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23523
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23523.patch
From e6b8fa45e091d3ecec53a4fc336ccce00a57649c Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Sat, 13 Jun 2026 00:51:50 +0200
Subject: [PATCH 1/2] swscale/uops: skip offset from unity detection for linear
There is no easy optimization that can be triggered by knowing that the
offset is exactly 1. This led to identical functions being instantiated
for different params.
---
libswscale/uops.c | 2 +-
libswscale/uops_macros.h | 34 ++++++++++------------------------
tests/ref/fate/sws-ops-list | 2 +-
3 files changed, 12 insertions(+), 26 deletions(-)
diff --git a/libswscale/uops.c b/libswscale/uops.c
index b73aedb6e1..f527afb0ef 100644
--- a/libswscale/uops.c
+++ b/libswscale/uops.c
@@ -712,7 +712,7 @@ static int translate_linear_op(SwsContext *ctx, SwsUOpList *ops,
uop.data.mat4[i][j] = px;
if (k.num == 0)
uop.par.lin.zero |= SWS_MASK(i, j);
- else if (k.num == k.den)
+ else if (j < 4 && k.num == k.den)
uop.par.lin.one |= SWS_MASK(i, j);
else if (j < 4 && (!bitexact || exact_prod(uop.type, px, input, j)))
exact |= SWS_MASK(i, j);
diff --git a/libswscale/uops_macros.h b/libswscale/uops_macros.h
index f63d046aa3..3a7ca8ece9 100644
--- a/libswscale/uops_macros.h
+++ b/libswscale/uops_macros.h
@@ -1142,18 +1142,15 @@
#define SWS_FOR_F32_CLEAR(MACRO, ...)
#define SWS_FOR_STRUCT_F32_CLEAR(MACRO, ...)
#define SWS_FOR_F32_LINEAR(MACRO, ...) \
+ MACRO(__VA_ARGS__, f32_linear_x_xxx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x1, 0x41040, 0xbefa8) \
MACRO(__VA_ARGS__, f32_linear_x_x000x , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x1, 0x41040, 0xbefae) \
MACRO(__VA_ARGS__, f32_linear_x_xxx00 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x1, 0x41040, 0xbefb8) \
- MACRO(__VA_ARGS__, f32_linear_x_xxx01 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x1, 0x41050, 0xbefa8) \
- MACRO(__VA_ARGS__, f32_linear_x_x0001 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x1, 0x41050, 0xbefae) \
MACRO(__VA_ARGS__, f32_linear_y_0x000 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x2, 0x41001, 0xbefbe) \
MACRO(__VA_ARGS__, f32_linear_xyz_xxx0x_xxx0x_xxx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x7, 0x40000, 0xba108) \
MACRO(__VA_ARGS__, f32_linear_xyz_x0x0x_xxx0x_xx00x , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x7, 0x40000, 0xbb10a) \
MACRO(__VA_ARGS__, f32_linear_xyz_xxx00_xxx0x_xxx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x7, 0x40000, 0xba118) \
MACRO(__VA_ARGS__, f32_linear_xyz_x000x_0x00x_00x0x , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x7, 0x40000, 0xbadae) \
MACRO(__VA_ARGS__, f32_linear_xyz_x0000_0x000_00x00 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x7, 0x40000, 0xbefbe) \
- MACRO(__VA_ARGS__, f32_linear_xyz_x0001_0x00x_00x01 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x7, 0x44010, 0xbadae) \
- MACRO(__VA_ARGS__, f32_linear_xyz_x0001_0x001_00x01 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x7, 0x44210, 0xbadae) \
MACRO(__VA_ARGS__, f32_linear_xyz_10x0x_1xx0x_1x00x , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x7, 0x40421, 0xbb10a) \
MACRO(__VA_ARGS__, f32_linear_w_000x0 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x8, 0x01041, 0xbefbe) \
MACRO(__VA_ARGS__, f32_linear_xw_x000x_000x0 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0x9, 0x01040, 0xbefae) \
@@ -1162,18 +1159,15 @@
MACRO(__VA_ARGS__, f32_linear_xyzw_x0x0x_xxx0x_xx00x_000x0 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0xf, 0x00000, 0xbb10a) \
MACRO(__VA_ARGS__, f32_linear_xyzw_x0000_0x000_00x00_000x0 , SWS_PIXEL_F32, SWS_UOP_LINEAR , 0xf, 0x00000, 0xbefbe)
#define SWS_FOR_STRUCT_F32_LINEAR(MACRO, ...) \
+ MACRO(__VA_ARGS__, f32_linear_x_xxx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefa8) \
MACRO(__VA_ARGS__, f32_linear_x_x000x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefae) \
MACRO(__VA_ARGS__, f32_linear_x_xxx00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8) \
- MACRO(__VA_ARGS__, f32_linear_x_xxx01 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x1, .par.lin.one = 0x41050, .par.lin.zero = 0xbefa8) \
- MACRO(__VA_ARGS__, f32_linear_x_x0001 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x1, .par.lin.one = 0x41050, .par.lin.zero = 0xbefae) \
MACRO(__VA_ARGS__, f32_linear_y_0x000 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x2, .par.lin.one = 0x41001, .par.lin.zero = 0xbefbe) \
MACRO(__VA_ARGS__, f32_linear_xyz_xxx0x_xxx0x_xxx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba108) \
MACRO(__VA_ARGS__, f32_linear_xyz_x0x0x_xxx0x_xx00x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbb10a) \
MACRO(__VA_ARGS__, f32_linear_xyz_xxx00_xxx0x_xxx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba118) \
MACRO(__VA_ARGS__, f32_linear_xyz_x000x_0x00x_00x0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbadae) \
MACRO(__VA_ARGS__, f32_linear_xyz_x0000_0x000_00x00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbefbe) \
- MACRO(__VA_ARGS__, f32_linear_xyz_x0001_0x00x_00x01 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x7, .par.lin.one = 0x44010, .par.lin.zero = 0xbadae) \
- MACRO(__VA_ARGS__, f32_linear_xyz_x0001_0x001_00x01 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x7, .par.lin.one = 0x44210, .par.lin.zero = 0xbadae) \
MACRO(__VA_ARGS__, f32_linear_xyz_10x0x_1xx0x_1x00x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x7, .par.lin.one = 0x40421, .par.lin.zero = 0xbb10a) \
MACRO(__VA_ARGS__, f32_linear_w_000x0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x8, .par.lin.one = 0x1041, .par.lin.zero = 0xbefbe) \
MACRO(__VA_ARGS__, f32_linear_xw_x000x_000x0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0x9, .par.lin.one = 0x1040, .par.lin.zero = 0xbefae) \
@@ -1182,6 +1176,10 @@
MACRO(__VA_ARGS__, f32_linear_xyzw_x0x0x_xxx0x_xx00x_000x0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0xf, .par.lin.one = 0x0, .par.lin.zero = 0xbb10a) \
MACRO(__VA_ARGS__, f32_linear_xyzw_x0000_0x000_00x00_000x0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR , .mask = 0xf, .par.lin.one = 0x0, .par.lin.zero = 0xbefbe)
#define SWS_FOR_F32_LINEAR_FMA(MACRO, ...) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_xxx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefa8, 0xfffe8) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_XXx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefa8, 0xfffeb) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_xXX0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefa8, 0xfffee) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_XXX0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefa8, 0xfffef) \
MACRO(__VA_ARGS__, f32_linear_fma_x_x000x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefae, 0xfffee) \
MACRO(__VA_ARGS__, f32_linear_fma_x_X000x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefae, 0xfffef) \
MACRO(__VA_ARGS__, f32_linear_fma_x_xxx00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xffff8) \
@@ -1189,12 +1187,6 @@
MACRO(__VA_ARGS__, f32_linear_fma_x_XxX00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xffffd) \
MACRO(__VA_ARGS__, f32_linear_fma_x_xXX00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xffffe) \
MACRO(__VA_ARGS__, f32_linear_fma_x_XXX00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xfffff) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_xxx01 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41050, 0xbefa8, 0xffff8) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_XXx01 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41050, 0xbefa8, 0xffffb) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_xXX01 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41050, 0xbefa8, 0xffffe) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_XXX01 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41050, 0xbefa8, 0xfffff) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_x0001 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41050, 0xbefae, 0xffffe) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_X0001 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41050, 0xbefae, 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_y_0x000 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x2, 0x41001, 0xbefbe, 0xfffbf) \
MACRO(__VA_ARGS__, f32_linear_fma_y_0X000 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x2, 0x41001, 0xbefbe, 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_xxx0x_xxx0x_xxx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba108, 0xfa108) \
@@ -1215,8 +1207,6 @@
MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0000_0X000_00X00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbefbe, 0xffffe) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0000_0X000_00x00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbefbe, 0xfefff) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0000_0X000_00X00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbefbe, 0xfffff) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0001_0X00x_00X01 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x44010, 0xbadae, 0xffdff) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0001_0X001_00X01 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x44210, 0xbadae, 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_10X0x_1XX0x_1X00x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40421, 0xbb10a, 0xfbdef) \
MACRO(__VA_ARGS__, f32_linear_fma_w_000X0 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x8, 0x01041, 0xbefbe, 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xw_x000x_000x0 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x9, 0x01040, 0xbefae, 0xbffee) \
@@ -1228,6 +1218,10 @@
MACRO(__VA_ARGS__, f32_linear_fma_xyzw_X0X0x_XXX0x_XX00x_000X0, SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0xf, 0x00000, 0xbb10a, 0xfbdef) \
MACRO(__VA_ARGS__, f32_linear_fma_xyzw_X0000_0X000_00X00_000X0, SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0xf, 0x00000, 0xbefbe, 0xfffff)
#define SWS_FOR_STRUCT_F32_LINEAR_FMA(MACRO, ...) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_xxx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffe8) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_XXx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffeb) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_xXX0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffee) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_XXX0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffef) \
MACRO(__VA_ARGS__, f32_linear_fma_x_x000x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefae, .par.lin.exact = 0xfffee) \
MACRO(__VA_ARGS__, f32_linear_fma_x_X000x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefae, .par.lin.exact = 0xfffef) \
MACRO(__VA_ARGS__, f32_linear_fma_x_xxx00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xffff8) \
@@ -1235,12 +1229,6 @@
MACRO(__VA_ARGS__, f32_linear_fma_x_XxX00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xffffd) \
MACRO(__VA_ARGS__, f32_linear_fma_x_xXX00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xffffe) \
MACRO(__VA_ARGS__, f32_linear_fma_x_XXX00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xfffff) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_xxx01 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41050, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xffff8) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_XXx01 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41050, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xffffb) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_xXX01 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41050, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xffffe) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_XXX01 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41050, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffff) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_x0001 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41050, .par.lin.zero = 0xbefae, .par.lin.exact = 0xffffe) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_X0001 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41050, .par.lin.zero = 0xbefae, .par.lin.exact = 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_y_0x000 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x2, .par.lin.one = 0x41001, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfffbf) \
MACRO(__VA_ARGS__, f32_linear_fma_y_0X000 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x2, .par.lin.one = 0x41001, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_xxx0x_xxx0x_xxx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba108, .par.lin.exact = 0xfa108) \
@@ -1261,8 +1249,6 @@
MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0000_0X000_00X00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xffffe) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0000_0X000_00x00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfefff) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0000_0X000_00X00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfffff) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0001_0X00x_00X01 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x44010, .par.lin.zero = 0xbadae, .par.lin.exact = 0xffdff) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0001_0X001_00X01 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x44210, .par.lin.zero = 0xbadae, .par.lin.exact = 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_10X0x_1XX0x_1X00x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40421, .par.lin.zero = 0xbb10a, .par.lin.exact = 0xfbdef) \
MACRO(__VA_ARGS__, f32_linear_fma_w_000X0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x8, .par.lin.one = 0x1041, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xw_x000x_000x0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x9, .par.lin.one = 0x1040, .par.lin.zero = 0xbefae, .par.lin.exact = 0xbffee) \
diff --git a/tests/ref/fate/sws-ops-list b/tests/ref/fate/sws-ops-list
index 68a1fc1105..6b4003121a 100644
--- a/tests/ref/fate/sws-ops-list
+++ b/tests/ref/fate/sws-ops-list
@@ -1 +1 @@
-e2f26cb6df5c11015e613016bb1a004a
+bbe27c8c324f08d933f6397f5fb96650
--
2.52.0
From 3f7421f89f3679ae1354039567966582e96d4546 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Sat, 13 Jun 2026 01:41:47 +0200
Subject: [PATCH 2/2] swscale/uops: relax detection of exact computations in
linear
The first computation in a linear row doesn't have anything to
accumulate to, so a multiply-accumulate instruction won't be used
either way. This led to identical functions being instantiated for
different params.
---
libswscale/uops.c | 5 +++-
libswscale/uops_macros.h | 54 ++++++++++++++++------------------------
2 files changed, 26 insertions(+), 33 deletions(-)
diff --git a/libswscale/uops.c b/libswscale/uops.c
index f527afb0ef..1bd3e2f763 100644
--- a/libswscale/uops.c
+++ b/libswscale/uops.c
@@ -706,6 +706,7 @@ static int translate_linear_op(SwsContext *ctx, SwsUOpList *ops,
for (int i = 0; i < 4; i++) {
if (SWS_OP_NEEDED(op, i) && (op->lin.mask & SWS_MASK_ROW(i)))
uop.mask |= SWS_COMP(i);
+ bool nonzero = (op->lin.m[i][4].num != 0);
for (int j = 0; j < 5; j++) {
const AVRational k = op->lin.m[i][j];
const SwsPixel px = Q2PIXEL(k);
@@ -714,8 +715,10 @@ static int translate_linear_op(SwsContext *ctx, SwsUOpList *ops,
uop.par.lin.zero |= SWS_MASK(i, j);
else if (j < 4 && k.num == k.den)
uop.par.lin.one |= SWS_MASK(i, j);
- else if (j < 4 && (!bitexact || exact_prod(uop.type, px, input, j)))
+ else if (j < 4 && nonzero && (!bitexact || exact_prod(uop.type, px, input, j)))
exact |= SWS_MASK(i, j);
+ if (k.num != 0)
+ nonzero = true;
}
}
diff --git a/libswscale/uops_macros.h b/libswscale/uops_macros.h
index 3a7ca8ece9..3c4d6b6a3e 100644
--- a/libswscale/uops_macros.h
+++ b/libswscale/uops_macros.h
@@ -1183,12 +1183,10 @@
MACRO(__VA_ARGS__, f32_linear_fma_x_x000x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefae, 0xfffee) \
MACRO(__VA_ARGS__, f32_linear_fma_x_X000x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefae, 0xfffef) \
MACRO(__VA_ARGS__, f32_linear_fma_x_xxx00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xffff8) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_XXx00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xffffb) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_XxX00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xffffd) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_xXx00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xffffa) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_xxX00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xffffc) \
MACRO(__VA_ARGS__, f32_linear_fma_x_xXX00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xffffe) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_XXX00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x1, 0x41040, 0xbefb8, 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_y_0x000 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x2, 0x41001, 0xbefbe, 0xfffbf) \
- MACRO(__VA_ARGS__, f32_linear_fma_y_0X000 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x2, 0x41001, 0xbefbe, 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_xxx0x_xxx0x_xxx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba108, 0xfa108) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXx0x_XXx0x_XXx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba108, 0xfad6b) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXX0x_XxX0x_XXX0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba108, 0xfbdaf) \
@@ -1197,26 +1195,23 @@
MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0x0x_xxx0x_xx00x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbb10a, 0xfb10a) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0X0x_XXX0x_XX00x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbb10a, 0xfbdef) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_xxx00_xxx0x_xxx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba118, 0xfa118) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXx00_XXx0x_XXx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba118, 0xfad7b) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXX00_XxX0x_XXX0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba118, 0xfbdbf) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXx00_XXx0x_XXx0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba118, 0xfad7a) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_XxX0x_XXX0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba118, 0xfbdbe) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_xXX0x_xXX0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba118, 0xfb9de) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXX00_XXX0x_XXX0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba118, 0xfbdff) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_XXX0x_XXX0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xba118, 0xfbdfe) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_x000x_0x00x_00x0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbadae, 0xfadae) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_X000x_0X00x_00X0x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbadae, 0xfbdef) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0000_0x000_00x00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbefbe, 0xfefbe) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0000_0X000_00X00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbefbe, 0xffffe) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0000_0X000_00x00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbefbe, 0xfefff) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0000_0X000_00X00 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40000, 0xbefbe, 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_10X0x_1XX0x_1X00x , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x7, 0x40421, 0xbb10a, 0xfbdef) \
- MACRO(__VA_ARGS__, f32_linear_fma_w_000X0 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x8, 0x01041, 0xbefbe, 0xfffff) \
+ MACRO(__VA_ARGS__, f32_linear_fma_w_000x0 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x8, 0x01041, 0xbefbe, 0xbffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xw_x000x_000x0 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x9, 0x01040, 0xbefae, 0xbffee) \
- MACRO(__VA_ARGS__, f32_linear_fma_xw_X000x_000X0 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x9, 0x01040, 0xbefae, 0xfffef) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xw_X000x_000x0 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x9, 0x01040, 0xbefae, 0xbffef) \
MACRO(__VA_ARGS__, f32_linear_fma_xw_xxx00_000x0 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x9, 0x01040, 0xbefb8, 0xbfff8) \
- MACRO(__VA_ARGS__, f32_linear_fma_xw_XXX00_000X0 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x9, 0x01040, 0xbefb8, 0xfffff) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xw_xXX00_000x0 , SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0x9, 0x01040, 0xbefb8, 0xbfffe) \
MACRO(__VA_ARGS__, f32_linear_fma_xyzw_xxx0x_xxx0x_xxx0x_000x0, SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0xf, 0x00000, 0xba108, 0xba108) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyzw_XXX0x_XXX0x_XXX0x_000X0, SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0xf, 0x00000, 0xba108, 0xfbdef) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyzw_X0X0x_XXX0x_XX00x_000X0, SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0xf, 0x00000, 0xbb10a, 0xfbdef) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyzw_X0000_0X000_00X00_000X0, SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0xf, 0x00000, 0xbefbe, 0xfffff)
+ MACRO(__VA_ARGS__, f32_linear_fma_xyzw_XXX0x_XXX0x_XXX0x_000x0, SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0xf, 0x00000, 0xba108, 0xbbdef) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xyzw_X0X0x_XXX0x_XX00x_000x0, SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0xf, 0x00000, 0xbb10a, 0xbbdef) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xyzw_x0000_0x000_00x00_000x0, SWS_PIXEL_F32, SWS_UOP_LINEAR_FMA , 0xf, 0x00000, 0xbefbe, 0xbefbe)
#define SWS_FOR_STRUCT_F32_LINEAR_FMA(MACRO, ...) \
MACRO(__VA_ARGS__, f32_linear_fma_x_xxx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffe8) \
MACRO(__VA_ARGS__, f32_linear_fma_x_XXx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefa8, .par.lin.exact = 0xfffeb) \
@@ -1225,12 +1220,10 @@
MACRO(__VA_ARGS__, f32_linear_fma_x_x000x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefae, .par.lin.exact = 0xfffee) \
MACRO(__VA_ARGS__, f32_linear_fma_x_X000x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefae, .par.lin.exact = 0xfffef) \
MACRO(__VA_ARGS__, f32_linear_fma_x_xxx00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xffff8) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_XXx00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xffffb) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_XxX00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xffffd) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_xXx00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xffffa) \
+ MACRO(__VA_ARGS__, f32_linear_fma_x_xxX00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xffffc) \
MACRO(__VA_ARGS__, f32_linear_fma_x_xXX00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xffffe) \
- MACRO(__VA_ARGS__, f32_linear_fma_x_XXX00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x1, .par.lin.one = 0x41040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_y_0x000 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x2, .par.lin.one = 0x41001, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfffbf) \
- MACRO(__VA_ARGS__, f32_linear_fma_y_0X000 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x2, .par.lin.one = 0x41001, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_xxx0x_xxx0x_xxx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba108, .par.lin.exact = 0xfa108) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXx0x_XXx0x_XXx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba108, .par.lin.exact = 0xfad6b) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXX0x_XxX0x_XXX0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba108, .par.lin.exact = 0xfbdaf) \
@@ -1239,26 +1232,23 @@
MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0x0x_xxx0x_xx00x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbb10a, .par.lin.exact = 0xfb10a) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0X0x_XXX0x_XX00x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbb10a, .par.lin.exact = 0xfbdef) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_xxx00_xxx0x_xxx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfa118) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXx00_XXx0x_XXx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfad7b) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXX00_XxX0x_XXX0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfbdbf) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXx00_XXx0x_XXx0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfad7a) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_XxX0x_XXX0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfbdbe) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_xXX0x_xXX0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfb9de) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_XXX00_XXX0x_XXX0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfbdff) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xyz_xXX00_XXX0x_XXX0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xba118, .par.lin.exact = 0xfbdfe) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_x000x_0x00x_00x0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbadae, .par.lin.exact = 0xfadae) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_X000x_0X00x_00X0x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbadae, .par.lin.exact = 0xfbdef) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0000_0x000_00x00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfefbe) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_x0000_0X000_00X00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xffffe) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0000_0X000_00x00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfefff) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyz_X0000_0X000_00X00 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40000, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xyz_10X0x_1XX0x_1X00x , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x7, .par.lin.one = 0x40421, .par.lin.zero = 0xbb10a, .par.lin.exact = 0xfbdef) \
- MACRO(__VA_ARGS__, f32_linear_fma_w_000X0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x8, .par.lin.one = 0x1041, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfffff) \
+ MACRO(__VA_ARGS__, f32_linear_fma_w_000x0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x8, .par.lin.one = 0x1041, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xbffff) \
MACRO(__VA_ARGS__, f32_linear_fma_xw_x000x_000x0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x9, .par.lin.one = 0x1040, .par.lin.zero = 0xbefae, .par.lin.exact = 0xbffee) \
- MACRO(__VA_ARGS__, f32_linear_fma_xw_X000x_000X0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x9, .par.lin.one = 0x1040, .par.lin.zero = 0xbefae, .par.lin.exact = 0xfffef) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xw_X000x_000x0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x9, .par.lin.one = 0x1040, .par.lin.zero = 0xbefae, .par.lin.exact = 0xbffef) \
MACRO(__VA_ARGS__, f32_linear_fma_xw_xxx00_000x0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x9, .par.lin.one = 0x1040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xbfff8) \
- MACRO(__VA_ARGS__, f32_linear_fma_xw_XXX00_000X0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x9, .par.lin.one = 0x1040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xfffff) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xw_xXX00_000x0 , .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0x9, .par.lin.one = 0x1040, .par.lin.zero = 0xbefb8, .par.lin.exact = 0xbfffe) \
MACRO(__VA_ARGS__, f32_linear_fma_xyzw_xxx0x_xxx0x_xxx0x_000x0, .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0xf, .par.lin.one = 0x0, .par.lin.zero = 0xba108, .par.lin.exact = 0xba108) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyzw_XXX0x_XXX0x_XXX0x_000X0, .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0xf, .par.lin.one = 0x0, .par.lin.zero = 0xba108, .par.lin.exact = 0xfbdef) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyzw_X0X0x_XXX0x_XX00x_000X0, .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0xf, .par.lin.one = 0x0, .par.lin.zero = 0xbb10a, .par.lin.exact = 0xfbdef) \
- MACRO(__VA_ARGS__, f32_linear_fma_xyzw_X0000_0X000_00X00_000X0, .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0xf, .par.lin.one = 0x0, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xfffff)
+ MACRO(__VA_ARGS__, f32_linear_fma_xyzw_XXX0x_XXX0x_XXX0x_000x0, .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0xf, .par.lin.one = 0x0, .par.lin.zero = 0xba108, .par.lin.exact = 0xbbdef) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xyzw_X0X0x_XXX0x_XX00x_000x0, .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0xf, .par.lin.one = 0x0, .par.lin.zero = 0xbb10a, .par.lin.exact = 0xbbdef) \
+ MACRO(__VA_ARGS__, f32_linear_fma_xyzw_x0000_0x000_00x00_000x0, .type = SWS_PIXEL_F32, .uop = SWS_UOP_LINEAR_FMA , .mask = 0xf, .par.lin.one = 0x0, .par.lin.zero = 0xbefbe, .par.lin.exact = 0xbefbe)
#define SWS_FOR_F32_DITHER(MACRO, ...) \
MACRO(__VA_ARGS__, f32_dither_x_0_16x16 , SWS_PIXEL_F32, SWS_UOP_DITHER , 0x1, 0, 0, 0, 0, 4) \
MACRO(__VA_ARGS__, f32_dither_y_3_16x16 , SWS_PIXEL_F32, SWS_UOP_DITHER , 0x2, 0, 3, 0, 0, 4) \
--
2.52.0
1
0
[PR] avformat/matroskaenc: Avoid tmp buffer when writing LCEVC side data (PR #23522)
by mkver 17 Jun '26
by mkver 17 Jun '26
17 Jun '26
PR #23522 opened by mkver
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23522
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23522.patch
From 114ec661084966e36c51209108582c22fb98ca19 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt(a)outlook.com>
Date: Wed, 17 Jun 2026 22:11:53 +0200
Subject: [PATCH 1/2] avformat/matroskaenc: Extend EBML writer to write lists
of buffers
This is intended for LCEVC where an EBML buffer is assembled
by prepending a short header to an already existing buffer.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt(a)outlook.com>
---
libavformat/matroskaenc.c | 42 +++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 97d66558f8..0d0cd0832b 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -116,8 +116,15 @@ typedef enum EbmlType {
EBML_BIN,
EBML_BLOCK, ///< pseudo-type for writing (Simple)Blocks
EBML_MASTER,
+ EBML_BUFARRAY, ///< pseudo-type for writing an array of BufEntry,
+ ///< terminated by a BufEntry with data == NULL.
} EbmlType;
+typedef struct BufEntry {
+ const void *data;
+ size_t size;
+} BufEntry;
+
typedef struct BlockContext {
struct mkv_track *track;
const AVPacket *pkt;
@@ -144,6 +151,7 @@ typedef struct EbmlElement {
const uint8_t *bin;
struct MatroskaMuxContext *mkv; ///< used by EBML_BLOCK
EbmlMaster master;
+ const BufEntry *bufs;
} priv;
} EbmlElement;
@@ -585,6 +593,14 @@ static void ebml_writer_add_block(EbmlWriter *writer, MatroskaMuxContext *mkv)
elem->priv.mkv = mkv;
}
+static void ebml_writer_add_bufarray(EbmlWriter *writer, uint32_t id,
+ const BufEntry *bufs)
+{
+ EbmlElement *elem = ebml_writer_add(writer, id, EBML_BUFARRAY);
+ av_assert2(bufs && bufs->data);
+ elem->priv.bufs = bufs;
+}
+
static int ebml_writer_str_len(EbmlElement *elem)
{
size_t len = strlen(elem->priv.str);
@@ -676,6 +692,22 @@ static int ebml_writer_block_len(EbmlElement *elem)
return 0;
}
+static int ebml_writer_buf_array_len(EbmlElement *elem)
+{
+ const BufEntry *bufs = elem->priv.bufs;
+ uint64_t total_size = 0;
+
+ do {
+ if (bufs->size > UINT64_MAX - total_size)
+ return AVERROR(ERANGE);
+ total_size += bufs->size;
+ } while ((++bufs)->data);
+
+ elem->size = total_size;
+
+ return 0;
+}
+
static void ebml_writer_write_block(const EbmlElement *elem, AVIOContext *pb)
{
MatroskaMuxContext *const mkv = elem->priv.mkv;
@@ -722,6 +754,9 @@ static int ebml_writer_elem_len(EbmlWriter *writer, EbmlElement *elem,
case EBML_MASTER:
ret = ebml_writer_master_len(writer, elem, remaining_elems);
break;
+ case EBML_BUFARRAY:
+ ret = ebml_writer_buf_array_len(elem);
+ break;
}
if (ret < 0)
return ret;
@@ -770,6 +805,13 @@ static int ebml_writer_elem_write(const EbmlElement *elem, AVIOContext *pb)
return nb_elems;
}
+ case EBML_BUFARRAY: {
+ const BufEntry *bufs = elem->priv.bufs;
+ do {
+ avio_write(pb, bufs->data, bufs->size);
+ } while ((++bufs)->data);
+ break;
+ }
}
return 0;
}
--
2.52.0
From 1c090a57ea7a3a03c391258c74393239af0596c2 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt(a)outlook.com>
Date: Wed, 17 Jun 2026 22:51:41 +0200
Subject: [PATCH 2/2] avformat/matroskaenc: Avoid tmp buffer when writing LCEVC
side data
Also avoid an av_free() call in the ordinary case when there is
no LCEVC side data.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt(a)outlook.com>
---
libavformat/matroskaenc.c | 40 +++++++++++++++++++++------------------
1 file changed, 22 insertions(+), 18 deletions(-)
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 0d0cd0832b..e091761ba9 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -2903,6 +2903,16 @@ static void mkv_write_blockadditional(EbmlWriter *writer, const uint8_t *buf,
ebml_writer_close_master(writer);
}
+static void mkv_add_blockadditional_bufarray(EbmlWriter *writer,
+ const BufEntry *bufs,
+ uint64_t additional_id)
+{
+ ebml_writer_open_master(writer, MATROSKA_ID_BLOCKMORE);
+ ebml_writer_add_uint(writer, MATROSKA_ID_BLOCKADDID, additional_id);
+ ebml_writer_add_bufarray(writer, MATROSKA_ID_BLOCKADDITIONAL, bufs);
+ ebml_writer_close_master(writer);
+}
+
static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv,
AVIOContext *pb, const AVStream *st,
mkv_track *track, const AVPacket *pkt,
@@ -2913,7 +2923,8 @@ static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv,
uint8_t t35_buf[6 + AV_HDR_PLUS_MAX_PAYLOAD_SIZE];
#define SMPTE_2094_APP5_MAX_SIZE 855
uint8_t smpte_2094_app5_buf[5 + SMPTE_2094_APP5_MAX_SIZE];
- uint8_t *lcevc = NULL;
+ BufEntry lcevc_buffers[3];
+ uint8_t lcevc_header[4];
uint8_t *side_data;
size_t side_data_size;
uint64_t additional_id;
@@ -3033,19 +3044,16 @@ static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv,
side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_LCEVC,
&side_data_size);
if (side_data) {
- size_t payload_size = side_data_size + 4;
+ AV_WB8 (lcevc_header + 0, ITU_T_T35_COUNTRY_CODE_UK);
+ AV_WB8 (lcevc_header + 1, 0); // t35_uk_country_code_second_octet
+ AV_WB16(lcevc_header + 2, ITU_T_T35_PROVIDER_CODE_VNOVA);
+ lcevc_buffers[0] = (BufEntry){ .data = lcevc_header, .size = 4 };
+ lcevc_buffers[1] = (BufEntry){ .data = side_data,
+ .size = side_data_size };
+ lcevc_buffers[2].data = NULL;
- lcevc = av_malloc(payload_size);
- if (!lcevc)
- return AVERROR(ENOMEM);
-
- AV_WB8 (lcevc + 0, ITU_T_T35_COUNTRY_CODE_UK);
- AV_WB8 (lcevc + 1, 0); // t35_uk_country_code_second_octet
- AV_WB16(lcevc + 2, ITU_T_T35_PROVIDER_CODE_VNOVA);
- memcpy (lcevc + 4, side_data, side_data_size);
-
- mkv_write_blockadditional(&writer, lcevc, payload_size,
- MATROSKA_BLOCK_ADD_ID_ITU_T_T35);
+ mkv_add_blockadditional_bufarray(&writer, lcevc_buffers,
+ MATROSKA_BLOCK_ADD_ID_ITU_T_T35);
track->max_blockaddid = FFMAX(track->max_blockaddid,
MATROSKA_BLOCK_ADD_ID_ITU_T_T35);
}
@@ -3065,11 +3073,7 @@ static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv,
ebml_writer_add_sint(&writer, MATROSKA_ID_BLOCKREFERENCE,
track->last_timestamp - ts);
- ret = ebml_writer_write(&writer, pb);
-
- av_free(lcevc);
-
- return ret;
+ return ebml_writer_write(&writer, pb);
}
static int mkv_end_cluster(AVFormatContext *s)
--
2.52.0
1
0
17 Jun '26
PR #23521 opened by Kacper Michajłow (kasper93)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23521
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23521.patch
From 4630f6b9c739b2cba358926b7774a3ac78ad7fee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <kasper93(a)gmail.com>
Date: Wed, 17 Jun 2026 22:03:59 +0200
Subject: [PATCH 1/2] fate: allow tests to clean up generated files
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add CLEANFILES, a per-test list of extra files to remove after a run.
Honoured unless KEEP_FILES is set.
Signed-off-by: Kacper Michajłow <kasper93(a)gmail.com>
---
tests/Makefile | 2 +-
tests/fate-run.sh | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/tests/Makefile b/tests/Makefile
index 8c7d4539a3..4f194874e2 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -324,7 +324,7 @@ $(FATE): export EXECSUF = $(EXESUF)
$(FATE): export HOSTEXECSUF = $(HOSTEXESUF)
$(FATE): $(FATE_UTILS:%=tests/%$(HOSTEXESUF)) | $(FATE_OUTDIRS)
@echo "TEST $(@:fate-%=%)$(FATE_SUFFIX)"
- $(Q)$(SRC_PATH)/tests/fate-run.sh $@$(FATE_SUFFIX) "$(TARGET_SAMPLES)" "$(TARGET_EXEC)" "$(TARGET_PATH)" '$(CMD)' '$(CMP)' '$(REF)' '$(FUZZ)' '$(THREADS)' '$(THREAD_TYPE)' '$(CPUFLAGS)' '$(CMP_SHIFT)' '$(CMP_TARGET)' '$(SIZE_TOLERANCE)' '$(CMP_UNIT)' '$(GEN)' '$(HWACCEL)' '$(REPORT)' '$(KEEP_FILES)'
+ $(Q)$(SRC_PATH)/tests/fate-run.sh $@$(FATE_SUFFIX) "$(TARGET_SAMPLES)" "$(TARGET_EXEC)" "$(TARGET_PATH)" '$(CMD)' '$(CMP)' '$(REF)' '$(FUZZ)' '$(THREADS)' '$(THREAD_TYPE)' '$(CPUFLAGS)' '$(CMP_SHIFT)' '$(CMP_TARGET)' '$(SIZE_TOLERANCE)' '$(CMP_UNIT)' '$(GEN)' '$(HWACCEL)' '$(REPORT)' '$(KEEP_FILES)' '$(CLEANFILES)'
fate-list:
@printf '%s\n' $(sort $(FATE))
diff --git a/tests/fate-run.sh b/tests/fate-run.sh
index 33c7dfac9d..ff7da2fbb1 100755
--- a/tests/fate-run.sh
+++ b/tests/fate-run.sh
@@ -27,6 +27,10 @@ hwaccel=${17:-none}
report_type=${18:-standard}
keep=${19:-0}
+# Extra files (e.g. generated playlists and segments) to remove after a
+# successful run. Honour $keep so they can be inspected when debugging.
+test "$keep" -ge 1 || cleanfiles=${20}
+
outdir="tests/data/fate"
outfile="${outdir}/${test}"
errfile="${outdir}/${test}.err"
--
2.52.0
From cbd5ba3309f77cc97a1e7ab37efac9db1eb409a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <kasper93(a)gmail.com>
Date: Wed, 17 Jun 2026 22:04:05 +0200
Subject: [PATCH 2/2] fate/hlsenc: clean up generated playlists and segments
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Kacper Michajłow <kasper93(a)gmail.com>
---
tests/fate/hlsenc.mak | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/tests/fate/hlsenc.mak b/tests/fate/hlsenc.mak
index b71fe219a6..df82c25128 100644
--- a/tests/fate/hlsenc.mak
+++ b/tests/fate/hlsenc.mak
@@ -7,6 +7,7 @@ tests/data/live_no_endlist.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC-$(call FILTERDEMDECENCMUX, HDCD AEVALSRC ARESAMPLE, HLS MPEGTS, MP2 PCM_F64LE, MP2FIXED PCM_S24LE, HLS MPEGTS PCM_S24LE, LAVFI_INDEV) += fate-hls-live-no-endlist
fate-hls-live-no-endlist: tests/data/live_no_endlist.m3u8
+fate-hls-live-no-endlist: CLEANFILES = tests/data/live_no_endlist.m3u8 tests/data/live_no_endlist_*.ts
fate-hls-live-no-endlist: SRC = $(TARGET_PATH)/tests/data/live_no_endlist.m3u8
fate-hls-live-no-endlist: CMD = md5 -i $(SRC) -af hdcd=process_stereo=false -t 6 -f s24le
fate-hls-live-no-endlist: CMP = oneline
@@ -22,6 +23,7 @@ tests/data/event_no_endlist.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC-$(call FILTERDEMDECENCMUX, HDCD AEVALSRC ARESAMPLE, HLS MPEGTS, MP2 PCM_F64LE, MP2FIXED PCM_S24LE, HLS MPEGTS PCM_S24LE, LAVFI_INDEV) += fate-hls-event-no-endlist
fate-hls-event-no-endlist: tests/data/event_no_endlist.m3u8
+fate-hls-event-no-endlist: CLEANFILES = tests/data/event_no_endlist.m3u8 tests/data/event_no_endlist_*.ts
fate-hls-event-no-endlist: SRC = $(TARGET_PATH)/tests/data/event_no_endlist.m3u8
fate-hls-event-no-endlist: CMD = md5 -ss 3 -i $(SRC) -af hdcd=process_stereo=false -t 3 -f s24le
fate-hls-event-no-endlist: CMP = oneline
@@ -36,6 +38,7 @@ tests/data/live_last_endlist.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC-$(call FILTERDEMDECENCMUX, HDCD AEVALSRC ARESAMPLE, HLS MPEGTS, MP2 PCM_F64LE, MP2FIXED PCM_S24LE, HLS MPEGTS PCM_S24LE, LAVFI_INDEV) += fate-hls-live-last-endlist
fate-hls-live-last-endlist: tests/data/live_last_endlist.m3u8
+fate-hls-live-last-endlist: CLEANFILES = tests/data/live_last_endlist.m3u8 tests/data/live_last_endlist_*.ts
fate-hls-live-last-endlist: SRC = $(TARGET_PATH)/tests/data/live_last_endlist.m3u8
fate-hls-live-last-endlist: CMD = md5 -i $(SRC) -af hdcd=process_stereo=false -t 6 -f s24le
fate-hls-live-last-endlist: CMP = oneline
@@ -51,6 +54,7 @@ tests/data/live_endlist.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC-$(call FILTERDEMDECENCMUX, HDCD AEVALSRC ARESAMPLE, HLS MPEGTS, MP2 PCM_F64LE, MP2FIXED PCM_S24LE, HLS MPEGTS PCM_S24LE, LAVFI_INDEV ) += fate-hls-live-endlist
fate-hls-live-endlist: tests/data/live_endlist.m3u8
+fate-hls-live-endlist: CLEANFILES = tests/data/live_endlist.m3u8 tests/data/live_endlist_*.ts
fate-hls-live-endlist: SRC = $(TARGET_PATH)/tests/data/live_endlist.m3u8
fate-hls-live-endlist: CMD = md5 -i $(SRC) -af hdcd=process_stereo=false -t 20 -f s24le
fate-hls-live-endlist: CMP = oneline
@@ -65,6 +69,7 @@ tests/data/hls_segment_size.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC-$(call FILTERDEMDECENCMUX, AEVALSRC ARESAMPLE, HLS MPEGTS, MP2 PCM_F64LE, MP2FIXED, HLS MPEGTS, LAVFI_INDEV) += fate-hls-segment-size
fate-hls-segment-size: tests/data/hls_segment_size.m3u8
+fate-hls-segment-size: CLEANFILES = tests/data/hls_segment_size.m3u8 tests/data/hls_segment_size_*.ts
fate-hls-segment-size: CMD = framecrc -auto_conversion_filters -flags +bitexact -i $(TARGET_PATH)/tests/data/hls_segment_size.m3u8 -vf setpts=N*23
tests/data/hls_segment_single.m3u8: TAG = GEN
@@ -76,6 +81,7 @@ tests/data/hls_segment_single.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC-$(call FILTERDEMDECENCMUX, AEVALSRC ARESAMPLE, HLS MPEGTS, MP2 PCM_F64LE, MP2FIXED, HLS MPEGTS, LAVFI_INDEV) += fate-hls-segment-single
fate-hls-segment-single: tests/data/hls_segment_single.m3u8
+fate-hls-segment-single: CLEANFILES = tests/data/hls_segment_single.m3u8 tests/data/hls_segment_single.ts
fate-hls-segment-single: CMD = framecrc -auto_conversion_filters -flags +bitexact -i $(TARGET_PATH)/tests/data/hls_segment_single.m3u8 -vf setpts=N*23
tests/data/hls_init_time.m3u8: TAG = GEN
@@ -87,6 +93,7 @@ tests/data/hls_init_time.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC-$(call FILTERDEMDECENCMUX, AEVALSRC ARESAMPLE, HLS MPEGTS, MP2 PCM_F64LE, MP2FIXED, HLS MPEGTS, LAVFI_INDEV) += fate-hls-init-time
fate-hls-init-time: tests/data/hls_init_time.m3u8
+fate-hls-init-time: CLEANFILES = tests/data/hls_init_time.m3u8 tests/data/hls_init_time_*.ts
fate-hls-init-time: CMD = framecrc -auto_conversion_filters -flags +bitexact -i $(TARGET_PATH)/tests/data/hls_init_time.m3u8 -vf setpts=N*23
tests/data/hls_list_size.m3u8: TAG = GEN
@@ -98,6 +105,7 @@ tests/data/hls_list_size.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC-$(call FILTERDEMDECENCMUX, AEVALSRC ARESAMPLE, HLS MPEGTS, MP2 PCM_F64LE, MP2FIXED, HLS MPEGTS, LAVFI_INDEV) += fate-hls-list-size
fate-hls-list-size: tests/data/hls_list_size.m3u8
+fate-hls-list-size: CLEANFILES = tests/data/hls_list_size.m3u8 tests/data/hls_list_size_*.ts
fate-hls-list-size: CMD = framecrc -auto_conversion_filters -flags +bitexact -i $(TARGET_PATH)/tests/data/hls_list_size.m3u8 -vf setpts=N*23
tests/data/hls_fmp4.m3u8: TAG = GEN
@@ -110,6 +118,7 @@ tests/data/hls_fmp4.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC-$(call FILTERDEMDECENCMUX, AEVALSRC ARESAMPLE, HLS MPEGTS, MP2 PCM_F64LE, MP2FIXED, HLS MPEGTS, LAVFI_INDEV) += fate-hls-fmp4
fate-hls-fmp4: tests/data/hls_fmp4.m3u8
+fate-hls-fmp4: CLEANFILES = tests/data/hls_fmp4.m3u8 tests/data/hls_fmp4_[0-9]*.m4s tests/data/now.mp4
fate-hls-fmp4: CMD = framecrc -auto_conversion_filters -flags +bitexact -i $(TARGET_PATH)/tests/data/hls_fmp4.m3u8 -vf setpts=N*23
tests/data/hls_fmp4_ac3.m3u8: TAG = GEN
@@ -124,6 +133,7 @@ FATE_HLSENC-yes := $(if $(call FRAMECRC), $(FATE_HLSENC-yes))
FATE_HLSENC_PROBE-$(call DEMMUX, HLS AC3, HLS MP4, AC3_DECODER) += fate-hls-fmp4_ac3
fate-hls-fmp4_ac3: tests/data/hls_fmp4_ac3.m3u8
+fate-hls-fmp4_ac3: CLEANFILES = tests/data/hls_fmp4_ac3.m3u8 tests/data/hls_fmp4_ac3_*.m4s tests/data/now_ac3.mp4
fate-hls-fmp4_ac3: CMD = probeaudiostream $(TARGET_PATH)/tests/data/now_ac3.mp4
@@ -139,6 +149,7 @@ FATE_HLSENC-yes := $(if $(call FRAMECRC), $(FATE_HLSENC-yes))
FATE_HLSENC_PROBE-$(call FRAMECRC, HLS) += fate-hls-cmfa
fate-hls-cmfa: tests/data/hls_cmfa.m3u8
+fate-hls-cmfa: CLEANFILES = tests/data/hls_cmfa.m3u8 tests/data/hls_fmp4_[0-9]*.cmfa tests/data/now.cmfa
fate-hls-cmfa: CMD = framecrc -i $(TARGET_PATH)/tests/data/hls_cmfa.m3u8 -c copy
FATE_SAMPLES_FFMPEG += $(FATE_HLSENC-yes)
@@ -156,6 +167,7 @@ tests/data/hls_playlist_type_vod.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC_LAVFI-$(call ALLYES, TESTSRC2_FILTER LAVFI_INDEV MPEG2VIDEO_ENCODER HLS_MUXER MPEGTS_MUXER FILE_PROTOCOL) += fate-hls-playlist-type-vod
fate-hls-playlist-type-vod: tests/data/hls_playlist_type_vod.m3u8
+fate-hls-playlist-type-vod: CLEANFILES = tests/data/hls_playlist_type_vod.m3u8 tests/data/hls_playlist_type_vod_*.ts
fate-hls-playlist-type-vod: CMD = sed -n -e /^\#EXT-X-PLAYLIST-TYPE:/p -e /^\#EXT-X-ENDLIST/p $(TARGET_PATH)/tests/data/hls_playlist_type_vod.m3u8
fate-hls-playlist-type-vod: CMP = diff
@@ -169,6 +181,7 @@ tests/data/hls_playlist_type_event.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC_LAVFI-$(call ALLYES, TESTSRC2_FILTER LAVFI_INDEV MPEG2VIDEO_ENCODER HLS_MUXER MPEGTS_MUXER FILE_PROTOCOL) += fate-hls-playlist-type-event
fate-hls-playlist-type-event: tests/data/hls_playlist_type_event.m3u8
+fate-hls-playlist-type-event: CLEANFILES = tests/data/hls_playlist_type_event.m3u8 tests/data/hls_playlist_type_event_*.ts
fate-hls-playlist-type-event: CMD = sed -n -e /^\#EXT-X-PLAYLIST-TYPE:/p -e /^\#EXT-X-ENDLIST/p $(TARGET_PATH)/tests/data/hls_playlist_type_event.m3u8
fate-hls-playlist-type-event: CMP = diff
@@ -182,6 +195,7 @@ tests/data/hls_round_durations.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC_LAVFI-$(call ALLYES, TESTSRC2_FILTER LAVFI_INDEV MPEG2VIDEO_ENCODER HLS_MUXER MPEGTS_MUXER FILE_PROTOCOL) += fate-hls-round-durations
fate-hls-round-durations: tests/data/hls_round_durations.m3u8
+fate-hls-round-durations: CLEANFILES = tests/data/hls_round_durations.m3u8 tests/data/hls_round_durations_*.ts
fate-hls-round-durations: CMD = sed -n -e /^\#EXTINF:/p $(TARGET_PATH)/tests/data/hls_round_durations.m3u8
fate-hls-round-durations: CMP = diff
@@ -195,6 +209,7 @@ tests/data/hls_discont_start.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC_LAVFI-$(call ALLYES, TESTSRC2_FILTER LAVFI_INDEV MPEG2VIDEO_ENCODER HLS_MUXER MPEGTS_MUXER FILE_PROTOCOL) += fate-hls-discont-start
fate-hls-discont-start: tests/data/hls_discont_start.m3u8
+fate-hls-discont-start: CLEANFILES = tests/data/hls_discont_start.m3u8 tests/data/hls_discont_start_*.ts
fate-hls-discont-start: CMD = sed -n -e /^\#EXT-X-DISCONTINUITY/p -e /^\#EXTINF:/p -e /^[^\#]/p $(TARGET_PATH)/tests/data/hls_discont_start.m3u8
fate-hls-discont-start: CMP = diff
@@ -208,6 +223,7 @@ tests/data/hls_independent_segments.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/dat
FATE_HLSENC_LAVFI-$(call ALLYES, TESTSRC2_FILTER LAVFI_INDEV MPEG2VIDEO_ENCODER HLS_MUXER MPEGTS_MUXER FILE_PROTOCOL) += fate-hls-independent-segments
fate-hls-independent-segments: tests/data/hls_independent_segments.m3u8
+fate-hls-independent-segments: CLEANFILES = tests/data/hls_independent_segments.m3u8 tests/data/hls_independent_segments_*.ts
fate-hls-independent-segments: CMD = sed -n -e /^\#EXT-X-INDEPENDENT-SEGMENTS/p $(TARGET_PATH)/tests/data/hls_independent_segments.m3u8
fate-hls-independent-segments: CMP = diff
@@ -221,6 +237,7 @@ tests/data/hls_start_number.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
FATE_HLSENC_LAVFI-$(call ALLYES, TESTSRC2_FILTER LAVFI_INDEV MPEG2VIDEO_ENCODER HLS_MUXER MPEGTS_MUXER FILE_PROTOCOL) += fate-hls-start-number
fate-hls-start-number: tests/data/hls_start_number.m3u8
+fate-hls-start-number: CLEANFILES = tests/data/hls_start_number.m3u8 tests/data/hls_start_number_*.ts
fate-hls-start-number: CMD = sed -n -e /^\#EXT-X-MEDIA-SEQUENCE:/p -e /^[^\#]/p $(TARGET_PATH)/tests/data/hls_start_number.m3u8
fate-hls-start-number: CMP = diff
--
2.52.0
1
0