]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/mediacodec_wrapper.c
avfilter/buffersrc: postpone removal of sws_param
[ffmpeg] / libavcodec / mediacodec_wrapper.c
index d9f0e27a7d8942d4df69c03c146e1a80ea997647..c829941d6b0c18ab1f16205f65d7174ba40164b6 100644 (file)
@@ -45,6 +45,7 @@ struct JNIAMediaCodecListFields {
     jmethodID get_codec_capabilities_id;
     jmethodID get_supported_types_id;
     jmethodID is_encoder_id;
+    jmethodID is_software_only_id;
 
     jclass codec_capabilities_class;
     jfieldID color_formats_id;
@@ -81,6 +82,7 @@ static const struct FFJniField jni_amediacodeclist_mapping[] = {
         { "android/media/MediaCodecInfo", "getCapabilitiesForType", "(Ljava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, get_codec_capabilities_id), 1 },
         { "android/media/MediaCodecInfo", "getSupportedTypes", "()[Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, get_supported_types_id), 1 },
         { "android/media/MediaCodecInfo", "isEncoder", "()Z", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, is_encoder_id), 1 },
+        { "android/media/MediaCodecInfo", "isSoftwareOnly", "()Z", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, is_software_only_id), 0 },
 
     { "android/media/MediaCodecInfo$CodecCapabilities", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecListFields, codec_capabilities_class), 1 },
         { "android/media/MediaCodecInfo$CodecCapabilities", "colorFormats", "[I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecListFields, color_formats_id), 1 },
@@ -111,6 +113,8 @@ struct JNIAMediaFormatFields {
 
     jmethodID init_id;
 
+    jmethodID contains_key_id;
+
     jmethodID get_integer_id;
     jmethodID get_long_id;
     jmethodID get_float_id;
@@ -132,6 +136,8 @@ static const struct FFJniField jni_amediaformat_mapping[] = {
 
         { "android/media/MediaFormat", "<init>", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, init_id), 1 },
 
+        { "android/media/MediaFormat", "containsKey", "(Ljava/lang/String;)Z", FF_JNI_METHOD,offsetof(struct JNIAMediaFormatFields, contains_key_id), 1 },
+
         { "android/media/MediaFormat", "getInteger", "(Ljava/lang/String;)I", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_integer_id), 1 },
         { "android/media/MediaFormat", "getLong", "(Ljava/lang/String;)J", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_long_id), 1 },
         { "android/media/MediaFormat", "getFloat", "(Ljava/lang/String;)F", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_float_id), 1 },
