summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gst/multifile/gstsplitmuxsink.c26
-rw-r--r--gst/multifile/gstsplitmuxsink.h2
-rw-r--r--tests/check/elements/splitmux.c107
3 files changed, 104 insertions, 31 deletions
diff --git a/gst/multifile/gstsplitmuxsink.c b/gst/multifile/gstsplitmuxsink.c
index ab9fa00eb..1db6a45f9 100644
--- a/gst/multifile/gstsplitmuxsink.c
+++ b/gst/multifile/gstsplitmuxsink.c
@@ -1,5 +1,5 @@
/* GStreamer Muxer bin that splits output stream by size/time
- * Copyright (C) <2014> Jan Schmidt <jan@centricular.com>
+ * Copyright (C) <2014-2019> Jan Schmidt <jan@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -146,6 +146,11 @@ GST_STATIC_PAD_TEMPLATE ("video",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
+static GstStaticPadTemplate video_aux_sink_template =
+GST_STATIC_PAD_TEMPLATE ("video_aux_%u",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate audio_sink_template =
GST_STATIC_PAD_TEMPLATE ("audio_%u",
GST_PAD_SINK,
@@ -265,6 +270,8 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass)
gst_element_class_add_static_pad_template (gstelement_class,
&video_sink_template);
gst_element_class_add_static_pad_template (gstelement_class,
+ &video_aux_sink_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
&audio_sink_template);
gst_element_class_add_static_pad_template (gstelement_class,
&subtitle_sink_template);
@@ -2580,7 +2587,7 @@ gst_splitmux_sink_request_new_pad (GstElement * element,
GstElement *q;
GstPad *q_sink = NULL, *q_src = NULL;
gchar *gname, *qname;
- gboolean is_video = FALSE;
+ gboolean is_primary_video = FALSE;
MqStreamCtx *ctx;
GST_DEBUG_OBJECT (element, "templ:%s, name:%s", templ->name_template, name);
@@ -2591,8 +2598,10 @@ gst_splitmux_sink_request_new_pad (GstElement * element,
g_signal_emit (splitmux, signals[SIGNAL_MUXER_ADDED], 0, splitmux->muxer);
if (templ->name_template) {
- if (g_str_equal (templ->name_template, "video")) {
- if (splitmux->have_video)
+ if (g_str_equal (templ->name_template, "video") ||
+ g_str_has_prefix (templ->name_template, "video_aux_")) {
+ is_primary_video = g_str_equal (templ->name_template, "video");
+ if (is_primary_video && splitmux->have_video)
goto already_have_video;
/* FIXME: Look for a pad template with matching caps, rather than by name */
@@ -2610,7 +2619,6 @@ gst_splitmux_sink_request_new_pad (GstElement * element,
gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS
(splitmux->muxer), "video");
}
- is_video = TRUE;
name = NULL;
} else {
GST_DEBUG_OBJECT (element, "searching for pad-template with name '%s'",
@@ -2620,7 +2628,7 @@ gst_splitmux_sink_request_new_pad (GstElement * element,
(splitmux->muxer), templ->name_template);
/* Fallback to find sink pad templates named 'audio' (flvmux) */
- if (!mux_template) {
+ if (!mux_template && g_str_has_prefix (templ->name_template, "audio_")) {
GST_DEBUG_OBJECT (element,
"searching for pad-template with name 'audio'");
mux_template =
@@ -2677,7 +2685,7 @@ gst_splitmux_sink_request_new_pad (GstElement * element,
goto fail;
}
- if (is_video)
+ if (is_primary_video)
gname = g_strdup ("video");
else if (name == NULL)
gname = gst_pad_get_name (res);
@@ -2720,7 +2728,7 @@ gst_splitmux_sink_request_new_pad (GstElement * element,
gst_pad_add_probe (q_src,
GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM | GST_PAD_PROBE_TYPE_EVENT_FLUSH,
(GstPadProbeCallback) handle_mq_output, ctx, NULL);
- if (is_video && splitmux->reference_ctx != NULL) {
+ if (is_primary_video && splitmux->reference_ctx != NULL) {
splitmux->reference_ctx->is_reference = FALSE;
splitmux->reference_ctx = NULL;
}
@@ -2745,7 +2753,7 @@ gst_splitmux_sink_request_new_pad (GstElement * element,
g_free (gname);
- if (is_video)
+ if (is_primary_video)
splitmux->have_video = TRUE;
gst_pad_set_active (res, TRUE);
diff --git a/gst/multifile/gstsplitmuxsink.h b/gst/multifile/gstsplitmuxsink.h
index a5a148e94..8e78bf1a5 100644
--- a/gst/multifile/gstsplitmuxsink.h
+++ b/gst/multifile/gstsplitmuxsink.h
@@ -1,5 +1,5 @@
/* GStreamer split muxer bin
- * Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
+ * Copyright (C) 2014-2019 Jan Schmidt <jan@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
diff --git a/tests/check/elements/splitmux.c b/tests/check/elements/splitmux.c
index 25925e97f..9dfd14e26 100644
--- a/tests/check/elements/splitmux.c
+++ b/tests/check/elements/splitmux.c
@@ -188,7 +188,7 @@ receive_handoff (GstElement * object G_GNUC_UNUSED, GstBuffer * buf,
static void
test_playback (const gchar * in_pattern, GstClockTime exp_first_time,
- GstClockTime exp_last_time)
+ GstClockTime exp_last_time, gboolean test_reverse)
{
GstMessage *msg;
GstElement *pipeline;
@@ -229,20 +229,22 @@ test_playback (const gchar * in_pattern, GstClockTime exp_first_time,
"Expected end of playback range 3s, got %" GST_TIME_FORMAT,
GST_TIME_ARGS (last_ts));
- /* Test backwards */
- seek_pipeline (pipeline, -1.0, 0, -1);
- msg = run_pipeline (pipeline);
- fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
- gst_message_unref (msg);
- /* Check we saw the entire range of values */
- fail_unless (first_ts == exp_first_time,
- "Expected start of playback range %" GST_TIME_FORMAT
- ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (exp_first_time),
- GST_TIME_ARGS (first_ts));
- fail_unless (last_ts == exp_last_time,
- "Expected end of playback range %" GST_TIME_FORMAT
- ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (exp_last_time),
- GST_TIME_ARGS (last_ts));
+ if (test_reverse) {
+ /* Test backwards */
+ seek_pipeline (pipeline, -1.0, 0, -1);
+ msg = run_pipeline (pipeline);
+ fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+ gst_message_unref (msg);
+ /* Check we saw the entire range of values */
+ fail_unless (first_ts == exp_first_time,
+ "Expected start of playback range %" GST_TIME_FORMAT
+ ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (exp_first_time),
+ GST_TIME_ARGS (first_ts));
+ fail_unless (last_ts == exp_last_time,
+ "Expected end of playback range %" GST_TIME_FORMAT
+ ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (exp_last_time),
+ GST_TIME_ARGS (last_ts));
+ }
gst_object_unref (pipeline);
}
@@ -251,7 +253,7 @@ GST_START_TEST (test_splitmuxsrc)
{
gchar *in_pattern =
g_build_filename (GST_TEST_FILES_PATH, "splitvideo*.ogg", NULL);
- test_playback (in_pattern, 0, 3 * GST_SECOND);
+ test_playback (in_pattern, 0, 3 * GST_SECOND, TRUE);
g_free (in_pattern);
}
@@ -367,7 +369,62 @@ GST_START_TEST (test_splitmuxsink)
fail_unless (count == 3, "Expected 3 output files, got %d", count);
in_pattern = g_build_filename (tmpdir, "out*.ogg", NULL);
- test_playback (in_pattern, 0, 3 * GST_SECOND);
+ test_playback (in_pattern, 0, 3 * GST_SECOND, TRUE);
+ g_free (in_pattern);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_splitmuxsink_multivid)
+{
+ GstMessage *msg;
+ GstElement *pipeline;
+ GstElement *sink;
+ gchar *dest_pattern;
+ guint count;
+ gchar *in_pattern;
+
+ /* This pipeline should start a new file every GOP, ie 1 second,
+ * driven by the primary video stream and with 2 auxilliary video streams */
+ pipeline =
+ gst_parse_launch
+ ("splitmuxsink name=splitsink "
+ " max-size-time=1000000 max-size-bytes=1000000 muxer=qtmux "
+ "videotestsrc num-buffers=15 ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !"
+ " queue ! vp8enc keyframe-max-dist=5 ! splitsink.video "
+ "videotestsrc num-buffers=15 pattern=snow ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !"
+ " queue ! vp8enc keyframe-max-dist=6 ! splitsink.video_aux_0 "
+ "videotestsrc num-buffers=15 pattern=ball ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !"
+ " queue ! vp8enc keyframe-max-dist=8 ! splitsink.video_aux_1 ", NULL);
+ fail_if (pipeline == NULL);
+ sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink");
+ fail_if (sink == NULL);
+ g_signal_connect (sink, "format-location-full",
+ (GCallback) check_format_location, NULL);
+ dest_pattern = g_build_filename (tmpdir, "out%05d.m4v", NULL);
+ g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL);
+ g_free (dest_pattern);
+ g_object_unref (sink);
+
+ 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);
+
+ count = count_files (tmpdir);
+ fail_unless (count == 3, "Expected 3 output files, got %d", count);
+
+ in_pattern = g_build_filename (tmpdir, "out*.m4v", NULL);
+ /* FIXME: Reverse playback works poorly with multiple video streams
+ * in qtdemux (at least, maybe other demuxers) at the time this was
+ * written, and causes test failures like buffers being output
+ * multiple times by qtdemux as it loops through GOPs. Disable that
+ * for now */
+ test_playback (in_pattern, 0, 3 * GST_SECOND, FALSE);
g_free (in_pattern);
}
@@ -431,7 +488,7 @@ GST_START_TEST (test_splitmuxsink_async)
fail_unless (count == 3, "Expected 3 output files, got %d", count);
in_pattern = g_build_filename (tmpdir, "matroska*.mkv", NULL);
- test_playback (in_pattern, 0, 3 * GST_SECOND);
+ test_playback (in_pattern, 0, 3 * GST_SECOND, TRUE);
g_free (in_pattern);
}
@@ -713,7 +770,7 @@ GST_START_TEST (test_splitmuxsrc_caps_change)
fail_unless (count == 2, "Expected 2 output files, got %d", count);
in_pattern = g_build_filename (tmpdir, "out*.mp4", NULL);
- test_playback (in_pattern, 0, GST_SECOND);
+ test_playback (in_pattern, 0, GST_SECOND, TRUE);
g_free (in_pattern);
}
@@ -760,7 +817,7 @@ GST_START_TEST (test_splitmuxsrc_robust_mux)
* reserved duration property. All we care about is that the muxing didn't fail because space ran out */
in_pattern = g_build_filename (tmpdir, "out*.mp4", NULL);
- test_playback (in_pattern, 0, GST_SECOND);
+ test_playback (in_pattern, 0, GST_SECOND, TRUE);
g_free (in_pattern);
}
@@ -802,7 +859,7 @@ splitmux_suite (void)
TCase *tc_chain_complex = tcase_create ("complex");
TCase *tc_chain_mp4_jpeg = tcase_create ("caps_change");
gboolean have_theora, have_ogg, have_vorbis, have_matroska, have_qtmux,
- have_jpeg;
+ have_jpeg, have_vp8;
/* we assume that if encoder/muxer are there, decoder/demuxer will be a well */
have_theora = gst_registry_check_feature_version (gst_registry_get (),
@@ -817,6 +874,8 @@ splitmux_suite (void)
"qtmux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
have_jpeg = gst_registry_check_feature_version (gst_registry_get (),
"jpegenc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
+ have_vp8 = gst_registry_check_feature_version (gst_registry_get (),
+ "vp8enc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
suite_add_tcase (s, tc_chain);
suite_add_tcase (s, tc_chain_basic);
@@ -854,6 +913,12 @@ splitmux_suite (void)
} else {
GST_INFO ("Skipping tests, missing plugins: jpegenc or mp4mux");
}
+
+ if (have_qtmux && have_vp8) {
+ tcase_add_test (tc_chain, test_splitmuxsink_multivid);
+ } else {
+ GST_INFO ("Skipping tests, missing plugins: vp8enc or mp4mux");
+ }
return s;
}