splitmux: Fix file switch-on-caps-change.

Switching to a new fragment because the input caps have
changed didn't properly end the previous file. Use the normal
EOS sequence to ensure that happens. Add a test that it works.
This commit is contained in:
Jan Schmidt 2017-11-24 16:56:03 +11:00
parent e82c24e893
commit 3a813a0dcc
2 changed files with 108 additions and 11 deletions

View file

@ -944,22 +944,22 @@ handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
if (ok) if (ok)
break; break;
} else { } else {
break; break;
} }
/* This is in the case the muxer doesn't allow this change of caps */ /* This is in the case the muxer doesn't allow this change of caps */
GST_SPLITMUX_LOCK (splitmux); GST_SPLITMUX_LOCK (splitmux);
locked = TRUE; locked = TRUE;
ctx->caps_change = TRUE; ctx->caps_change = TRUE;
splitmux->ready_for_output = FALSE;
if (splitmux->output_state != SPLITMUX_OUTPUT_STATE_START_NEXT_FILE) { if (splitmux->output_state != SPLITMUX_OUTPUT_STATE_START_NEXT_FILE) {
GST_DEBUG_OBJECT (splitmux,
"New caps were not accepted. Switching output file");
if (ctx->out_eos == FALSE) { if (ctx->out_eos == FALSE) {
send_eos (splitmux, ctx); splitmux->output_state = SPLITMUX_OUTPUT_STATE_ENDING_FILE;
GST_SPLITMUX_BROADCAST_OUTPUT (splitmux);
} }
splitmux->output_state = SPLITMUX_OUTPUT_STATE_START_NEXT_FILE;
} }
/* Lets it fall through, if it fails again, then the muxer just can't /* Lets it fall through, if it fails again, then the muxer just can't
@ -983,9 +983,10 @@ handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx)
* because it would cause a new file to be created without the first * because it would cause a new file to be created without the first
* buffer being available. * buffer being available.
*/ */
if (ctx->caps_change && GST_EVENT_IS_STICKY (event)) if (ctx->caps_change && GST_EVENT_IS_STICKY (event)) {
return GST_PAD_PROBE_DROP; gst_event_unref (event);
else return GST_PAD_PROBE_HANDLED;
} else
return GST_PAD_PROBE_PASS; return GST_PAD_PROBE_PASS;
} }

View file

