splitmuxsink: Implement split-after

The behaviour of split-now is to output the current GOP after
starting a new file.

The newly-added split-after signal will output the current GOP
to the old file if possible once a new GOP is opened.

https://bugzilla.gnome.org/show_bug.cgi?id=796982
This commit is contained in:
Mathieu Duponchelle 2018-08-16 21:42:37 +02:00
parent 916ad09009
commit 9605028a71
2 changed files with 41 additions and 7 deletions

View file

@ -84,6 +84,7 @@ GST_DEBUG_CATEGORY_STATIC (splitmux_debug);
#define GST_SPLITMUX_BROADCAST_OUTPUT(s) g_cond_broadcast (&(s)->output_cond) #define GST_SPLITMUX_BROADCAST_OUTPUT(s) g_cond_broadcast (&(s)->output_cond)
static void split_now (GstSplitMuxSink * splitmux); static void split_now (GstSplitMuxSink * splitmux);
static void split_after (GstSplitMuxSink * splitmux);
enum enum
{ {
@ -130,6 +131,7 @@ enum
SIGNAL_FORMAT_LOCATION, SIGNAL_FORMAT_LOCATION,
SIGNAL_FORMAT_LOCATION_FULL, SIGNAL_FORMAT_LOCATION_FULL,
SIGNAL_SPLIT_NOW, SIGNAL_SPLIT_NOW,
SIGNAL_SPLIT_AFTER,
SIGNAL_MUXER_ADDED, SIGNAL_MUXER_ADDED,
SIGNAL_SINK_ADDED, SIGNAL_SINK_ADDED,
SIGNAL_LAST SIGNAL_LAST
@ -407,7 +409,7 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass)
* @splitmux: the #GstSplitMuxSink * @splitmux: the #GstSplitMuxSink
* *
* When called by the user, this action signal splits the video file (and begins a new one) immediately. * When called by the user, this action signal splits the video file (and begins a new one) immediately.
* * The current GOP will be output to the new file.
* *
* Since: 1.14 * Since: 1.14
*/ */
@ -416,6 +418,20 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass)
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstSplitMuxSinkClass, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstSplitMuxSinkClass,
split_now), NULL, NULL, NULL, G_TYPE_NONE, 0); split_now), NULL, NULL, NULL, G_TYPE_NONE, 0);
/**
* GstSplitMuxSink::split-after:
* @splitmux: the #GstSplitMuxSink
*
* When called by the user, this action signal splits the video file (and begins a new one) immediately.
* The current GOP will be output to the old file.
*
* Since: 1.16
*/
signals[SIGNAL_SPLIT_AFTER] =
g_signal_new ("split-after", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstSplitMuxSinkClass,
split_after), NULL, NULL, NULL, G_TYPE_NONE, 0);
/** /**
* GstSplitMuxSink::muxer-added: * GstSplitMuxSink::muxer-added:
* @splitmux: the #GstSplitMuxSink * @splitmux: the #GstSplitMuxSink
@ -439,6 +455,7 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass)
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
klass->split_now = split_now; klass->split_now = split_now;
klass->split_after = split_after;
} }
static void static void
@ -468,7 +485,8 @@ gst_splitmux_sink_init (GstSplitMuxSink * splitmux)
splitmux->sink_properties = NULL; splitmux->sink_properties = NULL;
GST_OBJECT_FLAG_SET (splitmux, GST_ELEMENT_FLAG_SINK); GST_OBJECT_FLAG_SET (splitmux, GST_ELEMENT_FLAG_SINK);
splitmux->split_now = FALSE; splitmux->split_requested = FALSE;
splitmux->do_split_next_gop = FALSE;
} }
static void static void
@ -1830,7 +1848,7 @@ need_new_fragment (GstSplitMuxSink * splitmux,
return FALSE; return FALSE;
/* User told us to split now */ /* User told us to split now */
if (g_atomic_int_get (&(splitmux->split_now)) == TRUE) if (g_atomic_int_get (&(splitmux->do_split_next_gop)) == TRUE)
return TRUE; return TRUE;
if (thresh_bytes > 0 && queued_bytes > thresh_bytes) if (thresh_bytes > 0 && queued_bytes > thresh_bytes)
@ -1933,7 +1951,7 @@ handle_gathered_gop (GstSplitMuxSink * splitmux)
*sink_running_time = splitmux->reference_ctx->out_running_time; *sink_running_time = splitmux->reference_ctx->out_running_time;
g_object_set_qdata_full (G_OBJECT (splitmux->sink), g_object_set_qdata_full (G_OBJECT (splitmux->sink),
RUNNING_TIME, sink_running_time, g_free); RUNNING_TIME, sink_running_time, g_free);
g_atomic_int_set (&(splitmux->split_now), FALSE); g_atomic_int_set (&(splitmux->do_split_next_gop), FALSE);
/* Tell the output side to start a new fragment */ /* Tell the output side to start a new fragment */
GST_INFO_OBJECT (splitmux, GST_INFO_OBJECT (splitmux,
"This GOP (dur %" GST_STIME_FORMAT "This GOP (dur %" GST_STIME_FORMAT
@ -2063,6 +2081,13 @@ check_completed_gop (GstSplitMuxSink * splitmux, MqStreamCtx * ctx)
"Collected GOP is complete. Processing (ctx %p)", ctx); "Collected GOP is complete. Processing (ctx %p)", ctx);
/* All pads have a complete GOP, release it into the multiqueue */ /* All pads have a complete GOP, release it into the multiqueue */
handle_gathered_gop (splitmux); handle_gathered_gop (splitmux);
/* The user has requested a split, we can split now that the previous GOP
* has been collected to the correct location */
if (g_atomic_int_compare_and_exchange (&(splitmux->split_requested), TRUE,
FALSE)) {
g_atomic_int_set (&(splitmux->do_split_next_gop), TRUE);
}
} }
} }
@ -2955,7 +2980,8 @@ gst_splitmux_sink_change_state (GstElement * element, GstStateChange transition)
break; break;
} }
case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_PAUSED_TO_READY:
g_atomic_int_set (&(splitmux->split_now), FALSE); g_atomic_int_set (&(splitmux->split_requested), FALSE);
g_atomic_int_set (&(splitmux->do_split_next_gop), FALSE);
case GST_STATE_CHANGE_READY_TO_NULL: case GST_STATE_CHANGE_READY_TO_NULL:
GST_SPLITMUX_LOCK (splitmux); GST_SPLITMUX_LOCK (splitmux);
splitmux->output_state = SPLITMUX_OUTPUT_STATE_STOPPED; splitmux->output_state = SPLITMUX_OUTPUT_STATE_STOPPED;
@ -3038,5 +3064,11 @@ gst_splitmux_sink_ensure_max_files (GstSplitMuxSink * splitmux)
static void static void
split_now (GstSplitMuxSink * splitmux) split_now (GstSplitMuxSink * splitmux)
{ {
g_atomic_int_set (&(splitmux->split_now), TRUE); g_atomic_int_set (&(splitmux->do_split_next_gop), TRUE);
}
static void
split_after (GstSplitMuxSink * splitmux)
{
g_atomic_int_set (&(splitmux->split_requested), TRUE);
} }

View file

@ -171,7 +171,8 @@ struct _GstSplitMuxSink
gboolean use_robust_muxing; gboolean use_robust_muxing;
gboolean muxer_has_reserved_props; gboolean muxer_has_reserved_props;
gboolean split_now; gboolean split_requested;
gboolean do_split_next_gop;
/* Async finalize options */ /* Async finalize options */
gboolean async_finalize; gboolean async_finalize;
@ -187,6 +188,7 @@ struct _GstSplitMuxSinkClass
/* actions */ /* actions */
void (*split_now) (GstSplitMuxSink * splitmux); void (*split_now) (GstSplitMuxSink * splitmux);
void (*split_after) (GstSplitMuxSink * splitmux);
}; };
G_END_DECLS G_END_DECLS