@@ -152,7 +158,7 @@ static const struct FFJniField jni_amediaformat_mapping[] = {
 static const AVClass amediaformat_class = {
     .class_name = "amediaformat",
     .item_name  = av_default_item_name,
-    .version    = LIBAVCODEC_VERSION_INT,
+    .version    = LIBAVUTIL_VERSION_INT,
 };
 
 struct FFAMediaFormat {
@@ -264,7 +270,7 @@ static const struct FFJniField jni_amediacodec_mapping[] = {
 static const AVClass amediacodec_class = {
     .class_name = "amediacodec",
     .item_name  = av_default_item_name,
-    .version    = LIBAVCODEC_VERSION_INT,
+    .version    = LIBAVUTIL_VERSION_INT,
 };
 
 struct FFAMediaCodec {
@@ -274,6 +280,7 @@ struct FFAMediaCodec {
     struct JNIAMediaCodecFields jfields;
 
     jobject object;
+    jobject buffer_info;
 
     jobject input_buffers;
     jobject output_buffers;
@@ -387,8 +394,6 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e
     struct JNIAMediaCodecListFields jfields = { 0 };
     struct JNIAMediaFormatFields mediaformat_jfields = { 0 };
 
-    jobject format = NULL;
-    jobject codec = NULL;
     jobject codec_name = NULL;
 
     jobject info = NULL;
@@ -438,6 +443,41 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e
             goto done_with_info;
         }
 
+        if (jfields.is_software_only_id) {
+            int is_software_only = (*env)->CallBooleanMethod(env, info, jfields.is_software_only_id);
+            if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+                goto done;
+            }
+
+            if (is_software_only) {
+                goto done_with_info;
+            }
+        }
+
+        codec_name = (*env)->CallObjectMethod(env, info, jfields.get_name_id);
+        if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+            goto done;
+        }
+
+        name = ff_jni_jstring_to_utf_chars(env, codec_name, log_ctx);
+        if (!name) {
+            goto done;
+        }
+
+        if (codec_name) {
+            (*env)->DeleteLocalRef(env, codec_name);
+            codec_name = NULL;
+        }
+
+        /* Skip software decoders */
+        if (
+            strstr(name, "OMX.google") ||
+            strstr(name, "OMX.ffmpeg") ||
+            (strstr(name, "OMX.SEC") && strstr(name, ".sw.")) ||
+            !strcmp(name, "OMX.qcom.video.decoder.hevcswvdec")) {
+            goto done_with_info;
+        }
+
         type_count = (*env)->GetArrayLength(env, types);
         for (j = 0; j < type_count; j++) {
             int k;
@@ -453,64 +493,51 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e
                 goto done;
             }
 
-            if (!av_strcasecmp(supported_type, mime)) {
-                codec_name = (*env)->CallObjectMethod(env, info, jfields.get_name_id);
-                if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
-                    goto done;
-                }
+            if (av_strcasecmp(supported_type, mime)) {
+                goto done_with_type;
+            }
 
-                name = ff_jni_jstring_to_utf_chars(env, codec_name, log_ctx);
-                if (!name) {
-                    goto done;
-                }
+            capabilities = (*env)->CallObjectMethod(env, info, jfields.get_codec_capabilities_id, type);
+            if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+                goto done;
+            }
+
+            profile_levels = (*env)->GetObjectField(env, capabilities, jfields.profile_levels_id);
+            if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+                goto done;
+            }
+
+            profile_count = (*env)->GetArrayLength(env, profile_levels);
+            if (!profile_count) {
+                found_codec = 1;
+            }
+            for (k = 0; k < profile_count; k++) {
+                int supported_profile = 0;
 
-                if (strstr(name, "OMX.google")) {
-                    av_freep(&name);
-                    goto done_with_type;
+                if (profile < 0) {
+                    found_codec = 1;
+                    break;
                 }
 
-                capabilities = (*env)->CallObjectMethod(env, info, jfields.get_codec_capabilities_id, type);
+                profile_level = (*env)->GetObjectArrayElement(env, profile_levels, k);
                 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
                     goto done;
                 }
 
-                profile_levels = (*env)->GetObjectField(env, capabilities, jfields.profile_levels_id);
+                supported_profile = (*env)->GetIntField(env, profile_level, jfields.profile_id);
                 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
                     goto done;
                 }
 
-                profile_count = (*env)->GetArrayLength(env, profile_levels);
-                if (!profile_count) {
-                    found_codec = 1;
+                found_codec = profile == supported_profile;
+
+                if (profile_level) {
+                    (*env)->DeleteLocalRef(env, profile_level);
+                    profile_level = NULL;
                 }
-                for (k = 0; k < profile_count; k++) {
-                    int supported_profile = 0;
-
-                    if (profile < 0) {
-                        found_codec = 1;
-                        break;
-                    }
-
-                    profile_level = (*env)->GetObjectArrayElement(env, profile_levels, k);
-                    if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
-                        goto done;
-                    }
-
-                    supported_profile = (*env)->GetIntField(env, profile_level, jfields.profile_id);
-                    if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
-                        goto done;
-                    }
-
-                    found_codec = profile == supported_profile;
-
-                    if (profile_level) {
-                        (*env)->DeleteLocalRef(env, profile_level);
-                        profile_level = NULL;
-                    }
-
-                    if (found_codec) {
-                        break;
-                    }
+
+                if (found_codec) {
+                    break;
                 }
             }
 
@@ -535,8 +562,6 @@ done_with_type:
             if (found_codec) {
                 break;
             }
-
-            av_freep(&name);
         }
 
 done_with_info:
@@ -553,17 +578,11 @@ done_with_info:
         if (found_codec) {
             break;
         }
-    }
 
-done:
-    if (format) {
-        (*env)->DeleteLocalRef(env, format);
-    }
-
-    if (codec) {
-        (*env)->DeleteLocalRef(env, codec);
+        av_freep(&name);
     }
 
