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
#include <string.h>
#include <glib/gstdio.h>
#include <string.h>
#include <glib/gstdio.h>
+#include <gst/video/video.h>
#include "gstsplitmuxsink.h"
GST_DEBUG_CATEGORY_STATIC (splitmux_debug);
#include "gstsplitmuxsink.h"
GST_DEBUG_CATEGORY_STATIC (splitmux_debug);
PROP_LOCATION,
PROP_MAX_SIZE_TIME,
PROP_MAX_SIZE_BYTES,
PROP_LOCATION,
PROP_MAX_SIZE_TIME,
PROP_MAX_SIZE_BYTES,
+ PROP_SEND_KEYFRAME_REQUESTS,
PROP_MAX_FILES,
PROP_MUXER_OVERHEAD,
PROP_MUXER,
PROP_MAX_FILES,
PROP_MUXER_OVERHEAD,
PROP_MUXER,
#define DEFAULT_MAX_SIZE_BYTES 0
#define DEFAULT_MAX_FILES 0
#define DEFAULT_MUXER_OVERHEAD 0.02
#define DEFAULT_MAX_SIZE_BYTES 0
#define DEFAULT_MAX_FILES 0
#define DEFAULT_MUXER_OVERHEAD 0.02
+#define DEFAULT_SEND_KEYFRAME_REQUESTS FALSE
#define DEFAULT_MUXER "mp4mux"
#define DEFAULT_SINK "filesink"
#define DEFAULT_MUXER "mp4mux"
#define DEFAULT_SINK "filesink"
g_param_spec_uint64 ("max-size-bytes", "Max. size bytes",
"Max. amount of data per file (in bytes, 0=disable)", 0, G_MAXUINT64,
DEFAULT_MAX_SIZE_BYTES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_param_spec_uint64 ("max-size-bytes", "Max. size bytes",
"Max. amount of data per file (in bytes, 0=disable)", 0, G_MAXUINT64,
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_param_spec_uint ("max-files", "Max files",
"Maximum number of files to keep on disk. Once the maximum is reached,"
g_object_class_install_property (gobject_class, PROP_MAX_FILES,
g_param_spec_uint ("max-files", "Max files",
"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.",
- 0, G_MAXUINT, DEFAULT_MAX_FILES,
+ "old files start to be deleted to make room for new ones.", 0,
+ G_MAXUINT, DEFAULT_MAX_FILES,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
splitmux->threshold_time = DEFAULT_MAX_SIZE_TIME;
splitmux->threshold_bytes = DEFAULT_MAX_SIZE_BYTES;
splitmux->max_files = DEFAULT_MAX_FILES;
splitmux->threshold_time = DEFAULT_MAX_SIZE_TIME;
splitmux->threshold_bytes = DEFAULT_MAX_SIZE_BYTES;
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);
}
splitmux->threshold_time = g_value_get_uint64 (value);
GST_OBJECT_UNLOCK (splitmux);
break;
splitmux->threshold_time = g_value_get_uint64 (value);
GST_OBJECT_UNLOCK (splitmux);
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:
GST_OBJECT_LOCK (splitmux);
splitmux->max_files = g_value_get_uint (value);
case PROP_MAX_FILES:
GST_OBJECT_LOCK (splitmux);
splitmux->max_files = g_value_get_uint (value);
g_value_set_uint64 (value, splitmux->threshold_time);
GST_OBJECT_UNLOCK (splitmux);
break;
g_value_set_uint64 (value, splitmux->threshold_time);
GST_OBJECT_UNLOCK (splitmux);
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:
GST_OBJECT_LOCK (splitmux);
g_value_set_uint (value, splitmux->max_files);
case PROP_MAX_FILES:
GST_OBJECT_LOCK (splitmux);
g_value_set_uint (value, splitmux->max_files);
+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
handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
{
static GstPadProbeReturn
handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
{
pad, GST_STIME_ARGS (ctx->out_running_time), buf_info->buf_size);
if (splitmux->opening_first_fragment) {
pad, GST_STIME_ARGS (ctx->out_running_time), buf_info->buf_size);
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);
splitmux->opening_first_fragment = FALSE;
}
send_fragment_opened_closed_msg (splitmux, TRUE);
splitmux->opening_first_fragment = FALSE;
}
splitmux->muxed_out_time = buf_info->run_ts;
splitmux->muxed_out_bytes += buf_info->buf_size;
splitmux->muxed_out_time = buf_info->run_ts;
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
{
/* Store the overflow parameters as the basis for the next fragment */
splitmux->mux_start_time = splitmux->muxed_out_time;
/* Store the overflow parameters as the basis for the next fragment */
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;
GST_DEBUG_OBJECT (splitmux,
splitmux->mux_start_bytes = splitmux->muxed_out_bytes;
GST_DEBUG_OBJECT (splitmux,
GST_STIME_ARGS (splitmux->max_out_running_time));
send_fragment_opened_closed_msg (splitmux, TRUE);
GST_STIME_ARGS (splitmux->max_out_running_time));
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);
}
queued_time > splitmux->threshold_time)))) {
splitmux->state = SPLITMUX_STATE_ENDING_FILE;
queued_time > splitmux->threshold_time)))) {
splitmux->state = SPLITMUX_STATE_ENDING_FILE;
GST_INFO_OBJECT (splitmux,
"mq overflowed since last, draining out. max out TS is %"
GST_STIME_FORMAT, GST_STIME_ARGS (splitmux->max_out_running_time));
GST_INFO_OBJECT (splitmux,
"mq overflowed since last, draining out. max out TS is %"
GST_STIME_FORMAT, GST_STIME_ARGS (splitmux->max_out_running_time));
buf_info->run_ts = ctx->in_running_time;
buf_info->buf_size = gst_buffer_get_size (buf);
buf_info->run_ts = ctx->in_running_time;
buf_info->buf_size = gst_buffer_get_size (buf);
+ buf_info->duration = GST_BUFFER_DURATION (buf);
/* Update total input byte counter for overflow detect */
ctx->in_bytes += buf_info->buf_size;
/* Update total input byte counter for overflow detect */
ctx->in_bytes += buf_info->buf_size;
splitmux->state = SPLITMUX_STATE_COLLECTING_GOP_START;
splitmux->max_in_running_time = GST_CLOCK_STIME_NONE;
splitmux->muxed_out_time = splitmux->mux_start_time =
splitmux->state = SPLITMUX_STATE_COLLECTING_GOP_START;
splitmux->max_in_running_time = GST_CLOCK_STIME_NONE;
splitmux->muxed_out_time = splitmux->mux_start_time =
+ splitmux->last_frame_duration = GST_CLOCK_STIME_NONE;
splitmux->muxed_out_bytes = splitmux->mux_start_bytes = 0;
splitmux->opening_first_fragment = TRUE;
GST_SPLITMUX_UNLOCK (splitmux);
splitmux->muxed_out_bytes = splitmux->mux_start_bytes = 0;
splitmux->opening_first_fragment = TRUE;
GST_SPLITMUX_UNLOCK (splitmux);
gboolean keyframe;
GstClockTimeDiff run_ts;
gsize buf_size;
gboolean keyframe;
GstClockTimeDiff run_ts;
gsize buf_size;
} MqStreamBuf;
typedef struct _MqStreamCtx
} MqStreamBuf;
typedef struct _MqStreamCtx
GstClockTime threshold_time;
guint64 threshold_bytes;
guint max_files;
GstClockTime threshold_time;
guint64 threshold_bytes;
guint max_files;
+ gboolean send_keyframe_requests;
GstClockTimeDiff mux_start_time;
gsize mux_start_bytes;
GstClockTimeDiff mux_start_time;
gsize mux_start_bytes;
+ GstClockTime last_frame_duration;
gboolean opening_first_fragment;
gboolean switching_fragment;
gboolean opening_first_fragment;
gboolean switching_fragment;