diff --git a/subprojects/gst-plugins-good/gst/videofilter/gstvideoflip.c b/subprojects/gst-plugins-good/gst/videofilter/gstvideoflip.c index dc1861e771..8cd5d67697 100644 --- a/subprojects/gst-plugins-good/gst/videofilter/gstvideoflip.c +++ b/subprojects/gst-plugins-good/gst/videofilter/gstvideoflip.c @@ -1787,11 +1787,24 @@ gst_video_flip_sink_event (GstBaseTransform * trans, GstEvent * event) gst_event_parse_tag (event, &taglist); if (gst_video_orientation_from_tag (taglist, &method)) { - gst_video_flip_set_method (vf, method, TRUE); + if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_STREAM) { + vf->got_orientation_stream_tag = TRUE; + } + + if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL + && vf->got_orientation_stream_tag) { + GST_DEBUG_OBJECT (vf, + "ignoring global tags as we received stream specific ones: %" + GST_PTR_FORMAT, taglist); + } else { + gst_video_flip_set_method (vf, method, TRUE); + } } + break; case GST_EVENT_STREAM_START: GST_DEBUG_OBJECT (vf, "new stream, reset orientation from tags"); + vf->got_orientation_stream_tag = FALSE; gst_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_IDENTITY, TRUE); break; default: diff --git a/subprojects/gst-plugins-good/gst/videofilter/gstvideoflip.h b/subprojects/gst-plugins-good/gst/videofilter/gstvideoflip.h index 3320153181..d0c0fd2291 100644 --- a/subprojects/gst-plugins-good/gst/videofilter/gstvideoflip.h +++ b/subprojects/gst-plugins-good/gst/videofilter/gstvideoflip.h @@ -79,6 +79,8 @@ struct _GstVideoFlip { GstVideoOrientationMethod method; GstVideoOrientationMethod tag_method; + /* TRUE if we received orientation from tag event with GST_TAG_SCOPE_STREAM */ + gboolean got_orientation_stream_tag; GstVideoOrientationMethod proposed_method; gboolean change_configuring_method; GstVideoOrientationMethod configuring_method; diff --git a/subprojects/gst-plugins-good/tests/check/elements/videoflip.c b/subprojects/gst-plugins-good/tests/check/elements/videoflip.c index 7e1b857acf..992b59efa6 100644 --- a/subprojects/gst-plugins-good/tests/check/elements/videoflip.c +++ b/subprojects/gst-plugins-good/tests/check/elements/videoflip.c @@ -308,7 +308,8 @@ caps_update (GstHarness * flip, GstVideoInfo * in_info, gboolean rotate) } static void -send_orientation_tag (GstHarness * flip, const gchar * orientation) +send_orientation_tag (GstHarness * flip, const gchar * orientation, + GstTagScope scope) { GstTagList *tags; gchar *tmp; @@ -323,6 +324,7 @@ send_orientation_tag (GstHarness * flip, const gchar * orientation) tags = gst_tag_list_new_from_string (tmp); g_free (tmp); fail_unless (tags != NULL); + gst_tag_list_set_scope (tags, scope); gst_harness_push_event (flip, gst_event_new_tag (tags)); e = gst_harness_pull_event (flip); @@ -364,7 +366,7 @@ GST_START_TEST (test_orientation_tag) fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_SEGMENT); gst_event_unref (e); - send_orientation_tag (flip, "rotate-90"); + send_orientation_tag (flip, "rotate-90", GST_TAG_SCOPE_STREAM); // caps is updated as the frame is now rotated caps_update (flip, &in_info, TRUE); @@ -383,6 +385,81 @@ GST_START_TEST (test_orientation_tag) GST_END_TEST; +// send a buffer and ensure caps have not been updated +static void +caps_not_updated (GstHarness * flip, GstVideoInfo * in_info) +{ + GstBuffer *buf; + GstEvent *e; + + buf = create_test_video_buffer_rgba8 (in_info); + buf = gst_harness_push_and_pull (flip, buf); + fail_unless (buf != NULL); + gst_buffer_unref (buf); + + // caps is not updated + e = gst_harness_try_pull_event (flip); + fail_unless (e == NULL); +} + +// receive orientation updates from tags with the global and stream scopes +GST_START_TEST (test_orientation_tag_scopes) +{ + GstHarness *flip = gst_harness_new ("videoflip"); + GstVideoInfo in_info, out_info; + GstCaps *in_caps, *out_caps; + GstEvent *e; + + g_object_set (flip->element, "video-direction", 8 /* auto */ , NULL); + + // downstream accept any resolution + gst_harness_set_sink_caps_str (flip, "video/x-raw"); + + gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, 4, 9); + in_caps = gst_video_info_to_caps (&in_info); + gst_harness_set_src_caps (flip, in_caps); + + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_STREAM_START); + gst_event_unref (e); + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_CAPS); + gst_event_parse_caps (e, &out_caps); + fail_unless (gst_video_info_from_caps (&out_info, out_caps)); + fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&in_info), + GST_VIDEO_INFO_WIDTH (&out_info)); + fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&in_info), + GST_VIDEO_INFO_HEIGHT (&out_info)); + gst_event_unref (e); + + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_SEGMENT); + gst_event_unref (e); + + // send orientation global tag (global: 90, stream: /) + send_orientation_tag (flip, "rotate-90", GST_TAG_SCOPE_GLOBAL); + // caps is updated as the frame is now rotated + caps_update (flip, &in_info, TRUE); + + // send orientation stream tag, overriding the global one (global: 90, stream: 0) + send_orientation_tag (flip, "rotate-0", GST_TAG_SCOPE_STREAM); + // caps is updated as the frame is no longer rotated + caps_update (flip, &in_info, FALSE); + + // resend orientation global tag, which won't change the orientation as the stream tag takes precedence (global: 90, stream: 0) + send_orientation_tag (flip, "rotate-90", GST_TAG_SCOPE_GLOBAL); + caps_not_updated (flip, &in_info); + + // actually update the orientation with the stream tag (global: 90, stream: 90) + send_orientation_tag (flip, "rotate-90", GST_TAG_SCOPE_STREAM); + // caps is updated as the frame is now rotated + caps_update (flip, &in_info, TRUE); + + gst_harness_teardown (flip); +} + +GST_END_TEST; + static Suite * videoflip_suite (void) { @@ -396,6 +473,7 @@ videoflip_suite (void) test_change_method_twice_same_caps_different_method); tcase_add_test (tc_chain, test_stress_change_method); tcase_add_test (tc_chain, test_orientation_tag); + tcase_add_test (tc_chain, test_orientation_tag_scopes); return s; }