splitmuxsink: Don't crash on EOS without buffer

Fix a case where upstream pushed EOS without buffers.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2174>
This commit is contained in:
Seungha Yang 2022-04-14 01:19:51 +09:00 committed by GStreamer Marge Bot
parent 6066e913ee
commit b233df3537
2 changed files with 81 additions and 2 deletions

View file

@ -2805,14 +2805,34 @@ handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
splitmux->input_state = SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT;
/* Wake up other input pads to collect this GOP */
GST_SPLITMUX_BROADCAST_INPUT (splitmux);
check_completed_gop (splitmux, ctx);
if (g_queue_is_empty (&splitmux->pending_input_gops)) {
GST_WARNING_OBJECT (splitmux,
"EOS with no buffers received on the reference pad");
/* - child muxer and sink might be still locked state
* (see gst_splitmux_reset_elements()) so should be unlocked
* for state change of splitmuxsink to be applied to child
* - would need to post async done message
* - location on sink element is still null then it will post
* error message on bus (muxer will produce something, header
* data for example)
*
* Calls start_next_fragment() here, the method will address
* everything the above mentioned one */
ret = start_next_fragment (splitmux, ctx);
if (ret != GST_FLOW_OK)
goto beach;
} else {
check_completed_gop (splitmux, ctx);
}
} else if (splitmux->input_state ==
SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT) {
/* If we are waiting for a GOP to be completed (ie, for aux
* pads to catch up), then this pad is complete, so check
* if the whole GOP is.
*/
check_completed_gop (splitmux, ctx);
if (!g_queue_is_empty (&splitmux->pending_input_gops))
check_completed_gop (splitmux, ctx);
}
GST_SPLITMUX_UNLOCK (splitmux);
break;
@ -3178,6 +3198,15 @@ handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
GST_LOG_OBJECT (pad,
"Collected last packet of GOP. Checking other pads");
if (g_queue_is_empty (&splitmux->pending_input_gops)) {
GST_WARNING_OBJECT (pad,
"Reference was closed without GOP, dropping");
GST_SPLITMUX_UNLOCK (splitmux);
GST_PAD_PROBE_INFO_FLOW_RETURN (info) = GST_FLOW_EOS;
return GST_PAD_PROBE_DROP;
}
check_completed_gop (splitmux, ctx);
break;
}

View file

@ -663,6 +663,55 @@ GST_START_TEST (test_splitmuxsink_muxer_pad_map)
GST_END_TEST;
static void
run_eos_pipeline (guint num_video_buf, guint num_audio_buf,
gboolean configure_audio)
{
GstMessage *msg;
GstElement *pipeline;
gchar *dest_pattern;
gchar *pipeline_str;
gchar *audio_branch = NULL;
dest_pattern = g_build_filename (tmpdir, "out%05d.mp4", NULL);
if (configure_audio) {
audio_branch = g_strdup_printf ("audiotestsrc num-buffers=%d ! "
"splitsink.audio_0", num_audio_buf);
}
pipeline_str = g_strdup_printf ("splitmuxsink name=splitsink location=%s "
"muxer-factory=qtmux videotestsrc num-buffers=%d ! jpegenc ! splitsink. "
"%s", dest_pattern, num_video_buf, audio_branch ? audio_branch : "");
pipeline = gst_parse_launch (pipeline_str, NULL);
g_free (dest_pattern);
g_free (audio_branch);
g_free (pipeline_str);
fail_if (pipeline == NULL);
msg = run_pipeline (pipeline);
if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR)
dump_error (msg);
fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
gst_message_unref (msg);
gst_object_unref (pipeline);
}
GST_START_TEST (test_splitmuxsink_eos_without_buffer)
{
/* below pipelines will create non-playable files but at least we should not
* crash */
run_eos_pipeline (0, 0, FALSE);
run_eos_pipeline (0, 0, TRUE);
run_eos_pipeline (1, 0, TRUE);
run_eos_pipeline (0, 1, TRUE);
}
GST_END_TEST;
static GstPadProbeReturn
count_upstrea_fku (GstPad * pad, GstPadProbeInfo * info,
guint * upstream_fku_count)
@ -863,6 +912,7 @@ splitmuxsink_suite (void)
tcase_add_checked_fixture (tc_chain_mp4_jpeg, tempdir_setup,
tempdir_cleanup);
tcase_add_test (tc_chain_mp4_jpeg, test_splitmuxsink_muxer_pad_map);
tcase_add_test (tc_chain_mp4_jpeg, test_splitmuxsink_eos_without_buffer);
} else {
GST_INFO ("Skipping tests, missing plugins: jpegenc or mp4mux");
}