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;
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;
}
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)
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");
}