opencv: Backport videoio fixes for ffmpeg 9

oe-core upgraded ffmpeg 8.1.2 -> 9.0, which removed the AVCodec::pix_fmts
and AVCodec::supported_framerates fields (deprecated since FFmpeg 7.1 /
libavcodec 61.13.100). opencv's videoio ffmpeg backend still reads both
of them directly in cap_ffmpeg_hw.hpp and cap_ffmpeg_impl.hpp, so it does
not build against ffmpeg 9.

Backport the merged upstream series from opencv/opencv#29533, which reads
those lists through avcodec_get_supported_config() when building against
libavcodec 61.13.100 or newer and keeps the old field access otherwise.
The series was merged on 2026-08-11, after the 4.14.0 tag (2026-07-17),
so it is not part of the release we build.

Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
This commit is contained in:
Khem Raj
2026-09-11 07:07:59 -07:00
parent b183cb8a1c
commit c2f9fb9496
2 changed files with 243 additions and 0 deletions
@@ -0,0 +1,242 @@
From 700cd32ffd59ed3c6f6aec1919867653d8b125ea Mon Sep 17 00:00:00 2001
From: Aadhu23 <aadhavansalthivel5@gmail.com>
Date: Thu, 16 Jul 2026 09:21:37 +0000
Subject: [PATCH 1/3] videoio: support FFmpeg after AVCodec::pix_fmts removal
Upstream-Status: Backport [https://github.com/opencv/opencv/pull/29533]
Signed-off-by: Khem Raj <raj.khem@gmail.com>
---
modules/videoio/src/cap_ffmpeg_hw.hpp | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/modules/videoio/src/cap_ffmpeg_hw.hpp b/modules/videoio/src/cap_ffmpeg_hw.hpp
index 65045a2bc79e..bb5e4c108819 100644
--- a/modules/videoio/src/cap_ffmpeg_hw.hpp
+++ b/modules/videoio/src/cap_ffmpeg_hw.hpp
@@ -757,6 +757,30 @@ AVCodec *hw_find_codec(AVCodecID id, AVHWDeviceType hw_type, int (*check_categor
#endif
if (hw_type == AV_HWDEVICE_TYPE_CUDA) // CUDA encoders don't support avcodec_get_hw_config()
hw_native_fmt = AV_PIX_FMT_CUDA;
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)
+ if (av_codec_is_encoder(c) && hw_native_fmt != AV_PIX_FMT_NONE) {
+ const AVPixelFormat *pix_fmts = NULL;
+ int num_pix_fmts = 0;
+
+ int ret = avcodec_get_supported_config(
+ NULL,
+ c,
+ AV_CODEC_CONFIG_PIX_FORMAT,
+ 0,
+ (const void **)&pix_fmts,
+ &num_pix_fmts);
+
+ if (ret >= 0 && pix_fmts && num_pix_fmts > 0) {
+ for (int i = 0; i < num_pix_fmts; i++) {
+ if (pix_fmts[i] == hw_native_fmt) {
+ *hw_pix_fmt = hw_native_fmt;
+ if (hw_check_codec(c, hw_type, disabled_codecs))
+ return c;
+ }
+ }
+ }
+ }
+#else
if (av_codec_is_encoder(c) && hw_native_fmt != AV_PIX_FMT_NONE && c->pix_fmts) {
for (int i = 0; c->pix_fmts[i] != AV_PIX_FMT_NONE; i++) {
if (c->pix_fmts[i] == hw_native_fmt) {
@@ -766,6 +790,7 @@ AVCodec *hw_find_codec(AVCodecID id, AVHWDeviceType hw_type, int (*check_categor
}
}
}
+#endif
for (int i = 0;; i++) {
const AVCodecHWConfig *hw_config = avcodec_get_hw_config(c, i);
if (!hw_config)
From 83ed22ca2800267050a4a9a94afab605c990c0e0 Mon Sep 17 00:00:00 2001
From: Arnesh Banerjee <linkrinku13@gmail.com>
Date: Tue, 4 Aug 2026 19:49:11 +0530
Subject: [PATCH 2/3] videoio(ffmpeg): use avcodec_get_supported_config for
framerates on FFmpeg 9
AVCodec::supported_framerates was deprecated in FFmpeg 7.1 and removed in
FFmpeg 9, so direct field access no longer builds against FFmpeg 9.
Read the supported frame rate list through avcodec_get_supported_config()
when building against libavcodec 61.13.100 or newer. That call returns the
same list plus its entry count, so the loop iterates by count instead of the
old sentinel terminator. Older FFmpeg keeps the previous field access.
Upstream-Status: Backport [https://github.com/opencv/opencv/pull/29533]
Signed-off-by: Khem Raj <raj.khem@gmail.com>
---
modules/videoio/src/cap_ffmpeg_impl.hpp | 34 +++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp
index a7fb1eda9a54..d5b950392c94 100644
--- a/modules/videoio/src/cap_ffmpeg_impl.hpp
+++ b/modules/videoio/src/cap_ffmpeg_impl.hpp
@@ -2627,6 +2627,39 @@ static AVCodecContext * icv_configure_video_stream_FFMPEG(AVFormatContext *oc,
c->time_base.den = frame_rate;
c->time_base.num = frame_rate_base;
/* adjust time base for supported framerates */
+ // AVCodec::supported_framerates was deprecated in FFmpeg 7.1 and removed in
+ // FFmpeg 9. avcodec_get_supported_config() returns the same list together
+ // with its entry count, so use it when available.
+#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(61, 13, 100)
+ const AVRational *supported_framerates = NULL;
+ int num_supported_framerates = 0;
+ if (codec)
+ avcodec_get_supported_config(NULL, codec, AV_CODEC_CONFIG_FRAME_RATE, 0,
+ (const void **)&supported_framerates, &num_supported_framerates);
+ if (supported_framerates && num_supported_framerates > 0){
+ AVRational req = {frame_rate, frame_rate_base};
+ const AVRational *best=NULL;
+ AVRational best_error= {INT_MAX, 1};
+ for(int i = 0; i < num_supported_framerates; i++){
+ const AVRational *p = &supported_framerates[i];
+ AVRational error= av_sub_q(req, *p);
+ if(error.num <0) error.num *= -1;
+ if(av_cmp_q(error, best_error) < 0){
+ best_error= error;
+ best= p;
+ }
+ }
+ if (best == NULL)
+ {
+#ifdef CV_FFMPEG_CODECPAR
+ avcodec_free_context(&c);
+#endif
+ return NULL;
+ }
+ c->time_base.den= best->num;
+ c->time_base.num= best->den;
+ }
+#else
if(codec && codec->supported_framerates){
const AVRational *p= codec->supported_framerates;
AVRational req = {frame_rate, frame_rate_base};
@@ -2650,6 +2683,7 @@ static AVCodecContext * icv_configure_video_stream_FFMPEG(AVFormatContext *oc,
c->time_base.den= best->num;
c->time_base.num= best->den;
}
+#endif
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = pixel_format;
From c0166c617d765ac707dde6b9acd8cfcd49751049 Mon Sep 17 00:00:00 2001
From: Alexander Smorkalov <alexander.smorkalov@opencv.ai>
Date: Tue, 11 Aug 2026 13:01:55 +0300
Subject: [PATCH 3/3] Code review fixes.
Upstream-Status: Backport [https://github.com/opencv/opencv/pull/29533]
Signed-off-by: Khem Raj <raj.khem@gmail.com>
---
modules/videoio/src/cap_ffmpeg_hw.hpp | 16 ++++----
modules/videoio/src/cap_ffmpeg_impl.hpp | 51 ++++++++++++-------------
2 files changed, 33 insertions(+), 34 deletions(-)
diff --git a/modules/videoio/src/cap_ffmpeg_hw.hpp b/modules/videoio/src/cap_ffmpeg_hw.hpp
index bb5e4c108819..6c456881122a 100644
--- a/modules/videoio/src/cap_ffmpeg_hw.hpp
+++ b/modules/videoio/src/cap_ffmpeg_hw.hpp
@@ -757,7 +757,7 @@ AVCodec *hw_find_codec(AVCodecID id, AVHWDeviceType hw_type, int (*check_categor
#endif
if (hw_type == AV_HWDEVICE_TYPE_CUDA) // CUDA encoders don't support avcodec_get_hw_config()
hw_native_fmt = AV_PIX_FMT_CUDA;
-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)
+#if LIBAVCODEC_BUILD >= AV_VERSION_INT(61, 13, 100)
if (av_codec_is_encoder(c) && hw_native_fmt != AV_PIX_FMT_NONE) {
const AVPixelFormat *pix_fmts = NULL;
int num_pix_fmts = 0;
@@ -770,15 +770,15 @@ AVCodec *hw_find_codec(AVCodecID id, AVHWDeviceType hw_type, int (*check_categor
(const void **)&pix_fmts,
&num_pix_fmts);
- if (ret >= 0 && pix_fmts && num_pix_fmts > 0) {
- for (int i = 0; i < num_pix_fmts; i++) {
- if (pix_fmts[i] == hw_native_fmt) {
- *hw_pix_fmt = hw_native_fmt;
- if (hw_check_codec(c, hw_type, disabled_codecs))
- return c;
+ if (ret >= 0 && pix_fmts && num_pix_fmts > 0) {
+ for (int i = 0; i < num_pix_fmts; i++) {
+ if (pix_fmts[i] == hw_native_fmt) {
+ *hw_pix_fmt = hw_native_fmt;
+ if (hw_check_codec(c, hw_type, disabled_codecs))
+ return c;
+ }
}
}
- }
}
#else
if (av_codec_is_encoder(c) && hw_native_fmt != AV_PIX_FMT_NONE && c->pix_fmts) {
diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp
index d5b950392c94..fc4479e07c5f 100644
--- a/modules/videoio/src/cap_ffmpeg_impl.hpp
+++ b/modules/videoio/src/cap_ffmpeg_impl.hpp
@@ -2627,37 +2627,36 @@ static AVCodecContext * icv_configure_video_stream_FFMPEG(AVFormatContext *oc,
c->time_base.den = frame_rate;
c->time_base.num = frame_rate_base;
/* adjust time base for supported framerates */
- // AVCodec::supported_framerates was deprecated in FFmpeg 7.1 and removed in
- // FFmpeg 9. avcodec_get_supported_config() returns the same list together
- // with its entry count, so use it when available.
#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(61, 13, 100)
- const AVRational *supported_framerates = NULL;
- int num_supported_framerates = 0;
- if (codec)
- avcodec_get_supported_config(NULL, codec, AV_CODEC_CONFIG_FRAME_RATE, 0,
- (const void **)&supported_framerates, &num_supported_framerates);
- if (supported_framerates && num_supported_framerates > 0){
- AVRational req = {frame_rate, frame_rate_base};
- const AVRational *best=NULL;
- AVRational best_error= {INT_MAX, 1};
- for(int i = 0; i < num_supported_framerates; i++){
- const AVRational *p = &supported_framerates[i];
- AVRational error= av_sub_q(req, *p);
- if(error.num <0) error.num *= -1;
- if(av_cmp_q(error, best_error) < 0){
- best_error= error;
- best= p;
+ if (codec){
+ const AVRational *supported_framerates = NULL;
+ int num_supported_framerates = 0;
+ int ret = avcodec_get_supported_config(NULL, codec, AV_CODEC_CONFIG_FRAME_RATE, 0,
+ (const void **)&supported_framerates, &num_supported_framerates);
+
+ if (ret >= 0 && supported_framerates && num_supported_framerates > 0){
+ AVRational req = {frame_rate, frame_rate_base};
+ const AVRational *best=NULL;
+ AVRational best_error= {INT_MAX, 1};
+ for(int i = 0; i < num_supported_framerates; i++){
+ const AVRational *p = &supported_framerates[i];
+ AVRational error = av_sub_q(req, *p);
+ if(error.num <0) error.num *= -1;
+ if(av_cmp_q(error, best_error) < 0){
+ best_error = error;
+ best = p;
+ }
}
- }
- if (best == NULL)
- {
+ if (best == NULL)
+ {
#ifdef CV_FFMPEG_CODECPAR
- avcodec_free_context(&c);
+ avcodec_free_context(&c);
#endif
- return NULL;
+ return NULL;
+ }
+ c->time_base.den = best->num;
+ c->time_base.num = best->den;
}
- c->time_base.den= best->num;
- c->time_base.num= best->den;
}
#else
if(codec && codec->supported_framerates){
@@ -34,6 +34,7 @@ SRC_URI = "git://github.com/opencv/opencv.git;name=opencv;branch=4.x;protocol=ht
file://download.patch \
file://0001-Make-ts-module-external.patch \
file://0008-Do-not-embed-build-directory-in-binaries.patch \
file://29533.patch \
"
SRC_URI:append:riscv64 = " file://0001-Use-Os-to-compile-tinyxml2.cpp.patch;patchdir=contrib"
SRC_URI:append:aarch64 = " git://gitlab.arm.com/kleidi/kleidicv;branch=main;destsuffix=${BB_GIT_DEFAULT_DESTSUFFIX}/3rdparty/kleidicv;name=kleidicv;protocol=https"