From patchwork Sun Feb 21 19:51:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 25867 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id BBA49449DB5 for ; Sun, 21 Feb 2021 21:53:43 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id A4C0F68A8A5; Sun, 21 Feb 2021 21:53:43 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f46.google.com (mail-wr1-f46.google.com [209.85.221.46]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EDE9F689805 for ; Sun, 21 Feb 2021 21:53:33 +0200 (EET) Received: by mail-wr1-f46.google.com with SMTP id v1so16894618wrd.6 for ; Sun, 21 Feb 2021 11:53:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jkqxz-net.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=dO27ShCrhaFJMYDCGI5mQrfGS5JRIX3xoGS/wzX8gFQ=; b=wXSPhNkehFVFDRBzGQ+4OtJkdhzrlML12hi3VF01x9CIE3nlmfBLMSYebXznQmV+KC zxsTqCogYdhyaNrVgOfVDlOmFUvzYtveLBobOEx7pOVN7LmrUalWUYhBdzwhSOn6tQcD rtahk8M/FgEAk5VSugiiwtifAhly0ALg4a8tHzQ8vOQYJdbIJIBsbFqHPPABuXC36O9X AsmwOw9JfP4NeOCHorfl75Wfl8Z3BmD1wprK/lMmQwT1Nf7SKBJDyoXmJ6U6KfSqDD5Y Y45mOXucxjSJdI8s4IHACGWcq4zmht9aYZSSV2Rci6m1wMm8WPk/JPpxuCe8+w6kYUGt xigw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=dO27ShCrhaFJMYDCGI5mQrfGS5JRIX3xoGS/wzX8gFQ=; b=lm5PlgFYqVI0tZ73wQ6ahXuj7K93E8OJISm7Pvqb4kv/jTQnOe8jPKVWb9JCVR/BfC mVXQMBNiv2SM/DB0AqvO9fqSEvsyobqm3rXdYjoUFocmpMHMOTehHxPMgiUERDNNC6rI n+9nVFZAvb3FhRsv/gDq13SOZVSgW1bRa623cqalTyGVBRR0i0LH4rfy1S5lMT1pRKE6 1YkPSZnEMEpLlcV6O/F5dXpgiv6ndICk2CbYvtq08vgoDdt08dT4S/qE96I8IERKiEeq 5LPQ3uB3j7cgd6EHJ+PmQSdQ8glQppwO118XficvvCN3QM8VQae7nuTxh7rToCdniUWA i+KQ== X-Gm-Message-State: AOAM5336QMZVACfspOPZ8U/uPmNoH2Ot1OMT73c9cnv7r1rjiNqzqD87 MWUFy/33cn5baltXTmQhDfBOlCnaxWmO4A== X-Google-Smtp-Source: ABdhPJwKPeLUSdy553Tloun8TvHpaN42QAgOd28ZyCliZSC5fuPO9IM97CaRwVh5H8FrErE9nHIVaA== X-Received: by 2002:adf:d20c:: with SMTP id j12mr18477415wrh.76.1613937213449; Sun, 21 Feb 2021 11:53:33 -0800 (PST) Received: from localhost.localdomain (cpc91226-cmbg18-2-0-cust7.5-4.cable.virginm.net. [82.0.29.8]) by smtp.gmail.com with ESMTPSA id z18sm1780372wrs.19.2021.02.21.11.53.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 21 Feb 2021 11:53:32 -0800 (PST) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Sun, 21 Feb 2021 19:51:12 +0000 Message-Id: <20210221195125.1901683-5-sw@jkqxz.net> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210221195125.1901683-1-sw@jkqxz.net> References: <20210221195125.1901683-1-sw@jkqxz.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v2 05/18] cbs_sei: Implement fill and extract for HDR SEI messages X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 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 cb0005cc1b..ecd2001816 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" @@ -1513,6 +1514,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, @@ -1537,12 +1665,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 83bb5cca55..a5990205d0 100644 --- a/libavcodec/cbs_sei.c +++ b/libavcodec/cbs_sei.c @@ -380,6 +380,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