From 6c1e5ab3110b5635f46a28c1d192a71fed38025b Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 31 Jan 2020 02:01:12 +1100 Subject: [PATCH] androidmedia: Support float i-frame-interval Android 25 added support for i-frame-interval to be a floating point value. Store the property as a float and use the newer version when it's available. --- sys/androidmedia/gstamcvideoenc.c | 40 ++++++++++++++++++++++++++++--- sys/androidmedia/gstamcvideoenc.h | 2 +- sys/androidmedia/gstjniutils.c | 22 +++++++++++++++++ sys/androidmedia/gstjniutils.h | 2 ++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/sys/androidmedia/gstamcvideoenc.c b/sys/androidmedia/gstamcvideoenc.c index e387f45719..8725520c98 100644 --- a/sys/androidmedia/gstamcvideoenc.c +++ b/sys/androidmedia/gstamcvideoenc.c @@ -41,6 +41,10 @@ #define orc_memcpy memcpy #endif +#ifdef HAVE_JNI_H +#include "gstjniutils.h" +#endif + #include "gstamcvideoenc.h" #include "gstamc-constants.h" @@ -95,7 +99,8 @@ enum { PROP_0, PROP_BIT_RATE, - PROP_I_FRAME_INTERVAL + PROP_I_FRAME_INTERVAL, + PROP_I_FRAME_INTERVAL_FLOAT }; /* class initialization */ @@ -263,8 +268,22 @@ create_amc_format (GstAmcVideoEnc * encoder, GstVideoCodecState * input_state, /* gst_amc_format_set_int (format, amc_level.key, amc_level.id); */ } - gst_amc_format_set_int (format, "i-frame-interval", encoder->i_frame_int, - &err); + /* On Android N_MR1 and higher, i-frame-interval can be a float value */ +#ifdef HAVE_JNI_H + if (gst_amc_jni_get_android_level () >= 25) { + GST_LOG_OBJECT (encoder, "Setting i-frame-interval to %f", + encoder->i_frame_int); + gst_amc_format_set_float (format, "i-frame-interval", encoder->i_frame_int, + &err); + } else +#endif + { + int i_frame_int = encoder->i_frame_int; + /* Round a fractional interval to 1 per sec on older Android */ + if (encoder->i_frame_int > 0 && encoder->i_frame_int < 1.0) + i_frame_int = 1; + gst_amc_format_set_int (format, "i-frame-interval", i_frame_int, &err); + } if (err) GST_ELEMENT_WARNING_FROM_ERROR (encoder, err); @@ -501,6 +520,11 @@ gst_amc_video_enc_set_property (GObject * object, guint prop_id, if (codec_active) goto wrong_state; break; + case PROP_I_FRAME_INTERVAL_FLOAT: + encoder->i_frame_int = g_value_get_float (value); + if (codec_active) + goto wrong_state; + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -532,6 +556,9 @@ gst_amc_video_enc_get_property (GObject * object, guint prop_id, case PROP_I_FRAME_INTERVAL: g_value_set_uint (value, encoder->i_frame_int); break; + case PROP_I_FRAME_INTERVAL_FLOAT: + g_value_set_float (value, encoder->i_frame_int); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -582,6 +609,13 @@ gst_amc_video_enc_class_init (GstAmcVideoEncClass * klass) "The frequency of I frames expressed in seconds between I frames (0 for automatic)", 0, G_MAXINT, I_FRAME_INTERVAL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_I_FRAME_INTERVAL_FLOAT, + g_param_spec_float ("i-frame-interval-float", "I-frame interval", + "The frequency of I frames expressed in seconds between I frames (0 for automatic). " + "Fractional intervals work on Android >= 25", + 0, G_MAXFLOAT, I_FRAME_INTERVAL_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void diff --git a/sys/androidmedia/gstamcvideoenc.h b/sys/androidmedia/gstamcvideoenc.h index 92833de9c0..e72ac56304 100644 --- a/sys/androidmedia/gstamcvideoenc.h +++ b/sys/androidmedia/gstamcvideoenc.h @@ -63,7 +63,7 @@ struct _GstAmcVideoEnc GstAmcColorFormatInfo color_format_info; guint bitrate; - guint i_frame_int; + gfloat i_frame_int; /* TRUE if the component is configured and saw * the first buffer */ diff --git a/sys/androidmedia/gstjniutils.c b/sys/androidmedia/gstjniutils.c index 0934082430..219268cfe8 100644 --- a/sys/androidmedia/gstjniutils.c +++ b/sys/androidmedia/gstjniutils.c @@ -43,6 +43,28 @@ static gboolean started_java_vm = FALSE; static pthread_key_t current_jni_env; static jobject (*get_class_loader) (void); +gint +gst_amc_jni_get_android_level () +{ + JNIEnv *env; + gint ret = __ANDROID_API__; + jfieldID sdkIntFieldID = NULL; + + env = gst_amc_jni_get_env (); + + jclass versionClass = (*env)->FindClass (env, "android/os/Build$VERSION"); + if (versionClass == NULL) + goto done; + + sdkIntFieldID = (*env)->GetStaticFieldID (env, versionClass, "SDK_INT", "I"); + if (sdkIntFieldID == NULL) + goto done; + + ret = (*env)->GetStaticIntField (env, versionClass, sdkIntFieldID); +done: + return ret; +} + jclass gst_amc_jni_get_class (JNIEnv * env, GError ** err, const gchar * name) { diff --git a/sys/androidmedia/gstjniutils.h b/sys/androidmedia/gstjniutils.h index 98c932c9d3..421a0007ed 100644 --- a/sys/androidmedia/gstjniutils.h +++ b/sys/androidmedia/gstjniutils.h @@ -37,6 +37,8 @@ #define GPOINTER_TO_JLONG(value) (jlong)(jint)(value) #endif +gint gst_amc_jni_get_android_level(void); + jclass gst_amc_jni_get_class (JNIEnv * env, GError ** err, const gchar * name);