androidmedia: Support float i-frame-interval
authorJan Schmidt <jan@centricular.com>
Thu, 30 Jan 2020 15:01:12 +0000 (02:01 +1100)
committerJan Schmidt <jan@centricular.com>
Sat, 8 Feb 2020 15:19:12 +0000 (02:19 +1100)
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
sys/androidmedia/gstamcvideoenc.h
sys/androidmedia/gstjniutils.c
sys/androidmedia/gstjniutils.h

index e387f45..8725520 100644 (file)
 #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
index 92833de..e72ac56 100644 (file)
@@ -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 */
index 0934082..219268c 100644 (file)
@@ -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)
 {
index 98c932c..421a000 100644 (file)
@@ -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);