mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 09:55:36 +00:00
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:
parent
b3c7b9be49
commit
b4a00f78bc
2 changed files with 107 additions and 24 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue