mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
splitmuxsink: Fix occasional deadlock when ending file with subtitle
Deadlock occurs when splitting files if one stream received no buffer during the first GOP of the next file. That can happen in that scenario for example: 1) The first GOP of video is collected, it has a duration of 10s. max_in_running_time is set to 10s. 2) Other streams catchup and we receive the first subtitle buffer at ts=0 and has a duration of 1min. 3) We receive the 2nd subtitle buffer with a ts=1min. in_running_time is set to 1min. That buffer is blocked in handle_mq_input() because max_in_running_time is still 10s. 4) Since all in_running_time are now > 10s, max_out_running_time is now set to 10s. That first GOP gets recorded into the file. The muxer pop buffers out of the mq, when it tries to pop a 2nd subtitle buffer it blocks because the GstDataQueue is empty. 5) A 2nd GOP of video is collected and has a duration of 10s as well. max_in_running_time is now 20s. Since subtitle's in_running_time is already 1min, that GOP is already complete. 6) But let's say we overran the max file size, we thus set state to SPLITMUX_STATE_ENDING_FILE now. As soon as a buffer with ts > 10s (end of previous GOP) arrives in handle_mq_output(), EOS event is sent downstream instead. But since the subtitle queue is empty, that's never going to happen. Pipeline is now deadlocked. To fix this situation we have to: - Send a dummy event through the queue to wakeup output thread. - Update out_running_time to at least max_out_running_time so it sends EOS. - Respect time order, so we set out_running_tim=max_in_running_time because that's bigger than previous buffer and smaller than next. https://bugzilla.gnome.org/show_bug.cgi?id=763711
This commit is contained in:
parent
4c0e509328
commit
fb835c100a
1 changed files with 36 additions and 1 deletions
|
@ -627,6 +627,25 @@ handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
|
|||
GST_SPLITMUX_UNLOCK (splitmux);
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_CUSTOM_DOWNSTREAM:{
|
||||
const GstStructure *s;
|
||||
GstClockTime ts = 0;
|
||||
|
||||
s = gst_event_get_structure (event);
|
||||
if (!gst_structure_has_name (s, "splitmuxsink-unblock"))
|
||||
break;
|
||||
|
||||
gst_structure_get_uint64 (s, "timestamp", &ts);
|
||||
|
||||
GST_SPLITMUX_LOCK (splitmux);
|
||||
|
||||
if (splitmux->state == SPLITMUX_STATE_STOPPED)
|
||||
goto beach;
|
||||
ctx->out_running_time = ts;
|
||||
complete_or_wait_on_out (splitmux, ctx);
|
||||
GST_SPLITMUX_UNLOCK (splitmux);
|
||||
return GST_PAD_PROBE_DROP;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1125,7 +1144,23 @@ handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
|
|||
"Collected last packet of GOP. Checking other pads");
|
||||
check_completed_gop (splitmux, ctx);
|
||||
break;
|
||||
case SPLITMUX_STATE_ENDING_FILE:
|
||||
case SPLITMUX_STATE_ENDING_FILE:{
|
||||
GstEvent *event;
|
||||
|
||||
/* If somes streams received no buffer during the last GOP that overran,
|
||||
* because its next buffer has a timestamp bigger than
|
||||
* ctx->max_in_running_time, its queue is empty. In that case the only
|
||||
* way to wakeup the output thread is by injecting an event in the
|
||||
* queue. This usually happen with subtitle streams.
|
||||
* See https://bugzilla.gnome.org/show_bug.cgi?id=763711. */
|
||||
GST_LOG_OBJECT (pad, "Sending splitmuxsink-unblock event");
|
||||
event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM |
|
||||
GST_EVENT_TYPE_SERIALIZED,
|
||||
gst_structure_new ("splitmuxsink-unblock", "timestamp",
|
||||
G_TYPE_UINT64, splitmux->max_in_running_time, NULL));
|
||||
gst_pad_send_event (ctx->sinkpad, event);
|
||||
/* fallthrough */
|
||||
}
|
||||
case SPLITMUX_STATE_START_NEXT_FRAGMENT:
|
||||
/* A fragment is ending, wait until that's done before continuing */
|
||||
GST_DEBUG_OBJECT (pad, "Sleeping for fragment restart");
|
||||
|
|
Loading…
Reference in a new issue