0005-mediacodec-changing-bitrate.patch 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. From 7323bd68c1b34e9298ea557ff7a3e1883b653957 Mon Sep 17 00:00:00 2001
  2. From: 21pages <sunboeasy@gmail.com>
  3. Date: Tue, 10 Dec 2024 14:28:16 +0800
  4. Subject: [PATCH 4/5] mediacodec changing bitrate
  5. Signed-off-by: 21pages <sunboeasy@gmail.com>
  6. ---
  7. libavcodec/mediacodec_wrapper.c | 98 +++++++++++++++++++++++++++++++++
  8. libavcodec/mediacodec_wrapper.h | 7 +++
  9. libavcodec/mediacodecenc.c | 18 ++++++
  10. 3 files changed, 123 insertions(+)
  11. diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c
  12. index 96c886666a..06b8504304 100644
  13. --- a/libavcodec/mediacodec_wrapper.c
  14. +++ b/libavcodec/mediacodec_wrapper.c
  15. @@ -35,6 +35,8 @@
  16. #include "ffjni.h"
  17. #include "mediacodec_wrapper.h"
  18. +#define PARAMETER_KEY_VIDEO_BITRATE "video-bitrate"
  19. +
  20. struct JNIAMediaCodecListFields {
  21. jclass mediacodec_list_class;
  22. @@ -195,6 +197,8 @@ struct JNIAMediaCodecFields {
  23. jmethodID set_input_surface_id;
  24. jmethodID signal_end_of_input_stream_id;
  25. + jmethodID set_parameters_id;
  26. +
  27. jclass mediainfo_class;
  28. jmethodID init_id;
  29. @@ -248,6 +252,8 @@ static const struct FFJniField jni_amediacodec_mapping[] = {
  30. { "android/media/MediaCodec", "setInputSurface", "(Landroid/view/Surface;)V", FF_JNI_METHOD, OFFSET(set_input_surface_id), 0 },
  31. { "android/media/MediaCodec", "signalEndOfInputStream", "()V", FF_JNI_METHOD, OFFSET(signal_end_of_input_stream_id), 0 },
  32. + { "android/media/MediaCodec", "setParameters", "(Landroid/os/Bundle;)V", FF_JNI_METHOD, OFFSET(set_parameters_id), 0 },
  33. +
  34. { "android/media/MediaCodec$BufferInfo", NULL, NULL, FF_JNI_CLASS, OFFSET(mediainfo_class), 1 },
  35. { "android/media/MediaCodec.BufferInfo", "<init>", "()V", FF_JNI_METHOD, OFFSET(init_id), 1 },
  36. @@ -292,6 +298,24 @@ typedef struct FFAMediaCodecJni {
  37. static const FFAMediaCodec media_codec_jni;
  38. +struct JNIABundleFields
  39. +{
  40. + jclass bundle_class;
  41. + jmethodID init_id;
  42. + jmethodID put_int_id;
  43. +};
  44. +
  45. +#define OFFSET(x) offsetof(struct JNIABundleFields, x)
  46. +static const struct FFJniField jni_abundle_mapping[] = {
  47. + { "android/os/Bundle", NULL, NULL, FF_JNI_CLASS, OFFSET(bundle_class), 1 },
  48. +
  49. + { "android/os/Bundle", "<init>", "()V", FF_JNI_METHOD, OFFSET(init_id), 1 },
  50. + { "android/os/Bundle", "putInt", "(Ljava/lang/String;I)V", FF_JNI_METHOD, OFFSET(put_int_id), 1 },
  51. +
  52. + { NULL }
  53. +};
  54. +#undef OFFSET
  55. +
  56. #define JNI_GET_ENV_OR_RETURN(env, log_ctx, ret) do { \
  57. (env) = ff_jni_get_env(log_ctx); \
  58. if (!(env)) { \
  59. @@ -1762,6 +1786,70 @@ static int mediacodec_jni_signalEndOfInputStream(FFAMediaCodec *ctx)
  60. return 0;
  61. }
  62. +
  63. +static int mediacodec_jni_setParameter(FFAMediaCodec *ctx, const char* name, int value)
  64. +{
  65. + JNIEnv *env = NULL;
  66. + struct JNIABundleFields jfields = { 0 };
  67. + jobject object = NULL;
  68. + jstring key = NULL;
  69. + FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
  70. + void *log_ctx = codec;
  71. + int ret = -1;
  72. +
  73. + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
  74. +
  75. + if (ff_jni_init_jfields(env, &jfields, jni_abundle_mapping, 0, log_ctx) < 0) {
  76. + av_log(log_ctx, AV_LOG_ERROR, "Failed to init jfields\n");
  77. + goto fail;
  78. + }
  79. +
  80. + object = (*env)->NewObject(env, jfields.bundle_class, jfields.init_id);
  81. + if (!object) {
  82. + av_log(log_ctx, AV_LOG_ERROR, "Failed to create bundle object\n");
  83. + goto fail;
  84. + }
  85. +
  86. + key = ff_jni_utf_chars_to_jstring(env, name, log_ctx);
  87. + if (!key) {
  88. + av_log(log_ctx, AV_LOG_ERROR, "Failed to convert key to jstring\n");
  89. + goto fail;
  90. + }
  91. +
  92. + (*env)->CallVoidMethod(env, object, jfields.put_int_id, key, value);
  93. + if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
  94. + goto fail;
  95. + }
  96. +
  97. + if (!codec->jfields.set_parameters_id) {
  98. + av_log(log_ctx, AV_LOG_ERROR, "System doesn't support setParameters\n");
  99. + goto fail;
  100. + }
  101. +
  102. + (*env)->CallVoidMethod(env, codec->object, codec->jfields.set_parameters_id, object);
  103. + if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
  104. + goto fail;
  105. + }
  106. +
  107. + ret = 0;
  108. +
  109. +fail:
  110. + if (key) {
  111. + (*env)->DeleteLocalRef(env, key);
  112. + }
  113. + if (object) {
  114. + (*env)->DeleteLocalRef(env, object);
  115. + }
  116. + ff_jni_reset_jfields(env, &jfields, jni_abundle_mapping, 0, log_ctx);
  117. +
  118. + return ret;
  119. +}
  120. +
  121. +static int mediacodec_jni_setDynamicBitrate(FFAMediaCodec *ctx, int bitrate)
  122. +{
  123. + return mediacodec_jni_setParameter(ctx, PARAMETER_KEY_VIDEO_BITRATE, bitrate);
  124. +}
  125. +
  126. static const FFAMediaFormat media_format_jni = {
  127. .class = &amediaformat_class,
  128. @@ -1821,6 +1909,8 @@ static const FFAMediaCodec media_codec_jni = {
  129. .getConfigureFlagEncode = mediacodec_jni_getConfigureFlagEncode,
  130. .cleanOutputBuffers = mediacodec_jni_cleanOutputBuffers,
  131. .signalEndOfInputStream = mediacodec_jni_signalEndOfInputStream,
  132. +
  133. + .setDynamicBitrate = mediacodec_jni_setDynamicBitrate,
  134. };
  135. typedef struct FFAMediaFormatNdk {
  136. @@ -2335,6 +2425,12 @@ static int mediacodec_ndk_signalEndOfInputStream(FFAMediaCodec *ctx)
  137. return 0;
  138. }
  139. +static int mediacodec_ndk_setDynamicBitrate(FFAMediaCodec *ctx, int bitrate)
  140. +{
  141. + av_log(ctx, AV_LOG_ERROR, "ndk setDynamicBitrate unavailable\n");
  142. + return -1;
  143. +}
  144. +
  145. static const FFAMediaFormat media_format_ndk = {
  146. .class = &amediaformat_ndk_class,
  147. @@ -2396,6 +2492,8 @@ static const FFAMediaCodec media_codec_ndk = {
  148. .getConfigureFlagEncode = mediacodec_ndk_getConfigureFlagEncode,
  149. .cleanOutputBuffers = mediacodec_ndk_cleanOutputBuffers,
  150. .signalEndOfInputStream = mediacodec_ndk_signalEndOfInputStream,
  151. +
  152. + .setDynamicBitrate = mediacodec_ndk_setDynamicBitrate,
  153. };
  154. FFAMediaFormat *ff_AMediaFormat_new(int ndk)
  155. diff --git a/libavcodec/mediacodec_wrapper.h b/libavcodec/mediacodec_wrapper.h
  156. index 11a4260497..86c64556ad 100644
  157. --- a/libavcodec/mediacodec_wrapper.h
  158. +++ b/libavcodec/mediacodec_wrapper.h
  159. @@ -219,6 +219,8 @@ struct FFAMediaCodec {
  160. // For encoder with FFANativeWindow as input.
  161. int (*signalEndOfInputStream)(FFAMediaCodec *);
  162. +
  163. + int (*setDynamicBitrate)(FFAMediaCodec *codec, int bitrate);
  164. };
  165. static inline char *ff_AMediaCodec_getName(FFAMediaCodec *codec)
  166. @@ -343,6 +345,11 @@ static inline int ff_AMediaCodec_signalEndOfInputStream(FFAMediaCodec *codec)
  167. return codec->signalEndOfInputStream(codec);
  168. }
  169. +static inline int ff_AMediaCodec_setDynamicBitrate(FFAMediaCodec *codec, int bitrate)
  170. +{
  171. + return codec->setDynamicBitrate(codec, bitrate);
  172. +}
  173. +
  174. int ff_Build_SDK_INT(AVCodecContext *avctx);
  175. enum FFAMediaFormatColorRange {
  176. diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c
  177. index 6ca3968a24..221f7360f4 100644
  178. --- a/libavcodec/mediacodecenc.c
  179. +++ b/libavcodec/mediacodecenc.c
  180. @@ -76,6 +76,8 @@ typedef struct MediaCodecEncContext {
  181. int level;
  182. int pts_as_dts;
  183. int extract_extradata;
  184. +
  185. + int last_bit_rate;
  186. } MediaCodecEncContext;
  187. enum {
  188. @@ -193,6 +195,8 @@ static av_cold int mediacodec_init(AVCodecContext *avctx)
  189. int ret;
  190. int gop;
  191. + s->last_bit_rate = avctx->bit_rate;
  192. +
  193. if (s->use_ndk_codec < 0)
  194. s->use_ndk_codec = !av_jni_get_java_vm(avctx);
  195. @@ -542,11 +546,25 @@ static int mediacodec_send(AVCodecContext *avctx,
  196. return 0;
  197. }
  198. +static void update_config(AVCodecContext *avctx)
  199. +{
  200. + MediaCodecEncContext *s = avctx->priv_data;
  201. + if (avctx->bit_rate != s->last_bit_rate) {
  202. + s->last_bit_rate = avctx->bit_rate;
  203. + if (0 != ff_AMediaCodec_setDynamicBitrate(s->codec, avctx->bit_rate)) {
  204. + av_log(avctx, AV_LOG_ERROR, "Failed to set bitrate to %d\n", avctx->bit_rate);
  205. + } else {
  206. + av_log(avctx, AV_LOG_INFO, "Set bitrate to %d\n", avctx->bit_rate);
  207. + }
  208. + }
  209. +}
  210. +
  211. static int mediacodec_encode(AVCodecContext *avctx, AVPacket *pkt)
  212. {
  213. MediaCodecEncContext *s = avctx->priv_data;
  214. int ret;
  215. + update_config(avctx);
  216. // Return on three case:
  217. // 1. Serious error
  218. // 2. Got a packet success
  219. --
  220. 2.43.0.windows.1