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>
This commit is contained in:
Jakub Adam 2021-05-25 21:16:48 +02:00 committed by Nicolas Dufresne
parent b3c7b9be49
commit b4a00f78bc
2 changed files with 107 additions and 24 deletions

View file

@ -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;
out_struct = gst_caps_get_structure (state->caps, 0);
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 (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);
}
/* 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);
}
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);
}
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;

View file

@ -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;
}