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
#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))
"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);
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;
mux->index = NULL;
/* reset timers */
- mux->max_cluster_duration = G_MAXINT16 * mux->time_scale;
mux->duration = 0;
/* reset cluster */
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;
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);
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;
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;