From f848619ff427aeb7b20ee8728e41e286885c8b74 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sat, 16 Apr 2022 21:26:55 +0900 Subject: [PATCH] qsvh265enc: Write HDR10 metadata SEI If device supports HDR10 metadata API, write the information into bitstream per IDR. Part-of: --- .../gst-plugins-bad/sys/qsv/gstqsvh265enc.cpp | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/subprojects/gst-plugins-bad/sys/qsv/gstqsvh265enc.cpp b/subprojects/gst-plugins-bad/sys/qsv/gstqsvh265enc.cpp index 6bcf6574fc..67b8b7ee91 100644 --- a/subprojects/gst-plugins-bad/sys/qsv/gstqsvh265enc.cpp +++ b/subprojects/gst-plugins-bad/sys/qsv/gstqsvh265enc.cpp @@ -138,6 +138,7 @@ typedef struct _GstQsvH265EncClassData guint impl_index; gint64 adapter_luid; gchar *display_path; + gboolean hdr10_aware; } GstQsvH265EncClassData; typedef struct _GstQsvH265Enc @@ -148,6 +149,8 @@ typedef struct _GstQsvH265Enc mfxExtCodingOption option; mfxExtCodingOption2 option2; mfxExtCodingOption3 option3; + mfxExtContentLightLevelInfo cll; + mfxExtMasteringDisplayColourVolume mdcv; mfxU16 profile; @@ -182,6 +185,8 @@ typedef struct _GstQsvH265Enc typedef struct _GstQsvH265EncClass { GstQsvEncoderClass parent_class; + + gboolean hdr10_aware; } GstQsvH265EncClass; static GstElementClass *parent_class = nullptr; @@ -382,6 +387,8 @@ gst_qsv_h265_enc_class_init (GstQsvH265EncClass * klass, gpointer data) qsvenc_class->check_reconfigure = GST_DEBUG_FUNCPTR (gst_qsv_h265_enc_check_reconfigure); + klass->hdr10_aware = cdata->hdr10_aware; + gst_caps_unref (cdata->sink_caps); gst_caps_unref (cdata->src_caps); g_free (cdata); @@ -828,6 +835,8 @@ gst_qsv_h265_enc_init_extra_params (GstQsvH265Enc * self) memset (&self->option, 0, sizeof (mfxExtCodingOption)); memset (&self->option2, 0, sizeof (mfxExtCodingOption2)); memset (&self->option3, 0, sizeof (mfxExtCodingOption3)); + memset (&self->cll, 0, sizeof (mfxExtContentLightLevelInfo)); + memset (&self->mdcv, 0, sizeof (mfxExtMasteringDisplayColourVolume)); self->signal_info.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO; self->signal_info.Header.BufferSz = sizeof (mfxExtVideoSignalInfo); @@ -840,6 +849,14 @@ gst_qsv_h265_enc_init_extra_params (GstQsvH265Enc * self) self->option3.Header.BufferId = MFX_EXTBUFF_CODING_OPTION3; self->option3.Header.BufferSz = sizeof (mfxExtCodingOption3); + + self->cll.Header.BufferId = MFX_EXTBUFF_CONTENT_LIGHT_LEVEL_INFO; + self->cll.Header.BufferSz = sizeof (mfxExtContentLightLevelInfo); + self->cll.InsertPayloadToggle = MFX_PAYLOAD_IDR; + + self->mdcv.Header.BufferId = MFX_EXTBUFF_MASTERING_DISPLAY_COLOUR_VOLUME; + self->mdcv.Header.BufferSz = sizeof (mfxExtMasteringDisplayColourVolume); + self->mdcv.InsertPayloadToggle = MFX_PAYLOAD_IDR; } static void @@ -883,12 +900,18 @@ gst_qsv_h265_enc_set_format (GstQsvEncoder * encoder, GstVideoCodecState * state, mfxVideoParam * param, GPtrArray * extra_params) { GstQsvH265Enc *self = GST_QSV_H265_ENC (encoder); + GstQsvH265EncClass *klass = GST_QSV_H265_ENC_GET_CLASS (self); mfxU16 mfx_profile = MFX_PROFILE_UNKNOWN; GstVideoInfo *info = &state->info; mfxExtVideoSignalInfo *signal_info = nullptr; mfxExtCodingOption *option; mfxExtCodingOption2 *option2; mfxExtCodingOption3 *option3; + mfxExtContentLightLevelInfo *cll; + mfxExtMasteringDisplayColourVolume *mdcv; + gboolean have_cll = FALSE; + gboolean have_mdcv = FALSE; + mfxFrameInfo *frame_info; frame_info = ¶m->mfx.FrameInfo; @@ -945,6 +968,37 @@ gst_qsv_h265_enc_set_format (GstQsvEncoder * encoder, option = &self->option; option2 = &self->option2; option3 = &self->option3; + cll = &self->cll; + mdcv = &self->mdcv; + + if (klass->hdr10_aware) { + GstVideoMasteringDisplayInfo mdcv_info; + GstVideoContentLightLevel cll_info; + + if (gst_video_content_light_level_from_caps (&cll_info, state->caps)) { + cll->MaxContentLightLevel = cll_info.max_content_light_level; + cll->MaxPicAverageLightLevel = cll_info.max_frame_average_light_level; + have_cll = TRUE; + } + + if (gst_video_mastering_display_info_from_caps (&mdcv_info, state->caps)) { + /* GBR order is used in HEVC */ + mdcv->DisplayPrimariesX[0] = mdcv_info.display_primaries[1].x; + mdcv->DisplayPrimariesY[0] = mdcv_info.display_primaries[1].y; + mdcv->DisplayPrimariesX[1] = mdcv_info.display_primaries[2].x; + mdcv->DisplayPrimariesY[1] = mdcv_info.display_primaries[2].y; + mdcv->DisplayPrimariesX[2] = mdcv_info.display_primaries[0].x; + mdcv->DisplayPrimariesY[2] = mdcv_info.display_primaries[0].y; + + mdcv->WhitePointX = mdcv_info.white_point.x; + mdcv->WhitePointY = mdcv_info.white_point.y; + mdcv->MaxDisplayMasteringLuminance = + mdcv_info.max_display_mastering_luminance; + mdcv->MinDisplayMasteringLuminance = + mdcv_info.min_display_mastering_luminance; + have_mdcv = TRUE; + } + } g_mutex_lock (&self->prop_lock); param->mfx.CodecId = MFX_CODEC_HEVC; @@ -1027,6 +1081,10 @@ gst_qsv_h265_enc_set_format (GstQsvEncoder * encoder, g_ptr_array_add (extra_params, option); g_ptr_array_add (extra_params, option2); g_ptr_array_add (extra_params, option3); + if (have_cll) + g_ptr_array_add (extra_params, cll); + if (have_mdcv) + g_ptr_array_add (extra_params, mdcv); param->ExtParam = (mfxExtBuffer **) extra_params->pdata; param->NumExtParam = extra_params->len; @@ -1290,9 +1348,15 @@ gst_qsv_h265_enc_register (GstPlugin * plugin, guint rank, guint impl_index, std::vector < mfxU16 > supported_profiles; std::vector < std::string > supported_formats; Resolution max_resolution; + mfxExtContentLightLevelInfo cll; + mfxExtMasteringDisplayColourVolume mdcv; + mfxExtBuffer *ext_buffers[2]; + gboolean hdr10_aware = FALSE; memset (¶m, 0, sizeof (mfxVideoParam)); memset (&max_resolution, 0, sizeof (Resolution)); + memset (&cll, 0, sizeof (mfxExtContentLightLevelInfo)); + memset (&mdcv, 0, sizeof (mfxExtMasteringDisplayColourVolume)); param.AsyncDepth = 4; param.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY; @@ -1354,6 +1418,32 @@ gst_qsv_h265_enc_register (GstPlugin * plugin, guint rank, guint impl_index, mfx->FrameInfo.Shift = 0; mfx->CodecProfile = MFX_PROFILE_HEVC_MAIN; + /* check hdr10 metadata SEI support */ + cll.Header.BufferId = MFX_EXTBUFF_CONTENT_LIGHT_LEVEL_INFO; + cll.Header.BufferSz = sizeof (mfxExtContentLightLevelInfo); + cll.InsertPayloadToggle = MFX_PAYLOAD_IDR; + cll.MaxContentLightLevel = 1; + cll.MaxPicAverageLightLevel = 1; + + mdcv.Header.BufferId = MFX_EXTBUFF_MASTERING_DISPLAY_COLOUR_VOLUME; + mdcv.Header.BufferSz = sizeof (mfxExtMasteringDisplayColourVolume); + mdcv.InsertPayloadToggle = MFX_PAYLOAD_IDR; + mdcv.MaxDisplayMasteringLuminance = 1; + mdcv.MinDisplayMasteringLuminance = 1; + + ext_buffers[0] = (mfxExtBuffer *) & cll; + ext_buffers[1] = (mfxExtBuffer *) & mdcv; + + param.NumExtParam = 2; + param.ExtParam = ext_buffers; + if (MFXVideoENCODE_Query (session, ¶m, ¶m) == MFX_ERR_NONE) { + GST_INFO ("HDR10 metadata SEI is supported"); + hdr10_aware = TRUE; + } + + param.NumExtParam = 0; + param.ExtParam = nullptr; + /* Check max-resolution */ for (guint i = 0; i < G_N_ELEMENTS (resolutions_to_check); i++) { mfx->FrameInfo.Width = GST_ROUND_UP_16 (resolutions_to_check[i].width); @@ -1453,6 +1543,7 @@ gst_qsv_h265_enc_register (GstPlugin * plugin, guint rank, guint impl_index, cdata->sink_caps = sink_caps; cdata->src_caps = src_caps; cdata->impl_index = impl_index; + cdata->hdr10_aware = hdr10_aware; #ifdef G_OS_WIN32 gint64 device_luid;