mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
splitmuxsink: Add option to split at exactly max-size-time
Will try to request a keyframe from the encoder to be sent at the target running time. https://bugzilla.gnome.org/show_bug.cgi?id=769664
This commit is contained in:
parent
369d37d227
commit
b9a8188704
2 changed files with 53 additions and 4 deletions
|
@ -55,6 +55,7 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
|
#include <gst/video/video.h>
|
||||||
#include "gstsplitmuxsink.h"
|
#include "gstsplitmuxsink.h"
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (splitmux_debug);
|
GST_DEBUG_CATEGORY_STATIC (splitmux_debug);
|
||||||
|
@ -71,6 +72,7 @@ enum
|
||||||
PROP_LOCATION,
|
PROP_LOCATION,
|
||||||
PROP_MAX_SIZE_TIME,
|
PROP_MAX_SIZE_TIME,
|
||||||
PROP_MAX_SIZE_BYTES,
|
PROP_MAX_SIZE_BYTES,
|
||||||
|
PROP_SEND_KEYFRAME_REQUESTS,
|
||||||
PROP_MAX_FILES,
|
PROP_MAX_FILES,
|
||||||
PROP_MUXER_OVERHEAD,
|
PROP_MUXER_OVERHEAD,
|
||||||
PROP_MUXER,
|
PROP_MUXER,
|
||||||
|
@ -81,6 +83,7 @@ enum
|
||||||
#define DEFAULT_MAX_SIZE_BYTES 0
|
#define DEFAULT_MAX_SIZE_BYTES 0
|
||||||
#define DEFAULT_MAX_FILES 0
|
#define DEFAULT_MAX_FILES 0
|
||||||
#define DEFAULT_MUXER_OVERHEAD 0.02
|
#define DEFAULT_MUXER_OVERHEAD 0.02
|
||||||
|
#define DEFAULT_SEND_KEYFRAME_REQUESTS FALSE
|
||||||
#define DEFAULT_MUXER "mp4mux"
|
#define DEFAULT_MUXER "mp4mux"
|
||||||
#define DEFAULT_SINK "filesink"
|
#define DEFAULT_SINK "filesink"
|
||||||
|
|
||||||
|
@ -207,11 +210,18 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass)
|
||||||
g_param_spec_uint64 ("max-size-bytes", "Max. size bytes",
|
g_param_spec_uint64 ("max-size-bytes", "Max. size bytes",
|
||||||
"Max. amount of data per file (in bytes, 0=disable)", 0, G_MAXUINT64,
|
"Max. amount of data per file (in bytes, 0=disable)", 0, G_MAXUINT64,
|
||||||
DEFAULT_MAX_SIZE_BYTES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
DEFAULT_MAX_SIZE_BYTES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_SEND_KEYFRAME_REQUESTS,
|
||||||
|
g_param_spec_boolean ("send-keyframe-requests",
|
||||||
|
"Request keyframes at max-size-time",
|
||||||
|
"Request a keyframe every max-size-time ns to try splitting at that point. "
|
||||||
|
"Needs max-size-bytes to be 0 in order to be effective.",
|
||||||
|
DEFAULT_SEND_KEYFRAME_REQUESTS,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
g_object_class_install_property (gobject_class, PROP_MAX_FILES,
|
g_object_class_install_property (gobject_class, PROP_MAX_FILES,
|
||||||
g_param_spec_uint ("max-files", "Max files",
|
g_param_spec_uint ("max-files", "Max files",
|
||||||
"Maximum number of files to keep on disk. Once the maximum is reached,"
|
"Maximum number of files to keep on disk. Once the maximum is reached,"
|
||||||
"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,
|
||||||
0, G_MAXUINT, DEFAULT_MAX_FILES,
|
G_MAXUINT, DEFAULT_MAX_FILES,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
|
||||||
|
@ -246,6 +256,7 @@ gst_splitmux_sink_init (GstSplitMuxSink * splitmux)
|
||||||
splitmux->threshold_time = DEFAULT_MAX_SIZE_TIME;
|
splitmux->threshold_time = DEFAULT_MAX_SIZE_TIME;
|
||||||
splitmux->threshold_bytes = DEFAULT_MAX_SIZE_BYTES;
|
splitmux->threshold_bytes = DEFAULT_MAX_SIZE_BYTES;
|
||||||
splitmux->max_files = DEFAULT_MAX_FILES;
|
splitmux->max_files = DEFAULT_MAX_FILES;
|
||||||
|
splitmux->send_keyframe_requests = DEFAULT_SEND_KEYFRAME_REQUESTS;
|
||||||
|
|
||||||
GST_OBJECT_FLAG_SET (splitmux, GST_ELEMENT_FLAG_SINK);
|
GST_OBJECT_FLAG_SET (splitmux, GST_ELEMENT_FLAG_SINK);
|
||||||
}
|
}
|
||||||
|
@ -320,6 +331,11 @@ gst_splitmux_sink_set_property (GObject * object, guint prop_id,
|
||||||
splitmux->threshold_time = g_value_get_uint64 (value);
|
splitmux->threshold_time = g_value_get_uint64 (value);
|
||||||
GST_OBJECT_UNLOCK (splitmux);
|
GST_OBJECT_UNLOCK (splitmux);
|
||||||
break;
|
break;
|
||||||
|
case PROP_SEND_KEYFRAME_REQUESTS:
|
||||||
|
GST_OBJECT_LOCK (splitmux);
|
||||||
|
splitmux->send_keyframe_requests = g_value_get_boolean (value);
|
||||||
|
GST_OBJECT_UNLOCK (splitmux);
|
||||||
|
break;
|
||||||
case PROP_MAX_FILES:
|
case PROP_MAX_FILES:
|
||||||
GST_OBJECT_LOCK (splitmux);
|
GST_OBJECT_LOCK (splitmux);
|
||||||
splitmux->max_files = g_value_get_uint (value);
|
splitmux->max_files = g_value_get_uint (value);
|
||||||
|
@ -372,6 +388,11 @@ gst_splitmux_sink_get_property (GObject * object, guint prop_id,
|
||||||
g_value_set_uint64 (value, splitmux->threshold_time);
|
g_value_set_uint64 (value, splitmux->threshold_time);
|
||||||
GST_OBJECT_UNLOCK (splitmux);
|
GST_OBJECT_UNLOCK (splitmux);
|
||||||
break;
|
break;
|
||||||
|
case PROP_SEND_KEYFRAME_REQUESTS:
|
||||||
|
GST_OBJECT_LOCK (splitmux);
|
||||||
|
g_value_set_boolean (value, splitmux->send_keyframe_requests);
|
||||||
|
GST_OBJECT_UNLOCK (splitmux);
|
||||||
|
break;
|
||||||
case PROP_MAX_FILES:
|
case PROP_MAX_FILES:
|
||||||
GST_OBJECT_LOCK (splitmux);
|
GST_OBJECT_LOCK (splitmux);
|
||||||
g_value_set_uint (value, splitmux->max_files);
|
g_value_set_uint (value, splitmux->max_files);
|
||||||
|
@ -601,6 +622,22 @@ complete_or_wait_on_out (GstSplitMuxSink * splitmux, MqStreamCtx * ctx)
|
||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
request_next_keyframe (GstSplitMuxSink * splitmux)
|
||||||
|
{
|
||||||
|
GstEvent *ev;
|
||||||
|
|
||||||
|
if (splitmux->send_keyframe_requests == FALSE || splitmux->threshold_time == 0
|
||||||
|
|| splitmux->threshold_bytes != 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
ev = gst_video_event_new_upstream_force_key_unit (splitmux->fragment_id *
|
||||||
|
splitmux->threshold_time, TRUE, 0);
|
||||||
|
GST_DEBUG_OBJECT (splitmux, "Requesting next keyframe at %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (splitmux->fragment_id * splitmux->threshold_time));
|
||||||
|
return gst_pad_push_event (splitmux->reference_ctx->sinkpad, ev);
|
||||||
|
}
|
||||||
|
|
||||||
static GstPadProbeReturn
|
static GstPadProbeReturn
|
||||||
handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
|
handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
|
||||||
{
|
{
|
||||||
|
@ -715,6 +752,9 @@ handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
|
||||||
pad, GST_STIME_ARGS (ctx->out_running_time), buf_info->buf_size);
|
pad, GST_STIME_ARGS (ctx->out_running_time), buf_info->buf_size);
|
||||||
|
|
||||||
if (splitmux->opening_first_fragment) {
|
if (splitmux->opening_first_fragment) {
|
||||||
|
if (request_next_keyframe (splitmux) == FALSE)
|
||||||
|
GST_WARNING_OBJECT (splitmux,
|
||||||
|
"Could not request a keyframe. Files may not split at the exact location they should");
|
||||||
send_fragment_opened_closed_msg (splitmux, TRUE);
|
send_fragment_opened_closed_msg (splitmux, TRUE);
|
||||||
splitmux->opening_first_fragment = FALSE;
|
splitmux->opening_first_fragment = FALSE;
|
||||||
}
|
}
|
||||||
|
@ -726,6 +766,7 @@ handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
|
||||||
splitmux->muxed_out_time = buf_info->run_ts;
|
splitmux->muxed_out_time = buf_info->run_ts;
|
||||||
|
|
||||||
splitmux->muxed_out_bytes += buf_info->buf_size;
|
splitmux->muxed_out_bytes += buf_info->buf_size;
|
||||||
|
splitmux->last_frame_duration = buf_info->duration;
|
||||||
|
|
||||||
#ifndef GST_DISABLE_GST_DEBUG
|
#ifndef GST_DISABLE_GST_DEBUG
|
||||||
{
|
{
|
||||||
|
@ -807,6 +848,8 @@ start_next_fragment (GstSplitMuxSink * splitmux)
|
||||||
|
|
||||||
/* Store the overflow parameters as the basis for the next fragment */
|
/* Store the overflow parameters as the basis for the next fragment */
|
||||||
splitmux->mux_start_time = splitmux->muxed_out_time;
|
splitmux->mux_start_time = splitmux->muxed_out_time;
|
||||||
|
if (splitmux->last_frame_duration != GST_CLOCK_STIME_NONE)
|
||||||
|
splitmux->mux_start_time += splitmux->last_frame_duration;
|
||||||
splitmux->mux_start_bytes = splitmux->muxed_out_bytes;
|
splitmux->mux_start_bytes = splitmux->muxed_out_bytes;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (splitmux,
|
GST_DEBUG_OBJECT (splitmux,
|
||||||
|
@ -814,6 +857,9 @@ start_next_fragment (GstSplitMuxSink * splitmux)
|
||||||
GST_STIME_ARGS (splitmux->max_out_running_time));
|
GST_STIME_ARGS (splitmux->max_out_running_time));
|
||||||
|
|
||||||
send_fragment_opened_closed_msg (splitmux, TRUE);
|
send_fragment_opened_closed_msg (splitmux, TRUE);
|
||||||
|
if (request_next_keyframe (splitmux) == FALSE)
|
||||||
|
GST_WARNING_OBJECT (splitmux,
|
||||||
|
"Could not request a keyframe. Files may not split at the exact location they should");
|
||||||
|
|
||||||
GST_SPLITMUX_BROADCAST (splitmux);
|
GST_SPLITMUX_BROADCAST (splitmux);
|
||||||
}
|
}
|
||||||
|
@ -907,7 +953,6 @@ handle_gathered_gop (GstSplitMuxSink * splitmux)
|
||||||
queued_time > splitmux->threshold_time)))) {
|
queued_time > splitmux->threshold_time)))) {
|
||||||
|
|
||||||
splitmux->state = SPLITMUX_STATE_ENDING_FILE;
|
splitmux->state = SPLITMUX_STATE_ENDING_FILE;
|
||||||
|
|
||||||
GST_INFO_OBJECT (splitmux,
|
GST_INFO_OBJECT (splitmux,
|
||||||
"mq overflowed since last, draining out. max out TS is %"
|
"mq overflowed since last, draining out. max out TS is %"
|
||||||
GST_STIME_FORMAT, GST_STIME_ARGS (splitmux->max_out_running_time));
|
GST_STIME_FORMAT, GST_STIME_ARGS (splitmux->max_out_running_time));
|
||||||
|
@ -1160,6 +1205,7 @@ handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
|
||||||
|
|
||||||
buf_info->run_ts = ctx->in_running_time;
|
buf_info->run_ts = ctx->in_running_time;
|
||||||
buf_info->buf_size = gst_buffer_get_size (buf);
|
buf_info->buf_size = gst_buffer_get_size (buf);
|
||||||
|
buf_info->duration = GST_BUFFER_DURATION (buf);
|
||||||
|
|
||||||
/* Update total input byte counter for overflow detect */
|
/* Update total input byte counter for overflow detect */
|
||||||
ctx->in_bytes += buf_info->buf_size;
|
ctx->in_bytes += buf_info->buf_size;
|
||||||
|
@ -1659,7 +1705,7 @@ gst_splitmux_sink_change_state (GstElement * element, GstStateChange transition)
|
||||||
splitmux->state = SPLITMUX_STATE_COLLECTING_GOP_START;
|
splitmux->state = SPLITMUX_STATE_COLLECTING_GOP_START;
|
||||||
splitmux->max_in_running_time = GST_CLOCK_STIME_NONE;
|
splitmux->max_in_running_time = GST_CLOCK_STIME_NONE;
|
||||||
splitmux->muxed_out_time = splitmux->mux_start_time =
|
splitmux->muxed_out_time = splitmux->mux_start_time =
|
||||||
GST_CLOCK_STIME_NONE;
|
splitmux->last_frame_duration = GST_CLOCK_STIME_NONE;
|
||||||
splitmux->muxed_out_bytes = splitmux->mux_start_bytes = 0;
|
splitmux->muxed_out_bytes = splitmux->mux_start_bytes = 0;
|
||||||
splitmux->opening_first_fragment = TRUE;
|
splitmux->opening_first_fragment = TRUE;
|
||||||
GST_SPLITMUX_UNLOCK (splitmux);
|
GST_SPLITMUX_UNLOCK (splitmux);
|
||||||
|
|
|
@ -50,6 +50,7 @@ typedef struct _MqStreamBuf
|
||||||
gboolean keyframe;
|
gboolean keyframe;
|
||||||
GstClockTimeDiff run_ts;
|
GstClockTimeDiff run_ts;
|
||||||
gsize buf_size;
|
gsize buf_size;
|
||||||
|
GstClockTime duration;
|
||||||
} MqStreamBuf;
|
} MqStreamBuf;
|
||||||
|
|
||||||
typedef struct _MqStreamCtx
|
typedef struct _MqStreamCtx
|
||||||
|
@ -95,6 +96,7 @@ struct _GstSplitMuxSink {
|
||||||
GstClockTime threshold_time;
|
GstClockTime threshold_time;
|
||||||
guint64 threshold_bytes;
|
guint64 threshold_bytes;
|
||||||
guint max_files;
|
guint max_files;
|
||||||
|
gboolean send_keyframe_requests;
|
||||||
|
|
||||||
guint mq_max_buffers;
|
guint mq_max_buffers;
|
||||||
|
|
||||||
|
@ -123,6 +125,7 @@ struct _GstSplitMuxSink {
|
||||||
|
|
||||||
GstClockTimeDiff mux_start_time;
|
GstClockTimeDiff mux_start_time;
|
||||||
gsize mux_start_bytes;
|
gsize mux_start_bytes;
|
||||||
|
GstClockTime last_frame_duration;
|
||||||
|
|
||||||
gboolean opening_first_fragment;
|
gboolean opening_first_fragment;
|
||||||
gboolean switching_fragment;
|
gboolean switching_fragment;
|
||||||
|
|
Loading…
Reference in a new issue