From patchwork Thu Aug 12 12:38:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc-Antoine ARNAUD X-Patchwork-Id: 29485 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:8e8b:0:0:0:0:0 with SMTP id q133csp722159iod; Thu, 12 Aug 2021 05:38:48 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxdlWbOTf0QsiOb70LoHoNSsu5BZcgkYsiIuZTGMOpncSFnSkEFaktaltx39qPk2SIIzOGc X-Received: by 2002:a17:906:1919:: with SMTP id a25mr3423149eje.161.1628771928663; Thu, 12 Aug 2021 05:38:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1628771928; cv=none; d=google.com; s=arc-20160816; b=Dp47+qUYH7Uo9WHJVcNHQfbq0Jv/75GQdi3MET7S8FxwdcaBFAKgjpFr+FrxO8SB0E 3EDyJu8VWkeExC1byEscJGH0tMgWrECK20JvdgwYyDRoC+EasluuuSZ+kjwBjVQhjq+q Nek/fpw2R45nytI/PRwv95KAY1bqu2FACT9tPfQXWbDz2XWo+/DD7mUBJFoyI822EUjj g9J9iLyH6IV6DY+z1+/JruAcnk8BVmfqpc3vnnIDxmrIotkRc45wQ+qw9kvwlXRFWVAW /+ibpCOJ8a0wskz7UQe/pEtSCLyYYE1S5aRgNmcL8buALkCs2yx6UDX+q4vtbGpEasTB f0Wg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=VnIN9D3upFkBQ6XIM+V/nb83bPE7rCpBZ7SdqvpoXps=; b=kjOWnze8qHfQSNgGjfKmreRZ79Vn5JcVMMVAtENf7k360VHa+UIIRLPyntQikTxvF8 3qUM0sAaj/fprpmsjph7S37NMP1YnkRLoSLOb2uhrG2bsXVIk3LZ/Un0miyuWb0K0oMW IhEQeWNn5AeoJBBm4aLRFevatgldFR5dZjuYxxaH5DNMNNJ4rgIdpTmzBK2FnIhaCokR i6gh0sCVRMkJFyTW3mKnjK9VNZXdj4LPSSs0q5Y+OKfNk0Yy5V17lDGOWO+WYU5As4mz Zd72MTkEfXgFXdwO2ZrSu/aCQN0egwIosbQvfEycYe2bJPTBd4m9ketOAicDujxNA4aR 1brw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@luminvent-com.20150623.gappssmtp.com header.s=20150623 header.b="uxl+u/Kk"; 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 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id yd27si3161801ejb.445.2021.08.12.05.38.48; Thu, 12 Aug 2021 05:38:48 -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=@luminvent-com.20150623.gappssmtp.com header.s=20150623 header.b="uxl+u/Kk"; 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 3AFB868A5AF; Thu, 12 Aug 2021 15:38:45 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f50.google.com (mail-wm1-f50.google.com [209.85.128.50]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id BC515680836 for ; Thu, 12 Aug 2021 15:38:38 +0300 (EEST) Received: by mail-wm1-f50.google.com with SMTP id 203-20020a1c00d40000b02902e6a4e244e4so4451923wma.4 for ; Thu, 12 Aug 2021 05:38:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=luminvent-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=riUF7C2PvjAQ4VI5XQ+w+zeFtffLNqe6ohM5QDa34Mg=; b=uxl+u/KktZs0/s8JOTcKLjrWO3u0vs5CnK3KDXOY0Mb/BpnTAn9SKhlV9tXo9lduJ9 XfyCLSHYXJ4Boy2XQL/unjoXNZafGymajwgf5hqEulHP3Cg11ZNUIdyL6Jl6oNPhEmVq EZZu4Y6FSR3P6U7K/IRiZW5mR87STWNQguod0Gv+ghGGZggRY9pSoFi6lZAIXi0WFNTz hEd5k/x6oHyVLMdYa9A4GsrG++AFA92SU8j9djsTMibjH/9DnqyhtAK848ELEuZM5CAn P64iPviwpJL9s1kmVbnFQ8bK9M3mAjtyfksEXVlbln3dC8FWhQjEzo4VIJVPLIcFr6Jk oNRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=riUF7C2PvjAQ4VI5XQ+w+zeFtffLNqe6ohM5QDa34Mg=; b=imfagDgUOfzfNyzAh1DZJXreNurCBIMr9YIbisTob73amH99sSYFtIJ1Ws3kTYJ30s hHO+4zUuCTYAS1vwa1w7f0YIAagYLUQUlfTUAnLD3KQgtVEtGk+C0Jwfus3fbVAIb5KD 6wSgehci7l9k2jmALlMUfv7THqfvPqAVxfdvudBCjw1C8f1UfxG5RggpmbHfVtiJA3Ht k9hfclxRaWXMx58/YvN7vwpU2qXMZhsBpuRBa1R/0jO6hbJL0kX/jnukfj2mCAnY6FPC MEAer/5iCgIx2qZ9OB41oKShFv7UdlGUcEid3p40XPerz7dmzYa1xaY+2JSaqIOGaO/2 elYQ== X-Gm-Message-State: AOAM532o+9vAEBxCaB/3aSRRt53wVo+ggn8A4qiG4vbQFzr+0xh+71nO jzQoz9Y/2OwCgc+yFitprkEgTDI7Z3B/7A== X-Received: by 2002:a05:600c:4784:: with SMTP id k4mr15612337wmo.166.1628771917341; Thu, 12 Aug 2021 05:38:37 -0700 (PDT) Received: from macbook-pro-de-marc-antoine.home ([2a01:cb14:915:1500:a092:292b:5d79:29b2]) by smtp.gmail.com with ESMTPSA id x13sm2842103wrq.44.2021.08.12.05.38.36 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 Aug 2021 05:38:36 -0700 (PDT) From: Marc-Antoine Arnaud To: ffmpeg-devel@ffmpeg.org Date: Thu, 12 Aug 2021 14:38:27 +0200 Message-Id: <20210812123827.13675-1-marc-antoine.arnaud@luminvent.com> X-Mailer: git-send-email 2.32.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avformat/mxf: support MCA audio information X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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: Marc-Antoine Arnaud Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: JT8yZRR49B9r --- libavformat/mxf.h | 1 + libavformat/mxfdec.c | 356 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 351 insertions(+), 6 deletions(-) diff --git a/libavformat/mxf.h b/libavformat/mxf.h index fe9c52732c..cddbcb13c9 100644 --- a/libavformat/mxf.h +++ b/libavformat/mxf.h @@ -50,6 +50,7 @@ enum MXFMetadataSetType { TaggedValue, TapeDescriptor, AVCSubDescriptor, + MCASubDescriptor, }; enum MXFFrameLayout { diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 34cbd2cd77..544895cd64 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -45,12 +45,14 @@ */ #include +#include #include "libavutil/aes.h" #include "libavutil/avstring.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/mathematics.h" #include "libavcodec/bytestream.h" +#include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/parseutils.h" #include "libavutil/timecode.h" @@ -177,6 +179,7 @@ typedef struct { int body_sid; MXFWrappingScheme wrapping; int edit_units_per_packet; /* how many edit units to read at a time (PCM, ClipWrapped) */ + int* channel_ordering; } MXFTrack; typedef struct MXFDescriptor { @@ -217,6 +220,15 @@ typedef struct MXFDescriptor { size_t coll_size; } MXFDescriptor; +typedef struct MXFMCASubDescriptor { + MXFMetadataSet meta; + UID uid; + UID mca_link_id; + UID mca_group_link_id; + UID mca_label_dictionnary_id; + char *language; +} MXFMCASubDescriptor; + typedef struct MXFIndexTableSegment { MXFMetadataSet meta; int edit_unit_byte_count; @@ -311,6 +323,10 @@ static const uint8_t mxf_system_item_key_cp[] = { 0x06,0x0e,0x2b,0x static const uint8_t mxf_system_item_key_gc[] = { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x03,0x01,0x14 }; static const uint8_t mxf_klv_key[] = { 0x06,0x0e,0x2b,0x34 }; static const uint8_t mxf_apple_coll_prefix[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x0e,0x20,0x04,0x01,0x05,0x03,0x01 }; +static const uint8_t mxf_mca_prefix[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01 }; +static const uint8_t mxf_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01 }; +static const uint8_t mxf_soundfield_group[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02 }; + /* 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 }; @@ -323,6 +339,59 @@ static const uint8_t mxf_indirect_value_utf16be[] = { 0x42,0x01,0x10,0x static const uint8_t mxf_apple_coll_max_cll[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x0e,0x20,0x04,0x01,0x05,0x03,0x01,0x01 }; static const uint8_t mxf_apple_coll_max_fall[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x0e,0x20,0x04,0x01,0x05,0x03,0x01,0x02 }; +static const uint8_t mxf_mca_label_dictionnary_id[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x01,0x00,0x00,0x00 }; +static const uint8_t mxf_mca_tag_symbol[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x02,0x00,0x00,0x00 }; +static const uint8_t mxf_mca_tag_name[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x03,0x00,0x00,0x00 }; +static const uint8_t mxf_mca_link_id[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x05,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_link_id[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0e,0x01,0x03,0x07,0x01,0x06,0x00,0x00,0x00 }; +static const uint8_t mxf_mca_rfc5646_spoken_language[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x0d,0x03,0x01,0x01,0x02,0x03,0x15,0x00,0x00 }; + +// Soundfield Groups +static const uint8_t mxf_soundfield_group_51[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x01,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_71ds[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x02,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_71sds[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x03,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_61[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x04,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_10_monoral[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x05,0x00,0x00,0x00,0x00 }; + +static const uint8_t mxf_soundfield_group_smpte_st2067_8_standard_stereo[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x01,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_dual_mono[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x02,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_discrete_numbered_sources[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x03,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_30[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x04,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_40[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x05,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_50[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x06,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_60[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x07,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_70_ds[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x08,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_lt_rt[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x09,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_51ex[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x0a,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_hearing_accessibility[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x0b,0x00,0x00,0x00 }; +static const uint8_t mxf_soundfield_group_smpte_st2067_8_visual_accessibility[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x02,0x20,0x0c,0x00,0x00,0x00 }; + +// Audio Channel definitions +static const uint8_t mxf_left_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_right_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x02,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_center_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x03,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_lfe_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x04,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_left_surround_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x05,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_right_surround_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x06,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_left_side_surround_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x07,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_right_side_surround_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x08,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_left_rear_surround_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x09,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_right_rear_surround_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0a,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_left_center_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0b,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_right_center_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0c,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_center_surround_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0d,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_hearing_impaired_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0e,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_visually_impaired_narrative_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0f,0x00,0x00,0x00,0x00 }; +static const uint8_t mxf_smpte_st2067_8_mono_one_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x20,0x01,0x00,0x00,0x00 }; +static const uint8_t mxf_smpte_st2067_8_mono_two_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x20,0x02,0x00,0x00,0x00 }; +static const uint8_t mxf_smpte_st2067_8_left_total_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x20,0x03,0x00,0x00,0x00 }; +static const uint8_t mxf_smpte_st2067_8_right_total_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x20,0x04,0x00,0x00,0x00 }; +static const uint8_t mxf_smpte_st2067_8_left_surround_total_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x20,0x05,0x00,0x00,0x00 }; +static const uint8_t mxf_smpte_st2067_8_right_surround_total_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x20,0x06,0x00,0x00,0x00 }; +static const uint8_t mxf_smpte_st2067_8_surround_audio_channel[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x20,0x07,0x00,0x00,0x00 }; + +static const uint8_t mxf_sub_descriptor[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x04,0x06,0x10,0x00,0x00 }; + static const uint8_t mxf_mastering_display_prefix[13] = { FF_MXF_MasteringDisplay_PREFIX }; static const uint8_t mxf_mastering_display_uls[4][16] = { FF_MXF_MasteringDisplayPrimaries, @@ -344,6 +413,10 @@ static void mxf_free_metadataset(MXFMetadataSet **ctx, int freectx) av_freep(&((MXFDescriptor *)*ctx)->coll); av_freep(&((MXFDescriptor *)*ctx)->sub_descriptors_refs); break; + case MCASubDescriptor: + if (((MXFMCASubDescriptor *)*ctx)->language) + av_freep(&((MXFMCASubDescriptor *)*ctx)->language); + break; case Sequence: av_freep(&((MXFSequence *)*ctx)->structural_components_refs); break; @@ -362,6 +435,8 @@ static void mxf_free_metadataset(MXFMetadataSet **ctx, int freectx) break; case Track: av_freep(&((MXFTrack *)*ctx)->name); + if (((MXFTrack *)*ctx)->channel_ordering) + av_freep(&((MXFTrack *)*ctx)->channel_ordering); break; case IndexTableSegment: seg = (MXFIndexTableSegment *)*ctx; @@ -899,6 +974,30 @@ static int mxf_read_strong_ref_array(AVIOContext *pb, UID **refs, int *count) return 0; } +static inline int mxf_read_us_ascii_string(AVIOContext *pb, int size, char** str) +{ + int ret; + size_t buf_size; + + if (size < 0) + return AVERROR(EINVAL); + + buf_size = size + 1; + av_free(*str); + *str = av_malloc(buf_size); + if (!*str) + return AVERROR(ENOMEM); + + ret = avio_get_str(pb, size, *str, buf_size); + + if (ret < 0) { + av_freep(str); + return ret; + } + + return ret; +} + static inline int mxf_read_utf16_string(AVIOContext *pb, int size, char** str, int be) { int ret; @@ -1353,11 +1452,45 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int descriptor->coll->MaxFALL = avio_rb16(pb); } } + + if (IS_KLV_KEY(uid, mxf_sub_descriptor)) { + mxf_read_strong_ref_array(pb, &descriptor->sub_descriptors_refs, &descriptor->sub_descriptors_count); + break; + } break; } return 0; } +static int mxf_read_mca_sub_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) +{ + MXFMCASubDescriptor *mca_sub_descriptor = arg; + + if (IS_KLV_KEY(uid, mxf_mca_prefix)) { + if (IS_KLV_KEY(uid, mxf_mca_label_dictionnary_id)) { + avio_read(pb, mca_sub_descriptor->mca_label_dictionnary_id, 16); + } + if (IS_KLV_KEY(uid, mxf_mca_link_id)) { + avio_read(pb, mca_sub_descriptor->mca_link_id, 16); + } + if (IS_KLV_KEY(uid, mxf_soundfield_group_link_id)) { + avio_read(pb, mca_sub_descriptor->mca_group_link_id, 16); + } + } + + if (IS_KLV_KEY(uid, mxf_mca_rfc5646_spoken_language)) { + char *str = NULL; + int ret = 0; + + if ((ret = mxf_read_us_ascii_string(pb, size, &str)) < 0) \ + return ret; + + mca_sub_descriptor->language = str; + } + + return 0; +} + static int mxf_read_indirect_value(void *arg, AVIOContext *pb, int size) { MXFTaggedValue *tagged_value = arg; @@ -2287,6 +2420,12 @@ static enum AVColorRange mxf_get_color_range(MXFContext *mxf, MXFDescriptor *des return AVCOL_RANGE_UNSPECIFIED; } +static int is_pcm(enum AVCodecID codec_id) +{ + /* we only care about "normal" PCM codecs until we get samples */ + return codec_id >= AV_CODEC_ID_PCM_S16LE && codec_id < AV_CODEC_ID_PCM_S24DAUD; +} + static int mxf_parse_structural_metadata(MXFContext *mxf) { MXFPackage *material_package = NULL; @@ -2322,7 +2461,10 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) const MXFCodecUL *pix_fmt_ul = NULL; AVStream *st; AVTimecode tc; + enum AVAudioServiceType *ast; + int* channel_ordering; int flags; + int current_channel; if (!(material_track = mxf_resolve_strong_ref(mxf, &material_package->tracks_refs[i], Track))) { av_log(mxf->fc, AV_LOG_ERROR, "could not resolve material track strong ref\n"); @@ -2681,6 +2823,185 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->internal->need_parsing = AVSTREAM_PARSE_FULL; } st->codecpar->bits_per_coded_sample = av_get_bits_per_sample(st->codecpar->codec_id); + + current_channel = 0; + + channel_ordering = av_mallocz_array(descriptor->channels, sizeof(int)); + + for (j = 0; j < descriptor->sub_descriptors_count; j++) { + MXFMCASubDescriptor *mca_sub_descriptor = mxf_resolve_strong_ref(mxf, &descriptor->sub_descriptors_refs[j], MCASubDescriptor); + if (mca_sub_descriptor == NULL) { + continue; + } + + // Soundfield group + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group)) { + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_51)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_5POINT1; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_71ds)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_7POINT1; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_71sds)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_7POINT1_WIDE; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_61)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_6POINT1; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_10_monoral)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + continue; + } + + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_standard_stereo)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_dual_mono)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_discrete_numbered_sources)) { + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_30)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_SURROUND; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_40)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_4POINT0; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_50)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_5POINT0; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_60)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_6POINT0; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_70_ds)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_7POINT0; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_lt_rt)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_51ex)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_5POINT1; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_hearing_accessibility)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + continue; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_soundfield_group_smpte_st2067_8_visual_accessibility)) { + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + continue; + } + } + + // Audio channel + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_audio_channel)) { + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_left_audio_channel)) { + channel_ordering[current_channel] = 0; + current_channel += 1; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_right_audio_channel)) { + channel_ordering[current_channel] = 1; + current_channel += 1; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_center_audio_channel)) { + channel_ordering[current_channel] = 2; + current_channel += 1; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_left_surround_audio_channel)|| + IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_left_side_surround_audio_channel)) { + channel_ordering[current_channel] = 3; + current_channel += 1; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_right_surround_audio_channel) || + IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_right_side_surround_audio_channel)) { + channel_ordering[current_channel] = 4; + current_channel += 1; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_lfe_audio_channel)) { + channel_ordering[current_channel] = 5; + current_channel += 1; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_left_center_audio_channel) || + IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_left_rear_surround_audio_channel) || + IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_center_surround_audio_channel)) { + channel_ordering[current_channel] = 6; + current_channel += 1; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_right_center_audio_channel) || + IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_right_rear_surround_audio_channel)) { + channel_ordering[current_channel] = 7; + current_channel += 1; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_hearing_impaired_audio_channel)) { + channel_ordering[current_channel] = 0; + current_channel += 1; + + ast = (enum AVAudioServiceType*)av_stream_new_side_data(st, AV_PKT_DATA_AUDIO_SERVICE_TYPE, sizeof(*ast)); + *ast = AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED; + } + if (IS_KLV_KEY(mca_sub_descriptor->mca_label_dictionnary_id, mxf_visually_impaired_narrative_audio_channel)) { + channel_ordering[current_channel] = 0; + current_channel += 1; + + ast = (enum AVAudioServiceType*)av_stream_new_side_data(st, AV_PKT_DATA_AUDIO_SERVICE_TYPE, sizeof(*ast)); + *ast = AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED; + } + + // TODO support other channels + // mxf_smpte_st2067_8_mono_one_audio_channel + // mxf_smpte_st2067_8_mono_two_audio_channel + // mxf_smpte_st2067_8_left_total_audio_channel + // mxf_smpte_st2067_8_right_total_audio_channel + // mxf_smpte_st2067_8_left_surround_total_audio_channel + // mxf_smpte_st2067_8_right_surround_total_audio_channel + // mxf_smpte_st2067_8_surround_audio_channel + } + + // set language from MCA spoken language information + // av_dict_set(&st->metadata, "language", mca_sub_descriptor->language, 0); + } + + // check if the mapping is not required + bool require_reordering = false; + for (j = 0; j < descriptor->channels; ++j) { + if (channel_ordering[j] != j) { + require_reordering = true; + break; + } + } + + if (require_reordering && is_pcm(st->codecpar->codec_id)) { + current_channel = 0; + av_log(mxf->fc, AV_LOG_INFO, "MCA Audio mapping ("); + for(j = 0; j < descriptor->channels; ++j) { + for(int k = 0; k < descriptor->channels; ++k) { + if(channel_ordering[k] == current_channel) { + av_log(mxf->fc, AV_LOG_INFO, "%d -> %d", channel_ordering[k], k); + if (current_channel != descriptor->channels - 1) + av_log(mxf->fc, AV_LOG_INFO, ", "); + current_channel += 1; + } + } + } + av_log(mxf->fc, AV_LOG_INFO, ")\n"); + + source_track->channel_ordering = channel_ordering; + } else { + av_free(channel_ordering); + } } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) { enum AVMediaType type; container_ul = mxf_get_codec_ul(mxf_data_essence_container_uls, essence_container_ul); @@ -2881,6 +3202,8 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x5c,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* VANC/VBI - SMPTE 436M */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x5e,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* MPEG2AudioDescriptor */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x64,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* DC Timed Text Descriptor */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6c,0x00 }, mxf_read_mca_sub_descriptor, sizeof(MXFMCASubDescriptor), MCASubDescriptor }, /* Soundfield Group Label Subdescriptor */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6b,0x00 }, mxf_read_mca_sub_descriptor, sizeof(MXFMCASubDescriptor), MCASubDescriptor }, /* Audio Channel Label Subdescriptor */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Static Track */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Generic Track */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x14,0x00 }, mxf_read_timecode_component, sizeof(MXFTimecodeComponent), TimecodeComponent }, @@ -3180,12 +3503,6 @@ static void mxf_compute_essence_containers(AVFormatContext *s) } } -static int is_pcm(enum AVCodecID codec_id) -{ - /* we only care about "normal" PCM codecs until we get samples */ - return codec_id >= AV_CODEC_ID_PCM_S16LE && codec_id < AV_CODEC_ID_PCM_S24DAUD; -} - static MXFIndexTable *mxf_find_index_table(MXFContext *mxf, int index_sid) { int i; @@ -3612,6 +3929,27 @@ static int mxf_set_pts(MXFContext *mxf, AVStream *st, AVPacket *pkt) return 0; } +static void mxf_audio_remapping(int* channel_ordering, uint8_t* data, int size, int sample_size, int channels) +{ + int sample_offset = channels * sample_size; + int number_of_samples = size / sample_offset; + uint8_t* tmp = av_malloc(sample_offset); + uint8_t* data_ptr = data; + + for (int sample = 0; sample < number_of_samples; ++sample) { + memcpy(tmp, data_ptr, sample_offset); + + for (int channel = 0; channel < channels; ++channel) { + for (int sample_index = 0; sample_index < sample_size; ++sample_index) { + data_ptr[sample_size * channel_ordering[channel] + sample_index] = tmp[sample_size * channel + sample_index]; + } + } + + data_ptr += sample_offset; + } + av_free(tmp); +} + static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) { KLVPacket klv; @@ -3726,6 +4064,12 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) return ret; } + // for audio, process audio remapping if MCA label requires it + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && track->channel_ordering != NULL) { + int byte_per_sample = st->codecpar->bits_per_coded_sample / 8; + mxf_audio_remapping(track->channel_ordering, pkt->data, pkt->size, byte_per_sample, st->codecpar->channels); + } + /* seek for truncated packets */ avio_seek(s->pb, klv.next_klv, SEEK_SET);