/* Copyright (c) MediaArea.net SARL. All Rights Reserved. * * Use of this source code is governed by a BSD-style license that can * be found in the License.html file in the root of the source tree. */ //--------------------------------------------------------------------------- // Pre-compilation #include "MediaInfo/PreComp.h" #ifdef __BORLANDC__ #pragma hdrstop #endif //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Setup.h" //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #if defined(MEDIAINFO_RIFF_YES) || defined(MEDIAINFO_MXF_YES) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Audio/File_DolbyAudioMetadata.h" #include "MediaInfo/TimeCode.h" #include "tinyxml2.h" #include "ThirdParty/base64/base64.h" using namespace tinyxml2; using namespace std; //--------------------------------------------------------------------------- namespace MediaInfoLib { //*************************************************************************** // Info //*************************************************************************** static const char* metadata_segment_Name[] = { "End", "Dolby E Metadata", NULL, "Dolby Digital Metadata", NULL, NULL, NULL, "Dolby Digital Plus Metadata", "Audio Info", "Dolby Atmos Metadata", "Dolby Atmos Supplemental Metadata", }; static size_t metadata_segment_Name_Size=sizeof(metadata_segment_Name)/sizeof(const char*); static const char* binaural_render_mode_Name[] = { "Off", "Near", "Far", "Mid", "Not Indicated (Mid)", }; static size_t binaural_render_mode_Name_Size=sizeof(binaural_render_mode_Name)/sizeof(const char*); static const char* warp_mode_Name[] = { "Direct Render", "Direct Render with room balance", "Dolby Pro Logic IIx", "Standard (Lo/Ro)", NULL, }; static size_t warp_mode_Name_Size=sizeof(warp_mode_Name)/sizeof(const char*); static const char* trim_bypass_Name[] = { "Trim applied", "Trim ignored", "Not Indicated", NULL, }; static const float32 frames_per_second_Values[] = { 0, 24/1.001, 24, 25, 30/1.001, // Drop frame 30/1.001, 30, }; static size_t frames_per_second_Size=sizeof(frames_per_second_Values)/sizeof(float32); static const char* downmix_type_5to2_Values[] = { "Not indicated (Lo/Ro)", "Lo/Ro", "Lt/Rt (Dolby Pro Logic)", "Lt/Rt (Dolby Pro Logic II)", "Direct stereo render", }; static size_t downmix_type_5to2_Size=sizeof(downmix_type_5to2_Values)/sizeof(const char*); static const char* phaseshift_90deg_5to2_Values[] = { "w/o Phase 90", "w/ Phase 90", }; static size_t phaseshift_90deg_5to2_Size=sizeof(phaseshift_90deg_5to2_Values)/sizeof(const char*); //--------------------------------------------------------------------------- void Merge_FillTimeCode(File__Analyze& In, const string& Prefix, const TimeCode& TC_Time, float FramesPerSecondF, bool DropFrame, TimeCode::rounding Rounding=TimeCode::Nearest, int32u Frequency=0); //*************************************************************************** // Constructor/Destructor //*************************************************************************** //--------------------------------------------------------------------------- File_DolbyAudioMetadata::File_DolbyAudioMetadata() { //Configuration StreamSource=IsContainerExtra; //In IsXML=false; //Out HasSegment9=false; } //*************************************************************************** // Buffer - File header //*************************************************************************** //--------------------------------------------------------------------------- bool File_DolbyAudioMetadata::FileHeader_Begin() { if (!IsXML) return true; XMLDocument document; if (!FileHeader_Begin_XML(document)) { return false; } XMLElement* Base64DbmdWrapper=document.FirstChildElement(); if (!Base64DbmdWrapper || strcmp(Base64DbmdWrapper->Name(), "Base64DbmdWrapper")) { return false; } if (const char* Text=Base64DbmdWrapper->GetText()) { const int8u* Save_Buffer=Buffer; size_t Save_Buffer_Size=Buffer_Size; string BufferS = Base64::decode(Text); Buffer=(const int8u*)BufferS.c_str(); Element_Size=Buffer_Size=BufferS.size(); Element_Begin1("Header"); int32u Name, Size; Get_C4 (Name, "Name"); Get_L4 (Size, "Size"); if (Name==0x64626D64 && Size==Element_Size-Element_Offset) Read_Buffer_Continue(); else Skip_XX(Element_Size-Element_Offset, "Unknown"); Buffer=Save_Buffer; Element_Offset=Element_Size=Buffer_Size=Save_Buffer_Size; } return true; } //*************************************************************************** // Buffer - Global //*************************************************************************** //--------------------------------------------------------------------------- void File_DolbyAudioMetadata::Read_Buffer_Continue() { Accept("DolbyAudioMetadata"); Stream_Prepare(Stream_Audio); //Parsing int32u version; Get_L4 (version, "version"); if ((version>>24)>1) { Skip_XX(Element_Size-Element_Offset, "Data"); return; } while(Element_Offsetmetadata_segment_size_Max) metadata_segment_size=metadata_segment_size_Max; size_t End=Element_Offset+metadata_segment_size; Element_Begin1("metadata_segment_payload"); switch (metadata_segment_id) { case 9: Dolby_Atmos_Metadata_Segment(); break; case 10: Dolby_Atmos_Supplemental_Metadata_Segment(); break; default:; } Skip_XX(End-Element_Offset, "Unknown"); Element_End0(); Skip_L1( "metadata_segment_checksum"); Element_End0(); } Finish(); } //*************************************************************************** // Elements //*************************************************************************** //--------------------------------------------------------------------------- void File_DolbyAudioMetadata::Dolby_Atmos_Metadata_Segment() { HasSegment9=true; // Needed for flagging Dolby Atmos Master ADM profile Fill(Stream_Audio, 0, "Dolby_Atmos_Metadata", "Yes"); //Parsing Ztring content_creation_tool; int32u content_creation_tool_version, first_action_time_SS; int8u warp_mode, frames_per_second, downmix_type_5to2, phaseshift_90deg_5to2, first_action_time_HH, first_action_time_MM; Skip_String(32, "reserved"); Element_Begin1("content_information"); Get_UTF8(64, content_creation_tool, "content_creation_tool"); Get_B3 (content_creation_tool_version, "content_creation_tool_version"); Skip_XX(12, "Unknown"); BS_Begin(); Skip_S1(4, "Unknown"); Get_S1 (4, frames_per_second, "frames_per_second"); Param_Info1C(frames_per_second>16)+__T('.') +Ztring::ToZtring((content_creation_tool_version>>8)&0xFF)+__T('.') +Ztring::ToZtring(content_creation_tool_version&0xFF); Fill(Stream_Audio, 0, "Dolby_Atmos_Metadata Encoded_Application", content_creation_tool+__T(", ")+Version); string Downmix_5to2; if (downmix_type_5to2 && downmix_type_5to2 TrimAutoSet; bool TrimNotAlwaysManual=false; Fill(Stream_Audio, 0, "Dolby_Atmos_Metadata TrimMode", "Yes"); for (int cfg=0; cfg<9; cfg++) { Element_Begin1("config_trim"); bool auto_trim; BS_Begin(); Skip_S1(7, "reserved"); Get_SB ( auto_trim, "auto_trim"); BS_End(); string FieldPrefix="Dolby_Atmos_Metadata TrimMode TrimMode"+Ztring::ToZtring(cfg).To_UTF8()+'i'; Fill(Stream_Audio, 0, FieldPrefix.c_str(), auto_trim?"Automatic":"Manual"); TrimAutoSet.set(auto_trim); if (auto_trim) { switch (cfg) { case 1: // 5.1 case 2: // 7.1 case 4: // 5.1.2 break; default: Fill_SetOptions(Stream_Audio, 0, FieldPrefix.c_str(), "N N Y"); } Skip_XX(14, "reserved"); Fill(Stream_Audio, 0, (FieldPrefix+" Trim_Center").c_str(), "Automatic"); Fill_SetOptions(Stream_Audio, 0, (FieldPrefix+" Trim_Center").c_str(), "N NTY"); Fill(Stream_Audio, 0, (FieldPrefix+" Trim_Surround").c_str(), "Automatic"); Fill_SetOptions(Stream_Audio, 0, (FieldPrefix+" Trim_Surround").c_str(), "N NTY"); Fill(Stream_Audio, 0, (FieldPrefix+" Trim_Height").c_str(), "Automatic"); Fill_SetOptions(Stream_Audio, 0, (FieldPrefix+" Trim_Height").c_str(), "N NTY"); } else { float center_trim, surround_trim, height_trim; int8u frontback_balance_ohfl_amount, frontback_balance_lstr_amount; bool frontback_balance_ohfl_direction, frontback_balance_lstr_direction; Get_LF4 (center_trim, "center_trim"); Get_LF4 (surround_trim, "surround_trim"); Get_LF4 (height_trim, "height_trim"); BS_Begin(); Get_SB ( frontback_balance_ohfl_direction, "frontback_balance_ohfl_direction"); Get_S1 (7, frontback_balance_ohfl_amount, "frontback_balance_ohfl_amount"); Get_SB ( frontback_balance_lstr_direction, "frontback_balance_lstr_direction"); Get_S1 (7, frontback_balance_lstr_amount, "frontback_balance_lstr_amount"); BS_End(); if (center_trim) { Fill(Stream_Audio, 0, (FieldPrefix+" Trim_Center").c_str(), center_trim); Fill_SetOptions(Stream_Audio, 0, (FieldPrefix+" Trim_Center").c_str(), "N NTY"); Fill(Stream_Audio, 0, (FieldPrefix+" Trim_Center/String").c_str(), Ztring::ToZtring(center_trim, 2)+__T(" dB")); Fill_SetOptions(Stream_Audio, 0, (FieldPrefix+" Trim_Center/String").c_str(), "Y NTN"); } if (surround_trim) { Fill(Stream_Audio, 0, (FieldPrefix+" Trim_Surround").c_str(), surround_trim); Fill_SetOptions(Stream_Audio, 0, (FieldPrefix+" Trim_Surround").c_str(), "N NTY"); Fill(Stream_Audio, 0, (FieldPrefix+" Trim_Surround/String").c_str(), Ztring::ToZtring(surround_trim, 2)+__T(" dB")); Fill_SetOptions(Stream_Audio, 0, (FieldPrefix+" Trim_Surround/String").c_str(), "Y NTN"); } if (height_trim) { Fill(Stream_Audio, 0, (FieldPrefix+" Trim_Height").c_str(), height_trim); Fill_SetOptions(Stream_Audio, 0, (FieldPrefix+" Trim_Height").c_str(), "N NTY"); Fill(Stream_Audio, 0, (FieldPrefix+" Trim_Height/String").c_str(), Ztring::ToZtring(height_trim, 2)+__T(" dB")); Fill_SetOptions(Stream_Audio, 0, (FieldPrefix+" Trim_Height/String").c_str(), "Y NTN"); } if (frontback_balance_ohfl_amount) { float32 frontback_balance_ohfl=((float32)frontback_balance_ohfl_amount)/127; if (frontback_balance_ohfl_direction) frontback_balance_ohfl=-frontback_balance_ohfl; Fill(Stream_Audio, 0, (FieldPrefix+" Balance_FrontBackOverheadFloor").c_str(), frontback_balance_ohfl, 2); } if (frontback_balance_lstr_amount) { float32 frontback_balance_lstr=((float32)frontback_balance_lstr_amount)/127; if (frontback_balance_lstr_direction) frontback_balance_lstr=-frontback_balance_lstr; Fill(Stream_Audio, 0, (FieldPrefix+" Balance_FrontBackListener").c_str(), frontback_balance_lstr, 2); } } Element_End0(); } ZtringList List; List.Separator_Set(0, __T(" / ")); if (TrimAutoSet[0]) List.push_back(__T("Manual")); if (TrimAutoSet[1]) { List.push_back(__T("Automatic")); if (!TrimAutoSet[0]) { for (int cfg=0; cfg<9; cfg++) { Fill_SetOptions(Stream_Audio, 0, (string("Dolby_Atmos_Metadata TrimMode TrimMode")+Ztring::ToZtring(cfg).To_UTF8()+'i').c_str(), "N NTY"); } } } Fill(Stream_Audio, 0, "Dolby_Atmos_Metadata TrimMode", List.Read(), true); if (object_count) { BS_Begin(); // Fill(Stream_Audio, 0, ("Dolby_Atmos_Metadata Objects"), "Yes"); for (int obj = 0; obj BinauralRenderMode_Diffs; BinauralRenderModes.Separator_Set(0, " + "); for (size_t i=0; i