+done:
     if (codec_name) {
         (*env)->DeleteLocalRef(env, codec_name);
     }
@@ -737,6 +756,7 @@ int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t *
 
     JNIEnv *env = NULL;
     jstring key = NULL;
+    jboolean contains_key;
 
     av_assert0(format != NULL);
 
@@ -748,6 +768,12 @@ int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t *
         goto fail;
     }
 
+    contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
+    if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+        ret = 0;
+        goto fail;
+    }
+
     *out = (*env)->CallIntMethod(env, format->object, format->jfields.get_integer_id, key);
     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
@@ -769,6 +795,7 @@ int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t *
 
     JNIEnv *env = NULL;
     jstring key = NULL;
+    jboolean contains_key;
 
     av_assert0(format != NULL);
 
@@ -780,6 +807,12 @@ int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t *
         goto fail;
     }
 
+    contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
+    if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+        ret = 0;
+        goto fail;
+    }
+
     *out = (*env)->CallLongMethod(env, format->object, format->jfields.get_long_id, key);
     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
@@ -801,6 +834,7 @@ int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *ou
 
     JNIEnv *env = NULL;
     jstring key = NULL;
+    jboolean contains_key;
 
     av_assert0(format != NULL);
 
@@ -812,6 +846,12 @@ int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *ou
         goto fail;
     }
 
+    contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
+    if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+        ret = 0;
+        goto fail;
+    }
+
     *out = (*env)->CallFloatMethod(env, format->object, format->jfields.get_float_id, key);
     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
@@ -833,6 +873,7 @@ int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** d
 
     JNIEnv *env = NULL;
     jstring key = NULL;
+    jboolean contains_key;
     jobject result = NULL;
 
     av_assert0(format != NULL);
@@ -845,6 +886,12 @@ int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** d
         goto fail;
     }
 
+    contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
+    if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+        ret = 0;
+        goto fail;
+    }
+
     result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_bytebuffer_id, key);
     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
@@ -884,6 +931,7 @@ int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const ch
 
     JNIEnv *env = NULL;
     jstring key = NULL;
+    jboolean contains_key;
     jstring result = NULL;
 
     av_assert0(format != NULL);
@@ -896,6 +944,12 @@ int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const ch
         goto fail;
     }
 
+    contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
+    if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+        ret = 0;
+        goto fail;
+    }
+
     result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_string_id, key);
     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
@@ -1143,6 +1197,7 @@ static inline FFAMediaCodec *codec_create(int method, const char *arg)
     FFAMediaCodec *codec = NULL;
     jstring jarg = NULL;
     jobject object = NULL;
+    jobject buffer_info = NULL;
     jmethodID create_id = NULL;
 
     codec = av_mallocz(sizeof(FFAMediaCodec));
@@ -1195,6 +1250,16 @@ static inline FFAMediaCodec *codec_create(int method, const char *arg)
         codec->has_get_i_o_buffer = 1;
     }
 
+    buffer_info = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id);
+    if (ff_jni_exception_check(env, 1, codec) < 0) {
+        goto fail;
+    }
+
+    codec->buffer_info = (*env)->NewGlobalRef(env, buffer_info);
+    if (!codec->buffer_info) {
+        goto fail;
+    }
+
     ret = 0;
 fail:
     if (jarg) {
@@ -1205,10 +1270,19 @@ fail:
         (*env)->DeleteLocalRef(env, object);
     }
 
+    if (buffer_info) {
+        (*env)->DeleteLocalRef(env, buffer_info);
+    }
+
     if (ret < 0) {
         if (codec->object) {
             (*env)->DeleteGlobalRef(env, codec->object);
         }
+
+        if (codec->buffer_info) {
+            (*env)->DeleteGlobalRef(env, codec->buffer_info);
+        }
+
         ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
         av_freep(&codec);
     }
@@ -1243,9 +1317,18 @@ int ff_AMediaCodec_delete(FFAMediaCodec* codec)
         ret = AVERROR_EXTERNAL;
     }
 
