From patchwork Sat Sep 24 05:19:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Robertson X-Patchwork-Id: 697 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.140.66 with SMTP id o63csp931208vsd; Fri, 23 Sep 2016 22:37:07 -0700 (PDT) X-Received: by 10.194.188.113 with SMTP id fz17mr11595459wjc.179.1474695427444; Fri, 23 Sep 2016 22:37:07 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id gi8si1690172wjb.58.2016.09.23.22.37.06; Fri, 23 Sep 2016 22:37:07 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@strobe-cc.20150623.gappssmtp.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id EBC08689C38; Sat, 24 Sep 2016 08:36:47 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pa0-f67.google.com (mail-pa0-f67.google.com [209.85.220.67]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id CCE24689AE9 for ; Sat, 24 Sep 2016 08:36:40 +0300 (EEST) Received: by mail-pa0-f67.google.com with SMTP id oz2so5910295pac.0 for ; Fri, 23 Sep 2016 22:36:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=strobe-cc.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=xI5ZI6aQvv0Xmn9gHGdScliJVIP/0gGsu9x1S4cQitg=; b=j/H5m8d38zBhz1tvAgHb8VJnAwoMGm9LitiqhHBkX2d+oYKMM8FB4ex5u0496641so zO+tOKw3KMWY8WFNvlEI93VbQq86VYvBCBRiSClhneRjF5n+oweOUV5LMOTFn2lh4enz mi02HNCs6R6w4N/93IG46xsknUrmEzAvQeSCHjHyATuUSW4aCB9Rfx07iSLUO7GWHlM/ EQswwtiL/2QNoUuKTbGT9j1TgoMYuimoH5gqCqLF9YrZRnBxQDh7iwPXMx5tit40POKB TWyQCqhm/MnMlLM2YCGzGv21KkISy4SvV31N6ZUCiWQHQ3/hZuxyZlnvmD6CgatxLm+o upQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xI5ZI6aQvv0Xmn9gHGdScliJVIP/0gGsu9x1S4cQitg=; b=KpigoCcChPH9/5o9lmSqIV8Lf8aQFbff++I9+eJzJlVT9dd5pX1uA1PmlzQTyBvC/+ qiyIsIQsxoeAa3hefwp99Lly9dd1J7uL7uB7YI2C3CqBdbUqICUmykbEHKECQXaIqkfb sCr0kCe/88P0Pr24//VNfWK8khDINeFO546J7No72CFGOa+hIxv1HwJN4tgjAMF+5Glb Ea0Sx3ahFGmiosjrjwApdzRk/zMv3+/WAwGqIcECXtMwqLBB0w0aVvJNUlHCzwflYMhg h62A8fJ8F2P2sbEk1lG/MayBr63IAQMTDPBLPYNz3BLupF54jkStmn4AfWaNXQDD3aqn U7GA== X-Gm-Message-State: AE9vXwOzqsYVCfTc+9FUTWUzvGWBkkecw5MnVlVVJAVJULt5ogEQBnmdQAR1tQplf+1MSA== X-Received: by 10.66.161.195 with SMTP id xu3mr18776618pab.68.1474694368393; Fri, 23 Sep 2016 22:19:28 -0700 (PDT) Received: from strobe.sbo.corp.google.com ([100.106.156.15]) by smtp.gmail.com with ESMTPSA id ic2sm15093355pad.24.2016.09.23.22.19.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 23 Sep 2016 22:19:27 -0700 (PDT) From: Steven Robertson To: ffmpeg-devel@ffmpeg.org Date: Fri, 23 Sep 2016 22:19:04 -0700 Message-Id: <1474694344-31167-2-git-send-email-steven@strobe.cc> X-Mailer: git-send-email 2.8.0.rc3.226.g39d4020 In-Reply-To: <1474694344-31167-1-git-send-email-steven@strobe.cc> References: <1474694344-31167-1-git-send-email-steven@strobe.cc> Subject: [FFmpeg-devel] [PATCH 2/2] [avformat/mxf] Add support for ST 2084 / ST 2067-21 mastering 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 Cc: Steven Robertson MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Steven Robertson --- libavformat/mxfdec.c | 132 ++++++++++++++++++++++++++++++++++++++++----------- libavformat/mxfenc.c | 43 ++++++++++++++++- 2 files changed, 145 insertions(+), 30 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index d012e41..761aa1f 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -52,6 +52,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/parseutils.h" #include "libavutil/timecode.h" +#include "libavutil/mastering_display_metadata.h" #include "avformat.h" #include "internal.h" #include "mxf.h" @@ -191,6 +192,10 @@ typedef struct MXFDescriptor { UID color_trc_ul; UID color_primaries_ul; UID color_space_ul; + uint16_t mastering_primaries[3][2]; + uint16_t mastering_white_point[2]; + uint32_t mastering_max_luminance; + uint32_t mastering_min_luminance; } MXFDescriptor; typedef struct MXFIndexTableSegment { @@ -284,22 +289,26 @@ typedef struct MXFMetadataReadTableEntry { static int mxf_read_close(AVFormatContext *s); /* partial keys to match */ -static const uint8_t mxf_header_partition_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02 }; -static const uint8_t mxf_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01 }; -static const uint8_t mxf_avid_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0e,0x04,0x03,0x01 }; -static const uint8_t mxf_canopus_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x0a,0x0e,0x0f,0x03,0x01 }; -static const uint8_t mxf_system_item_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x03,0x01,0x04 }; -static const uint8_t mxf_klv_key[] = { 0x06,0x0e,0x2b,0x34 }; +static const uint8_t mxf_header_partition_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02 }; +static const uint8_t mxf_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01 }; +static const uint8_t mxf_avid_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0e,0x04,0x03,0x01 }; +static const uint8_t mxf_canopus_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x0a,0x0e,0x0f,0x03,0x01 }; +static const uint8_t mxf_system_item_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x03,0x01,0x04 }; +static const uint8_t mxf_klv_key[] = { 0x06,0x0e,0x2b,0x34 }; /* complete keys to match */ -static const uint8_t mxf_crypto_source_container_ul[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x02,0x02,0x00,0x00,0x00 }; -static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 }; -static const uint8_t mxf_encrypted_essence_container[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 }; -static const uint8_t mxf_random_index_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x11,0x01,0x00 }; -static const uint8_t mxf_sony_mpeg4_extradata[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0e,0x06,0x06,0x02,0x02,0x01,0x00,0x00 }; -static const uint8_t mxf_avid_project_name[] = { 0xa5,0xfb,0x7b,0x25,0xf6,0x15,0x94,0xb9,0x62,0xfc,0x37,0x17,0x49,0x2d,0x42,0xbf }; -static const uint8_t mxf_jp2k_rsiz[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x01,0x00 }; -static const uint8_t mxf_indirect_value_utf16le[] = { 0x4c,0x00,0x02,0x10,0x01,0x00,0x00,0x00,0x00,0x06,0x0e,0x2b,0x34,0x01,0x04,0x01,0x01 }; -static const uint8_t mxf_indirect_value_utf16be[] = { 0x42,0x01,0x10,0x02,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x2b,0x34,0x01,0x04,0x01,0x01 }; +static const uint8_t mxf_crypto_source_container_ul[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x02,0x02,0x00,0x00,0x00 }; +static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 }; +static const uint8_t mxf_encrypted_essence_container[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 }; +static const uint8_t mxf_random_index_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x11,0x01,0x00 }; +static const uint8_t mxf_sony_mpeg4_extradata[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0e,0x06,0x06,0x02,0x02,0x01,0x00,0x00 }; +static const uint8_t mxf_avid_project_name[] = { 0xa5,0xfb,0x7b,0x25,0xf6,0x15,0x94,0xb9,0x62,0xfc,0x37,0x17,0x49,0x2d,0x42,0xbf }; +static const uint8_t mxf_jp2k_rsiz[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x01,0x00 }; +static const uint8_t mxf_indirect_value_utf16le[] = { 0x4c,0x00,0x02,0x10,0x01,0x00,0x00,0x00,0x00,0x06,0x0e,0x2b,0x34,0x01,0x04,0x01,0x01 }; +static const uint8_t mxf_indirect_value_utf16be[] = { 0x42,0x01,0x10,0x02,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x2b,0x34,0x01,0x04,0x01,0x01 }; +static const uint8_t mxf_mastering_display_primaries_ul[] = { 0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x20,0x04,0x01,0x01,0x01,0x00,0x00 }; +static const uint8_t mxf_mastering_display_white_point_ul[] = { 0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x20,0x04,0x01,0x01,0x02,0x00,0x00 }; +static const uint8_t mxf_mastering_display_max_luminance_ul[] = { 0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x20,0x04,0x01,0x01,0x03,0x00,0x00 }; +static const uint8_t mxf_mastering_display_min_luminance_ul[] = { 0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x20,0x04,0x01,0x01,0x04,0x00,0x00 }; #define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y))) @@ -968,6 +977,20 @@ static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor) ff_mxf_decode_pixel_layout(layout, &descriptor->pix_fmt); } +/* + * Match an uid independently of the version byte and up to len common bytes + * Returns: boolean + */ +static int mxf_match_uid(const UID key, const UID uid, int len) +{ + int i; + for (i = 0; i < len; i++) { + if (i != 7 && key[i] != uid[i]) + return 0; + } + return 1; +} + static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFDescriptor *descriptor = arg; @@ -1059,6 +1082,24 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int rsiz == FF_PROFILE_JPEG2000_DCINEMA_4K) descriptor->pix_fmt = AV_PIX_FMT_XYZ12; } + if (mxf_match_uid(uid, mxf_mastering_display_primaries_ul, 16)) { + descriptor->mastering_primaries[0][0] = avio_rb16(pb); + descriptor->mastering_primaries[0][1] = avio_rb16(pb); + descriptor->mastering_primaries[1][0] = avio_rb16(pb); + descriptor->mastering_primaries[1][1] = avio_rb16(pb); + descriptor->mastering_primaries[2][0] = avio_rb16(pb); + descriptor->mastering_primaries[2][1] = avio_rb16(pb); + } + if (mxf_match_uid(uid, mxf_mastering_display_white_point_ul, 16)) { + descriptor->mastering_white_point[0] = avio_rb16(pb); + descriptor->mastering_white_point[1] = avio_rb16(pb); + } + if (mxf_match_uid(uid, mxf_mastering_display_max_luminance_ul, 16)) { + descriptor->mastering_max_luminance = avio_rb32(pb); + } + if (mxf_match_uid(uid, mxf_mastering_display_min_luminance_ul, 16)) { + descriptor->mastering_min_luminance = avio_rb32(pb); + } break; } return 0; @@ -1094,20 +1135,6 @@ static int mxf_read_tagged_value(void *arg, AVIOContext *pb, int tag, int size, return 0; } -/* - * Match an uid independently of the version byte and up to len common bytes - * Returns: boolean - */ -static int mxf_match_uid(const UID key, const UID uid, int len) -{ - int i; - for (i = 0; i < len; i++) { - if (i != 7 && key[i] != uid[i]) - return 0; - } - return 1; -} - static const MXFCodecUL *mxf_get_codec_ul(const MXFCodecUL *uls, UID *uid) { while (uls->uid[0]) { @@ -1868,6 +1895,8 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) const MXFCodecUL *color_trc_ul = NULL; const MXFCodecUL *color_primaries_ul = NULL; const MXFCodecUL *color_space_ul = NULL; + int has_mastering_primaries; + int has_mastering_luminance; AVStream *st; AVTimecode tc; int flags; @@ -2114,6 +2143,51 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) if (color_trc_ul->uid[0]) st->codecpar->color_trc = color_trc_ul->id; + has_mastering_primaries = + descriptor->mastering_primaries[0][0] > 0 && descriptor->mastering_primaries[0][1] > 0 && + descriptor->mastering_primaries[1][0] > 0 && descriptor->mastering_primaries[1][1] > 0 && + descriptor->mastering_primaries[2][0] > 0 && descriptor->mastering_primaries[2][1] > 0 && + descriptor->mastering_white_point[0] > 0 && descriptor->mastering_white_point[1] > 0; + has_mastering_luminance = descriptor->mastering_max_luminance > 0; + + if (has_mastering_primaries || has_mastering_luminance) { + AVMasteringDisplayMetadata *metadata = + (AVMasteringDisplayMetadata*) av_stream_new_side_data( + st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, + sizeof(AVMasteringDisplayMetadata)); + if (!metadata) + return AVERROR(ENOMEM); + memset(metadata, 0, sizeof(AVMasteringDisplayMetadata)); + if (has_mastering_primaries) { + const int chroma_den = 50000; + metadata->display_primaries[0][0] = av_make_q( + descriptor->mastering_primaries[0][0], chroma_den); + metadata->display_primaries[0][1] = av_make_q( + descriptor->mastering_primaries[0][1], chroma_den); + metadata->display_primaries[1][0] = av_make_q( + descriptor->mastering_primaries[1][0], chroma_den); + metadata->display_primaries[1][1] = av_make_q( + descriptor->mastering_primaries[1][1], chroma_den); + metadata->display_primaries[2][0] = av_make_q( + descriptor->mastering_primaries[2][0], chroma_den); + metadata->display_primaries[2][1] = av_make_q( + descriptor->mastering_primaries[2][1], chroma_den); + metadata->white_point[0] = av_make_q( + descriptor->mastering_white_point[0], chroma_den); + metadata->white_point[1] = av_make_q( + descriptor->mastering_white_point[1], chroma_den); + metadata->has_primaries = 1; + } + if (has_mastering_luminance) { + const int luma_den = 10000; + metadata->max_luminance = av_make_q( + descriptor->mastering_max_luminance, luma_den); + metadata->min_luminance = av_make_q( + descriptor->mastering_min_luminance, luma_den); + metadata->has_luminance = 1; + } + } + st->need_parsing = AVSTREAM_PARSE_HEADERS; if (material_track->sequence->origin) { av_dict_set_int(&st->metadata, "material_track_origin", material_track->sequence->origin, 0); diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index eb77f3a..8222b58 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -34,6 +34,7 @@ * SMPTE 422M Mapping JPEG 2000 Codestreams into the MXF Generic Container * SMPTE RP210: SMPTE Metadata Dictionary * SMPTE RP224: Registry of SMPTE Universal Labels + * SMPTE 2067-21: Interoperable Master Format - Application #2E */ #include @@ -46,6 +47,7 @@ #include "libavutil/avassert.h" #include "libavutil/pixdesc.h" #include "libavutil/time_internal.h" +#include "libavutil/mastering_display_metadata.h" #include "libavcodec/bytestream.h" #include "libavcodec/dnxhddata.h" #include "libavcodec/h264.h" @@ -448,6 +450,11 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = { // Wave Audio Essence Descriptor { 0x3D09, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x02,0x03,0x03,0x05,0x00,0x00,0x00}}, /* Average Bytes Per Second */ { 0x3D0A, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x02,0x03,0x02,0x01,0x00,0x00,0x00}}, /* Block Align */ + // Dynamic Tags + { 0xFF01, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x20,0x04,0x01,0x01,0x01,0x00,0x00}}, /* Mastering Display Primaries */ + { 0xFF02, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x20,0x04,0x01,0x01,0x02,0x00,0x00}}, /* Mastering Display White Point Chromaticity */ + { 0xFF03, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x20,0x04,0x01,0x01,0x03,0x00,0x00}}, /* Mastering Display Maximum Luminance */ + { 0xFF04, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x20,0x04,0x01,0x01,0x04,0x00,0x00}}, /* Mastering Display Minimum Luminance */ }; static const MXFLocalTagPair mxf_user_comments_local_tag[] = { @@ -1018,7 +1025,9 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke const MXFCodecUL* color_space_ul; int stored_height = (st->codecpar->height+15)/16*16; int display_height; - int f1, f2; + int f1, f2, side_data_size; + const uint8_t *side_data; + const AVMasteringDisplayMetadata *mastering_metadata = NULL; unsigned desc_size = size+8+8+8+8+8+8+8+5+16+4+12+20+5; if (sc->interlaced && sc->field_dominance) desc_size += 5; @@ -1035,6 +1044,16 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke if (color_space_ul->uid[0]) desc_size += 20; + side_data = av_stream_get_side_data( + st, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, &side_data_size); + if (side_data_size == sizeof(AVMasteringDisplayMetadata)) { + mastering_metadata = (const AVMasteringDisplayMetadata*)side_data; + if (mastering_metadata->has_primaries) + desc_size += 16 + 8; + if (mastering_metadata->has_luminance) + desc_size += 8 + 8; + } + mxf_write_generic_desc(s, st, key, desc_size); mxf_write_local_tag(pb, 4, 0x3203); @@ -1127,6 +1146,28 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke mxf_write_local_tag(pb, 16, 0x321A); avio_write(pb, color_space_ul->uid, 16); } + if (mastering_metadata) { + if (mastering_metadata->has_primaries) { + AVRational chroma_factor = av_make_q(50000, 1); + mxf_write_local_tag(pb, 12, 0xFF01); + avio_wb16(pb, (uint16_t) av_q2d(av_mul_q(mastering_metadata->display_primaries[0][0], chroma_factor))); + avio_wb16(pb, (uint16_t) av_q2d(av_mul_q(mastering_metadata->display_primaries[0][1], chroma_factor))); + avio_wb16(pb, (uint16_t) av_q2d(av_mul_q(mastering_metadata->display_primaries[1][0], chroma_factor))); + avio_wb16(pb, (uint16_t) av_q2d(av_mul_q(mastering_metadata->display_primaries[1][1], chroma_factor))); + avio_wb16(pb, (uint16_t) av_q2d(av_mul_q(mastering_metadata->display_primaries[2][0], chroma_factor))); + avio_wb16(pb, (uint16_t) av_q2d(av_mul_q(mastering_metadata->display_primaries[2][1], chroma_factor))); + mxf_write_local_tag(pb, 4, 0xFF02); + avio_wb16(pb, (uint16_t) av_q2d(av_mul_q(mastering_metadata->white_point[0], chroma_factor))); + avio_wb16(pb, (uint16_t) av_q2d(av_mul_q(mastering_metadata->white_point[1], chroma_factor))); + } + if (mastering_metadata->has_luminance) { + AVRational luma_factor = av_make_q(10000, 1); + mxf_write_local_tag(pb, 4, 0xFF03); + avio_wb32(pb, (uint32_t) av_q2d(av_mul_q(mastering_metadata->max_luminance, luma_factor))); + mxf_write_local_tag(pb, 4, 0xFF04); + avio_wb32(pb, (uint32_t) av_q2d(av_mul_q(mastering_metadata->min_luminance, luma_factor))); + } + } } static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)