[FFmpeg-devel] [PATCH 16/27] cbs_sei: Implement fill and extract for HDR SEI messages
Mark Thompson
sw at jkqxz.net
Fri Jan 1 23:35:26 EET 2021
Fill and extract both mastering display colour volume and content light
level info messages.
---
libavcodec/cbs_h2645.c | 130 +++++++++++++++++++++++++++++++++++++++++
libavcodec/cbs_sei.c | 4 ++
2 files changed, 134 insertions(+)
diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
index 42b614034e..53d5b50b42 100644
--- a/libavcodec/cbs_h2645.c
+++ b/libavcodec/cbs_h2645.c
@@ -18,6 +18,7 @@
#include "libavutil/attributes.h"
#include "libavutil/avassert.h"
+#include "libavutil/mastering_display_metadata.h"
#include "bytestream.h"
#include "cbs.h"
@@ -1504,6 +1505,133 @@ const CodedBitstreamType ff_cbs_type_h265 = {
.extract_metadata = &ff_cbs_sei_extract_metadata,
};
+static uint32_t rescale_clip(AVRational value, uint32_t scale,
+ uint32_t min, uint32_t max)
+{
+ int64_t scaled = av_rescale(scale, value.num, value.den);
+ return av_clip64(scaled, min, max);
+}
+
+static void cbs_sei_fill_mastering_display_colour_volume
+ (SEIRawMasteringDisplayColourVolume *mdcv,
+ const AVMasteringDisplayMetadata *mdm)
+{
+ memset(mdcv, 0, sizeof(*mdcv));
+
+ if (mdm->has_primaries) {
+ // The values in the metadata structure are fractions between 0 and 1,
+ // while the SEI message contains fixed-point values with an increment
+ // of 0.00002. So, scale up by 50000 to convert between them and clip
+ // to the allowed range ([5, 37000] for x, [5, 42000] for y).
+
+ for (int a = 0; a < 3; a++) {
+ // The metadata structure stores this in RGB order, but the SEI
+ // wants it in GBR order.
+ static const uint8_t mapping[] = { 1, 2, 0 };
+ int b = mapping[a];
+ mdcv->display_primaries_x[a] =
+ rescale_clip(mdm->display_primaries[b][0], 50000, 5, 37000);
+ mdcv->display_primaries_y[a] =
+ rescale_clip(mdm->display_primaries[b][1], 50000, 5, 42000);
+ }
+
+ mdcv->white_point_x =
+ rescale_clip(mdm->white_point[0], 50000, 5, 37000);
+ mdcv->white_point_y =
+ rescale_clip(mdm->white_point[1], 50000, 5, 42000);
+ }
+
+ if (mdm->has_luminance) {
+ // Metadata are rational values in candelas per square metre, SEI
+ // contains fixed point in units of 0.0001 candelas per square
+ // metre. So scale up by 10000 to convert between them, and clip to
+ // the allowed ranges.
+
+ mdcv->max_display_mastering_luminance =
+ rescale_clip(mdm->max_luminance, 10000, 50000, 100000000);
+ mdcv->min_display_mastering_luminance =
+ rescale_clip(mdm->min_luminance, 10000, 1, 50000);
+
+ // The spec requires that they are not equal when in the normal
+ // range.
+ if (mdcv->min_display_mastering_luminance >=
+ mdcv->max_display_mastering_luminance) {
+ mdcv->min_display_mastering_luminance =
+ mdcv->max_display_mastering_luminance - 1;
+ }
+ } else {
+ mdcv->max_display_mastering_luminance = 0;
+ mdcv->min_display_mastering_luminance = 0;
+ }
+}
+
+static void cbs_sei_extract_mastering_display_colour_volume
+ (AVMasteringDisplayMetadata *mdm,
+ const SEIRawMasteringDisplayColourVolume *mdcv)
+{
+#define IN_RANGE(v, min, max) ((v) >= (min) && (v) <= (max))
+#define IS_VALID_COORD(x, y) (IN_RANGE(x, 5, 37000) && IN_RANGE(y, 5, 42000))
+ int valid_chromaticity = 1;
+ for (int a = 0; a < 3; a++) {
+ if (!IS_VALID_COORD(mdcv->display_primaries_x[a],
+ mdcv->display_primaries_y[a]))
+ valid_chromaticity = 0;
+ }
+ if (!IS_VALID_COORD(mdcv->white_point_x, mdcv->white_point_y))
+ valid_chromaticity = 0;
+
+ memset(mdm, 0, sizeof(*mdm));
+
+ if (valid_chromaticity) {
+ for (int a = 0; a < 3; a++) {
+ // SEI message in GBR order, but metadata structure in RGB order.
+ static const uint8_t mapping[] = { 2, 0, 1 };
+ int b = mapping[a];
+
+ mdm->display_primaries[a][0] =
+ av_make_q(mdcv->display_primaries_x[b], 50000);
+ mdm->display_primaries[a][1] =
+ av_make_q(mdcv->display_primaries_y[b], 50000);
+ }
+
+ mdm->white_point[0] = av_make_q(mdcv->white_point_x, 50000);
+ mdm->white_point[1] = av_make_q(mdcv->white_point_y, 50000);
+
+ mdm->has_primaries = 1;
+ }
+
+ if (IN_RANGE(mdcv->min_display_mastering_luminance, 1, 50000) &&
+ IN_RANGE(mdcv->max_display_mastering_luminance, 50000, 100000000)) {
+ mdm->min_luminance = av_make_q(mdcv->min_display_mastering_luminance, 10000);
+ mdm->max_luminance = av_make_q(mdcv->max_display_mastering_luminance, 10000);
+
+ mdm->has_luminance = 1;
+ }
+#undef IN_RANGE
+#undef IS_VALID_COORD
+}
+
+static void cbs_sei_fill_content_light_level_info
+ (SEIRawContentLightLevelInfo *cll, const AVContentLightMetadata *clm)
+{
+ memset(cll, 0, sizeof(*cll));
+
+ // Both the metadata and the SEI are in units of candelas per square
+ // metre, so we only need to clip to ensure that they are in the valid
+ // range.
+
+ cll->max_content_light_level = av_clip_uintp2(clm->MaxCLL, 16);
+ cll->max_pic_average_light_level = av_clip_uintp2(clm->MaxFALL, 16);
+}
+
+
+static void cbs_sei_extract_content_light_level_info
+ (AVContentLightMetadata *clm, const SEIRawContentLightLevelInfo *cll)
+{
+ clm->MaxCLL = cll->max_content_light_level;
+ clm->MaxFALL = cll->max_pic_average_light_level;
+}
+
static const SEIMessageTypeDescriptor cbs_sei_common_types[] = {
{
SEI_TYPE_FILLER_PAYLOAD,
@@ -1528,12 +1656,14 @@ static const SEIMessageTypeDescriptor cbs_sei_common_types[] = {
1, 0,
sizeof(SEIRawMasteringDisplayColourVolume),
SEI_MESSAGE_RW(sei, mastering_display_colour_volume),
+ SEI_MESSAGE_FE(sei, mastering_display_colour_volume),
},
{
SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO,
1, 0,
sizeof(SEIRawContentLightLevelInfo),
SEI_MESSAGE_RW(sei, content_light_level_info),
+ SEI_MESSAGE_FE(sei, content_light_level_info),
},
{
SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS,
diff --git a/libavcodec/cbs_sei.c b/libavcodec/cbs_sei.c
index e5f9e3e403..0c05b2bdc9 100644
--- a/libavcodec/cbs_sei.c
+++ b/libavcodec/cbs_sei.c
@@ -375,6 +375,10 @@ typedef struct SEIMetadata {
} SEIMetadata;
static const SEIMetadata cbs_sei_metadata[] = {
+ { CBS_METADATA_MASTERING_DISPLAY,
+ SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME },
+ { CBS_METADATA_CONTENT_LIGHT_LEVEL,
+ SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO },
};
static const SEIMessageTypeDescriptor *cbs_sei_find_type_from_metadata
--
2.29.2
More information about the ffmpeg-devel
mailing list