/* 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. */ //--------------------------------------------------------------------------- // https://developer.dolby.com/globalassets/professional/dolby-e/dolby-e-high-level-frame-description.pdf //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // Pre-compilation #include "MediaInfo/PreComp.h" #ifdef __BORLANDC__ #pragma hdrstop #endif //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Setup.h" //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #if defined(MEDIAINFO_DOLBYE_YES) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Audio/File_DolbyE.h" #include "MediaInfo/Audio/File_Aac.h" #include #if !defined(INT8_MAX) #define INT8_MAX (127) #endif //!defined(INT8_MAX) #if !defined(INT8_MIN) #define INT8_MIN (-128) #endif //!defined(INT8_MIN) using namespace std; //--------------------------------------------------------------------------- namespace MediaInfoLib { //*************************************************************************** // Info //*************************************************************************** //--------------------------------------------------------------------------- extern const float64 AC3_dynrng[]; extern const float64 AC3_compr[]; extern const int16u AC3_BitRate[]; extern const int8u AC3_Channels[]; extern const char* AC3_Surround[]; extern const char* AC3_Mode[]; extern const char* AC3_Mode_String[]; extern const char* AC3_ChannelPositions[]; extern const char* AC3_ChannelPositions2[]; extern const char* AC3_ChannelLayout_lfeoff[]; extern const char* AC3_ChannelLayout_lfeon[]; extern const char* AC3_roomtyp[]; extern const char* AC3_dmixmod[]; extern string AC3_Level_Value(int8u Index, float Start, float Multiplier); extern void AC3_Level_Fill(File__Analyze* A, size_t StreamPos, int8u Index, float Start, float Multiplier, const char* Name); extern string AC3_dynrngprof_Get(int8u Value); //*************************************************************************** // Utils //*************************************************************************** //--------------------------------------------------------------------------- //CRC computing, with incomplete first and last bytes //Inspired by http://zorc.breitbandkatze.de/crc.html extern const int16u CRC_16_Table[256]; int16u CRC_16_Compute(const int8u* Buffer_Begin, size_t Buffer_Size, int8u SkipBits_Begin, int8u SkipBits_End) { int16u CRC_16=0x0000; const int8u* Buffer=Buffer_Begin; const int8u* Buffer_End=Buffer+Buffer_Size; if (SkipBits_End) Buffer_End--; //Not handling completely the last byte //First partial byte if (SkipBits_Begin) { for (int8u Mask=(1<<(7-SkipBits_Begin)); Mask; Mask>>=1) { bool NewBit=(CRC_16&0x8000)?true:false; CRC_16<<=1; if ((*Buffer)&Mask) NewBit=!NewBit; if (NewBit) CRC_16^=0x8005; } Buffer++; } //Complete bytes while (Buffer>8)^(*Buffer)]; Buffer++; } //Last partial byte if (SkipBits_End) { for (int8u Mask=0x80; Mask>(1<<(SkipBits_End-1)); Mask>>=1) { bool NewBit=(CRC_16&0x8000)?true:false; CRC_16<<=1; if ((*Buffer)&Mask) NewBit=!NewBit; if (NewBit) CRC_16^=0x8005; } Buffer++; } return CRC_16; } //*************************************************************************** // Infos //*************************************************************************** //--------------------------------------------------------------------------- static const int8u DolbyE_Programs[64]= {2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 8, 1, 2, 3, 3, 4, 5, 6, 1, 2, 3, 4, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //--------------------------------------------------------------------------- static const int8u DolbyE_Channels[64]= {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //--------------------------------------------------------------------------- const int8u DolbyE_Channels_PerProgram(int8u program_config, int8u program) { switch (program_config) { case 0 : switch (program) { case 0 : return 6; default : return 2; } case 1 : switch (program) { case 0 : return 6; default : return 1; } case 2 : case 18 : return 4; case 3 : case 12 : switch (program) { case 0 : return 4; default : return 2; } case 4 : switch (program) { case 0 : return 4; case 1 : return 2; default : return 1; } case 5 : case 13 : switch (program) { case 0 : return 4; default : return 1; } case 6 : case 14 : case 19 : return 2; case 7 : switch (program) { case 0 : case 1 : case 2 : return 2; default : return 1; } case 8 : case 15 : switch (program) { case 0 : case 1 : return 2; default : return 1; } case 9 : case 16 : case 20 : switch (program) { case 0 : return 2; default : return 1; } case 10 : case 17 : case 21 : return 1; case 11 : return 6; case 22 : return 8; case 23 : return 8; default : return 0; } }; //--------------------------------------------------------------------------- const char* DolbyE_ChannelPositions[64]= { "Front: L C R, Side: L R, LFE / Front: L R", "Front: L C R, Side: L R, LFE / Front: C / Front: C", "Front: L C R, LFE / Front: L C R, LFE", "Front: L C R, LFE / Front: L R / Front: L R", "Front: L C R, LFE / Front: L R / Front: C / Front: C", "Front: L C R, LFE / Front: C / Front: C / Front: C / Front: C", "Front: L R / Front: L R / Front: L R / Front: L R", "Front: L R / Front: L R / Front: L R / Front: C / Front: C", "Front: L R / Front: L R / Front: C / Front: C / Front: C / Front: C", "Front: L R / Front: C / Front: C / Front: C / Front: C / Front: C / Front: C", "Front: C / Front: C / Front: C / Front: C / Front: C / Front: C / Front: C / Front: C", "Front: L C R, Side: L R, LFE", "Front: L C R, LFE / Front: L R", "Front: L C R, LFE / Front: C / Front: C", "Front: L R / Front: L R / Front: L R", "Front: L R / Front: L R / Front: C / Front: C", "Front: L R / Front: C / Front: C / Front: C / Front: C", "Front: C / Front: C / Front: C / Front: C / Front: C / Front: C", "Front: L C R, LFE", "Front: L R / Front: L R", "Front: L R / Front: C / Front: C", "Front: C / Front: C / Front: C / Front: C", "Front: L C R, Side: L R, Back: L R, LFE", "Front: L C C C R, Side: L R, LFE", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", }; //--------------------------------------------------------------------------- const char* DolbyE_ChannelPositions_PerProgram(int8u program_config, int8u program) { switch (program_config) { case 0 : switch (program) { case 0 : return "Front: L C R, Side: L R, LFE"; default : return "Front: L R"; } case 1 : switch (program) { case 0 : return "Front: L C R, Side: L R, LFE"; default : return "Front: C"; } case 2 : case 18 : return "Front: L C R, LFE"; case 3 : case 12 : switch (program) { case 0 : return "Front: L C R, LFE"; default : return "Front: L R"; } case 4 : switch (program) { case 0 : return "Front: L C R, LFE"; case 1 : return "Front: L R"; default : return "Front: C"; } case 5 : case 13 : switch (program) { case 0 : return "Front: L C R, LFE"; default : return "Front: C"; } case 6 : case 14 : case 19 : return "Front: L R"; case 7 : switch (program) { case 0 : case 1 : case 2 : return "Front: L R"; default : return "Front: C"; } case 8 : case 15 : switch (program) { case 0 : case 1 : return "Front: L R"; default : return "Front: C"; } case 9 : case 16 : case 20 : switch (program) { case 0 : return "Front: L R"; default : return "Front: C"; } case 10 : case 17 : case 21 : return "Front: C"; case 11 : return "Front: L C R, Side: L R, LFE"; case 22 : return "Front: L C R, Side: L R, Back: L R, LFE"; case 23 : return "Front: L C C C R, Side: L R, LFE"; default : return ""; } }; //--------------------------------------------------------------------------- const char* DolbyE_ChannelPositions2[64]= { "3/2/0.1 / 2/0/0", "3/2/0.1 / 1/0/0 / 1/0/0", "3/0/0.1 / 3/0/0.1", "3/0/0.1 / 2/0/0 / 2/0/0", "3/0/0.1 / 2/0/0 / 1/0/0 / 1/0/0", "3/0/0.1 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0", "2/0/0 / 2/0/0 / 2/0/0 / 2/0/0", "2/0/0 / 2/0/0 / 2/0/0 / 1/0/0 / 1/0/0", "2/0/0 / 2/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0", "2/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0", "1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0", "3/2/0.1", "3/0/0.1 / 2/0/0", "3/0/0.1 / 1/0/0 / 1/0/0", "2/0/0 / 2/0/0 / 2/0/0", "2/0/0 / 2/0/0 / 1/0/0 / 1/0/0", "2/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0", "1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0", "3/0/0.1", "2/0/0 / 2/0/0", "2/0/0 / 1/0/0 / 1/0/0", "1/0/0 / 1/0/0 / 1/0/0 / 1/0/0", "3/2/2.1", "5/2/0.1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", }; //--------------------------------------------------------------------------- const char* DolbyE_ChannelPositions2_PerProgram(int8u program_config, int8u program) { switch (program_config) { case 0 : switch (program) { case 0 : return "3/2/0.1"; default : return "2/0/0"; } case 1 : switch (program) { case 0 : return "3/2/0.1"; default : return "1/0/0"; } case 2 : case 18 : return "3/0/0.1"; case 3 : case 12 : switch (program) { case 0 : return "3/0/0.1"; default : return "2/0/0"; } case 4 : switch (program) { case 0 : return "3/0/0.1"; case 1 : return "2/0/0"; default : return "1/0/0"; } case 5 : case 13 : switch (program) { case 0 : return "3/0/0.1"; default : return "1/0/0"; } case 6 : case 14 : case 19 : return "Front: L R"; case 7 : switch (program) { case 0 : case 1 : case 2 : return "2/0/0"; default : return "1/0/0"; } case 8 : case 15 : switch (program) { case 0 : case 1 : return "2/0/0"; default : return "1/0/0"; } case 9 : case 16 : case 20 : switch (program) { case 0 : return "2/0/0"; default : return "1/0/0"; } case 10 : case 17 : case 21 : return "1/0/0"; case 11 : return "3/2/0.1"; case 22 : return "3/2/2.1"; case 23 : return "5/2/0.1"; default : return ""; } }; extern const char* AC3_Surround[]; //--------------------------------------------------------------------------- const char* DolbyE_ChannelLayout_PerProgram(int8u program_config, int8u ProgramNumber) { switch (program_config) { case 0 : switch (ProgramNumber) { case 0 : return "L C Ls X R LFE Rs X"; default : return "X X X L X X X R"; } case 1 : switch (ProgramNumber) { case 0 : return "L C Ls X R LFE Rs X"; case 1 : return "X X X C X X X X"; default : return "X X X X X X X C"; } case 2 : switch (ProgramNumber) { case 0 : return "L C X X R S X X"; default : return "X X L C X X R S"; } case 3 : switch (ProgramNumber) { case 0 : return "L C X X R S X X"; case 1 : return "X X L X X X R X"; default : return "X X X L X X X R"; } case 4 : switch (ProgramNumber) { case 0 : return "L C X X R S X X"; case 1 : return "X X L X X X R X"; case 2 : return "X X X C X X X X"; default : return "X X X X X X X C"; } case 5 : switch (ProgramNumber) { case 0 : return "L C X X R S X X"; case 1 : return "X X C X X X X X"; case 2 : return "X X X X X X C X"; case 3 : return "X X X C X X X X"; default : return "X X X X X X X C"; } case 6 : switch (ProgramNumber) { case 0 : return "L X X X R X X X"; case 1 : return "X L X X X R X X"; case 2 : return "X X L X X X R X"; default : return "X X X L X X X R"; } case 7 : switch (ProgramNumber) { case 0 : return "L X X X R X X X"; case 1 : return "X L X X X R X X"; case 2 : return "X X L X X X R X"; case 3 : return "X X X C X X X X"; default : return "X X X X X X X C"; } case 8 : switch (ProgramNumber) { case 0 : return "L X X X R X X X"; case 1 : return "X L X X X R X X"; case 2 : return "X X C X X X X X"; case 3 : return "X X X X X X C X"; case 4 : return "X X X C X X X X"; default : return "X X X X X X X C"; } case 9 : switch (ProgramNumber) { case 0 : return "L X X X R X X X"; case 1 : return "X C X X X X X X"; case 2 : return "X X X X X C X X"; case 3 : return "X X C X X X X X"; case 4 : return "X X X X X X C X"; case 5 : return "X X X C X X X X"; default : return "X X X X X X X C"; } case 10 : switch (ProgramNumber) { case 0 : return "C X X X X X X X"; case 1 : return "X X X X C X X X"; case 2 : return "X C X X X X X X"; case 3 : return "X X X X X C X X"; case 4 : return "X X C X X X X X"; case 5 : return "X X X X X X C X"; case 6 : return "X X X C X X X X"; default : return "X X X X X X X C"; } case 11 : return "L C Ls R LFE Rs"; case 12 : switch (ProgramNumber) { case 0 : return "L C X R S X"; default : return "X X L X X R"; } case 13 : switch (ProgramNumber) { case 0 : return "L C X R S X"; case 1 : return "X X C X X X"; default : return "X X X X X C"; } case 14 : switch (ProgramNumber) { case 0 : return "L X X R X X"; case 1 : return "X L X X R X"; default : return "X X L X X R"; } case 15 : switch (ProgramNumber) { case 0 : return "L X X R X X"; case 1 : return "X L X R X"; case 2 : return "X X C X X X"; default : return "X X X X X C"; } case 16 : switch (ProgramNumber) { case 0 : return "L X X R X X"; case 1 : return "X C X X X X"; case 2 : return "X X X X C X"; case 3 : return "X X C X X X"; default : return "X X X X X C"; } case 17 : switch (ProgramNumber) { case 0 : return "C X X X X X"; case 1 : return "X X X C X X"; case 2 : return "X C X X X X"; case 3 : return "X X X X C X"; case 4 : return "X X C X X X"; default : return "X X X X X C"; } case 18 : return "L C R S"; case 19 : switch (ProgramNumber) { case 0 : return "L X R X"; default : return "X L X R"; } case 20 : switch (ProgramNumber) { case 0 : return "L X R X"; case 1 : return "X C X X"; default : return "X X X C"; } case 21 : switch (ProgramNumber) { case 0 : return "C X X X"; case 1 : return "X X C X"; case 2 : return "X C X X"; default : return "X X X C"; } case 22 : return "L C Ls Lrs R LFE Rs Rrs"; case 23 : return "L C Ls Lc R LFE Rs Rc"; default : return ""; } }; extern const float64 Mpegv_frame_rate[16]; const bool Mpegv_frame_rate_type[16]= {false, false, false, false, false, false, true, true, true, false, false, false, false, false, false, false}; //--------------------------------------------------------------------------- static const int8u intermediate_spatial_format_object_count[8]= { 4, 8, 10, 14, 15, 30, 0, 0, }; const char* sound_category_Values[4]= { "", "Dialog", "", "", }; const char* hp_render_mode_Values[4]= { "Bypassed", "Near", "Far", "", }; string default_target_device_config_Value(int32u config) { string Value; if (config&0x1) Value+="Stereo / "; if (config&0x2) Value+="Surround / "; if (config&0x4) Value+="Immersive / "; if (!Value.empty()) Value.resize(Value.size()-3); return Value; } struct pos3d { int8u x; int8u y; int8u z; const char* Value; }; int16u mgi_6bit_unsigned_to_oari_Q15[0x40]= { 0, 529, 1057, 1586, 2114, 2643, 3171, 3700, 4228, 4757, 5285, 5814, 6342, 6871, 7399, 7928, 8456, 8985, 9513, 10042, 10570, 11099, 11627, 12156, 12684, 13213, 13741, 14270, 14798, 15327, 15855, 16384, 16913, 17441, 17970, 18498, 19027, 19555, 20084, 20612, 21141, 21669, 22198, 22726, 23255, 23783, 24312, 24840, 25369, 25897, 26426, 26954, 27483, 28011, 28540, 29068, 29597, 30125, 30654, 31182, 31711, 32239, 32767, 32767 }; int16u mgi_4bit_unsigned_to_oari_Q15[0x10]= { 0, 2185, 4369, 6554, 8738, 10923, 13107, 15292, 17476, 19661, 21845, 24030, 26214, 28399, 30583, 32767 }; int mgi_bitstream_val_to_Q15(int value, int8u num_bits) { bool sign; if (value<0) { sign=true; value=-value; } else sign=false; int16u* Table; switch (num_bits) { case 4: Table=mgi_4bit_unsigned_to_oari_Q15; break; case 6: Table=mgi_6bit_unsigned_to_oari_Q15; break; default: return 0; //Problem } int decoded=Table[value]; return sign?-decoded:decoded; } int mgi_bitstream_pos_z_to_Q15(bool pos_z_sign, int8u pos_z_bits) { if (pos_z_bits == 0xf) { if (pos_z_sign == 1) /* +1 */ { return(32767); } else /* -1 */ { return(-32768); } } else { /* Negative number */ if (pos_z_sign == 1) { return(mgi_bitstream_val_to_Q15(pos_z_bits, 4)); } else { return(mgi_bitstream_val_to_Q15(-pos_z_bits, 4)); } } } //--------------------------------------------------------------------------- namespace { struct speaker_info { int8u AzimuthAngle; //0 to 180 (right, if AzimuthDirection is false) or 179 (left, if AzimuthDirection is true) int8s ElevationDirectionAngle; //-90 (bottom) to 90 (top) enum flag { None = 0, AzimuthDirection = 1<<0, // true = right isLFE = 1<<1, }; int8u Flags; }; bool operator== (const speaker_info& L, const speaker_info& R) { return L.AzimuthAngle==R.AzimuthAngle && L.ElevationDirectionAngle==R.ElevationDirectionAngle && L.Flags==R.Flags; } } extern string Aac_ChannelLayout_GetString(const Aac_OutputChannel* const OutputChannels, size_t OutputChannels_Size); static const size_t SpeakerInfos_Size=43; static const speaker_info SpeakerInfos[SpeakerInfos_Size] = { { 30, 0, speaker_info::AzimuthDirection }, { 30, 0, speaker_info::None }, { 0, 0, speaker_info::None }, { 0, -15, speaker_info::isLFE }, { 110, 0, speaker_info::AzimuthDirection }, { 110, 0, speaker_info::None }, { 22, 0, speaker_info::AzimuthDirection }, { 22, 0, speaker_info::None }, { 135, 0, speaker_info::AzimuthDirection }, { 135, 0, speaker_info::None }, { 180, 0, speaker_info::None }, { 135, 0, speaker_info::AzimuthDirection }, { 135, 0, speaker_info::None }, { 90, 0, speaker_info::AzimuthDirection }, { 90, 0, speaker_info::None }, { 60, 0, speaker_info::AzimuthDirection }, { 60, 0, speaker_info::None }, { 30, 35, speaker_info::AzimuthDirection }, { 30, 35, speaker_info::None }, { 0, 35, speaker_info::None }, { 135, 35, speaker_info::AzimuthDirection }, { 135, 35, speaker_info::None }, { 180, 35, speaker_info::None }, { 90, 35, speaker_info::AzimuthDirection }, { 90, 35, speaker_info::None }, { 0, 90, speaker_info::None }, { 45, -15, speaker_info::isLFE }, { 45, -15, speaker_info::AzimuthDirection }, { 45, -15, speaker_info::None }, { 0, -15, speaker_info::None }, { 110, 35, speaker_info::AzimuthDirection }, { 110, 35, speaker_info::None }, { 45, 35, speaker_info::AzimuthDirection }, { 45, 35, speaker_info::None }, { 45, 0, speaker_info::AzimuthDirection }, { 45, 0, speaker_info::None }, { 45, -15, speaker_info::None | speaker_info::isLFE }, { 2, 0, speaker_info::AzimuthDirection }, { 2, 0, speaker_info::None }, { 1, 0, speaker_info::AzimuthDirection }, { 1, 0, speaker_info::None }, { 150, 0, speaker_info::AzimuthDirection }, { 150, 0, speaker_info::None }, }; struct angles { int Azimuth; int Elevation; angles() {} angles(int theta, int phi) : Azimuth(theta), Elevation(phi) {} }; Aac_OutputChannel AnglesToChannelName(angles Angles) { speaker_info SpeakerInfo; if (Angles.Azimuth<0) { SpeakerInfo.AzimuthAngle=(int8u)-Angles.Azimuth; SpeakerInfo.Flags=speaker_info::AzimuthDirection; } else { SpeakerInfo.AzimuthAngle=Angles.Azimuth; SpeakerInfo.Flags=speaker_info::None; } SpeakerInfo.ElevationDirectionAngle=Angles.Elevation; for (size_t i=0; i0) return angles(0, 90); else if (z<0) return angles(0, -90); return angles(0, 0); // Should not happen (is the center in practice) } else { angles ToReturn; float radius=sqrt(x*x+y*y+z*z); float theta_float=round(atan2(y, x)*180/3.14159265359/5)*5; ToReturn.Azimuth=float32_int32s(theta_float); float phi_float=round(acos(z/radius)*180/3.14159265359); ToReturn.Elevation=float32_int32s(phi_float); //Reference is front of viewer if (ToReturn.Azimuth<90) ToReturn.Azimuth+=90; else ToReturn.Azimuth-=270; ToReturn.Elevation=90-ToReturn.Elevation; return ToReturn; } } string Angles2String(angles Angles) { string ToReturn; //Elevation switch (Angles.Elevation) { case 0: ToReturn+='M'; break; case 90: ToReturn+='T'; break; case -90: ToReturn+='X'; break; //No standard for that default : ToReturn+=(Angles.Elevation>0?'U':'B'); //if (Angles.phi!=35 && Angles.phi!=-15) ToReturn+=ToAngle3Digits(Angles.Elevation); } ToReturn+='_'; //Azimuth if (Angles.Azimuth<0) ToReturn+='L'; else if (Angles.Azimuth>0 && Angles.Azimuth!=180) ToReturn+='R'; ToReturn+=ToAngle3Digits(Angles.Azimuth<0?-Angles.Azimuth:Angles.Azimuth); return ToReturn; } string Angles2KnownChannelName(angles& Angles) { //Exception handling int Azimuth; if (Angles.Azimuth==-180) Azimuth=180; else Azimuth=Angles.Azimuth; int Elevation; if (Angles.Elevation>=35 && Angles.Elevation<=45) Elevation=35; else Elevation=Angles.Elevation; Aac_OutputChannel KnownChannel=AnglesToChannelName(angles(Azimuth, Elevation)); if (KnownChannel!=CH_MAX) return Aac_ChannelLayout_GetString(&KnownChannel, 1); else return Angles2String(Angles); } //--------------------------------------------------------------------------- extern int32u AC3_bed_channel_assignment_mask_2_nonstd(int16u bed_channel_assignment_mask); extern Ztring AC3_nonstd_bed_channel_assignment_mask_ChannelLayout(int32u nonstd_bed_channel_assignment_mask); size_t BedChannelConfiguration_ChannelCount(int32u nonstd_bed_channel_assignment_mask) { Ztring BedChannelConfiguration=AC3_nonstd_bed_channel_assignment_mask_ChannelLayout(nonstd_bed_channel_assignment_mask); size_t BedChannelCount=0; if (!BedChannelConfiguration.empty()) for (size_t i=0; i1) DolbyE_Audio_Pos=(int8u)-1; for (int8u program=0; program= Count_Get(Stream_Audio)) Stream_Prepare(Stream_Audio); Fill(Stream_Audio, program, Audio_Format, "Dolby E"); if (DolbyE_Programs[program_config]>1) Fill(Stream_Audio, program, Audio_ID, program+1); Fill(Stream_Audio, program, Audio_Channel_s_, DolbyE_Channels_PerProgram(program_config, program)); Fill(Stream_Audio, program, Audio_ChannelPositions, DolbyE_ChannelPositions_PerProgram(program_config, program)); Fill(Stream_Audio, program, Audio_ChannelPositions_String2, DolbyE_ChannelPositions2_PerProgram(program_config, program)); Fill(Stream_Audio, program, Audio_ChannelLayout, DolbyE_ChannelLayout_PerProgram(program_config, program)); int32u Program_Size=0; if (DolbyE_Audio_Pos!=(int8u)-1) for (int8u Pos=0; Posfirst*8*Mpegv_frame_rate[frame_rate_code], 0); Fill(Stream_Audio, 0, Audio_BitRate_Encoded, FrameSizes.begin()->first*8*Mpegv_frame_rate[frame_rate_code], 0); } } } //--------------------------------------------------------------------------- void File_DolbyE::Streams_Fill_ED2() { if (Count_Get(Stream_Audio)) { while (Count_Get(Stream_Audio)>1) Stream_Erase(Stream_Audio, Count_Get(Stream_Audio)-1); // We may have several streams due to metadata, we keep one StreamPos_Last=0; } else Stream_Prepare(Stream_Audio); Fill(Stream_Audio, StreamPos_Last, Audio_Format, "Dolby ED2"); if (Guardband_EMDF_PresentAndSize) Fill(Stream_Audio, StreamPos_Last, Audio_BitRate, Guardband_EMDF_PresentAndSize*8*Mpegv_frame_rate[frame_rate_code], 0); size_t ChannelCount=DynObjects.size(); for (size_t p=0; pDynObjects[I1].Alts.size()) // 0 = OAMD, else Alt - 1 I2=0; // There is a problem } else { I1=i-DynObjects.size(); I2=Target_Current.md_indexes[i]; if (I2 && I2>BedInstances[I1].Alts.size()) // 0 = OAMD, else Alt - 1 I2=0; // There is a problem } int j=iPTS_Begin) { int64s Duration=float64_int64s(((float64)(FrameInfo.PTS-PTS_Begin))/1000000); int64s FrameCount; if (Mpegv_frame_rate[frame_rate_code]) FrameCount=float64_int64s(((float64)(FrameInfo.PTS-PTS_Begin))/1000000000*Mpegv_frame_rate[frame_rate_code]); else FrameCount=0; for (size_t Pos=0; PosBuffer_Size) return false; //Synched return true; } //--------------------------------------------------------------------------- bool File_DolbyE::Synched_Test() { //Must have enough buffer for having header if (Buffer_Offset+3>Buffer_Size) return false; //Quick test of synchro switch (bit_depth) { case 16 : if ((CC2(Buffer+Buffer_Offset)&0xFFFE )!=0x078E ) {Synched=false; return true;} break; case 20 : if ((CC3(Buffer+Buffer_Offset)&0xFFFFE0)!=0x0788E0) {Synched=false; return true;} break; case 24 : if ((CC3(Buffer+Buffer_Offset)&0xFFFFFE)!=0x07888E) {Synched=false; return true;} break; default : ; } //We continue return true; } //*************************************************************************** // Buffer - Global //*************************************************************************** //--------------------------------------------------------------------------- void File_DolbyE::Read_Buffer_Unsynched() { description_text_Values.clear(); num_desc_packets_m1=(int32u)-1; description_packet_data.clear(); } //*************************************************************************** // Buffer - Per element //*************************************************************************** //--------------------------------------------------------------------------- void File_DolbyE::Header_Parse() { //Filling if (IsSub) Header_Fill_Size(Buffer_Size-Buffer_Offset); else { //Looking for synchro //Synchronizing Buffer_Offset_Temp=Buffer_Offset+3; if (bit_depth==16) while (Buffer_Offset_Temp+2<=Buffer_Size) { if ((CC2(Buffer+Buffer_Offset_Temp)&0xFFFE)==0x078E) //16-bit break; //while() Buffer_Offset_Temp++; } if (bit_depth==20) while (Buffer_Offset_Temp+3<=Buffer_Size) { if ((CC3(Buffer+Buffer_Offset_Temp)&0xFFFFE0)==0x0788E0) //20-bit break; //while() Buffer_Offset_Temp++; } if (bit_depth==24) while (Buffer_Offset_Temp+3<=Buffer_Size) { if ((CC3(Buffer+Buffer_Offset_Temp)&0xFFFFFE)==0x07888E) //24-bit break; //while() Buffer_Offset_Temp++; } if (Buffer_Offset_Temp+(bit_depth>16?3:2)>Buffer_Size) { if (File_Offset+Buffer_Size==File_Size) Buffer_Offset_Temp=Buffer_Size; else { Element_WaitForMoreData(); return; } } Header_Fill_Size(Buffer_Offset_Temp-Buffer_Offset); } Header_Fill_Code(0, "Dolby_E_frame"); } //--------------------------------------------------------------------------- void File_DolbyE::Data_Parse() { FrameSizes[Element_Size]++; //In case of scrambling const int8u* Save_Buffer=NULL; size_t Save_Buffer_Offset=0; int64u Save_File_Offset=0; if (key_present) { //We must change the buffer, Save_Buffer=Buffer; Save_Buffer_Offset=Buffer_Offset; Save_File_Offset=File_Offset; File_Offset+=Buffer_Offset; Buffer_Offset=0; Descrambled_Buffer=new int8u[(size_t)Element_Size]; std::memcpy(Descrambled_Buffer, Save_Buffer+Save_Buffer_Offset, (size_t)Element_Size); Buffer=Descrambled_Buffer; } //Parsing BS_Begin(); sync_segment(); metadata_segment(); audio_segment(); metadata_extension_segment(); audio_extension_segment(); meter_segment(); BS_End(); //Check if there is content in padding int16u Padding; if (Element_Size-Element_Offset>=2) { Peek_B2(Padding); if (Padding==0x5838) guard_band(); } if (Element_Offset>1)+Element_Size; // Guardband + AES3 header + Dolby E frame if (ToRemove<(int64u)GuardBand_After) GuardBand_After-=ToRemove; else GuardBand_After=0; GuardBand_After/=bit_depth/4; GuardBand_After*=bit_depth/4; Element_Info1(GuardBand_Before); float64 GuardBand_Before_Duration=((float64)GuardBand_Before)/BytesPerSecond; Ztring GuardBand_Before_String=__T("GuardBand_Begin ")+Ztring::ToZtring(GuardBand_Before)+__T(" (")+Ztring::ToZtring(GuardBand_Before_Duration*1000000, 0)+Ztring().From_UTF8(" \0xC20xB5s"); //0xC20xB5 = micro sign Element_Info1(GuardBand_Before_String); } } if (!Status[IsAccepted]) { Accept("Dolby E"); PTS_Begin=FrameInfo.PTS; //Guard band GuardBand_Before_Initial=GuardBand_Before; GuardBand_After_Initial=GuardBand_After; } Frame_Count++; if (Frame_Count_NotParsedIncluded!=(int64u)-1) Frame_Count_NotParsedIncluded++; if (Mpegv_frame_rate[frame_rate_code]) FrameInfo.DUR=float64_int64s(1000000000/Mpegv_frame_rate[frame_rate_code]); else FrameInfo.DUR=(int64u)-1; if (FrameInfo.DTS!=(int64u)-1) FrameInfo.DTS+=FrameInfo.DUR; if (FrameInfo.PTS!=(int64u)-1) FrameInfo.PTS+=FrameInfo.DUR; if (!Status[IsFilled] && ((description_packet_data.empty() && description_text_Values.empty()) || Frame_Count>=32+1+1+32+1)) // max 32 chars (discarded) + ETX (discarded) + STX + max 32 chars + ETX Fill("Dolby E"); FILLING_END(); if (Frame_Count==0 && Buffer_TotalBytes>Buffer_TotalBytes_FirstSynched_Max) Reject("Dolby E"); } //--------------------------------------------------------------------------- void File_DolbyE::sync_segment() { //Parsing Element_Begin1("sync_segment"); Skip_S3(bit_depth, "sync_word"); Element_End0(); } //--------------------------------------------------------------------------- void File_DolbyE::metadata_segment() { //Parsing Element_Begin1("metadata_segment"); if (key_present) { //We must change the buffer switch (bit_depth) { case 16 : { int16u metadata_key; Get_S2 (16, metadata_key, "metadata_key"); int16u metadata_segment_size=((BigEndian2int16u(Buffer+Buffer_Offset+(size_t)Element_Size-Data_BS_Remain()/8)^metadata_key)>>2)&0x3FF; if (Data_BS_Remain()<((size_t)metadata_segment_size+1)*(size_t)bit_depth) //+1 for CRC return; //There is a problem int8u* Temp=Descrambled_Buffer+(size_t)Element_Size-Data_BS_Remain()/8; for (int16u Pos=0; Pos>4))>>2)&0x3FF; if (Data_BS_Remain()<((size_t)metadata_segment_size+1)*(size_t)bit_depth) //+1 for CRC return; //There is a problem Descramble_20bit(metadata_key, metadata_segment_size); } break; case 24 : { int32u metadata_key; Get_S3 (24, metadata_key, "metadata_key"); int32u metadata_segment_size=((BigEndian2int16u(Buffer+Buffer_Offset+(size_t)Element_Size-Data_BS_Remain()/8)^metadata_key)>>2)&0x3FF; if (Data_BS_Remain()<((size_t)metadata_segment_size+1)*bit_depth) //+1 for CRC return; //There is a problem int8u* Temp=Descrambled_Buffer+(size_t)Element_Size-Data_BS_Remain()/8; for (int16u Pos=0; Pos=description_text_Values.size()) description_text_Values.resize(Program+1); switch (description_text) { case 0x00: // No text if (Program=0x20 && description_text<=0x7E) description_text_Values[Program].Current.push_back(description_text); } Element_End0(); } for (int8u Channel=0; ChannelEnd) Skip_BS(Data_BS_Remain()-End, "unknown"); Element_End0(); } if (evolution_data_exists) { for (;;) { const size_t evolution_data_segment_id_Name_Size=2; const char* const evolution_data_segment_id_Name[evolution_data_segment_id_Name_Size]= { "End", "intelligent_loudness_evolution_data_segment", }; Element_Begin1("evolution_data_segment"); int16u evolution_data_segment_length; int8u evolution_data_segment_id; Get_S1 ( 4, evolution_data_segment_id, "evolution_data_segment_id"); Param_Info1C(evolution_data_segment_idEnd) Skip_BS(Data_BS_Remain()-End, "unknown"); Element_End0(); } } if (Data_BS_Remain()>metadata_segment_BitCountAfter) Skip_BS(Data_BS_Remain()-metadata_segment_BitCountAfter,"reserved_metadata_bits"); Skip_S3(bit_depth, "metadata_crc"); { //CRC test /* size_t Pos_End=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain(); size_t Pos_Begin=Pos_End-(metadata_segment_size+1)*bit_depth; //+1 for CRC int8u BitSkip_Begin=Pos_Begin%8; Pos_Begin/=8; int8u BitSkip_End=0; // Pos_End%8; Looks like that the last bits must not be in the CRC computing Pos_End/=8; if (BitSkip_End) Pos_End++; int16u CRC=CRC_16_Compute(Buffer+Pos_Begin, Pos_End-Pos_Begin, BitSkip_Begin, BitSkip_End); if (CRC) { // CRC is wrong Param_Info1("metadata_crc NOK"); } */ } Element_End0(); } //--------------------------------------------------------------------------- void File_DolbyE::guard_band() { int8u* NewBuffer=NULL; size_t Buffer_Offset_Save; size_t Buffer_Size_Save; int64u Element_Offset_Save; int64u Element_Size_Save; Element_Begin1("guard_band (with data)"); int16u element_length; int8u element_id; bool escape_code_valid; Skip_B2( "sync_word"); BS_Begin(); Skip_S1( 3, "reserved"); Get_SB ( escape_code_valid, "escape_code_valid"); if (escape_code_valid) { int16u escape_code; Get_S2 (12, escape_code, "escape_code"); BS_End(); for (int64u i=Element_Offset; i+1>4) && (Buffer[Buffer_Offset+i+1]>>4)==(escape_code&0x0F)) { //0xABCD --> 0x078D if (!NewBuffer) { NewBuffer=new int8u[Element_Size-Element_Offset]; memcpy(NewBuffer, Buffer+Buffer_Offset+Element_Offset, Element_Size-Element_Offset); } NewBuffer[i -Element_Offset]=0x07; NewBuffer[i+1-Element_Offset]=(NewBuffer[i+1-Element_Offset]&0x0F)|0x80; } if ((Buffer[Buffer_Offset+i ]&0xF)==(escape_code>>8) && Buffer[Buffer_Offset+i+1] ==(escape_code&0xFF)) { //0xABCD --> 0xA078 if (!NewBuffer) { NewBuffer=new int8u[Element_Size-Element_Offset]; memcpy(NewBuffer, Buffer+Buffer_Offset+Element_Offset, Element_Size-Element_Offset); } NewBuffer[i -Element_Offset]=(NewBuffer[i -Element_Offset]&0xF0); NewBuffer[i+1-Element_Offset]=0x78; } } if (NewBuffer) { Buffer=NewBuffer; Buffer_Offset_Save=Buffer_Offset; Buffer_Size_Save=Buffer_Offset; Element_Offset_Save=Element_Offset; Element_Size_Save=Element_Size; File_Offset+=Buffer_Offset+Element_Offset; Buffer_Offset=0; Buffer_Size=Element_Size-Element_Offset; Element_Offset=0; Element_Size=Buffer_Size; } } else { Skip_S2(12, "escape_code"); BS_End(); } Get_B1 ( element_id, "element_id"); Get_B2 ( element_length, "element_length"); int64u After=Element_Offset+element_length; switch (element_id) { case 0xBB: evo_frame(); break; default: Skip_XX(element_length, "Unknown"); } if (Element_OffsetAfter) { Param_Info1("Problem"); Element_Offset=After; } Skip_B2( "crc"); { //CRC test /* size_t Pos_End=Buffer_Offset+Element_Offset; size_t Pos_Begin=Pos_End-(element_length+2); //+2 for CRC int16u CRC=CRC_16_Compute(Buffer+Pos_Begin, Pos_End-Pos_Begin, 0, 0); if (CRC) { // CRC is wrong Param_Info1("crc NOK"); } */ Element_End0(); int64u RemainingBytes=Element_Size-Element_Offset; if (RemainingBytes && RemainingBytespayload_size*8)?(Data_BS_Remain()-payload_size*8):0; Element_Begin1("payload"); switch (payload_id) { case 11: object_audio_metadata_payload(); break; case 13: mgi_payload(); break; default: Skip_BS(payload_size*8, "(Unknown)"); } size_t Remaining=Data_BS_Remain()-payload_End; if (Remaining && Remaining<8) { int8u padding; Peek_S1(Remaining, padding); if (!padding) Skip_S1(Remaining, "padding"); } if (Data_BS_Remain()>payload_End) { Skip_BS(Data_BS_Remain()-payload_End, "(Unparsed payload bytes)"); } else if (Data_BS_Remain()=payload_End) Skip_BS(Data_BS_Remain()-payload_End, "(Problem during emdf_payload parsing)"); else Skip_BS(Data_BS_Remain(), "(Problem during payload parsing, going to end directly)"); Element_End0(); Element_End0(); break; } Element_End0(); Element_End0(); } evo_protection(); BS_End(); Element_End0(); } //--------------------------------------------------------------------------- void File_DolbyE::evo_payload_config() { Element_Begin1("payload_config"); bool timestamp_present; TEST_SB_GET (timestamp_present, "timestamp_present"); Skip_V4(11, "timestamp"); TEST_SB_END(); TEST_SB_SKIP( "duration_present"); Skip_V4(11, "duration"); TEST_SB_END(); TEST_SB_SKIP( "group_id_present"); Skip_V4(2, "group_id"); TEST_SB_END(); TEST_SB_SKIP( "codec_specific_id_present"); Skip_S1(8, "codec_specific_id"); TEST_SB_END(); bool dont_transcode; Get_SB(dont_transcode, "dont_transcode"); if (!dont_transcode) { bool now_or_never = false; if (!timestamp_present) { Get_SB (now_or_never, "now_or_never"); if (now_or_never) { Skip_SB( "create_duplicate"); Skip_SB( "remove_duplicate"); } } if (timestamp_present || now_or_never) { Skip_S1(5, "priority"); Skip_S1(2, "tight_coupling"); } } Element_End0(); } //--------------------------------------------------------------------------- void File_DolbyE::evo_protection() { Element_Begin1("protection"); int8u len_primary, len_second; Get_S1(2, len_primary, "protection_length_primary"); Get_S1(2, len_second, "protection_length_secondary"); switch (len_primary) { case 0: len_primary = 0; break; case 1: len_primary = 8; break; case 2: len_primary = 32; break; case 3: len_primary = 128; break; default:; //Cannot append, read only 2 bits }; switch (len_second) { case 0: len_second = 0; break; case 1: len_second = 8; break; case 2: len_second = 32; break; case 3: len_second = 128; break; default:; //Cannot append, read only 2 bits }; Skip_BS(len_primary, "protection_bits_primary"); if (len_second) Skip_BS(len_primary, "protection_bits_secondary"); Element_End0(); } //--------------------------------------------------------------------------- void File_DolbyE::object_audio_metadata_payload() { nonstd_bed_channel_assignment_masks.clear(); ObjectElements.clear(); Element_Begin1("object_audio_metadata_payload"); int8u oa_md_version_bits; Get_S1 (2, oa_md_version_bits, "oa_md_version_bits"); if (oa_md_version_bits == 0x3) { int8u oa_md_version_bits_ext; Get_S1 (3, oa_md_version_bits_ext, "oa_md_version_bits_ext"); oa_md_version_bits += oa_md_version_bits_ext; } int8u object_count_bits; Get_S1 (5, object_count_bits, "object_count_bits"); if (object_count_bits==0x1F) { int8u object_count_bits_ext; Get_S1 (7, object_count_bits_ext, "object_count_bits_ext"); object_count_bits=0x1F+object_count_bits_ext; } object_count=object_count_bits+1; Param_Info2(object_count, " objects"); program_assignment(); bool b_alternate_object_data_present; Get_SB(b_alternate_object_data_present, "b_alternate_object_data_present"); int8u oa_element_count_bits; Get_S1(4, oa_element_count_bits, "oa_element_count_bits"); if (oa_element_count_bits==0xF) { Get_S1(5, oa_element_count_bits, "oa_element_count_bits_ext"); oa_element_count_bits+=0xF; } for (int8u i=0; iData_BS_Remain()) { Skip_BS(oa_element_size_bits, "?"); Element_End0(); return; } oa_element_size_bits-=b_alternate_object_data_present_Reduced; if (b_alternate_object_data_present) Skip_S1(4, "alternate_object_data_id_idx"); Skip_SB( "b_discard_unknown_element"); size_t End=Data_BS_Remain()-oa_element_size_bits; switch (oa_element_id_idx) { case 1: object_element(); break; default: Skip_BS(oa_element_size_bits, "oa_element"); } if (Data_BS_Remain()>End) Skip_BS(Data_BS_Remain()-End, "padding"); Element_End0(); } void File_DolbyE::object_element() { Element_Begin1("object_element"); int8u num_obj_info_blocks_bits; md_update_info(num_obj_info_blocks_bits); bool b_reserved_data_not_present; Get_SB (b_reserved_data_not_present, "b_reserved_data_not_present"); if (!b_reserved_data_not_present) Skip_S1(5, "reserved"); for (int8u i=0; i>1, blk); // Use bit 1 else { dyn_object& D=ObjectElements[ObjectElements.size()-1]; dyn_object::dyn_object_alt& A=D.Alts[blk]; A.obj_gain_db=INT8_MAX; } if (b_object_not_active || (obj_idx>1, blk); // Use bit 1 else { dyn_object& D=ObjectElements[ObjectElements.size()-1]; dyn_object::dyn_object_alt& A=D.Alts[blk]; A.pos3d_x_bits=(int8u)-1; } bool b_additional_table_data_exists; Get_SB (b_additional_table_data_exists, "b_additional_table_data_exists"); if (b_additional_table_data_exists) { int8u additional_table_data_size_bits; Get_S1(4, additional_table_data_size_bits, "additional_table_data_size_bits"); additional_table_data_size_bits++; additional_table_data_size_bits*=8; Skip_BS(additional_table_data_size_bits, "additional_table_data"); } Element_End0(); } void File_DolbyE::object_basic_info(int8u object_basic_info_array, int8u blk) { Element_Begin1("object_basic_info"); if (!object_basic_info_array) // object_basic_info_array is "reuse" info at this point object_basic_info_array=3; // 2x 1 else Get_S1 (2, object_basic_info_array, "object_basic_info[]"); dyn_object& D=ObjectElements[ObjectElements.size()-1]; dyn_object::dyn_object_alt& A=D.Alts[blk]; if (object_basic_info_array>>1) // bit 1 { int8u object_gain_idx; Get_S1 (2, object_gain_idx, "object_gain_idx"); switch (object_gain_idx) { case 0 : A.obj_gain_db=0; break; case 1 : A.obj_gain_db=INT8_MIN; break; case 2 : { int8u object_gain_bits; Get_S1 (6, object_gain_bits, "object_gain_bits"); A.obj_gain_db=(object_gain_bits<15?15:14)-object_gain_bits; } break; default: if (ObjectElements.size()>=2) A.obj_gain_db=ObjectElements[ObjectElements.size()-2].Alts[blk].obj_gain_db; else A.obj_gain_db=0; } } else A.obj_gain_db=INT8_MAX; if (object_basic_info_array&1) // bit 0 { bool b_default_object_priority; Get_SB ( b_default_object_priority, "b_default_object_priority"); if (!b_default_object_priority) Skip_S1(5, "b_default_object_priority"); } Element_End0(); } void File_DolbyE::object_render_info(int8u object_render_info_array, int8u blk) { Element_Begin1("object_render_info"); if (!object_render_info_array) // object_render_info_array is "reuse" info at this point object_render_info_array=0xF; // 4x 1 else Get_S1 (4, object_render_info_array, "object_render_info[]"); dyn_object& D=ObjectElements[ObjectElements.size()-1]; dyn_object::dyn_object_alt& A=D.Alts[blk]; if (object_render_info_array&1) // bit 0 { bool b_differential_position_specified; if (!blk) b_differential_position_specified=0; else Get_SB(b_differential_position_specified, "b_differential_position_specified"); if (b_differential_position_specified) { Skip_S1(3, "diff_pos3D_X_bits"); Skip_S1(3, "diff_pos3D_Y_bits"); Skip_S1(3, "diff_pos3D_Z_bits"); A.pos3d_x_bits=(int8u)-1; // Not supported } else { bool b_object_distance_specified; Get_S1 (6, A.pos3d_x_bits, "pos3d_x_bits"); Param_Info3(mgi_bitstream_val_to_Q15(A.pos3d_x_bits, 6)/32768.0*100, "%", 0); Get_S1 (6, A.pos3d_y_bits, "pos3d_y_bits"); Param_Info3(mgi_bitstream_val_to_Q15(A.pos3d_y_bits, 6)/32768.0*100, "%", 0); Get_SB ( A.pos3d_z_sig, "pos3d_z_sig"); Get_S1 (4, A.pos3d_z_bits, "pos3d_z_bits"); Param_Info3(mgi_bitstream_pos_z_to_Q15(A.pos3d_z_sig, A.pos3d_z_bits)/32768.0*100, "%", 0); Get_SB ( b_object_distance_specified, "b_object_distance_specified"); if (b_object_distance_specified) { bool b_object_at_infinity; Get_SB ( b_object_at_infinity, "b_object_at_infinity"); if (!b_object_at_infinity) Skip_S1(4, "distance_factor_idx"); } } } else A.pos3d_x_bits=(int8u)-1; A.hp_render_mode=(int8u)-1; if ((object_render_info_array>>1)&1) // bit 1 { Skip_S1(3, "zone_constraints_idx"); Skip_SB( "b_enable_elevation"); } if ((object_render_info_array>>2)&1) // bit 2 { int8u object_size_idx; Get_S1 (2, object_size_idx, "object_size_idx"); switch (object_size_idx) { case 1: { Skip_S1(5, "object_size_bits"); } break; case 2: { Skip_S1(5, "object_width_bits"); Skip_S1(5, "object_depth_bits"); Skip_S1(5, "object_height_bits"); } break; default:; } } if (object_render_info_array>>3) // bit 3 { bool b_object_use_screen_ref; Get_SB ( b_object_use_screen_ref, "b_object_use_screen_ref"); if (b_object_use_screen_ref) { Skip_S1(3, "screen_factor_bits"); Skip_S1(2, "depth_factor_idx"); } Skip_SB( "b_object_snap"); } Element_End0(); } int8u bits_needed(size_t value) { if (!value) return 0; int8u res = 0; while (value) { res += 1; value >>= 1; } return res; } void File_DolbyE::mgi_payload() { DynObjects.clear(); BedInstances.clear(); Presets.clear(); substream_mappings.clear(); Element_Begin1("mgi_payload"); size_t BS_Start=Data_BS_Remain(); int8u mgi_version, num_presets_m1, num_dyn_objects, num_bed_instances; bool program_id_available, is_substream_mapping_present, mini_mixgraph_extension_present, mini_mixgraph_description_present; Get_S1 (2, mgi_version, "mgi_version"); if (mgi_version ==3) { int32u mgi_version32; Get_V4 (2, mgi_version32, "mgi_version"); mgi_version32+=3; mgi_version=(int8u)mgi_version32; } if (mgi_version!=5) { Skip_BS(1, "(Unparsed mgi_payload data)"); //TODO: exact count of bits Element_End0(); return; } Get_SB (program_id_available, "program_id_available"); Get_SB (is_substream_mapping_present, "is_substream_mapping_present"); Get_SB (mini_mixgraph_extension_present, "mini_mixgraph_extension_present"); Get_SB (mini_mixgraph_description_present, "mini_mixgraph_description_present"); if (program_id_available) { Skip_S1( 3, "program_uuid_segment_number"); Skip_S2(16, "program_uuid_segment"); } { size_t ToPadd=(BS_Start-Data_BS_Remain())%8; if (ToPadd<8) Skip_BS(8-ToPadd, "byte_align"); } Skip_S2(16, "short_program_id"); Get_S1 (4, num_presets_m1, "num_presets_m1"); Get_S1 (7, num_dyn_objects, "num_dyn_objects"); Get_S1 (4, num_bed_instances, "num_bed_instances"); DynObjects.resize(num_dyn_objects); for (int8u i=0; iEnd) Skip_BS(Data_BS_Remain()-End, "padding"); Element_End0(); } Element_End0(); } Presets.resize(num_presets_m1 + 1); for (int8u i=0; i<=num_presets_m1; i++) { preset& P=Presets[i]; Element_Begin1("preset"); int32u num_target_device_configs_m1; Get_V4 (2, num_target_device_configs_m1, "num_target_device_configs_m1"); Get_V4 (2, P.default_target_device_config, "default_target_device_config"); Param_Info1(default_target_device_config_Value(P.default_target_device_config)); P.target_device_configs.resize(num_target_device_configs_m1+1); for (int32u j=0; j<=num_target_device_configs_m1; j++) { preset::target_device_config& T=P.target_device_configs[j]; Element_Begin1("target_device_config"); Get_V4 (3, T.target_devices_mask, "target_devices_mask"); Param_Info1(default_target_device_config_Value(T.target_devices_mask)); for (int32u k=0; k8?8:desc_pkt_size_bits; int8u data; Get_S1(bits8, data, "description_packet_data"); if (num_desc_packets_m1!=(int32u)-1) description_packet_data.push_back(data<<(8-bits8)); desc_pkt_size_bits-=bits8; } if (desc_packet_idx==num_desc_packets_m1 && !description_packet_data.empty()) { Presets_More.clear(); BitStream_Fast* BS_Save=BS; BS=new BitStream_Fast(&*description_packet_data.begin(), description_packet_data.size()); //In bytes, we can not provide a precise count of bits Element_Begin1("packet_description"); int8u preset_description_id_bits; Get_S1(3, preset_description_id_bits, "preset_description_id_bits"); for (int8u i=0; i <=num_presets_m1; i++) { Skip_BS(preset_description_id_bits, "preset_description_id[i]"); } TEST_SB_SKIP("preset_description_text_present"); Presets_More.resize(num_presets_m1+1); for (int8u i=0; i<=num_presets_m1; i++) { preset_more& P=Presets_More[i]; int8u desc_text_len; Get_S1(5, desc_text_len, "desc_text_len"); Element_Begin1("preset_description"); for (int8u j=0; jGet4(Bits); Count+=1+Bits; if (!BS->GetB() || !(--MaxLoops)) break; Info<<=Bits; Info+=(1<Get4(Bits); if (!BS->GetB() || !(--MaxLoops)) break; Info<<=Bits; Info+=(1<Get4(Bits); Count+=1+Bits; if (!BS->GetB()) break; Info<<=Bits; Info+=(1<Get4(Bits); if (!BS->GetB()) break; Info<<=Bits; Info+=(1<Get4(Bits); Count+=1+Bits; if (!BS->GetB()) break; Info<<=Bits; Info+=(1<Skip(Bits); if (!BS->GetB()) break; } } } //--------------------------------------------------------------------------- void File_DolbyE::audio_segment() { //Parsing Element_Begin1("audio_segment"); #if MEDIAINFO_TRACE //CRC test size_t Pos_Begin=0; #endif //MEDIAINFO_TRACE for (int8u Channel=0; Channelmetadata_extension_segment_BitCountAfter) Skip_BS(Data_BS_Remain()-metadata_extension_segment_BitCountAfter,"reserved_metadata_extension_bits"); } Skip_S3(bit_depth, "metadata_extension_crc"); #if MEDIAINFO_TRACE //CRC test /* size_t Pos_End=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain(); int8u BitSkip_Begin=Pos_Begin%8; Pos_Begin/=8; int8u BitSkip_End=0; // Pos_End%8; Looks like that the last bits must not be in the CRC computing Pos_End/=8; if (BitSkip_End) Pos_End++; int16u CRC=CRC_16_Compute(Buffer+Pos_Begin, Pos_End-Pos_Begin, BitSkip_Begin, BitSkip_End); if (CRC) { //CRC is wrong Param_Info1("NOK"); } */ #endif //MEDIAINFO_TRACE Element_End0(); } //--------------------------------------------------------------------------- void File_DolbyE::audio_extension_segment() { //Parsing Element_Begin1("audio_extension_segment"); #if MEDIAINFO_TRACE //CRC test size_t Pos_Begin=0; #endif //MEDIAINFO_TRACE for (int8u Channel=0; Channelmeter_segment_BitCountAfter) Skip_BS(Data_BS_Remain()>meter_segment_BitCountAfter, "reserved_meter_bits"); Skip_S3(bit_depth, "meter_crc"); #if MEDIAINFO_TRACE //CRC test /* size_t Pos_End=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain(); size_t Pos_Begin=Pos_End-(meter_segment_size+1)*bit_depth; //+1 for CRC int8u BitSkip_Begin=Pos_Begin%8; Pos_Begin/=8; int8u BitSkip_End=0; // Pos_End%8; Looks like that the last bits must not be in the CRC computing Pos_End/=8; if (BitSkip_End) Pos_End++; int16u CRC=CRC_16_Compute(Buffer+Pos_Begin, Pos_End-Pos_Begin, BitSkip_Begin, BitSkip_End); if (CRC) { //CRC is wrong Param_Info1("NOK"); } */ #endif //MEDIAINFO_TRACE Element_End0(); } //--------------------------------------------------------------------------- enum ac3 { ac3_datarate, ac3_bsmod, ac3_acmod, ac3_cmixlev, ac3_surmixlev, ac3_dsurmod, ac3_lfeon, ac3_dialnorm, ac3_langcode, ac3_langcod, ac3_audprodie, ac3_mixlevel, ac3_roomtyp, ac3_copyrightb, ac3_origbs, ac3_xbsi1e, ac3_dmixmod, ac3_ltrtcmixlev, ac3_ltrtsurmixlev, ac3_lorocmixlev, ac3_lorosurmixlev, ac3_xbsi2e, ac3_dsurexmod, ac3_dheadphonmod, ac3_adconvtyp, ac3_xbsi2, ac3_encinfo, ac3_hpfon, ac3_bwlpfon, ac3_lfelpfon, ac3_sur90on, ac3_suratton, ac3_rfpremphon, ac3_compre, ac3_compr1, ac3_dynrnge, ac3_dynrng1, ac3_dynrng2, ac3_dynrng3, ac3_dynrng4, ac3_max }; void File_DolbyE::ac3_metadata_subsegment(bool xbsi) { for (int8u program=0; program=2, meta[ac3_dsurexmod]==2?"Dolby Surround EX":"Dolby Pro Logic IIz"); Get_S1 (2, meta[ac3_dheadphonmod], "ac3_dheadphonmod"); Param_Info1C(meta[ac3_dheadphonmod], "Dolby Headphone"); Get_S1 (1, meta[ac3_adconvtyp], "ac3_adconvtyp"); Param_Info1C(meta[ac3_xbsi2e] && meta[ac3_adconvtyp], "HDCD"); Get_S1 (8, meta[ac3_xbsi2], "ac3_xbsi2"); Get_S1 (1, meta[ac3_encinfo], "ac3_encinfo"); } else { Skip_S1(1, "ac3_timecode1e"); Skip_S2(14, "ac3_timecode1"); Skip_S1(1, "ac3_timecode2e"); Skip_S2(14, "ac3_timecode2"); } Get_S1 (1, meta[ac3_hpfon], "ac3_hpfon"); Get_S1 (1, meta[ac3_bwlpfon], "ac3_bwlpfon"); Get_S1 (1, meta[ac3_lfelpfon], "ac3_lfelpfon"); Get_S1 (1, meta[ac3_sur90on], "ac3_sur90on"); Get_S1 (1, meta[ac3_suratton], "ac3_suratton"); Get_S1 (1, meta[ac3_rfpremphon], "ac3_rfpremphon"); Get_S1 (1, meta[ac3_compre], "ac3_compre"); Get_S1 (8, meta[ac3_compr1], "ac3_compr1"); Param_Info2C(meta[ac3_compre], Ztring::ToZtring(meta[ac3_dynrng1]?(AC3_compr[meta[ac3_compr1]>>4]+20*std::log10(((float)(0x10+(meta[ac3_compr1]&0x0F)))/32)):0, 2), " dB"); Get_S1 (1, meta[ac3_dynrnge], "ac3_dynrnge"); Get_S1 (8, meta[ac3_dynrng1], "ac3_dynrng1"); Param_Info2C(meta[ac3_dynrnge], Ztring::ToZtring(meta[ac3_dynrng1]?(AC3_dynrng[meta[ac3_dynrng1]>>5]+20*std::log10(((float)(0x20+(meta[ac3_dynrng1]&0x1F)))/64)):0, 2), " dB"); Get_S1 (8, meta[ac3_dynrng2], "ac3_dynrng2"); Param_Info2C(meta[ac3_dynrnge], Ztring::ToZtring(meta[ac3_dynrng2]?(AC3_dynrng[meta[ac3_dynrng2]>>5]+20*std::log10(((float)(0x20+(meta[ac3_dynrng2]&0x1F)))/64)):0, 2), " dB"); Get_S1 (8, meta[ac3_dynrng3], "ac3_dynrng3"); Param_Info2C(meta[ac3_dynrnge], Ztring::ToZtring(meta[ac3_dynrng3]?(AC3_dynrng[meta[ac3_dynrng3]>>5]+20*std::log10(((float)(0x20+(meta[ac3_dynrng3]&0x1F)))/64)):0, 2), " dB"); Get_S1 (8, meta[ac3_dynrng4], "ac3_dynrng4"); Param_Info2C(meta[ac3_dynrnge], Ztring::ToZtring(meta[ac3_dynrng4]?(AC3_dynrng[meta[ac3_dynrng4]>>5]+20*std::log10(((float)(0x20+(meta[ac3_dynrng4]&0x1F)))/64)):0, 2), " dB"); Element_End0(); FILLING_BEGIN() if (!Frame_Count) { if (program >= Count_Get(Stream_Audio)) Stream_Prepare(Stream_Audio); Fill(Stream_Audio, program, "AC3_Metadata", "Yes"); if (meta[ac3_datarate]<19) { Fill(Stream_Audio, program, "AC3_Metadata BitRate", AC3_BitRate[meta[ac3_datarate]]*1000); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata BitRate", "N NTY"); Fill(Stream_Audio, program, "AC3_Metadata BitRate/String", Ztring::ToZtring(AC3_BitRate[meta[ac3_datarate]])+__T(" kbps")); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata BitRate/String", "Y NTN"); } Fill(Stream_Audio, program, "AC3_Metadata ServiceKind", AC3_Mode[meta[ac3_bsmod]]); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata ServiceKind", "N NTY"); Fill(Stream_Audio, program, "AC3_Metadata ServiceKind/String", AC3_Mode_String[meta[ac3_bsmod]]); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata ServiceKind/String", "Y NTN"); int8u Channels = AC3_Channels[meta[ac3_acmod]]; Ztring ChannelPositions; ChannelPositions.From_UTF8(AC3_ChannelPositions[meta[ac3_acmod]]); Ztring ChannelPositions2; ChannelPositions2.From_UTF8(AC3_ChannelPositions2[meta[ac3_acmod]]); Ztring ChannelLayout; ChannelLayout.From_UTF8(meta[ac3_lfeon] ? AC3_ChannelLayout_lfeon[meta[ac3_acmod]] : AC3_ChannelLayout_lfeoff[meta[ac3_acmod]]); if (meta[ac3_lfeon]) { Channels += 1; ChannelPositions += __T(", LFE"); ChannelPositions2 += __T(".1"); } Fill(Stream_Audio, program, "AC3_Metadata ChannelLayout", ChannelLayout); //Surround if (meta[ac3_dsurmod]==2) { Fill(Stream_Audio, program, Audio_Format_Settings, "Dolby Surround"); } if (meta[ac3_dsurexmod]==2) { Fill(Stream_Audio, program, Audio_Format_Settings, "Dolby Surround EX"); } if (meta[ac3_dsurexmod]==3) { Fill(Stream_Audio, program, Audio_Format_Settings, "Dolby Pro Logic IIz"); } if (meta[ac3_dheadphonmod]==2) { Fill(Stream_Audio, program, Audio_Format_Settings, "Dolby Headphone"); } // Metadata Fill(Stream_Audio, program, "AC3_Metadata dialnorm", meta[ac3_dialnorm]==0?-31:-(int)meta[ac3_dialnorm]); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata dialnorm", "N NT"); Fill(Stream_Audio, program, "AC3_Metadata dialnorm/String", Ztring::ToZtring(meta[ac3_dialnorm]==0?-31:-(int)meta[ac3_dialnorm])+__T(" dB")); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata dialnorm/String", "Y NTN"); if (meta[ac3_compre]) { float64 Value; if (meta[ac3_compr1]==0) Value=0; //Special case in the formula else Value=AC3_compr[meta[ac3_compr1]>>4]+20*std::log10(((float)(0x10+(meta[ac3_compr1]&0x0F)))/32); Fill(Stream_Audio, program, "AC3_Metadata compr", Value, 2); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata compr", "N NT"); Fill(Stream_Audio, program, "AC3_Metadata compr/String", Ztring::ToZtring(Value, 2)+__T(" dB")); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata compr/String", "Y NTN"); } else if (meta[ac3_compr1]) { Fill(Stream_Audio, program, "AC3_Metadata comprprof", AC3_dynrngprof_Get(meta[ac3_compr1])); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata comprprof", "Y NT"); } if (meta[ac3_dynrnge]) { float64 Value; if (meta[ac3_dynrng1]==0) Value=0; //Special case in the formula else Value=AC3_dynrng[meta[ac3_dynrng1]>>5]+20*std::log10(((float)(0x20+(meta[ac3_dynrng1]&0x1F)))/64); Fill(Stream_Audio, program, "AC3_Metadata dynrng", Value, 2); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata dynrng", "N NT"); Fill(Stream_Audio, program, "AC3_Metadata dynrng/String", Ztring::ToZtring(Value, 2)+__T(" dB")); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata dynrng/String", "Y NTN"); } else if (meta[ac3_dynrng1]) { Fill(Stream_Audio, program, "AC3_Metadata dynrngprof", AC3_dynrngprof_Get(meta[ac3_dynrng1])); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata dynrngprof", "Y NT"); } // Other metadata if (meta[ac3_cmixlev]<=2) { string Value = Ztring::ToZtring(-3 - ((float)meta[ac3_cmixlev]) * 1.5, 1).To_UTF8(); Fill(Stream_Audio, program, "AC3_Metadata cmixlev", Value); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata cmixlev", "N NT"); Fill(Stream_Audio, program, "AC3_Metadata cmixlev/String", Value + " dB"); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata cmixlev/String", "Y NTN"); } if (meta[ac3_surmixlev]<=2) { string Value = (meta[ac3_surmixlev]==2?string("-inf"):to_string(-3 - (int)meta[ac3_cmixlev] * 3)); Fill(Stream_Audio, program, "AC3_Metadata surmixlev", Value + " dB"); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata surmixlev", "N NT"); Fill(Stream_Audio, program, "AC3_Metadata surmixlev/String", Value + " dB"); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata surmixlev/String", "Y NTN"); } if (meta[ac3_audprodie]) { string Value = to_string(80 + meta[ac3_mixlevel]); Fill(Stream_Audio, program, "AC3_Metadata mixlevel", Value); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata mixlevel", "N NT"); Fill(Stream_Audio, program, "AC3_Metadata mixlevel/String", Value + " dB"); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata mixlevel/String", "Y NTN"); if (meta[ac3_roomtyp]) { Fill(Stream_Audio, program, "AC3_Metadata roomtyp", AC3_roomtyp[meta[ac3_roomtyp] - 1]); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata roomtyp", "Y NTY"); } } if (xbsi) { if (meta[ac3_xbsi1e]) { if (meta[ac3_dmixmod]) { Fill(Stream_Audio, program, "AC3_Metadata dmixmod", AC3_dmixmod[meta[ac3_dmixmod] - 1]); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata dmixmod", "Y NTY"); } AC3_Level_Fill(this, program, meta[ac3_ltrtcmixlev], 3, 1.5, "AC3_Metadata ltrtcmixlev"); AC3_Level_Fill(this, program, meta[ac3_ltrtsurmixlev], 3, 1.5, "AC3_Metadata ltrtsurmixlev"); AC3_Level_Fill(this, program, meta[ac3_lorocmixlev], 3, 1.5, "AC3_Metadata lorocmixlev"); AC3_Level_Fill(this, program, meta[ac3_lorosurmixlev], 3, 1.5, "AC3_Metadata lorosurmixlev"); } if (meta[ac3_xbsi2e] && meta[ac3_adconvtyp]) { Fill(Stream_Audio, program, "AC3_Metadata adconvtyp", "HDCD"); Fill_SetOptions(Stream_Audio, program, "AC3_Metadata adconvtyp", "Y NTY"); } } Fill(Stream_Audio, program, "AC3_Metadata hpfon", meta[ac3_hpfon] ? "Yes" : "No"); Fill(Stream_Audio, program, "AC3_Metadata bwlpfon", meta[ac3_bwlpfon] ? "Yes" : "No"); Fill(Stream_Audio, program, "AC3_Metadata lfelpfon", meta[ac3_lfelpfon] ? "Yes" : "No"); Fill(Stream_Audio, program, "AC3_Metadata sur90on", meta[ac3_sur90on] ? "Yes" : "No"); Fill(Stream_Audio, program, "AC3_Metadata suratton", meta[ac3_suratton] ? "Yes" : "No"); Fill(Stream_Audio, program, "AC3_Metadata rfpremphon", meta[ac3_rfpremphon] ? "Yes" : "No"); } FILLING_END() } for (int8u program=0; program