@ -220,10 +220,10 @@ test_playback (const gchar * in_pattern, GstClockTime exp_first_time,
gst_message_unref (msg); gst_message_unref (msg);
/* Check we saw the entire range of values */ /* Check we saw the entire range of values */
fail_unless (first_ts == 0, fail_unless (first_ts == exp_first_time,
"Expected start of playback range 0, got %" GST_TIME_FORMAT, "Expected start of playback range 0, got %" GST_TIME_FORMAT,
GST_TIME_ARGS (first_ts)); GST_TIME_ARGS (first_ts));
fail_unless (last_ts == (3 * GST_SECOND), fail_unless (last_ts == exp_last_time,
"Expected end of playback range 3s, got %" GST_TIME_FORMAT, "Expected end of playback range 3s, got %" GST_TIME_FORMAT,
GST_TIME_ARGS (last_ts)); GST_TIME_ARGS (last_ts));
@ -572,6 +572,87 @@ GST_START_TEST (test_splitmuxsrc_sparse_streams)
GST_END_TEST; GST_END_TEST;
struct CapsChangeData
{
guint count;
GstElement *cf;
};
static GstPadProbeReturn
switch_caps (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
struct CapsChangeData *data = (struct CapsChangeData *) (user_data);
if (data->count == 4) {
GST_INFO ("Saw 5 buffers to the encoder. Switching caps");
gst_util_set_object_arg (G_OBJECT (data->cf), "caps",
"video/x-raw,width=160,height=128,framerate=10/1");
}
data->count++;
return GST_PAD_PROBE_OK;
}
GST_START_TEST (test_splitmuxsrc_caps_change)
{
GstMessage *msg;
GstElement *pipeline;
GstElement *sink;
GstElement *cf;
GstPad *sinkpad;
gchar *dest_pattern;
guint count;
gchar *in_pattern;
struct CapsChangeData data;
/* This test creates a new file only by changing the caps, which
* qtmux will reject (for now - if qtmux starts supporting caps
* changes, this test will break and need fixing/disabling */
pipeline =
gst_parse_launch
("videotestsrc num-buffers=10 !"
" capsfilter name=c caps=video/x-raw,width=80,height=64,framerate=10/1 !"
" jpegenc ! splitmuxsink name=splitsink muxer=qtmux", 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.mp4", NULL);
g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL);
g_free (dest_pattern);
g_object_unref (sink);
cf = gst_bin_get_by_name (GST_BIN (pipeline), "c");
sinkpad = gst_element_get_static_pad (cf, "sink");
data.cf = cf;
data.count = 0;
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER,
switch_caps, &data, NULL);
gst_object_unref (sinkpad);
gst_object_unref (cf);
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 == 2, "Expected 2 output files, got %d", count);
in_pattern = g_build_filename (tmpdir, "out*.mp4", NULL);
test_playback (in_pattern, 0, GST_SECOND);
g_free (in_pattern);
}
GST_END_TEST;
/* For verifying bug https://bugzilla.gnome.org/show_bug.cgi?id=762893 */ /* For verifying bug https://bugzilla.gnome.org/show_bug.cgi?id=762893 */
GST_START_TEST (test_splitmuxsink_reuse_simple) GST_START_TEST (test_splitmuxsink_reuse_simple)
{ {
@ -606,7 +687,9 @@ splitmux_suite (void)
TCase *tc_chain = tcase_create ("general"); TCase *tc_chain = tcase_create ("general");
TCase *tc_chain_basic = tcase_create ("basic"); TCase *tc_chain_basic = tcase_create ("basic");
TCase *tc_chain_complex = tcase_create ("complex"); TCase *tc_chain_complex = tcase_create ("complex");
gboolean have_theora, have_ogg, have_vorbis, have_matroska; TCase *tc_chain_caps_change = tcase_create ("caps_change");
gboolean have_theora, have_ogg, have_vorbis, have_matroska, have_qtmux,
have_jpeg;
/* we assume that if encoder/muxer are there, decoder/demuxer will be a well */ /* we assume that if encoder/muxer are there, decoder/demuxer will be a well */
have_theora = gst_registry_check_feature_version (gst_registry_get (), have_theora = gst_registry_check_feature_version (gst_registry_get (),
@ -617,10 +700,15 @@ splitmux_suite (void)
"vorbisenc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); "vorbisenc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
have_matroska = gst_registry_check_feature_version (gst_registry_get (), have_matroska = gst_registry_check_feature_version (gst_registry_get (),
"matroskamux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); "matroskamux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0);
have_qtmux = gst_registry_check_feature_version (gst_registry_get (),
"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);
suite_add_tcase (s, tc_chain); suite_add_tcase (s, tc_chain);
suite_add_tcase (s, tc_chain_basic); suite_add_tcase (s, tc_chain_basic);
suite_add_tcase (s, tc_chain_complex); suite_add_tcase (s, tc_chain_complex);
suite_add_tcase (s, tc_chain_caps_change);
tcase_add_test (tc_chain_basic, test_splitmuxsink_reuse_simple); tcase_add_test (tc_chain_basic, test_splitmuxsink_reuse_simple);
@ -643,6 +731,14 @@ splitmux_suite (void)
GST_INFO ("Skipping tests, missing plugins: theora and/or ogg"); GST_INFO ("Skipping tests, missing plugins: theora and/or ogg");
} }
if (have_qtmux && have_jpeg) {
tcase_add_checked_fixture (tc_chain_caps_change, tempdir_setup,
tempdir_cleanup);
tcase_add_test (tc_chain_caps_change, test_splitmuxsrc_caps_change);
} else {
GST_INFO ("Skipping tests, missing plugins: jpegenc or mp4mux");
}
return s; return s;
} }