/* 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_AC4_YES) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Audio/File_Ac4.h" #include "MediaInfo/MediaInfo_Config_MediaInfo.h" #include #include #include using namespace ZenLib; using namespace std; //--------------------------------------------------------------------------- namespace MediaInfoLib { typedef File_Ac4::dmx::cdmx::gain::type gain; //*************************************************************************** // Infos //*************************************************************************** //--------------------------------------------------------------------------- // CRC_16_Table extern const int16u CRC_16_Table[256]; //--------------------------------------------------------------------------- extern const float64 Ac4_frame_rate[2][16]= { { //44.1 kHz (float64)0, (float64)0, (float64)0, (float64)0, (float64)0, (float64)0, (float64)0, (float64)0, (float64)0, (float64)0, (float64)0, (float64)0, (float64)0, (float64)11025/(float64)512, (float64)0, (float64)0, }, { //48 kHz (float64)24000/(float64)1001, (float64)24, (float64)25, (float64)30000/(float64)1001, (float64)30, (float64)48000/(float64)1001, (float64)48, (float64)50, (float64)60000/(float64)1001, (float64)60, (float64)100, (float64)120000/(float64)1001, (float64)120, (float64)12000/(float64)512, (float64)0, (float64)0, }, }; //--------------------------------------------------------------------------- typedef const float sized_array_float[]; string Value(const sized_array_float Array, size_t Pos, size_t AfterComma=3) { if (Pos++>=(size_t)Array[0] || !Array[Pos]) return "Index "+Ztring::ToZtring(Pos).To_UTF8(); if (Array[Pos]==-FLT_MAX) return "-inf"; if (Array[Pos]==FLT_MAX) return "inf"; return Ztring(Ztring::ToZtring(Array[Pos], AfterComma)).To_UTF8(); } typedef const char* sized_array_string[]; string Value(const sized_array_string Array, size_t Pos) { if (Pos++>=(size_t)Array[0] || !Array[Pos]) return Ztring::ToZtring(Pos-1).To_UTF8(); return Array[Pos]; } bool Value_IsEmpty(const sized_array_string Array, size_t Pos) { if (Pos++>=(size_t)Array[0] || !Array[Pos]) return false; return !Array[Pos][0]; } static const int16u Ac4_fs_index[2]= { 44100, 48000, }; static const variable_size Ac4_channel_mode[]= { {13, 0}, // Total size {1, 0x00}, // 0b0 {1, 0x01}, // 0b10 {2, 0x0C}, // 0b1100 {0, 0x0D}, // 0b1101 {0, 0x0E}, // 0b1110 {3, 0x78}, // 0b1111000 {0, 0x79}, // 0b1111001 {0, 0x7A}, // 0b1111010 {0, 0x7B}, // 0b1111011 {0, 0x7C}, // 0b1111100 {0, 0x7D}, // 0b1111101 {0, 0x7E}, // 0b1111110 {0, 0x7F}, // 0b1111111 }; static const variable_size Ac4_channel_mode2[]= { {17, 0}, // Total size {1, 0x000}, // 0b0 {1, 0x002}, // 0b10 {2, 0x00C}, // 0b1100 {0, 0x00D}, // 0b1101 {0, 0x00E}, // 0b1110 {3, 0x078}, // 0b1111000 {0, 0x079}, // 0b1111001 {0, 0x07A}, // 0b1111010 {0, 0x07B}, // 0b1111011 {0, 0x07C}, // 0b1111100 {0, 0x07D}, // 0b1111101 {1, 0x0FC}, // 0b11111100 {0, 0x0FD}, // 0b11111101 {1, 0x1FC}, // 0b111111100 {0, 0x1FD}, // 0b111111101 {0, 0x1FE}, // 0b111111110 {0, 0x1FF}, // 0b111111111 }; enum content_classifier { CM, ME, VI, HI, D, Co, E, VO, A, //Generic "Associate" }; static const sized_array_string Ac4_content_classifier= { (const char*)9, "Main", "Music and Effects", "Visually Impaired", "Hearing Impaired", "Dialogue", "Commentary", "Emergency", "Voice Over", "Associate", //Generic "Associate" }; static const sized_array_string Ac4_ch_mode_String= { (const char*)16, "Mono", "Stereo", "3.0", "5.0", "5.1", "7.0 3/4/0", "7.1 3/4/0.1", "7.0 5/2/0", "7.1 5/2/0.1", "7.0 3/2/2", "7.1 3/2/2.1", "7.0.4", "7.1.4", "9.0.4", "9.1.4", "22.2", }; enum ch { L = 1 << 0, R = 1 << 1, C = 1 << 2, LFE = 1 << 3, Ls = 1 << 4, Rs = 1 << 5, Lb = 1 << 6, Rb = 1 << 7, Tfl = 1 << 8, Tfr = 1 << 9, Tl = 1 << 10, Tr = 1 << 11, Tbl = 1 << 12, Tbr = 1 << 13, Lw = 1 << 14, Rw = 1 << 15, LFE2 = 1 << 16, // Not in nonstd_bed_channel_assignment Cb = 1 << 17, Lscr = 1 << 18, Rscr = 1 << 19, Tsl = 1 << 20, Tsr = 1 << 21, Tc = 1 << 22, Bfl = 1 << 23, Bfr = 1 << 24, Bfc = 1 << 25, Tfc = 1 << 26, Tbc = 1 << 27, Vhl = 1 << 26, Vhr = 1 << 27, ch_Max = 1 << 31 }; static const size_t Ac4_channel_mask_Size=19; static ch Ac4_channel_mask[Ac4_channel_mask_Size][2] = { {L, R}, {C, ch_Max}, {Ls, Rs}, {Lb, Rb}, {Tfl, Tfr}, {Tbl, Tbr}, {LFE, ch_Max}, {Tl, Tr}, {Tsl, Tsr}, {Tfc, ch_Max}, {Tbc, ch_Max}, {Tc, ch_Max}, {LFE2, ch_Max}, {Bfl, Bfr}, {Bfc, ch_Max}, {Cb, ch_Max}, {Lscr, Rscr}, {Lw, Rw}, {Vhl, Vhr}, }; static const sized_array_string Ac4_immersive_stereo_String= { (const char*)2, "Multichannel Content", "Dolby Atmos Content", }; static int32u Ac4_ch_mode_2_nonstd_Values[16]= { 0, //Mono L | R, //Stereo L | R | C, //3.0 L | R | C | Ls | Rs, //5.0 L | R | C | Ls | Rs | LFE, //5.1 L | R | C | Ls | Rs | Lb | Rb, //7.0 3/4/0 L | R | C | Ls | Rs | Lb | Rb | LFE, //7.1 3/4/0 L | R | C | Ls | Rs | Lw | Rw, //7.0 5/2/0 L | R | C | Ls | Rs | Lw | Rw | LFE, //7.1 5/2/0 L | R | C | Ls | Rs | Vhl | Vhl, //7.0 3/2/2 L | R | C | Ls | Rs | Vhl | Vhl | LFE, //7.1 3/2/2 L | R | C | Ls | Rs | Lb | Rb | Tfl | Tfr | Tbl | Tbr, //7.0.4 L | R | C | Ls | Rs | Lb | Rb | Tfl | Tfr | Tbl | Tbr | LFE, //7.1.4 L | R | C | Ls | Rs | Lb | Rb | Tfl | Tfr | Tbl | Tbr | Lscr | Rscr, //9.0.4 L | R | C | Ls | Rs | Lb | Rb | Tfl | Tfr | Tbl | Tbr | Lscr | Rscr | LFE, //9.1.4 L | R | C | Ls | Rs | Lb | Rb | Lw | Rw | Cb | Tfc | Tbc | Tfl | Tfr | Tbl | Tbr | Tsl | Tsr | Tc | Bfl | Bfr | Bfc | LFE | LFE2, //22.2 }; static int32u Ac4_ch_mode_2_nonstd(int8u ch_mode, bool b_4_back_channels_present=false, bool b_centre_present=false, int8u top_channels_present=0) { if (ch_mode>15) return (int32u)-1; int32u Value=Ac4_ch_mode_2_nonstd_Values[ch_mode]; if (ch_mode>=11 && ch_mode<=14) { if (!b_4_back_channels_present) Value&=~(Lb | Rb); if (!b_centre_present) Value&=~(LFE); if (top_channels_present<=1) Value&=~(Tbl | Tbr); if (!top_channels_present || top_channels_present==2) Value&=~(Tfl | Tfr); } return Value; } static string Ac4_nonstd_2_ch_mode_String(int32u nonstd_bed_channel_assignment_mask) { if (!nonstd_bed_channel_assignment_mask) return "Mono"; string ToReturn="0.0.0"; for (int8u i=0; i<17; i++) { int32u Value=nonstd_bed_channel_assignment_mask&(1<=2 && ch_mode<=15))?true:false; } //--------------------------------------------------------------------------- static inline bool Channel_Mode_Contains_Lr(int8u ch_mode) { return (ch_mode>=1 && ch_mode<=15)?true:false; } //--------------------------------------------------------------------------- static inline bool Channel_Mode_Contains_LsRs(int8u ch_mode) { return (ch_mode>=3 && ch_mode<=15)?true:false; } //--------------------------------------------------------------------------- static inline bool Channel_Mode_Contains_LrsRrs(int8u ch_mode) { return (ch_mode==5 || ch_mode==6 || (ch_mode>=11 && ch_mode<=15))?true:false; } //--------------------------------------------------------------------------- static inline bool Channel_Mode_Contains_LwRw(int8u ch_mode) { return (ch_mode==7 || ch_mode==8 || ch_mode==15)?true:false; } //--------------------------------------------------------------------------- static inline bool Channel_Mode_Contains_VhlVhr(int8u ch_mode) { return (ch_mode==9 || ch_mode==10)?true:false; } //--------------------------------------------------------------------------- static inline bool Channel_Mode_Contains_LscrRscr(int8u ch_mode) { return (ch_mode == 13 || ch_mode == 14) ? true : false; } //--------------------------------------------------------------------------- static inline int8u objs_to_channel_mode(int8u n_objects_code) { if (n_objects_code && n_objects_code<=4) return n_objects_code-1; return (int8u)-1; //Reserved/Unknown/Problem } //--------------------------------------------------------------------------- static inline int8u objs_to_n_objects(int8u n_objects_code, bool b_lfe) { if (n_objects_code<=3) return n_objects_code+(b_lfe?1:0); if (n_objects_code==4) return 5+(b_lfe?1:0); return (int8u)-1; //Reserved/Unknown/Problem } //--------------------------------------------------------------------------- static const char* AC4_nonstd_bed_channel_assignment_mask_ChannelLayout_List[17+11] = { "L", "R", "C", "LFE", "Ls", "Rs", "Lb", "Rb", "Tfl", "Tfr", "Tsl", //Tl "Tsr", //Tr "Tbl", "Tbr", "Lw", "Rw", "LFE2", // Not in nonstd_bed_channel_assignment "Cb", "Lscr", "Rscr", "Tsl", "Tsr", "Tc", "Bfl", "Bfr", "Bfc", "Tfc", "Tbc", }; static int8s AC4_nonstd_bed_channel_assignment_mask_ChannelLayout_Reordering[17+11] = { 0, 0, 0, 0, 0, 0, 0, 0, 6, // Wide channels before top layer 6, // Wide channels before top layer -2, -2, -2, -2, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static Ztring AC4_nonstd_bed_channel_assignment_mask_ChannelLayout(int32u nonstd_bed_channel_assignment_mask, size_t Groups_Size=0) { if (!nonstd_bed_channel_assignment_mask) return Groups_Size==1?__T("M"):__T("C"); Ztring ToReturn; for (int8u i=0; i<17+11; i++) { int8u i2=i+AC4_nonstd_bed_channel_assignment_mask_ChannelLayout_Reordering[i]; if (nonstd_bed_channel_assignment_mask&(1<1) ToReturn|=(1<<(j++)); } else j+=AC4_bed_channel_assignment_mask_ChannelLayout_Mapping[i]; } return ToReturn; } static int32u AC4_bed_chan_assign_code_2_nonstd_Values[8]= { L | R, //Stereo L | R | C, //3.0 L | R | C | Ls | Rs | LFE, //5.1 L | R | C | Ls | Rs | Tl | Tr | LFE, //5.1.2 L | R | C | Ls | Rs | Tfl | Tfr | Tbl | Tbr | LFE, //5.1.4 L | R | C | Ls | Rs | Lb | Rb | LFE, //7.1 3/4/0 L | R | C | Ls | Rs | Lb | Rb | Tl | Tr | LFE, //7.1.2 L | R | C | Ls | Rs | Lb | Rb | Tfl | Tfr | Tbl | Tbr | LFE, //7.1.4 }; static int32u AC4_bed_chan_assign_code_2_nonstd(int8u bed_chan_assign_code) { return AC4_bed_chan_assign_code_2_nonstd_Values[bed_chan_assign_code]; } //--------------------------------------------------------------------------- static int32u AC4_nonstd_2_desc_Values[17] = { 0, 0, 0, 1, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, }; static string AC4_nonstd_2_desc(int32u nonstd_bed_channel_assignment_mask) { string ToReturn="0.0.0"; for (int8u i=0; i<17; i++) if (nonstd_bed_channel_assignment_mask&(1<=7) return -INFINITY; return 1.5*(-((int)code)+2); }; //--------------------------------------------------------------------------- static const float32 gain_xx_Values(int8u code) { if (code>=7) return -INFINITY; if (code>=4) return 3*(-((int)code)+2); return 1.5*(-((int)code)); }; //--------------------------------------------------------------------------- static const char* gain_Text[] = { "ScreenToCenter", "ScreenToFront", "Back4ToBack2", "Top4ToTop2", "TopFrontToFront", "TopFrontToSide", "TopFrontToBack", "TopBackToFront", "TopBackToSide", "TopBackToBack", }; static constexpr size_t gain_Size=sizeof(gain_Text)/sizeof(const char*); //*************************************************************************** // Constructor/Destructor //*************************************************************************** //--------------------------------------------------------------------------- File_Ac4::File_Ac4() :File__Analyze() { //Configuration #if MEDIAINFO_TRACE Trace_Layers_Update(8); //Stream #endif //MEDIAINFO_TRACE MustSynchronize=true; Buffer_TotalBytes_FirstSynched_Max=64*1024; Buffer_TotalBytes_Fill_Max=1024*1024; PTS_DTS_Needed=true; StreamSource=IsStream; Frame_Count_NotParsedIncluded=0; //In Frame_Count_Valid=0; MustParse_dac4=false; } //--------------------------------------------------------------------------- File_Ac4::~File_Ac4() { } //*************************************************************************** // Streams management //*************************************************************************** //--------------------------------------------------------------------------- void File_Ac4::Streams_Fill() { //I-Frames Ztring IFrames_Value; if (IFrames.size()>1) { set IFrames_IsVariable; for (size_t i=1; i::iterator It=IFrames_IsVariable.begin(); size_t Value1=*It; It++; size_t Value2=*It; if (Value1+1==Value2) { if ((size_t)Ac4_frame_rate[fs_index][frame_rate_index]==Value1) // if Frame rate is in I-frame interval, use frame rate)) IFrames_Value=Ztring::ToZtring(Ac4_frame_rate[fs_index][frame_rate_index], 3); else IFrames_Value=Ztring::ToZtring(Value1)+__T('/')+Ztring::ToZtring(Value2); } } } //Filling Fill(Stream_General, 0, General_Format, "AC-4"); Stream_Prepare(Stream_Audio); Fill(Stream_Audio, 0, Audio_Format, "AC-4"); Fill(Stream_Audio, 0, Audio_Format_Commercial_IfAny, "Dolby AC-4"); Fill(Stream_Audio, 0, Audio_Format_Version, __T("Version ")+Ztring::ToZtring(bitstream_version)); Fill(Stream_Audio, 0, "bitstream_version", bitstream_version, 10, true);//TODO remove Fill_SetOptions(Stream_Audio, 0, "bitstream_version", "N NTN"); //TODO remove Fill(Stream_Audio, 0, Audio_SamplingRate, fs_index?48000:44100); Fill(Stream_Audio, 0, Audio_FrameRate, Ac4_frame_rate[fs_index][frame_rate_index]); if (!IFrames_Value.empty()) Fill_Measure(Stream_Audio, 0, "IFrameInterval", IFrames_Value, __T(" frames")); //If no frame, use dac4 content bool IsUsingDac4; if (Presentations.empty() && Groups.empty() && AudioSubstreams.empty()) { Presentations=Presentations_dac4; Groups=Groups_dac4; IsUsingDac4=true; } else IsUsingDac4=false; //Filling if (!Presentations.empty()) Fill(Stream_Audio, 0, "NumberOfPresentations", Presentations.size()); if (!Groups.empty() && bitstream_version>=2) Fill(Stream_Audio, 0, "NumberOfGroups", Groups.size()); if (!AudioSubstreams.empty()) Fill(Stream_Audio, 0, "NumberOfSubstreams", AudioSubstreams.size()); for (size_t p=0; p=11 && Presentation_Current.pres_ch_mode<=14) { if (!Presentation_Current.b_pres_4_back_channels_present) ChannelMode[0]-=2; if (!Presentation_Current.b_pres_centre_present) ChannelMode[0]-=1; if (Presentation_Current.pres_top_channel_pairs!=2) ChannelMode[4]-=2*(2-Presentation_Current.pres_top_channel_pairs); if (Channel_Mode_Contains_LscrRscr(Presentation_Current.pres_ch_mode)) ChannelMode += " (scr)"; } } else { for (size_t i=0; i=2) { for (size_t s=0; s PresentationConfigs; if (PresentationConfigs.empty()) { //Check content_classifer from presentations for (size_t p=0; p::iterator PresentationConfig=PresentationConfigs.begin(); PresentationConfig!=PresentationConfigs.end(); ++PresentationConfig) { if (!Summary.empty()) Summary+=" / "; Summary+=*PresentationConfig; } Fill(Stream_Audio, 0, G.c_str(), Summary); Fill(Stream_Audio, 0, (G+" Pos").c_str(), g); Fill_SetOptions(Stream_Audio, 0, (G+" Pos").c_str(), "N NIY"); if (Group.ContentInfo.content_classifier!=(int8u)-1) Fill(Stream_Audio, 0, (G+" Classifier").c_str(), Value(Ac4_content_classifier, Group.ContentInfo.content_classifier)); if (!Group.ContentInfo.language_tag_bytes.empty()) { Fill(Stream_Audio, 0, (G+" Language").c_str(), Group.ContentInfo.language_tag_bytes); Fill(Stream_Audio, 0, (G+" Language/String").c_str(), MediaInfoLib::Config.Iso639_Translate(Ztring().From_UTF8(Group.ContentInfo.language_tag_bytes))); Fill_SetOptions(Stream_Audio, 0, (G+" Language").c_str(), "N NTY"); Fill_SetOptions(Stream_Audio, 0, (G+" Language/String").c_str(), "Y NTN"); } Fill(Stream_Audio, 0, (G+" ChannelCoded").c_str(), Group.b_channel_coded?"Yes":"No"); for (size_t s=0; s=num_channels_in_bed_Total) Fill(Stream_Audio, 0, (G+" NumberOfDynamicObjects").c_str(), n_objects-num_channels_in_bed_Total); } ZtringList SubstreamPos, SubstreamNum; for (size_t s=0; s::iterator Substream_Type_Item=Substream_Type.begin(); for (; Substream_Type_Item!=Substream_Type.end() && Substream_Type_Item->first!=GroupInfo.substream_index; Substream_Type_Item++) if (Substream_Type_Item->second==Type_Ac4_Substream) AudioSubstream_Pos++; if (Substream_Type_Item==Substream_Type.end()) continue; SubstreamPos.push_back(Ztring::ToZtring(AudioSubstream_Pos)); SubstreamNum.push_back(Ztring::ToZtring(AudioSubstream_Pos+1)); } SubstreamPos.Separator_Set(0, __T(" + ")); Fill(Stream_Audio, 0, (G+" LinkedTo_Substream_Pos").c_str(), SubstreamPos.Read()); Fill_SetOptions(Stream_Audio, 0, (G+" LinkedTo_Substream_Pos").c_str(), "N NIY"); SubstreamNum.Separator_Set(0, __T(" + ")); Fill(Stream_Audio, 0, (G+" LinkedTo_Substream_Pos/String").c_str(), SubstreamNum.Read()); Fill_SetOptions(Stream_Audio, 0, (G+" LinkedTo_Substream_Pos/String").c_str(), "Y NIN"); } for (map::iterator Substream_Info=AudioSubstreams.begin(); Substream_Info!=AudioSubstreams.end(); Substream_Info++) { string ChannelMode, ImmersiveStereo; for (size_t g=0; gfirst) { if (Groups[g].b_channel_coded) { ChannelMode2=Value(Ac4_ch_mode_String, GroupInfo.ch_mode); if (GroupInfo.immersive_stereo!=(int8u)-1) ImmersiveStereo2=Value(Ac4_immersive_stereo_String, GroupInfo.immersive_stereo); if (GroupInfo.ch_mode>=11 && GroupInfo.ch_mode<=14) { if (!GroupInfo.b_4_back_channels_present) ChannelMode2[0]-=2; if (!GroupInfo.b_centre_present) ChannelMode2[0]-=1; if (GroupInfo.top_channel_pairs!=2) ChannelMode2[4]-=2*(2-GroupInfo.top_channel_pairs); if (Channel_Mode_Contains_LscrRscr(GroupInfo.ch_mode)) ChannelMode2 += " (scr)"; } } else if (GroupInfo.b_ajoc) { ChannelMode2="A-JOC "; ChannelMode2+=Ztring::ToZtring(GroupInfo.n_fullband_upmix_signals).To_UTF8(); ChannelMode2+='.'; ChannelMode2+='0'+GroupInfo.b_lfe; ChannelMode2+=" ("; ChannelMode2+=Ztring::ToZtring(GroupInfo.n_fullband_dmx_signals).To_UTF8(); ChannelMode2+='.'; ChannelMode2+='0'+GroupInfo.b_lfe; ChannelMode2+=' '; ChannelMode2+=GroupInfo.b_static_dmx?"channel":"object"; ChannelMode2+=" core)"; } else if (!GroupInfo.b_ajoc && GroupInfo.n_objects_code!=(int8u)-1) { int8u n=objs_to_n_objects(GroupInfo.n_objects_code, GroupInfo.b_lfe); if (n!=(int8u)-1) { ChannelMode2=Ztring::ToZtring(n-(GroupInfo.b_lfe?1:0)).To_UTF8(); if (GroupInfo.b_lfe) ChannelMode2+=".1"; ChannelMode2+=" objects"; } else ChannelMode2="n_objects_code="+Ztring::ToZtring(GroupInfo.n_objects_code).To_UTF8()+" b_lfe="+(GroupInfo.b_lfe?'1':'0'); } if (!ChannelMode2.empty() && ChannelMode2!=ChannelMode) { if (!ChannelMode.empty()) ChannelMode+=" + "; ChannelMode+=ChannelMode2; } if (!ImmersiveStereo2.empty() && ImmersiveStereo2!=ImmersiveStereo) { if (!ImmersiveStereo.empty()) ImmersiveStereo+=" + "; ImmersiveStereo+=ImmersiveStereo2; } } } } string Summary=ChannelMode; if (Summary.empty()) { Summary="?"; } size_t AudioSubstream_Pos=0; for (std::map::iterator Substream_Type_Item=Substream_Type.begin(); Substream_Type_Item!=Substream_Type.end() && Substream_Type_Item->first!=Substream_Info->first; Substream_Type_Item++) if (Substream_Type_Item->second==Type_Ac4_Substream) AudioSubstream_Pos++; string S=Ztring(__T("Substream")+Ztring::ToZtring(AudioSubstream_Pos)).To_UTF8(); Fill(Stream_Audio, 0, S.c_str(), Summary); Fill(Stream_Audio, 0, (S+" Pos").c_str(), AudioSubstream_Pos); Fill_SetOptions(Stream_Audio, 0, (S+" Pos").c_str(), "N NIY"); Fill(Stream_Audio, 0, (S+" Index").c_str(), Substream_Info->first); Fill_SetOptions(Stream_Audio, 0, (S+" Index").c_str(), "N NIY"); if (!ChannelMode.empty()) { Fill(Stream_Audio, 0, (S+" ChannelMode").c_str(), ChannelMode); } if (!ImmersiveStereo.empty()) { Fill(Stream_Audio, 0, (S+" ImmersiveStereo").c_str(), ImmersiveStereo); } //Info from group bool b_channel_coded=false; bool b_de_data_present=false; int8u de_max_gain, de_channel_config; for (size_t i=0; i first) { const group_substream& GroupInfo=Groups[i].Substreams[j]; if (Groups[i].b_channel_coded) { //Channel based b_channel_coded=true; const de_info& D=Substream_Info->second.DeInfo; //b_de_data_present=D.b_de_data_present; //if (b_de_data_present) //{ // de_max_gain=D.Config.de_max_gain; // de_channel_config=D.Config.de_channel_config; //} Fill_Dup(Stream_Audio, 0, (S + " ChannelLayout").c_str(), AC4_nonstd_bed_channel_assignment_mask_ChannelLayout(Ac4_ch_mode_2_nonstd(GroupInfo.ch_mode, GroupInfo.b_4_back_channels_present, GroupInfo.b_centre_present, GroupInfo.top_channels_present), Groups.size())); } else if (GroupInfo.b_ajoc || GroupInfo.n_objects_code!=(int8u)-1) { //Object based int8u n_objects; if (!GroupInfo.b_ajoc) { n_objects=objs_to_n_objects(GroupInfo.n_objects_code, GroupInfo.b_lfe); Fill_Dup(Stream_Audio, 0, (S+" NumberOfObjects").c_str(), Ztring::ToZtring(n_objects)); //b_de_data_present=Substream_Info->second.b_dialog; //if (b_de_data_present) //{ // de_max_gain=Substream_Info->second.dialog_max_gain; // de_channel_config=(int8u)-1; //} } if (GroupInfo.nonstd_bed_channel_assignment_mask!=(int32u)-1) { Ztring BedChannelConfiguration=AC4_nonstd_bed_channel_assignment_mask_ChannelLayout(GroupInfo.nonstd_bed_channel_assignment_mask, Groups.size()); int8u num_channels_in_bed=AC4_nonstd_bed_channel_assignment_mask_2_num_channels_in_bed(GroupInfo.nonstd_bed_channel_assignment_mask); if (!GroupInfo.b_ajoc && n_objects>num_channels_in_bed) Fill_Dup(Stream_Audio, 0, (S+" NumberOfDynamicObjects").c_str(), Ztring::ToZtring(n_objects-num_channels_in_bed)); Fill_Dup(Stream_Audio, 0, (S+" BedChannelCount").c_str(), Ztring::ToZtring(num_channels_in_bed)); Fill_SetOptions(Stream_Audio, 0, (S+" BedChannelCount").c_str(), "N NIY"); Fill_Dup(Stream_Audio, 0, (S+" BedChannelCount/String").c_str(), MediaInfoLib::Config.Language_Get(Ztring::ToZtring(num_channels_in_bed), __T(" channel"))); Fill_SetOptions(Stream_Audio, 0, (S+" BedChannelCount/String").c_str(), "Y NIN"); Fill_Dup(Stream_Audio, 0, (S+" BedChannelConfiguration").c_str(), BedChannelConfiguration); } } } } if (Substream_Info->second.LoudnessInfo.dialnorm_bits!=(int8u)-1) Fill(Stream_Audio, 0, (S+" dialnorm").c_str(), -0.25*Substream_Info->second.LoudnessInfo.dialnorm_bits, 2); { const preprocessing& P=Substream_Info->second.Preprocessing; bitset<3> Preprocessing_Available; Preprocessing_Available[0]=(P.pre_dmixtyp_2ch!=(int8u)-1 && (!Value_IsEmpty(Ac4_pre_dmixtyp_2ch, P.pre_dmixtyp_2ch) || !Value_IsEmpty(Ac4_phase90_info_2ch, P.phase90_info_2ch))); Preprocessing_Available[1]=(P.pre_dmixtyp_5ch!=(int8u)-1 && (!Value_IsEmpty(Ac4_pre_dmixtyp_5ch, P.pre_dmixtyp_5ch))); Preprocessing_Available[2]=(P.phase90_info_mc!=(int8u)-1 && (!Value_IsEmpty(Ac4_phase90_info_mc, P.phase90_info_mc) || P.b_surround_attenuation_known || P.b_lfe_attenuation_known)); if (Preprocessing_Available.any()) { Fill(Stream_Audio, 0, (S+" Preprocessing").c_str(), "Yes"); if (Preprocessing_Available[0]) { Fill(Stream_Audio, 0, (S+" Preprocessing PreviousMixType2ch").c_str(), Value(Ac4_pre_dmixtyp_2ch, P.pre_dmixtyp_2ch)); Fill(Stream_Audio, 0, (S+" Preprocessing Phase90FilterInfo2ch").c_str(), Value(Ac4_phase90_info_2ch, P.phase90_info_2ch)); } if (Preprocessing_Available[1]) { Fill(Stream_Audio, 0, (S+" Preprocessing PreviousDownmixType5ch").c_str(), Value(Ac4_pre_dmixtyp_5ch, P.pre_dmixtyp_5ch)); } if (Preprocessing_Available[2]) { Fill(Stream_Audio, 0, (S+" Preprocessing Phase90FilterInfo").c_str(), Value(Ac4_phase90_info_mc, P.phase90_info_mc)); Fill(Stream_Audio, 0, (S+" Preprocessing SurroundAttenuationKnown").c_str(), P.b_surround_attenuation_known?"Yes":"No"); Fill(Stream_Audio, 0, (S+" Preprocessing LfeAttenuationKnown").c_str(), P.b_lfe_attenuation_known?"Yes":"No"); } } } { const de_info& D=Substream_Info->second.DeInfo; b_de_data_present=Substream_Info->second.b_dialog; if (b_de_data_present) { de_max_gain=Substream_Info->second.dialog_max_gain; de_channel_config=(int8u)-1; } else { b_de_data_present=D.b_de_data_present; if (b_de_data_present) { de_max_gain=D.Config.de_max_gain; de_channel_config=D.Config.de_channel_config; } } if (b_de_data_present) { Fill(Stream_Audio, 0, (S+" DialogueEnhancement").c_str(), "Yes"); Fill(Stream_Audio, 0, (S+" DialogueEnhancement Enabled").c_str(), "Yes"); if (de_max_gain!=(int8u)-1) { Fill_Measure(Stream_Audio, 0, (S+" DialogueEnhancement MaxGain").c_str(), (de_max_gain+1)*3, __T(" dB")); if (de_channel_config!=(int8u)-1) Fill(Stream_Audio, 0, (S+" DialogueEnhancement ChannelConfiguration").c_str(), Value(Ac4_de_channel_config, de_channel_config)); } } } } } //--------------------------------------------------------------------------- void File_Ac4::Streams_Finish() { } //--------------------------------------------------------------------------- void File_Ac4::Read_Buffer_Unsynched() { } //*************************************************************************** // Buffer - Synchro //*************************************************************************** //--------------------------------------------------------------------------- bool File_Ac4::Synchronize() { //Synchronizing size_t Buffer_Offset_Current; while (Buffer_OffsetBuffer_Size) { while (Buffer_Offset+2<=Buffer_Size && (BigEndian2int16u(Buffer+Buffer_Offset)>>1)!=(0xAC40>>1)) Buffer_Offset++; if (Buffer_Offset+1==Buffer_Size && Buffer[Buffer_Offset]==0xAC) Buffer_Offset++; return false; } //Synched return true; } //--------------------------------------------------------------------------- void File_Ac4::Synched_Init() { Accept(); if (!Frame_Count_Valid) Frame_Count_Valid=Config->ParseSpeed>=0.3?128:(IsSub?1:2); //FrameInfo PTS_End=0; if (!IsSub) { FrameInfo.DTS=0; //No DTS in container FrameInfo.PTS=0; //No PTS in container } DTS_Begin=FrameInfo.DTS; DTS_End=FrameInfo.DTS; if (Frame_Count_NotParsedIncluded==(int64u)-1) Frame_Count_NotParsedIncluded=0; //No Frame_Count_NotParsedIncluded in the container } //--------------------------------------------------------------------------- bool File_Ac4::Synched_Test() { //Must have enough buffer for having header if (Buffer_Offset+4>=Buffer_Size) return false; //sync_word sync_word=BigEndian2int16u(Buffer+Buffer_Offset); if ((sync_word>>1)!=(0xAC40>>1)) //0xAC40 or 0xAC41 { Synched=false; return true; } //frame_size frame_size=BigEndian2int16u(Buffer+Buffer_Offset+2); if (frame_size==(int16u)-1) { if (Buffer_Offset+7>Buffer_Size) return false; frame_size=BigEndian2int24u(Buffer+Buffer_Offset+4)+7; } else frame_size+=4; //crc_word if (sync_word&1) { frame_size+=2; if (Buffer_Offset+frame_size>Buffer_Size) return false; if (!CRC_Compute(frame_size)) Synched=false; } //We continue return true; } //*************************************************************************** // Buffer - Global //*************************************************************************** //--------------------------------------------------------------------------- void File_Ac4::Read_Buffer_Continue() { if (MustParse_dac4) { dac4(); return; } if (!MustSynchronize) { if (!Frame_Count) Synched_Init(); raw_ac4_frame(); Buffer_Offset=Buffer_Size; } } //*************************************************************************** // Buffer - Per element //*************************************************************************** //--------------------------------------------------------------------------- void File_Ac4::Header_Parse() { //Parsing //sync_word & frame_size16 were previously calculated in Synched_Test() int16u frame_size16; Skip_B2 ( "sync_word"); Get_B2 (frame_size16, "frame_size"); if (frame_size16==0xFFFF) Skip_B3( "frame_size"); //Filling Header_Fill_Size(frame_size); Header_Fill_Code(sync_word, "ac4_syncframe"); } //--------------------------------------------------------------------------- void File_Ac4::Data_Parse() { Element_Info1(Frame_Count); //CRC if (Element_Code==0xAC41) Element_Size-=2; //Parsing raw_ac4_frame(); //CRC Element_Offset=Element_Size; if (Element_Code==0xAC41) { Element_Size+=2; Skip_B2( "crc_word"); } } //--------------------------------------------------------------------------- void File_Ac4::raw_ac4_frame() { Element_Begin1("raw_ac4_frame"); BS_Begin(); ac4_toc(); if (Element_Offset!=Element_Size) //Indicates that ac4_toc was not fully parsed raw_ac4_frame_substreams(); Element_End0(); Frame_Count++; FILLING_BEGIN(); if (!Status[IsFilled] && Frame_Count>=Frame_Count_Valid) { Fill(); Finish(); } FILLING_END(); if (!Presentations_IFrame.empty()) { Presentations=Presentations_IFrame; Presentations_IFrame.clear(); Groups=Groups_IFrame; Groups_IFrame.clear(); for (std::map::iterator AudioSubstream=AudioSubstreams_IFrame.begin(); AudioSubstream!=AudioSubstreams_IFrame.end(); ++AudioSubstream) { AudioSubstreams[AudioSubstream->first]=AudioSubstream->second; AudioSubstream->second.Buffer.Data=NULL; //This is a move, Buffer moves from AudioSubstreams_IFrame to AudioSubstreams } AudioSubstreams_IFrame.clear(); } } //--------------------------------------------------------------------------- void File_Ac4::raw_ac4_frame_substreams() { size_t byte_align=Data_BS_Remain()%8; if (byte_align) Skip_S1(byte_align, "byte_align"); BS_End(); if (payload_base) { if (payload_base>Element_Size-Element_Offset) { Skip_XX(Element_Size-Element_Offset, "?"); return; } size_t Max=Buffer_Offset+(size_t)(Element_Offset+payload_base); size_t Min=Buffer_Offset+(size_t)Element_Offset; size_t End=Min; while (End=0x20 && Buffer[End]<0x7F) End++; if (End!=Min) { size_t Encoded_Library_Size=(End-Min); string Encoded_Library; Get_String (Encoded_Library_Size, Encoded_Library, "Library name (guessed)"); if (Retrieve_Const(Stream_Audio, 0, Audio_Encoded_Library).empty()) { //Fill(Stream_General, 0, General_Encoded_Library, Encoded_Library); //Fill(Stream_Audio, 0, Audio_Encoded_Library, Encoded_Library); } payload_base-=(int32u)Encoded_Library_Size; } while (End=2) for (size_t i=0; i=1) { int8u substream_index=Presentations[i].substream_index; if (substream_index>=Substream_Size.size()) { Skip_XX(Element_Size-Element_Offset, "?"); return; } if (Substream_Size[substream_index]) { Element_Offset=Substreams_StartOffset; for (size_t i=0; i::iterator SubstreamTypeIt=Substream_Type.find(substream_index); substream_type_t SubstreamTypeInfo=SubstreamTypeIt==Substream_Type.end()?Type_Unknown:SubstreamTypeIt->second; if (SubstreamTypeInfo>=sizeof(substream_type_Trace)/sizeof(const char*)) SubstreamTypeInfo=Type_Unknown; switch (SubstreamTypeInfo) { case Type_Ac4_Substream: ac4_substream(substream_index); break; case Type_Ac4_Presentation_Substream: Element_Offset=Element_Size; // Previously parsed, skip break; default: Skip_XX(Substream_Size[substream_index], substream_type_Trace[SubstreamTypeInfo]); Param_Info1(substream_index); } if (Element_Offset::iterator Substream_Info=AudioSubstreams.begin(); Substream_Info!=AudioSubstreams.end(); Substream_Info++) if (Substream_Info->second.Buffer_Index) NoSkip=true; } if (!NoSkip) { Element_End0(); BS_End(); Element_Offset=Element_Size; return; } if (b_iframe_global) { Presentations.clear(); Groups.clear(); AudioSubstreams.clear(); } else { Presentations_IFrame=Presentations; Groups_IFrame=Groups; for (map::iterator AudioSubstream=AudioSubstreams.begin(); AudioSubstream!=AudioSubstreams.end();) { if (!AudioSubstream->second.Buffer_Index) { AudioSubstreams_IFrame[AudioSubstream->first]=AudioSubstream->second; AudioSubstream->second.Buffer.Data=NULL; //This is a move, Buffer moves from AudioSubstreams to AudioSubstreams_IFrame AudioSubstreams.erase(AudioSubstream++); } else ++AudioSubstream; } } max_group_index=0; TESTELSE_SB_SKIP( "b_single_presentation"); n_presentations=1; TESTELSE_SB_ELSE( "b_single_presentation"); TESTELSE_SB_SKIP( "b_more_presentations"); int32u n_presentations32; Get_V4 (2, n_presentations32, "n_presentations_minus2"); n_presentations32+=2; n_presentations=(int8u)n_presentations32; Param_Info1(n_presentations); TESTELSE_SB_ELSE( "b_more_presentations"); n_presentations=0; TESTELSE_SB_END(); TESTELSE_SB_END(); payload_base=0; TEST_SB_SKIP( "b_payload_base"); Get_S4 (5, payload_base, "payload_base_minus1"); payload_base++; if (payload_base==32) { Get_V4 (3, payload_base, "payload_base"); payload_base+=32; } TEST_SB_END(); if (bitstream_version<=1) { Presentations.resize(n_presentations); for(int8u Pos=0; Pos& Ps, vector& Gs, bool FromDac4) { //Compute helper values for (size_t p=0; p=11 && S.ch_mode<=14) { // b_pres_4_back_channels_present if (S.b_4_back_channels_present) P.b_pres_4_back_channels_present=true; // b_pres_centre_present if (S.b_centre_present) P.b_pres_centre_present=true; // pres_top_channel_pairs if (P.pres_top_channel_pairs=7 && ch_mode<=10) Skip_SB( "add_ch_base"); TEST_SB_GET(b_content_type, "b_content_type"); content_type(ContentInfo); TEST_SB_END(); vector b_iframes; for (int8u Pos=0; Pos=5 && G.ch_mode<=10) { //Difference with other versions G.immersive_stereo=G.ch_mode-5; G.ch_mode=1; } } } } } switch (G.ch_mode) { case 11: case 13: G.ch_mode_core=5; break; case 12: case 14: G.ch_mode_core=6; break; } Param_Info1(Value(Ac4_ch_mode_String, G.ch_mode)); if (G.ch_mode_core!=(int8u)-1) Param_Info1(Value(Ac4_ch_mode_String, G.ch_mode_core)); if (G.immersive_stereo!=(int8u)-1) Param_Info1(Value(Ac4_immersive_stereo_String, G.immersive_stereo)); if (G.ch_mode>=11 && G.ch_mode<=14) { Get_SB ( G.b_4_back_channels_present, "b_4_back_channels_present"); Get_SB ( G.b_centre_present, "b_centre_present"); Get_S1 (2, G.top_channels_present, "top_channels_present"); // Compute G.top_channel_pairs=0; switch (G.top_channels_present) { case 1: case 2: if (!G.top_channel_pairs) G.top_channel_pairs=1; break; case 3: G.top_channel_pairs=2; break; } } if (fs_index==1) { TEST_SB_SKIP( "b_sf_multiplier"); Skip_SB( "sf_multiplier"); TEST_SB_END(); } TEST_SB_SKIP( "b_bitrate_info"); Skip_V4(3, 5, 1, "bitrate_indicator"); TEST_SB_END(); if (G.ch_mode>=7 && G.ch_mode<=10) Skip_SB( "add_ch_base"); vector b_iframes; for (int8u Pos=0; Pos b_iframes; for (int8u Pos=0; Pos b_iframes; for (int8u Pos=0; Pos1) { int8u bed_ch_bits=ceil(log((float)n_signals)/log(2.0)); // ceil(log2(n_signals)); Get_S1 (bed_ch_bits, n_bed_signals, "n_bed_signals_minus1"); n_bed_signals++; } else { n_bed_signals=1; } G.nonstd_bed_channel_assignment_mask=0; for (int8u Pos=0; Pos::iterator AudioSubstream_It=AudioSubstreams.find(substream_index); if (AudioSubstream_It==AudioSubstreams.end()) AudioSubstream_It=AudioSubstreams.insert(std::pair((int8u)substream_index, audio_substream(GroupInfo.b_iframe))).first; audio_substream& AudioSubstream=AudioSubstream_It->second; //Looks for efficient high frame rate (data span over several audio frames) for (int8u p=0; p1) { TEST_SB_SKIP( "b_substream_group_gains_present"); TESTELSE_SB_SKIP( "b_keep"); TESTELSE_SB_ELSE( "b_keep"); for (int8u Pos=0; Pos=4) //TODO: remove this when parsing issue is understood { loud_corr(P.pres_ch_mode, P.pres_ch_mode_core, false/* TODO: b_objects? */); } else { Skip_BS(Data_BS_Remain(), "Problem"); Fill(Stream_Audio, 0, "NOK", "presentation_substream", -1, true, true);//TODO remove } size_t byte_align=Data_BS_Remain()%8; if (!byte_align && Data_BS_Remain()==8) byte_align = Data_BS_Remain(); //TODO: found in 1 stream but spec says 0..7 if (byte_align) Skip_S1(byte_align, "byte_align"); BS_End(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::metadata(audio_substream& AudioSubstream, size_t Substream_Index) { //Looks for corresponding group info (we take the last one found) size_t Group_Pos=(size_t)-1; size_t SubStream_Pos; for (size_t i=0; i 1; //TODO: from presentation_config if content_classifier not present AudioSubstream.b_dialog=ContentInfo.content_classifier==4; //TODO: from presentation_config if content_classifier not present Element_Begin1("metadata"); basic_metadata(AudioSubstream.LoudnessInfo, AudioSubstream.Preprocessing, GroupInfo.ch_mode, GroupInfo.sus_ver); extended_metadata(AudioSubstream, b_associated, GroupInfo.ch_mode, GroupInfo.sus_ver); // TODO: // if (b_alternative && !b_ajoc) // oamd_dyndata_single(n_objs, num_obj_info_blocks, b_iframe, b_alternative, obj_type[n_objs], b_lfe[n_objs]); int8u tools_metadata_size8; Get_S1 (7, tools_metadata_size8, "tools_metadata_size"); int32u tools_metadata_size=tools_metadata_size8; TEST_SB_SKIP( "b_more_bits"); int32u tools_metadata_size32; Get_V4 (3, tools_metadata_size32, "tools_metadata_size"); tools_metadata_size+=tools_metadata_size32<<7; TEST_SB_END(); if (false) { Skip_BS(tools_metadata_size, "tools_metadata"); } else { size_t Pos_Before = Data_BS_Remain(); if (!GroupInfo.sus_ver) drc_frame(AudioSubstream.DrcInfo, AudioSubstream.b_iframe); dialog_enhancement(AudioSubstream.DeInfo, GroupInfo.ch_mode, AudioSubstream.b_iframe); size_t Pos_After=Data_BS_Remain(); if (tools_metadata_size!=Pos_Before-Pos_After) { Fill(Stream_Audio, 0, "NOK", "tools_metadata", -1, true, true);//TODO remove Element_Info1("Problem"); if (tools_metadata_size>Pos_Before-Pos_After) Skip_BS(tools_metadata_size-(Pos_Before-Pos_After), "?"); } } TEST_SB_SKIP("b_emdf_payloads_substream"); for (;;) { Element_Begin1("umd_payload"); int32u umd_payload_id, umd_payload_size; int8u extSizeBits; bool b_smpoffst, b_discard_unknown_payload; Get_S4 (5, umd_payload_id, "umd_payload_id"); if (!umd_payload_id) { Element_End0(); break; } if (umd_payload_id==31) { Get_V4 (5, umd_payload_id, "umd_payload_id"); umd_payload_id+=31; } Element_Begin1("umd_payload_config"); TEST_SB_GET(b_smpoffst, "b_smpoffst"); Skip_V4(11, "smpoffst"); TEST_SB_END(); TEST_SB_SKIP( "b_duration"); Skip_V4(11, "duration"); TEST_SB_END(); TEST_SB_SKIP( "b_groupid"); Skip_V4(2, "groupid"); TEST_SB_END(); TEST_SB_SKIP( "b_codecdata"); Skip_V4(8, "b_codecdata"); TEST_SB_END(); Get_SB (b_discard_unknown_payload, "b_discard_unknown_payload"); if (!b_discard_unknown_payload) { bool b_payload_frame_aligned; if (!b_smpoffst) { TEST_SB_GET(b_payload_frame_aligned, "b_payload_frame_aligned"); Skip_SB( "b_create_duplicate"); Skip_SB( "b_remove_duplicate"); TEST_SB_END(); } if (b_smpoffst || b_payload_frame_aligned) { Skip_S1(5, "priority"); Skip_S1(2, "proc_allowed"); } } Element_End0(); Get_V4 (8, umd_payload_size, "umd_payload_size"); switch (umd_payload_id) { default: if (umd_payload_size) Skip_BS(umd_payload_size*8, "(Unknown)"); } Element_End0(); } TEST_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::basic_metadata(loudness_info& L, preprocessing& P, int8u ch_mode, bool sus_ver) { Element_Begin1("basic_metadata"); if (!sus_ver) Get_S1 (7, L.dialnorm_bits, "dialnorm_bits"); TEST_SB_SKIP( "b_more_basic_metadata"); if (!sus_ver) { TEST_SB_SKIP( "b_further_loudness_info"); further_loudness_info(L, sus_ver, false); TEST_SB_END(); } else { TEST_SB_SKIP( "b_substream_loudness_info"); Skip_S1(8, "substream_loudness_bits"); TEST_SB_SKIP( "b_further_substream_loudness_info"); further_loudness_info(L, sus_ver, false); TEST_SB_END(); TEST_SB_END(); } if (ch_mode==1) // stereo { TEST_SB_SKIP( "b_prev_dmx_info"); Get_S1 (3, P.pre_dmixtyp_2ch, "pre_dmixtyp_2ch"); Get_S1 (2, P.phase90_info_2ch, "phase90_info_2ch"); TEST_SB_END(); } else if (ch_mode!=(int8u)-1 && ch_mode>1) { if (!sus_ver) { TEST_SB_SKIP( "b_stereo_dmx_coeff"); Skip_S1(3, "loro_centre_mixgain"); Skip_S1(3, "loro_surround_mixgain"); TEST_SB_SKIP( "b_loro_dmx_loud_corr"); Skip_S1(5, "loro_dmx_loud_corr"); TEST_SB_END(); TEST_SB_SKIP( "b_ltrt_mixinfo"); Skip_S1(3, "ltrt_centre_mixgain"); Skip_S1(3, "ltrt_surround_mixgain"); TEST_SB_END(); TEST_SB_SKIP( "b_ltrt_dmx_loud_corr"); Skip_S1(5, "ltrt_dmx_loud_corr"); TEST_SB_END(); if (Channel_Mode_Contains_Lfe(ch_mode)) { TEST_SB_SKIP( "b_lfe_mixinfo"); Skip_S1(5, "lfe_mixgain"); TEST_SB_END(); } Skip_S1(2, "preferred_dmx_method"); TEST_SB_END(); } if (ch_mode==3 || ch_mode==4) // 5.x { TEST_SB_SKIP( "b_predmixtyp_5ch"); Get_S1 (3, P.pre_dmixtyp_5ch, "pre_dmixtyp_5ch"); TEST_SB_END(); TEST_SB_SKIP( "b_preupmixtyp_5ch"); Skip_S1(4, "pre_upmixtyp_5ch"); TEST_SB_END(); } if (ch_mode>=5 && ch_mode<=10) { TEST_SB_SKIP( "b_upmixtyp_7ch"); if (ch_mode==5 || ch_mode==6) Skip_S1(2, "pre_upmixtyp_3_4"); else if (ch_mode==9 || ch_mode==10) Skip_SB( "pre_upmixtyp_3_2_2"); TEST_SB_END(); } Get_S1 (2, P.phase90_info_mc, "phase90_info_mc"); Get_SB ( P.b_surround_attenuation_known, "b_surround_attenuation_known"); Get_SB ( P.b_lfe_attenuation_known, "b_lfe_attenuation_known"); } TEST_SB_SKIP( "b_dc_blocking"); Skip_SB( "dc_block_on"); TEST_SB_END(); TEST_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::extended_metadata(audio_substream& AudioSubstream, bool b_associated, int8u ch_mode, bool sus_ver) { Element_Begin1("extended_metadata"); if (sus_ver) { Get_SB (AudioSubstream.b_dialog, "b_dialog"); } else if (b_associated) { TEST_SB_SKIP( "b_scale_main"); Skip_S1(8, "scale_main"); TEST_SB_END(); TEST_SB_SKIP( "b_scale_main_centre"); Skip_S1(8, "scale_main_centre"); TEST_SB_END(); TEST_SB_SKIP( "b_scale_main_front"); Skip_S1(8, "scale_main_front"); TEST_SB_END(); if (ch_mode==0) Skip_S1(8, "pan_associated"); } if (AudioSubstream.b_dialog) { TEST_SB_SKIP( "b_dialog_max_gain"); Get_S1 (2, AudioSubstream.dialog_max_gain, "dialog_max_gain"); TEST_SB_END(); TEST_SB_SKIP( "b_pan_dialog_present"); if (ch_mode==0) { Skip_S1(8, "pan_dialog"); } else { Skip_S1(8, "pan_dialog[0]"); Skip_S1(8, "pan_dialog[1]"); Skip_S1(2, "pan_signal_selector"); } TEST_SB_END(); } TEST_SB_SKIP( "b_channels_classifier"); if (Channel_Mode_Contains_C(ch_mode)) { TEST_SB_SKIP( "b_c_active"); Skip_SB( "b_c_has_dialog"); TEST_SB_END(); } if (Channel_Mode_Contains_Lr(ch_mode)) { TEST_SB_SKIP( "b_l_active"); Skip_SB( "b_l_has_dialog"); TEST_SB_END(); TEST_SB_SKIP( "b_r_active"); Skip_SB( "b_r_has_dialog"); TEST_SB_END(); } if (Channel_Mode_Contains_LsRs(ch_mode)) { Skip_SB( "b_ls_active"); Skip_SB( "b_rs_active"); } if (Channel_Mode_Contains_LrsRrs(ch_mode)) { Skip_SB( "b_lrs_active"); Skip_SB( "b_rrs_active"); } if (Channel_Mode_Contains_LwRw(ch_mode)) { Skip_SB( "b_lw_active"); Skip_SB( "b_rw_active"); } if (Channel_Mode_Contains_VhlVhr(ch_mode)) { Skip_SB( "b_vhl_active"); Skip_SB( "b_vhr_active"); } if (Channel_Mode_Contains_Lfe(ch_mode)) { Skip_SB( "b_lfe_active"); } TEST_SB_END(); TEST_SB_SKIP( "b_event_probability"); Skip_S1(4, "event_probability"); TEST_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::dialog_enhancement(de_info& Info, int8u ch_mode, bool b_iframe) { Element_Begin1("dialog_enhancement"); TEST_SB_GET (Info.b_de_data_present, "b_de_data_present"); bool b_de_config_flag; if (!b_iframe) Get_SB (b_de_config_flag, "b_de_config_flag"); else b_de_config_flag=b_iframe; if (b_de_config_flag) dialog_enhancement_config(Info); dialog_enhancement_data(Info, b_iframe, 0); if (ch_mode==13 || ch_mode==14) { TEST_SB_SKIP( "b_de_simulcast"); dialog_enhancement_data(Info, b_iframe, 1); TEST_SB_END(); } TEST_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::dialog_enhancement_config(de_info& Info) { Element_Begin1("de_config"); Get_S1 (2, Info.Config.de_method, "de_method"); Get_S1 (2, Info.Config.de_max_gain, "de_max_gain"); Get_S1 (3, Info.Config.de_channel_config, "de_channel_config"); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::dialog_enhancement_data(de_info& Info, bool b_iframe, bool b_de_simulcast) { bool de_keep_pos_flag=false, de_keep_data_flag=false, de_ms_proc_flag=false; ac4_huffman abs_table=Info.Config.de_method%2==0?de_hcb_abs_0:de_hcb_abs_1; ac4_huffman diff_table=Info.Config.de_method%2==0?de_hcb_diff_0:de_hcb_diff_1; int8u de_nr_channels=0, de_nr_bands=8; switch (Info.Config.de_channel_config) { case 0x1: // 0b001 case 0x2: // 0b010 case 0x4: // 0b100 de_nr_channels=1; break; case 0x3: // 0b011 case 0x5: // 0b101 case 0x6: // 0b110 de_nr_channels=2; break; case 0x7: // 0b111 de_nr_channels=3; break; } Element_Begin1("de_data"); if (de_nr_channels>0) { if (de_nr_channels>1 && (Info.Config.de_method==1 || Info.Config.de_method==3) && !b_de_simulcast) { if (!b_iframe) Get_SB (de_keep_pos_flag, "de_keep_pos_flag"); if (!de_keep_pos_flag) { Skip_S1(5, "de_mix_coef1_idx"); if (de_nr_channels==3) Skip_S1(5, "de_mix_coef2_idx"); } } if (!b_iframe) Get_SB (de_keep_data_flag, "de_keep_data_flag"); if (!de_keep_data_flag) { if (de_nr_channels==2 && (Info.Config.de_method==0 || Info.Config.de_method==2)) Skip_SB( "de_ms_proc_flag"); for (int8u ch=0; ch=2) Skip_S1(5, "de_signal_contribution"); } } Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::custom_dmx_data(dmx& D, int8u pres_ch_mode, int8u pres_ch_mode_core, bool b_pres_4_back_channels_present, int8u pres_top_channel_pairs, bool b_pres_has_lfe) { int8u bs_ch_config=(int8u)-1, n_cdmx_configs; if (pres_ch_mode>=11 && pres_ch_mode<=14 && pres_top_channel_pairs) { if (pres_top_channel_pairs==2) { if (pres_ch_mode >=13 && b_pres_4_back_channels_present) bs_ch_config=0; else if (pres_ch_mode<=12 && b_pres_4_back_channels_present) bs_ch_config=1; else if (pres_ch_mode<=12) bs_ch_config=2; } else if (pres_top_channel_pairs==1) { if (pres_ch_mode>=13 && b_pres_4_back_channels_present) bs_ch_config=3; if (pres_ch_mode<=12 && b_pres_4_back_channels_present) bs_ch_config=4; else if (pres_ch_mode<=12) bs_ch_config = 5; } } Element_Begin1("custom_dmx_data"); if (bs_ch_config!=(int8u)-1) { TEST_SB_SKIP( "b_cdmx_data_present"); Get_S1(2, n_cdmx_configs, "n_cdmx_configs_minus1"); n_cdmx_configs++; Presentations.back().Dmx.Cdmxs.reserve(n_cdmx_configs); for (int8u Pos=0; Pos=3) || (pres_ch_mode_core!=(int8u)-1 && pres_ch_mode_core>=3)) { TEST_SB_SKIP( "b_stereo_dmx_coeff"); Get_S1 (3, D.loro_centre_mixgain, "loro_centre_mixgain"); Get_S1 (3, D.loro_surround_mixgain, "loro_surround_mixgain"); TEST_SB_SKIP( "b_ltrt_mixinfo"); Get_S1 (3, D.ltrt_centre_mixgain, "ltrt_centre_mixgain"); Get_S1 (3, D.ltrt_surround_mixgain, "ltrt_surround_mixgain"); TEST_SB_END(); if (b_pres_has_lfe) { TEST_SB_SKIP( "b_lfe_mixinfo"); Get_S1 (5, D.lfe_mixgain, "lfe_mixgain"); TEST_SB_END(); } Get_S1 (2, D.preferred_dmx_method, "preferred_dmx_method"); TEST_SB_END(); } Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::cdmx_parameters(int8u bs_ch_config, int8u out_ch_config) { Element_Begin1("cdmx_parameters"); if (bs_ch_config==0 || bs_ch_config==3) tool_scr_to_c_l(); if (bs_ch_config<2) { switch (out_ch_config) { case 0: tool_t4_to_f_s(); tool_b4_to_b2(); break; case 1: tool_t4_to_t2(); tool_b4_to_b2(); break; case 2: tool_b4_to_b2(); break; case 3: tool_t4_to_f_s_b(); break; case 4: tool_t4_to_t2(); break; } } else if (bs_ch_config==2) { switch (out_ch_config) { case 0: tool_t4_to_f_s(); break; case 1: tool_t4_to_t2(); break; } } else if (bs_ch_config==3 || bs_ch_config==4) { switch (out_ch_config) { case 0: tool_t2_to_f_s(); tool_b4_to_b2(); break; case 1: tool_b4_to_b2(); break; case 2: tool_b4_to_b2(); break; case 3: tool_t2_to_f_s_b(); break; } } else if (bs_ch_config==5 && out_ch_config==0) { tool_t2_to_f_s(); } Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::tool_scr_to_c_l() { Element_Begin1("tool_scr_to_c_l"); TESTELSE_SB_SKIP( "b_put_screen_to_c"); Get_Gain(3, gain::f1_code, "gain_f1_code"); TESTELSE_SB_ELSE( "b_put_screen_to_c"); Get_Gain(3, gain::f2_code, "gain_f2_code"); TESTELSE_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::tool_b4_to_b2() { Element_Begin1("tool_b4_to_b2"); Get_Gain(3, gain::b_code, "gain_b_code"); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::tool_t4_to_t2() { Element_Begin1("tool_t4_to_t2"); Get_Gain(3, gain::t1_code, "gain_t1_code"); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::tool_t4_to_f_s_b() { Element_Begin1("tool_t4_to_f_s_b"); TESTELSE_SB_SKIP( "b_top_front_to_front"); Get_Gain(3, gain::t2a_code, "gain_t2a_code"); Get_Gain(0, gain::t2b_code, nullptr); TESTELSE_SB_ELSE( "b_top_front_to_front"); TESTELSE_SB_SKIP( "b_top_front_to_side"); Get_Gain(3, gain::t2b_code, "gain_t2b_code"); TESTELSE_SB_ELSE( "b_top_front_to_side"); Get_Gain(0, gain::t2b_code, nullptr); Get_Gain(3, gain::t2c_code, "gain_t2c_code"); TESTELSE_SB_END(); TESTELSE_SB_END(); TESTELSE_SB_SKIP( "b_top_back_to_front"); Get_Gain(3, gain::t2d_code, "gain_t2d_code"); Get_Gain(0, gain::t2e_code, nullptr); TESTELSE_SB_ELSE( "b_top_back_to_front"); TESTELSE_SB_SKIP( "b_top_back_to_side"); Get_Gain(3, gain::t2e_code, "gain_t2e_code"); TESTELSE_SB_ELSE( "b_top_back_to_side"); Get_Gain(0, gain::t2e_code, nullptr); Get_Gain(3, gain::t2f_code, "gain_t2f_code"); TESTELSE_SB_END(); TESTELSE_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::tool_t4_to_f_s() { Element_Begin1("tool_t4_to_f_s"); TESTELSE_SB_SKIP( "b_top_front_to_front"); Get_Gain(3, gain::t2a_code, "gain_t2a_code"); Get_Gain(0, gain::t2b_code, nullptr); TESTELSE_SB_ELSE( "b_top_front_to_front"); Get_Gain(3, gain::t2b_code, "gain_t2b_code"); TESTELSE_SB_END(); TESTELSE_SB_SKIP( "b_top_back_to_front"); Get_Gain(3, gain::t2d_code, "gain_t2d_code"); Get_Gain(0, gain::t2e_code, nullptr); TESTELSE_SB_ELSE( "b_top_back_to_front"); Get_Gain(3, gain::t2e_code, "gain_t2e_code"); TESTELSE_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::tool_t2_to_f_s_b() { Element_Begin1("tool_t2_to_f_s_b"); TESTELSE_SB_SKIP( "b_top_to_front"); Get_Gain(3, gain::t2a_code, "gain_t2a_code"); Get_Gain(0, gain::t2b_code, nullptr); TESTELSE_SB_ELSE( "b_top_to_front"); TESTELSE_SB_SKIP( "b_top_to_side"); Get_Gain(3, gain::t2b_code, "gain_t2b_code"); TESTELSE_SB_ELSE( "b_top_to_side"); Get_Gain(0, gain::t2b_code, nullptr); Get_Gain(3, gain::t2c_code, "gain_t2c_code"); TESTELSE_SB_END(); TESTELSE_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::tool_t2_to_f_s() { Element_Begin1("tool_t2_to_f_s"); TESTELSE_SB_SKIP( "b_top_to_front"); Get_Gain(3, gain::t2a_code, "gain_t2a_code"); Get_Gain(0, gain::t2b_code, nullptr); TESTELSE_SB_ELSE( "b_top_to_front"); Get_Gain(3, gain::t2b_code, "gain_t2b_code"); TESTELSE_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::loud_corr(int8u pres_ch_mode, int8u pres_ch_mode_core, bool b_objects) { bool b_obj_loud_corr=false, b_corr_for_immersive_out=false; Element_Begin1("loud_corr"); if (b_objects) Get_SB (b_obj_loud_corr, "b_obj_loud_corr"); if ((pres_ch_mode!=(int8u)-1 && pres_ch_mode>4) || b_obj_loud_corr) Get_SB (b_corr_for_immersive_out, "b_corr_for_immersive_out"); if ((pres_ch_mode!=(int8u)-1 && pres_ch_mode>1) || b_obj_loud_corr) { TEST_SB_SKIP( "b_loro_loud_comp"); Skip_S1(5, "loro_dmx_loud_corr"); TEST_SB_END(); TEST_SB_SKIP( "b_ltrt_loud_comp"); Skip_S1(5, "ltrt_dmx_loud_corr"); TEST_SB_END(); } if ((pres_ch_mode!=(int8u)-1 && pres_ch_mode>4) || b_obj_loud_corr) { TEST_SB_SKIP( "b_loud_comp"); Skip_S1(5, "loud_corr_5_X"); TEST_SB_END(); if (b_corr_for_immersive_out) { TEST_SB_SKIP( "b_loud_comp"); Skip_S1(5, "loud_corr_5_X_2"); TEST_SB_END(); TEST_SB_SKIP( "b_loud_comp"); Skip_S1(5, "loud_corr_7_X"); TEST_SB_END(); } } if (((pres_ch_mode!=(int8u)-1 && pres_ch_mode>10) || b_obj_loud_corr) && b_corr_for_immersive_out) { TEST_SB_SKIP( "b_loud_comp"); Skip_S1(5, "loud_corr_7_X_4"); TEST_SB_END(); TEST_SB_SKIP( "b_loud_comp"); Skip_S1(5, "loud_corr_7_X_2"); TEST_SB_END(); TEST_SB_SKIP( "b_loud_comp"); Skip_S1(5, "loud_corr_5_X_4"); TEST_SB_END(); } if (pres_ch_mode_core!=(int8u)-1 && pres_ch_mode_core>4) { TEST_SB_SKIP( "b_loud_comp"); Skip_S1(5, "loud_corr_5_X_2"); TEST_SB_END(); } if (pres_ch_mode_core!=(int8u)-1 && pres_ch_mode_core>2) { TEST_SB_SKIP( "b_loud_comp"); Skip_S1(5, "loud_corr_5_X"); TEST_SB_END(); TEST_SB_SKIP( "b_loud_comp"); Skip_S1(5, "loud_corr_core_loro"); Skip_S1(5, "loud_corr_core_ltrt"); TEST_SB_END(); } if (b_obj_loud_corr) { TEST_SB_SKIP( "b_loud_comp"); Skip_S1(5, "loud_corr_9_X_4"); TEST_SB_END(); } Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::drc_frame(drc_info& DrcInfo, bool b_iframe) { Element_Begin1("drc_frame"); TEST_SB_SKIP( "b_drc_present"); if (b_iframe) drc_config(DrcInfo); drc_data(DrcInfo); TEST_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::drc_config(drc_info& DrcInfo) { int8u drc_decoder_nr_modes; Element_Begin1("drc_config"); Get_S1 (3, drc_decoder_nr_modes, "drc_decoder_nr_modes"); DrcInfo.Decoders.clear(); for (int8u Pos=0; Pos<=drc_decoder_nr_modes; Pos++) { DrcInfo.Decoders.resize(DrcInfo.Decoders.size()+1); drc_decoder_mode_config(DrcInfo.Decoders.back()); } //Manage drc_repeat_id for (int8u i=0; i<=drc_decoder_nr_modes; i++) { if (DrcInfo.Decoders[i].drc_repeat_id!=(int8u)-1) { for (int8u j=0; j<=drc_decoder_nr_modes; j++) if (j!=i && DrcInfo.Decoders[j].drc_decoder_mode_id==DrcInfo.Decoders[i].drc_repeat_id) { int8u drc_decoder_mode_id=DrcInfo.Decoders[i].drc_decoder_mode_id; DrcInfo.Decoders[i]=DrcInfo.Decoders[j]; DrcInfo.Decoders[i].drc_decoder_mode_id=drc_decoder_mode_id; DrcInfo.Decoders[i].drc_compression_curve_flag=true; break; } } } Get_S1 (3, DrcInfo.drc_eac3_profile, "drc_eac3_profile"); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::drc_data(drc_info& DrcInfo) { bool curve_present=false; int16u drc_gainset_size; int8u drc_version; size_t Remain_Before, used_bits=0; Element_Begin1("drc_data"); for (int8u Pos=0; Pos=1) { Skip_BS(drc_gainset_size-2-used_bits, "drc2_bits"); } } else { curve_present=true; } } if (curve_present) { Skip_SB( "drc_reset_flag"); Skip_S1(2, "drc_reserved"); } Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::drc_gains(drc_decoder_config& D) { Element_Begin1("drc_gains"); Skip_S1(7, "drc_gain_val"); if (D.drc_gains_config>0) { // TODO: } Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::drc_decoder_mode_config(drc_decoder_config& D) { D.drc_compression_curve_flag=false; Element_Begin1("drc_decoder_mode_config"); Get_S1 (3, D.drc_decoder_mode_id, "drc_decoder_mode_id[pcount]"); if (D.drc_decoder_mode_id>3) { Skip_S1(5, "drc_output_level_from"); Skip_S1(5, "drc_output_level_to"); } TESTELSE_SB_SKIP( "drc_repeat_profile_flag"); Get_S1 (3, D.drc_repeat_id, "drc_repeat_id"); D.drc_compression_curve_flag=true; TESTELSE_SB_ELSE( "drc_repeat_profile_flag"); TESTELSE_SB_GET (D.drc_default_profile_flag, "drc_default_profile_flag"); D.drc_compression_curve_flag=true; TESTELSE_SB_ELSE( "drc_default_profile_flag"); TESTELSE_SB_GET(D.drc_compression_curve_flag, "drc_compression_curve_flag[drc_decoder_mode_id[pcount]]"); drc_compression_curve(D.drc_compression_curve); TESTELSE_SB_ELSE( "drc_compression_curve_flag[drc_decoder_mode_id[pcount]]"); Get_S1 (2, D.drc_gains_config, "drc_gains_config[drc_decoder_mode_id[pcount]]"); TESTELSE_SB_END(); TESTELSE_SB_END(); TESTELSE_SB_END(); Element_End0(); }; void File_Ac4::drc_compression_curve(drc_decoder_config_curve& C) { memset(&C, -1, sizeof(C)); Element_Begin1("drc_compression_curve"); Get_S1 (4, C.drc_lev_nullband_low, "drc_lev_nullband_low"); Get_S1 (4, C.drc_lev_nullband_high, "drc_lev_nullband_high"); Get_S1 (4, C.drc_gain_max_boost, "drc_gain_max_boost"); if (C.drc_gain_max_boost) { Skip_S1(5, "drc_lev_max_boost"); TEST_SB_SKIP( "drc_nr_boost_sections"); Skip_S1(4, "drc_gain_section_boost"); Skip_S1(5, "drc_lev_section_boost"); TEST_SB_END(); } Get_S1 (5, C.drc_gain_max_cut, "drc_gain_max_cut"); if (C.drc_gain_max_cut) { Get_S1 (6, C.drc_lev_max_cut, "drc_lev_max_cut"); TEST_SB_SKIP( "drc_nr_cut_sections"); Get_S1 (5, C.drc_gain_section_cut, "drc_gain_section_cut"); Get_S1 (5, C.drc_lev_section_cut, "drc_lev_section_cut"); TEST_SB_END(); } TESTELSE_SB_SKIP( "drc_tc_default_flag"); TESTELSE_SB_ELSE( "drc_tc_default_flag"); Get_S1 (8, C.drc_tc_attack, "drc_tc_attack"); Get_S1 (8, C.drc_tc_release, "drc_tc_release"); Get_S1 (8, C.drc_tc_attack_fast, "drc_tc_attack_fast"); Get_S1 (8, C.drc_tc_release_fast, "drc_tc_release_fast"); TEST_SB_SKIP( "drc_adaptive_smoothing_flag"); Get_S1 (5, C.drc_attack_threshold, "drc_attack_threshold"); Get_S1 (5, C.drc_release_threshold, "drc_release_threshold"); TEST_SB_END(); TESTELSE_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::further_loudness_info(loudness_info& L, bool sus_ver, bool b_presentation_ldn) { bool b_loudcorr_type; Element_Begin1("further_loudness_info"); if (b_presentation_ldn || !sus_ver) { int8u loudness_version; Get_S1 (2, loudness_version, "loudness_version"); if (loudness_version==3) Skip_S1(4, "extended_loudness_version"); Get_S1 (4, L.loud_prac_type, "loud_prac_type"); if (L.loud_prac_type) { TEST_SB_SKIP( "b_loudcorr_dialgate"); Get_S1 (3, L.loud_dialgate_prac_type, "dialgate_prac_type"); TEST_SB_END(); Get_SB (L.b_loudcorr_type, "b_loudcorr_type"); } } else { Skip_SB( "b_loudcorr_dialgate"); } TEST_SB_SKIP( "b_loudrelgat"); Get_S2 (11, L.loudrelgat, "loudrelgat"); TEST_SB_END(); TEST_SB_SKIP( "b_loudspchgat"); Get_S2 (11, L.loudspchgat, "loudspchgat"); Get_S1 (3, L.loudspchgat_dialgate_prac_type, "dialgate_prac_type"); TEST_SB_END(); TEST_SB_SKIP( "b_loudstrm3s"); Skip_S2(11, "loudstrm3s"); TEST_SB_END(); TEST_SB_SKIP( "b_max_loudstrm3s"); Skip_S2(11, "max_loudstrm3s"); TEST_SB_END(); TEST_SB_SKIP( "b_truepk"); Skip_S2(11, "truepk"); TEST_SB_END(); TEST_SB_SKIP( "b_max_truepk"); Get_S2 (11, L.max_truepk, "max_truepk"); TEST_SB_END(); if (b_presentation_ldn || !sus_ver) { TEST_SB_SKIP( "b_prgmbndy"); Element_Begin1("prgmbndy_bits"); int32u prgmbndy=1; bool prgmbndy_bit=false; while(!prgmbndy_bit) Get_SB (prgmbndy_bit, "prgmbndy_bit"); Element_Info1(prgmbndy); Element_End0(); Skip_SB( "b_end_or_start"); TEST_SB_SKIP( "b_prgmbndy_offset"); Skip_S2(11, "prgmbndy_offset"); TEST_SB_END(); TEST_SB_END(); } TEST_SB_SKIP( "b_lra"); Get_S2 (10, L.lra, "lra"); Get_S1 ( 3, L.lra_prac_type, "lra_prac_type"); TEST_SB_END(); TEST_SB_SKIP( "b_loudmntry"); Skip_S2(11, "loudmntry"); TEST_SB_END(); TEST_SB_SKIP( "b_max_loudmntry"); Get_S2 (11, L.max_loudmntry, "max_loudmntry"); TEST_SB_END(); if (sus_ver) { TEST_SB_SKIP( "b_rtllcomp"); Skip_S1(8, "rtllcomp"); TEST_SB_END(); } TEST_SB_SKIP( "b_extension"); int8u e_bits_size; Get_S1 (5, e_bits_size, "e_bits_size"); if (e_bits_size==31) { int32u e_bits_size32; Get_V4 (4, e_bits_size32, "e_bits_size"); e_bits_size32+=31; e_bits_size=(int8u)e_bits_size32; } if (!sus_ver) { e_bits_size--; TEST_SB_SKIP( "b_rtllcomp"); e_bits_size-=8; Skip_S1(8, "rtll_comp"); TEST_SB_END(); } Skip_BS(e_bits_size, "extensions_bits"); TEST_SB_END(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::dac4() { Element_Begin1("ac4_dsi"); BS_Begin(); int16u n_presentations; int8u ac4_dsi_version; Get_S1 (3, ac4_dsi_version, "ac4_dsi_version"); if (ac4_dsi_version>1) { Skip_BS(Data_BS_Remain(), "Unknown"); BS_End(); return; } Get_S1 (7, bitstream_version, "bitstream_version"); if (bitstream_version>2) { Skip_BS(Data_BS_Remain(), "Unknown"); BS_End(); Element_End0(); return; } Get_SB ( fs_index, "fs_index"); Get_S1 (4, frame_rate_index, "frame_rate_index"); Param_Info1(Ac4_frame_rate[fs_index][frame_rate_index]); Get_S2 (9, n_presentations, "n_presentations"); if (bitstream_version > 1) { TEST_SB_SKIP( "b_program_id"); Skip_S2(16, "short_program_id"); TEST_SB_SKIP( "b_program_uuid_present"); Skip_BS(128, "program_uuid"); TEST_SB_END(); TEST_SB_END(); } ac4_bitrate_dsi(); size_t byte_align=Data_BS_Remain()%8; if (byte_align) Skip_S1(byte_align, "byte_align"); BS_End(); Presentations_dac4.resize(n_presentations); for (int8u p=0; p=11 && P.pres_ch_mode<=14) { Get_SB (P.b_pres_4_back_channels_present, "pres_b_4_back_channels_present"); Get_S1 (2, P.pres_top_channel_pairs, "pres_top_channel_pairs"); } int32u presentation_channel_mask_v1; Get_S3 (24, presentation_channel_mask_v1, "presentation_channel_mask_v1"); presentation_channel_mask_v1 &=((int32u)-1)>>(32-Ac4_channel_mask_Size); int32u nonstd_bed_channel_assignment_mask=0; for (size_t i=0; i5) { int8u n_skip_bytes; Get_S1 (7, n_skip_bytes, "n_skip_bytes"); if (n_skip_bytes) Skip_XX(n_skip_bytes*8, "skip_data"); } } Skip_SB( "b_pre_virtualized"); Get_SB (b_add_emdf_substreams, "b_add_emdf_substreams"); } if (b_add_emdf_substreams) { int8u n_add_emdf_substreams; Get_S1 (7, n_add_emdf_substreams, "n_add_emdf_substreams"); for (int8u Pos=0; Pos=8) { Skip_SB( "de_indicator"); Skip_S1(5, "reserved"); TESTELSE_SB_SKIP( "b_extended_presentation_id"); Skip_S2(9, "extended_presentation_id"); TESTELSE_SB_ELSE( "b_extended_presentation_id"); Skip_SB( "reserved"); TESTELSE_SB_END(); } BS_End(); Element_End0(); } //--------------------------------------------------------------------------- void File_Ac4::ac4_substream_group_dsi(presentation& P) { P.substream_group_info_specifiers.push_back(Groups_dac4.size()); Groups_dac4.resize(Groups_dac4.size()+1); group& G=Groups_dac4.back(); bool b_substreams_present; int8u n_substreams; Element_Begin1("ac4_substream_group_dsi"); Get_SB (b_substreams_present, "b_substreams_present"); Get_SB (G.b_hsf_ext, "b_hsf_ext"); Get_SB (G.b_channel_coded, "b_channel_coded"); Get_S1 (8, n_substreams, "n_substreams"); G.Substreams.resize(n_substreams); for (int8u Pos=0; Pos>(32-Ac4_channel_mask_Size); int32u nonstd_bed_channel_assignment_mask=0; for (size_t i=0; iGet4(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+=Bits; if (!BS->GetB()) break; Info<<=Bits; Info+=(1<Skip(Bits); if (!BS->GetB()) break; } } } //--------------------------------------------------------------------------- void File_Ac4::Get_V4(int8u Bits1, int8u Bits2, int8u Flag_Value, int32u &Info, const char* Name) { Info = 0; int8u Count=Bits1; Peek_S4(Count, Info); if (Info==Flag_Value) { Count=Bits2; Peek_S4(Count, Info); } BS->Skip(Count); #if MEDIAINFO_TRACE if (Trace_Activated) { Param(Name, Info, Count); Param_Info(__T("(")+Ztring::ToZtring(Count)+__T(" bits)")); } #endif } //--------------------------------------------------------------------------- void File_Ac4::Skip_V4(int8u Bits1, int8u Bits2, int8u Flag_Value, const char* Name) { int32u Info = 0; int8u Count=Bits1; Peek_S4(Count, Info); if (Info==Flag_Value) { Count=Bits2; Peek_S4(Count, Info); } BS->Skip(Count); #if MEDIAINFO_TRACE if (Trace_Activated) { Param(Name, Info, Count); Param_Info(__T("(")+Ztring::ToZtring(Count)+__T(" bits)")); } #endif } //--------------------------------------------------------------------------- void File_Ac4::Get_V4(int8u Bits1, int8u Bits2, int8u Bits3, int8u Bits4, int32u &Info, const char* Name) { Info = 0; int8u Temp; int8u Count=Bits1; Peek_S1(Bits1, Temp); if (Temp==~(~0u<Skip(Count); #if MEDIAINFO_TRACE if (Trace_Activated) { Param(Name, Info, Count); Param_Info(__T("(")+Ztring::ToZtring(Count)+__T(" bits)")); } #endif //MEDIAINFO_TRACE } //--------------------------------------------------------------------------- void File_Ac4::Get_V4(const variable_size* Bits, int8u &Info, const char* Name) { int8u TotalSize=Bits[0].AddedSize; Bits++; int8u BitSize=0; int16u Temp; for (int8u i=0; iGetB()) { Info++; Count++; } Param(Name, Info, Count); Param_Info(__T("(")+Ztring::ToZtring(Count)+__T(" bits)")); } else #endif //MEDIAINFO_TRACE { while (BS->GetB()) Info++; } } //--------------------------------------------------------------------------- void File_Ac4::Skip_VB(const char* Name) { #if MEDIAINFO_TRACE if (Trace_Activated) { int8u Info=0; int8u Count=0; do { Info++; Count++; } while (BS->GetB()); Param(Name, Info, Count); Param_Info(__T("(")+Ztring::ToZtring(Count)+__T(" bits)")); } else #endif //MEDIAINFO_TRACE { while (BS->GetB()); } } //*************************************************************************** // Utils //*************************************************************************** //--------------------------------------------------------------------------- bool File_Ac4::CRC_Compute(size_t Size) { int16u CRC_16=0x0000; const int8u* CRC_16_Buffer=Buffer+Buffer_Offset+2; //After sync_word const int8u* CRC_16_Buffer_End=Buffer+Buffer_Offset+Size; //End of frame while(CRC_16_Buffer>8)^(*CRC_16_Buffer)]; CRC_16_Buffer++; } return (CRC_16==0x0000); } //--------------------------------------------------------------------------- int8u File_Ac4::Superset(int8u Ch_Mode1, int8u Ch_Mode2) { if (Ch_Mode1>15 && Ch_Mode2>15) return (int8u)-1; else if (Ch_Mode1>15) return Ch_Mode2; else if (Ch_Mode2>15) return Ch_Mode1; else if (Ch_Mode1==15 || Ch_Mode2==15) return 15; static int8u Modes[16][3]= { {1,0,0}, {2,0,0}, {3,0,0}, {5,0,0}, {5,1,0}, {7,0,0}, {7,1,0}, {7,0,1}, {7,1,1}, {7,0,2}, {7,1,2}, {7,0,4}, {7,1,4}, {9,0,4}, {9,1,4}, {22,2,0} }; for (int8u Pos=0; Pos<15; Pos++) { if (Modes[Ch_Mode1][0]<=Modes[Pos][0] && Modes[Ch_Mode1][1]<=Modes[Pos][1] && Modes[Ch_Mode1][2]<=Modes[Pos][2] && Modes[Ch_Mode2][0]<=Modes[Pos][0] && Modes[Ch_Mode2][1]<=Modes[Pos][1] && Modes[Ch_Mode2][2]<=Modes[Pos][2]) return Pos; } return (int8u)-1; } //--------------------------------------------------------------------------- int16u File_Ac4::Huffman_Decode(const ac4_huffman& Table, const char* Name) { bool bit; int16s index = 0; Element_Begin1(Name); while (index>=0) { Get_SB (bit, "bit"); index=Table[index][bit]; } Element_End0(); return index+64; } void File_Ac4::Get_Gain(int8u Bits, gain Type, const char* Name) { dmx::cdmx::gain Gain; Gain.Type=Type; if (Bits) { Get_S1(Bits, Gain.Value, Name); Param_Info3(Gain.Type==gain::f1_code?gain_f1_Values(Gain.Value):gain_xx_Values(Gain.Value), " dB", 1); } else Gain.Value=7; Presentations.back().Dmx.Cdmxs.back().Gains.push_back(Gain); } } //NameSpace #endif //MEDIAINFO_AC4_YES