From 7323bd68c1b34e9298ea557ff7a3e1883b653957 Mon Sep 17 00:00:00 2001 From: 21pages Date: Tue, 10 Dec 2024 14:28:16 +0800 Subject: [PATCH 4/5] mediacodec changing bitrate Signed-off-by: 21pages --- libavcodec/mediacodec_wrapper.c | 98 +++++++++++++++++++++++++++++++++ libavcodec/mediacodec_wrapper.h | 7 +++ libavcodec/mediacodecenc.c | 18 ++++++ 3 files changed, 123 insertions(+) diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c index 96c886666a..06b8504304 100644 --- a/libavcodec/mediacodec_wrapper.c +++ b/libavcodec/mediacodec_wrapper.c @@ -35,6 +35,8 @@ #include "ffjni.h" #include "mediacodec_wrapper.h" +#define PARAMETER_KEY_VIDEO_BITRATE "video-bitrate" + struct JNIAMediaCodecListFields { jclass mediacodec_list_class; @@ -195,6 +197,8 @@ struct JNIAMediaCodecFields { jmethodID set_input_surface_id; jmethodID signal_end_of_input_stream_id; + jmethodID set_parameters_id; + jclass mediainfo_class; jmethodID init_id; @@ -248,6 +252,8 @@ static const struct FFJniField jni_amediacodec_mapping[] = { { "android/media/MediaCodec", "setInputSurface", "(Landroid/view/Surface;)V", FF_JNI_METHOD, OFFSET(set_input_surface_id), 0 }, { "android/media/MediaCodec", "signalEndOfInputStream", "()V", FF_JNI_METHOD, OFFSET(signal_end_of_input_stream_id), 0 }, + { "android/media/MediaCodec", "setParameters", "(Landroid/os/Bundle;)V", FF_JNI_METHOD, OFFSET(set_parameters_id), 0 }, + { "android/media/MediaCodec$BufferInfo", NULL, NULL, FF_JNI_CLASS, OFFSET(mediainfo_class), 1 }, { "android/media/MediaCodec.BufferInfo", "", "()V", FF_JNI_METHOD, OFFSET(init_id), 1 }, @@ -292,6 +298,24 @@ typedef struct FFAMediaCodecJni { static const FFAMediaCodec media_codec_jni; +struct JNIABundleFields +{ + jclass bundle_class; + jmethodID init_id; + jmethodID put_int_id; +}; + +#define OFFSET(x) offsetof(struct JNIABundleFields, x) +static const struct FFJniField jni_abundle_mapping[] = { + { "android/os/Bundle", NULL, NULL, FF_JNI_CLASS, OFFSET(bundle_class), 1 }, + + { "android/os/Bundle", "", "()V", FF_JNI_METHOD, OFFSET(init_id), 1 }, + { "android/os/Bundle", "putInt", "(Ljava/lang/String;I)V", FF_JNI_METHOD, OFFSET(put_int_id), 1 }, + + { NULL } +}; +#undef OFFSET + #define JNI_GET_ENV_OR_RETURN(env, log_ctx, ret) do { \ (env) = ff_jni_get_env(log_ctx); \ if (!(env)) { \ @@ -1762,6 +1786,70 @@ static int mediacodec_jni_signalEndOfInputStream(FFAMediaCodec *ctx) return 0; } + +static int mediacodec_jni_setParameter(FFAMediaCodec *ctx, const char* name, int value) +{ + JNIEnv *env = NULL; + struct JNIABundleFields jfields = { 0 }; + jobject object = NULL; + jstring key = NULL; + FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx; + void *log_ctx = codec; + int ret = -1; + + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); + + if (ff_jni_init_jfields(env, &jfields, jni_abundle_mapping, 0, log_ctx) < 0) { + av_log(log_ctx, AV_LOG_ERROR, "Failed to init jfields\n"); + goto fail; + } + + object = (*env)->NewObject(env, jfields.bundle_class, jfields.init_id); + if (!object) { + av_log(log_ctx, AV_LOG_ERROR, "Failed to create bundle object\n"); + goto fail; + } + + key = ff_jni_utf_chars_to_jstring(env, name, log_ctx); + if (!key) { + av_log(log_ctx, AV_LOG_ERROR, "Failed to convert key to jstring\n"); + goto fail; + } + + (*env)->CallVoidMethod(env, object, jfields.put_int_id, key, value); + if (ff_jni_exception_check(env, 1, log_ctx) < 0) { + goto fail; + } + + if (!codec->jfields.set_parameters_id) { + av_log(log_ctx, AV_LOG_ERROR, "System doesn't support setParameters\n"); + goto fail; + } + + (*env)->CallVoidMethod(env, codec->object, codec->jfields.set_parameters_id, object); + if (ff_jni_exception_check(env, 1, log_ctx) < 0) { + goto fail; + } + + ret = 0; + +fail: + if (key) { + (*env)->DeleteLocalRef(env, key); + } + if (object) { + (*env)->DeleteLocalRef(env, object); + } + ff_jni_reset_jfields(env, &jfields, jni_abundle_mapping, 0, log_ctx); + + return ret; +} + +static int mediacodec_jni_setDynamicBitrate(FFAMediaCodec *ctx, int bitrate) +{ + return mediacodec_jni_setParameter(ctx, PARAMETER_KEY_VIDEO_BITRATE, bitrate); +} + static const FFAMediaFormat media_format_jni = { .class = &amediaformat_class, @@ -1821,6 +1909,8 @@ static const FFAMediaCodec media_codec_jni = { .getConfigureFlagEncode = mediacodec_jni_getConfigureFlagEncode, .cleanOutputBuffers = mediacodec_jni_cleanOutputBuffers, .signalEndOfInputStream = mediacodec_jni_signalEndOfInputStream, + + .setDynamicBitrate = mediacodec_jni_setDynamicBitrate, }; typedef struct FFAMediaFormatNdk { @@ -2335,6 +2425,12 @@ static int mediacodec_ndk_signalEndOfInputStream(FFAMediaCodec *ctx) return 0; } +static int mediacodec_ndk_setDynamicBitrate(FFAMediaCodec *ctx, int bitrate) +{ + av_log(ctx, AV_LOG_ERROR, "ndk setDynamicBitrate unavailable\n"); + return -1; +} + static const FFAMediaFormat media_format_ndk = { .class = &amediaformat_ndk_class, @@ -2396,6 +2492,8 @@ static const FFAMediaCodec media_codec_ndk = { .getConfigureFlagEncode = mediacodec_ndk_getConfigureFlagEncode, .cleanOutputBuffers = mediacodec_ndk_cleanOutputBuffers, .signalEndOfInputStream = mediacodec_ndk_signalEndOfInputStream, + + .setDynamicBitrate = mediacodec_ndk_setDynamicBitrate, }; FFAMediaFormat *ff_AMediaFormat_new(int ndk) diff --git a/libavcodec/mediacodec_wrapper.h b/libavcodec/mediacodec_wrapper.h index 11a4260497..86c64556ad 100644 --- a/libavcodec/mediacodec_wrapper.h +++ b/libavcodec/mediacodec_wrapper.h @@ -219,6 +219,8 @@ struct FFAMediaCodec { // For encoder with FFANativeWindow as input. int (*signalEndOfInputStream)(FFAMediaCodec *); + + int (*setDynamicBitrate)(FFAMediaCodec *codec, int bitrate); }; static inline char *ff_AMediaCodec_getName(FFAMediaCodec *codec) @@ -343,6 +345,11 @@ static inline int ff_AMediaCodec_signalEndOfInputStream(FFAMediaCodec *codec) return codec->signalEndOfInputStream(codec); } +static inline int ff_AMediaCodec_setDynamicBitrate(FFAMediaCodec *codec, int bitrate) +{ + return codec->setDynamicBitrate(codec, bitrate); +} + int ff_Build_SDK_INT(AVCodecContext *avctx); enum FFAMediaFormatColorRange { diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c index 6ca3968a24..221f7360f4 100644 --- a/libavcodec/mediacodecenc.c +++ b/libavcodec/mediacodecenc.c @@ -76,6 +76,8 @@ typedef struct MediaCodecEncContext { int level; int pts_as_dts; int extract_extradata; + + int last_bit_rate; } MediaCodecEncContext; enum { @@ -193,6 +195,8 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) int ret; int gop; + s->last_bit_rate = avctx->bit_rate; + if (s->use_ndk_codec < 0) s->use_ndk_codec = !av_jni_get_java_vm(avctx); @@ -542,11 +546,25 @@ static int mediacodec_send(AVCodecContext *avctx, return 0; } +static void update_config(AVCodecContext *avctx) +{ + MediaCodecEncContext *s = avctx->priv_data; + if (avctx->bit_rate != s->last_bit_rate) { + s->last_bit_rate = avctx->bit_rate; + if (0 != ff_AMediaCodec_setDynamicBitrate(s->codec, avctx->bit_rate)) { + av_log(avctx, AV_LOG_ERROR, "Failed to set bitrate to %d\n", avctx->bit_rate); + } else { + av_log(avctx, AV_LOG_INFO, "Set bitrate to %d\n", avctx->bit_rate); + } + } +} + static int mediacodec_encode(AVCodecContext *avctx, AVPacket *pkt) { MediaCodecEncContext *s = avctx->priv_data; int ret; + update_config(avctx); // Return on three case: // 1. Serious error // 2. Got a packet success -- 2.43.0.windows.1