mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-28 12:41:05 +00:00
videoaggregator: properly handle interlace-mode restrictions
videoaggregator can't handle interlace-mode changes so it must always restrict itself to the first interlacing mode it receives. Tests included https://bugzilla.gnome.org/show_bug.cgi?id=754495
This commit is contained in:
parent
cd4e3e0f0a
commit
cf6a36721b
2 changed files with 217 additions and 9 deletions
|
@ -819,6 +819,26 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_videoaggregator_get_sinkpads_interlace_mode (GstVideoAggregator * vagg,
|
||||||
|
GstVideoAggregatorPad * skip_pad, GstVideoInterlaceMode * mode)
|
||||||
|
{
|
||||||
|
GList *walk;
|
||||||
|
|
||||||
|
for (walk = GST_ELEMENT (vagg)->sinkpads; walk; walk = g_list_next (walk)) {
|
||||||
|
GstVideoAggregatorPad *vaggpad = walk->data;
|
||||||
|
|
||||||
|
if (skip_pad && vaggpad == skip_pad)
|
||||||
|
continue;
|
||||||
|
if (vaggpad->info.finfo
|
||||||
|
&& GST_VIDEO_INFO_FORMAT (&vaggpad->info) != GST_VIDEO_FORMAT_UNKNOWN) {
|
||||||
|
*mode = GST_VIDEO_INFO_INTERLACE_MODE (&vaggpad->info);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_videoaggregator_pad_sink_setcaps (GstPad * pad, GstObject * parent,
|
gst_videoaggregator_pad_sink_setcaps (GstPad * pad, GstObject * parent,
|
||||||
GstCaps * caps)
|
GstCaps * caps)
|
||||||
|
@ -839,14 +859,28 @@ gst_videoaggregator_pad_sink_setcaps (GstPad * pad, GstObject * parent,
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_VIDEO_AGGREGATOR_LOCK (vagg);
|
GST_VIDEO_AGGREGATOR_LOCK (vagg);
|
||||||
if (GST_VIDEO_INFO_FORMAT (&vagg->info) != GST_VIDEO_FORMAT_UNKNOWN) {
|
{
|
||||||
if (GST_VIDEO_INFO_INTERLACE_MODE (&vagg->info) !=
|
GstVideoInterlaceMode pads_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
|
||||||
GST_VIDEO_INFO_INTERLACE_MODE (&info)) {
|
gboolean has_mode = FALSE;
|
||||||
GST_ERROR_OBJECT (pad,
|
|
||||||
"got input caps %" GST_PTR_FORMAT ", but " "current caps are %"
|
/* get the current output setting or fallback to other pads settings */
|
||||||
GST_PTR_FORMAT, caps, vagg->priv->current_caps);
|
if (GST_VIDEO_INFO_FORMAT (&vagg->info) != GST_VIDEO_FORMAT_UNKNOWN) {
|
||||||
GST_VIDEO_AGGREGATOR_UNLOCK (vagg);
|
pads_mode = GST_VIDEO_INFO_INTERLACE_MODE (&vagg->info);
|
||||||
return FALSE;
|
has_mode = TRUE;
|
||||||
|
} else {
|
||||||
|
has_mode =
|
||||||
|
gst_videoaggregator_get_sinkpads_interlace_mode (vagg, vaggpad,
|
||||||
|
&pads_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_mode) {
|
||||||
|
if (pads_mode != GST_VIDEO_INFO_INTERLACE_MODE (&info)) {
|
||||||
|
GST_ERROR_OBJECT (pad,
|
||||||
|
"got input caps %" GST_PTR_FORMAT ", but current caps are %"
|
||||||
|
GST_PTR_FORMAT, caps, vagg->priv->current_caps);
|
||||||
|
GST_VIDEO_AGGREGATOR_UNLOCK (vagg);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -918,6 +952,8 @@ gst_videoaggregator_pad_sink_getcaps (GstPad * pad, GstVideoAggregator * vagg,
|
||||||
GstAggregator *agg = GST_AGGREGATOR (vagg);
|
GstAggregator *agg = GST_AGGREGATOR (vagg);
|
||||||
GstPad *srcpad = GST_PAD (agg->srcpad);
|
GstPad *srcpad = GST_PAD (agg->srcpad);
|
||||||
gboolean has_alpha;
|
gboolean has_alpha;
|
||||||
|
GstVideoInterlaceMode interlace_mode;
|
||||||
|
gboolean has_interlace_mode;
|
||||||
|
|
||||||
template_caps = gst_pad_get_pad_template_caps (srcpad);
|
template_caps = gst_pad_get_pad_template_caps (srcpad);
|
||||||
|
|
||||||
|
@ -927,6 +963,10 @@ gst_videoaggregator_pad_sink_getcaps (GstPad * pad, GstVideoAggregator * vagg,
|
||||||
srccaps = gst_caps_make_writable (srccaps);
|
srccaps = gst_caps_make_writable (srccaps);
|
||||||
has_alpha = gst_videoaggregator_caps_has_alpha (srccaps);
|
has_alpha = gst_videoaggregator_caps_has_alpha (srccaps);
|
||||||
|
|
||||||
|
has_interlace_mode =
|
||||||
|
gst_videoaggregator_get_sinkpads_interlace_mode (vagg, NULL,
|
||||||
|
&interlace_mode);
|
||||||
|
|
||||||
n = gst_caps_get_size (srccaps);
|
n = gst_caps_get_size (srccaps);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
s = gst_caps_get_structure (srccaps, i);
|
s = gst_caps_get_structure (srccaps, i);
|
||||||
|
@ -936,6 +976,9 @@ gst_videoaggregator_pad_sink_getcaps (GstPad * pad, GstVideoAggregator * vagg,
|
||||||
|
|
||||||
gst_structure_remove_fields (s, "colorimetry", "chroma-site", "format",
|
gst_structure_remove_fields (s, "colorimetry", "chroma-site", "format",
|
||||||
"pixel-aspect-ratio", NULL);
|
"pixel-aspect-ratio", NULL);
|
||||||
|
if (has_interlace_mode)
|
||||||
|
gst_structure_set (s, "interlace-mode", G_TYPE_STRING,
|
||||||
|
gst_video_interlace_mode_to_string (interlace_mode), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
|
|
|
@ -355,6 +355,15 @@ GST_START_TEST (test_caps_query)
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
gst_caps_unref (restriction_caps);
|
gst_caps_unref (restriction_caps);
|
||||||
|
|
||||||
|
/* check that compositor proxies downstream interlaced-mode */
|
||||||
|
restriction_caps =
|
||||||
|
gst_caps_from_string ("video/x-raw, interlace-mode=(string)interleaved");
|
||||||
|
g_object_set (capsfilter, "caps", restriction_caps, NULL);
|
||||||
|
caps = gst_pad_query_caps (sinkpad, NULL);
|
||||||
|
fail_unless (gst_caps_is_subset (caps, restriction_caps));
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
gst_caps_unref (restriction_caps);
|
||||||
|
|
||||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
gst_element_release_request_pad (compositor, sinkpad);
|
gst_element_release_request_pad (compositor, sinkpad);
|
||||||
gst_object_unref (sinkpad);
|
gst_object_unref (sinkpad);
|
||||||
|
@ -365,6 +374,82 @@ GST_START_TEST (test_caps_query)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
|
||||||
|
GST_START_TEST (test_caps_query_interlaced)
|
||||||
|
{
|
||||||
|
GstElement *compositor, *sink;
|
||||||
|
GstElement *pipeline;
|
||||||
|
gboolean res;
|
||||||
|
GstStateChangeReturn state_res;
|
||||||
|
GstPad *sinkpad;
|
||||||
|
GstCaps *caps;
|
||||||
|
GstCaps *caps_mixed, *caps_progressive, *caps_interleaved;
|
||||||
|
GstEvent *caps_event;
|
||||||
|
|
||||||
|
caps_interleaved =
|
||||||
|
gst_caps_from_string ("video/x-raw, interlace-mode=interleaved");
|
||||||
|
caps_mixed = gst_caps_from_string ("video/x-raw, interlace-mode=mixed");
|
||||||
|
caps_progressive =
|
||||||
|
gst_caps_from_string ("video/x-raw, interlace-mode=progressive");
|
||||||
|
|
||||||
|
/* initial setup */
|
||||||
|
compositor = gst_element_factory_make ("compositor", "compositor");
|
||||||
|
sink = gst_element_factory_make ("fakesink", "sink");
|
||||||
|
pipeline = gst_pipeline_new ("test-pipeline");
|
||||||
|
|
||||||
|
gst_bin_add_many (GST_BIN (pipeline), compositor, sink, NULL);
|
||||||
|
res = gst_element_link (compositor, sink);
|
||||||
|
fail_unless (res == TRUE, NULL);
|
||||||
|
sinkpad = gst_element_get_request_pad (compositor, "sink_%u");
|
||||||
|
|
||||||
|
state_res = gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||||
|
fail_if (state_res == GST_STATE_CHANGE_FAILURE);
|
||||||
|
|
||||||
|
/* try an unrestricted caps query, should be compatible with all formats */
|
||||||
|
caps = gst_pad_query_caps (sinkpad, NULL);
|
||||||
|
fail_unless (gst_caps_can_intersect (caps, caps_interleaved));
|
||||||
|
fail_unless (gst_caps_can_intersect (caps, caps_progressive));
|
||||||
|
fail_unless (gst_caps_can_intersect (caps, caps_mixed));
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
/* now set caps on the pad, it should restrict the interlaced-mode for
|
||||||
|
* future caps */
|
||||||
|
caps = gst_caps_from_string ("video/x-raw, width=100, height=100, "
|
||||||
|
"format=RGB, framerate=1/1, interlace-mode=progressive");
|
||||||
|
caps_event = gst_event_new_caps (caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
fail_unless (gst_pad_send_event (sinkpad, caps_event));
|
||||||
|
|
||||||
|
/* now recheck the interlace-mode */
|
||||||
|
gst_object_unref (sinkpad);
|
||||||
|
sinkpad = gst_element_get_request_pad (compositor, "sink_%u");
|
||||||
|
caps = gst_pad_query_caps (sinkpad, NULL);
|
||||||
|
fail_if (gst_caps_can_intersect (caps, caps_interleaved));
|
||||||
|
fail_unless (gst_caps_can_intersect (caps, caps_progressive));
|
||||||
|
fail_if (gst_caps_can_intersect (caps, caps_mixed));
|
||||||
|
gst_object_unref (sinkpad);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
|
gst_object_unref (pipeline);
|
||||||
|
gst_caps_unref (caps_interleaved);
|
||||||
|
gst_caps_unref (caps_mixed);
|
||||||
|
gst_caps_unref (caps_progressive);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_interlaced_mode_to_caps (GstCaps * caps, const gchar * mode)
|
||||||
|
{
|
||||||
|
GstStructure *s;
|
||||||
|
|
||||||
|
for (gint i = 0; i < gst_caps_get_size (caps); i++) {
|
||||||
|
s = gst_caps_get_structure (caps, i);
|
||||||
|
gst_structure_set (s, "interlace-mode", G_TYPE_STRING, mode, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define MODE_ALL 1
|
#define MODE_ALL 1
|
||||||
#define MODE_NON_ALPHA 2
|
#define MODE_NON_ALPHA 2
|
||||||
|
|
||||||
|
@ -384,6 +469,11 @@ run_late_caps_query_test (GstCaps * input_caps, GstCaps * output_allowed_caps,
|
||||||
all_caps = _compositor_get_all_supported_caps ();
|
all_caps = _compositor_get_all_supported_caps ();
|
||||||
non_alpha_caps = _compositor_get_non_alpha_supported_caps ();
|
non_alpha_caps = _compositor_get_non_alpha_supported_caps ();
|
||||||
|
|
||||||
|
/* add progressive mode as it is what is used in the test, otherwise
|
||||||
|
* is_equal checks would fail */
|
||||||
|
add_interlaced_mode_to_caps (all_caps, "progressive");
|
||||||
|
add_interlaced_mode_to_caps (non_alpha_caps, "progressive");
|
||||||
|
|
||||||
compositor = gst_element_factory_make ("compositor", "compositor");
|
compositor = gst_element_factory_make ("compositor", "compositor");
|
||||||
capsfilter = gst_element_factory_make ("capsfilter", "out-cf");
|
capsfilter = gst_element_factory_make ("capsfilter", "out-cf");
|
||||||
sink = gst_element_factory_make ("fakesink", "sink");
|
sink = gst_element_factory_make ("fakesink", "sink");
|
||||||
|
@ -450,7 +540,6 @@ GST_START_TEST (test_late_caps_query)
|
||||||
|
|
||||||
rgb_caps = gst_caps_from_string ("video/x-raw, format=(string)RGB, "
|
rgb_caps = gst_caps_from_string ("video/x-raw, format=(string)RGB, "
|
||||||
"width=(int)100, height=(int)100, framerate=(fraction)1/1");
|
"width=(int)100, height=(int)100, framerate=(fraction)1/1");
|
||||||
|
|
||||||
non_alpha_caps = gst_caps_from_string ("video/x-raw, format=(string)RGB");
|
non_alpha_caps = gst_caps_from_string ("video/x-raw, format=(string)RGB");
|
||||||
|
|
||||||
/* check that a 2nd pad that is added late to compositor will be able to
|
/* check that a 2nd pad that is added late to compositor will be able to
|
||||||
|
@ -465,6 +554,80 @@ GST_START_TEST (test_late_caps_query)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
static void
|
||||||
|
run_late_caps_set_test (GstCaps * first_caps, GstCaps * expected_query_caps,
|
||||||
|
GstCaps * second_caps, gboolean accept_caps)
|
||||||
|
{
|
||||||
|
GstElement *capsfilter_1;
|
||||||
|
GstElement *compositor;
|
||||||
|
GstElement *pipeline;
|
||||||
|
GstStateChangeReturn state_res;
|
||||||
|
GstPad *sinkpad_2;
|
||||||
|
GstCaps *caps;
|
||||||
|
GstEvent *caps_event;
|
||||||
|
GstBus *bus;
|
||||||
|
GstMessage *msg;
|
||||||
|
|
||||||
|
pipeline =
|
||||||
|
gst_parse_launch ("videotestsrc num-buffers=10 ! capsfilter name=cf1 !"
|
||||||
|
" compositor name=c ! fakesink sync=true", NULL);
|
||||||
|
fail_unless (pipeline != NULL);
|
||||||
|
|
||||||
|
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||||||
|
|
||||||
|
compositor = gst_bin_get_by_name (GST_BIN (pipeline), "c");
|
||||||
|
capsfilter_1 = gst_bin_get_by_name (GST_BIN (pipeline), "cf1");
|
||||||
|
|
||||||
|
g_object_set (capsfilter_1, "caps", first_caps, NULL);
|
||||||
|
|
||||||
|
state_res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||||
|
fail_if (state_res == GST_STATE_CHANGE_FAILURE);
|
||||||
|
|
||||||
|
/* wait for pipeline to get to paused */
|
||||||
|
msg =
|
||||||
|
gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
|
||||||
|
GST_MESSAGE_ASYNC_DONE);
|
||||||
|
fail_unless (msg != NULL);
|
||||||
|
fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE);
|
||||||
|
gst_message_unref (msg);
|
||||||
|
|
||||||
|
/* try to set the second caps */
|
||||||
|
sinkpad_2 = gst_element_get_request_pad (compositor, "sink_%u");
|
||||||
|
caps = gst_pad_query_caps (sinkpad_2, NULL);
|
||||||
|
fail_unless (gst_caps_is_subset (expected_query_caps, caps));
|
||||||
|
caps_event = gst_event_new_caps (second_caps);
|
||||||
|
fail_unless (gst_pad_send_event (sinkpad_2, caps_event) == accept_caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
gst_object_unref (sinkpad_2);
|
||||||
|
|
||||||
|
gst_object_unref (bus);
|
||||||
|
gst_object_unref (compositor);
|
||||||
|
gst_object_unref (capsfilter_1);
|
||||||
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
|
gst_object_unref (pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_START_TEST (test_late_caps_different_interlaced)
|
||||||
|
{
|
||||||
|
GstCaps *non_interlaced_caps;
|
||||||
|
GstCaps *interlaced_caps;
|
||||||
|
|
||||||
|
non_interlaced_caps =
|
||||||
|
gst_caps_from_string ("video/x-raw, interlace-mode=progressive, "
|
||||||
|
"format=RGB, width=100, height=100, framerate=1/1");
|
||||||
|
interlaced_caps =
|
||||||
|
gst_caps_from_string ("video/x-raw, interlace-mode=interleaved, "
|
||||||
|
"format=RGB, width=100, height=100, framerate=1/1");
|
||||||
|
|
||||||
|
run_late_caps_set_test (non_interlaced_caps, non_interlaced_caps,
|
||||||
|
interlaced_caps, FALSE);
|
||||||
|
|
||||||
|
gst_caps_unref (non_interlaced_caps);
|
||||||
|
gst_caps_unref (interlaced_caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
static guint play_count = 0;
|
static guint play_count = 0;
|
||||||
static GstEvent *play_seek_event = NULL;
|
static GstEvent *play_seek_event = NULL;
|
||||||
|
|
||||||
|
@ -1915,7 +2078,9 @@ compositor_suite (void)
|
||||||
tcase_add_test (tc_chain, test_caps);
|
tcase_add_test (tc_chain, test_caps);
|
||||||
tcase_add_test (tc_chain, test_event);
|
tcase_add_test (tc_chain, test_event);
|
||||||
tcase_add_test (tc_chain, test_caps_query);
|
tcase_add_test (tc_chain, test_caps_query);
|
||||||
|
tcase_add_test (tc_chain, test_caps_query_interlaced);
|
||||||
tcase_add_test (tc_chain, test_late_caps_query);
|
tcase_add_test (tc_chain, test_late_caps_query);
|
||||||
|
tcase_add_test (tc_chain, test_late_caps_different_interlaced);
|
||||||
tcase_add_test (tc_chain, test_play_twice);
|
tcase_add_test (tc_chain, test_play_twice);
|
||||||
tcase_add_test (tc_chain, test_play_twice_then_add_and_play_again);
|
tcase_add_test (tc_chain, test_play_twice_then_add_and_play_again);
|
||||||
tcase_add_test (tc_chain, test_add_pad);
|
tcase_add_test (tc_chain, test_add_pad);
|
||||||
|
|
Loading…
Reference in a new issue