+    (*env)->DeleteGlobalRef(env, codec->input_buffers);
+    codec->input_buffers = NULL;
+
+    (*env)->DeleteGlobalRef(env, codec->output_buffers);
+    codec->output_buffers = NULL;
+
     (*env)->DeleteGlobalRef(env, codec->object);
     codec->object = NULL;
 
+    (*env)->DeleteGlobalRef(env, codec->buffer_info);
+    codec->buffer_info = NULL;
+
     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
 
     av_freep(&codec);
@@ -1269,6 +1352,10 @@ char *ff_AMediaCodec_getName(FFAMediaCodec *codec)
     ret = ff_jni_jstring_to_utf_chars(env, name, codec);
 
 fail:
+    if (name) {
+        (*env)->DeleteLocalRef(env, name);
+    }
+
     return ret;
 }
 
@@ -1364,7 +1451,7 @@ int ff_AMediaCodec_releaseOutputBufferAtTime(FFAMediaCodec *codec, size_t idx, i
 
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
-    (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, (jint)idx, timestampNs);
+    (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, (jint)idx, (jlong)timestampNs);
     if (ff_jni_exception_check(env, 1, codec) < 0) {
         ret = AVERROR_EXTERNAL;
         goto fail;
@@ -1413,48 +1500,31 @@ ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBu
     int ret = 0;
     JNIEnv *env = NULL;
 
-    jobject mediainfo = NULL;
-
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
-    mediainfo = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id);
+    ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, codec->buffer_info, timeoutUs);
     if (ff_jni_exception_check(env, 1, codec) < 0) {
-        ret = AVERROR_EXTERNAL;
-        goto fail;
+        return AVERROR_EXTERNAL;
     }
 
-    ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, mediainfo, timeoutUs);
+    info->flags = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.flags_id);
     if (ff_jni_exception_check(env, 1, codec) < 0) {
-        ret = AVERROR_EXTERNAL;
-        goto fail;
+        return AVERROR_EXTERNAL;
     }
 
-    info->flags = (*env)->GetIntField(env, mediainfo, codec->jfields.flags_id);
+    info->offset = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.offset_id);
     if (ff_jni_exception_check(env, 1, codec) < 0) {
-        ret = AVERROR_EXTERNAL;
-        goto fail;
+        return AVERROR_EXTERNAL;
     }
 
-    info->offset = (*env)->GetIntField(env, mediainfo, codec->jfields.offset_id);
+    info->presentationTimeUs = (*env)->GetLongField(env, codec->buffer_info, codec->jfields.presentation_time_us_id);
     if (ff_jni_exception_check(env, 1, codec) < 0) {
-        ret = AVERROR_EXTERNAL;
-        goto fail;
+        return AVERROR_EXTERNAL;
     }
 
-    info->presentationTimeUs = (*env)->GetLongField(env, mediainfo, codec->jfields.presentation_time_us_id);
+    info->size = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.size_id);
     if (ff_jni_exception_check(env, 1, codec) < 0) {
-        ret = AVERROR_EXTERNAL;
-        goto fail;
-    }
-
-    info->size = (*env)->GetIntField(env, mediainfo, codec->jfields.size_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
-        ret = AVERROR_EXTERNAL;
-        goto fail;
-    }
-fail:
-    if (mediainfo) {
-        (*env)->DeleteLocalRef(env, mediainfo);
+        return AVERROR_EXTERNAL;
     }
 
     return ret;
@@ -1636,3 +1706,18 @@ int ff_AMediaCodec_cleanOutputBuffers(FFAMediaCodec *codec)
 fail:
     return ret;
 }
+
+int ff_Build_SDK_INT(AVCodecContext *avctx)
+{
+    int ret = -1;
+    JNIEnv *env = NULL;
+    jclass versionClass;
+    jfieldID sdkIntFieldID;
+    JNI_GET_ENV_OR_RETURN(env, avctx, -1);
+
+    versionClass = (*env)->FindClass(env, "android/os/Build$VERSION");
+    sdkIntFieldID = (*env)->GetStaticFieldID(env, versionClass, "SDK_INT", "I");
+    ret = (*env)->GetStaticIntField(env, versionClass, sdkIntFieldID);
+    (*env)->DeleteLocalRef(env, versionClass);
+    return ret;
+}