summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Adam <jakub.adam@collabora.com>2021-05-25 21:16:48 +0200
committerNicolas Dufresne <nicolas@ndufresne.ca>2021-08-17 14:54:06 +0000
commitb4a00f78bc438b9a2b0121cc47ae7b6817ea3060 (patch)
treeba94c23d9e219071f1d425df490aede9c3147bf2
parentb3c7b9be49f713c348b5b0b70d55fbb256ecd68e (diff)
downloadgstreamer-plugins-base-b4a00f78bc438b9a2b0121cc47ae7b6817ea3060.tar.gz
videoencoder: pass upstream HDR information through codec state
Don't copy HDR metadata from sink pad, because its caps may not have been set yet if GstVideoEncoder::negotiate is called from GstVideoEncoder::set_format, as e.g. vpx encoder does. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/1175>
-rw-r--r--gst-libs/gst/video/gstvideoencoder.c59
-rw-r--r--tests/check/libs/videoencoder.c72
2 files changed, 107 insertions, 24 deletions
diff --git a/gst-libs/gst/video/gstvideoencoder.c b/gst-libs/gst/video/gstvideoencoder.c
index 0d85ba232..ae859a139 100644
--- a/gst-libs/gst/video/gstvideoencoder.c
+++ b/gst-libs/gst/video/gstvideoencoder.c
@@ -674,6 +674,15 @@ _new_output_state (GstCaps * caps, GstVideoCodecState * reference)
GST_VIDEO_INFO_MULTIVIEW_MODE (tgt) = GST_VIDEO_INFO_MULTIVIEW_MODE (ref);
GST_VIDEO_INFO_MULTIVIEW_FLAGS (tgt) = GST_VIDEO_INFO_MULTIVIEW_FLAGS (ref);
+
+ if (reference->mastering_display_info) {
+ state->mastering_display_info = g_slice_dup (GstVideoMasteringDisplayInfo,
+ reference->mastering_display_info);
+ }
+ if (reference->content_light_level) {
+ state->content_light_level = g_slice_dup (GstVideoContentLightLevel,
+ reference->content_light_level);
+ }
}
return state;
@@ -683,6 +692,8 @@ static GstVideoCodecState *
_new_input_state (GstCaps * caps)
{
GstVideoCodecState *state;
+ GstStructure *c_struct;
+ const gchar *s;
state = g_slice_new0 (GstVideoCodecState);
state->ref_count = 1;
@@ -691,6 +702,18 @@ _new_input_state (GstCaps * caps)
goto parse_fail;
state->caps = gst_caps_ref (caps);
+ c_struct = gst_caps_get_structure (caps, 0);
+
+ if ((s = gst_structure_get_string (c_struct, "mastering-display-info"))) {
+ state->mastering_display_info = g_slice_new (GstVideoMasteringDisplayInfo);
+ gst_video_mastering_display_info_from_string (state->mastering_display_info,
+ s);
+ }
+ if ((s = gst_structure_get_string (c_struct, "content-light-level"))) {
+ state->content_light_level = g_slice_new (GstVideoContentLightLevel);
+ gst_video_content_light_level_from_string (state->content_light_level, s);
+ }
+
return state;
parse_fail:
@@ -1815,7 +1838,7 @@ gst_video_encoder_negotiate_default (GstVideoEncoder * encoder)
g_return_val_if_fail (state->caps != NULL, FALSE);
if (encoder->priv->output_state_changed) {
- GstCaps *incaps;
+ GstStructure *out_struct;
state->caps = gst_caps_make_writable (state->caps);
@@ -1874,30 +1897,20 @@ gst_video_encoder_negotiate_default (GstVideoEncoder * encoder)
GST_VIDEO_INFO_MULTIVIEW_FLAGS (info), GST_FLAG_SET_MASK_EXACT, NULL);
}
- incaps = gst_pad_get_current_caps (GST_VIDEO_ENCODER_SINK_PAD (encoder));
- if (incaps) {
- GstStructure *in_struct;
- GstStructure *out_struct;
- const gchar *s;
-
- in_struct = gst_caps_get_structure (incaps, 0);
- out_struct = gst_caps_get_structure (state->caps, 0);
-
- /* forward upstream mastering display info and content light level
- * if subclass didn't set */
- if ((s = gst_structure_get_string (in_struct, "mastering-display-info"))
- && !gst_structure_has_field (out_struct, "mastering-display-info")) {
- gst_caps_set_simple (state->caps, "mastering-display-info",
- G_TYPE_STRING, s, NULL);
- }
+ out_struct = gst_caps_get_structure (state->caps, 0);
- if ((s = gst_structure_get_string (in_struct, "content-light-level")) &&
- !gst_structure_has_field (out_struct, "content-light-level")) {
- gst_caps_set_simple (state->caps,
- "content-light-level", G_TYPE_STRING, s, NULL);
- }
+ /* forward upstream mastering display info and content light level
+ * if subclass didn't set */
+ if (state->mastering_display_info &&
+ !gst_structure_has_field (out_struct, "mastering-display-info")) {
+ gst_video_mastering_display_info_add_to_caps
+ (state->mastering_display_info, state->caps);
+ }
- gst_caps_unref (incaps);
+ if (state->content_light_level &&
+ !gst_structure_has_field (out_struct, "content-light-level")) {
+ gst_video_content_light_level_add_to_caps (state->content_light_level,
+ state->caps);
}
encoder->priv->output_state_changed = FALSE;
diff --git a/tests/check/libs/videoencoder.c b/tests/check/libs/videoencoder.c
index a481fc24b..ee13b0fb3 100644
--- a/tests/check/libs/videoencoder.c
+++ b/tests/check/libs/videoencoder.c
@@ -54,6 +54,7 @@ struct _GstVideoEncoderTester
gboolean send_headers;
gboolean key_frame_sent;
gboolean enable_step_by_step;
+ gboolean negotiate_in_set_format;
GstVideoCodecFrame *last_frame;
};
@@ -83,12 +84,19 @@ static gboolean
gst_video_encoder_tester_set_format (GstVideoEncoder * enc,
GstVideoCodecState * state)
{
+ GstVideoEncoderTester *enc_tester = GST_VIDEO_ENCODER_TESTER (enc);
+
GstVideoCodecState *res = gst_video_encoder_set_output_state (enc,
gst_caps_new_simple ("video/x-test-custom", "width", G_TYPE_INT,
480, "height", G_TYPE_INT, 360, NULL),
- NULL);
+ state);
gst_video_codec_state_unref (res);
+
+ if (enc_tester->negotiate_in_set_format) {
+ gst_video_encoder_negotiate (enc);
+ }
+
return TRUE;
}
@@ -1194,6 +1202,67 @@ GST_START_TEST (videoencoder_force_keyunit_min_interval)
GST_END_TEST;
+GST_START_TEST (videoencoder_hdr_metadata)
+{
+ const gchar *mdi_str =
+ "35399:14599:8500:39850:6550:2300:15634:16450:10000000:1";
+ const gchar *cll_str = "1000:50";
+ gint i;
+
+ /* Check that HDR metadata get passed to src pad no matter if negotiate gets
+ * called from gst_video_encoder_finish_frame() or GstVideoEncoder::set_format
+ */
+ for (i = 1; i >= 0; --i) {
+ GstVideoMasteringDisplayInfo mdi;
+ GstVideoContentLightLevel cll;
+ GstSegment segment;
+ GstCaps *caps;
+ GstStructure *s;
+ const gchar *str;
+
+ setup_videoencodertester ();
+ GST_VIDEO_ENCODER_TESTER (enc)->negotiate_in_set_format = i;
+
+ gst_pad_set_active (mysrcpad, TRUE);
+ gst_element_set_state (enc, GST_STATE_PLAYING);
+ gst_pad_set_active (mysinkpad, TRUE);
+
+ fail_unless (gst_pad_push_event (mysrcpad,
+ gst_event_new_stream_start ("id")));
+
+ gst_video_mastering_display_info_from_string (&mdi, mdi_str);
+ gst_video_content_light_level_from_string (&cll, cll_str);
+
+ caps = create_test_caps ();
+ gst_video_mastering_display_info_add_to_caps (&mdi, caps);
+ gst_video_content_light_level_add_to_caps (&cll, caps);
+
+ fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_caps (caps)));
+ gst_caps_unref (caps);
+
+ gst_segment_init (&segment, GST_FORMAT_TIME);
+ fail_unless (gst_pad_push_event (mysrcpad,
+ gst_event_new_segment (&segment)));
+
+ gst_pad_push (mysrcpad, create_test_buffer (0));
+
+ caps = gst_pad_get_current_caps (mysinkpad);
+
+ s = gst_caps_get_structure (caps, 0);
+ fail_unless (str = gst_structure_get_string (s, "mastering-display-info"));
+ fail_unless_equals_string (str, mdi_str);
+
+ fail_unless (str = gst_structure_get_string (s, "content-light-level"));
+ fail_unless_equals_string (str, cll_str);
+
+ gst_caps_unref (caps);
+
+ cleanup_videoencodertest ();
+ }
+}
+
+GST_END_TEST;
+
static Suite *
gst_videoencoder_suite (void)
{
@@ -1212,6 +1281,7 @@ gst_videoencoder_suite (void)
tcase_add_test (tc, videoencoder_playback_events_subframes);
tcase_add_test (tc, videoencoder_force_keyunit_handling);
tcase_add_test (tc, videoencoder_force_keyunit_min_interval);
+ tcase_add_test (tc, videoencoder_hdr_metadata);
return s;
}