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
Adds a native decoder for the VDEC codec used in AVI files produced by
VIDEC capture hardware. The codec uses a two-stage pipeline: a 9/13-bit
Huffman decode (patent fig. 4-3) followed by DPCM reconstruction
(patent fig. 4-6) as described in US patent 5,675,382. Output
resolution is inferred from pixel count since the container advertises
2x the encoded dimensions.
Based on the Python reference implementation at:
https://github.com/a-d-j-i/videc2
Co-Authored-By: Claude Sonnet 4.6 <noreply(a)anthropic.com>
Signed-off-by: adji <aadjiman(a)gmail.com>
---
libavcodec/Makefile | 1 +
libavcodec/allcodecs.c | 1 +
libavcodec/codec_desc.c | 7 +
libavcodec/codec_id.h | 1 +
libavcodec/vdecdec.c | 447 ++++++++++++++++++++++++++++++++++++++++
libavformat/riff.c | 1 +
6 files changed, 458 insertions(+)
create mode 100644 libavcodec/vdecdec.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index ffbacc2ed3..27b0aeee03 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -891,6 +891,7 @@ OBJS-$(CONFIG_ZLIB_DECODER) += lcldec.o
OBJS-$(CONFIG_ZLIB_ENCODER) += lclenc.o
OBJS-$(CONFIG_ZMBV_DECODER) += zmbv.o
OBJS-$(CONFIG_ZMBV_ENCODER) += zmbvenc.o
+OBJS-$(CONFIG_VDEC_DECODER) += vdecdec.o
# (AD)PCM decoders/encoders
OBJS-$(CONFIG_PCM_ALAW_DECODER) += pcm.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 314cb230a4..0106bcea38 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -428,6 +428,7 @@ extern const FFCodec ff_zlib_encoder;
extern const FFCodec ff_zlib_decoder;
extern const FFCodec ff_zmbv_encoder;
extern const FFCodec ff_zmbv_decoder;
+extern const FFCodec ff_vdec_decoder;
/* audio codecs */
extern const FFCodec ff_aac_encoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 7a16d002b9..b6999eada3 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2017,6 +2017,13 @@ static const AVCodecDescriptor
codec_descriptors[] = {
.props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS,
.mime_types= MT("image/webp"),
},
+ {
+ .id = AV_CODEC_ID_VDEC,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "vdec",
+ .long_name = NULL_IF_CONFIG_SMALL("VDEC Huffman+DPCM video"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ },
/* various PCM "codecs" */
{
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index 1aad9ba0e9..13442fb543 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -333,6 +333,7 @@ enum AVCodecID {
AV_CODEC_ID_PRORES_RAW,
AV_CODEC_ID_JPEGXS,
AV_CODEC_ID_WEBP_ANIM,
+ AV_CODEC_ID_VDEC,
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at
the start of audio codecs
diff --git a/libavcodec/vdecdec.c b/libavcodec/vdecdec.c
new file mode 100644
index 0000000000..1934e53b3b
--- /dev/null
+++ b/libavcodec/vdecdec.c
@@ -0,0 +1,447 @@
+/*
+ * VDEC video decoder
+ * Huffman + DPCM compression as described in US patent 5,675,382
+ *
https://patentimages.storage.googleapis.com/e5/59/90/dbb789f1f1bdb5/US56753…
+ *
+ * Based on the Python reference implementation:
+ * https://github.com/a-d-j-i/videc2
+ */
+
+#include "avcodec.h"
+#include "codec_internal.h"
+#include "decode.h"
+#include "get_bits.h"
+#include "libavutil/mem.h"
+
+/* 9-bit Huffman table (patent fig. 4-3a).
+ * Entry format: bits[15:11]=nbits, bits[8:6]=b, bits[5:3]=g, bits[2:0]=r.
+ * Keys 0x000–0x03F (top 3 bits == 0) are never dispatched here;
+ * those go to table_430b instead, so those entries are 0x0000. */
+static const uint16_t table_430a[512] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x401b, 0x401b, 0x4058, 0x4058, 0x4050, 0x4050, 0x4094, 0x4094,
+ 0x4052, 0x4052, 0x4081, 0x4081, 0x40c0, 0x40c0, 0x4003, 0x4003,
+ 0x401d, 0x401d, 0x405d, 0x405d, 0x4054, 0x4054, 0x40db, 0x40db,
+ 0x405b, 0x405b, 0x4082, 0x4082, 0x4014, 0x4014, 0x400b, 0x400b,
+ 0x38d9, 0x38d9, 0x38d9, 0x38d9, 0x384b, 0x384b, 0x384b, 0x384b,
+ 0x3859, 0x3859, 0x3859, 0x3859, 0x3842, 0x3842, 0x3842, 0x3842,
+ 0x38c8, 0x38c8, 0x38c8, 0x38c8, 0x38c9, 0x38c9, 0x38c9, 0x38c9,
+ 0x3812, 0x3812, 0x3812, 0x3812, 0x3892, 0x3892, 0x3892, 0x3892,
+ 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890,
+ 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890, 0x2890,
+ 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802,
+ 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802, 0x2802,
+ 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810,
+ 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810, 0x2810,
+ 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880,
+ 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880, 0x2880,
+ 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841,
+ 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841, 0x2841,
+ 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809,
+ 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809, 0x2809,
+ 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849,
+ 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849, 0x2849,
+ 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808,
+ 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808, 0x2808,
+ 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001,
+ 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001,
+ 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001,
+ 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001, 0x2001,
+ 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048,
+ 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048,
+ 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048,
+ 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048, 0x2048,
+ 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840,
+ 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840,
+ 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840,
+ 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840,
+ 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840,
+ 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840,
+ 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840,
+ 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840, 0x1840,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000,
+};
+
+/* 13-bit Huffman table (patent fig. 4-3b).
+ * Only keys 0x0000–0x03FF are reachable (top 3 bits must all be 0). */
+static const uint16_t table_430b[1024] = {
+ 0x69f7, 0x69f6, 0x69f3, 0x69f1, 0x69e7, 0x69e6, 0x69e3, 0x69de,
+ 0x69d7, 0x69d6, 0x69d5, 0x69d3, 0x69cf, 0x69ce, 0x69c7, 0x69c6,
+ 0x69c5, 0x69c3, 0x69c2, 0x69a7, 0x699f, 0x699e, 0x6997, 0x6996,
+ 0x698e, 0x698d, 0x6987, 0x6986, 0x6984, 0x697e, 0x6957, 0x6947,
+ 0x693f, 0x692f, 0x690f, 0x6907, 0x68bf, 0x68be, 0x68b7, 0x687e,
+ 0x687c, 0x687a, 0x6847, 0x683e, 0x683a, 0x6838, 0x69f4, 0x69e5,
+ 0x69e4, 0x69df, 0x69dc, 0x69d4, 0x69d1, 0x69cc, 0x69ca, 0x69c4,
+ 0x69b8, 0x69aa, 0x698f, 0x698c, 0x698b, 0x6985, 0x694f, 0x691f,
+ 0x6917, 0x68e7, 0x68a7, 0x6897, 0x6887, 0x6857, 0x683c, 0x6837,
+ 0x69f5, 0x69ee, 0x69e2, 0x69cd, 0x69cb, 0x69c1, 0x69bf, 0x699d,
+ 0x699a, 0x698a, 0x6983, 0x6981, 0x6976, 0x693e, 0x68fe, 0x68d7,
+ 0x68c7, 0x68b8, 0x6877, 0x683f, 0x683d, 0x6817, 0x69fe, 0x69d2,
+ 0x699c, 0x6995, 0x6991, 0x6989, 0x6982, 0x697c, 0x694e, 0x6946,
+ 0x68cf, 0x68ce, 0x68b5, 0x68b3, 0x688f, 0x6876, 0x6867, 0x684f,
+ 0x6827, 0x69ec, 0x69ea, 0x69e1, 0x69da, 0x69b1, 0x69af, 0x69a5,
+ 0x699b, 0x6993, 0x6970, 0x6967, 0x6956, 0x693d, 0x6935, 0x6927,
+ 0x68f7, 0x68bb, 0x688e, 0x6875, 0x6835, 0x69fc, 0x69f0, 0x69be,
+ 0x69bd, 0x69b3, 0x695f, 0x6945, 0x690e, 0x68bd, 0x68bc, 0x68ba,
+ 0x68ae, 0x686e, 0x6836, 0x680f, 0x680e, 0x69f8, 0x69bb, 0x69ac,
+ 0x69a3, 0x6988, 0x6953, 0x68fc, 0x68f6, 0x68df, 0x6878, 0x6871,
+ 0x683b, 0x6833, 0x6807, 0x69c0, 0x695e, 0x693b, 0x6937, 0x685e,
+ 0x69ef, 0x69e0, 0x69b9, 0x6906, 0x68fa, 0x68c6, 0x6886, 0x6831,
+ 0x682e, 0x681e, 0x69ba, 0x69b7, 0x69ab, 0x6955, 0x692e, 0x692a,
+ 0x687b, 0x6870, 0x6839, 0x69f2, 0x6999, 0x6998, 0x6978, 0x6960,
+ 0x689f, 0x69dd, 0x69a1, 0x693c, 0x6873, 0x69db, 0x6972, 0x6965,
+ 0x6943, 0x693a, 0x6933, 0x68f3, 0x6879, 0x682c, 0x69bc, 0x6974,
+ 0x6951, 0x6931, 0x6928, 0x691e, 0x6916, 0x687d, 0x6874, 0x684e,
+ 0x681f, 0x69e8, 0x69ae, 0x69ad, 0x697a, 0x690c, 0x68f4, 0x6896,
+ 0x6830, 0x69d0, 0x69a9, 0x6977, 0x692c, 0x68ee, 0x689e, 0x69eb,
+ 0x6994, 0x6961, 0x6939, 0x68ff, 0x68f8, 0x68f5, 0x68de, 0x68b1,
+ 0x68aa, 0x6872, 0x6971, 0x68f1, 0x682a, 0x69b5, 0x6938, 0x685f,
+ 0x6806, 0x69fa, 0x6966, 0x69ff, 0x696e, 0x68ac, 0x68f2, 0x68f0,
+ 0x68b9, 0x6846, 0x69ed, 0x697f, 0x6962, 0x686c, 0x6963, 0x68c5,
+ 0x687f, 0x686a, 0x6973, 0x6915, 0x68ef, 0x69d8, 0x69d9, 0x69a6,
+ 0x68fd, 0x6992, 0x6964, 0x695c, 0x69f9, 0x690a, 0x6950, 0x68b6,
+ 0x6834, 0x69fd, 0x69a8, 0x6952, 0x68fb, 0x691c, 0x68a8, 0x686f,
+ 0x68f9, 0x68ea, 0x69c8, 0x692b, 0x6980, 0x696f, 0x692d, 0x696a,
+ 0x6941, 0x69fb, 0x69c9, 0x6975, 0x6905, 0x696c, 0x68ec, 0x69e9,
+ 0x6918, 0x68af, 0x6832, 0x694c, 0x6929, 0x68d6, 0x68a6, 0x6904,
+ 0x69a2, 0x6823, 0x697b, 0x6936, 0x691a, 0x6855, 0x6816, 0x69b0,
+ 0x6861, 0x6821, 0x68d5, 0x69b6, 0x6942, 0x68a5, 0x68a9, 0x697d,
+ 0x6925, 0x68b0, 0x6828, 0x6909, 0x6895, 0x6845, 0x68ab, 0x68a1,
+ 0x681c, 0x6979, 0x6921, 0x6926, 0x6815, 0x69b4, 0x68b2, 0x688c,
+ 0x6863, 0x694d, 0x6930, 0x6908, 0x68e0, 0x69b2, 0x6903, 0x690d,
+ 0x6923, 0x68b4, 0x68e6, 0x6856, 0x6913, 0x69a4, 0x682f, 0x695a,
+ 0x690b, 0x68a3, 0x6825, 0x6885, 0x6829, 0x68e1, 0x681a, 0x69a0,
+ 0x689a, 0x6944, 0x68dc, 0x6860, 0x6853, 0x68d3, 0x6826, 0x6901,
+ 0x6932, 0x6968, 0x6919, 0x6868, 0x685c, 0x695d, 0x682b, 0x689c,
+ 0x68e8, 0x6954, 0x6865, 0x6934, 0x691d, 0x6990, 0x694a, 0x691b,
+ 0x68e2, 0x68cc, 0x6805, 0x68e3, 0x680c, 0x6911, 0x6911, 0x6911,
+ 0x5066, 0x5066, 0x5066, 0x5066, 0x5066, 0x5066, 0x5066, 0x5066,
+ 0x50d1, 0x50d1, 0x50d1, 0x50d1, 0x50d1, 0x50d1, 0x50d1, 0x50d1,
+ 0x50e5, 0x50e5, 0x50e5, 0x50e5, 0x50e5, 0x50e5, 0x50e5, 0x50e5,
+ 0x5098, 0x5098, 0x5098, 0x5098, 0x5098, 0x5098, 0x5098, 0x5098,
+ 0x5158, 0x5158, 0x5158, 0x5158, 0x5158, 0x5158, 0x5158, 0x5158,
+ 0x5013, 0x5013, 0x5013, 0x5013, 0x5013, 0x5013, 0x5013, 0x5013,
+ 0x5102, 0x5102, 0x5102, 0x5102, 0x5102, 0x5102, 0x5102, 0x5102,
+ 0x5062, 0x5062, 0x5062, 0x5062, 0x5062, 0x5062, 0x5062, 0x5062,
+ 0x508a, 0x508a, 0x508a, 0x508a, 0x508a, 0x508a, 0x508a, 0x508a,
+ 0x5140, 0x5140, 0x5140, 0x5140, 0x5140, 0x5140, 0x5140, 0x5140,
+ 0x50c3, 0x50c3, 0x50c3, 0x50c3, 0x50c3, 0x50c3, 0x50c3, 0x50c3,
+ 0x505a, 0x505a, 0x505a, 0x505a, 0x505a, 0x505a, 0x505a, 0x505a,
+ 0x504c, 0x504c, 0x504c, 0x504c, 0x504c, 0x504c, 0x504c, 0x504c,
+ 0x5020, 0x5020, 0x5020, 0x5020, 0x5020, 0x5020, 0x5020, 0x5020,
+ 0x50e4, 0x50e4, 0x50e4, 0x50e4, 0x50e4, 0x50e4, 0x50e4, 0x50e4,
+ 0x5099, 0x5099, 0x5099, 0x5099, 0x5099, 0x5099, 0x5099, 0x5099,
+ 0x5114, 0x5114, 0x5114, 0x5114, 0x5114, 0x5114, 0x5114, 0x5114,
+ 0x5084, 0x5084, 0x5084, 0x5084, 0x5084, 0x5084, 0x5084, 0x5084,
+ 0x5069, 0x5069, 0x5069, 0x5069, 0x5069, 0x5069, 0x5069, 0x5069,
+ 0x514b, 0x514b, 0x514b, 0x514b, 0x514b, 0x514b, 0x514b, 0x514b,
+ 0x5148, 0x5148, 0x5148, 0x5148, 0x5148, 0x5148, 0x5148, 0x5148,
+ 0x50da, 0x50da, 0x50da, 0x50da, 0x50da, 0x50da, 0x50da, 0x50da,
+ 0x506b, 0x506b, 0x506b, 0x506b, 0x506b, 0x506b, 0x506b, 0x506b,
+ 0x50cd, 0x50cd, 0x50cd, 0x50cd, 0x50cd, 0x50cd, 0x50cd, 0x50cd,
+ 0x5093, 0x5093, 0x5093, 0x5093, 0x5093, 0x5093, 0x5093, 0x5093,
+ 0x50c4, 0x50c4, 0x50c4, 0x50c4, 0x50c4, 0x50c4, 0x50c4, 0x50c4,
+ 0x50ca, 0x50ca, 0x50ca, 0x50ca, 0x50ca, 0x50ca, 0x50ca, 0x50ca,
+ 0x509b, 0x509b, 0x509b, 0x509b, 0x509b, 0x509b, 0x509b, 0x509b,
+ 0x5051, 0x5051, 0x5051, 0x5051, 0x5051, 0x5051, 0x5051, 0x5051,
+ 0x50d2, 0x50d2, 0x50d2, 0x50d2, 0x50d2, 0x50d2, 0x50d2, 0x50d2,
+ 0x515b, 0x515b, 0x515b, 0x515b, 0x515b, 0x515b, 0x515b, 0x515b,
+ 0x50d0, 0x50d0, 0x50d0, 0x50d0, 0x50d0, 0x50d0, 0x50d0, 0x50d0,
+ 0x5169, 0x5169, 0x5169, 0x5169, 0x5169, 0x5169, 0x5169, 0x5169,
+ 0x50c2, 0x50c2, 0x50c2, 0x50c2, 0x50c2, 0x50c2, 0x50c2, 0x50c2,
+ 0x516b, 0x516b, 0x516b, 0x516b, 0x516b, 0x516b, 0x516b, 0x516b,
+ 0x50ed, 0x50ed, 0x50ed, 0x50ed, 0x50ed, 0x50ed, 0x50ed, 0x50ed,
+ 0x5022, 0x5022, 0x5022, 0x5022, 0x5022, 0x5022, 0x5022, 0x5022,
+ 0x50c1, 0x50c1, 0x50c1, 0x50c1, 0x50c1, 0x50c1, 0x50c1, 0x50c1,
+ 0x50ad, 0x50ad, 0x50ad, 0x50ad, 0x50ad, 0x50ad, 0x50ad, 0x50ad,
+ 0x5120, 0x5120, 0x5120, 0x5120, 0x5120, 0x5120, 0x5120, 0x5120,
+ 0x504d, 0x504d, 0x504d, 0x504d, 0x504d, 0x504d, 0x504d, 0x504d,
+ 0x5018, 0x5018, 0x5018, 0x5018, 0x5018, 0x5018, 0x5018, 0x5018,
+ 0x506d, 0x506d, 0x506d, 0x506d, 0x506d, 0x506d, 0x506d, 0x506d,
+ 0x5159, 0x5159, 0x5159, 0x5159, 0x5159, 0x5159, 0x5159, 0x5159,
+ 0x508d, 0x508d, 0x508d, 0x508d, 0x508d, 0x508d, 0x508d, 0x508d,
+ 0x5083, 0x5083, 0x5083, 0x5083, 0x5083, 0x5083, 0x5083, 0x5083,
+ 0x50a0, 0x50a0, 0x50a0, 0x50a0, 0x50a0, 0x50a0, 0x50a0, 0x50a0,
+ 0x50eb, 0x50eb, 0x50eb, 0x50eb, 0x50eb, 0x50eb, 0x50eb, 0x50eb,
+ 0x5044, 0x5044, 0x5044, 0x5044, 0x5044, 0x5044, 0x5044, 0x5044,
+ 0x508b, 0x508b, 0x508b, 0x508b, 0x508b, 0x508b, 0x508b, 0x508b,
+ 0x5004, 0x5004, 0x5004, 0x5004, 0x5004, 0x5004, 0x5004, 0x5004,
+ 0x500d, 0x500d, 0x500d, 0x500d, 0x500d, 0x500d, 0x500d, 0x500d,
+ 0x5089, 0x5089, 0x5089, 0x5089, 0x5089, 0x5089, 0x5089, 0x5089,
+ 0x5064, 0x5064, 0x5064, 0x5064, 0x5064, 0x5064, 0x5064, 0x5064,
+ 0x50e9, 0x50e9, 0x50e9, 0x50e9, 0x50e9, 0x50e9, 0x50e9, 0x50e9,
+ 0x516d, 0x516d, 0x516d, 0x516d, 0x516d, 0x516d, 0x516d, 0x516d,
+ 0x5149, 0x5149, 0x5149, 0x5149, 0x5149, 0x5149, 0x5149, 0x5149,
+ 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122,
+ 0x5024, 0x5024, 0x5024, 0x5024, 0x5024, 0x5024, 0x5024, 0x5024,
+ 0x5112, 0x5112, 0x5112, 0x5112, 0x5112, 0x5112, 0x5112, 0x5112,
+ 0x5100, 0x5100, 0x5100, 0x5100, 0x5100, 0x5100, 0x5100, 0x5100,
+ 0x502d, 0x502d, 0x502d, 0x502d, 0x502d, 0x502d, 0x502d, 0x502d,
+ 0x50a4, 0x50a4, 0x50a4, 0x50a4, 0x50a4, 0x50a4, 0x50a4, 0x50a4,
+ 0x5088, 0x5088, 0x5088, 0x5088, 0x5088, 0x5088, 0x5088, 0x5088,
+ 0x5091, 0x5091, 0x5091, 0x5091, 0x5091, 0x5091, 0x5091, 0x5091,
+ 0x5043, 0x5043, 0x5043, 0x5043, 0x5043, 0x5043, 0x5043, 0x5043,
+ 0x500a, 0x500a, 0x500a, 0x500a, 0x500a, 0x500a, 0x500a, 0x500a,
+ 0x5124, 0x5124, 0x5124, 0x5124, 0x5124, 0x5124, 0x5124, 0x5124,
+ 0x509d, 0x509d, 0x509d, 0x509d, 0x509d, 0x509d, 0x509d, 0x509d,
+ 0x50dd, 0x50dd, 0x50dd, 0x50dd, 0x50dd, 0x50dd, 0x50dd, 0x50dd,
+ 0x50d4, 0x50d4, 0x50d4, 0x50d4, 0x50d4, 0x50d4, 0x50d4, 0x50d4,
+ 0x50d8, 0x50d8, 0x50d8, 0x50d8, 0x50d8, 0x50d8, 0x50d8, 0x50d8,
+ 0x5019, 0x5019, 0x5019, 0x5019, 0x5019, 0x5019, 0x5019, 0x5019,
+ 0x5110, 0x5110, 0x5110, 0x5110, 0x5110, 0x5110, 0x5110, 0x5110,
+ 0x5011, 0x5011, 0x5011, 0x5011, 0x5011, 0x5011, 0x5011, 0x5011,
+ 0x504a, 0x504a, 0x504a, 0x504a, 0x504a, 0x504a, 0x504a, 0x504a,
+ 0x50a2, 0x50a2, 0x50a2, 0x50a2, 0x50a2, 0x50a2, 0x50a2, 0x50a2,
+ 0x50cb, 0x50cb, 0x50cb, 0x50cb, 0x50cb, 0x50cb, 0x50cb, 0x50cb,
+};
+
+/* DPCM reconstruction tables (patent fig. 4-6a/b).
+ * Index: category (0–7) + predictor (0–31) * 8.
+ * Output: reconstructed pixel value 0–31. */
+static const uint8_t table_460a[256] = {
+ 0x00, 0x01, 0x03, 0x08, 0x0d, 0x12, 0x17, 0x1d,
+ 0x01, 0x02, 0x04, 0x09, 0x0e, 0x13, 0x18, 0x1d,
+ 0x02, 0x03, 0x01, 0x05, 0x0a, 0x0f, 0x16, 0x1c,
+ 0x03, 0x04, 0x01, 0x06, 0x0b, 0x10, 0x16, 0x1c,
+ 0x04, 0x05, 0x02, 0x07, 0x0c, 0x11, 0x17, 0x1d,
+ 0x05, 0x06, 0x03, 0x08, 0x0d, 0x12, 0x17, 0x1d,
+ 0x06, 0x07, 0x04, 0x09, 0x0e, 0x13, 0x18, 0x1d,
+ 0x07, 0x08, 0x05, 0x0a, 0x01, 0x0f, 0x15, 0x1c,
+ 0x08, 0x09, 0x06, 0x0b, 0x01, 0x10, 0x16, 0x1d,
+ 0x09, 0x0a, 0x07, 0x0c, 0x02, 0x11, 0x16, 0x1c,
+ 0x0a, 0x0b, 0x08, 0x0d, 0x02, 0x12, 0x17, 0x1d,
+ 0x0b, 0x0c, 0x09, 0x0e, 0x03, 0x13, 0x18, 0x1d,
+ 0x0c, 0x0d, 0x0a, 0x0f, 0x05, 0x15, 0x01, 0x1c,
+ 0x0d, 0x0e, 0x0b, 0x10, 0x06, 0x15, 0x01, 0x1c,
+ 0x0e, 0x0f, 0x0c, 0x11, 0x07, 0x16, 0x02, 0x1c,
+ 0x0f, 0x10, 0x0d, 0x12, 0x08, 0x17, 0x02, 0x1d,
+ 0x10, 0x11, 0x0e, 0x13, 0x09, 0x18, 0x03, 0x1d,
+ 0x11, 0x12, 0x0f, 0x14, 0x09, 0x19, 0x02, 0x1e,
+ 0x12, 0x13, 0x10, 0x15, 0x0a, 0x1a, 0x03, 0x1e,
+ 0x13, 0x14, 0x11, 0x16, 0x0c, 0x1c, 0x07, 0x01,
+ 0x14, 0x15, 0x12, 0x17, 0x0d, 0x1c, 0x08, 0x02,
+ 0x15, 0x16, 0x13, 0x18, 0x0e, 0x1d, 0x08, 0x02,
+ 0x16, 0x17, 0x14, 0x19, 0x0f, 0x1e, 0x09, 0x02,
+ 0x17, 0x18, 0x15, 0x1a, 0x10, 0x1e, 0x0a, 0x03,
+ 0x18, 0x19, 0x16, 0x1b, 0x11, 0x1e, 0x0b, 0x03,
+ 0x19, 0x1a, 0x17, 0x1c, 0x12, 0x0d, 0x07, 0x02,
+ 0x1a, 0x1b, 0x18, 0x1d, 0x13, 0x0e, 0x08, 0x02,
+ 0x1b, 0x1c, 0x19, 0x1e, 0x14, 0x0f, 0x09, 0x02,
+ 0x1c, 0x1d, 0x1a, 0x15, 0x10, 0x0b, 0x06, 0x01,
+ 0x1d, 0x1e, 0x1b, 0x16, 0x11, 0x0c, 0x07, 0x02,
+ 0x1e, 0x1f, 0x1c, 0x17, 0x12, 0x0d, 0x08, 0x02,
+ 0x1f, 0x1e, 0x1b, 0x17, 0x12, 0x0d, 0x08, 0x02,
+};
+
+static const uint8_t table_460b[256] = {
+ 0x00, 0x01, 0x04, 0x08, 0x0d, 0x12, 0x17, 0x1d,
+ 0x01, 0x00, 0x03, 0x08, 0x0d, 0x12, 0x17, 0x1d,
+ 0x02, 0x01, 0x04, 0x09, 0x0e, 0x13, 0x18, 0x1d,
+ 0x03, 0x02, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1e,
+ 0x04, 0x03, 0x06, 0x01, 0x0b, 0x10, 0x16, 0x1d,
+ 0x05, 0x04, 0x07, 0x02, 0x0c, 0x11, 0x17, 0x1d,
+ 0x06, 0x05, 0x08, 0x03, 0x0d, 0x12, 0x18, 0x1d,
+ 0x07, 0x06, 0x09, 0x04, 0x0e, 0x01, 0x14, 0x1c,
+ 0x08, 0x07, 0x0a, 0x05, 0x0f, 0x01, 0x15, 0x1c,
+ 0x09, 0x08, 0x0b, 0x06, 0x10, 0x01, 0x16, 0x1d,
+ 0x0a, 0x09, 0x0c, 0x07, 0x11, 0x02, 0x17, 0x1d,
+ 0x0b, 0x0a, 0x0d, 0x08, 0x12, 0x03, 0x17, 0x1d,
+ 0x0c, 0x0b, 0x0e, 0x09, 0x13, 0x03, 0x18, 0x1e,
+ 0x0d, 0x0c, 0x0f, 0x0a, 0x15, 0x05, 0x1c, 0x01,
+ 0x0e, 0x0d, 0x10, 0x0b, 0x16, 0x06, 0x1d, 0x01,
+ 0x0f, 0x0e, 0x11, 0x0c, 0x16, 0x07, 0x1c, 0x02,
+ 0x10, 0x0f, 0x12, 0x0d, 0x17, 0x08, 0x1d, 0x02,
+ 0x11, 0x10, 0x13, 0x0e, 0x18, 0x09, 0x1d, 0x03,
+ 0x12, 0x11, 0x14, 0x0f, 0x19, 0x0a, 0x1e, 0x03,
+ 0x13, 0x12, 0x15, 0x10, 0x1a, 0x0a, 0x1e, 0x03,
+ 0x14, 0x13, 0x16, 0x11, 0x1c, 0x0c, 0x07, 0x02,
+ 0x15, 0x14, 0x17, 0x12, 0x1d, 0x0d, 0x08, 0x02,
+ 0x16, 0x15, 0x18, 0x13, 0x1d, 0x0e, 0x09, 0x03,
+ 0x17, 0x16, 0x19, 0x14, 0x1e, 0x0f, 0x09, 0x02,
+ 0x18, 0x17, 0x1a, 0x15, 0x1e, 0x10, 0x0a, 0x03,
+ 0x19, 0x18, 0x1b, 0x16, 0x11, 0x0c, 0x07, 0x02,
+ 0x1a, 0x19, 0x1c, 0x17, 0x12, 0x0d, 0x08, 0x02,
+ 0x1b, 0x1a, 0x1d, 0x18, 0x13, 0x0e, 0x08, 0x02,
+ 0x1c, 0x1b, 0x1e, 0x19, 0x14, 0x0f, 0x09, 0x03,
+ 0x1d, 0x1c, 0x1e, 0x1a, 0x15, 0x10, 0x09, 0x03,
+ 0x1e, 0x1d, 0x1b, 0x16, 0x11, 0x0c, 0x07, 0x02,
+ 0x1f, 0x1e, 0x1c, 0x17, 0x12, 0x0d, 0x08, 0x02,
+};
+
+/* Replicate seg3:0x5918 — 32-entry blue-channel gain LUT.
+ * Maps reconstructed 5-bit value (0..31) → gain-adjusted 5-bit value
(0..31). */
+static void build_gain_lut(uint8_t lut[32], uint8_t gain_byte)
+{
+ uint32_t step = 0x300U * (uint32_t)gain_byte + (5U << 16);
+ uint32_t acc = 0;
+ for (int i = 0; i < 32; i++) {
+ acc += step;
+ lut[i] = FFMIN(acc >> 19, 31);
+ }
+}
+
+static av_cold int vdec_decode_init(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ return 0;
+}
+
+static int vdec_decode_frame(AVCodecContext *avctx, AVFrame *frame,
+ int *got_frame, AVPacket *avpkt)
+{
+ const uint8_t *buf = avpkt->data;
+ int size = avpkt->size;
+ uint8_t gain_lut[32];
+ uint8_t *codes = NULL;
+ uint8_t *recon = NULL;
+ GetBitContext gb;
+ int ret;
+
+ if (size < 2) {
+ av_log(avctx, AV_LOG_ERROR, "packet too small (%d bytes)\n", size);
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* Header: buf[0]+1 bytes to skip (type tag + gain byte + optional
padding).
+ * buf[1] is always the blue-channel gain register. */
+ int skip = buf[0] + 1;
+ if (size <= skip) {
+ av_log(avctx, AV_LOG_ERROR, "header overruns packet\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ build_gain_lut(gain_lut, buf[1]);
+
+ ret = init_get_bits8(&gb, buf + skip, size - skip);
+ if (ret < 0)
+ return ret;
+
+ /* Step 1 — Huffman decode all codes. Dimensions are inferred from the
+ * bitstream after decoding, so the container size is ignored entirely.
+ * 640×480 is the largest known VDEC resolution. */
+ int max_codes = 640 * 480;
+ codes = av_malloc(max_codes * 3);
+ if (!codes)
+ return AVERROR(ENOMEM);
+
+ int n_decoded = 0;
+ while (n_decoded < max_codes) {
+ uint16_t v;
+ if (get_bits_left(&gb) >= 13 && show_bits(&gb, 3) == 0) {
+ v = table_430b[show_bits(&gb, 13)];
+ } else if (get_bits_left(&gb) >= 9) {
+ v = table_430a[show_bits(&gb, 9)];
+ } else {
+ break;
+ }
+ int nbits = (v >> 11) & 0x1f;
+ if (nbits == 0)
+ break;
+ codes[n_decoded * 3] = v & 0x7;
+ codes[n_decoded * 3 + 1] = (v >> 3) & 0x7;
+ codes[n_decoded * 3 + 2] = (v >> 6) & 0x7;
+ n_decoded++;
+ skip_bits(&gb, nbits);
+ }
+
+ if (n_decoded == 0) {
+ av_log(avctx, AV_LOG_ERROR, "no pixels decoded\n");
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ /* Infer encoded dimensions from pixel count (always 4:3 aspect ratio).
+ * The AVI container reports 2× the encoded size in each dimension,
so the
+ * packet contains pixels for one of: 160×120, 320×240, or 640×480. */
+ int enc_w, enc_h;
+ if (n_decoded <= 48000) { enc_w = 160; enc_h = 120; }
+ else if (n_decoded <= 192000) { enc_w = 320; enc_h = 240; }
+ else { enc_w = 640; enc_h = 480; }
+
+ ret = ff_set_dimensions(avctx, enc_w, enc_h);
+ if (ret < 0)
+ goto end;
+
+ /* Step 2 — DPCM reconstruction + write to output frame. */
+ recon = av_malloc(enc_w * enc_h * 3);
+ if (!recon) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ ret = ff_get_buffer(avctx, frame, 0);
+ if (ret < 0)
+ goto end;
+
+ int n = enc_w * enc_h;
+ for (int i = 0; i < n; i++) {
+ int col = i % enc_w;
+ int row = i / enc_w;
+ int carry = (row + col + 1) & 1;
+
+ int lr = col > 0 ? recon[(i - 1) * 3] : 16;
+ int lg = col > 0 ? recon[(i - 1) * 3 + 1] : 16;
+ int lb = col > 0 ? recon[(i - 1) * 3 + 2] : 16;
+ int ar = row > 0 ? recon[(i - enc_w) * 3] : 16;
+ int ag = row > 0 ? recon[(i - enc_w) * 3 + 1] : 16;
+ int ab = row > 0 ? recon[(i - enc_w) * 3 + 2] : 16;
+
+ int pr = (lr + ar + carry) >> 1;
+ int pg = (lg + ag + carry) >> 1;
+ int pb = (lb + ab + carry) >> 1;
+
+ const uint8_t *tbl = carry ? table_460b : table_460a;
+ recon[i * 3] = tbl[codes[i * 3] + pr * 8];
+ recon[i * 3 + 1] = tbl[codes[i * 3 + 1] + pg * 8];
+ recon[i * 3 + 2] = tbl[codes[i * 3 + 2] + pb * 8];
+
+ /* Codec bit layout: bits 0-2 = Blue, bits 3-5 = Green, bits
6-8 = Red.
+ * Gain LUT is applied to the Red channel. */
+ uint8_t b5 = recon[i * 3];
+ uint8_t g5 = recon[i * 3 + 1];
+ uint8_t r5 = gain_lut[recon[i * 3 + 2]];
+ uint8_t *dst = frame->data[0] + row * frame->linesize[0] + col * 3;
+ dst[0] = (r5 << 3) | (r5 >> 2);
+ dst[1] = (g5 << 3) | (g5 >> 2);
+ dst[2] = (b5 << 3) | (b5 >> 2);
+ }
+
+ *got_frame = 1;
+ ret = avpkt->size;
+end:
+ av_freep(&codes);
+ av_freep(&recon);
+ return ret;
+}
+
+const FFCodec ff_vdec_decoder = {
+ .p.name = "vdec",
+ CODEC_LONG_NAME("VDEC Huffman+DPCM video"),
+ .p.type = AVMEDIA_TYPE_VIDEO,
+ .p.id = AV_CODEC_ID_VDEC,
+ .init = vdec_decode_init,
+ FF_CODEC_DECODE_CB(vdec_decode_frame),
+ .p.capabilities = AV_CODEC_CAP_DR1,
+};
\ No newline at end of file
diff --git a/libavformat/riff.c b/libavformat/riff.c
index fc79d0ac21..a11e5a059d 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -382,6 +382,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_TRUEMOTION2RT,MKTAG('T', 'R', '2', '0') },
{ AV_CODEC_ID_CSCD, MKTAG('C', 'S', 'C', 'D') },
{ AV_CODEC_ID_ZMBV, MKTAG('Z', 'M', 'B', 'V') },
+ { AV_CODEC_ID_VDEC, MKTAG('V', 'D', 'E', 'C') },
{ AV_CODEC_ID_KMVC, MKTAG('K', 'M', 'V', 'C') },
{ AV_CODEC_ID_CAVS, MKTAG('C', 'A', 'V', 'S') },
{ AV_CODEC_ID_AVS2, MKTAG('A', 'V', 'S', '2') },
--
2.39.5
1
0
[PR] avfilter/vf_vqe_amf: Add AMF Video Quality Enhancer filter (PR #23536)
by ArazIusubov 19 Jun '26
by ArazIusubov 19 Jun '26
19 Jun '26
PR #23536 opened by ArazIusubov
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23536
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23536.patch
Introduce a new vqe_amf filter implementing AMD AMF Video Quality Enhancer.
The filter exposes VQ enhancement functionality through the attenuation option.
At present, the filter is available on Windows systems only.
Examples:
_ffmpeg -hwaccel amf -hwaccel_output_format amf -i input.mp4 -vf vqe_amf=attenuation=0.4 -c:v hevc_amf output.mp4_
_ffmpeg -init_hw_device d3d11va=dx11 -init_hw_device amf=hw@dx11 -filter_hw_device hw -i input.mp4 -vf vqe_amf=attenuation=0.4 -c:v hevc_amf output.mp4_
From 70e560eb05e76a4338b008789e26cd5440c4eb07 Mon Sep 17 00:00:00 2001
From: Araz Iusubov <Primeadvice(a)gmail.com>
Date: Fri, 19 Jun 2026 17:19:37 +0200
Subject: [PATCH] avfilter/vf_vqe_amf: Add AMF Video Quality Enhancer filter
---
Changelog | 2 +-
configure | 1 +
doc/filters.texi | 37 +++++++++
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/vf_vqe_amf.c | 169 +++++++++++++++++++++++++++++++++++++++
6 files changed, 210 insertions(+), 1 deletion(-)
create mode 100644 libavfilter/vf_vqe_amf.c
diff --git a/Changelog b/Changelog
index 2ad3ee255f..6f54ca07d7 100644
--- a/Changelog
+++ b/Changelog
@@ -18,7 +18,7 @@ version <next>:
- Remove ogg/celt parsing
- Bitstream filter to split Dolby Vision multi-layer HEVC
- Add AMF hardware memory mapping support.
-
+- Add AMF Video Quality Enhancer (vf_vqe_amf) filter
version 8.1:
- ffprobe -codec option
diff --git a/configure b/configure
index 5149f3c217..e4de18171d 100755
--- a/configure
+++ b/configure
@@ -4272,6 +4272,7 @@ scale_filter_deps="swscale"
sr_amf_filter_deps="amf"
vpp_amf_filter_deps="amf"
frc_amf_filter_deps="amf windows_h"
+vqe_amf_filter_deps="amf windows_h"
scale_qsv_filter_deps="libmfx"
scale_qsv_filter_select="qsvvpp"
scdet_filter_select="scene_sad"
diff --git a/doc/filters.texi b/doc/filters.texi
index 2cae41c7c5..63b4fcf1ab 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -14816,6 +14816,43 @@ Boolean value: enable dependency on future frame, improves quality for the cost
of latency (Default value: enabled).
@end table
+@section vqe_amf
+
+AMD AMF VQ Enhancer filter.
+This filter applies AMD AMF VQ Enhancement to the input video.
+
+This filter accepts the following option:
+
+@table @option
+
+@item attenuation
+Set VQ Enhancer strength. Allowed range is from @code{0.02} to @code{0.4}.
+Default is @code{0.1}.
+
+@item engine_type
+Set AMF memory type used by the filter.
+
+Possible values:
+
+@table @samp
+@item dx11
+DirectX 11
+@item dx12
+DirectX 12
+@item vulkan
+Vulkan
+@item opencl
+OpenCL
+@end table
+
+@end table
+
+Example:
+
+@example
+ffmpeg -i input.mp4 -vf vqe_amf=attenuation=0.4 -c:v hevc_amf output.mp4
+@end example
+
@section framestep
Select one frame every N-th frame.
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 5f0760a2ff..ae7da8b068 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -576,6 +576,7 @@ OBJS-$(CONFIG_VIGNETTE_FILTER) += vf_vignette.o
OBJS-$(CONFIG_VMAFMOTION_FILTER) += vf_vmafmotion.o framesync.o
OBJS-$(CONFIG_VPP_AMF_FILTER) += vf_vpp_amf.o scale_eval.o vf_amf_common.o
OBJS-$(CONFIG_FRC_AMF_FILTER) += vf_frc_amf.o vf_amf_common.o
+OBJS-$(CONFIG_VQE_AMF_FILTER) += vf_vqe_amf.o vf_amf_common.o
OBJS-$(CONFIG_VPP_QSV_FILTER) += vf_vpp_qsv.o
OBJS-$(CONFIG_VSTACK_FILTER) += vf_stack.o framesync.o
OBJS-$(CONFIG_W3FDIF_FILTER) += vf_w3fdif.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 66c49d453b..a56ca79f8f 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -444,6 +444,7 @@ extern const FFFilter ff_vf_scale;
extern const FFFilter ff_vf_vpp_amf;
extern const FFFilter ff_vf_sr_amf;
extern const FFFilter ff_vf_frc_amf;
+extern const FFFilter ff_vf_vqe_amf;
extern const FFFilter ff_vf_scale_cuda;
extern const FFFilter ff_vf_scale_d3d11;
extern const FFFilter ff_vf_scale_d3d12;
diff --git a/libavfilter/vf_vqe_amf.c b/libavfilter/vf_vqe_amf.c
new file mode 100644
index 0000000000..d7249d999b
--- /dev/null
+++ b/libavfilter/vf_vqe_amf.c
@@ -0,0 +1,169 @@
+/*
+ * 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
+ */
+
+/**
+ * @file
+ * Quality Enhancer video filter with AMF hardware acceleration
+ */
+
+#include "libavutil/opt.h"
+
+#include "libavutil/hwcontext.h"
+#include "libavutil/hwcontext_amf.h"
+#include "libavutil/hwcontext_amf_internal.h"
+
+#include "AMF/components/VQEnhancer.h"
+#include "vf_amf_common.h"
+
+#include "avfilter.h"
+#include "avfilter_internal.h"
+#include "formats.h"
+#include "video.h"
+
+#if CONFIG_D3D11VA
+#include <d3d11.h>
+#endif
+
+#if CONFIG_D3D12VA
+#include <d3d12.h>
+#endif
+
+typedef struct AMFVQEFilterContext {
+ AMFFilterContext common;
+
+ int engine_type;
+ double attenuation;
+} AMFVQEFilterContext;
+
+static int amf_vqe_init(AVFilterContext *avctx) {
+ AMFVQEFilterContext *ctx = avctx->priv;
+
+ ctx->common.format = AV_PIX_FMT_NONE;
+
+ return 0;
+}
+
+static int amf_filter_query_formats(AVFilterContext *avctx)
+{
+ const enum AVPixelFormat *output_pix_fmts;
+ static const enum AVPixelFormat input_pix_fmts[] = {
+ AV_PIX_FMT_AMF_SURFACE,
+ AV_PIX_FMT_NV12,
+ AV_PIX_FMT_P010,
+ AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_RGBAF16,
+ AV_PIX_FMT_X2BGR10,
+ AV_PIX_FMT_NONE,
+ };
+ static const enum AVPixelFormat output_pix_fmts_default[] = {
+ AV_PIX_FMT_AMF_SURFACE,
+ AV_PIX_FMT_NV12,
+ AV_PIX_FMT_P010,
+ AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_RGBAF16,
+ AV_PIX_FMT_X2BGR10,
+ AV_PIX_FMT_NONE,
+ };
+ output_pix_fmts = output_pix_fmts_default;
+
+ return amf_setup_input_output_formats(avctx, input_pix_fmts, output_pix_fmts);
+}
+
+static int amf_vqe_filter_config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *avctx = outlink->src;
+ AMFComponent *amf_filter = NULL;
+ AVFilterLink *inlink = avctx->inputs[0];
+ AMFVQEFilterContext *vqe_ctx = avctx->priv;
+ AMFFilterContext *amf_ctx = &vqe_ctx->common;
+ AVAMFDeviceContext *device_ctx = NULL;
+
+ int err;
+ AMF_RESULT res;
+ enum AVPixelFormat in_format;
+
+ err = amf_init_filter_config(outlink, &in_format);
+ if (err < 0)
+ return err;
+
+ device_ctx = amf_ctx->amf_device_ctx;
+
+ res = AMF_IFACE_CALL(device_ctx->factory, CreateComponent, device_ctx->context, AMFVQEnhancer, &amf_ctx->component);
+ AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_FILTER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", AMFVQEnhancer, res);
+
+ amf_filter = amf_ctx->component;
+
+ if (vqe_ctx->engine_type != -1)
+ AMF_ASSIGN_PROPERTY_INT64(res, amf_filter, AMF_VIDEO_ENHANCER_ENGINE_TYPE, vqe_ctx->engine_type);
+
+ AMF_ASSIGN_PROPERTY_DOUBLE(res, amf_filter, AMF_VE_FCR_ATTENUATION, vqe_ctx->attenuation);
+ AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "Failed to set VQ enhancer attenuation: %d\n", res);
+
+ res = AMF_IFACE_CALL(amf_filter, Init, av_av_to_amf_format(in_format), inlink->w, inlink->h);
+ AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "AMFVQEnhancer-Init() failed with error %d\n", res);
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(AMFVQEFilterContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption vqe_amf_options[] = {
+ { "engine_type", "Engine type", OFFSET(engine_type), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_MEMORY_OPENCL, .flags = FLAGS, "engine_type" },
+ { "dx11", "DirectX 11", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_MEMORY_DX11 }, 0, 0, FLAGS, "engine_type" },
+ { "dx12", "DirectX 12", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_MEMORY_DX12 }, 0, 0, FLAGS, "engine_type" },
+ { "vulkan", "Vulkan", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_MEMORY_VULKAN }, 0, 0, FLAGS, "engine_type" },
+ { "opencl", "OpenCL", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_MEMORY_OPENCL }, 0, 0, FLAGS, "engine_type" },
+
+ { "attenuation", "Control VQEnhancer strength", OFFSET(attenuation), AV_OPT_TYPE_DOUBLE, { .dbl = 0.1 }, 0.02, 0.4, FLAGS, "attenuation" },
+
+ { NULL },
+};
+
+AVFILTER_DEFINE_CLASS(vqe_amf);
+
+static const AVFilterPad amf_filter_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = amf_filter_filter_frame,
+ }
+};
+
+static const AVFilterPad amf_filter_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = amf_vqe_filter_config_output,
+ }
+};
+
+FFFilter ff_vf_vqe_amf = {
+ .p.name = "vqe_amf",
+ .p.description = NULL_IF_CONFIG_SMALL("AMD AMF VQ Enhancer"),
+ .p.priv_class = &vqe_amf_class,
+ .p.flags = AVFILTER_FLAG_HWDEVICE,
+ .priv_size = sizeof(AMFVQEFilterContext),
+ .init = amf_vqe_init,
+ .uninit = amf_filter_uninit,
+ FILTER_INPUTS(amf_filter_inputs),
+ FILTER_OUTPUTS(amf_filter_outputs),
+ FILTER_QUERY_FUNC(&amf_filter_query_formats),
+ .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
+};
--
2.52.0
1
0
[PATCH] ffbuild/common.mak: ensure target directories are created before running shell redirects into them
by Alexander Kanavin 19 Jun '26
by Alexander Kanavin 19 Jun '26
19 Jun '26
Otherwise, occasional build races have been observed:
https://autobuilder.yoctoproject.org/valkyrie/#/builders/37/builds/3001/ste…
/bin/sh: 4: cannot create fftools/resources/graph.css.min: Directory nonexistent
mkdir -p fftools/graph
/bin/sh: 1: cannot create fftools/resources/graph.html.gz: Directory nonexistent
make: *** [/srv/pokybuild/.../ffmpeg-8.0.1/ffbuild/common.mak:165: fftools/resources/graph.html.gz] Error 2
make: *** Waiting for unfinished jobs....
make: *** [/srv/pokybuild/.../ffmpeg-8.0.1/ffbuild/common.mak:145: fftools/resources/graph.css.min] Error 2
There's a separate rule for making those directories, but unfortunately
it's racing with the rules that expect the directories to exist. Rather
than add a Makefile dependency, I've injected the dir creation directly
in front of commands that can otherwise fail - a proper fix would probably
add the rule rather.
Signed-off-by: Alexander Kanavin <alex(a)linutronix.de>
---
ffbuild/common.mak | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ffbuild/common.mak b/ffbuild/common.mak
index 89c0c413e1..7f223297b8 100644
--- a/ffbuild/common.mak
+++ b/ffbuild/common.mak
@@ -125,8 +125,8 @@ $(BIN2CEXE): ffbuild/bin2c_host.o
$(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $^ $(HOSTEXTRALIBS)
RUN_BIN2C = $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@)))
-RUN_GZIP = $(M)gzip -nc9 $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) >$@
-RUN_MINIFY = $(M)sed 's!/\\*.*\\*/!!g' $< | tr '\n' ' ' | tr -s ' ' | sed 's/^ //; s/ $$//' > $@
+RUN_GZIP = mkdir -p $(dir $@) && $(M)gzip -nc9 $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) >$@
+RUN_MINIFY = mkdir -p $(dir $@) && $(M)sed 's!/\\*.*\\*/!!g' $< | tr '\n' ' ' | tr -s ' ' | sed 's/^ //; s/ $$//' > $@
%.gz: TAG = GZIP
%.min: TAG = MINIFY
--
2.47.3
2
1
18 Jun '26
PR #23535 opened by qwerzoid
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23535
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23535.patch
This commit adds support for vp8 and vp9 video codecs in addition
to the existing h264 so that the streams can be published using
either of them.
Signed-off-by: Aditya Banavi <adityabanavi(a)gmail.com>
From b4ed6d615830475ed1957f85474dcdc50294fa29 Mon Sep 17 00:00:00 2001
From: Aditya Banavi <adityabanavi(a)gmail.com>
Date: Thu, 18 Jun 2026 18:37:57 +0000
Subject: [PATCH] avformat/whip: Support for vp8 and vp9 video codecs
This commit adds support for vp8 and vp9 video codecs in addition
to the existing h264 so that the streams can be published using
either of them.
Signed-off-by: Aditya Banavi <adityabanavi(a)gmail.com>
---
libavformat/whip.c | 288 ++++++++++++++++++++++++++++++---------------
1 file changed, 190 insertions(+), 98 deletions(-)
diff --git a/libavformat/whip.c b/libavformat/whip.c
index edd9136d3e..79bc2fba50 100644
--- a/libavformat/whip.c
+++ b/libavformat/whip.c
@@ -96,8 +96,12 @@
*/
#define MAX_UDP_BUFFER_SIZE 4096
-/* Referring to Chrome's definition of RTP payload types. */
-#define WHIP_RTP_PAYLOAD_TYPE_H264 106
+/* Referring to Chrome's definition of RTP payload types. ( webrtc/media/base/constant.cc )*/
+#define WHIP_RTP_PAYLOAD_TYPE_VIDEO_VP8_RTX 96
+#define WHIP_RTP_PAYLOAD_TYPE_VIDEO_VP9_RTX 97
+#define WHIP_RTP_PAYLOAD_TYPE_VP8 100
+#define WHIP_RTP_PAYLOAD_TYPE_VP9 101
+#define WHIP_RTP_PAYLOAD_TYPE_H264 107
#define WHIP_RTP_PAYLOAD_TYPE_OPUS 111
#define WHIP_RTP_PAYLOAD_TYPE_VIDEO_RTX 105
@@ -484,39 +488,42 @@ static int parse_profile_level(AVFormatContext *s, AVCodecParameters *par)
uint32_t state;
WHIPContext *whip = s->priv_data;
- if (par->codec_id != AV_CODEC_ID_H264)
+ if (par->codec_id != AV_CODEC_ID_H264 && par->codec_id != AV_CODEC_ID_VP8 && par->codec_id != AV_CODEC_ID_VP9)
return ret;
- if (par->profile != AV_PROFILE_UNKNOWN && par->level != AV_LEVEL_UNKNOWN)
- return ret;
+ if (par->codec_id == AV_CODEC_ID_H264) {
- if (!par->extradata || par->extradata_size <= 0) {
- av_log(whip, AV_LOG_ERROR, "Unable to parse profile from empty extradata=%p, size=%d\n",
- par->extradata, par->extradata_size);
- return AVERROR(EINVAL);
- }
+ if (par->profile != AV_PROFILE_UNKNOWN && par->level != AV_LEVEL_UNKNOWN)
+ return ret;
- while (1) {
- r = avpriv_find_start_code(r, end, &state);
- if (r >= end)
- break;
-
- r1 = ff_nal_find_startcode(r, end);
- if ((state & 0x1f) == H264_NAL_SPS) {
- ret = ff_avc_decode_sps(sps, r, r1 - r);
- if (ret < 0) {
- av_log(whip, AV_LOG_ERROR, "Failed to decode SPS, state=%x, size=%d\n",
- state, (int)(r1 - r));
- return ret;
- }
-
- av_log(whip, AV_LOG_VERBOSE, "Parse profile=%d, level=%d from SPS\n",
- sps->profile_idc, sps->level_idc);
- par->profile = sps->profile_idc;
- par->level = sps->level_idc;
+ if (!par->extradata || par->extradata_size <= 0) {
+ av_log(whip, AV_LOG_ERROR, "Unable to parse profile from empty extradata=%p, size=%d\n",
+ par->extradata, par->extradata_size);
+ return AVERROR(EINVAL);
}
- r = r1;
+ while (1) {
+ r = avpriv_find_start_code(r, end, &state);
+ if (r >= end)
+ break;
+
+ r1 = ff_nal_find_startcode(r, end);
+ if ((state & 0x1f) == H264_NAL_SPS) {
+ ret = ff_avc_decode_sps(sps, r, r1 - r);
+ if (ret < 0) {
+ av_log(whip, AV_LOG_ERROR, "Failed to decode SPS, state=%x, size=%d\n",
+ state, (int)(r1 - r));
+ return ret;
+ }
+
+ av_log(whip, AV_LOG_VERBOSE, "Parse profile=%d, level=%d from SPS\n",
+ sps->profile_idc, sps->level_idc);
+ par->profile = sps->profile_idc;
+ par->level = sps->level_idc;
+ }
+
+ r = r1;
+ }
}
return ret;
@@ -559,32 +566,35 @@ static int parse_codec(AVFormatContext *s)
return AVERROR_PATCHWELCOME;
}
- if ((ret = parse_profile_level(s, par)) < 0) {
- av_log(whip, AV_LOG_ERROR, "Failed to parse SPS/PPS from extradata\n");
- return AVERROR(EINVAL);
- }
+ if (par->codec_id == AV_CODEC_ID_H264) {
- if (par->profile == AV_PROFILE_UNKNOWN) {
- av_log(whip, AV_LOG_WARNING, "No profile found in extradata, consider baseline\n");
- return AVERROR(EINVAL);
- }
- if (par->level == AV_LEVEL_UNKNOWN) {
- av_log(whip, AV_LOG_WARNING, "No level found in extradata, consider 3.1\n");
- return AVERROR(EINVAL);
- }
- break;
- case AVMEDIA_TYPE_AUDIO:
- whip->audio_par = par;
+ if ((ret = parse_profile_level(s, par)) < 0) {
+ av_log(whip, AV_LOG_ERROR, "Failed to parse SPS/PPS from extradata\n");
+ return AVERROR(EINVAL);
+ }
- if (par->ch_layout.nb_channels != 2) {
- av_log(whip, AV_LOG_ERROR, "Unsupported audio channels %d by RTC, choose stereo\n",
- par->ch_layout.nb_channels);
- return AVERROR_PATCHWELCOME;
- }
+ if (par->profile == AV_PROFILE_UNKNOWN) {
+ av_log(whip, AV_LOG_WARNING, "No profile found in extradata, consider baseline\n");
+ return AVERROR(EINVAL);
+ }
+ if (par->level == AV_LEVEL_UNKNOWN) {
+ av_log(whip, AV_LOG_WARNING, "No level found in extradata, consider 3.1\n");
+ return AVERROR(EINVAL);
+ }
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ whip->audio_par = par;
- if (par->sample_rate != 48000) {
- av_log(whip, AV_LOG_ERROR, "Unsupported audio sample rate %d by RTC, choose 48000\n", par->sample_rate);
- return AVERROR_PATCHWELCOME;
+ if (par->ch_layout.nb_channels != 2) {
+ av_log(whip, AV_LOG_ERROR, "Unsupported audio channels %d by RTC, choose stereo\n",
+ par->ch_layout.nb_channels);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (par->sample_rate != 48000) {
+ av_log(whip, AV_LOG_ERROR, "Unsupported audio sample rate %d by RTC, choose 48000\n", par->sample_rate);
+ return AVERROR_PATCHWELCOME;
+ }
}
break;
default:
@@ -632,10 +642,6 @@ static int generate_sdp_offer(AVFormatContext *s)
whip->video_ssrc = whip->audio_ssrc + 1;
whip->video_rtx_ssrc = whip->video_ssrc + 1;
- whip->audio_payload_type = WHIP_RTP_PAYLOAD_TYPE_OPUS;
- whip->video_payload_type = WHIP_RTP_PAYLOAD_TYPE_H264;
- whip->video_rtx_payload_type = WHIP_RTP_PAYLOAD_TYPE_VIDEO_RTX;
-
if (whip->audio_par) {
bundle[bundle_index++] = '0';
bundle[bundle_index++] = ' ';
@@ -659,8 +665,10 @@ static int generate_sdp_offer(AVFormatContext *s)
bundle);
if (whip->audio_par) {
- if (whip->audio_par->codec_id == AV_CODEC_ID_OPUS)
+ if (whip->audio_par->codec_id == AV_CODEC_ID_OPUS) {
acodec_name = "opus";
+ whip->audio_payload_type = WHIP_RTP_PAYLOAD_TYPE_OPUS;
+ }
av_bprintf(&bp, ""
"m=audio 9 UDP/TLS/RTP/SAVPF %u\r\n"
@@ -693,51 +701,135 @@ static int generate_sdp_offer(AVFormatContext *s)
level = whip->video_par->level;
if (whip->video_par->codec_id == AV_CODEC_ID_H264) {
vcodec_name = "H264";
+ whip->video_payload_type = WHIP_RTP_PAYLOAD_TYPE_H264;
+ whip->video_rtx_payload_type = WHIP_RTP_PAYLOAD_TYPE_VIDEO_RTX;
profile_iop |= whip->video_par->profile & AV_PROFILE_H264_CONSTRAINED ? 1 << 6 : 0;
profile_iop |= whip->video_par->profile & AV_PROFILE_H264_INTRA ? 1 << 4 : 0;
profile_idc = whip->video_par->profile & 0x00ff;
- }
- av_bprintf(&bp, ""
- "m=video 9 UDP/TLS/RTP/SAVPF %u %u\r\n"
- "c=IN IP4 0.0.0.0\r\n"
- "a=ice-ufrag:%s\r\n"
- "a=ice-pwd:%s\r\n"
- "a=fingerprint:sha-256 %s\r\n"
- "a=setup:%s\r\n"
- "a=mid:1\r\n"
- "a=sendonly\r\n"
- "a=msid:FFmpeg video\r\n"
- "a=rtcp-mux\r\n"
- "a=rtcp-rsize\r\n"
- "a=rtpmap:%u %s/90000\r\n"
- "a=fmtp:%u level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=%02x%02x%02x\r\n"
- "a=rtcp-fb:%u nack\r\n"
- "a=rtpmap:%u rtx/90000\r\n"
- "a=fmtp:%u apt=%u\r\n"
- "a=ssrc-group:FID %u %u\r\n"
- "a=ssrc:%u cname:FFmpeg\r\n"
- "a=ssrc:%u msid:FFmpeg video\r\n",
- whip->video_payload_type,
- whip->video_rtx_payload_type,
- whip->ice_ufrag_local,
- whip->ice_pwd_local,
- whip->dtls_fingerprint,
- is_dtls_active ? "active" : "passive",
- whip->video_payload_type,
- vcodec_name,
- whip->video_payload_type,
- profile_idc,
- profile_iop,
- level,
- whip->video_payload_type,
- whip->video_rtx_payload_type,
- whip->video_rtx_payload_type,
- whip->video_payload_type,
- whip->video_ssrc,
- whip->video_rtx_ssrc,
- whip->video_ssrc,
- whip->video_ssrc);
+ av_bprintf(&bp, ""
+ "m=video 9 UDP/TLS/RTP/SAVPF %u %u\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=ice-ufrag:%s\r\n"
+ "a=ice-pwd:%s\r\n"
+ "a=fingerprint:sha-256 %s\r\n"
+ "a=setup:%s\r\n"
+ "a=mid:1\r\n"
+ "a=sendonly\r\n"
+ "a=msid:FFmpeg video\r\n"
+ "a=rtcp-mux\r\n"
+ "a=rtcp-rsize\r\n"
+ "a=rtpmap:%u %s/90000\r\n"
+ "a=fmtp:%u level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=%02x%02x%02x\r\n"
+ "a=rtcp-fb:%u nack\r\n"
+ "a=rtpmap:%u rtx/90000\r\n"
+ "a=fmtp:%u apt=%u\r\n"
+ "a=ssrc-group:FID %u %u\r\n"
+ "a=ssrc:%u cname:FFmpeg\r\n"
+ "a=ssrc:%u msid:FFmpeg video\r\n",
+ whip->video_payload_type,
+ whip->video_rtx_payload_type,
+ whip->ice_ufrag_local,
+ whip->ice_pwd_local,
+ whip->dtls_fingerprint,
+ is_dtls_active ? "active" : "passive",
+ whip->video_payload_type,
+ vcodec_name,
+ whip->video_payload_type,
+ profile_idc,
+ profile_iop,
+ level,
+ whip->video_payload_type,
+ whip->video_rtx_payload_type,
+ whip->video_rtx_payload_type,
+ whip->video_payload_type,
+ whip->video_ssrc,
+ whip->video_rtx_ssrc,
+ whip->video_ssrc,
+ whip->video_ssrc);
+ }
+ else if (whip->video_par->codec_id == AV_CODEC_ID_VP8) {
+ vcodec_name = "VP8";
+ whip->video_payload_type = WHIP_RTP_PAYLOAD_TYPE_VP8;
+ whip->video_rtx_payload_type = WHIP_RTP_PAYLOAD_TYPE_VIDEO_VP8_RTX;
+
+ av_bprintf(&bp, ""
+ "m=video 9 UDP/TLS/RTP/SAVPF %u %u\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=ice-ufrag:%s\r\n"
+ "a=ice-pwd:%s\r\n"
+ "a=fingerprint:sha-256 %s\r\n"
+ "a=setup:%s\r\n"
+ "a=mid:1\r\n"
+ "a=sendonly\r\n"
+ "a=msid:FFmpeg video\r\n"
+ "a=rtcp-mux\r\n"
+ "a=rtcp-rsize\r\n"
+ "a=rtpmap:%u %s/90000\r\n"
+ "a=rtcp-fb:%u nack\r\n"
+ "a=rtpmap:%u rtx/90000\r\n"
+ "a=fmtp:%u apt=%u\r\n"
+ "a=ssrc-group:FID %u %u\r\n"
+ "a=ssrc:%u cname:FFmpeg\r\n"
+ "a=ssrc:%u msid:FFmpeg video\r\n",
+ whip->video_payload_type,
+ whip->video_rtx_payload_type,
+ whip->ice_ufrag_local,
+ whip->ice_pwd_local,
+ whip->dtls_fingerprint,
+ is_dtls_active ? "active" : "passive",
+ whip->video_payload_type,
+ vcodec_name,
+ whip->video_payload_type,
+ whip->video_rtx_payload_type,
+ whip->video_rtx_payload_type,
+ whip->video_payload_type,
+ whip->video_ssrc,
+ whip->video_rtx_ssrc,
+ whip->video_ssrc,
+ whip->video_ssrc);
+ }
+ else if (whip->video_par->codec_id == AV_CODEC_ID_VP9) {
+ vcodec_name = "VP9";
+ whip->video_payload_type = WHIP_RTP_PAYLOAD_TYPE_VP9;
+ whip->video_rtx_payload_type = WHIP_RTP_PAYLOAD_TYPE_VIDEO_VP9_RTX;
+
+ av_bprintf(&bp, ""
+ "m=video 9 UDP/TLS/RTP/SAVPF %u %u\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=ice-ufrag:%s\r\n"
+ "a=ice-pwd:%s\r\n"
+ "a=fingerprint:sha-256 %s\r\n"
+ "a=setup:%s\r\n"
+ "a=mid:1\r\n"
+ "a=sendonly\r\n"
+ "a=msid:FFmpeg video\r\n"
+ "a=rtcp-mux\r\n"
+ "a=rtcp-rsize\r\n"
+ "a=rtpmap:%u %s/90000\r\n"
+ "a=rtcp-fb:%u nack\r\n"
+ "a=rtpmap:%u rtx/90000\r\n"
+ "a=fmtp:%u apt=%u\r\n"
+ "a=ssrc-group:FID %u %u\r\n"
+ "a=ssrc:%u cname:FFmpeg\r\n"
+ "a=ssrc:%u msid:FFmpeg video\r\n",
+ whip->video_payload_type,
+ whip->video_rtx_payload_type,
+ whip->ice_ufrag_local,
+ whip->ice_pwd_local,
+ whip->dtls_fingerprint,
+ is_dtls_active ? "active" : "passive",
+ whip->video_payload_type,
+ vcodec_name,
+ whip->video_payload_type,
+ whip->video_rtx_payload_type,
+ whip->video_rtx_payload_type,
+ whip->video_payload_type,
+ whip->video_ssrc,
+ whip->video_rtx_ssrc,
+ whip->video_ssrc,
+ whip->video_ssrc);
+ }
}
if (!av_bprint_is_complete(&bp)) {
--
2.52.0
1
0
[PR] avformat/movenc: look for remainder samples in packet side data (PR #23534)
by James Almer 18 Jun '26
by James Almer 18 Jun '26
18 Jun '26
PR #23534 opened by James Almer (jamrial)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23534
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23534.patch
Sometimes the duration itself reflects the remainder samples by being set to a value lower than the frame size, but in other cases it's done only through a discard padding value in side data.
Take the latter into account when calculating durations.
From 0e1cf2dbdb9c7fa95f1b85ce25d6e6fd1af19f3b Mon Sep 17 00:00:00 2001
From: James Almer <jamrial(a)gmail.com>
Date: Thu, 18 Jun 2026 15:05:04 -0300
Subject: [PATCH] avformat/movenc: look for remainder samples in packet side
data
Sometimes the duration itself reflects the remainder samples by being set to a
value lower than the frame size, but in other cases it's done only through
a discard padding value in side data.
Take the latter into account when calculating durations.
Fixes issue #23532.
Signed-off-by: James Almer <jamrial(a)gmail.com>
---
libavformat/movenc.c | 17 ++++++++++++++---
tests/ref/fate/filter-meta-4560-rotate0 | 6 +++---
tests/ref/fate/mov-cover-image | 4 ++--
3 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 7c9dbb29f7..1ab9d170c7 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -6941,6 +6941,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
AVCodecParameters *par;
AVProducerReferenceTime *prft;
unsigned int samples_in_chunk = 0;
+ int64_t duration = pkt->duration;
int size = pkt->size, ret = 0, offset = 0;
size_t prft_size;
uint8_t *reformatted_data = NULL;
@@ -7310,7 +7311,17 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
"this case.\n",
pkt->stream_index, pkt->dts);
}
- trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
+
+ sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_SKIP_SAMPLES);
+ if (sd && sd->size >= 10 && trk->par->frame_size) {
+ duration = FFMAX(trk->par->frame_size, duration);
+ duration -= av_rescale_q(AV_RL32(sd->data + 4), (AVRational){ 1, trk->par->sample_rate },
+ trk->st->time_base);
+ if (duration < 0)
+ return AVERROR_INVALIDDATA;
+ }
+
+ trk->track_duration = pkt->dts - trk->start_dts + duration;
trk->last_sample_is_subtitle_end = 0;
if (pkt->pts == AV_NOPTS_VALUE) {
@@ -7325,11 +7336,11 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
trk->start_cts = pkt->pts - pkt->dts;
if (trk->end_pts == AV_NOPTS_VALUE)
trk->end_pts = trk->cluster[trk->entry].dts +
- trk->cluster[trk->entry].cts + pkt->duration;
+ trk->cluster[trk->entry].cts + duration;
else
trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
trk->cluster[trk->entry].cts +
- pkt->duration);
+ duration);
if (!(pkt->flags & AV_PKT_FLAG_DISCARD))
trk->elst_end_pts = trk->end_pts;
diff --git a/tests/ref/fate/filter-meta-4560-rotate0 b/tests/ref/fate/filter-meta-4560-rotate0
index 7ebd52092d..cd49574672 100644
--- a/tests/ref/fate/filter-meta-4560-rotate0
+++ b/tests/ref/fate/filter-meta-4560-rotate0
@@ -1,5 +1,5 @@
-8718876acc3ffd74610daba770900b40 *tests/data/fate/filter-meta-4560-rotate0.mov
-347425 tests/data/fate/filter-meta-4560-rotate0.mov
+18ca1e5d9da95d06b75937eae003a38f *tests/data/fate/filter-meta-4560-rotate0.mov
+347433 tests/data/fate/filter-meta-4560-rotate0.mov
#tb 0: 1/30
#media_type 0: video
#codec_id 0: rawvideo
@@ -265,4 +265,4 @@
1, 151552, 151552, 1024, 2048, 0x473a05a3
1, 152576, 152576, 1024, 2048, 0x26721b75
0, 104, 104, 1, 195840, 0x46851b87
-1, 153600, 153600, 1024, 2048, 0x97a2f42c
+1, 153600, 153600, 89, 178, 0x94b35030
diff --git a/tests/ref/fate/mov-cover-image b/tests/ref/fate/mov-cover-image
index b0db8f9dd2..f128037a8b 100644
--- a/tests/ref/fate/mov-cover-image
+++ b/tests/ref/fate/mov-cover-image
@@ -1,5 +1,5 @@
-017a372d92c59971c2ddee95298e745a *tests/data/fate/mov-cover-image.mp4
-1024065 tests/data/fate/mov-cover-image.mp4
+616f09865fa0e4f90b168f16ce2b2538 *tests/data/fate/mov-cover-image.mp4
+1024073 tests/data/fate/mov-cover-image.mp4
#extradata 0: 2, 0x00340022
#tb 0: 1/44100
#media_type 0: audio
--
2.52.0
1
0
Hi all
planing to backport fixes and make new releases from 8.0 + 8.1 branches soon
ideal case would be finishing backporting today and releases tomorrow but
iam not sure ill manage to achieve that
thx
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Into a blind darkness they enter who follow after the Ignorance,
they as if into a greater darkness enter who devote themselves
to the Knowledge alone. -- Isha Upanishad
1
2
18 Jun '26
The Resolume DXV codec is based on 4x4 pixel DXT1/DXT5/BC4/BC5 blocks, so
it's natural to assume that files would be padded to multiples of 4 in width
and height. But in practice .mov files produced by the Resolume software are
always padded to multiples of 16 in width and height, so FFmpeg currently
decodes them incorrectly.
When encoding FFmpeg already pads both width and height to 16 so no change
is required - see libavcodec/dxvenc.c:37-40 (commit
d4556c98f02e4f2d3deb86efeb060ebe4659be96):
/*
* Resolume will refuse to display frames that are not padded to 16x16 pixels.
*/
#define DXV_ALIGN(x) FFALIGN(x, 16)
---
libavcodec/dxv.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libavcodec/dxv.c b/libavcodec/dxv.c
index 344c7b2f3c..bae46cdee0 100644
--- a/libavcodec/dxv.c
+++ b/libavcodec/dxv.c
@@ -1089,8 +1089,8 @@ static av_cold int dxv_init(AVCodecContext *avctx)
return ret;
}
- /* Since codec is based on 4x4 blocks, size is aligned to 4 */
- avctx->coded_width = FFALIGN(avctx->width, TEXTURE_BLOCK_W);
+ /* Codec is based on 4x4 blocks, but in practice width is aligned to 16 */
+ avctx->coded_width = FFALIGN(avctx->width, 16);
avctx->coded_height = FFALIGN(avctx->height, TEXTURE_BLOCK_H);
ff_texturedsp_init(&ctx->texdsp);
--
1
0
[PR] avformat/mov: don't assume a sample to be the last in fragmented input (PR #23533)
by James Almer 18 Jun '26
by James Almer 18 Jun '26
18 Jun '26
PR #23533 opened by James Almer (jamrial)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23533
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23533.patch
Both the seek index and the stream duration are constantly being updated as trun boxes are read.
Fixes mpv issue 18149.
From 62731e05ab6f8b1aaefc33f3400952e88ada04fe Mon Sep 17 00:00:00 2001
From: James Almer <jamrial(a)gmail.com>
Date: Thu, 18 Jun 2026 13:46:52 -0300
Subject: [PATCH] avformat/mov: don't assume a sample to be the last in
fragmented input
Both the seek index and the stream duration are constantly being updated as
trun boxes are read.
Fixes mpv issue 18149.
Signed-off-by: James Almer <jamrial(a)gmail.com>
---
libavformat/mov.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 7513b3ccc1..0915b35a7f 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -11626,6 +11626,7 @@ static int get_eia608_packet(AVIOContext *pb, AVPacket *pkt, int src_size)
static int mov_finalize_packet(AVFormatContext *s, AVStream *st, AVIndexEntry *sample,
int64_t current_index, AVPacket *pkt)
{
+ MOVContext *mov = s->priv_data;
MOVStreamContext *sc = st->priv_data;
pkt->stream_index = sc->ffindex;
@@ -11647,7 +11648,7 @@ static int mov_finalize_packet(AVFormatContext *s, AVStream *st, AVIndexEntry *s
pkt->pts = pkt->dts;
}
- if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && !mov->fragment.found_tfhd &&
sc->current_sample >= ffstream(st)->nb_index_entries) {
int64_t pts = av_rescale_q(pkt->pts, st->time_base, (AVRational){ 1, st->codecpar->sample_rate });
int64_t total = av_rescale_q(st->duration, st->time_base, (AVRational){ 1, st->codecpar->sample_rate });
--
2.52.0
1
0
[PR] avdevice/avfoundation: wait for frame consumption to avoid dropping A/V frames (PR #23531)
by Jun Zhao 18 Jun '26
by Jun Zhao 18 Jun '26
18 Jun '26
PR #23531 opened by Jun Zhao (mypopydev)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23531
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23531.patch
The capture callback dropped the previous frame instead of waiting for it
to be consumed, so frames were lost when avf_read_packet() fell behind;
39fbd06314 (return EAGAIN instead of waiting) made it easy to hit.
Add back a condition variable: the capture callback blocks until
avf_read_packet() takes the current frame, and the reader waits on it when
no frame is ready. An is_stopping flag set in destroy_context() wakes both
sides so teardown cannot deadlock. observed_quit is now set under the lock
and broadcast as well, so a blocked reader wakes and returns EOF when a
transport-control device stops delivering frames.
Based on a patch by Zhongxin Zhuang <zx.zhuang(a)hotmail.com>; here
unlock_frames() only broadcasts and unlocks, so a read no longer releases
the other stream's still-unconsumed frame.
Verified by capturing camera+mic for 8s and comparing delivered packet
counts before/after this change:
ffmpeg -f avfoundation -pixel_format nv12 -framerate 30 -i "0:0" -t 8 \
-vf "scale=2560:1440,hqdn3d" -c:v libx264 -preset medium \
-c:a aac out.mp4
ffprobe -count_packets -show_entries stream=nb_read_packets out.mp4
slow consumer (ideal: video ~240, audio ~375)
video audio
before (EAGAIN) 174 163 (audio ~57% dropped)
after (condvar) 234 376 (no drops)
fast consumer (-preset ultrafast, no filter)
before 240 328
after 238 376
Signed-off-by: Jun Zhao <barryjzhao(a)tencent.com>
# Summary of changes
Briefly describe what this PR does and why.
<!--
If this PR requires new FATE test samples, attach them to the PR and
list their target paths below (relative to the fate-suite root).
Attached filenames must match the sample's filename:
```fate-samples
# e.g. vorbis/new-sample.ogg
```
-->
From 388eaee4fde6cc5ee8ee297588a3cd907fe0bfcf Mon Sep 17 00:00:00 2001
From: Jun Zhao <barryjzhao(a)tencent.com>
Date: Thu, 18 Jun 2026 23:14:21 +0800
Subject: [PATCH] avdevice/avfoundation: wait for frame consumption to avoid
dropping A/V frames
The capture callback dropped the previous frame instead of waiting for it
to be consumed, so frames were lost when avf_read_packet() fell behind;
39fbd06314 (return EAGAIN instead of waiting) made it easy to hit.
Add back a condition variable: the capture callback blocks until
avf_read_packet() takes the current frame, and the reader waits on it when
no frame is ready. An is_stopping flag set in destroy_context() wakes both
sides so teardown cannot deadlock. observed_quit is now set under the lock
and broadcast as well, so a blocked reader wakes and returns EOF when a
transport-control device stops delivering frames.
Based on a patch by Zhongxin Zhuang <zx.zhuang(a)hotmail.com>; here
unlock_frames() only broadcasts and unlocks, so a read no longer releases
the other stream's still-unconsumed frame.
Verified by capturing camera+mic for 8s and comparing delivered packet
counts before/after this change:
ffmpeg -f avfoundation -pixel_format nv12 -framerate 30 -i "0:0" -t 8 \
-vf "scale=2560:1440,hqdn3d" -c:v libx264 -preset medium \
-c:a aac out.mp4
ffprobe -count_packets -show_entries stream=nb_read_packets out.mp4
slow consumer (ideal: video ~240, audio ~375)
video audio
before (EAGAIN) 174 163 (audio ~57% dropped)
after (condvar) 234 376 (no drops)
fast consumer (-preset ultrafast, no filter)
before 240 328
after 238 376
Signed-off-by: Jun Zhao <barryjzhao(a)tencent.com>
---
libavdevice/avfoundation.m | 56 ++++++++++++++++++++++++++++++++------
1 file changed, 47 insertions(+), 9 deletions(-)
diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m
index ebec1ac4f2..6f52989fc9 100644
--- a/libavdevice/avfoundation.m
+++ b/libavdevice/avfoundation.m
@@ -89,6 +89,8 @@ typedef struct
int frames_captured;
int audio_frames_captured;
pthread_mutex_t frame_lock;
+ pthread_cond_t frame_wait_cond;
+ int is_stopping;
id avf_delegate;
id avf_audio_delegate;
@@ -147,6 +149,7 @@ static void lock_frames(AVFContext* ctx)
static void unlock_frames(AVFContext* ctx)
{
+ pthread_cond_broadcast(&ctx->frame_wait_cond);
pthread_mutex_unlock(&ctx->frame_lock);
}
@@ -210,7 +213,12 @@ static void unlock_frames(AVFContext* ctx)
if (mode != _context->observed_mode) {
if (mode == AVCaptureDeviceTransportControlsNotPlayingMode) {
+ // Set under the lock and broadcast so a reader blocked in
+ // avf_read_packet() wakes up and returns EOF instead of
+ // hanging once the device stops delivering frames.
+ lock_frames(_context);
_context->observed_quit = 1;
+ unlock_frames(_context);
}
_context->observed_mode = mode;
}
@@ -229,8 +237,13 @@ static void unlock_frames(AVFContext* ctx)
{
lock_frames(_context);
- if (_context->current_frame != nil) {
- CFRelease(_context->current_frame);
+ while ((_context->current_frame != nil) && !_context->is_stopping) {
+ pthread_cond_wait(&_context->frame_wait_cond, &_context->frame_lock);
+ }
+
+ if (_context->is_stopping) {
+ unlock_frames(_context);
+ return;
}
_context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame);
@@ -273,8 +286,13 @@ static void unlock_frames(AVFContext* ctx)
{
lock_frames(_context);
- if (_context->current_audio_frame != nil) {
- CFRelease(_context->current_audio_frame);
+ while ((_context->current_audio_frame != nil) && !_context->is_stopping) {
+ pthread_cond_wait(&_context->frame_wait_cond, &_context->frame_lock);
+ }
+
+ if (_context->is_stopping) {
+ unlock_frames(_context);
+ return;
}
_context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame);
@@ -288,6 +306,12 @@ static void unlock_frames(AVFContext* ctx)
static void destroy_context(AVFContext* ctx)
{
+ // Wake any capture callback blocked waiting for the consumer and make it
+ // bail out, so stopRunning() can drain the session without a deadlock.
+ lock_frames(ctx);
+ ctx->is_stopping = 1;
+ unlock_frames(ctx);
+
[ctx->capture_session stopRunning];
[ctx->capture_session release];
@@ -305,10 +329,17 @@ static void destroy_context(AVFContext* ctx)
av_freep(&ctx->url);
av_freep(&ctx->audio_buffer);
+ pthread_cond_destroy(&ctx->frame_wait_cond);
pthread_mutex_destroy(&ctx->frame_lock);
if (ctx->current_frame) {
CFRelease(ctx->current_frame);
+ ctx->current_frame = nil;
+ }
+
+ if (ctx->current_audio_frame) {
+ CFRelease(ctx->current_audio_frame);
+ ctx->current_audio_frame = nil;
}
}
@@ -836,6 +867,8 @@ static int avf_read_header(AVFormatContext *s)
ctx->num_video_devices = [devices count] + [devices_muxed count];
pthread_mutex_init(&ctx->frame_lock, NULL);
+ pthread_cond_init(&ctx->frame_wait_cond, NULL);
+ ctx->is_stopping = 0;
#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
CGGetActiveDisplayList(0, NULL, &num_screens);
@@ -1120,10 +1153,10 @@ static int avf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVFContext* ctx = (AVFContext*)s->priv_data;
+ lock_frames(ctx);
do {
CVImageBufferRef image_buffer;
CMBlockBufferRef block_buffer;
- lock_frames(ctx);
if (ctx->current_frame != nil) {
int status;
@@ -1253,16 +1286,21 @@ static int avf_read_packet(AVFormatContext *s, AVPacket *pkt)
ctx->current_audio_frame = nil;
} else {
pkt->data = NULL;
- unlock_frames(ctx);
if (ctx->observed_quit) {
+ unlock_frames(ctx);
return AVERROR_EOF;
- } else {
- return AVERROR(EAGAIN);
}
+ // No frame available yet: wait until a capture callback delivers
+ // one (or until the device is being torn down).
+ pthread_cond_wait(&ctx->frame_wait_cond, &ctx->frame_lock);
}
+ } while (!pkt->data && !ctx->is_stopping);
+ if (ctx->is_stopping) {
unlock_frames(ctx);
- } while (!pkt->data);
+ return AVERROR_EOF;
+ }
+ unlock_frames(ctx);
return 0;
}
--
2.52.0
1
0
PR #23530 opened by Ramiro Polla (ramiro)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23530
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23530.patch
Introduces more specific swizzle operations, and removes some duplicates for read/write/clear/linear.
From 6bd6059aecbae45670d0ebfee44a21423a719ed6 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Tue, 16 Jun 2026 13:56:20 +0200
Subject: [PATCH 1/4] swscale/aarch64/ops: remove redundant single-component
packed read/write
These functions are essentially the same as single-component planar
read/write, and are actually never instantiated. This was left over
from the initial implementation.
---
libswscale/aarch64/ops_asmgen.c | 56 +++++----------------------------
1 file changed, 8 insertions(+), 48 deletions(-)
diff --git a/libswscale/aarch64/ops_asmgen.c b/libswscale/aarch64/ops_asmgen.c
index c03e0832ee..53501f52ea 100644
--- a/libswscale/aarch64/ops_asmgen.c
+++ b/libswscale/aarch64/ops_asmgen.c
@@ -449,23 +449,6 @@ static void asmgen_op_read_nibble(SwsAArch64Context *s, const SwsAArch64OpImplPa
}
}
-static void asmgen_op_read_packed_1(SwsAArch64Context *s, const SwsAArch64OpImplParams *p)
-{
- RasmContext *r = s->rctx;
- AArch64VecViews vl[1];
- AArch64VecViews vh[1];
-
- a64op_vec_views(s->vl[0], &vl[0]);
- a64op_vec_views(s->vh[0], &vh[0]);
-
- switch ((s->use_vh ? 0x100 : 0) | s->vec_size) {
- case 0x008: i_ldr(r, vl[0].d, a64op_post(s->in[0], s->vec_size * 1)); break;
- case 0x010: i_ldr(r, vl[0].q, a64op_post(s->in[0], s->vec_size * 1)); break;
- case 0x108: i_ldp(r, vl[0].d, vh[0].d, a64op_post(s->in[0], s->vec_size * 2)); break;
- case 0x110: i_ldp(r, vl[0].q, vh[0].q, a64op_post(s->in[0], s->vec_size * 2)); break;
- }
-}
-
static void asmgen_op_read_packed_n(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, RasmOp *vx)
{
RasmContext *r = s->rctx;
@@ -479,13 +462,10 @@ static void asmgen_op_read_packed_n(SwsAArch64Context *s, const SwsAArch64OpImpl
static void asmgen_op_read_packed(SwsAArch64Context *s, const SwsAArch64OpImplParams *p)
{
- if (p->mask == 0x0001) {
- asmgen_op_read_packed_1(s, p);
- } else {
- asmgen_op_read_packed_n(s, p, s->vl);
- if (s->use_vh)
- asmgen_op_read_packed_n(s, p, s->vh);
- }
+ av_assert0(p->mask != 0x0001);
+ asmgen_op_read_packed_n(s, p, s->vl);
+ if (s->use_vh)
+ asmgen_op_read_packed_n(s, p, s->vh);
}
static void asmgen_op_read_planar(SwsAArch64Context *s, const SwsAArch64OpImplParams *p)
@@ -574,23 +554,6 @@ static void asmgen_op_write_nibble(SwsAArch64Context *s, const SwsAArch64OpImplP
}
}
-static void asmgen_op_write_packed_1(SwsAArch64Context *s, const SwsAArch64OpImplParams *p)
-{
- RasmContext *r = s->rctx;
- AArch64VecViews vl[1];
- AArch64VecViews vh[1];
-
- a64op_vec_views(s->vl[0], &vl[0]);
- a64op_vec_views(s->vh[0], &vh[0]);
-
- switch ((s->use_vh ? 0x100 : 0) | s->vec_size) {
- case 0x008: i_str(r, vl[0].d, a64op_post(s->out[0], s->vec_size * 1)); break;
- case 0x010: i_str(r, vl[0].q, a64op_post(s->out[0], s->vec_size * 1)); break;
- case 0x108: i_stp(r, vl[0].d, vh[0].d, a64op_post(s->out[0], s->vec_size * 2)); break;
- case 0x110: i_stp(r, vl[0].q, vh[0].q, a64op_post(s->out[0], s->vec_size * 2)); break;
- }
-}
-
static void asmgen_op_write_packed_n(SwsAArch64Context *s, const SwsAArch64OpImplParams *p, RasmOp *vx)
{
RasmContext *r = s->rctx;
@@ -604,13 +567,10 @@ static void asmgen_op_write_packed_n(SwsAArch64Context *s, const SwsAArch64OpImp
static void asmgen_op_write_packed(SwsAArch64Context *s, const SwsAArch64OpImplParams *p)
{
- if (p->mask == 0x0001) {
- asmgen_op_write_packed_1(s, p);
- } else {
- asmgen_op_write_packed_n(s, p, s->vl);
- if (s->use_vh)
- asmgen_op_write_packed_n(s, p, s->vh);
- }
+ av_assert0(p->mask != 0x0001);
+ asmgen_op_write_packed_n(s, p, s->vl);
+ if (s->use_vh)
+ asmgen_op_write_packed_n(s, p, s->vh);
}
static void asmgen_op_write_planar(SwsAArch64Context *s, const SwsAArch64OpImplParams *p)
--
2.52.0
From 462be68c6eebb1ffba087585aa20cf21887e1010 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Tue, 16 Jun 2026 14:17:16 +0200
Subject: [PATCH 2/4] swscale/aarch64/ops: fix mask for swizzle ops
The mask for swizzle ops assumed that merely having a component assigned
to itself was enough to detect whether the swizzle was needed for that
component, but that wasn't correct. We should also take into account
whether the component is needed for the next operation or not.
Additionally, prevent duplicate functions from being generated by
clearing the swizzle index for unused components.
---
libswscale/aarch64/ops_entries.c | 123 ++++++++++++++++++-----------
libswscale/aarch64/ops_impl_conv.c | 17 ++--
2 files changed, 85 insertions(+), 55 deletions(-)
diff --git a/libswscale/aarch64/ops_entries.c b/libswscale/aarch64/ops_entries.c
index 4b8e4bbae1..3cd59f9c3d 100644
--- a/libswscale/aarch64/ops_entries.c
+++ b/libswscale/aarch64/ops_entries.c
@@ -95,63 +95,92 @@
{ .op = AARCH64_SWS_OP_SWAP_BYTES, .block_size = 16, .type = AARCH64_PIXEL_U16, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0001, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0001, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0003, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0003, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0003, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x000f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x000f, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x000f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0123, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0123, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0123, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0132, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0132, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0132, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0213, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1001 },
-{ .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 = 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 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x012f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x012f, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x012f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0321, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0321, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1000, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1000, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1000, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x03f2, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1101 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0ff1, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1001 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0fff, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1000 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0fff, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1000 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x0fff, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1000 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x100f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x100f, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x100f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1023, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1023, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1203, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1011 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1230, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1230, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1230, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1010 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1320, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1320, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1320, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2013, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2013, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2013, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1101 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x102f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x102f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x132f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x132f, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1f0f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1010 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1f3f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1010 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1f3f, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1010 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1f3f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1010 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x1fff, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1000 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x20f3, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1101 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x20f3, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1101 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x20ff, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1100 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x20ff, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1100 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2103, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2103, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2103, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2130, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2130, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x2130, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3000, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3000, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3000, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3012, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3012, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3012, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0101 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3021, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3021, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3021, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3102, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3102, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3102, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3120, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3120, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3120, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3201, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3201, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
-{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x3201, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x210f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x210f, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0x210f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x1110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf00f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf00f, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf00f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf021, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf021, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf021, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0f2, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0f2, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0f2, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0f3, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0ff, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0100 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf0ff, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0100 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf102, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf102, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf102, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf123, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf123, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf123, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf12f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf12f, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf12f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf132, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf132, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf132, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf321, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf321, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf321, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf3f2, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xf3f2, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0101 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff01, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff01, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff01, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff03, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff03, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff0f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff0f, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff0f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff31, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff3f, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff3f, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xff3f, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0010 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xfff1, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xfff2, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xfff3, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xfff3, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_SWIZZLE, .swizzle = 0xfff3, .block_size = 32, .type = AARCH64_PIXEL_U8, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_UNPACK, .pack = 0x0121, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_UNPACK, .pack = 0x0121, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_UNPACK, .pack = 0x0233, .block_size = 8, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
diff --git a/libswscale/aarch64/ops_impl_conv.c b/libswscale/aarch64/ops_impl_conv.c
index 479afbb3ab..b0a286edb6 100644
--- a/libswscale/aarch64/ops_impl_conv.c
+++ b/libswscale/aarch64/ops_impl_conv.c
@@ -155,15 +155,16 @@ static int convert_to_aarch64_impl(SwsContext *ctx, const SwsOpList *ops, int n,
out->type = AARCH64_PIXEL_U32;
break;
case AARCH64_SWS_OP_SWIZZLE:
+ /* Recompute mask taking identity swizzle into account */
out->mask = 0;
- MASK_SET(out->mask, 0, op->swizzle.in[0] != 0);
- MASK_SET(out->mask, 1, op->swizzle.in[1] != 1);
- MASK_SET(out->mask, 2, op->swizzle.in[2] != 2);
- MASK_SET(out->mask, 3, op->swizzle.in[3] != 3);
- MASK_SET(out->swizzle, 0, op->swizzle.in[0]);
- MASK_SET(out->swizzle, 1, op->swizzle.in[1]);
- MASK_SET(out->swizzle, 2, op->swizzle.in[2]);
- MASK_SET(out->swizzle, 3, op->swizzle.in[3]);
+ for (int i = 0; i < 4; i++) {
+ if (SWS_OP_NEEDED(op, i) && op->swizzle.in[i] != i) {
+ MASK_SET(out->mask, i, 1);
+ MASK_SET(out->swizzle, i, op->swizzle.in[i]);
+ } else {
+ MASK_SET(out->swizzle, i, 0xf);
+ }
+ }
/* The element size and type don't matter. */
out->block_size = block_size * ff_sws_pixel_type_size(op->type);
out->type = AARCH64_PIXEL_U8;
--
2.52.0
From 0960d2fb1c04405c76be1b29e4292d7ac7fe581f Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Sat, 13 Jun 2026 02:19:48 +0200
Subject: [PATCH 3/4] swscale/aarch64/ops: remove redundant linear combinations
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.
Also simplified the AVRational comparisons a bit.
---
libswscale/aarch64/ops_entries.c | 10 ++--------
libswscale/aarch64/ops_impl_conv.c | 5 +++--
2 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/libswscale/aarch64/ops_entries.c b/libswscale/aarch64/ops_entries.c
index 3cd59f9c3d..3f6bd92b1a 100644
--- a/libswscale/aarch64/ops_entries.c
+++ b/libswscale/aarch64/ops_entries.c
@@ -349,14 +349,12 @@
{ .op = AARCH64_SWS_OP_SCALE, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_SCALE, .block_size = 16, .type = AARCH64_PIXEL_U16, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_SCALE, .block_size = 16, .type = AARCH64_PIXEL_U16, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000000000dULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000000000dULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000000000fULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000000000fULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x00000000fcULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x00000000fcULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x00000000fdULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x00000000fdULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x00000000ffULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x00000000ffULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000000c000ULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0010 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000000c000ULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0010 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000373dcc7ULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
@@ -365,10 +363,6 @@
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x0003f3fccfULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000c00c00cULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000c00c00cULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000c10c40dULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000c10c40dULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000c10cc0dULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000c10cc0dULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000c30cc0fULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000c30cc0fULL, .linear.fmla = 1, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_LINEAR, .linear.mask = 0x000ff3fcfcULL, .linear.fmla = 0, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
diff --git a/libswscale/aarch64/ops_impl_conv.c b/libswscale/aarch64/ops_impl_conv.c
index b0a286edb6..4e401527cd 100644
--- a/libswscale/aarch64/ops_impl_conv.c
+++ b/libswscale/aarch64/ops_impl_conv.c
@@ -214,10 +214,11 @@ static int convert_to_aarch64_impl(SwsContext *ctx, const SwsOpList *ops, int n,
continue;
MASK_SET(out->mask, i, 1);
for (int j = 0; j < 5; j++) {
+ const AVRational k = op->lin.m[i][j];
int jj = linear_index_from_sws_op(j);
- if (!av_cmp_q(op->lin.m[i][j], av_make_q(1, 1)))
+ if (j < 4 && k.num == k.den)
LINEAR_MASK_SET(out->linear.mask, i, jj, LINEAR_MASK_1);
- else if (av_cmp_q(op->lin.m[i][j], av_make_q(0, 1)))
+ else if (k.num != 0)
LINEAR_MASK_SET(out->linear.mask, i, jj, LINEAR_MASK_X);
}
}
--
2.52.0
From 753079b80290d0f7482b41d5692cc044e6338d41 Mon Sep 17 00:00:00 2001
From: Ramiro Polla <ramiro.polla(a)gmail.com>
Date: Tue, 16 Jun 2026 16:34:52 +0200
Subject: [PATCH 4/4] swscale/aarch64/ops: mark more operations as
type-invariant
This prevents the generation of a few more duplicate functions (where
there would be both f32 and u32 functions).
---
libswscale/aarch64/ops_entries.c | 25 +++++++++++--------------
libswscale/aarch64/ops_impl_conv.c | 22 +++++++++++++++++-----
2 files changed, 28 insertions(+), 19 deletions(-)
diff --git a/libswscale/aarch64/ops_entries.c b/libswscale/aarch64/ops_entries.c
index 3f6bd92b1a..e340d0086d 100644
--- a/libswscale/aarch64/ops_entries.c
+++ b/libswscale/aarch64/ops_entries.c
@@ -13,9 +13,9 @@
{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x0011 },
{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0011 },
-{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_READ_PACKED, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
@@ -31,9 +31,8 @@
{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_READ_PLANAR, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
@@ -50,9 +49,9 @@
{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x0011 },
{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x1111 },
-{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0011 },
-{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0011 },
+{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0011 },
{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_WRITE_PACKED, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
@@ -66,9 +65,8 @@
{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0001 },
-{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0111 },
-{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1111 },
+{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0111 },
+{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x1111 },
{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0111 },
{ .op = AARCH64_SWS_OP_WRITE_PLANAR, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x1111 },
@@ -261,13 +259,12 @@
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x1101 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_U16, .mask = 0x1110 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0001 },
+{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0010 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x0101 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x1000 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x1010 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x1011 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_U32, .mask = 0x1101 },
-{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x0010 },
-{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 8, .type = AARCH64_PIXEL_F32, .mask = 0x1000 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0001 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0010 },
{ .op = AARCH64_SWS_OP_CLEAR, .block_size = 16, .type = AARCH64_PIXEL_U8, .mask = 0x0110 },
diff --git a/libswscale/aarch64/ops_impl_conv.c b/libswscale/aarch64/ops_impl_conv.c
index 4e401527cd..075569b3b9 100644
--- a/libswscale/aarch64/ops_impl_conv.c
+++ b/libswscale/aarch64/ops_impl_conv.c
@@ -149,11 +149,6 @@ static int convert_to_aarch64_impl(SwsContext *ctx, const SwsOpList *ops, int n,
case 4: out->mask = 0x1111; break;
};
break;
- case AARCH64_SWS_OP_SWAP_BYTES:
- /* Only the element size matters, not the type. */
- if (out->type == AARCH64_PIXEL_F32)
- out->type = AARCH64_PIXEL_U32;
- break;
case AARCH64_SWS_OP_SWIZZLE:
/* Recompute mask taking identity swizzle into account */
out->mask = 0;
@@ -238,5 +233,22 @@ static int convert_to_aarch64_impl(SwsContext *ctx, const SwsOpList *ops, int n,
break;
}
+ switch (out->op) {
+ case AARCH64_SWS_OP_READ_BIT:
+ case AARCH64_SWS_OP_READ_NIBBLE:
+ case AARCH64_SWS_OP_READ_PACKED:
+ case AARCH64_SWS_OP_READ_PLANAR:
+ case AARCH64_SWS_OP_WRITE_BIT:
+ case AARCH64_SWS_OP_WRITE_NIBBLE:
+ case AARCH64_SWS_OP_WRITE_PACKED:
+ case AARCH64_SWS_OP_WRITE_PLANAR:
+ case AARCH64_SWS_OP_SWAP_BYTES:
+ case AARCH64_SWS_OP_CLEAR:
+ /* Only the element size matters, not the type. */
+ if (out->type == AARCH64_PIXEL_F32)
+ out->type = AARCH64_PIXEL_U32;
+ break;
+ }
+
return 0;
}
--
2.52.0
1
0