PR #22870 opened by padenot
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22870
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22870.patch

When the encoder receives a frame with pict_type == AV_PICTURE_TYPE_I,
use AMediaCodec_setParameters with "request-sync" to request a sync
frame from the Android MediaCodec encoder. Implement setParameters for
both the JNI and NDK codec wrappers (JNI stub returns
AVERROR_PATCHWELCOME as the JNI path does not support it).

The NDK setParameters function pointer is loaded via dlsym (matching the
pattern for other API 26 symbols in FFAMediaCodecNdk) so that the code
degrades gracefully on older devices.

No tests, but this has been tested both on CI (emulators) and real devices,
when compiled in Firefox.

Signed-off-by: Paul Adenot <[email protected]>


>From fa6d161751fdec99d7a378cae38cf944de9b995d Mon Sep 17 00:00:00 2001
From: Andrew Osmond <[email protected]>
Date: Mon, 20 Apr 2026 16:32:01 +0000
Subject: [PATCH] avcodec/mediacodecenc: allow forcing key frames via
 AMediaCodec_setParameters

When the encoder receives a frame with pict_type == AV_PICTURE_TYPE_I,
use AMediaCodec_setParameters with "request-sync" to request a sync
frame from the Android MediaCodec encoder. Implement setParameters for
both the JNI and NDK codec wrappers (JNI stub returns
AVERROR_PATCHWELCOME as the JNI path does not support it).

The NDK setParameters function pointer is loaded via dlsym (matching the
pattern for other API 26 symbols in FFAMediaCodecNdk) so that the code
degrades gracefully on older devices.

Signed-off-by: Paul Adenot <[email protected]>
---
 libavcodec/mediacodec_wrapper.c | 36 +++++++++++++++++++++++++++++++++
 libavcodec/mediacodec_wrapper.h |  7 +++++++
 libavcodec/mediacodecenc.c      | 13 ++++++++++++
 3 files changed, 56 insertions(+)

diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c
index 283bbe72d6..68054c6be5 100644
--- a/libavcodec/mediacodec_wrapper.c
+++ b/libavcodec/mediacodec_wrapper.c
@@ -1411,6 +1411,12 @@ fail:
     return ret;
 }
 
