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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".