[FFmpeg-devel] [PATCH 2/2] lavc/mediacodec: bypass width/height restrictions when looking for a decoder

Matthieu Bouron matthieu.bouron at gmail.com
Tue May 31 15:00:45 CEST 2016


From: Matthieu Bouron <matthieu.bouron at stupeflix.com>

Codec width/height restrictions seem hardcoded at the OMX level and
seem arbitrary. Bypassing those restrictions allows a device to decode
streams at higher resolutions.

For example it allows a Nexus 5 to decode h264 streams with a resolution
higher than 1920x1080.
---
 libavcodec/mediacodec_wrapper.c | 31 ++++++++++++++++++++++++++-----
 libavcodec/mediacodec_wrapper.h |  2 +-
 libavcodec/mediacodecdec.c      |  2 +-
 3 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c
index c847a11..2e3fcef 100644
--- a/libavcodec/mediacodec_wrapper.c
+++ b/libavcodec/mediacodec_wrapper.c
@@ -33,7 +33,8 @@
 struct JNIAMediaCodecListFields {
 
     jclass mediaformat_class;
-    jmethodID create_video_format_id;
+    jmethodID mediaformat_init_id;
+    jmethodID set_string_id;
 
     jclass mediacodec_list_class;
     jmethodID init_id;
@@ -51,7 +52,8 @@ struct JNIAMediaCodecListFields {
 
 static const struct FFJniField jfields_mapping[] = {
     { "android/media/MediaFormat", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecListFields, mediaformat_class), 1 },
-        { "android/media/MediaFormat", "createVideoFormat", "(Ljava/lang/String;II)Landroid/media/MediaFormat;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecListFields, create_video_format_id), 1 },
+        { "android/media/MediaFormat", "<init>", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, mediaformat_init_id), 1},
+        { "android/media/MediaFormat", "setString", "(Ljava/lang/String;Ljava/lang/String;)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, set_string_id), 1},
 
     { "android/media/MediaCodecList", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecListFields, mediacodec_list_class), 1 },
         { "android/media/MediaCodecList", "<init>", "(I)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, init_id), 0 },
@@ -87,7 +89,7 @@ static const struct FFJniField jfields_mapping[] = {
         ff_jni_detach_env(log_ctx);            \
 } while (0)
 
-char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int width, int height, void *log_ctx)
+char *ff_AMediaCodecList_getCodecNameByType(const char *mime, void *log_ctx)
 {
     int ret;
     char *name = NULL;
@@ -99,6 +101,7 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int width, int hei
 
     jobject format = NULL;
     jobject codec = NULL;
+    jstring key = NULL;
     jstring tmp = NULL;
 
     jobject info = NULL;
@@ -112,15 +115,29 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int width, int hei
     }
 
     if (jfields.init_id && jfields.find_decoder_for_format_id) {
+        key = ff_jni_utf_chars_to_jstring(env, "mime", log_ctx);
+        if (!key) {
+            goto done;
+        }
+
         tmp = ff_jni_utf_chars_to_jstring(env, mime, log_ctx);
         if (!tmp) {
             goto done;
         }
 
-        format = (*env)->CallStaticObjectMethod(env, jfields.mediaformat_class, jfields.create_video_format_id, tmp, width, height);
+        format = (*env)->NewObject(env, jfields.mediaformat_class, jfields.mediaformat_init_id);
+        if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+            goto done;
+        }
+
+        (*env)->CallVoidMethod(env, format, jfields.set_string_id, key, tmp);
         if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
             goto done;
         }
+
+        (*env)->DeleteLocalRef(env, key);
+        key = NULL;
+
         (*env)->DeleteLocalRef(env, tmp);
         tmp = NULL;
 
@@ -135,7 +152,7 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int width, int hei
         }
         if (!tmp) {
             av_log(NULL, AV_LOG_ERROR, "Could not find decoder in media codec list "
-                                       "for format { mime=%s width=%d height=%d }\n", mime, width, height);
+                                       "for format { mime=%s }\n", mime);
             goto done;
         }
 
@@ -232,6 +249,10 @@ done:
         (*env)->DeleteLocalRef(env, codec);
     }
 
+    if (key) {
+        (*env)->DeleteLocalRef(env, key);
+    }
+
     if (tmp) {
         (*env)->DeleteLocalRef(env, tmp);
     }
diff --git a/libavcodec/mediacodec_wrapper.h b/libavcodec/mediacodec_wrapper.h
index a804b61..36cd258 100644
--- a/libavcodec/mediacodec_wrapper.h
+++ b/libavcodec/mediacodec_wrapper.h
@@ -52,7 +52,7 @@
  *
  */
 
-char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int width, int height, void *log_ctx);
+char *ff_AMediaCodecList_getCodecNameByType(const char *mime, void *log_ctx);
 
 struct FFAMediaFormat;
 typedef struct FFAMediaFormat FFAMediaFormat;
diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c
index c21ceba..712f984 100644
--- a/libavcodec/mediacodecdec.c
+++ b/libavcodec/mediacodecdec.c
@@ -311,7 +311,7 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
 
     s->first_buffer_at = av_gettime();
 
-    s->codec_name = ff_AMediaCodecList_getCodecNameByType(mime, avctx->width, avctx->height, avctx);
+    s->codec_name = ff_AMediaCodecList_getCodecNameByType(mime, avctx);
     if (!s->codec_name) {
         ret = AVERROR_EXTERNAL;
         goto fail;
-- 
2.8.3



More information about the ffmpeg-devel mailing list