2 * Copyright (C) 2020-2021 Collabora Ltd.
3 * @author: Jakub Adam <jakub.adam@collabora.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * SECTION:rtphdrextcolorspace
23 * @title: GstRtphdrext-Colorspace
24 * @short_description: Helper methods for dealing with Color Space RTP header
25 * extension as defined in http://www.webrtc.org/experiments/rtp-hdrext/color-space
26 * @see_also: #GstRTPHeaderExtension, #GstRTPBasePayload, #GstRTPBaseDepayload
31 #include "gstrtphdrext-colorspace.h"
33 #include "gstrtpelements.h"
35 #include <gst/base/gstbytereader.h>
36 #include <gst/video/video-color.h>
37 #include <gst/video/video-hdr.h>
39 GST_DEBUG_CATEGORY_STATIC (rtphdrext_colorspace_debug);
40 #define GST_CAT_DEFAULT (rtphdrext_colorspace_debug)
43 * GstRTPHeaderExtensionColorspace:
44 * @parent: the parent #GstRTPHeaderExtension
46 * Instance struct for Color Space RTP header extension.
48 * http://www.webrtc.org/experiments/rtp-hdrext/color-space
50 struct _GstRTPHeaderExtensionColorspace
52 GstRTPHeaderExtension parent;
54 GstVideoColorimetry colorimetry;
55 GstVideoChromaSite chroma_site;
56 GstVideoMasteringDisplayInfo mdi;
57 GstVideoContentLightLevel cll;
58 gboolean has_hdr_meta;
61 G_DEFINE_TYPE_WITH_CODE (GstRTPHeaderExtensionColorspace,
62 gst_rtp_header_extension_colorspace, GST_TYPE_RTP_HEADER_EXTENSION,
63 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "rtphdrextcolorspace", 0,
64 "RTP Color Space Header Extension");
66 GST_ELEMENT_REGISTER_DEFINE (rtphdrextcolorspace, "rtphdrextcolorspace",
67 GST_RANK_MARGINAL, GST_TYPE_RTP_HEADER_EXTENSION_COLORSPACE);
70 gst_rtp_header_extension_colorspace_init (GstRTPHeaderExtensionColorspace *
75 static GstRTPHeaderExtensionFlags
76 gst_rtp_header_extension_colorspace_get_supported_flags (GstRTPHeaderExtension *
79 GstRTPHeaderExtensionColorspace *self =
80 GST_RTP_HEADER_EXTENSION_COLORSPACE (ext);
82 return self->has_hdr_meta ?
83 GST_RTP_HEADER_EXTENSION_TWO_BYTE : GST_RTP_HEADER_EXTENSION_ONE_BYTE;
87 gst_rtp_header_extension_colorspace_get_max_size (GstRTPHeaderExtension * ext,
88 const GstBuffer * buffer)
90 GstRTPHeaderExtensionColorspace *self =
91 GST_RTP_HEADER_EXTENSION_COLORSPACE (ext);
93 return self->has_hdr_meta ?
94 GST_RTP_HDREXT_COLORSPACE_WITH_HDR_META_SIZE :
95 GST_RTP_HDREXT_COLORSPACE_SIZE;
99 gst_rtp_header_extension_colorspace_write (GstRTPHeaderExtension * ext,
100 const GstBuffer * input_meta, GstRTPHeaderExtensionFlags write_flags,
101 GstBuffer * output, guint8 * data, gsize size)
103 GstRTPHeaderExtensionColorspace *self =
104 GST_RTP_HEADER_EXTENSION_COLORSPACE (ext);
105 GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
106 gboolean is_frame_last_buffer;
108 guint8 horizontal_site;
109 guint8 vertical_site;
111 g_return_val_if_fail (size >=
112 gst_rtp_header_extension_colorspace_get_max_size (ext, NULL), -1);
113 g_return_val_if_fail (write_flags &
114 gst_rtp_header_extension_colorspace_get_supported_flags (ext), -1);
116 if (self->colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN &&
117 self->colorimetry.primaries == GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
118 self->colorimetry.range == GST_VIDEO_COLOR_RANGE_UNKNOWN &&
119 self->colorimetry.transfer == GST_VIDEO_TRANSFER_UNKNOWN) {
120 /* Nothing to write. */
124 gst_rtp_buffer_map (output, GST_MAP_READ, &rtp);
125 is_frame_last_buffer = gst_rtp_buffer_get_marker (&rtp);
126 gst_rtp_buffer_unmap (&rtp);
128 if (!is_frame_last_buffer) {
129 /* Only a video frame's final packet should carry color space info. */
133 *ptr++ = gst_video_color_primaries_to_iso (self->colorimetry.primaries);
134 *ptr++ = gst_video_transfer_function_to_iso (self->colorimetry.transfer);
135 *ptr++ = gst_video_color_matrix_to_iso (self->colorimetry.matrix);
137 if (self->chroma_site & GST_VIDEO_CHROMA_SITE_H_COSITED) {
139 } else if (self->chroma_site & GST_VIDEO_CHROMA_SITE_NONE) {
145 if (self->chroma_site & GST_VIDEO_CHROMA_SITE_V_COSITED) {
147 } else if (self->chroma_site & GST_VIDEO_CHROMA_SITE_NONE) {
154 (self->colorimetry.range << 4) + (horizontal_site << 2) + vertical_site;
156 if (self->has_hdr_meta) {
159 GST_WRITE_UINT16_BE (ptr,
160 self->mdi.max_display_mastering_luminance / 10000);
162 GST_WRITE_UINT16_BE (ptr, self->mdi.min_display_mastering_luminance);
165 for (i = 0; i < 3; ++i) {
166 GST_WRITE_UINT16_BE (ptr, self->mdi.display_primaries[i].x);
168 GST_WRITE_UINT16_BE (ptr, self->mdi.display_primaries[i].y);
172 GST_WRITE_UINT16_BE (ptr, self->mdi.white_point.x);
174 GST_WRITE_UINT16_BE (ptr, self->mdi.white_point.y);
177 GST_WRITE_UINT16_BE (ptr, self->cll.max_content_light_level);
179 GST_WRITE_UINT16_BE (ptr, self->cll.max_frame_average_light_level);
187 parse_colorspace (GstByteReader * reader, GstVideoColorimetry * colorimetry,
188 GstVideoChromaSite * chroma_site)
192 g_return_val_if_fail (reader != NULL, FALSE);
193 g_return_val_if_fail (colorimetry != NULL, FALSE);
194 g_return_val_if_fail (chroma_site != NULL, FALSE);
196 if (gst_byte_reader_get_remaining (reader) < GST_RTP_HDREXT_COLORSPACE_SIZE) {
200 if (!gst_byte_reader_get_uint8 (reader, &val)) {
203 colorimetry->primaries = gst_video_color_primaries_from_iso (val);
205 if (!gst_byte_reader_get_uint8 (reader, &val)) {
208 colorimetry->transfer = gst_video_transfer_function_from_iso (val);
210 if (!gst_byte_reader_get_uint8 (reader, &val)) {
213 colorimetry->matrix = gst_video_color_matrix_from_iso (val);
215 *chroma_site = GST_VIDEO_CHROMA_SITE_UNKNOWN;
217 if (!gst_byte_reader_get_uint8 (reader, &val)) {
220 switch ((val >> 2) & 0x03) {
222 *chroma_site |= GST_VIDEO_CHROMA_SITE_H_COSITED;
225 *chroma_site |= GST_VIDEO_CHROMA_SITE_NONE;
229 switch (val & 0x03) {
231 *chroma_site |= GST_VIDEO_CHROMA_SITE_V_COSITED;
234 *chroma_site |= GST_VIDEO_CHROMA_SITE_NONE;
238 colorimetry->range = val >> 4;
244 parse_colorspace_with_hdr_meta (GstByteReader * reader,
245 GstVideoColorimetry * colorimetry,
246 GstVideoChromaSite * chroma_site,
247 GstVideoMasteringDisplayInfo * mastering_display_info,
248 GstVideoContentLightLevel * content_light_level)
253 g_return_val_if_fail (reader != NULL, FALSE);
254 g_return_val_if_fail (mastering_display_info != NULL, FALSE);
255 g_return_val_if_fail (content_light_level != NULL, FALSE);
257 if (gst_byte_reader_get_remaining (reader) <
258 GST_RTP_HDREXT_COLORSPACE_WITH_HDR_META_SIZE) {
262 if (!parse_colorspace (reader, colorimetry, chroma_site)) {
266 if (!gst_byte_reader_get_uint16_be (reader, &val16)) {
269 mastering_display_info->max_display_mastering_luminance = val16 * 10000;
271 if (!gst_byte_reader_get_uint16_be (reader, &val16)) {
274 mastering_display_info->min_display_mastering_luminance = val16;
276 for (i = 0; i < 3; ++i) {
277 if (!gst_byte_reader_get_uint16_be (reader,
278 &mastering_display_info->display_primaries[i].x)) {
282 if (!gst_byte_reader_get_uint16_be (reader,
283 &mastering_display_info->display_primaries[i].y)) {
288 if (!gst_byte_reader_get_uint16_be (reader,
289 &mastering_display_info->white_point.x)) {
292 if (!gst_byte_reader_get_uint16_be (reader,
293 &mastering_display_info->white_point.y)) {
297 if (!gst_byte_reader_get_uint16_be (reader,
298 &content_light_level->max_content_light_level)) {
301 if (!gst_byte_reader_get_uint16_be (reader,
302 &content_light_level->max_frame_average_light_level)) {
310 gst_rtp_header_extension_colorspace_read (GstRTPHeaderExtension * ext,
311 GstRTPHeaderExtensionFlags read_flags, const guint8 * data, gsize size,
314 GstRTPHeaderExtensionColorspace *self =
315 GST_RTP_HEADER_EXTENSION_COLORSPACE (ext);
316 gboolean has_hdr_meta;
317 GstByteReader *reader;
318 GstVideoColorimetry colorimetry;
319 GstVideoChromaSite chroma_site;
320 GstVideoMasteringDisplayInfo mdi;
321 GstVideoContentLightLevel cll;
322 gboolean caps_update_needed;
325 if (size != GST_RTP_HDREXT_COLORSPACE_SIZE &&
326 size != GST_RTP_HDREXT_COLORSPACE_WITH_HDR_META_SIZE) {
327 GST_WARNING_OBJECT (ext, "Invalid Color Space header extension size %"
328 G_GSIZE_FORMAT, size);
332 has_hdr_meta = size == GST_RTP_HDREXT_COLORSPACE_WITH_HDR_META_SIZE;
334 reader = gst_byte_reader_new (data, size);
337 result = parse_colorspace_with_hdr_meta (reader, &colorimetry, &chroma_site,
340 result = parse_colorspace (reader, &colorimetry, &chroma_site);
343 g_clear_pointer (&reader, gst_byte_reader_free);
345 if (!gst_video_colorimetry_is_equal (&self->colorimetry, &colorimetry)) {
346 caps_update_needed = TRUE;
347 self->colorimetry = colorimetry;
350 if (self->chroma_site != chroma_site) {
351 caps_update_needed = TRUE;
352 self->chroma_site = chroma_site;
355 if (self->has_hdr_meta != has_hdr_meta) {
356 caps_update_needed = TRUE;
357 self->has_hdr_meta = has_hdr_meta;
361 if (!gst_video_mastering_display_info_is_equal (&self->mdi, &mdi)) {
362 caps_update_needed = TRUE;
365 if (!gst_video_content_light_level_is_equal (&self->cll, &cll)) {
366 caps_update_needed = TRUE;
371 if (caps_update_needed) {
372 gst_rtp_header_extension_set_wants_update_non_rtp_src_caps (ext, TRUE);
379 gst_rtp_header_extension_colorspace_set_non_rtp_sink_caps
380 (GstRTPHeaderExtension * ext, const GstCaps * caps)
382 GstRTPHeaderExtensionColorspace *self =
383 GST_RTP_HEADER_EXTENSION_COLORSPACE (ext);
385 const gchar *colorimetry;
386 const gchar *chroma_site;
388 s = gst_caps_get_structure (caps, 0);
390 colorimetry = gst_structure_get_string (s, "colorimetry");
392 gst_video_colorimetry_from_string (&self->colorimetry, colorimetry);
395 gst_video_mastering_display_info_from_caps (&self->mdi, caps);
397 gst_video_content_light_level_from_caps (&self->cll, caps);
400 chroma_site = gst_structure_get_string (s, "chroma-site");
402 self->chroma_site = gst_video_chroma_from_string (chroma_site);
409 gst_rtp_header_extension_colorspace_update_non_rtp_src_caps
410 (GstRTPHeaderExtension * ext, GstCaps * caps)
412 GstRTPHeaderExtensionColorspace *self =
413 GST_RTP_HEADER_EXTENSION_COLORSPACE (ext);
417 gst_structure_remove_fields (gst_caps_get_structure (caps, 0),
418 "mastering-display-info", "content-light-level", NULL);
420 if ((color_str = gst_video_colorimetry_to_string (&self->colorimetry))) {
421 gst_caps_set_simple (caps, "colorimetry", G_TYPE_STRING, color_str, NULL);
424 if (self->chroma_site != GST_VIDEO_CHROMA_SITE_UNKNOWN) {
425 gst_caps_set_simple (caps, "chroma-site", G_TYPE_STRING,
426 gst_video_chroma_to_string (self->chroma_site), NULL);
428 if (self->has_hdr_meta) {
429 gst_video_mastering_display_info_add_to_caps (&self->mdi, caps);
430 gst_video_content_light_level_add_to_caps (&self->cll, caps);
437 gst_rtp_header_extension_colorspace_class_init
438 (GstRTPHeaderExtensionColorspaceClass * klass)
440 GstRTPHeaderExtensionClass *rtp_hdr_class =
441 GST_RTP_HEADER_EXTENSION_CLASS (klass);
442 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
444 rtp_hdr_class->get_supported_flags =
445 gst_rtp_header_extension_colorspace_get_supported_flags;
446 rtp_hdr_class->get_max_size =
447 gst_rtp_header_extension_colorspace_get_max_size;
448 rtp_hdr_class->write = gst_rtp_header_extension_colorspace_write;
449 rtp_hdr_class->read = gst_rtp_header_extension_colorspace_read;
450 rtp_hdr_class->set_non_rtp_sink_caps =
451 gst_rtp_header_extension_colorspace_set_non_rtp_sink_caps;
452 rtp_hdr_class->update_non_rtp_src_caps =
453 gst_rtp_header_extension_colorspace_update_non_rtp_src_caps;
454 rtp_hdr_class->set_caps_from_attributes =
455 gst_rtp_header_extension_set_caps_from_attributes_simple_sdp;
457 gst_element_class_set_static_metadata (gstelement_class,
458 "Color Space", GST_RTP_HDREXT_ELEMENT_CLASS,
459 "Extends RTP packets with color space and high dynamic range (HDR) information.",
460 "Jakub Adam <jakub.adam@collabora.com>");
461 gst_rtp_header_extension_class_set_uri (rtp_hdr_class,
462 GST_RTP_HDREXT_COLORSPACE_URI);