matroskamux: add properties to control cluster duration
authorNicola Murino <nicola.murino@gmail.com>
Mon, 17 Jul 2017 22:26:11 +0000 (00:26 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Tue, 18 Jul 2017 07:08:33 +0000 (10:08 +0300)
https://bugzilla.gnome.org/show_bug.cgi?id=784971

gst/matroska/matroska-mux.c
gst/matroska/matroska-mux.h

index 2a0bdcc..fdabe5b 100644 (file)
@@ -70,7 +70,9 @@ enum
   PROP_DOCTYPE_VERSION,
   PROP_MIN_INDEX_INTERVAL,
   PROP_STREAMABLE,
-  PROP_TIMECODESCALE
+  PROP_TIMECODESCALE,
+  PROP_MIN_CLUSTER_DURATION,
+  PROP_MAX_CLUSTER_DURATION
 };
 
 #define  DEFAULT_DOCTYPE_VERSION         2
@@ -78,6 +80,8 @@ enum
 #define  DEFAULT_MIN_INDEX_INTERVAL      0
 #define  DEFAULT_STREAMABLE              FALSE
 #define  DEFAULT_TIMECODESCALE           GST_MSECOND
+#define  DEFAULT_MIN_CLUSTER_DURATION    500 * GST_MSECOND
+#define  DEFAULT_MAX_CLUSTER_DURATION    65535 * GST_MSECOND
 
 /* WAVEFORMATEX is gst_riff_strf_auds + an extra guint16 extension size */
 #define WAVEFORMATEX_SIZE  (2 + sizeof (gst_riff_strf_auds))
@@ -344,6 +348,20 @@ gst_matroska_mux_class_init (GstMatroskaMuxClass * klass)
           "TimecodeScale used to calculate the Raw Timecode of a Block", 1,
           GST_SECOND, DEFAULT_TIMECODESCALE,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MIN_CLUSTER_DURATION,
+      g_param_spec_int64 ("min-cluster-duration", "Minimum cluster duration",
+          "Desidered cluster duration as nanoseconds. A new cluster will be "
+          "created irrespective of this property if a force key unit event "
+          "is received. 0 means create a new cluster for each video keyframe "
+          "or for each audio buffer in audio only streams.", 0,
+          G_MAXINT64, DEFAULT_MIN_CLUSTER_DURATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAX_CLUSTER_DURATION,
+      g_param_spec_int64 ("max-cluster-duration", "Maximum cluster duration",
+          "A new cluster will be created if its duration exceeds this value. "
+          "0 means no maximum duration.", 0,
+          G_MAXINT64, DEFAULT_MAX_CLUSTER_DURATION,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_matroska_mux_change_state);
@@ -471,6 +489,8 @@ gst_matroska_mux_init (GstMatroskaMux * mux, gpointer g_class)
   mux->min_index_interval = DEFAULT_MIN_INDEX_INTERVAL;
   mux->ebml_write->streamable = DEFAULT_STREAMABLE;
   mux->time_scale = DEFAULT_TIMECODESCALE;
+  mux->min_cluster_duration = DEFAULT_MIN_CLUSTER_DURATION;
+  mux->max_cluster_duration = DEFAULT_MAX_CLUSTER_DURATION;
 
   /* initialize internal variables */
   mux->index = NULL;
@@ -664,7 +684,6 @@ gst_matroska_mux_reset (GstElement * element)
   mux->index = NULL;
 
   /* reset timers */
-  mux->max_cluster_duration = G_MAXINT16 * mux->time_scale;
   mux->duration = 0;
 
   /* reset cluster */
@@ -3526,6 +3545,8 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
   gboolean is_video_keyframe = FALSE;
   gboolean is_video_invisible = FALSE;
   gboolean is_audio_only = FALSE;
+  gboolean is_min_duration_reached = FALSE;
+  gboolean is_max_duration_exceeded = FALSE;
   GstMatroskamuxPad *pad;
   gint flags = 0;
   GstClockTime buffer_timestamp;
@@ -3602,13 +3623,20 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad,
 
   is_audio_only = (collect_pad->track->type == GST_MATROSKA_TRACK_TYPE_AUDIO) &&
       (mux->num_streams == 1);
+  is_min_duration_reached = (mux->min_cluster_duration == 0
+      || (buffer_timestamp > mux->cluster_time
+          && (buffer_timestamp - mux->cluster_time) >=
+          mux->min_cluster_duration));
+  is_max_duration_exceeded = (mux->max_cluster_duration > 0
+      && buffer_timestamp > mux->cluster_time
+      && (buffer_timestamp - mux->cluster_time) >= mux->max_cluster_duration);
 
   if (mux->cluster) {
     /* start a new cluster at every keyframe, at every GstForceKeyUnit event,
      * or when we may be reaching the limit of the relative timestamp */
-    if (mux->cluster_time +
-        mux->max_cluster_duration < buffer_timestamp
-        || is_video_keyframe || mux->force_key_unit_event || is_audio_only) {
+    if (is_max_duration_exceeded || (is_video_keyframe
+            && is_min_duration_reached) || mux->force_key_unit_event
+        || (is_audio_only && is_min_duration_reached)) {
       if (!mux->ebml_write->streamable)
         gst_ebml_write_master_finish (ebml, mux->cluster);
 
@@ -3940,6 +3968,12 @@ gst_matroska_mux_set_property (GObject * object,
     case PROP_TIMECODESCALE:
       mux->time_scale = g_value_get_int64 (value);
       break;
+    case PROP_MIN_CLUSTER_DURATION:
+      mux->min_cluster_duration = g_value_get_int64 (value);
+      break;
+    case PROP_MAX_CLUSTER_DURATION:
+      mux->max_cluster_duration = g_value_get_int64 (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -3971,6 +4005,12 @@ gst_matroska_mux_get_property (GObject * object,
     case PROP_TIMECODESCALE:
       g_value_set_int64 (value, mux->time_scale);
       break;
+    case PROP_MIN_CLUSTER_DURATION:
+      g_value_set_int64 (value, mux->min_cluster_duration);
+      break;
+    case PROP_MAX_CLUSTER_DURATION:
+      g_value_set_int64 (value, mux->max_cluster_duration);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index c389416..aaeeecd 100644 (file)
@@ -107,8 +107,9 @@ struct _GstMatroskaMux {
  
   /* timescale in the file */
   guint64        time_scale;
-  /* based on timescale, limit of nanoseconds you can have in a cluster */ 
+  /* minimum and maximum limit of nanoseconds you can have in a cluster */
   guint64        max_cluster_duration;
+  guint64        min_cluster_duration;
 
   /* length, position (time, ns) */
   guint64        duration;