Commit 1bbdfa87 authored by Nicola Murino's avatar Nicola Murino Committed by Sebastian Dröge

matroskamux: add properties to control cluster duration

https://bugzilla.gnome.org/show_bug.cgi?id=784971
parent a6d22452
......@@ -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;
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment