From patchwork Sat Aug 8 23:48:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kenny McClive X-Patchwork-Id: 21546 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 AFEC144AE59 for ; Sun, 9 Aug 2020 02:48:56 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 843E368A175; Sun, 9 Aug 2020 02:48:56 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from ms11p00im-hyfv17291101.me.com (ms11p00im-hyfv17291101.me.com [17.58.38.40]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 9F0686881E4 for ; Sun, 9 Aug 2020 02:48:50 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=me.com; s=1a1hai; t=1596930528; bh=41RQc6oyI1G4jowkwiUTtslMh5cg2Am9zfTvDTvEV+0=; h=From:Content-Type:Mime-Version:Subject:Message-Id:Date:To; b=NgCdtmmTYiLG4MUFITkNDq8wmBfs4WY3kmdVWlFWeGx99Hk9Rx0pnLBwskHs+oKI+ vQPzoEca+VGgbdXVp1kqc2ZqZqGjPRl/nPoCAuUw1ITOUNLwh+7su23UNktNucPAwf /F/796vn38SkKxtoe/6EWcvZVEto1GY9LltcbhJR3KoAzq77E35/dTPYpqtP3f/4X3 BgXRforTx0tY7g7egkUeLibA0+GaNaaeiwDZHSLfRromszQpKBjzGS7MK6nEPOxUBY czYhvpdrFuY64pr0mTWuLxPOpBobw/PPf1SntqpWsh/+UG6LkmMlqOgiSk9sETTwLU SHSj9xPGUOlvg== Received: from [10.0.1.2] (c-24-9-115-65.hsd1.co.comcast.net [24.9.115.65]) by ms11p00im-hyfv17291101.me.com (Postfix) with ESMTPSA id 43A5C6C0156 for ; Sat, 8 Aug 2020 23:48:48 +0000 (UTC) From: Kenny McClive Mime-Version: 1.0 (Mac OS X Mail 13.0 \(3608.60.0.2.5\)) Message-Id: Date: Sat, 8 Aug 2020 17:48:47 -0600 To: ffmpeg-devel@ffmpeg.org X-Mailer: Apple Mail (2.3608.60.0.2.5) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.235, 18.0.687 definitions=2020-08-08_15:2020-08-06, 2020-08-08 signatures=0 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=1 malwarescore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1011 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-2004280000 definitions=main-2008080185 Subject: [FFmpeg-devel] [PATCH] avcodec/options: Add options for inputing HDR10-related metadata 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" Previously, the only way to input the master display and content light metadata required for HDR10 was through x265-params. Obviously, that only worked with x265. If you wanted to use a different encoder like nvenc, you were out of luck. The options specified are written to the container (mov or matroska) only. Additional work would be required to write it to frames. The default values for the master display options may seem unorthodox, but it allows you to differentiate between 0 (which some movies use) and unspecified. The same was not done for content light metadata because 0 seems to mean unspecified in other systems such as x265. Signed-off-by: Kenny McClive --- libavcodec/avcodec.h | 84 +++++++++++++++++++++++ libavcodec/codec_par.h | 7 ++ libavcodec/options_table.h | 12 ++++ libavcodec/utils.c | 133 +++++++++++++++++++++++++++++++++++++ libavformat/matroskaenc.c | 62 +++++++++++------ libavformat/movenc.c | 29 ++++++-- 6 files changed, 298 insertions(+), 29 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index c91b2fd169..24f97345b7 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -2352,6 +2352,90 @@ typedef struct AVCodecContext { * - encoding: set by user */ int export_side_data; + + /** + * CIE 1931 x chromaticity coord of red color primary for mastering display. + * - encoding: Set by user + * - decoding: unused + */ + AVRational master_display_red_x; + + /** + * CIE 1931 y chromaticity coord of red color primary for mastering display. + * - encoding: Set by user + * - decoding: unused + */ + AVRational master_display_red_y; + + /** + * CIE 1931 x chromaticity coord of green color primary for mastering display. + * - encoding: Set by user + * - decoding: unused + */ + AVRational master_display_green_x; + + /** + * CIE 1931 y chromaticity coord of green color primary for mastering display. + * - encoding: Set by user + * - decoding: unused + */ + AVRational master_display_green_y; + + /** + * CIE 1931 x chromaticity coord of blue color primary for mastering display. + * - encoding: Set by user + * - decoding: unused + */ + AVRational master_display_blue_x; + + /** + * CIE 1931 y chromaticity coord of blue color primary for mastering display. + * - encoding: Set by user + * - decoding: unused + */ + AVRational master_display_blue_y; + + /** + * CIE 1931 x chromaticity coord of white point for mastering display. + * - encoding: Set by user + * - decoding: unused + */ + AVRational master_display_white_x; + + /** + * CIE 1931 y chromaticity coord of white point for mastering display. + * - encoding: Set by user + * - decoding: unused + */ + AVRational master_display_white_y; + + /** + * Min luminance of mastering display (cd/m^2). + * - encoding: Set by user + * - decoding: unused + */ + AVRational master_display_min_luminance; + + /** + * Max luminance of mastering display (cd/m^2). + * - encoding: Set by user + * - decoding: unused + */ + AVRational master_display_max_luminance; + + /** + * Max content light level (cd/m^2). + * - encoding: Set by user + * - decoding: unused + */ + unsigned max_cll; + + /** + * Max average light level per frame (cd/m^2). + * - encoding: Set by user + * - decoding: unused + */ + unsigned max_fall; } AVCodecContext; #if FF_API_CODEC_GET_SET diff --git a/libavcodec/codec_par.h b/libavcodec/codec_par.h index 948758e237..fe1fe3861b 100644 --- a/libavcodec/codec_par.h +++ b/libavcodec/codec_par.h @@ -24,6 +24,7 @@ #include #include "libavutil/avutil.h" +#include "libavutil/mastering_display_metadata.h" #include "libavutil/rational.h" #include "libavutil/pixfmt.h" @@ -149,6 +150,12 @@ typedef struct AVCodecParameters { enum AVColorSpace color_space; enum AVChromaLocation chroma_location; + /** + * Video only. HDR metadata. + */ + AVMasteringDisplayMetadata master_display_metadata; + AVContentLightMetadata content_light_metadata; + /** * Video only. Number of delayed frames. */ diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h index 1d0db1b5a4..680d05469a 100644 --- a/libavcodec/options_table.h +++ b/libavcodec/options_table.h @@ -412,6 +412,18 @@ static const AVOption avcodec_options[] = { {"bottomleft", "Bottom-left", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_BOTTOMLEFT }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, {"bottom", "Bottom", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_BOTTOM }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, {"unspecified", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, +{"master_display_red_x", "mastering display x chromaticity coord for red color primary", OFFSET(master_display_red_x), AV_OPT_TYPE_RATIONAL, {.dbl = INT_MAX}, 0, INT_MAX, V|E}, +{"master_display_red_y", "mastering display y chromaticity coord for red color primary", OFFSET(master_display_red_y), AV_OPT_TYPE_RATIONAL, {.dbl = INT_MAX}, 0, INT_MAX, V|E}, +{"master_display_green_x", "mastering display x chromaticity coord for green color primary", OFFSET(master_display_green_x), AV_OPT_TYPE_RATIONAL, {.dbl = INT_MAX}, 0, INT_MAX, V|E}, +{"master_display_green_y", "mastering display y chromaticity coord for green color primary", OFFSET(master_display_green_y), AV_OPT_TYPE_RATIONAL, {.dbl = INT_MAX}, 0, INT_MAX, V|E}, +{"master_display_blue_x", "mastering display x chromaticity coord for blue color primary", OFFSET(master_display_blue_x), AV_OPT_TYPE_RATIONAL, {.dbl = INT_MAX}, 0, INT_MAX, V|E}, +{"master_display_blue_y", "mastering display y chromaticity coord for blue color primary", OFFSET(master_display_blue_y), AV_OPT_TYPE_RATIONAL, {.dbl = INT_MAX}, 0, INT_MAX, V|E}, +{"master_display_white_x", "mastering display x chromaticity coord for white point", OFFSET(master_display_white_x), AV_OPT_TYPE_RATIONAL, {.dbl = INT_MAX}, 0, INT_MAX, V|E}, +{"master_display_white_y", "mastering display y chromaticity coord for white point", OFFSET(master_display_white_y), AV_OPT_TYPE_RATIONAL, {.dbl = INT_MAX}, 0, INT_MAX, V|E}, +{"master_display_min_lum", "mastering display min luminance", OFFSET(master_display_min_luminance), AV_OPT_TYPE_RATIONAL, {.dbl = INT_MAX}, 0, INT_MAX, V|E}, +{"master_display_max_lum", "mastering display max luminance", OFFSET(master_display_max_luminance), AV_OPT_TYPE_RATIONAL, {.dbl = INT_MAX}, 0, INT_MAX, V|E}, +{"max_cll", "max content light level", OFFSET(max_cll), AV_OPT_TYPE_INT64, {.i64 = DEFAULT }, 0, INT_MAX, V|E}, +{"max_fall", "max frame average light level", OFFSET(max_fall), AV_OPT_TYPE_INT64, {.i64 = DEFAULT }, 0, INT_MAX, V|E}, {"log_level_offset", "set the log level offset", OFFSET(log_level_offset), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX }, {"slices", "set the number of slices, used in parallelized encoding", OFFSET(slices), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|E}, {"thread_type", "select multithreading type", OFFSET(thread_type), AV_OPT_TYPE_FLAGS, {.i64 = FF_THREAD_SLICE|FF_THREAD_FRAME }, 0, INT_MAX, V|A|E|D, "thread_type"}, diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 5a2a90b030..b31041a755 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -35,6 +35,7 @@ #include "libavutil/frame.h" #include "libavutil/hwcontext.h" #include "libavutil/internal.h" +#include "libavutil/mastering_display_metadata.h" #include "libavutil/mathematics.h" #include "libavutil/mem_internal.h" #include "libavutil/pixdesc.h" @@ -67,6 +68,7 @@ const char av_codec_ffversion[] = "FFmpeg version " FFMPEG_VERSION; static AVMutex codec_mutex = AV_MUTEX_INITIALIZER; +static int unspecified_coord = INT_MAX; void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size) { @@ -2031,6 +2033,34 @@ AVCPBProperties *ff_add_cpb_side_data(AVCodecContext *avctx) return props; } +static void master_display_metadata_reset(AVMasteringDisplayMetadata *metadata) +{ + if (!metadata) + return; + + metadata->display_primaries[0][0] = (AVRational){ 0, 1 }; + metadata->display_primaries[0][1] = (AVRational){ 0, 1 }; + metadata->display_primaries[1][0] = (AVRational){ 0, 1 }; + metadata->display_primaries[1][1] = (AVRational){ 0, 1 }; + metadata->display_primaries[2][0] = (AVRational){ 0, 1 }; + metadata->display_primaries[2][1] = (AVRational){ 0, 1 }; + metadata->white_point[0] = (AVRational){ 0, 1 }; + metadata->white_point[1] = (AVRational){ 0, 1 }; + metadata->has_primaries = 0; + metadata->min_luminance = (AVRational){ 0, 1 }; + metadata->max_luminance = (AVRational){ 0, 1 }; + metadata->has_luminance = 0; +} + +static void content_light_metadata_reset(AVContentLightMetadata *metadata) +{ + if (!metadata) + return; + + metadata->MaxCLL = 0; + metadata->MaxFALL = 0; +} + static void codec_parameters_reset(AVCodecParameters *par) { av_freep(&par->extradata); @@ -2049,6 +2079,9 @@ static void codec_parameters_reset(AVCodecParameters *par) par->sample_aspect_ratio = (AVRational){ 0, 1 }; par->profile = FF_PROFILE_UNKNOWN; par->level = FF_LEVEL_UNKNOWN; + + master_display_metadata_reset(&par->master_display_metadata); + content_light_metadata_reset(&par->content_light_metadata); } AVCodecParameters *avcodec_parameters_alloc(void) @@ -2090,6 +2123,53 @@ int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src return 0; } +static void mastering_display_metadata_from_context(AVMasteringDisplayMetadata *metadata, + const AVCodecContext *codec) +{ + if (!metadata || !codec) + return; + + master_display_metadata_reset(metadata); + + if (codec->master_display_red_x.num != unspecified_coord && + codec->master_display_red_y.num != unspecified_coord && + codec->master_display_green_x.num != unspecified_coord && + codec->master_display_green_y.num != unspecified_coord && + codec->master_display_blue_x.num != unspecified_coord && + codec->master_display_blue_y.num != unspecified_coord && + codec->master_display_white_x.num != unspecified_coord && + codec->master_display_white_y.num != unspecified_coord) + { + metadata->display_primaries[0][0] = codec->master_display_red_x; + metadata->display_primaries[0][1] = codec->master_display_red_y; + metadata->display_primaries[1][0] = codec->master_display_green_x; + metadata->display_primaries[1][1] = codec->master_display_green_y; + metadata->display_primaries[2][0] = codec->master_display_blue_x; + metadata->display_primaries[2][1] = codec->master_display_blue_y; + metadata->white_point[0] = codec->master_display_white_x; + metadata->white_point[1] = codec->master_display_white_y; + metadata->has_primaries = 1; + } + + if (codec->master_display_min_luminance.den > 0 && + codec->master_display_max_luminance.den > 0) + { + metadata->min_luminance = codec->master_display_min_luminance; + metadata->max_luminance = codec->master_display_max_luminance; + metadata->has_luminance = 1; + } +} + +static void content_light_metadata_from_context(AVContentLightMetadata *metadata, + const AVCodecContext *codec) +{ + if (!metadata || !codec) + return; + + metadata->MaxCLL = codec->max_cll; + metadata->MaxFALL = codec->max_fall; +} + int avcodec_parameters_from_context(AVCodecParameters *par, const AVCodecContext *codec) { @@ -2118,6 +2198,9 @@ int avcodec_parameters_from_context(AVCodecParameters *par, par->chroma_location = codec->chroma_sample_location; par->sample_aspect_ratio = codec->sample_aspect_ratio; par->video_delay = codec->has_b_frames; + + mastering_display_metadata_from_context(&par->master_display_metadata, codec); + content_light_metadata_from_context(&par->content_light_metadata, codec); break; case AVMEDIA_TYPE_AUDIO: par->format = codec->sample_fmt; @@ -2147,6 +2230,53 @@ int avcodec_parameters_from_context(AVCodecParameters *par, return 0; } +static void mastering_display_metadata_to_context(AVCodecContext *codec, + const AVMasteringDisplayMetadata *metadata) +{ + if (!codec || !metadata) + return; + + if (metadata->has_primaries) + { + codec->master_display_red_x = metadata->display_primaries[0][0]; + codec->master_display_red_y = metadata->display_primaries[0][1]; + codec->master_display_green_x = metadata->display_primaries[1][0]; + codec->master_display_green_y = metadata->display_primaries[1][1]; + codec->master_display_blue_x = metadata->display_primaries[2][0]; + codec->master_display_blue_y = metadata->display_primaries[2][1]; + codec->master_display_white_x = metadata->white_point[0]; + codec->master_display_white_y = metadata->white_point[1]; + } else { + codec->master_display_red_x = (AVRational){ unspecified_coord, 1 }; + codec->master_display_red_y = (AVRational){ unspecified_coord, 1 }; + codec->master_display_green_x = (AVRational){ unspecified_coord, 1 }; + codec->master_display_green_y = (AVRational){ unspecified_coord, 1 }; + codec->master_display_blue_x = (AVRational){ unspecified_coord, 1 }; + codec->master_display_blue_y = (AVRational){ unspecified_coord, 1 }; + codec->master_display_white_x = (AVRational){ unspecified_coord, 1 }; + codec->master_display_white_y = (AVRational){ unspecified_coord, 1 }; + } + + if (metadata->has_luminance) + { + codec->master_display_min_luminance = metadata->min_luminance; + codec->master_display_max_luminance = metadata->max_luminance; + } else { + codec->master_display_min_luminance = (AVRational){ unspecified_coord, 1 }; + codec->master_display_max_luminance = (AVRational){ unspecified_coord, 1 }; + } +} + +static void content_light_metadata_to_context(AVCodecContext *codec, + const AVContentLightMetadata *metadata) +{ + if (!codec || !metadata) + return; + + codec->max_cll = metadata->MaxCLL; + codec->max_fall = metadata->MaxFALL; +} + int avcodec_parameters_to_context(AVCodecContext *codec, const AVCodecParameters *par) { @@ -2173,6 +2303,9 @@ int avcodec_parameters_to_context(AVCodecContext *codec, codec->chroma_sample_location = par->chroma_location; codec->sample_aspect_ratio = par->sample_aspect_ratio; codec->has_b_frames = par->video_delay; + + mastering_display_metadata_to_context(codec, &par->master_display_metadata); + content_light_metadata_to_context(codec, &par->content_light_metadata); break; case AVMEDIA_TYPE_AUDIO: codec->sample_fmt = par->format; diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 233c472b8f..dfe9d45f6f 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -869,43 +869,61 @@ static void mkv_write_video_color(AVIOContext *pb, const AVStream *st, put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOCOLORCHROMASITINGVERT, (ypos >> 7) + 1); } - side_data = av_stream_get_side_data(st, AV_PKT_DATA_CONTENT_LIGHT_LEVEL, - NULL); - if (side_data) { - const AVContentLightMetadata *metadata = side_data; - put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOCOLORMAXCLL, metadata->MaxCLL); - put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOCOLORMAXFALL, metadata->MaxFALL); + const AVContentLightMetadata *content_light_metadata = &par->content_light_metadata; + + if (content_light_metadata->MaxCLL <= 0 || content_light_metadata->MaxFALL <= 0) { + side_data = av_stream_get_side_data(st, AV_PKT_DATA_CONTENT_LIGHT_LEVEL, + NULL); + if (side_data) { + content_light_metadata = side_data; + } else { + content_light_metadata = NULL; + } + } + + if (content_light_metadata) { + put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOCOLORMAXCLL, content_light_metadata->MaxCLL); + put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOCOLORMAXFALL, content_light_metadata->MaxFALL); } - side_data = av_stream_get_side_data(st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, - NULL); - if (side_data) { + const AVMasteringDisplayMetadata *master_display_metadata = &par->master_display_metadata; + + if (!master_display_metadata->has_primaries || !master_display_metadata->has_luminance) { + side_data = av_stream_get_side_data(st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, + NULL); + if (side_data) { + master_display_metadata = side_data; + } else { + master_display_metadata = NULL; + } + } + + if (master_display_metadata) { ebml_master meta_element = start_ebml_master( dyn_cp, MATROSKA_ID_VIDEOCOLORMASTERINGMETA, 10 * (2 + 1 + 8)); - const AVMasteringDisplayMetadata *metadata = side_data; - if (metadata->has_primaries) { + if (master_display_metadata->has_primaries) { put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_RX, - av_q2d(metadata->display_primaries[0][0])); + av_q2d(master_display_metadata->display_primaries[0][0])); put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_RY, - av_q2d(metadata->display_primaries[0][1])); + av_q2d(master_display_metadata->display_primaries[0][1])); put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_GX, - av_q2d(metadata->display_primaries[1][0])); + av_q2d(master_display_metadata->display_primaries[1][0])); put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_GY, - av_q2d(metadata->display_primaries[1][1])); + av_q2d(master_display_metadata->display_primaries[1][1])); put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_BX, - av_q2d(metadata->display_primaries[2][0])); + av_q2d(master_display_metadata->display_primaries[2][0])); put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_BY, - av_q2d(metadata->display_primaries[2][1])); + av_q2d(master_display_metadata->display_primaries[2][1])); put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_WHITEX, - av_q2d(metadata->white_point[0])); + av_q2d(master_display_metadata->white_point[0])); put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_WHITEY, - av_q2d(metadata->white_point[1])); + av_q2d(master_display_metadata->white_point[1])); } - if (metadata->has_luminance) { + if (master_display_metadata->has_luminance) { put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_LUMINANCEMAX, - av_q2d(metadata->max_luminance)); + av_q2d(master_display_metadata->max_luminance)); put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOCOLOR_LUMINANCEMIN, - av_q2d(metadata->min_luminance)); + av_q2d(master_display_metadata->min_luminance)); } end_ebml_master(dyn_cp, meta_element); } diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 7db2e28840..074c463cee 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -1947,14 +1947,21 @@ static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc) static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track) { const uint8_t *side_data; - const AVContentLightMetadata *content_light_metadata; + const AVContentLightMetadata *content_light_metadata = &track->par->content_light_metadata; - side_data = av_stream_get_side_data(track->st, AV_PKT_DATA_CONTENT_LIGHT_LEVEL, NULL); - if (!side_data) { + if (content_light_metadata->MaxCLL <= 0 || content_light_metadata->MaxFALL <= 0) { + side_data = av_stream_get_side_data(track->st, AV_PKT_DATA_CONTENT_LIGHT_LEVEL, NULL); + if (side_data) { + content_light_metadata = (const AVContentLightMetadata*)side_data; + } else { + content_light_metadata = NULL; + } + } + + if (!content_light_metadata) { av_log(NULL, AV_LOG_VERBOSE, "Not writing 'clli' atom. No content light level info.\n"); return 0; } - content_light_metadata = (const AVContentLightMetadata*)side_data; avio_wb32(pb, 12); // size ffio_wfourcc(pb, "clli"); @@ -1973,10 +1980,18 @@ static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track) const int chroma_den = 50000; const int luma_den = 10000; const uint8_t *side_data; - const AVMasteringDisplayMetadata *metadata; + const AVMasteringDisplayMetadata *metadata = &track->par->master_display_metadata; - side_data = av_stream_get_side_data(track->st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, NULL); - metadata = (const AVMasteringDisplayMetadata*)side_data; + if (!metadata->has_primaries || !metadata->has_luminance) { + side_data = av_stream_get_side_data(track->st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, NULL); + + if (side_data) { + metadata = (const AVMasteringDisplayMetadata*)side_data; + } else { + metadata = NULL; + } + } + if (!metadata || !metadata->has_primaries || !metadata->has_luminance) { av_log(NULL, AV_LOG_VERBOSE, "Not writing 'mdcv' atom. Missing mastering metadata.\n"); return 0;