+static int mediacodec_jni_setParameters(FFAMediaCodec *ctx,
+                                        const FFAMediaFormat* format_ctx)
+{
+    return AVERROR_PATCHWELCOME;
+}
+
 static int mediacodec_jni_start(FFAMediaCodec* ctx)
 {
     int ret = 0;
@@ -1802,6 +1808,7 @@ static const FFAMediaCodec media_codec_jni = {
     .delete = mediacodec_jni_delete,
 
     .configure = mediacodec_jni_configure,
+    .setParameters = mediacodec_jni_setParameters,
     .start = mediacodec_jni_start,
     .stop = mediacodec_jni_stop,
     .flush = mediacodec_jni_flush,
@@ -1863,6 +1870,7 @@ typedef struct FFAMediaCodecNdk {
     media_status_t (*signalEndOfInputStream)(AMediaCodec *);
     media_status_t (*setAsyncNotifyCallback)(AMediaCodec *,
             struct AMediaCodecOnAsyncNotifyCallback callback, void *userdata);
+    media_status_t (*setParameters)(AMediaCodec*, const AMediaFormat *);
 } FFAMediaCodecNdk;
 
 static const FFAMediaFormat media_format_ndk;
@@ -2101,6 +2109,7 @@ static inline FFAMediaCodec *ndk_codec_create(int method, 
const char *arg) {
     GET_SYMBOL(setInputSurface)
     GET_SYMBOL(signalEndOfInputStream)
     GET_SYMBOL(setAsyncNotifyCallback)
+    GET_SYMBOL(setParameters)
 
 #undef GET_SYMBOL
 
@@ -2219,6 +2228,32 @@ static int mediacodec_ndk_configure(FFAMediaCodec* ctx,
     return 0;
 }
 
+static int mediacodec_ndk_setParameters(FFAMediaCodec *ctx,
+                                        const FFAMediaFormat* format_ctx)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)format_ctx;
+    media_status_t status;
+
+    if (format_ctx->class != &amediaformat_ndk_class) {
+        av_log(ctx, AV_LOG_ERROR, "invalid media format\n");
+        return AVERROR(EINVAL);
+    }
+
+    if (!codec->setParameters) {
+        av_log(ctx, AV_LOG_ERROR, "setParameters() unavailable\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    status = codec->setParameters(codec->impl, format->impl);
+    if (status != AMEDIA_OK) {
+        av_log(codec, AV_LOG_ERROR, "setParameters failed, %d\n", status);
+        return AVERROR_EXTERNAL;
+    }
+
+    return 0;
+}
+
 #define MEDIACODEC_NDK_WRAPPER(method)                                   \
 static int mediacodec_ndk_ ## method(FFAMediaCodec* ctx)                 \
 {                                                                        \
@@ -2498,6 +2533,7 @@ static const FFAMediaCodec media_codec_ndk = {
     .delete = mediacodec_ndk_delete,
 
     .configure = mediacodec_ndk_configure,
+    .setParameters = mediacodec_ndk_setParameters,
     .start = mediacodec_ndk_start,
     .stop = mediacodec_ndk_stop,
     .flush = mediacodec_ndk_flush,
diff --git a/libavcodec/mediacodec_wrapper.h b/libavcodec/mediacodec_wrapper.h
index 18d0796445..3b3975a3b2 100644
--- a/libavcodec/mediacodec_wrapper.h
+++ b/libavcodec/mediacodec_wrapper.h
@@ -205,6 +205,7 @@ struct FFAMediaCodec {
     int (*delete)(FFAMediaCodec* codec);
 
     int (*configure)(FFAMediaCodec* codec, const FFAMediaFormat* format, 
FFANativeWindow* surface, void *crypto, uint32_t flags);
+    int (*setParameters)(FFAMediaCodec* codec, const FFAMediaFormat* format);
     int (*start)(FFAMediaCodec* codec);
     int (*stop)(FFAMediaCodec* codec);
     int (*flush)(FFAMediaCodec* codec);
@@ -259,6 +260,12 @@ static inline int ff_AMediaCodec_configure(FFAMediaCodec 
*codec,
     return codec->configure(codec, format, surface, crypto, flags);
 }
 
+static inline int ff_AMediaCodec_setParameters(FFAMediaCodec *codec,
+                                               const FFAMediaFormat *format)
+{
+    return codec->setParameters(codec, format);
+}
+
 static inline int ff_AMediaCodec_start(FFAMediaCodec* codec)
 {
     return codec->start(codec);
diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c
index 507c48df9c..d76c56cf1c 100644
--- a/libavcodec/mediacodecenc.c
+++ b/libavcodec/mediacodecenc.c
@@ -827,6 +827,19 @@ static int mediacodec_send(AVCodecContext *avctx,
         copy_frame_to_buffer(avctx, frame, input_buf, input_size);
 
         pts = av_rescale_q(frame->pts, avctx->time_base, AV_TIME_BASE_Q);
+
+        if (frame->pict_type == AV_PICTURE_TYPE_I) {
+            FFAMediaFormat *format = ff_AMediaFormat_new(s->use_ndk_codec);
+            if (format) {
+                int set_ret;
+                ff_AMediaFormat_setInt32(format, "request-sync", 0);
+                set_ret = ff_AMediaCodec_setParameters(codec, format);
+                if (set_ret < 0)
+                    av_log(avctx, AV_LOG_WARNING,
+                           "Failed to request key frame: %d\n", set_ret);
+                ff_AMediaFormat_delete(format);
+            }
+        }
     } else {
         flags |= ff_AMediaCodec_getBufferFlagEndOfStream(codec);
         s->eof_sent = 1;
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to