hlssink: Add segment target-duration property
This property causes hlssink to push a force key unit event upstream every target-duration seconds. This is for simple automatic segmenting. To disable it, set the property to 0 and push the force key unit event manually.
This commit is contained in:
parent
b1029d767e
commit
9d003f4d2b
@ -36,6 +36,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_hls_sink_debug);
|
|||||||
#define DEFAULT_PLAYLIST_LOCATION "playlist.m3u8"
|
#define DEFAULT_PLAYLIST_LOCATION "playlist.m3u8"
|
||||||
#define DEFAULT_PLAYLIST_ROOT NULL
|
#define DEFAULT_PLAYLIST_ROOT NULL
|
||||||
#define DEFAULT_MAX_FILES 10
|
#define DEFAULT_MAX_FILES 10
|
||||||
|
#define DEFAULT_TARGET_DURATION 15
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -43,7 +44,8 @@ enum
|
|||||||
PROP_LOCATION,
|
PROP_LOCATION,
|
||||||
PROP_PLAYLIST_LOCATION,
|
PROP_PLAYLIST_LOCATION,
|
||||||
PROP_PLAYLIST_ROOT,
|
PROP_PLAYLIST_ROOT,
|
||||||
PROP_MAX_FILES
|
PROP_MAX_FILES,
|
||||||
|
PROP_TARGET_DURATION
|
||||||
};
|
};
|
||||||
|
|
||||||
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
@ -140,6 +142,13 @@ gst_hls_sink_class_init (GstHlsSinkClass * klass)
|
|||||||
"old files start to be deleted to make room for new ones.",
|
"old files start to be deleted to make room for new ones.",
|
||||||
0, G_MAXUINT, DEFAULT_MAX_FILES,
|
0, G_MAXUINT, DEFAULT_MAX_FILES,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_TARGET_DURATION,
|
||||||
|
g_param_spec_uint ("target-duration", "Target duration",
|
||||||
|
"The target duration in seconds of a segment/file. "
|
||||||
|
"(0 - disabled, useful for management of segment duration by the "
|
||||||
|
"streaming server)",
|
||||||
|
0, G_MAXUINT, DEFAULT_TARGET_DURATION,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -160,6 +169,9 @@ gst_hls_sink_init (GstHlsSink * sink, GstHlsSinkClass * sink_class)
|
|||||||
sink->playlist_root = g_strdup (DEFAULT_PLAYLIST_ROOT);
|
sink->playlist_root = g_strdup (DEFAULT_PLAYLIST_ROOT);
|
||||||
sink->playlist = gst_m3u8_playlist_new (6, 5, FALSE);
|
sink->playlist = gst_m3u8_playlist_new (6, 5, FALSE);
|
||||||
sink->max_files = DEFAULT_MAX_FILES;
|
sink->max_files = DEFAULT_MAX_FILES;
|
||||||
|
sink->target_duration = DEFAULT_TARGET_DURATION;
|
||||||
|
sink->count = 0;
|
||||||
|
sink->timeout_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -250,6 +262,27 @@ gst_hls_sink_handle_message (GstBin * bin, GstMessage * message)
|
|||||||
GST_BIN_CLASS (parent_class)->handle_message (bin, message);
|
GST_BIN_CLASS (parent_class)->handle_message (bin, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
send_force_key_unit_event (gpointer user_data)
|
||||||
|
{
|
||||||
|
GstHlsSink *sink = GST_HLS_SINK_CAST (user_data);
|
||||||
|
GstPad *sinkpad = gst_element_get_static_pad (GST_ELEMENT (sink), "sink");
|
||||||
|
|
||||||
|
/* FIXME - try to make segments >= target duration in length by setting the
|
||||||
|
* time parameter of the force key unit event to last segment cut time +
|
||||||
|
* target duration */
|
||||||
|
sink->count++;
|
||||||
|
if (!gst_pad_push_event (sinkpad,
|
||||||
|
gst_video_event_new_upstream_force_key_unit (sink->target_duration *
|
||||||
|
sink->count, TRUE, sink->count))) {
|
||||||
|
GST_WARNING_OBJECT (sink, "Failed to push upstream force key unit event");
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_object_unref (sinkpad);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static GstStateChangeReturn
|
static GstStateChangeReturn
|
||||||
gst_hls_sink_change_state (GstElement * element, GstStateChange trans)
|
gst_hls_sink_change_state (GstElement * element, GstStateChange trans)
|
||||||
{
|
{
|
||||||
@ -262,6 +295,13 @@ gst_hls_sink_change_state (GstElement * element, GstStateChange trans)
|
|||||||
return GST_STATE_CHANGE_FAILURE;
|
return GST_STATE_CHANGE_FAILURE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||||
|
if (sink->target_duration) {
|
||||||
|
sink->timeout_id =
|
||||||
|
g_timeout_add_seconds (sink->target_duration,
|
||||||
|
send_force_key_unit_event, sink);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -269,6 +309,16 @@ gst_hls_sink_change_state (GstElement * element, GstStateChange trans)
|
|||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans);
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans);
|
||||||
|
|
||||||
switch (trans) {
|
switch (trans) {
|
||||||
|
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||||
|
if (sink->timeout_id && !g_source_remove (sink->timeout_id)) {
|
||||||
|
GST_WARNING_OBJECT (sink, "Failed to remove target-duration timeout");
|
||||||
|
}
|
||||||
|
sink->timeout_id = 0;
|
||||||
|
break;
|
||||||
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
|
/* reset the segment/file count */
|
||||||
|
sink->count = 0;
|
||||||
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -307,6 +357,9 @@ gst_hls_sink_set_property (GObject * object, guint prop_id,
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PROP_TARGET_DURATION:
|
||||||
|
sink->target_duration = g_value_get_uint (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -332,6 +385,9 @@ gst_hls_sink_get_property (GObject * object, guint prop_id,
|
|||||||
case PROP_MAX_FILES:
|
case PROP_MAX_FILES:
|
||||||
g_value_set_uint (value, sink->max_files);
|
g_value_set_uint (value, sink->max_files);
|
||||||
break;
|
break;
|
||||||
|
case PROP_TARGET_DURATION:
|
||||||
|
g_value_set_uint (value, sink->target_duration);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -50,6 +50,9 @@ struct _GstHlsSink
|
|||||||
GstM3U8Playlist *playlist;
|
GstM3U8Playlist *playlist;
|
||||||
guint index;
|
guint index;
|
||||||
gint max_files;
|
gint max_files;
|
||||||
|
gint target_duration;
|
||||||
|
gint count;
|
||||||
|
guint timeout_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstHlsSinkClass
|
struct _GstHlsSinkClass
|
||||||
|
Loading…
x
Reference in New Issue
Block a user