From: Stéphane Cerveau Date: Mon, 19 Oct 2020 13:36:58 +0000 (+0200) Subject: video-hdr: introduce HDR10+ parser X-Git-Tag: 1.19.3~511^2~320 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a1ed7a8f49568094f79fd76d7842d67e723229d1;p=platform%2Fupstream%2Fgstreamer.git video-hdr: introduce HDR10+ parser Video can now parse a HDR10+ data structure coming from a SEI message. Part-of: --- diff --git a/gst-libs/gst/video/video-hdr.c b/gst-libs/gst/video/video-hdr.c index bf4cf37..5f924cd 100644 --- a/gst-libs/gst/video/video-hdr.c +++ b/gst-libs/gst/video/video-hdr.c @@ -22,9 +22,13 @@ #endif #include +#include #include "video-hdr.h" +#define HDR10_PLUS_MAX_BEZIER_CURVE_ANCHORS 9 +#define HDR10_PLUS_MAX_DIST_MAXRGB_PERCENTILES 9 + #define N_ELEMENT_MASTERING_DISPLAY_INFO 10 #define MASTERING_FORMAT \ "%d:%d:" \ @@ -496,3 +500,198 @@ gst_buffer_add_video_hdr_meta (GstBuffer * buffer, return meta; } + +#define CHECK_HDR10PLUS_REMAINING(br, needed) \ +if (gst_bit_reader_get_remaining (&br) < needed) { \ + GST_DEBUG ("Not enough bits remaining %d, needed %d", gst_bit_reader_get_remaining (&br), needed); \ + return FALSE; \ +} + +/** + * gst_video_hdr_parse_hdr10_plus: + * @data: HDR10+ data + * @size: size of data + * @hdr10_plus: (out): #GstVideoHDR10Plus structure to fill in. + * + * Parse HDR10+ (SMPTE2094-40) user data and store in @hdr10_plus + * For more details, see: + * https://www.atsc.org/wp-content/uploads/2018/02/S34-301r2-A341-Amendment-2094-40-1.pdf + * and SMPTE ST2094-40 + * + * Returns: %TRUE if @data was successfully parsed to @hdr10_plus + * + * Since: 1.20 + */ +gboolean +gst_video_hdr_parse_hdr10_plus (const guint8 * data, gsize size, + GstVideoHDR10Plus * hdr10_plus) +{ + guint16 provider_oriented_code; + int w, i, j; + GstBitReader br; + + /* there must be at least one byte, and not more than GST_VIDEO_HDR10_PLUS_MAX_BYTES bytes */ + g_return_val_if_fail (data != NULL, FALSE); + + memset (hdr10_plus, 0, sizeof (GstVideoHDR10Plus)); + gst_bit_reader_init (&br, data, size); + GST_MEMDUMP ("HDR10+", data, size); + CHECK_HDR10PLUS_REMAINING (br, 2 + 8 + 8 + 2); + provider_oriented_code = gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + if (provider_oriented_code != 0x0001) + return FALSE; + + + hdr10_plus->application_identifier = + gst_bit_reader_get_bits_uint8_unchecked (&br, 8); + hdr10_plus->application_version = + gst_bit_reader_get_bits_uint8_unchecked (&br, 8); + hdr10_plus->num_windows = gst_bit_reader_get_bits_uint8_unchecked (&br, 2); + if (hdr10_plus->num_windows != GST_VIDEO_HDR10_PLUS_NUM_WINDOWS) + return FALSE; + for (w = 0; w < hdr10_plus->num_windows; w++) { + CHECK_HDR10PLUS_REMAINING (br, + 16 + 16 + 16 + 16 + 16 + 16 + 8 + 16 + 16 + 16 + 1); + hdr10_plus->processing_window[w].window_upper_left_corner_x = + gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + hdr10_plus->processing_window[w].window_upper_left_corner_y = + gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + hdr10_plus->processing_window[w].window_lower_right_corner_x = + gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + hdr10_plus->processing_window[w].window_lower_right_corner_y = + gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + hdr10_plus->processing_window[w].center_of_ellipse_x = + gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + hdr10_plus->processing_window[w].center_of_ellipse_y = + gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + hdr10_plus->processing_window[w].rotation_angle = + gst_bit_reader_get_bits_uint8_unchecked (&br, 8); + hdr10_plus->processing_window[w].semimajor_axis_internal_ellipse = + gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + hdr10_plus->processing_window[w].semimajor_axis_external_ellipse = + gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + hdr10_plus->processing_window[w].semiminor_axis_external_ellipse = + gst_bit_reader_get_bits_uint16_unchecked (&br, 16); + hdr10_plus->processing_window[w].overlap_process_option = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + } + CHECK_HDR10PLUS_REMAINING (br, 27 + 1); + hdr10_plus->targeted_system_display_maximum_luminance = + gst_bit_reader_get_bits_uint32_unchecked (&br, 27); + hdr10_plus->targeted_system_display_actual_peak_luminance_flag = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (hdr10_plus->targeted_system_display_actual_peak_luminance_flag) { + CHECK_HDR10PLUS_REMAINING (br, 5 + 5); + hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance = + gst_bit_reader_get_bits_uint8_unchecked (&br, 5); + hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance = + gst_bit_reader_get_bits_uint8_unchecked (&br, 5); + if (hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance > + GST_VIDEO_HDR10_PLUS_MAX_TSD_APL) + return FALSE; + if (hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance > + GST_VIDEO_HDR10_PLUS_MAX_TSD_APL) + return FALSE; + CHECK_HDR10PLUS_REMAINING (br, + hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance * + hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance * 4); + for (i = 0; + i < hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance; + i++) { + for (j = 0; + j < + hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance; + j++) + hdr10_plus->targeted_system_display_actual_peak_luminance[i][j] = + gst_bit_reader_get_bits_uint8_unchecked (&br, 4); + } + for (w = 0; w < hdr10_plus->num_windows; w++) { + CHECK_HDR10PLUS_REMAINING (br, (17 * 3)); + for (i = 0; i < 3; i++) + hdr10_plus->processing_window[w].maxscl[i] = + gst_bit_reader_get_bits_uint32_unchecked (&br, 17); + CHECK_HDR10PLUS_REMAINING (br, 17 + 4); + hdr10_plus->processing_window[w].average_maxrgb = + gst_bit_reader_get_bits_uint32_unchecked (&br, 17); + hdr10_plus->processing_window[w].num_distribution_maxrgb_percentiles = + gst_bit_reader_get_bits_uint8_unchecked (&br, 4); + if (hdr10_plus-> + processing_window[w].num_distribution_maxrgb_percentiles != + HDR10_PLUS_MAX_DIST_MAXRGB_PERCENTILES) + return FALSE; + CHECK_HDR10PLUS_REMAINING (br, + hdr10_plus->processing_window[w].num_distribution_maxrgb_percentiles * + (17 + 7)); + for (i = 0; + i < + hdr10_plus->processing_window[w].num_distribution_maxrgb_percentiles; + i++) { + hdr10_plus->processing_window[w].distribution_maxrgb_percentages[i] = + gst_bit_reader_get_bits_uint8_unchecked (&br, 7); + hdr10_plus->processing_window[w].distribution_maxrgb_percentiles[i] = + gst_bit_reader_get_bits_uint32_unchecked (&br, 17); + } + CHECK_HDR10PLUS_REMAINING (br, 10) + hdr10_plus->processing_window[w].fraction_bright_pixels = + gst_bit_reader_get_bits_uint16_unchecked (&br, 10); + } + } + CHECK_HDR10PLUS_REMAINING (br, 1) + hdr10_plus->mastering_display_actual_peak_luminance_flag = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (hdr10_plus->targeted_system_display_actual_peak_luminance_flag) { + CHECK_HDR10PLUS_REMAINING (br, 5 + 5) + hdr10_plus->num_rows_mastering_display_actual_peak_luminance = + gst_bit_reader_get_bits_uint8_unchecked (&br, 5); + hdr10_plus->num_cols_mastering_display_actual_peak_luminance = + gst_bit_reader_get_bits_uint8_unchecked (&br, 5); + if (hdr10_plus->num_rows_mastering_display_actual_peak_luminance > + GST_VIDEO_HDR10_PLUS_MAX_MD_APL) + return FALSE; + if (hdr10_plus->num_cols_mastering_display_actual_peak_luminance > + GST_VIDEO_HDR10_PLUS_MAX_MD_APL) + return FALSE; + CHECK_HDR10PLUS_REMAINING (br, + hdr10_plus->num_rows_mastering_display_actual_peak_luminance * + hdr10_plus->num_cols_mastering_display_actual_peak_luminance * 4) + for (i = 0; + i < hdr10_plus->num_rows_mastering_display_actual_peak_luminance; i++) { + for (j = 0; + j < hdr10_plus->num_cols_mastering_display_actual_peak_luminance; j++) + hdr10_plus->mastering_display_actual_peak_luminance[i][j] = + gst_bit_reader_get_bits_uint8_unchecked (&br, 4); + } + for (w = 0; w < hdr10_plus->num_windows; w++) { + CHECK_HDR10PLUS_REMAINING (br, 1) + hdr10_plus->processing_window[w].tone_mapping_flag = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (hdr10_plus->processing_window[w].tone_mapping_flag) { + CHECK_HDR10PLUS_REMAINING (br, 12 + 12 + 4) + hdr10_plus->processing_window[w].knee_point_x = + gst_bit_reader_get_bits_uint16_unchecked (&br, 12); + hdr10_plus->processing_window[w].knee_point_y = + gst_bit_reader_get_bits_uint16_unchecked (&br, 12); + hdr10_plus->processing_window[w].num_bezier_curve_anchors = + gst_bit_reader_get_bits_uint8_unchecked (&br, 4); + if (hdr10_plus->processing_window[w].num_bezier_curve_anchors > + HDR10_PLUS_MAX_BEZIER_CURVE_ANCHORS) + return FALSE; + CHECK_HDR10PLUS_REMAINING (br, + 10 * hdr10_plus->processing_window[w].num_bezier_curve_anchors); + for (i = 0; + i < hdr10_plus->processing_window[w].num_bezier_curve_anchors; i++) + hdr10_plus->processing_window[w].bezier_curve_anchors[i] = + gst_bit_reader_get_bits_uint16_unchecked (&br, 10); + } + CHECK_HDR10PLUS_REMAINING (br, 1); + hdr10_plus->processing_window[w].color_saturation_mapping_flag = + gst_bit_reader_get_bits_uint8_unchecked (&br, 1); + if (hdr10_plus->processing_window[w].color_saturation_mapping_flag) { + CHECK_HDR10PLUS_REMAINING (br, 6); + hdr10_plus->processing_window[w].color_saturation_weight = + gst_bit_reader_get_bits_uint8_unchecked (&br, 6); + } + } + } + return TRUE; +} diff --git a/gst-libs/gst/video/video-hdr.h b/gst-libs/gst/video/video-hdr.h index c5b5fdb..54d6e3a 100644 --- a/gst-libs/gst/video/video-hdr.h +++ b/gst-libs/gst/video/video-hdr.h @@ -44,6 +44,7 @@ typedef enum { GST_VIDEO_HDR_FORMAT_DOLBY_VISION, } GstVideoHDRFormat; +#define GST_VIDEO_HDR10_PLUS_MAX_BYTES 1024 /* defined in CTA-861-G */ #define GST_VIDEO_HDR10_PLUS_NUM_WINDOWS 1 /* number of windows, shall be 1. */ #define GST_VIDEO_HDR10_PLUS_MAX_TSD_APL 25 /* targeted_system_display_actual_peak_luminance max value */ @@ -335,6 +336,10 @@ struct _GstVideoHDR10Plus gpointer _gst_reserved[GST_PADDING]; }; +GST_VIDEO_API gboolean +gst_video_hdr_parse_hdr10_plus (const guint8 * data, gsize size, + GstVideoHDR10Plus * hdr10_plus); + G_END_DECLS #endif /* __GST_VIDEO_HDR_H__ */