/* 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"
//---------------------------------------------------------------------------
//***************************************************************************
// Infos (Common)
//***************************************************************************
//---------------------------------------------------------------------------
#if defined(MEDIAINFO_AC3_YES) || defined(MEDIAINFO_DVDV_YES) || defined(MEDIAINFO_MPEGPS_YES) || defined(MEDIAINFO_MPEGTS_YES) || defined(MEDIAINFO_MIXML_YES)
//---------------------------------------------------------------------------
#include "ZenLib/Conf.h"
using namespace ZenLib;
namespace MediaInfoLib
{
//---------------------------------------------------------------------------
extern const float64 Mpegv_frame_rate[16];
//---------------------------------------------------------------------------
extern const int32u AC3_SamplingRate[]=
{ 48000, 44100, 32000, 0,};
//---------------------------------------------------------------------------
const char* AC3_Mode[] =
{
"CM",
"ME",
"VI",
"HI",
"D",
"C",
"E",
"VO",
};
//---------------------------------------------------------------------------
const char* AC3_Mode_String[] =
{
"Complete Main",
"Music and Effects",
"Visually Impaired",
"Hearing Impaired",
"Dialogue",
"Commentary",
"Emergency",
"Voice Over",
};
//---------------------------------------------------------------------------
const char* AC3_Surround[]=
{
"",
"Not Dolby Surround encoded",
"Dolby Surround encoded",
"",
};
//---------------------------------------------------------------------------
extern const int16u AC3_BitRate[]=
{
32,
40,
48,
56,
64,
80,
96,
112,
128,
160,
192,
224,
256,
320,
384,
448,
512,
576,
640,
};
//---------------------------------------------------------------------------
extern const int8u AC3_Channels[]=
{2, 1, 2, 3, 3, 4, 4, 5};
//---------------------------------------------------------------------------
} //NameSpace
//---------------------------------------------------------------------------
#endif //...
//---------------------------------------------------------------------------
//***************************************************************************
//
//***************************************************************************
//---------------------------------------------------------------------------
#if defined(MEDIAINFO_AC3_YES)
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "MediaInfo/Audio/File_Ac3.h"
#include <vector>
#include <cmath>
#if MEDIAINFO_EVENTS
#include "MediaInfo/MediaInfo_Config_MediaInfo.h"
#include "MediaInfo/MediaInfo_Events_Internal.h"
#endif //MEDIAINFO_EVENTS
#include "MediaInfo/MediaInfo_Internal.h"
using namespace ZenLib;
using namespace std;
//---------------------------------------------------------------------------
namespace MediaInfoLib
{
//***************************************************************************
// Infos
//***************************************************************************
//---------------------------------------------------------------------------
const int32u AC3_SamplingRate2[]=
{ 24000, 22050, 16000, 0,};
//---------------------------------------------------------------------------
const char* AC3_ChannelPositions[]=
{
"Dual mono",
"Front: C",
"Front: L R",
"Front: L C R",
"Front: L R, Back: C",
"Front: L C R, Back: C",
"Front: L R, Side: L R",
"Front: L C R, Side: L R",
};
//---------------------------------------------------------------------------
const char* AC3_ChannelPositions2[]=
{
"1+1",
"1/0/0",
"2/0/0",
"3/0/0",
"2/1/0",
"3/1/0",
"2/2/0",
"3/2/0",
};
//---------------------------------------------------------------------------
const char* AC3_ChannelLayout_lfeoff[]=
{
"M M",
"C",
"L R",
"L R C",
"L R S",
"L R C Cs",
"L R Ls Rs",
"L R C Ls Rs",
};
//---------------------------------------------------------------------------
const char* AC3_ChannelLayout_lfeon[]=
{
"1+1 LFE",
"C LFE",
"L R LFE",
"L R C LFE",
"L R S LFE",
"L R C LFE Cs",
"L R LFE Ls Rs",
"L R C LFE Ls Rs",
};
//---------------------------------------------------------------------------
int16u AC3_acmod2chanmap[]=
{
0xA000,
0x4000,
0xA000,
0xE000,
0xA100,
0xE100,
0xB800,
0xF800,
};
//---------------------------------------------------------------------------
Ztring AC3_chanmap_ChannelPositions (int16u chanmap)
{
Ztring Front;
Ztring Side;
Ztring Back;
Ztring More;
for (int8u Pos=0; Pos<16; Pos++)
{
if (chanmap&(1<<(15-Pos)))
{
switch (Pos)
{
case 0 : Front+=__T(" L"); break;
case 1 : Front+=__T(" C"); break;
case 2 : Front+=__T(" R"); break;
case 3 : Side+=__T(" L"); break;
case 4 : Side+=__T(" R"); break;
case 5 : {
bool HasR=false;
if (Front.find(__T(" R"))!=string::npos)
{
Front.resize(Front.size()-2);
HasR=true;
}
Front+=__T(" C C");
if (HasR)
Front+=__T(" R");
}
break;
case 6 : Back+=__T(" L R"); break;
case 7 : if (Back.empty())
Back=__T(" C");
else
Back=__T(" L C R");
break;
case 15 : More+=__T(", LFE");
break;
default: ;
}
}
}
Ztring ToReturn;
if (!Front.empty())
{
ToReturn+=__T("Front:")+Front;
}
if (!Side.empty())
{
if (!ToReturn.empty())
ToReturn+=__T(", ");
ToReturn+=__T("Side:")+Side;
}
if (!Back.empty())
{
if (!ToReturn.empty())
ToReturn+=__T(", ");
ToReturn+=__T("Back:")+Back;
}
ToReturn+=More;
return ToReturn;
}
//---------------------------------------------------------------------------
int8u AC3_chanmap_Channels (int16u chanmap)
{
int8u Channels=0;
for (int8u Pos=0; Pos<16; Pos++)
{
if (chanmap&(1<<(15-Pos)))
{
switch (Pos)
{
case 5 :
case 6 :
case 9 :
case 10 :
case 11 :
case 13 :
Channels+=2; break;
default:
Channels++; break;
}
}
}
return Channels;
}
//---------------------------------------------------------------------------
static const char* AC3_chanmap_ChannelLayout_List[16] =
{
"L",
"C",
"R",
"Ls",
"Rs",
"Lc Rc",
"Lrs Rrs",
"Cs",
"Ts",
"Lsd Rsd",
"Lw Rw",
"Lvh Rvh",
"Vhc", // Cvh is a typo in specs
"Lts Rts",
"LFE2",
"LFE",
};
Ztring AC3_chanmap_ChannelLayout (int16u chanmap, const Ztring &ChannelLayout0)
{
Ztring ToReturn=ChannelLayout0;
for (int8u Pos=5; Pos<15; Pos++) // Custom ones only
{
if (chanmap&(1<<(15-Pos)))
{
if (!ChannelLayout0.empty())
ToReturn+=__T(' ');
ToReturn+=Ztring().From_UTF8(AC3_chanmap_ChannelLayout_List[Pos]);
}
}
return ToReturn;
}
//---------------------------------------------------------------------------
static const char* AC3_nonstd_bed_channel_assignment_mask_ChannelLayout_List[17] =
{
"L",
"R",
"C",
"LFE",
"Ls",
"Rs",
"Lrs",
"Rrs",
"Lvh", // Lfh in spec but same as Lvh from E-AC-3
"Rvh", // Rfh in spec but same as Rvh from E-AC-3
"Lts", // Ltm in spec but same as Lts from E-AC-3
"Rts", // Rtm in spec but same as Rts from E-AC-3
"Lrh",
"Rrh",
"Lw",
"Rw",
"LFE2",
};
static int8s AC3_nonstd_bed_channel_assignment_mask_ChannelLayout_Reordering[17] =
{
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,
};
Ztring AC3_nonstd_bed_channel_assignment_mask_ChannelLayout(int32u nonstd_bed_channel_assignment_mask)
{
Ztring ToReturn;
for (int8u i=0; i<17; i++)
{
int8u i2=i+AC3_nonstd_bed_channel_assignment_mask_ChannelLayout_Reordering[i];
if (nonstd_bed_channel_assignment_mask&(1<<i2))
{
ToReturn+=Ztring().From_UTF8(AC3_nonstd_bed_channel_assignment_mask_ChannelLayout_List[i2]);
ToReturn+=__T(' ');
}
}
if (!ToReturn.empty())
ToReturn.resize(ToReturn.size()-1);
return ToReturn;
}
//---------------------------------------------------------------------------
static const int8u AC3_bed_channel_assignment_mask_ChannelLayout_Mapping[10] =
{
2,
1,
1,
2,
2,
2,
2,
2,
2,
1,
};
extern int32u AC3_bed_channel_assignment_mask_2_nonstd(int16u bed_channel_assignment_mask)
{
int32u ToReturn=0;
int8u j=0;
for (int8u i=0; i<10; i++)
{
if (bed_channel_assignment_mask&(1<<i))
{
ToReturn|=(1<<(j++));
if (AC3_bed_channel_assignment_mask_ChannelLayout_Mapping[i]>1)
ToReturn|=(1<<(j++));
}
else
j+=AC3_bed_channel_assignment_mask_ChannelLayout_Mapping[i];
}
return ToReturn;
}
//---------------------------------------------------------------------------
const int16u AC3_FrameSize[27][4]=
{
{ 128, 138, 192, 0},
{ 160, 174, 240, 0},
{ 192, 208, 288, 0},
{ 224, 242, 336, 0},
{ 256, 278, 384, 0},
{ 320, 348, 480, 0},
{ 384, 416, 576, 0},
{ 448, 486, 672, 0},
{ 512, 556, 768, 0},
{ 640, 696, 960, 0},
{ 768, 834, 1152, 0},
{ 896, 974, 1344, 0},
{1024, 1114, 1536, 0},
{1280, 1392, 1920, 0},
{1536, 1670, 2304, 0},
{1792, 1950, 2688, 0},
{2048, 2228, 3072, 0},
{2304, 2506, 3456, 0},
{2560, 2786, 3840, 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},
{ 768, 0, 0, 0},
};
//---------------------------------------------------------------------------
int16u AC3_FrameSize_Get(int8u frmsizecod, int8u fscod)
{
bool Padding=(frmsizecod%2)?true:false;
int16u frame_size_id=frmsizecod/2;
if (frame_size_id>26 || fscod>3)
return 0;
int16u FrameSize=AC3_FrameSize[frame_size_id][fscod];
if (fscod==1 && Padding)
FrameSize+=2; // frame lengths are padded by 1 word (16 bits) at 44100 Hz
return FrameSize;
}
//---------------------------------------------------------------------------
// CRC_16_Table
// A CRC is computed like this:
// Init: int32u CRC_16 = 0x0000;
// for each data byte do
// CRC_16=(CRC_16<<8) ^ CRC_16_Table[(CRC_16>>8)^(data_byte)];
extern const int16u CRC_16_Table[256] =
{
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
};
int CRC16_Init(int16u *Table, int16u Polynomial)
{
for (size_t Pos=0; Pos<256; Pos++)
{
Table[Pos]=(int16u)Pos<<8;
for(int8u bit=0; bit<8; bit++)
{
if (Table[Pos]&0x8000)
Table[Pos]=(Table[Pos]<<1)^Polynomial;
else
Table[Pos]=Table[Pos]<<1;
}
}
return 0;
}
//---------------------------------------------------------------------------
const float64 AC3_dynrng[]=
{
6.02,
12.04,
18.06,
24.08,
-18.06,
-12.04,
- 6.02,
0.00,
};
//---------------------------------------------------------------------------
const float64 AC3_compr[]=
{
6.02,
12.04,
18.06,
24.08,
30.10,
36.12,
42.14,
48.16,
-42.14,
-36.12,
-30.10,
-24.08,
-18.06,
-12.04,
- 6.02,
0.00,
};
//---------------------------------------------------------------------------
const char* AC3_HD_StreamType(int8u StreamType)
{
switch (StreamType)
{
case 0xBA : return "TrueHD";
case 0xBB : return "MLP";
default : return "";
}
}
//---------------------------------------------------------------------------
int32u AC3_HD_SamplingRate(int8u SamplingRate)
{
if (SamplingRate==0xF)
return 0;
return ((SamplingRate&8)?44100:48000)<<(SamplingRate&7) ;
}
//---------------------------------------------------------------------------
static const int8u AC3_TrueHD_ChannelCountPerBit[13]=
{
2, //LR
1, //C
1, //LFE
2, //LRs
2, //LRvh
2, //LRc
2, //LRrs
1, //Cs
1, //Ts
2, //LRsd
2, //LRw
1, //Cvh
1, //LFE2
};
//---------------------------------------------------------------------------
int8u AC3_TrueHD_Channels(int16u ChannelsMap)
{
int8u Channels=0;
for (int8u Pos=0; Pos<13; Pos++)
Channels+=AC3_TrueHD_ChannelCountPerBit[Pos]*((ChannelsMap>>Pos)&0x1);
return Channels;
}
//---------------------------------------------------------------------------
std::string AC3_TrueHD_Channels_Positions(int16u ChannelsMap, bool Bit11=false)
{
std::string Text;
if ((ChannelsMap&0x0003)==0x0003)
Text+="Front: L C R";
else
{
if (ChannelsMap&0x0001)
Text+="Front: C";
if (ChannelsMap&0x0002)
Text+="Front: L, R";
}
if (ChannelsMap&0x08)
Text+=", Side: L R";
if (ChannelsMap&0x80)
Text+=", Back: C";
if ((ChannelsMap&0x0810)==0x0810 && Bit11)
Text+=", vh: L C R";
else
{
if (ChannelsMap&0x0010 && !Bit11)
Text+=", vh: L R";
if (ChannelsMap&0x0800)
Text+=", vh: C";
}
if (ChannelsMap&0x0020)
Text+=", c: L R";
if (ChannelsMap&0x0040)
Text+=", Back: L R";
if (ChannelsMap&0x0100)
Text+=", s: T";
if (ChannelsMap&0x0200)
Text+=", sd: L R";
if (ChannelsMap&0x0400)
Text+=", w: L R";
if (ChannelsMap&0x0004)
Text+=", LFE";
if (ChannelsMap&0x1000)
Text+=", LFE2";
return Text;
}
//---------------------------------------------------------------------------
Ztring AC3_TrueHD_Channels_Positions2(int16u ChannelsMap, bool Bit11=false)
{
int8u Front=0, Surround=0, Rear=0, LFE=0;
if (ChannelsMap&0x0001)
Front++;
if (ChannelsMap&0x0002)
Front+=2;
if (ChannelsMap&0x08)
Surround+=2;
if (ChannelsMap&0x80)
Surround++;
if (ChannelsMap & 0x0010)
Rear+=2; //vh
if (!Bit11)
{
if (ChannelsMap&0x0800)
Rear++; //vh
if (ChannelsMap&0x0020)
Rear+=2; //c
if (ChannelsMap&0x0040)
Rear+=2; //rs
if (ChannelsMap&0x0100)
Rear+=2; //s
if (ChannelsMap&0x0200)
Rear+=2; //sd
if (ChannelsMap&0x0400)
Rear+=2; //w
if (ChannelsMap&0x0004)
LFE++;
if (ChannelsMap&0x1000)
LFE++;
}
Ztring Text;
Text+=Ztring::ToZtring(Front);
Text+=__T('/')+Ztring::ToZtring(Surround);
Text+=__T('/')+Ztring::ToZtring(Rear);
Text+=__T('.')+Ztring::ToZtring(LFE);
return Text;
}
//---------------------------------------------------------------------------
static const size_t AC3_TrueHD_ChannelLayoutNames_Size=13;
const char* AC3_TrueHD_ChannelLayoutNames[AC3_TrueHD_ChannelLayoutNames_Size]=
{
"L R",
"C",
"LFE",
"Ls Rs",
"Tfl Tfr",
"Lsc Rsc",
"Lb Rb",
"Cb",
"Tc",
"Lsd Rsd",
"Lw Rw",
"Tfc",
"LFE2",
};
static const size_t AC3_TrueHD_ChannelLayoutNames2_Size=1;
const char* AC3_TrueHD_ChannelLayoutNames2[AC3_TrueHD_ChannelLayoutNames2_Size]=
{
"Tsl Tsr",
};
std::string AC3_TrueHD_Channels_ChannelLayout(int16u ChannelsMap, bool Bit11=false)
{
std::string Text;
for (size_t i=0; i<16; i++)
if (ChannelsMap&(1<<i))
{
if (!Text.empty())
Text+=' ';
if ((!Bit11 && i>=AC3_TrueHD_ChannelLayoutNames_Size) || (Bit11 && i>=4 && i-4>=AC3_TrueHD_ChannelLayoutNames2_Size))
{
Text+='+'; //Unknown layout
return Text;
}
Text+=(Bit11 && i>=4)?AC3_TrueHD_ChannelLayoutNames2[i-4]:AC3_TrueHD_ChannelLayoutNames[i];
}
return Text;
}
//---------------------------------------------------------------------------
static const int32u AC3_MLP_Channels[32]=
{
1,
2,
3,
4,
3,
4,
5,
3,
4,
5,
4,
5,
6,
4,
5,
4,
5,
6,
5,
5,
6,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
//---------------------------------------------------------------------------
static const int32u AC3_MLP_Resolution[16]=
{
16,
20,
24,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
//---------------------------------------------------------------------------
extern const char* Ac3_emdf_payload_id[16]=
{
"Container End",
"Programme loudness data",
"Programme information",
"E-AC-3 substream structure",
"Dynamic range compression data for portable devices",
"Programme Language",
"External Data",
"Headphone rendering data",
"",
"",
"",
"OAMD",
"",
"Personalized Audio Mix-Graph",
"JOC",
"",
};
//---------------------------------------------------------------------------
int32u Ac3_variable_bits(BitStream_Fast &Search2, int8u Bits)
{
int32u Info = 0;
for (;;)
{
Info += Search2.Get4(Bits);
if (!Search2.GetB())
break;
Info <<= Bits;
Info += (1 << Bits);
}
return Info;
}
//---------------------------------------------------------------------------
bool Ac3_EMDF_Test(const BitStream_Fast &Search)
{
BitStream_Fast Search2(Search);
Search2.Skip(16); //syncword
size_t Size=((size_t)Search2.Get2(16))*8+17; //emdf_container_length
if (Size>Search2.Remain())
return false;
size_t End=Search2.Remain()-Size;
if (Search2.Get1(2)) //emdf_version
return false;
if (Search2.Get1(3) == 0x7) //key_id
Ac3_variable_bits(Search2, 3);
for (;;)
{
int8u emdf_payload_id=Search2.Get1(5);
if (!emdf_payload_id)
break;
if (emdf_payload_id == 0x1F)
Ac3_variable_bits(Search2, 5);
bool smploffste=Search2.GetB();
if (smploffste)
Search2.Skip(12);
if (Search2.GetB()) //duratione
Ac3_variable_bits(Search2, 11); //duration
if (Search2.GetB()) //groupide
Ac3_variable_bits(Search2, 2); //groupid
if (Search2.GetB()) //codecdatae
return false; //must be 0
if (!Search2.GetB()) //discard_unknown_payload
{
bool payload_frame_aligned=false;
if (!smploffste)
{
payload_frame_aligned=Search2.GetB();
if (payload_frame_aligned)
Search2.Skip(2);
}
if (smploffste || payload_frame_aligned)
Search2.Skip(7);
}
size_t emdf_payload_size=((size_t)Ac3_variable_bits(Search2, 8))*8;
Search2.Skip(emdf_payload_size);
}
int8u protection_length_primary=Search2.Get1(2);
switch (protection_length_primary)
{
case 0: return false;
case 1: protection_length_primary=8; break;
case 2: protection_length_primary=32; break;
case 3: protection_length_primary=128; break;
default: ;
}
int8u protection_bits_secondary=Search2.Get1(2);
switch (protection_bits_secondary)
{
case 0: protection_bits_secondary=0; break;
case 1: protection_bits_secondary=8; break;
case 2: protection_bits_secondary=32; break;
case 3: protection_bits_secondary=128; break;
default: ;
}
Search2.Skip(protection_length_primary);
Search2.Skip(protection_bits_secondary);
return Search2.Remain()>=17?true:false;
}
//---------------------------------------------------------------------------
/*
static const int8u ecplsubbndtab[]=
{
13,
19,
25,
31,
37,
49,
61,
73,
85,
97,
109,
121,
133,
145,
157,
169,
181,
193,
205,
217,
229,
241,
253,
};
*/
//***************************************************************************
// Constructor/Destructor
//***************************************************************************
//---------------------------------------------------------------------------
File_Ac3::File_Ac3()
:File__Analyze()
{
//Configuration
#if MEDIAINFO_EVENTS
ParserIDs[0]=MediaInfo_Parser_Ac3;
StreamIDs_Width[0]=0;
#endif //MEDIAINFO_EVENTS
#if MEDIAINFO_TRACE
Trace_Layers_Update(8); //Stream
#endif //MEDIAINFO_TRACE
MustSynchronize=true;
Buffer_TotalBytes_FirstSynched_Max=32*1024;
Buffer_TotalBytes_Fill_Max=1024*1024;
PTS_DTS_Needed=true;
StreamSource=IsStream;
Frame_Count_NotParsedIncluded=0;
//In
Frame_Count_Valid=0;
MustParse_dac3=false;
MustParse_dec3=false;
MustParse_dmlp=false;
CalculateDelay=false;
//Buffer
Save_Buffer=NULL;
//Temp
Frame_Count_HD=0;
addbsi_Buffer=NULL;
addbsi_Buffer_Size=0;
fscod=0;
fscod2=0;
frmsizecod=0;
bsid_Max=(int8u)-1;
Formats[0]=0;
Formats[1]=0;
for (int8u Pos=0; Pos<8; Pos++)
for (int8u Pos2=0; Pos2<9; Pos2++)
{
frmsizplus1_Max[Pos][Pos2]=0;
acmod_Max[Pos][Pos2]=(int8u)-1;
lfeon_Max[Pos][Pos2]=false;
bsmod_Max[Pos][Pos2]=0;
dsurmod_Max[Pos][Pos2]=0;
chanmape_Max[Pos][Pos2]=false;
chanmap_Max[Pos][Pos2]=0;
}
numblkscod=0;
dsurexmod=0;
dheadphonmod=0;
substreamid_Independant_Current=0;
substreams_Count=0;
joc_complexity_index_Container=(int8u)-1;
joc_complexity_index_Stream=(int8u)-1;
num_dynamic_objects=(int8u)-1;
nonstd_bed_channel_assignment_mask=(int32u)-1;
dxc3_Parsed=false;
HD_MajorSync_Parsed=false;
Core_IsPresent=false;
HD_IsPresent=false;
HD_HasAtmos=false;
dynrnge_Exists=false;
TimeStamp_IsPresent=false;
TimeStamp_IsParsing=false;
TimeStamp_Parsed=false;
TimeStamp_Count=0;
BigEndian=true;
IgnoreCrc_Done=false;
}
//---------------------------------------------------------------------------
File_Ac3::~File_Ac3()
{
delete[] addbsi_Buffer;
}
//***************************************************************************
// Streams management
//***************************************************************************
//---------------------------------------------------------------------------
void File_Ac3::Streams_Fill()
{
if (dxc3_Parsed)
{
if (Count_Get(Stream_Audio)==0)
Stream_Prepare(Stream_Audio);
}
if (HD_MajorSync_Parsed)
{
if (Count_Get(Stream_Audio)==0)
Stream_Prepare(Stream_Audio);
if (HD_BitRate_Max)
Fill(Stream_Audio, 0, Audio_BitRate_Maximum, (HD_BitRate_Max*AC3_HD_SamplingRate(HD_SamplingRate2)+8)>>4);
if (HD_StreamType==0xBA) //TrueHD
{
{
Fill(Stream_Audio, 0, Audio_Format, "MLP FBA");
Fill(Stream_Audio, 0, Audio_Codec, "MLP FBA");
}
if (HD_HasAtmos)
{
Fill(Stream_Audio, 0, Audio_Format_Profile, "MLP FBA 16-ch / MLP FBA");
Fill(Stream_Audio, 0, Audio_Codec_Profile, "MLP FBA 16-ch / MLP FBA");
}
Fill(Stream_Audio, 0, Audio_BitRate_Mode, "VBR");
Fill(Stream_Audio, 0, Audio_Compression_Mode, "Lossless");
Ztring Sampling;
Sampling.From_Number(AC3_HD_SamplingRate(HD_SamplingRate1));
Fill(Stream_Audio, 0, Audio_SamplingRate, Sampling);
Fill(Stream_Audio, 0, Audio_Channel_s_, AC3_TrueHD_Channels(HD_Channels2));
Fill(Stream_Audio, 0, Audio_ChannelPositions, AC3_TrueHD_Channels_Positions(HD_Channels2, HD_flags&(1<<11)));
Fill(Stream_Audio, 0, Audio_ChannelPositions_String2, AC3_TrueHD_Channels_Positions2(HD_Channels2, HD_flags&(1<<11)));
Fill(Stream_Audio, 0, Audio_ChannelLayout, AC3_TrueHD_Channels_ChannelLayout(HD_Channels2, HD_flags&(1<<11)));
}
if (HD_StreamType==0xBB) //TrueHD
{
{
Fill(Stream_Audio, 0, Audio_Format, "MLP");
Fill(Stream_Audio, 0, Audio_Codec, "MLP");
}
Fill(Stream_Audio, 0, Audio_BitRate_Mode, "VBR");
Fill(Stream_Audio, 0, Audio_Compression_Mode, "Lossless");
Fill(Stream_Audio, 0, Audio_SamplingRate, AC3_HD_SamplingRate(HD_SamplingRate2));
if (HD_SamplingRate1!=HD_SamplingRate2)
Fill(Stream_Audio, 0, Audio_SamplingRate, AC3_HD_SamplingRate(HD_SamplingRate2));
Fill(Stream_Audio, 0, Audio_Channel_s_, AC3_MLP_Channels[HD_Channels1]);
if (MediaInfoLib::Config.LegacyStreamDisplay_Get() && HD_Channels1!=HD_Channels2)
Fill(Stream_Audio, 0, Audio_Channel_s_, AC3_MLP_Channels[HD_Channels1]);
Fill(Stream_Audio, 0, Audio_BitDepth, AC3_MLP_Resolution[HD_Resolution2]);
if (MediaInfoLib::Config.LegacyStreamDisplay_Get() && HD_Resolution1!=HD_Resolution2)
Fill(Stream_Audio, 0, Audio_BitDepth, AC3_MLP_Resolution[HD_Resolution1]);
}
}
bool HasJOC = joc_num_objects_map.size()==1 && (joc_num_objects_map.begin()->second >= Frame_Count_Valid / 8 || joc_num_objects_map.begin()->second >= Frame_Count / 8); //Accepting that some frames do not contain JOC
if (HasJOC || HD_HasAtmos)
{
if (Count_Get(Stream_Audio)==0)
Stream_Prepare(Stream_Audio);
if (HasJOC)
{
Fill(Stream_Audio, 0, Audio_Format_Profile, bsid_Max<=0x09?"AC-3 JOC":"E-AC-3 JOC");
Fill(Stream_Audio, 0, Audio_Codec_Profile, bsid_Max<=0x09?"AC-3 JOC":"E-AC-3 JOC");
}
if (dxc3_Parsed && joc_complexity_index_Container!=(int8u)-1)
Fill(Stream_Audio, 0, "ComplexityIndex", joc_complexity_index_Container);
if (dxc3_Parsed && joc_complexity_index_Container==(int8u)-1 && joc_complexity_index_Stream!=(int8u)-1)
Fill(Stream_Audio, 0, "ComplexityIndex", "Not present");
if (joc_complexity_index_Stream!=(int8u)-1 && joc_complexity_index_Stream!=joc_complexity_index_Container)
Fill(Stream_Audio, 0, "ComplexityIndex", joc_complexity_index_Stream);
if (dxc3_Parsed && joc_complexity_index_Container!=(int8u)-1 && joc_complexity_index_Stream==(int8u)-1)
Fill(Stream_Audio, 0, "ComplexityIndex", "Not present");
if (num_dynamic_objects!=(int8u)-1)
Fill(Stream_Audio, 0, "NumberOfDynamicObjects", num_dynamic_objects);
if (nonstd_bed_channel_assignment_mask !=(int32u)-1)
{
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; i<BedChannelConfiguration.size();)
{
BedChannelCount++;
i=BedChannelConfiguration.find(__T(' '), i+1);
}
Fill(Stream_Audio, 0, "BedChannelCount", BedChannelCount);
Fill_SetOptions(Stream_Audio, 0, "BedChannelCount", "N NIY");
Fill(Stream_Audio, 0, "BedChannelCount/String", MediaInfoLib::Config.Language_Get(Ztring::ToZtring(BedChannelCount), __T(" channel")));
Fill_SetOptions(Stream_Audio, 0, "BedChannelCount/String", "Y NIN");
Fill(Stream_Audio, 0, "BedChannelConfiguration", BedChannelConfiguration);
}
}
//Surround
if (dsurmod_Max[0][0]==2)
{
Fill(Stream_Audio, 0, Audio_Format_Settings, "Dolby Surround");
Fill(Stream_Audio, 0, Audio_Format_Settings_Mode, "Dolby Surround");
}
if (dsurexmod==2)
{
Fill(Stream_Audio, 0, Audio_Format_Settings, "Dolby Surround EX");
Fill(Stream_Audio, 0, Audio_Format_Settings_Mode, "Dolby Surround EX");
}
if (dsurexmod==3)
{
Fill(Stream_Audio, 0, Audio_Format_Settings, "Dolby Pro Logic IIz");
Fill(Stream_Audio, 0, Audio_Format_Settings_Mode, "Dolby Pro Logic IIz");
}
if (dheadphonmod==2)
{
Fill(Stream_Audio, 0, Audio_Format_Settings, "Dolby Headphone");
Fill(Stream_Audio, 0, Audio_Format_Settings_Mode, "Dolby Headphone");
}
//AC-3
if (bsid_Max<=0x09)
{
if (Count_Get(Stream_Audio)==0)
Stream_Prepare(Stream_Audio);
if (Retrieve(Stream_Audio, 0, Audio_Format).empty() || MediaInfoLib::Config.LegacyStreamDisplay_Get())
{
Fill(Stream_Audio, 0, Audio_Format, "AC-3");
Fill(Stream_Audio, 0, Audio_Codec, "AC3");
}
int32u Divider=bsid_Max==9?2:1; // Unofficial hack for low sample rate (e.g. 22.05 kHz)
if (Ztring::ToZtring(AC3_SamplingRate[fscod]/Divider)!=Retrieve(Stream_Audio, 0, Audio_SamplingRate))
Fill(Stream_Audio, 0, Audio_SamplingRate, AC3_SamplingRate[fscod]/Divider);
if (frmsizecod/2<19)
{
if (Frame_Count_HD)
Fill(Stream_Audio, 0, Audio_BitRate, "Unknown");
int32u BitRate=AC3_BitRate[frmsizecod/2]*1000;
int32u Divider=bsid_Max==9?2:1; // Unofficial hack for low sample rate (e.g. 22.05 kHz)
int32u TimeStamp_BitRate=0;
if (TimeStamp_Count==Frame_Count || TimeStamp_Count>Frame_Count/2) // In case of corrupted stream, check that there is a minimal count of timestamps
TimeStamp_BitRate+=float32_int32s(AC3_SamplingRate[fscod]/Divider/12.0); // 12 = 1536 samples per frame / 128 bits per timestamp frame
Fill(Stream_Audio, 0, Audio_BitRate, BitRate/Divider);
if (TimeStamp_BitRate)
Fill(Stream_Audio, 0, Audio_BitRate_Encoded, BitRate/Divider+TimeStamp_BitRate);
if (CalculateDelay && Buffer_TotalBytes_FirstSynched>100 && BitRate>0)
{
Fill(Stream_Audio, 0, Audio_Delay, (float)Buffer_TotalBytes_FirstSynched*8*1000/BitRate, 0);
Fill(Stream_Audio, 0, Audio_Delay_Source, "Stream");
}
}
Fill(Stream_Audio, 0, Audio_ServiceKind, AC3_Mode[bsmod_Max[0][0]]);
Fill(Stream_Audio, 0, Audio_ServiceKind_String, AC3_Mode_String[bsmod_Max[0][0]]);
if ((MediaInfoLib::Config.LegacyStreamDisplay_Get() || Retrieve(Stream_Audio, 0, Audio_ChannelLayout).empty()) && acmod_Max[0][0]!=(int8u)-1)
{
int8u Channels=AC3_Channels[acmod_Max[0][0]];
Ztring ChannelPositions; ChannelPositions.From_UTF8(AC3_ChannelPositions[acmod_Max[0][0]]);
Ztring ChannelPositions2; ChannelPositions2.From_UTF8(AC3_ChannelPositions2[acmod_Max[0][0]]);
Ztring ChannelLayout; ChannelLayout.From_UTF8(lfeon_Max[0][0]?AC3_ChannelLayout_lfeon[acmod_Max[0][0]]:AC3_ChannelLayout_lfeoff[acmod_Max[0][0]]);
if (lfeon_Max[0][0])
{
Channels+=1;
ChannelPositions+=__T(", LFE");
ChannelPositions2+=__T(".1");
}
if (Ztring::ToZtring(Channels)!=Retrieve(Stream_Audio, 0, Audio_Channel_s_))
Fill(Stream_Audio, 0, Audio_Channel_s_, Channels);
if (ChannelPositions!=Retrieve(Stream_Audio, 0, Audio_ChannelPositions))
Fill(Stream_Audio, 0, Audio_ChannelPositions, ChannelPositions);
if (ChannelPositions2!=Retrieve(Stream_Audio, 0, Audio_ChannelPositions_String2))
Fill(Stream_Audio, 0, Audio_ChannelPositions_String2, ChannelPositions2);
if (Retrieve(Stream_Audio, 0, Audio_ChannelLayout).empty())
Fill(Stream_Audio, 0, Audio_ChannelLayout, ChannelLayout);
}
if (!Retrieve(Stream_Audio, 0, Audio_Format_Profile).empty())
Fill(Stream_Audio, 0, Audio_Format_Profile, "AC-3");
if (!Retrieve(Stream_Audio, 0, Audio_Codec_Profile).empty())
Fill(Stream_Audio, 0, Audio_Codec_Profile, "AC-3");
if ((MediaInfoLib::Config.LegacyStreamDisplay_Get() && __T("CBR")!=Retrieve(Stream_Audio, 0, Audio_BitRate_Mode)) || Retrieve(Stream_Audio, 0, Audio_BitRate_Mode).empty())
Fill(Stream_Audio, 0, Audio_BitRate_Mode, "CBR");
}
//E-AC-3
else if (bsid_Max<=0x10)
{
for (size_t Pos=0; Pos<8; Pos++)
if (acmod_Max[Pos][0]!=(int8u)-1)
{
if (Count_Get(Stream_Audio)==0)
Stream_Prepare(Stream_Audio);
if (Retrieve(Stream_Audio, 0, Audio_Format).empty())
{
Fill(Stream_Audio, 0, Audio_Format, Formats[0]?"AC-3":"E-AC-3");
Fill(Stream_Audio, 0, Audio_Codec, Formats[0] ?"AC-3":"AC3+");
}
if (acmod_Max[1][0]!=(int8u)-1)
Fill(Stream_Audio, 0, Audio_ID, 1+Pos);
Fill(Stream_Audio, 0, Audio_BitRate_Mode, "CBR");
int8u numblks=numblkscod==3?6:numblkscod+1;
int32u frmsiz_Total=0;
for (size_t Pos2=0; Pos2<8; Pos2++)
frmsiz_Total+=frmsizplus1_Max[Pos][Pos2];
int32u SamplingRate;
if (fscod!=3)
SamplingRate=AC3_SamplingRate[fscod];
else
SamplingRate=AC3_SamplingRate2[fscod2];
int32u TimeStamp_Size=0;
if (TimeStamp_Count==Frame_Count || TimeStamp_Count>Frame_Count/2) // In case of corrupted stream, check that there is a minimal count of timestamps
TimeStamp_Size=16;
Fill(Stream_Audio, 0, Audio_SamplingRate, SamplingRate);
Fill(Stream_Audio, 0, Audio_BitRate, ((int64u)frmsiz_Total)*SamplingRate/32/numblks);
if (TimeStamp_Size)
Fill(Stream_Audio, 0, Audio_BitRate_Encoded, ((int64u)frmsiz_Total+TimeStamp_Size)*SamplingRate/32/numblks);
if (acmod_Max[Pos][1]!=(int8u)-1)
{
int16u chanmap_Final=0;
for (int8u Pos2=0; Pos2<9; Pos2++)
if (acmod_Max[Pos][Pos2]!=(int8u)-1)
{
if (chanmape_Max[Pos][Pos2])
chanmap_Final|=chanmap_Max[Pos][Pos2];
else
{
chanmap_Final|=AC3_acmod2chanmap[acmod_Max[Pos][Pos2]];
if (lfeon_Max[Pos][Pos2])
chanmap_Final|=1; // LFE position in chanmap is bit 0
}
}
Fill(Stream_Audio, 0, Audio_Format_Profile, "E-AC-3+Dep");
Fill(Stream_Audio, 0, Audio_Codec_Profile, "E-AC-3+Dep");
Fill(Stream_Audio, 0, Audio_Channel_s_, AC3_chanmap_Channels(chanmap_Final));
Fill(Stream_Audio, 0, Audio_ChannelPositions, AC3_chanmap_ChannelPositions(chanmap_Final));
Ztring ChannelPositions2; ChannelPositions2.From_UTF8(AC3_ChannelPositions2[acmod_Max[0][0]]); //TODO: handle the dependancy
if (lfeon_Max[Pos][0])
{
ChannelPositions2+=__T(".1");
}
Fill(Stream_Audio, 0, Audio_ChannelPositions_String2, ChannelPositions2);
if (MediaInfoLib::Config.LegacyStreamDisplay_Get() || Retrieve(Stream_Audio, 0, Audio_ChannelLayout).empty())
{
Ztring ChannelLayout; ChannelLayout.From_UTF8(lfeon_Max[0][0]?AC3_ChannelLayout_lfeon[acmod_Max[0][0]]:AC3_ChannelLayout_lfeoff[acmod_Max[0][0]]);
Fill(Stream_Audio, 0, Audio_ChannelLayout, AC3_chanmap_ChannelLayout(chanmap_Final, ChannelLayout));
}
}
if (!Retrieve(Stream_Audio, 0, Audio_Format_Profile).empty())
Fill(Stream_Audio, 0, Audio_Format_Profile, Retrieve(Stream_Audio, 0, Audio_Format));
if (!Retrieve(Stream_Audio, 0, Audio_Codec_Profile).empty())
Fill(Stream_Audio, 0, Audio_Codec_Profile, Retrieve(Stream_Audio, 0, Audio_Format));
Fill(Stream_Audio, 0, Audio_ServiceKind, AC3_Mode[bsmod_Max[0][0]]);
Fill(Stream_Audio, 0, Audio_ServiceKind_String, AC3_Mode_String[bsmod_Max[0][0]]);
if ((MediaInfoLib::Config.LegacyStreamDisplay_Get() || Retrieve(Stream_Audio, 0, Audio_Channel_s_).empty()) && acmod_Max[Pos][0]!=(int8u)-1)
{
int8u Channels=AC3_Channels[acmod_Max[Pos][0]];
Ztring ChannelPositions; ChannelPositions.From_UTF8(AC3_ChannelPositions[acmod_Max[Pos][0]]);
Ztring ChannelPositions2; ChannelPositions2.From_UTF8(AC3_ChannelPositions2[acmod_Max[0][0]]);
if (lfeon_Max[Pos][0])
{
Channels+=1;
ChannelPositions+=__T(", LFE");
ChannelPositions2+=__T(".1");
}
Fill(Stream_Audio, 0, Audio_Channel_s_, Channels);
Fill(Stream_Audio, 0, Audio_ChannelPositions, ChannelPositions);
Fill(Stream_Audio, 0, Audio_ChannelPositions_String2, ChannelPositions2);
Fill(Stream_Audio, 0, Audio_ChannelLayout, lfeon_Max[0][0]?AC3_ChannelLayout_lfeon[acmod_Max[0][0]]:AC3_ChannelLayout_lfeoff[acmod_Max[0][0]]);
}
}
}
if (HD_MajorSync_Parsed)
{
//Filling Maximum bitrate with the constant core bitrate for better coherancy
ZtringList List;
List.Separator_Set(0, __T(" / "));
List.Write(Retrieve(Stream_Audio, 0, Audio_BitRate));
if (List.size()>=2)
Fill(Stream_Audio, 0, Audio_BitRate_Maximum, List[1]);
}
//Dolby Metadata
if (Core_IsPresent)
{
//Endianess
Fill(Stream_Audio, 0, Audio_Format_Settings_Endianness, BigEndian?"Big":"Little");
Fill(Stream_Audio, 0, "bsid", bsid_Max);
Fill(Stream_Audio, 0, "dialnorm", FirstFrame_Dolby.dialnorm==0?-31:-FirstFrame_Dolby.dialnorm);
Fill_SetOptions(Stream_Audio, 0, "dialnorm", "N NT");
Fill(Stream_Audio, 0, "dialnorm/String", Ztring::ToZtring(FirstFrame_Dolby.dialnorm==0?-31:-FirstFrame_Dolby.dialnorm)+__T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "dialnorm/String", "N NTN");
if (FirstFrame_Dolby.compre)
{
float64 Value=AC3_compr[FirstFrame_Dolby.compr>>4]+20*std::log10(((float)(0x10+(FirstFrame_Dolby.compr&0x0F)))/32);
Fill(Stream_Audio, 0, "compr", Value, 2);
Fill_SetOptions(Stream_Audio, 0, "compr", "N NT");
Fill(Stream_Audio, 0, "compr/String", Ztring::ToZtring(Value, 2)+__T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "compr/String", "N NTN");
}
if (FirstFrame_Dolby.dynrnge)
{
float64 Value;
if (FirstFrame_Dolby.dynrng==0)
Value=0; //Special case in the formula
else
Value=AC3_dynrng[FirstFrame_Dolby.dynrng>>5]+20*std::log10(((float)(0x20+(FirstFrame_Dolby.dynrng&0x1F)))/64);
Fill(Stream_Audio, 0, "dynrng", Value, 2);
Fill_SetOptions(Stream_Audio, 0, "dynrng", "N NT");
Fill(Stream_Audio, 0, "dynrng/String", Ztring::ToZtring(Value, 2)+__T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "dynrng/String", "N NTN");
}
for (int8u Pos=0; Pos<8; Pos++)
for (int8u Pos2=0; Pos2<9; Pos2++)
{
if (acmod_Max[Pos][Pos2]==(int8u)-1)
break;
else
{
if (acmod_Max[Pos][Pos2]==2)
{
Fill(Stream_Audio, 0, "dsurmod", dsurmod_Max[Pos][Pos2]);
Fill_SetOptions(Stream_Audio, 0, "dsurmod", "N NT");
Fill(Stream_Audio, 0, "dsurmod/String", AC3_Surround[dsurmod_Max[Pos][Pos2]]);
Fill_SetOptions(Stream_Audio, 0, "dsurmod/String", "N NTN");
}
Fill_SetOptions(Stream_Audio, 0, "bsid", "N NT");
Fill(Stream_Audio, 0, "acmod", acmod_Max[Pos][Pos2]);
Fill_SetOptions(Stream_Audio, 0, "acmod", "N NT");
Fill(Stream_Audio, 0, "lfeon", (lfeon_Max[Pos][Pos2])?1:0);
Fill_SetOptions(Stream_Audio, 0, "lfeon", "N NT");
}
}
}
//TimeStamp
if (TimeStamp_IsPresent)
{
Ztring TimeCode_FrameRate=Ztring::ToZtring((float64)TimeStamp_FirstFrame.FramesPerSecond/((TimeStamp_FirstFrame.DropFrame|TimeStamp_FirstFrame.FramesPerSecond_Is1001)?1.001:1.000), 3);
if (TimeStamp_FirstFrame.MoreSamples)
TimeStamp_FirstFrame.MoreSamples_Frequency=Retrieve(Stream_Audio, 0, Audio_SamplingRate).To_int32s();
Fill(Stream_Audio, 0, "TimeCode_FirstFrame", TimeStamp_FirstFrame.ToString());
Fill_SetOptions(Stream_Audio, 0, "TimeCode_FirstFrame", "N YCY");
Fill(Stream_Audio, 0, "TimeCode_FirstFrame/String", TimeStamp_FirstFrame.ToString()+" ("+TimeCode_FrameRate.To_UTF8()+" fps), embedded in stream");
Fill_SetOptions(Stream_Audio, 0, "TimeCode_FirstFrame/String", "Y NTN");
Fill(Stream_Audio, 0, "TimeCode_FirstFrame_FrameRate", TimeStamp_FirstFrame.ToString());
Fill_SetOptions(Stream_Audio, 0, "TimeCode_FirstFrame_FrameRate", "N YFY");
Fill(Stream_Audio, 0, "TimeCode_Source", "Stream");
Fill_SetOptions(Stream_Audio, 0, "TimeCode_Source", "N YTY");
Fill(Stream_Audio, 0, Audio_Delay, TimeStamp_FirstFrame.ToMilliseconds());
Fill(Stream_Audio, 0, Audio_Delay_Source, "Stream");
Fill(Stream_Audio, 0, Audio_Delay_Settings, TimeStamp_FirstFrame.DropFrame?"drop_frame_flag=1":"drop_frame_flag=0");
}
//Samples per frame
int16u SamplesPerFrame;
if (bsid_Max<=0x08)
SamplesPerFrame=1536;
else if (bsid_Max<=0x09)
SamplesPerFrame=768; // Unofficial hack for low sample rate (e.g. 22.05 kHz)
else if (bsid_Max>0x0A && bsid_Max<=0x10)
SamplesPerFrame=256*(numblkscod==3?6:(numblkscod+1));
else if (HD_MajorSync_Parsed && (HD_StreamType==0xBA || HD_StreamType==0xBB)) // TrueHD or MLP
{
int64u HD_SamplingRate=Retrieve_Const(Stream_Audio, 0, Audio_SamplingRate).To_int64u();
if (HD_SamplingRate<44100)
SamplesPerFrame=0; //Unknown
else if (HD_SamplingRate<=48000)
SamplesPerFrame=40;
else if (HD_SamplingRate<=96000)
SamplesPerFrame=80;
else if (HD_SamplingRate<=192000)
SamplesPerFrame=160;
else
SamplesPerFrame=0; //Unknown
}
else
SamplesPerFrame=0;
if (SamplesPerFrame)
Fill(Stream_Audio, 0, Audio_SamplesPerFrame, SamplesPerFrame);
// Commercial name
if (Retrieve(Stream_Audio, 0, Audio_Format)==__T("E-AC-3") || Retrieve(Stream_Audio, 0, Audio_Format_Profile).find(__T("E-AC-3"))==0)
{
if (HasJOC)
Fill(Stream_Audio, 0, Audio_Format_Commercial_IfAny, "Dolby Digital Plus with Dolby Atmos");
else
Fill(Stream_Audio, 0, Audio_Format_Commercial_IfAny, "Dolby Digital Plus");
}
else if (Retrieve(Stream_Audio, 0, Audio_Format)==__T("MLP FBA") || Retrieve(Stream_Audio, 0, Audio_Format_Profile).find(__T("MLP FBA"))==0)
{
if (HasJOC || HD_HasAtmos)
Fill(Stream_Audio, 0, Audio_Format_Commercial_IfAny, "Dolby TrueHD with Dolby Atmos");
else
Fill(Stream_Audio, 0, Audio_Format_Commercial_IfAny, "Dolby TrueHD");
}
else if (Retrieve(Stream_Audio, 0, Audio_Format)==__T("MLP") || Retrieve(Stream_Audio, 0, Audio_Format_Profile).find(__T("MLP"))==0)
{
Fill(Stream_Audio, 0, Audio_Format_Commercial_IfAny, "MLP Lossless");
}
else if (Retrieve(Stream_Audio, 0, Audio_Format)==__T("AC-3"))
Fill(Stream_Audio, 0, Audio_Format_Commercial_IfAny, "Dolby Digital");
Fill(Stream_General, 0, General_Format, Retrieve(Stream_Audio, 0, Audio_Format), true);
Fill(Stream_General, 0, General_Format_Profile, Retrieve(Stream_Audio, 0, Audio_Format_Profile));
Fill(Stream_General, 0, General_Format_Commercial_IfAny, Retrieve(Stream_Audio, 0, Audio_Format_Commercial_IfAny));
}
//---------------------------------------------------------------------------
void File_Ac3::Streams_Finish()
{
//Stats
if (!dialnorms.empty())
{
int8u Minimum_Raw=1;
int8u Maximum_Raw=31;
float64 Sum_Intensity=0;
int64u Count=0;
for (int8u Pos=0; (size_t)Pos<dialnorms.size(); Pos++)
if (dialnorms[Pos])
{
if (Minimum_Raw<(Pos==0?31:Pos))
Minimum_Raw=(Pos==0?31:Pos);
if (Maximum_Raw>(Pos==0?31:Pos))
Maximum_Raw=(Pos==0?31:Pos);
Sum_Intensity+=dialnorms[Pos]*pow(10, -((float64)Pos)/10);
Count+=dialnorms[Pos];
}
if (Count)
{
float64 Average_dB = log10(Sum_Intensity / Count) * 10;
Fill(Stream_Audio, 0, "dialnorm_Average", Average_dB, 0);
Fill_SetOptions(Stream_Audio, 0, "dialnorm_Average", "N NT");
Fill(Stream_Audio, 0, "dialnorm_Average/String", Ztring::ToZtring(Average_dB, 0) + __T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "dialnorm_Average/String", "N NTN");
Fill(Stream_Audio, 0, "dialnorm_Minimum", -Minimum_Raw);
Fill_SetOptions(Stream_Audio, 0, "dialnorm_Minimum", "N NT");
Fill(Stream_Audio, 0, "dialnorm_Minimum/String", Ztring::ToZtring(-Minimum_Raw) + __T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "dialnorm_Minimum/String", "N NTN");
Fill(Stream_Audio, 0, "dialnorm_Maximum", -Maximum_Raw);
Fill_SetOptions(Stream_Audio, 0, "dialnorm_Maximum", "N NTN");
Fill(Stream_Audio, 0, "dialnorm_Maximum/String", Ztring::ToZtring(-Maximum_Raw) + __T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "dialnorm_Maximum/String", "N NTN");
Fill(Stream_Audio, 0, "dialnorm_Count", Count);
Fill_SetOptions(Stream_Audio, 0, "dialnorm_Count", "N NTN");
}
}
if (!comprs.empty())
{
float64 Minimum_dB=47.89;
float64 Maximum_dB=-48.16;
float64 Sum_Intensity=0;
int64u Count=0;
for (size_t Pos=0; Pos<comprs.size(); Pos++)
if (comprs[Pos])
{
float64 Value=AC3_compr[Pos>>4]+20*std::log10(((float)(0x10+(Pos&0x0F)))/32);
if (Minimum_dB>Value)
Minimum_dB=Value;
if (Maximum_dB<Value)
Maximum_dB=Value;
Sum_Intensity+=comprs[Pos]*pow(10, Value/10);
Count+=comprs[Pos];
}
if (Count)
{
float64 Average_dB = log10(Sum_Intensity / Count) * 10;
Fill(Stream_Audio, 0, "compr_Average", Average_dB, 2);
Fill_SetOptions(Stream_Audio, 0, "compr_Average", "N NT");
Fill(Stream_Audio, 0, "compr_Average/String", Ztring::ToZtring(Average_dB, 2) + __T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "compr_Average/String", "N NTN");
Fill(Stream_Audio, 0, "compr_Minimum", Minimum_dB, 2);
Fill_SetOptions(Stream_Audio, 0, "compr_Minimum", "N NT");
Fill(Stream_Audio, 0, "compr_Minimum/String", Ztring::ToZtring(Minimum_dB, 2) + __T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "compr_Minimum/String", "N NTN");
Fill(Stream_Audio, 0, "compr_Maximum", Maximum_dB, 2);
Fill_SetOptions(Stream_Audio, 0, "compr_Maximum", "N NT");
Fill(Stream_Audio, 0, "compr_Maximum/String", Ztring::ToZtring(Maximum_dB, 2) + __T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "compr_Maximum/String", "N NTN");
Fill(Stream_Audio, 0, "compr_Count", Count);
Fill_SetOptions(Stream_Audio, 0, "compr_Count", "N NT");
}
}
if (dynrnge_Exists && !dynrngs.empty())
{
float64 Minimum_dB=23.95;
float64 Maximum_dB=-24.08;
float64 Sum_Intensity=0;
int64u Count=0;
for (size_t Pos=0; Pos<dynrngs.size(); Pos++)
if (dynrngs[Pos])
{
float64 Value;
if (Pos==0)
Value=0; //Special case in the formula
else
Value=AC3_dynrng[Pos>>5]+20*std::log10(((float)(0x20+(Pos&0x1F)))/64);
if (Minimum_dB>Value)
Minimum_dB=Value;
if (Maximum_dB<Value)
Maximum_dB=Value;
Sum_Intensity+=dynrngs[Pos]*pow(10, Value/10);
Count+=dynrngs[Pos];
}
if (Count)
{
float64 Average_dB = log10(Sum_Intensity / Count) * 10;
Fill(Stream_Audio, 0, "dynrng_Average", Average_dB, 2);
Fill_SetOptions(Stream_Audio, 0, "dynrng_Average", "N NT");
Fill(Stream_Audio, 0, "dynrng_Average/String", Ztring::ToZtring(Average_dB, 2) + __T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "dynrng_Average/String", "N NTN");
Fill(Stream_Audio, 0, "dynrng_Minimum", Minimum_dB, 2);
Fill_SetOptions(Stream_Audio, 0, "dynrng_Minimum", "N NT");
Fill(Stream_Audio, 0, "dynrng_Minimum/String", Ztring::ToZtring(Minimum_dB, 2) + __T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "dynrng_Minimum/String", "N NTN");
Fill(Stream_Audio, 0, "dynrng_Maximum", Maximum_dB, 2);
Fill_SetOptions(Stream_Audio, 0, "dynrng_Maximum", "N NT");
Fill(Stream_Audio, 0, "dynrng_Maximum/String", Ztring::ToZtring(Maximum_dB, 2) + __T(" dB"));
Fill_SetOptions(Stream_Audio, 0, "dynrng_Maximum/String", "N NTN");
Fill(Stream_Audio, 0, "dynrng_Count", Count);
Fill_SetOptions(Stream_Audio, 0, "dynrng_Count", "N NT");
}
}
//Duration
if (!IsSub)
{
int64u Frame_Count_ForDuration=0;
if (Config->ParseSpeed>=1)
{
Frame_Count_ForDuration=Frame_Count; //We have the exact count of frames
Fill(Stream_Audio, 0, Audio_StreamSize, File_Offset+Buffer_Offset+Element_Size-File_Offset_FirstSynched);
}
else if (bsid_Max<=9 && frmsizecods.size()==1 && fscods.size()==1 && Frame_Count_HD==0)
{
int16u Size=AC3_FrameSize_Get(frmsizecods.begin()->first, fscods.begin()->first);
if (Size)
{
if (TimeStamp_IsPresent)
Size+=16;
Frame_Count_ForDuration=(File_Size-File_Offset_FirstSynched)/Size; //Only complete frames
Fill(Stream_Audio, 0, Audio_StreamSize, Frame_Count_ForDuration*Size);
}
}
if (Frame_Count_ForDuration)
{
Clear(Stream_Audio, 0, Audio_BitRate);
//HD part
if (Frame_Count_HD)
{
int32u HD_SamplingRate=AC3_HD_SamplingRate(HD_SamplingRate1);
if (HD_SamplingRate)
{
int8u FrameDuration; //In samples
if (HD_SamplingRate<44100)
FrameDuration=0; //Unknown
else if (HD_SamplingRate<=48000)
FrameDuration=40;
else if (HD_SamplingRate<=96000)
FrameDuration=80;
else if (HD_SamplingRate<=192000)
FrameDuration=160;
else
FrameDuration=0; //Unknown
if (FrameDuration)
{
int64u SamplingCount=Frame_Count_HD*FrameDuration;
Fill(Stream_Audio, 0, Audio_Duration, SamplingCount/(((float64)HD_SamplingRate)/1000), 0);
Fill(Stream_Audio, 0, Audio_SamplingCount, SamplingCount);
Fill(Stream_Audio, 0, Audio_BitRate, (File_Size-File_Offset_FirstSynched)/(SamplingCount/(((float64)HD_SamplingRate)/1000))*8, 0);
}
Fill(Stream_Audio, 0, Audio_FrameCount, Frame_Count_HD);
}
}
if (Core_IsPresent)
{
Fill(Stream_Audio, 0, Audio_FrameCount, Frame_Count_ForDuration);
if (AC3_SamplingRate[fscod])
{
float64 FrameDuration;
if (bsid_Max<=0x08)
FrameDuration=32;
else if (bsid_Max<=0x09)
FrameDuration=16; // Unofficial hack for low sample rate (e.g. 22.05 kHz)
else
FrameDuration=0;
if (FrameDuration)
{
FrameDuration*=((float64)48000)/AC3_SamplingRate[fscod]; //32 ms for 48 KHz, else proportional (34.83 for 44.1 KHz, 48 ms for 32 KHz)
Fill(Stream_Audio, 0, Audio_SamplingCount, Frame_Count_ForDuration*1536);
Fill(Stream_Audio, 0, Audio_Duration, Frame_Count_ForDuration*FrameDuration, 0);
if (frmsizecod/2<19)
{
int32u BitRate=AC3_BitRate[frmsizecod/2]*1000;
int32u Divider=bsid_Max == 9?2:1; // Unofficial hack for low sample rate (e.g. 22.05 kHz)
Fill(Stream_Audio, 0, Audio_BitRate, BitRate/Divider);
}
}
}
}
}
}
else if (FrameInfo.PTS!=(int64u)-1 && FrameInfo.PTS>PTS_Begin)
{
Fill(Stream_Audio, 0, Audio_Duration, float64_int64s(((float64)(FrameInfo.PTS-PTS_Begin))/1000000));
float64 FrameDuration;
if (bsid_Max<=0x08)
FrameDuration=32;
else if (bsid_Max<=0x09)
FrameDuration=16; // Unofficial hack for low sample rate (e.g. 22.05 kHz)
else if (bsid_Max>0x0A && bsid_Max<=0x10)
{
int8u numblks=numblkscod==3?6:numblkscod+1;
FrameDuration=((float64)32)/6*numblks;
}
else
FrameDuration=0;
if (FrameDuration)
Fill(Stream_Audio, 0, Audio_FrameCount, float64_int64s(((float64)(FrameInfo.PTS-PTS_Begin))/1000000/FrameDuration));
}
}
//---------------------------------------------------------------------------
void File_Ac3::Read_Buffer_Unsynched()
{
delete[] Save_Buffer; Save_Buffer=NULL;
if (File_GoTo==0)
Synched_Init();
}
//---------------------------------------------------------------------------
#if MEDIAINFO_SEEK
size_t File_Ac3::Read_Buffer_Seek (size_t Method, int64u Value, int64u /*ID*/)
{
GoTo(0);
Open_Buffer_Unsynch();
return 1;
}
#endif //MEDIAINFO_SEEK
//***************************************************************************
// Buffer - Synchro
//***************************************************************************
//---------------------------------------------------------------------------
bool File_Ac3::FileHeader_Begin()
{
//Specific cases
if (MustParse_dac3 || MustParse_dec3)
return true;
//Must have enough buffer for having header
if (Buffer_Size<4)
return false; //Must wait for more data
//False positives detection: detect Matroska files, AC-3 parser is not smart enough
if (!FileHeader_Begin_0x000001())
{
Finish("AC-3");
return false;
}
//All should be OK...
return true;
}
//***************************************************************************
// Buffer - Synchro
//***************************************************************************
//---------------------------------------------------------------------------
bool File_Ac3::Synchronize()
{
//Specific cases
if (MustParse_dac3 || MustParse_dec3)
return true;
//Synchronizing
while (Buffer_Offset+8<=Buffer_Size)
{
if (!FrameSynchPoint_Test())
return false; //Need more data
if (Synched)
break;
Buffer_Offset++;
}
//Parsing last bytes if needed
if (Buffer_Offset+8>Buffer_Size)
{
//We must keep more bytes in order to detect TimeStamp
if (Frame_Count==0)
{
if (Buffer_Offset>=16)
Buffer_Offset-=16;
else
Buffer_Offset=0;
return false;
}
if (Buffer_Offset+7==Buffer_Size && CC3(Buffer+Buffer_Offset+4)!=0xF8726F && CC2(Buffer+Buffer_Offset)!=0x0B77 && CC2(Buffer+Buffer_Offset)!=0x770B)
Buffer_Offset++;
if (Buffer_Offset+6==Buffer_Size && CC2(Buffer+Buffer_Offset+4)!=0xF872 && CC2(Buffer+Buffer_Offset)!=0x0B77 && CC2(Buffer+Buffer_Offset)!=0x770B)
Buffer_Offset++;
if (Buffer_Offset+5==Buffer_Size && CC1(Buffer+Buffer_Offset+4)!=0xF8 && CC2(Buffer+Buffer_Offset)!=0x0B77 && CC2(Buffer+Buffer_Offset)!=0x770B)
Buffer_Offset++;
if (Buffer_Offset+4==Buffer_Size && CC2(Buffer+Buffer_Offset)!=0x0B77 && CC2(Buffer+Buffer_Offset)!=0x770B)
Buffer_Offset++;
if (Buffer_Offset+3==Buffer_Size && CC2(Buffer+Buffer_Offset)!=0x0B77 && CC2(Buffer+Buffer_Offset)!=0x770B)
Buffer_Offset++;
if (Buffer_Offset+2==Buffer_Size && CC2(Buffer+Buffer_Offset)!=0x0B77 && CC2(Buffer+Buffer_Offset)!=0x770B)
Buffer_Offset++;
if (Buffer_Offset+1==Buffer_Size && CC1(Buffer+Buffer_Offset)!=0x0B && CC1(Buffer+Buffer_Offset)!=0x77)
Buffer_Offset++;
return false;
}
//Testing if we have TimeStamp
if (Buffer_Offset>=16)
{
if ( Buffer[Buffer_Offset-0x10+0x00]==0x01 //Magic value? Always 0x01
&& Buffer[Buffer_Offset-0x10+0x01]==0x10 //Size? Always 0x10
&& Buffer[Buffer_Offset-0x10+0x02]==0x00 //First byte of HH? Always 0x00
&& (Buffer[Buffer_Offset-0x10+0x03]>>4 )<0x6 //Second byte of HH? First 4 bits must be <0x6
&& (Buffer[Buffer_Offset-0x10+0x03]&0xF)<0xA //Second byte of HH? Second 4 bits must be <0xA
&& Buffer[Buffer_Offset-0x10+0x04]==0x00 //First byte of MM? Always 0x00
&& (Buffer[Buffer_Offset-0x10+0x05]>>4 )<0x6 //Second byte of MM? First 4 bits must be <0x6
&& (Buffer[Buffer_Offset-0x10+0x05]&0xF)<0xA //Second byte of MM? Second 4 bits must be <0xA
&& Buffer[Buffer_Offset-0x10+0x06]==0x00 //First byte of SS? Always 0x00
&& (Buffer[Buffer_Offset-0x10+0x07]>>4 )<0x6 //Second byte of SS? First 4 bits must be <0x6
&& (Buffer[Buffer_Offset-0x10+0x07]&0xF)<0xA //Second byte of SS? Second 4 bits must be <0xA
&& Buffer[Buffer_Offset-0x10+0x08]==0x00 //First byte of FF? Always 0x00
&& (Buffer[Buffer_Offset-0x10+0x09]>>4 )<0x4 //Second byte of FF? First 4 bits must be <0x4
&& (Buffer[Buffer_Offset-0x10+0x09]&0xF)<0xA //Second byte of FF? Second 4 bits must be <0xA
&& !(Buffer[Buffer_Offset-0x10+0x00]==0x00 //We want at least a byte not zero, in order to differentiate TimeStamp from padding
&& Buffer[Buffer_Offset-0x10+0x01]==0x00
&& Buffer[Buffer_Offset-0x10+0x0C]==0x00
&& Buffer[Buffer_Offset-0x10+0x0D]==0x00
&& Buffer[Buffer_Offset-0x10+0x0E]==0x00
&& Buffer[Buffer_Offset-0x10+0x0F]==0x00))
{
TimeStamp_IsPresent=true;
Buffer_Offset-=16;
}
}
//Synched
return true;
}
//---------------------------------------------------------------------------
void File_Ac3::Synched_Init()
{
if (!Frame_Count_Valid)
Frame_Count_Valid=Config->ParseSpeed>=0.3?32: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_Ac3::Synched_Test()
{
//Specific cases
if (MustParse_dac3 || MustParse_dec3)
return true;
//Must have enough buffer for having header
if (Buffer_Offset+(TimeStamp_IsPresent?16:0)+6>Buffer_Size)
return false;
//TimeStamp
if (TimeStamp_IsPresent && !TimeStamp_Parsed)
{
if (!( Buffer[Buffer_Offset+0x00]==0x01 //Magic value? Always 0x01
&& Buffer[Buffer_Offset+0x01]==0x10 //Size? Always 0x10
&& Buffer[Buffer_Offset+0x02]==0x00 //First byte of HH? Always 0x00
&& (Buffer[Buffer_Offset+0x03]>>4 )<0x6 //Second byte of HH? First 4 bits must be <0x6
&& (Buffer[Buffer_Offset+0x03]&0xF)<0xA //Second byte of HH? Second 4 bits must be <0xA
&& Buffer[Buffer_Offset+0x04]==0x00 //First byte of MM? Always 0x00
&& (Buffer[Buffer_Offset+0x05]>>4 )<0x6 //Second byte of MM? First 4 bits must be <0x6
&& (Buffer[Buffer_Offset+0x05]&0xF)<0xA //Second byte of MM? Second 4 bits must be <0xA
&& Buffer[Buffer_Offset+0x06]==0x00 //First byte of SS? Always 0x00
&& (Buffer[Buffer_Offset+0x07]>>4 )<0x6 //Second byte of SS? First 4 bits must be <0x6
&& (Buffer[Buffer_Offset+0x07]&0xF)<0xA //Second byte of SS? Second 4 bits must be <0xA
&& Buffer[Buffer_Offset+0x08]==0x00 //First byte of FF? Always 0x00
&& (Buffer[Buffer_Offset+0x09]>>4 )<0x4 //Second byte of FF? First 4 bits must be <0x4
&& (Buffer[Buffer_Offset+0x09]&0xF)<0xA)) //Second byte of FF? Second 4 bits must be <0xA
TimeStamp_IsPresent=false;
}
if (TimeStamp_IsPresent && !TimeStamp_Parsed)
Buffer_Offset+=16;
//Quick test of synchro
if (!FrameSynchPoint_Test())
{
if (TimeStamp_IsPresent && !TimeStamp_Parsed && Buffer_Offset>=16)
Buffer_Offset-=16;
return false; //Need more data
}
if (!Synched)
return true;
//TimeStamp
if (TimeStamp_IsPresent && !TimeStamp_Parsed)
{
Buffer_Offset-=16;
if (Synched)
{
TimeStamp_IsParsing=true;
TimeStamp_Parsed=false;
}
else
{
TimeStamp_IsParsing=false;
TimeStamp_Parsed=false;
}
}
//We continue
return true;
}
//***************************************************************************
// Buffer - Demux
//***************************************************************************
//---------------------------------------------------------------------------
#if MEDIAINFO_DEMUX
bool File_Ac3::Demux_UnpacketizeContainer_Test()
{
if (TimeStamp_IsPresent)
Buffer_Offset+=16;
if (!HD_IsPresent && Frame_Count==0 && Save_Buffer==NULL)
{
//Searching HD part
size_t Buffer_Offset_Save=Buffer_Offset;
Buffer_Offset++;
Synched=false;
while (Buffer_Offset+8<=Buffer_Size)
{
if (!FrameSynchPoint_Test())
{
Buffer_Offset=Buffer_Offset_Save;
return false; //Need more data
}
if (Synched)
break;
Buffer_Offset++;
}
Buffer_Offset=Buffer_Offset_Save;
if (!Synched)
{
Synched=true;
if (TimeStamp_IsPresent)
Buffer_Offset-=16;
return false; //Need more data
}
}
if (Save_Buffer)
{
Demux_TotalBytes-=Buffer_Offset;
Demux_Offset-=Buffer_Offset;
File_Offset+=Buffer_Offset;
swap(Buffer, Save_Buffer);
swap(Buffer_Offset, Save_Buffer_Offset);
swap(Buffer_Size, Save_Buffer_Size);
}
if (Buffer[Buffer_Offset]==0x0B && Buffer[Buffer_Offset+1]==0x77)
{
int8u bsid=Buffer[Buffer_Offset+5]>>3;
if (bsid<=0x08)
FrameInfo.DUR=32000000;
else if (bsid<=0x09)
FrameInfo.DUR=16000000; // Unofficial hack for low sample rate (e.g. 22.05 kHz)
else if (bsid>0x0A && bsid<=0x10)
{
numblkscod=(Buffer[Buffer_Offset+4]>>4)&0x3;
int64u numblks=numblkscod==3?6:numblkscod+1;
FrameInfo.DUR=32000000*numblks/6;
}
Demux_Offset=Buffer_Offset+Core_Size_Get();
//Core part
if (HD_IsPresent)
{
if (TimeStamp_IsPresent)
Buffer_Offset-=16;
if (Save_Buffer)
{
swap(Buffer, Save_Buffer);
swap(Buffer_Offset, Save_Buffer_Offset);
swap(Buffer_Size, Save_Buffer_Size);
Demux_TotalBytes+=Buffer_Offset;
Demux_Offset+=Buffer_Offset;
File_Offset-=Buffer_Offset;
}
return true; //No AC-3 demux
}
}
else
{
Demux_Offset=Buffer_Offset+HD_Size_Get();
}
if (Demux_Offset>Buffer_Size && File_Offset+Buffer_Size!=File_Size)
{
if (TimeStamp_IsPresent)
Buffer_Offset-=16;
if (Save_Buffer)
{
swap(Buffer, Save_Buffer);
swap(Buffer_Offset, Save_Buffer_Offset);
swap(Buffer_Size, Save_Buffer_Size);
Demux_TotalBytes+=Buffer_Offset;
Demux_Offset+=Buffer_Offset;
File_Offset-=Buffer_Offset;
}
return false; //No complete frame
}
Demux_UnpacketizeContainer_Demux();
if (Save_Buffer)
{
swap(Buffer, Save_Buffer);
swap(Buffer_Offset, Save_Buffer_Offset);
swap(Buffer_Size, Save_Buffer_Size);
Demux_TotalBytes+=Buffer_Offset;
Demux_Offset+=Buffer_Offset;
File_Offset-=Buffer_Offset;
}
if (TimeStamp_IsPresent)
Buffer_Offset-=16;
return true;
}
#endif //MEDIAINFO_DEMUX
//***************************************************************************
// Buffer - Global
//***************************************************************************
//---------------------------------------------------------------------------
void File_Ac3::Read_Buffer_OutOfBand()
{
if (MustParse_dmlp)
{
dmlp();
return;
}
}
//---------------------------------------------------------------------------
void File_Ac3::Read_Buffer_Continue()
{
if (MustParse_dac3)
{
dac3();
return;
}
if (MustParse_dec3)
{
dec3();
return;
}
}
//***************************************************************************
// Buffer - Per element
//***************************************************************************
//---------------------------------------------------------------------------
void File_Ac3::Header_Parse()
{
//TimeStamp
if (TimeStamp_IsParsing)
{
Header_Fill_Size(16);
Header_Fill_Code(2, "TimeStamp");
return;
}
if (Save_Buffer)
{
File_Offset+=Buffer_Offset;
swap(Buffer, Save_Buffer);
swap(Buffer_Offset, Save_Buffer_Offset);
swap(Buffer_Size, Save_Buffer_Size);
}
//Filling
if ((Buffer[Buffer_Offset]==0x0B && Buffer[Buffer_Offset+1]==0x77)
|| (Buffer[Buffer_Offset]==0x77 && Buffer[Buffer_Offset+1]==0x0B))
{
Header_Fill_Size(Core_Size_Get());
Header_Fill_Code(0, "syncframe");
//Little Endian management
if (Save_Buffer)
{
swap(Buffer, Save_Buffer);
swap(Buffer_Offset, Save_Buffer_Offset);
swap(Buffer_Size, Save_Buffer_Size);
File_Offset-=Buffer_Offset;
}
return;
}
//MLP or TrueHD specific
int16u Size;
BS_Begin();
Skip_S1( 4, "CRC?");
Get_S2 (12, Size, "Size");
BS_End();
Skip_B2( "Timestamp?");
//Little Endian management
if (Save_Buffer)
{
swap(Buffer, Save_Buffer);
swap(Buffer_Offset, Save_Buffer_Offset);
swap(Buffer_Size, Save_Buffer_Size);
}
//Filling
if (Size<2)
{
Synched=false;
Size=2;
}
Size*=2;
Header_Fill_Size(Size);
Header_Fill_Code(1, "HD");
}
//---------------------------------------------------------------------------
void File_Ac3::Data_Parse()
{
if (Element_Code != 2) // Not time stamp
TimeStamp_Parsed=false; //Currently, only one kind of intermediate element is detected (no TimeStamp and HD part together), and we don't know the precise specification of MLP nor TimeStamp, so we consider next eleemnt is TimeStamp
if (Save_Buffer)
{
File_Offset+=Buffer_Offset;
swap(Buffer, Save_Buffer);
swap(Buffer_Offset, Save_Buffer_Offset);
swap(Buffer_Size, Save_Buffer_Size);
}
//Parsing
switch (Element_Code)
{
case 0 :
Core();
break;
case 1 :
Element_Info1C((FrameInfo.PTS!=(int64u)-1), __T("PTS ")+Ztring().Duration_From_Milliseconds(float64_int64s(((float64)FrameInfo.PTS)/1000000)));
Element_Info1(Frame_Count);
HD();
break;
case 2 : TimeStamp(); break;
default: ;
}
//Little Endian management
if (Save_Buffer)
{
delete[] Buffer;
Buffer=Save_Buffer; Save_Buffer=NULL;
Buffer_Offset=Save_Buffer_Offset;
Buffer_Size=Save_Buffer_Size;
File_Offset-=Buffer_Offset;
}
}
//---------------------------------------------------------------------------
void File_Ac3::Core()
{
while (Element_Offset<Element_Size)
{
if (substreams_Count)
{
Element_Name("Block");
Element_Begin1("syncframe");
}
Core_Frame();
if (substreams_Count)
Element_End0();
}
if (acmod_Max[0][0]==(int8u)-1)
return; //Waiting for the first sync frame
FILLING_BEGIN();
if (bsid>0x10)
return; //Not supported
//Counting
if (Frame_Count==0)
{
Core_IsPresent=true;
PTS_Begin=FrameInfo.PTS;
}
if (bsid==0x09)
Frequency_b=AC3_SamplingRate2[fscod]; // Unofficial hack for low sample rate (e.g. 22.05 kHz)
else
{
if (fscod!=3)
Frequency_b=AC3_SamplingRate[fscod];
else
Frequency_b=AC3_SamplingRate2[fscod2];
}
if (bsid>0x0A)
{
int64u numblks = numblkscod == 3 ? 6 : numblkscod + 1;
TS_Add(numblks*256);
}
else
TS_Add(1536);
if (File_Offset+Buffer_Offset+Element_Size==File_Size)
Frame_Count_Valid=Frame_Count; //Finish frames in case of there are less than Frame_Count_Valid frames
//Filling
if (!Status[IsAccepted])
Accept("AC-3");
if (!Status[IsFilled] && Frame_Count>=Frame_Count_Valid)
{
Fill("AC-3");
//No more need data
if (!IsSub && Config->ParseSpeed<1.0)
Finish("AC-3");
}
FILLING_END();
}
//---------------------------------------------------------------------------
void File_Ac3::Core_Frame()
{
//Save true Element_Size (if Core+substreams, Element_Size is for all elements, and we want to limit to core)
int64u Element_Size_Save=Element_Size;
bsid=CC1(Buffer+Buffer_Offset+Element_Offset+5)>>3;
if (bsid<=0x09)
{
fscod =(Buffer[(size_t)(Buffer_Offset+4)]&0xC0)>>6;
frmsizecod= Buffer[(size_t)(Buffer_Offset+4)]&0x3F;
//Filling
fscods[fscod]++;
frmsizecods[frmsizecod]++;
Element_Size=Element_Offset+AC3_FrameSize_Get(frmsizecod, fscod);
if (Element_Size>Element_Size_Save)
Element_Size=Element_Size_Save; // Not expected, but trying to parse the begining
}
else if (bsid>0x0A && bsid<=0x10) //E-AC-3 only
{
int16u frmsiz=CC2(Buffer+Buffer_Offset+(size_t)Element_Offset+2)&0x07FF;
Element_Size=Element_Offset+2+frmsiz*2;
if (Element_Size>Element_Size_Save)
Element_Size=Element_Size_Save; // Not expected, but trying to parse the begining
}
if (Element_Offset==Element_Size)
Element_Size=Element_Size_Save; // Something went wrong, using the whole packet
//Pre-parsing, finding some elements presence
int16u auxdatal;
if (Buffer[Buffer_Offset+(Element_Size)-3]&0x02) //auxdatae
auxdatal=(((int16u)Buffer[Buffer_Offset+(Element_Size)-4])<<6)
|( Buffer[Buffer_Offset+(Element_Size)-3] >>2);
else
auxdatal=(int16u)-1; //auxdata is empty
BitStream_Fast Search(Buffer+Buffer_Offset+Element_Offset, Element_Size-Element_Offset);
while(Search.Remain()>18)
{
if (Search.Peek2(16)==0x5838 && Ac3_EMDF_Test(Search))
break;
Search.Skip(1);
}
if (Search.Remain()>18)
EMDF_RemainPos=Search.Remain();
else
EMDF_RemainPos=(size_t)-1;
//Parsing
int16u frmsiz=0, chanmap=0;
int8u dialnorm=(int8u)-1, dialnorm2=(int8u)-1, compr=(int8u)-1, compr2=(int8u)-1, dynrng=(int8u)-1, dynrng2=(int8u)-1;
int8u strmtyp=0, substreamid=0, acmod=0, bsmod=0, dsurmod=0;
bool compre=false, compr2e=false, dynrnge=false, dynrng2e=false;
bool lfeon=false, chanmape=false;
bool addbsie;
if (bsid<=0x09)
{
Element_Begin1("synchinfo");
Skip_B2( "syncword");
Skip_B2( "crc1");
BS_Begin();
Get_S1 (2, fscod, "fscod - Sample Rate Code"); Param_Info2(AC3_SamplingRate[fscod], " Hz");
Get_S1 (6, frmsizecod, "frmsizecod - Frame Size Code"); Param_Info2C(frmsizecod/2<19,AC3_BitRate[frmsizecod/2]*1000, " bps");
Element_End0();
Element_Begin1("bsi");
Get_S1 (5, bsid, "bsid - Bit Stream Identification");
Get_S1 (3, bsmod, "bsmod - Bit Stream Mode"); Param_Info1(AC3_Mode[bsmod]);
Get_S1 (3, acmod, "acmod - Audio Coding Mode"); Param_Info1(AC3_ChannelPositions[acmod]);
if ((acmod&1) && acmod!=1) //central present
Skip_S1(2, "cmixlev - Center Mix Level");
if (acmod&4) //back present
Skip_S1(2, "surmixlev - Surround Mix Level");
if (acmod==2)
Get_S1 (2, dsurmod, "dsurmod - Dolby Surround Mode"); Param_Info1(AC3_Surround[dsurmod]);
Get_SB ( lfeon, "lfeon - Low Frequency Effects");
Get_S1 (5, dialnorm, "dialnorm - Dialogue Normalization");
Get_SB ( compre, "compre - Compression Gain Word Exists");
if (compre)
Get_S1 (8, compr, "compr - Compression Gain Word");
TEST_SB_SKIP( "langcode - Language Code Exists");
Skip_S1(8, "langcod - Language Code");
TEST_SB_END();
TEST_SB_SKIP( "audprodie - Audio Production Information Exists");
Skip_S1(8, "mixlevel - Mixing Level");
Skip_S1(2, "roomtyp - Room Type");
TEST_SB_END();
if (acmod==0) //1+1 mode
{
Get_S1 (5, dialnorm2, "dialnorm2 - Dialogue Normalization");
Get_SB ( compr2e, "compr2e - Compression Gain Word Exists");
if (compr2e)
Get_S1 (8, compr2, "compr2 - Compression Gain Word");
TEST_SB_SKIP( "langcod2e - Language Code Exists");
Skip_S1(8, "langcod2 - Language Code");
TEST_SB_END();
TEST_SB_SKIP( "audprodi2e - Audio Production Information Exists");
Skip_S1(8, "mixlevel2 - Mixing Level");
Skip_S1(2, "roomtyp2 - Room Type");
TEST_SB_END();
}
Skip_SB( "copyrightb - Copyright Bit");
Skip_SB( "origbs - Original Bit Stream");
if (bsid==0x06)
{
TEST_SB_SKIP( "xbsi1e");
Skip_S1(2, "dmixmod");
Skip_S1(3, "ltrtcmixlev");
Skip_S1(3, "ltrtsurmixlev");
Skip_S1(3, "lorocmixlev");
Skip_S1(3, "lorosurmixlev");
TEST_SB_END();
TEST_SB_SKIP( "xbsi2e");
Get_S1 (2, dsurexmod, "dsurexmod");
Get_S1 (2, dheadphonmod, "dheadphonmod");
Skip_SB( "adconvtyp");
Skip_S1(8, "xbsi2");
Skip_SB( "encinfo");
TEST_SB_END();
}
else
{
TEST_SB_SKIP( "timecod1e");
Skip_S2(14, "timecod1");
TEST_SB_END();
TEST_SB_SKIP( "timecod2e");
Skip_S2(14, "timecod2");
TEST_SB_END();
}
TEST_SB_SKIP( "addbsie");
int8u addbsil;
Get_S1 (6, addbsil, "addbsil");
for (int8u Pos=0; Pos<=addbsil; Pos++) //addbsil+1 bytes
Skip_S1(8, "addbsi");
TEST_SB_END();
Element_End0();
Element_Begin1("audblk");
for (int8u Pos=0; Pos<AC3_Channels[acmod]; Pos++)
Skip_SB( "blksw - Block Switch Flag");
for (int8u Pos=0; Pos<AC3_Channels[acmod]; Pos++)
Skip_SB( "dithflag - Dither Flag");
Get_SB ( dynrnge, "dynrnge - Dynamic Range Gain Word Exists");
if (dynrnge)
Get_S1 (8, dynrng, "dynrng - Dynamic Range Gain Word");
if (acmod==0) //1+1 mode
{
Get_SB ( dynrng2e, "dynrng2e - Dynamic Range Gain Word Exists");
if (dynrng2e)
Get_S1 (8, dynrng2, "dynrng2 - Dynamic Range Gain Word");
}
Element_End0();
}
else if (bsid>0x0A && bsid<=0x10)
{
/* Not finished, for reference only
static const size_t MAX_AUD_BLK = 6;
static const size_t MAX_CHANNELS = 5;
struct Aud_Blk
{
bool cplstre;
bool cplinu;
bool lfeexpstr;
int8u blkmixcfginfo;
int8u cplexpstr;
int8u chexpstr[MAX_CHANNELS];
};
Aud_Blk aud_blks[MAX_AUD_BLK];
struct Aud_Chan_Blk
{
bool blksw;
bool chahtinu;
bool chincpl;
bool chinspx;
bool cplcoe;
bool dithflag;
bool ecplparam1e;
bool firstspxcos;
bool firstcplcos;
bool rsvdfieldse;
bool spxcoe;
int8u chactivegaqbins; //todo
int8u chbwcod;
int8u convexpstr;
int8u deltbae;
int8u endmant;
int8u frmchexpstr;
int8u mstrspxco;
int8u spxblnd;
int8u strtmant;
};
Aud_Chan_Blk aud_chan_blk[MAX_CHANNELS];
bool firstcplleak = false;
//*/
Element_Begin1("synchinfo");
Skip_B2( "syncword");
Element_End0();
Element_Begin1("bsi");
BS_Begin();
size_t Bits_Begin=Data_BS_Remain();
Get_S1 ( 2, strmtyp, "strmtyp");
Get_S1 ( 3, substreamid, "substreamid");
Get_S2 (11, frmsiz, "frmsiz");
Get_S1 ( 2, fscod, "fscod"); Param_Info2(AC3_SamplingRate[fscod], " Hz");
if (fscod==3)
{
Get_S1 ( 2, fscod2, "fscod2"); Param_Info2(AC3_SamplingRate2[fscod2], " Hz");
numblkscod=3;
}
else
Get_S1 ( 2, numblkscod, "numblkscod");
Get_S1 (3, acmod, "acmod - Audio Coding Mode"); Param_Info1(AC3_ChannelPositions[acmod]);
Get_SB ( lfeon, "lfeon - Low Frequency Effects");
Get_S1 (5, bsid, "bsid - Bit Stream Identification");
Get_S1 (5, dialnorm, "dialnorm");
TEST_SB_GET(compre, "compre");
Get_S1 (8, compr, "compr");
TEST_SB_END();
if (acmod==0) //1+1 mode
{
Get_S1 (5, dialnorm2, "dialnorm2");
TEST_SB_GET(compr2e, "compr2e");
Get_S1 (8, compr2, "compr2");
TEST_SB_END();
}
if (strmtyp==1) //dependent stream
{
TEST_SB_GET (chanmape, "chanmape");
Get_S2(16, chanmap, "chanmap"); Param_Info1(AC3_chanmap_ChannelPositions(chanmap));
TEST_SB_END();
}
TEST_SB_SKIP( "mixmdate");
int8u dmixmod, ltrtcmixlev, lorocmixlev, ltrtsurmixlev, lorosurmixlev, mixdef;
if(acmod > 0x2)
Get_S1 (2, dmixmod, "dmixmod");
if((acmod&0x1) && (acmod>0x2))
{
Get_S1 (3, ltrtcmixlev, "ltrtcmixlev");
Get_S1 (3, lorocmixlev, "lorocmixlev");
}
if(acmod>0x4)
{
Get_S1 (3, ltrtsurmixlev, "ltrtsurmixlev");
Get_S1 (3, lorosurmixlev, "lorosurmixlev");
}
if(lfeon)
{
TEST_SB_SKIP( "lfemixlevcode");
Skip_S1 (5, "lfemixlevcod");
TEST_SB_END();
}
if(strmtyp == 0x0)
{
TEST_SB_SKIP( "pgmscle");
Skip_S1 (6, "pgmscl");
TEST_SB_END();
if (acmod == 0x0)
{
TEST_SB_SKIP( "pgmscle12e");
Skip_S1 (6, "pgmscl12e");
TEST_SB_END();
}
TEST_SB_SKIP( "extpgmscle");
Skip_S1 (6, "extpgmscl");
TEST_SB_END();
Get_S1 (2, mixdef, "mixdef");
if(mixdef == 0x1)
{
Skip_S1 (1, "premixcmpsel");
Skip_S1 (1, "drcsrc");
Skip_S1 (3, "premixcmpscl");
}
else if(mixdef == 0x2) Skip_S2 (12, "mixdata");
else if(mixdef == 0x3)
{
int8u mixdeflen;
Get_S1 (5, mixdeflen, "mixdeflen");
TEST_SB_SKIP( "mixdata2e");
Skip_S1 (6, "premixcmpsel");
Skip_S1 (1, "drcsrc");
Skip_S1 (3, "premixcmpscl");
TEST_SB_SKIP( "extpgmlscle");
Skip_S1 (4, "extpgmlscl");
TEST_SB_END();
TEST_SB_SKIP( "extpgmcscle");
Skip_S1 (4, "extpgmcscl");
TEST_SB_END();
TEST_SB_SKIP( "extpgmrscle");
Skip_S1 (4, "extpgmrscl");
TEST_SB_END();
TEST_SB_SKIP( "extpgmlssle");
Skip_S1 (4, "extpgmlssl");
TEST_SB_END();
TEST_SB_SKIP( "extpgmrssle");
Skip_S1 (4, "extpgmrssl");
TEST_SB_END();
TEST_SB_SKIP( "extpgmlfescle");
Skip_S1 (4, "extpgmlfescl");
TEST_SB_END();
TEST_SB_SKIP( "dmixscle");
Skip_S1 (4, "dmixscl");
TEST_SB_END();
TEST_SB_SKIP( "addche");
TEST_SB_SKIP( "extpgmaux1scle");
Skip_S1 (4, "extpgmaux1scl");
TEST_SB_END();
TEST_SB_SKIP( "extpgmaux2scle");
Skip_S1 (4, "extpgmaux2scl");
TEST_SB_END();
TEST_SB_END();
TEST_SB_END();
TEST_SB_SKIP( "mixdata3e");
Skip_S1 (5, "spchdat");
TEST_SB_SKIP( "addspchdate");
Skip_S1 (5, "spchdat1");
Skip_S1 (2, "spchan1att");
TEST_SB_SKIP( "addspdat1e");
Skip_S1 (5, "spchdat2");
Skip_S1 (2, "spchan2att");
TEST_SB_END();
TEST_SB_END();
TEST_SB_END();
Skip_S2 (8*(mixdeflen+2), "mixdata");
//Skip_S1 (, "mixdatafill");
}
if(acmod<0x2)
{
TEST_SB_SKIP( "paninfoe");
Skip_S1 (6, "panmean");
Skip_S1 (8, "paninfo");
TEST_SB_END();
if(acmod==0x0)
{
TEST_SB_SKIP( "paninfo2e");
Skip_S1 (6, "panmean2");
Skip_S1 (8, "paninfo2");
TEST_SB_END();
}
}
TEST_SB_SKIP( "frmmixcfginfoe");
if(numblkscod==0x0)
{
int8u blkmixcfginfo;
Get_S1 (5, blkmixcfginfo, "blkmixcfginfo[0]");
//aud_blks[0].blkmixcfginfo = blkmixcfginfo;
}
else
{
int8u nb_blocks_per_syncframe = numblkscod == 3 ? 6 : (numblkscod + 1);
for (int8u blk = 0; blk < nb_blocks_per_syncframe; ++blk)
{
TEST_SB_SKIP( "blkmixcfginfoe");
int8u blkmixcfginfo;
Get_S1 (5, blkmixcfginfo, "blkmixcfginfo[x]");
//aud_blks[blk].blkmixcfginfo = blkmixcfginfo;
TEST_SB_END();
}
}
TEST_SB_END();
}
TEST_SB_END();
TEST_SB_SKIP( "infomdate");
Skip_S1(3, "bsmod");
Skip_SB( "copyrightb - Copyright Bit");
Skip_SB( "origbs - Original Bit Stream");
if (acmod==0x2)
{
Get_S1 (2, dsurmod, "dsurmod");
Get_S1 (2, dheadphonmod, "dheadphonmod");
}
if (acmod>=0x6)
Get_S1 (2, dsurexmod, "dsurexmod");
TEST_SB_SKIP( "audprodie");
Skip_S1(5, "mixlevel");
Skip_S1(2, "roomtyp");
Skip_S1(1, "adconvtyp");
TEST_SB_END();
if (acmod==0x0)
{
TEST_SB_SKIP( "audprodi2e");
Skip_S1(5, "mixlevel2");
Skip_S1(2, "roomtyp2");
Skip_S1(1, "adconvtyp2");
TEST_SB_END();
}
if (fscod < 0x3)
Skip_S1(1, "sourcefscod");
TEST_SB_END();
if (strmtyp==0x0 && numblkscod!=0x3)
Skip_S1(1, "convsync");
if (strmtyp == 0x2)
{
int8u blkid = 0;
if (numblkscod==0x3)
blkid = 1;
else
Get_S1(1, blkid, "blkid");
if (blkid)
Get_S1(6, frmsizecod, "frmsizecod");
}
TEST_SB_GET (addbsie, "addbsie");
int8u addbsil;
Get_S1 (6, addbsil, "addbsil");
if (addbsil+1!=addbsi_Buffer_Size)
{
delete[] addbsi_Buffer;
addbsi_Buffer_Size=addbsil+1;
addbsi_Buffer=new int8u[addbsi_Buffer_Size];
}
for (int8u Pos=0; Pos<=addbsil; Pos++) //addbsil+1 bytes
Get_S1 (8, addbsi_Buffer[Pos], "addbsi");
TEST_SB_END();
Element_End0();
/* Not finished, for reference only
int8u numblks = numblkscod == 3 ? 6 : (numblkscod + 1);
Element_Begin1("audfrm");
int8u snroffststr, ncplblks = 0;
bool expstre = true, ahte = false;
bool transproce, blkswe, dithflage, bamode, frmfgaincode, dbaflde, skipflde, spxattene;
if (numblkscod==0x3)
{
Get_SB(expstre, "expstre");
Get_SB(ahte, "ahte");
}
Get_S1 (2, snroffststr, "snroffststr");
Get_SB (transproce, "transproce");
Get_SB (blkswe, "blkswe");
Get_SB (dithflage, "dithflage");
Get_SB (bamode, "bamode");
Get_SB (frmfgaincode, "frmfgaincode");
Get_SB (dbaflde, "dbaflde");
Get_SB (skipflde, "skipflde");
Get_SB (spxattene, "spxattene");
if (acmod>0x1)
{
aud_blks[0].cplstre = 1;
aud_blks[0].cplinu = 0;
for (int8u blk = 1; blk < numblks; ++blk)
{
Get_SB (aud_blks[blk].cplstre, "cplstre[x]");
if (aud_blks[blk].cplstre==1)
Get_SB (aud_blks[blk].cplinu, "cplinu[x]");
else
aud_blks[blk].cplinu = aud_blks[blk - 1].cplinu;
}
}
else
{
for(int8u blk = 0; blk < numblks; ++blk)
aud_blks[blk].cplinu = 0;
}
if (expstre)
{
for(int8u blk = 0; blk < numblks; ++blk)
{
if (aud_blks[blk].cplinu==1)
Get_S1 (2, aud_blks[blk].cplexpstr, "cplexpstr[x]");
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
Get_S1(2, aud_blks[blk].chexpstr[Pos], "chexpstr[blk][ch]");
}
}
else
{
int8u frmcplexpstr = 0;
ncplblks = 0;
for (int8u blk = 0; blk < numblks; ++blk)
ncplblks += aud_blks[blk].cplinu;
if (acmod > 0x1 && ncplblks > 0)
Get_S1(5, frmcplexpstr, "frmcplexpstr");
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
Get_S1(5, aud_chan_blk[Pos].frmchexpstr, "frmchexpstr[ch]");
}
if (lfeon)
for (int8u blk = 0; blk < numblks; ++blk)
Get_SB(aud_blks[blk].lfeexpstr, "lfeexpstr[blk]");
if (strmtyp == 0x0)
{
bool convexpstre = true;
if (numblkscod!=0x3)
Get_SB (convexpstre, "convexpstre");
if (convexpstre)
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
Get_S1(5, aud_chan_blk[Pos].convexpstr, "convexpstr[ch]");
}
int8u cplahtinu = 0;
int8u lfeahtinu = 0;
int8u *hebap = NULL; //TODO in ahte
if (ahte)
{
ncplblks = 0;
int8u ncplregs = 0;
for (int8u blk = 0; blk < numblks; ++blk)
{
//reuse corresponds to 0
if (aud_blks[blk].cplstre == 1 || aud_blks[blk].cplexpstr != 0)
++ncplregs;
}
if (ncplblks==6 && ncplregs==1)
{
bool tmp;
Get_SB (tmp, "cplahtinu");
if (tmp)
cplahtinu = 1;
}
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
int8u nchregs = 0;
for (int8u blk = 0; blk < numblks; ++blk)
{
if (aud_blks[blk].chexpstr[Pos]!=0)
++nchregs;
}
aud_chan_blk[Pos].chahtinu = 0;
if (nchregs==1)
{
bool tmp;
Get_SB (tmp, "chahtinu[ch]");
if (tmp)
aud_chan_blk[Pos].chahtinu = 1;
}
}
if (lfeon)
{
int8u nlferegs = 0;
for (int8u blk = 0; blk < numblks; ++blk)
{
if (aud_blks[blk].lfeexpstr!=false)
++nlferegs;
}
if (nlferegs==1)
{
bool tmp = false;
Get_SB (tmp, "lfeahtinu");
if (tmp)
lfeahtinu = 1;
}
}
}
if (snroffststr)
{
Skip_S1 (6, "frmcsnroffst");
Skip_S1 (4, "frmfsnroffst");
}
if (transproce)
{
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
TEST_SB_SKIP( "chintransproc[ch]");
Skip_S2(10, "transprocloc[ch]");
Skip_S1(8, "transproclen[ch]");
TEST_SB_END();
}
}
if (spxattene)
{
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
TEST_SB_SKIP( "chinspxatten[ch]");
Skip_S1(5, "spxattencod[ch]");
TEST_SB_END();
}
}
bool blkstrtinfoe = false;
int8u blkstrtinfo = 0;
if (numblkscod != 0x0)
Get_SB (blkstrtinfoe, "blkstrtinfoe");
if (blkstrtinfoe)
blkstrtinfo = (numblks - 1) * (4 + ceil(log2(frmsiz + 1)));
// These fields for syntax state initialization
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
aud_chan_blk[Pos].firstspxcos = true;
aud_chan_blk[Pos].firstcplcos = true;
}
firstcplleak = true;
Element_End0();
Element_Begin1("audblks");
for (int8u blk = 0; blk < numblks; ++blk)
{
Element_Begin1("audblk");
if (blkswe)
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
Get_SB (aud_chan_blk[Pos].blksw, "blksw[ch]");
else
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
aud_chan_blk[Pos].blksw = false;
if (dithflage)
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
Get_SB (aud_chan_blk[Pos].dithflag, "dithflag[ch]");
else
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
aud_chan_blk[Pos].dithflag = true;
int8u dynrng = 0;
int8u dynrng2 = 0;
TEST_SB_SKIP( "dynrnge");
Get_S1 (8, dynrng, "dynrng");
TEST_SB_END();
if (acmod==0x0)
{
TEST_SB_SKIP( "dynrng2e");
Get_S1 (8, dynrng, "dynrng2");
TEST_SB_END();
}
int8u spx_begin_subbnd, spx_end_subbnd;
int8u spxbegf = 0;
bool spxbndstrc[256];
bool spxstre = true;
bool spxinu = false;
if (blk!=0)
Peek_SB(spxstre);
if (spxstre)
{
Element_Begin1("spxstr");
Skip_SB( "spxstre");
Get_SB (spxinu, "spxinu");
if (spxinu)
{
if (acmod==0x1)
aud_chan_blk[0].chinspx = true;
else
{
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
Get_SB (aud_chan_blk[Pos].chinspx,"chinspx[ch]");
}
int8u spxstrtf, spxendf;
Get_S1 (2, spxstrtf, "spxstrtf");
Get_S1 (3, spxbegf, "spxbegf");
Get_S1 (3, spxendf, "spxendf");
if (spxbegf<6)
spx_begin_subbnd = spxbegf + 2;
else
spx_begin_subbnd = spxbegf * 2 - 3;
if (spxendf < 3)
spx_end_subbnd = spxendf + 5;
else
spx_end_subbnd = spxendf * 2 + 3;
TEST_SB_SKIP( "spxbndstrce");
for (int8u bnd = spx_begin_subbnd+1; bnd < spx_end_subbnd; ++bnd)
Get_SB (spxbndstrc[bnd], "spxbndstrc[bnd]");
TEST_SB_END();
}
else
{
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
aud_chan_blk[Pos].chinspx = false;
aud_chan_blk[Pos].firstspxcos = true;
}
}
Element_End0();
}
if (spxinu)
{
Element_Begin1("spxin");
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
Element_Begin1("Channel");
if (aud_chan_blk[Pos].chinspx)
{
if (aud_chan_blk[Pos].firstspxcos)
{
aud_chan_blk[Pos].spxcoe = true;
aud_chan_blk[Pos].firstspxcos = false;
}
else
Get_SB (aud_chan_blk[Pos].spxcoe, "spxcoe[ch]");
if (aud_chan_blk[Pos].spxcoe)
{
Get_S1 (5, aud_chan_blk[Pos].spxblnd,"spxblnd[ch]");
Get_S1 (2, aud_chan_blk[Pos].mstrspxco,"mstrspxco[ch]");
int8u nspxbnds = 1;
int8u spxbndsztab[256] = {0};
spxbndsztab[0] = 12;
for (int8u bnd = spx_begin_subbnd+1; bnd < spx_end_subbnd; ++bnd)
{
if (spxbndstrc[bnd] == false)
{
spxbndsztab[nspxbnds] = 12;
++nspxbnds;
}
else
spxbndsztab[nspxbnds - 1] += 12;
}
for (int8u bnd = 0; bnd < nspxbnds; ++bnd)
{
Element_Begin1("Bnd");
Skip_S1 (4, "spxcoexp[ch][bnd]");
Skip_S1 (2, "spxcomant[ch][bnd]");
Element_End0();
}
}
}
else
aud_chan_blk[Pos].firstspxcos = true;
Element_End0();
}
Element_End0();
}
bool ecplinu = false;
bool phsflginu = false;
bool cplbndstrce = false;
int8u ncplsubnd = 0;
bool *cplbndstrc = NULL;
int16u necplbnd = 0;
int8u ecplbegf, ecplendf = 0;
int8u cplbegf, cplendf = 0;
int16u ecpl_begin_subbnd = 0, ecpl_end_subbnd = 0;
size_t cplstrtmant = 0;
size_t lfeactivegaqbins = 0;
size_t cplendmant = 0;
if (aud_blks[blk].cplstre)
{
Element_Begin1("cplstr");
if (aud_blks[blk].cplinu)
{
Element_Begin1("cplin");
Get_SB (ecplinu, "ecplinu");
if (acmod==0x2)
{
aud_chan_blk[0].chincpl = true;
aud_chan_blk[1].chincpl = true;
}
else
{
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
Get_SB (aud_chan_blk[1].chincpl, "chincpl[ch]");
}
if (!ecplinu)
{
if (acmod==0x2)
Get_SB (phsflginu, "phsflginu");
Get_S1 (4, cplbegf, "cplbegf");
cplstrtmant = (cplbegf * 12) + 37;;
if (!spxinu)
Get_S1 (4, cplendf, "cplendf");
else
{
if (spxbegf < 6)
cplendf = spxbegf - 2;
else
cplendf = (spxbegf * 2) - 7;
}
ncplsubnd = 3 + cplendf - cplbegf;
Get_SB (cplbndstrce, "cplbndstrce");
if (cplbndstrce)
{
cplbndstrc = new bool [ncplsubnd];
cplbndstrc[0] = false;
for (int8u bnd = 1; bnd < ncplsubnd; ++bnd)
Get_SB (cplbndstrc[bnd], "cplbndstrc[bnd]");
}
}
else
{
Get_S1 (4, ecplbegf, "ecplbegf");
cplstrtmant = (cplbegf * 12) + 37;;
if (ecplbegf<3)
ecpl_begin_subbnd = ecplbegf * 2;
else if (ecplbegf<13)
ecpl_begin_subbnd = ecplbegf + 2;
else
ecpl_begin_subbnd = ecplbegf * 2 - 10;
if (!spxinu)
{
Get_S1 (4, ecplendf, "ecplendf");
ecpl_end_subbnd = ecplendf + 7;
}
else
{
if (spxbegf < 6)
ecpl_end_subbnd = spxbegf + 5;
else
ecpl_end_subbnd = spxbegf * 2;
}
necplbnd = ecpl_end_subbnd - ecpl_begin_subbnd;
TEST_SB_SKIP( "ecplbndstrce");
int16u max = 9;
if (max < ecpl_begin_subbnd+1)
max = ecpl_begin_subbnd+1;
ncplsubnd = ecpl_end_subbnd;
cplbndstrc = new bool [ecpl_end_subbnd];
for (size_t i = 0; i < max; ++i)
cplbndstrc[i] = false;
for (int16u sbnd = max; sbnd < ecpl_end_subbnd; ++sbnd)
Get_SB (cplbndstrc[sbnd], "cplbndstrc[bnd]");
necplbnd = 0;
for (int16u i = ecpl_begin_subbnd; i < ecpl_end_subbnd; ++i)
necplbnd += cplbndstrc[i];
TEST_SB_END();
}
Element_End0();
}
else
{
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
aud_chan_blk[Pos].chincpl = false;
aud_chan_blk[Pos].firstcplcos = true;
}
firstcplleak = true;
}
Element_End0();
}
if (aud_blks[blk].cplinu)
{
if (!ecplinu)
{
int16u ncplbnd = ncplsubnd;
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
if (aud_chan_blk[Pos].chincpl)
{
if (aud_chan_blk[Pos].firstcplcos)
{
aud_chan_blk[Pos].cplcoe = true;
aud_chan_blk[Pos].firstcplcos = false;
}
else
Get_SB(aud_chan_blk[Pos].cplcoe,"cplcoe[ch]");
if (aud_chan_blk[Pos].cplcoe)
{
Skip_S1 (2, "mstrcplco[ch]");
ncplbnd = ncplsubnd;
for (size_t i = 1; i < ncplsubnd; ++i)
ncplbnd += cplbndstrc[i];
for (int16u bnd = 0; bnd < ncplbnd; bnd++)
{
Skip_S1(4, "cplcoexp[ch][bnd]");
Skip_S1(4, "cplcomant[ch][bnd]");
}
}
}
else
{
aud_chan_blk[Pos].firstcplcos = true;
}
}
if (acmod==0x2 && phsflginu && (aud_chan_blk[0].cplcoe || aud_chan_blk[1].cplcoe))
{
for (size_t bnd = 0; bnd < ncplbnd; ++bnd)
Skip_SB( "phsflg[bnd]}");
}
}
else
{
int firstchincpl = -1;
Skip_SB( "reserved");
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
if (aud_chan_blk[Pos].chincpl)
{
if (firstchincpl == -1)
firstchincpl = Pos;
if (aud_chan_blk[Pos].firstcplcos)
{
aud_chan_blk[Pos].ecplparam1e = true;
if (Pos > firstchincpl)
aud_chan_blk[Pos].rsvdfieldse = true;
else
aud_chan_blk[Pos].rsvdfieldse = false;
aud_chan_blk[Pos].firstcplcos = false;
}
else
{
Get_SB (aud_chan_blk[Pos].ecplparam1e, "ecplparam1e");
if (Pos > firstchincpl)
Get_SB (aud_chan_blk[Pos].rsvdfieldse, "rsvdfieldse");
else
aud_chan_blk[Pos].rsvdfieldse = false;
}
if (aud_chan_blk[Pos].ecplparam1e)
{
if (aud_chan_blk[Pos].ecplparam1e)
{
for (size_t bnd = 0; bnd < necplbnd; bnd++)
Skip_S1(5, "ecplamp[ch][bnd]");
}
if (aud_chan_blk[Pos].rsvdfieldse)
Skip_BS(9 * (necplbnd - 1), "reserved");
if (Pos > firstchincpl)
Skip_SB( "reserved");
}
}
else
aud_chan_blk[Pos].firstcplcos = true;
}
}
}
//aud_chan_blk_init(acmod, cplbegf);
for (int8u Pos = 0; Pos<AC3_Channels[acmod]; ++Pos)
{
aud_chan_blk[Pos].strtmant = 0;
if (aud_chan_blk[Pos].chincpl)
aud_chan_blk[Pos].endmant = 37 + (12 * cplbegf);
else
aud_chan_blk[Pos].endmant = 37 + (3 * (aud_chan_blk[Pos].chbwcod + 12));
}
if (acmod==0x2)
{
bool rematstr = true;
if (blk!=0)
Get_SB(rematstr, "rematstr");
if (rematstr)
{
size_t nrematbd = 0;
if (aud_blks[blk].cplinu)
{
if (ecplinu)
{
if (ecplbegf == 0)
nrematbd = 0;
else if (ecplbegf == 1)
nrematbd = 1;
else if (ecplbegf == 2)
nrematbd = 2;
else if (ecplbegf < 5)
nrematbd = 3;
else
nrematbd = 4;
}
else
{
if (cplbegf == 0)
nrematbd = 2;
else if (cplbegf < 3)
nrematbd = 3;
else
nrematbd = 4;
}
}
else if (spxinu)
{
if (spxbegf < 2)
nrematbd = 3;
else
nrematbd = 4;
}
else
{
nrematbd = 4;
}
for (size_t bnd = 0; bnd < nrematbd; ++bnd)
Skip_SB( "rematflg[bnd]");
}
}
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
if (aud_blks[blk].chexpstr[Pos])
{
if (!aud_chan_blk[Pos].chincpl && !aud_chan_blk[Pos].chinspx)
Get_S1 (6, aud_chan_blk[Pos].chbwcod, "chbwcod[ch]");
}
}
if (aud_blks[blk].cplinu)
{
if (aud_blks[blk].cplexpstr!=0)
{
Skip_S1(4, "cplabsexp");
size_t ncplgrps = 0;
if (ecplinu)
{
int8u ecplstartmant = ecplsubbndtab[ecpl_begin_subbnd];
int8u ecplendmant = ecplsubbndtab[ecpl_end_subbnd];
if (aud_blks[blk].cplexpstr == 0x01)
ncplgrps = (ecplendmant - ecplstartmant) / 3;
else if (aud_blks[blk].cplexpstr == 0x02)
ncplgrps = (ecplendmant - ecplstartmant) / 6;
else if (aud_blks[blk].cplexpstr == 0x03)
ncplgrps = (ecplendmant - ecplstartmant) / 12;
}
else
{
cplendmant = ((cplendf + 3) * 12) + 37;
if (aud_blks[blk].cplexpstr == 0x01)
ncplgrps = (cplendmant - cplstrtmant) / 3;
else if (aud_blks[blk].cplexpstr == 0x02)
ncplgrps = (cplendmant - cplstrtmant) / 6;
else if (aud_blks[blk].cplexpstr == 0x03)
ncplgrps = (cplendmant - cplstrtmant) / 12;
}
for(size_t grp = 0; grp < ncplgrps; grp++)
Skip_S1(7, "cplexps[grp]");
}
}
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
if (aud_blks[blk].chexpstr[Pos]!=0)
{
Skip_S1(4, "exps[ch][0]");
size_t nchgrps = 0;
if (!aud_chan_blk[Pos].chincpl)
aud_chan_blk[Pos].endmant = ((aud_chan_blk[Pos].chbwcod + 12) * 3) + 37;
else
aud_chan_blk[Pos].endmant = cplstrtmant;
if (aud_blks[blk].cplexpstr==0x01)
nchgrps = (aud_chan_blk[Pos].endmant - 1) / 3;
else if (aud_blks[blk].cplexpstr==0x02)
nchgrps = (aud_chan_blk[Pos].endmant - 1) / 3;
else if (aud_blks[blk].cplexpstr==0x03)
nchgrps = (aud_chan_blk[Pos].endmant - 1) / 3;
for (size_t grp = 1; grp <= nchgrps; grp++)
Skip_S1(7, "exps[ch][grp]");
Skip_S1(2, "gainrng[ch]");
}
}
if (lfeon)
{
if (aud_blks[blk].lfeexpstr!=0)
{
Skip_S1(4, "lfeexps[0]");
size_t nlfegrps = 2;
for (size_t grp = 1; grp <= nlfegrps; ++grp)
Skip_S1(7, "lfeexps[grp]");
}
}
int8u sdcycod = 0x2;
int8u fdcycod = 0x1;
int8u sgaincod = 0x1;
int8u dbpbcod = 0x2;
int8u floorcod = 0x7;
if (bamode)
{
bool baie = false;
Get_SB(baie, "baie");
if (baie)
{
Get_S1(2, sdcycod, "sdcycod");
Get_S1(2, fdcycod, "fdcycod");
Get_S1(2, sgaincod, "sgaincod");
Get_S1(2, dbpbcod, "dbpbcod");
Get_S1(3, floorcod, "floorcod");
}
}
if (snroffststr!=0x0)
{
bool snroffste = true;
if (blk!=0)
Get_SB (snroffste, "snroffste");
if (snroffste)
{
Skip_S1(6, "csnroffst");
if (snroffststr==0x1)
Skip_S1(4, "blkfsnroffst");
else if (snroffststr == 0x2)
{
if (aud_blks[blk].cplinu)
Skip_S1(4, "cplfsnroffst");
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
Skip_S1(4, "fsnroffst[ch]");
if (lfeon)
Skip_S1(4, "lfefsnroffst");
}
}
}
bool fgaincode = false;
if (frmfgaincode)
Get_SB(fgaincode, "fgaincode");
if (fgaincode)
{
if (aud_blks[blk].cplinu)
Skip_S1(3, "cplfgaincod");
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
Skip_S1(3, "fgaincod[ch]");
if (lfeon)
Skip_S1(3, "lfefgaincod");
}
if (strmtyp == 0x0)
{
TEST_SB_SKIP( "convsnroffste");
Skip_S2(10, "convsnroffst");
TEST_SB_END();
}
if (aud_blks[blk].cplinu)
{
bool cplleake = true;
if (firstcplleak)
firstcplleak = false;
else
Get_SB (cplleake, "cplleake");
if (cplleake)
{
Skip_S1(3, "cplfleak");
Skip_S1(3, "cplsleak");
}
}
if (dbaflde)
{
TEST_SB_SKIP( "deltbaie");
int8u cpldeltbae = 0;
if (aud_blks[blk].cplinu)
Get_S1 (2, cpldeltbae, "cpldeltbae");
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
Get_S1 (2, aud_chan_blk[Pos].deltbae, "deltbae[ch]");
if (aud_blks[blk].cplinu)
{
if (cpldeltbae==0x01)
{
int8u cpldeltnseg;
Get_S1 (3, cpldeltnseg, "cpldeltnseg");
for (int8u seg = 0; seg <= cpldeltnseg; ++seg)
{
Skip_S1(5, "cpldeltoffst[seg]");
Skip_S1(4, "cpldeltlen[seg]");
Skip_S1(3, "cpldeltba[seg]");
}
}
}
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
if (aud_chan_blk[Pos].deltbae==0x01)
{
int8u deltnseg;
Get_S1 (3, deltnseg, "deltnseg[ch]");
for (int8u seg = 0; seg <= deltnseg; ++seg)
{
Skip_S1(5, "deltoffst[ch][seg]");
Skip_S1(4, "deltlen[ch][seg]");
Skip_S1(3, "deltba[ch][seg]");
}
}
}
TEST_SB_END();
}
if (skipflde)
{
TEST_SB_SKIP( "skiple");
int16u skipl;
Get_S2 (9, skipl, "skipl");
Skip_BS(skipl * 8, "skipfld");
//TODO: EMDF();
TEST_SB_END();
}
bool got_cplchan = false;
size_t cplactivegaqbins = 0;
int8u lfegaqmod = 0;
int8u* lfegaqbin = NULL;
size_t lfeendmant = 7;
int8u cplgaqmod = 0;
lfegaqbin = new int8u[lfeendmant];
int8u *cplgaqbin = NULL;
cplgaqbin = new int8u[cplendmant];
for (size_t bin = 0; bin < lfeendmant; ++bin)
lfegaqbin[bin] = 0;
for (int8u Pos=0; Pos<AC3_Channels[acmod]; ++Pos)
{
if (!aud_chan_blk[Pos].chahtinu)
{
aud_chan_blk[Pos].endmant = ((aud_chan_blk[Pos].chbwcod + 12) * 3) + 37;
for (size_t bin = 0; bin < aud_chan_blk[Pos].endmant; ++bin)
{
//TODO
// chmant[ch][bin];
// (0-16);
}
}
else if (aud_chan_blk[Pos].chahtinu)
{
int8u chgaqmod = 0;
size_t chgaqsections = 0;
Get_S1 (2, chgaqmod, "chgaqmod[ch]");
switch (chgaqmod)
{
case 0:
{
chgaqsections = 0;
break;
}
case 1:
case 2:
{
chgaqsections = aud_chan_blk[Pos].chactivegaqbins;
break;
}
case 3:
{
chgaqsections = aud_chan_blk[Pos].chactivegaqbins / 3;
if (aud_chan_blk[Pos].chactivegaqbins % 3)
++chgaqsections;
break;
}
};
if (chgaqmod>0x0 && chgaqmod<0x3)
{
for (size_t n = 0; n < chgaqsections; ++n)
Skip_SB( "chgaqgain[ch][n]");
}
else if (chgaqmod==0x3)
{
for (size_t n = 0; n < chgaqsections; ++n)
Skip_S1(5, "chgaqgain[ch][n]");
}
aud_chan_blk[Pos].endmant = cplstrtmant;
int8u* chgaqbin = new int8u [aud_chan_blk[Pos].endmant];
if (aud_chan_blk[Pos].chahtinu == 0)
{
for (size_t i = 0; i < aud_chan_blk[Pos].endmant; ++i)
chgaqbin[i] = 0;
}
else
{
int8u endbap = 17;
if (chgaqmod < 2)
endbap = 12;
aud_chan_blk[Pos].chactivegaqbins = 0;
for (size_t i = 0; i < aud_chan_blk[Pos].endmant; ++i)
{
if (hebap[i] > 7 && hebap[i] < endbap)
{
chgaqbin[i] = 1;
++aud_chan_blk[Pos].chactivegaqbins;
}
else if (hebap[i] >= endbap)
chgaqbin[i] = -1;
else
chgaqbin[i] = 0;
}
}
for (size_t bin = 0; bin < aud_chan_blk[Pos].endmant; ++bin)
{
if (!cplahtinu)
{
for (size_t i = cplstrtmant; i < cplendmant; ++i)
cplgaqbin[i] = 0;
}
else
{
int8u endbap = 17;
if (cplgaqmod < 2)
endbap = 12;
cplactivegaqbins = 0;
}
if (chgaqbin[bin])
{
for (size_t n = 0; n < 6; n++)
{
//TODO
// {pre_chmant[n][ch][bin]} ...........................
// (0-16);
}
}
else
{
//TODO
// pre_chmant[0][ch][bin] .................................................;
// (0-9);
}
}
aud_chan_blk[Pos].chahtinu = -1;
}
if (aud_blks[blk].cplinu && aud_chan_blk[Pos].chincpl && !got_cplchan)
{
size_t ncplmant = 12 * ncplsubnd;
if (cplahtinu==0)
{
for (size_t bin = 0; bin < ncplmant; ++bin)
{
//TODO
// cplmant[bin] ...........................;
// (0-16);
}
got_cplchan = true;
}
else if (cplahtinu==1)
{
Get_S1 (2, cplgaqmod, "cplgaqmod");
if (lfeahtinu == 0)
{
for (size_t bin = 0; bin < lfeendmant; bin++)
lfegaqbin[bin] = 0;
}
else
{
int8u endbap = 17;
if (lfegaqmod<2)
endbap = 12;
for (size_t bin = 0; bin < lfeendmant; bin++)
{
if (hebap[bin] > 7 && hebap[bin] < endbap)
{
lfegaqbin[bin] = 1;
++lfeactivegaqbins;
}
else if (hebap[bin] >= endbap)
lfegaqbin[bin] = -1;
else
lfegaqbin[bin] = 0;
}
}
if (cplgaqmod>0x0 && cplgaqmod<0x3)
{
size_t cplgaqsections = cplactivegaqbins;
for (size_t n = 0; n < cplgaqsections; n++)
Skip_SB( "cplgaqgain[n]");
}
else if (cplgaqmod == 0x3)
{
size_t cplgaqsections = cplactivegaqbins / 3;
if (cplactivegaqbins % 3)
++cplgaqsections;
for (size_t n = 0; n < cplgaqsections; n++)
Skip_S1(5, "cplgaqgain[n]");
}
for (size_t bin = 0; bin < ncplmant; ++bin)
{
if (cplgaqbin[bin])
{
for (size_t n = 0; n < 6; ++n)
{
//TODO
// pre_cplmant[n][bin] ...........................;
// (0-16);
}
}
else
{
//TODO
// pre_cplmant[0][bin] .................................................;
// (0-9);
}
}
got_cplchan = true;
cplahtinu = -1;
}
else
got_cplchan = true;
}
}
if (lfeon)
{
int8u nlfemant = 7;
if (lfeahtinu == 0)
{
for (size_t bin = 0; bin < nlfemant; ++bin)
{
//TODO
// lfemant[bin]..............................;
// (0-16);
}
}
else if (lfeahtinu == 1)
{
size_t lfegaqsections = 0;
Get_S1 (2, lfegaqmod, "lfegaqmod");
if (lfeahtinu!=0)
{
size_t sumgaqbins = 0;
for (size_t bin = 0; bin < lfeendmant; bin++)
sumgaqbins += lfegaqbin[bin];
switch (lfegaqmod)
{
case 0:
{
lfegaqsections = 0;
break;
}
case 1:
case 2:
{
lfegaqsections = lfeactivegaqbins;
break;
}
case 3:
{
lfegaqsections = lfeactivegaqbins / 3;
if (lfeactivegaqbins % 3)
lfegaqsections++;
break;
}
};
}
if (lfegaqmod>0x0 && lfegaqmod<0x3)
{
for (size_t n = 0; n < lfegaqsections; ++n)
Skip_SB( "lfegaqgain[n]");
}
else if (lfegaqmod==0x3)
{
for (size_t n = 0; n < lfegaqsections; ++n)
Skip_S1(5, "lfegaqgain[n]");
}
for (size_t bin = 0; bin < nlfemant; ++bin)
{
if (lfegaqbin[bin])
{
for (size_t n = 0; n < 6; ++n)
{
//TODO
// pre_lfemant[n][bin] ..............................;
// (0-16);
}
}
else
{
//TODO
// pre_lfemant[0][bin] ....................................................;
// (0-9);
}
}
lfeahtinu = (int8u)-1;
}
}
Element_End0();
}
//*/
}
else
Skip_XX(Element_Size-Element_Offset, "Unknown");
if (bsid<=0x10)
{
size_t BitsAtEnd=18; //auxdatae+errorcheck
if (auxdatal!=(int16u)-1)
BitsAtEnd+=auxdatal+14; //auxbits+auxdatal
if (Data_BS_Remain()>=BitsAtEnd)
{
if (EMDF_RemainPos!=(size_t)-1 && BitsAtEnd<EMDF_RemainPos)
{
Skip_BS(Data_BS_Remain()-EMDF_RemainPos, bsid<=0x0A?"(Unparsed audblk(continue)+5*audblk+padding)":"(Unparsed bsi+6*audblk+padding)");
emdf();
Skip_BS(Data_BS_Remain()-BitsAtEnd, bsid<=0x0A?"(Unparsed audblk(continue)+5*audblk+padding)":"(Unparsed bsi+6*audblk+padding)");
}
else if (Data_BS_Remain()>BitsAtEnd)
Skip_BS(Data_BS_Remain()-BitsAtEnd, bsid<=0x0A?"(Unparsed audblk(continue)+5*audblk+padding)":"(Unparsed bsi+6*audblk+padding)");
Element_Begin1("auxdata");
if (auxdatal!=(int16u)-1)
{
Skip_BS(auxdatal, "auxbits");
Skip_S2(14, "auxdatal");
}
Skip_SB( "auxdatae");
Element_End0();
Element_Begin1("errorcheck");
Skip_SB( "encinfo");
BS_End();
Skip_B2( "crc2");
Element_End0();
}
else
BS_End();
if (Element_Offset<Element_Size)
Skip_XX(Element_Size-Element_Offset, "Unknown");
Element_Size=Element_Size_Save;
}
FILLING_BEGIN();
if (bsid>0x10)
return; //Not supported
Formats[bsid<=0x09?0:1]++;
// addbsi
if (!joc_num_objects_map.empty() && addbsie && addbsi_Buffer_Size >= 2 && (addbsi_Buffer[0]&0x01))
{
joc_complexity_index_Stream = addbsi_Buffer[1];
}
//Information
if (strmtyp>1)
strmtyp=0; //TODO: check a file with strmtyp==2
if (strmtyp==0)
substreamid_Independant_Current=substreamid;
if (bsid_Max==(int8u)-1 || bsid>bsid_Max)
bsid_Max=bsid;
//Specific to first frame
if (!frmsizplus1_Max[substreamid_Independant_Current][strmtyp+substreamid])
{
frmsizplus1_Max[substreamid_Independant_Current][strmtyp+substreamid]=((bsid<=0x09)?(frmsizecod/2<19?AC3_BitRate[frmsizecod/2]*4:0):((frmsiz+1)*2));
acmod_Max[substreamid_Independant_Current][strmtyp+substreamid]=acmod;
lfeon_Max[substreamid_Independant_Current][strmtyp+substreamid]=lfeon;
bsmod_Max[substreamid_Independant_Current][strmtyp+substreamid]=bsmod;
dsurmod_Max[substreamid_Independant_Current][strmtyp+substreamid]=dsurmod;
chanmape_Max[substreamid_Independant_Current][strmtyp+substreamid]=chanmape;
chanmap_Max[substreamid_Independant_Current][strmtyp+substreamid]=chanmap;
FirstFrame_Dolby.dialnorm=dialnorm;
if (compre)
FirstFrame_Dolby.compr=compr;
if (dynrnge)
FirstFrame_Dolby.dynrng=dynrng;
FirstFrame_Dolby.compre=compre;
FirstFrame_Dolby.dynrnge=dynrnge;
}
//Stats
if (dialnorms.empty())
dialnorms.resize(32);
if (dialnorm!=(int8u)-1)
dialnorms[dialnorm]++;
if (compre)
{
if (comprs.empty())
comprs.resize(256);
if (compr!=(int8u)-1)
comprs[compr]++;
}
if (dynrnge)
{
//Saving new value
dynrnge_Exists=true;
}
if (!dynrnge)
dynrng=0;
if (dynrngs.empty())
dynrngs.resize(256);
if (dynrng!=(int8u)-1)
dynrngs[dynrng]++;
FILLING_END();
}
//---------------------------------------------------------------------------
void File_Ac3::emdf()
{
//JOC reinit
joc_complexity_index_Stream=(int8u)-1;
num_dynamic_objects=(int8u)-1;
nonstd_bed_channel_assignment_mask=(int32u)-1;
Element_Begin1("emdf");
emdf_sync();
emdf_container();
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::emdf_sync()
{
int16u emdf_container_length;
Element_Begin1("emdf_sync");
Skip_S2(16, "syncword");
Get_S2 (16, emdf_container_length, "emdf_container_length");
Element_End0();
RemainAfterEMDF=Data_BS_Remain()-emdf_container_length*8; //emdf_container_length coherency was already tested in sync layer
}
//---------------------------------------------------------------------------
void File_Ac3::emdf_container()
{
size_t Start = Data_BS_Remain();
int32u version, key_id;
Element_Begin1("emdf_container");
Get_S4 (2, version, "emdf_version");
if (version == 3)
{
int32u add;
Get_V4(2, add, "emdf_version addition");
version += add;
}
if (version)
{
Skip_BS(Data_BS_Remain()-RemainAfterEMDF, "(Unparsed emdf_container data)");
Element_End0();
return;
}
Get_S4 (3, key_id, "key_id");
if (key_id == 7)
{
int32u add;
Get_V4 (3, add, "key_id addition");
key_id += add;
}
int32u emdf_payload_id = 0;
for(;;)
{
Element_Begin1("emdf_payload");
Get_S4 (5, emdf_payload_id, "emdf_payload_id");
if (emdf_payload_id==0x1F)
{
int32u add;
Get_V4 (5, add, "emdf_payload_id addition");
emdf_payload_id += add;
}
if (emdf_payload_id<16)
Element_Info1(Ac3_emdf_payload_id[emdf_payload_id]);
if (emdf_payload_id == 0x00)
{
Element_End0();
break;
}
emdf_payload_config();
int32u emdf_payload_size = 0;
Get_V4 (8, emdf_payload_size, "emdf_payload_size");
size_t emdf_payload_End=Data_BS_Remain()-emdf_payload_size*8; //emdf_payload_size coherency was already tested in sync layer
Element_Begin1("emdf_payload_bytes");
switch (emdf_payload_id)
{
case 11: object_audio_metadata_payload(); break;
case 14: joc(); break;
default: Skip_BS(emdf_payload_size*8, "(Unknown)");
}
size_t RemainginBits=Data_BS_Remain();
if (RemainginBits>=emdf_payload_End)
{
if (RemainginBits>emdf_payload_End)
Skip_BS(RemainginBits-emdf_payload_End, "(Unparsed bits)");
}
else
{
//There is a problem, too many bits were consumed by the parser. //TODO: prevent the parser to consume more bits than count of bits in this element
if (Data_BS_Remain() >= RemainAfterEMDF)
Skip_BS(Data_BS_Remain() - RemainAfterEMDF, "(Problem during emdf_payload parsing)");
else
Skip_BS(Data_BS_Remain(), "(Problem during emdf_payload parsing, going to end directly)");
Element_End0();
Element_End0();
break;
}
Element_End0();
Element_End0();
}
emdf_protection();
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::emdf_payload_config()
{
Element_Begin1("emdf_payload_config");
bool smploffste = false;
Get_SB (smploffste, "smploffste");
if (smploffste)
{
Skip_S2(11, "smploffst");
Skip_SB( "reserved");
}
TEST_SB_SKIP( "duratione");
Skip_V4(11, "duration");
TEST_SB_END();
TEST_SB_SKIP( "groupide");
Skip_V4(2, "groupid");
TEST_SB_END();
TEST_SB_SKIP( "codecdatae");
Skip_S1(8, "reserved");
TEST_SB_END();
bool discard_unknown_payload = false;
Get_SB(discard_unknown_payload, "discard_unknown_payload");
if (!discard_unknown_payload)
{
bool payload_frame_aligned = false;
if (!smploffste)
{
Get_SB (payload_frame_aligned, "payload_frame_aligned");
if (payload_frame_aligned)
{
Skip_SB( "create_duplicate");
Skip_SB( "remove_duplicate");
}
}
if (smploffste || payload_frame_aligned)
{
Skip_S1(5, "priority");
Skip_S1(2, "proc_allowed");
}
}
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::emdf_protection()
{
int8u len_primary = 0, len_second = 0;
Element_Begin1("emdf_protection");
Get_S1(2, len_primary, "protection_length_primary");
Get_S1(2, len_second, "protection_length_secondary");
switch (len_primary)
{
//case 0: break; //protection_length_primary coherency was already tested in sync layer
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_Ac3::object_audio_metadata_payload()
{
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");
num_dynamic_objects = object_count_bits + 1;
if (object_count_bits == 0x1F)
{
int8u object_count_bits_ext;
Get_S1 (7, object_count_bits_ext, "object_count_bits_ext");
num_dynamic_objects += object_count_bits_ext;
}
program_assignment();
//TODO: next
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::program_assignment()
{
Element_Begin1("program_assignment");
bool b_dyn_object_only_program = false;
Get_SB (b_dyn_object_only_program, "b_dyn_object_only_program");
if (b_dyn_object_only_program)
{
bool b_lfe_present;
Get_SB (b_lfe_present, "b_lfe_present");
if (b_lfe_present)
{
nonstd_bed_channel_assignment_mask=(1<<3);
if (num_dynamic_objects!=(int8u)-1)
num_dynamic_objects--;
}
}
else
{
int8u content_description_mask;
Get_S1 (4, content_description_mask, "content_description_mask");
if (content_description_mask & 0x1)
{
bool b_bed_object_chan_distribute, b_multiple_bed_instances_present;
Get_SB (b_bed_object_chan_distribute, "b_bed_object_chan_distribute");
Get_SB (b_multiple_bed_instances_present, "b_multiple_bed_instances_present");
int32u num_bed_instances = 1;
if (b_multiple_bed_instances_present)
{
int8u num_bed_instances_bits = 0;
Get_S1 (3, num_bed_instances_bits, "num_bed_instances_bits");
num_bed_instances = num_bed_instances_bits + 2;
}
for (int32u bed = 0; bed < num_bed_instances; ++bed)
{
Element_Begin1("Bed");
bool b_lfe_only = true;
Get_SB (b_lfe_only, "b_lfe_only");
if (!b_lfe_only)
{
bool b_standard_chan_assign;
Get_SB (b_standard_chan_assign, "b_standard_chan_assign");
if (b_standard_chan_assign)
{
int16u bed_channel_assignment_mask;
Get_S2 (10, bed_channel_assignment_mask, "bed_channel_assignment_mask");
nonstd_bed_channel_assignment_mask=AC3_bed_channel_assignment_mask_2_nonstd(bed_channel_assignment_mask);
}
else
Get_S3 (17, nonstd_bed_channel_assignment_mask, "nonstd_bed_channel_assignment_mask");
}
Element_End0();
}
}
if (content_description_mask & 0x2)
Skip_S1(3, "intermediate_spatial_format_idx");
if (content_description_mask & 0x4)
{
int8u num_dynamic_objects_bits;
Get_S1(5, num_dynamic_objects_bits, "num_dynamic_objects_bits");
if (num_dynamic_objects_bits == 0x1F)
{
int8u num_dynamic_objects_bits_ext = 0;
Get_S1 (7, num_dynamic_objects_bits_ext, "num_dynamic_objects_bits_ext");
num_dynamic_objects_bits += num_dynamic_objects_bits_ext;
}
num_dynamic_objects = num_dynamic_objects_bits + 1;
}
else
num_dynamic_objects = 0;
if (content_description_mask & 0x8)
{
int8u reserved_data_size_bits;
Get_S1 (4, reserved_data_size_bits, "reserved_data_size_bits");
int8u padding = 8 - (reserved_data_size_bits % 8);
Skip_S1(reserved_data_size_bits, "reserved_data()");
if (padding)
Skip_S1(padding, "padding");
}
}
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::joc()
{
Element_Begin1("joc");
joc_header();
joc_info();
joc_data();
if (joc_ext_config_idx > 0)
joc_ext_data();
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::joc_header()
{
Element_Begin1("joc_header");
Skip_S1(3, "joc_dmx_config_idx");
int8u joc_num_objects_bits = 0;
Get_S1 (6, joc_num_objects_bits, "joc_num_objects_bits");
joc_num_objects = joc_num_objects_bits + 1;
joc_num_objects_map[joc_num_objects] ++;
Get_S1 (3, joc_ext_config_idx, "joc_ext_config_idx");
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::joc_info()
{
Element_Begin1("joc_info");
int8u joc_clipgain_x_bits, joc_clipgain_y_bits;
int16u joc_seq_count_bits;
Get_S1 (3, joc_clipgain_x_bits, "joc_clipgain_x_bits");
Get_S1 (5, joc_clipgain_y_bits, "joc_clipgain_y_bits");
Get_S2 (10, joc_seq_count_bits, "joc_seq_count_bits");
for (int8u obj = 0; obj < joc_num_objects; obj++)
{
TEST_SB_SKIP("b_joc_obj_present[obj]");
//TODO
TEST_SB_END();
}
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::joc_data_point_info()
{
Element_Begin1("joc_data_point_info");
//TODO
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::joc_data()
{
Element_Begin1("joc_data");
//TODO
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::joc_ext_data()
{
Element_Begin1("joc_ext_data");
//TODO
Element_End0();
}
//---------------------------------------------------------------------------
void File_Ac3::HD()
{
//Parsing
int32u Synch;
Peek_B3(Synch);
if (Synch==0xF8726F)
{
if (Buffer_Offset+28>Buffer_Size)
{
Trusted_IsNot("Not enough data");
return; //Need more data
}
//Testing
/* Not working
int16u CRC_16_Table_HD[256];
CRC16_Init(CRC_16_Table_HD, 0x002D);
int16u CRC_16=0x0000;
const int8u* CRC_16_Buffer=Buffer+Buffer_Offset;
while(CRC_16_Buffer<Buffer+Buffer_Offset+24)
{
CRC_16=(CRC_16<<8) ^ CRC_16_Table_HD[(CRC_16>>8)^(*CRC_16_Buffer)];
CRC_16_Buffer++;
}
CRC_16^=LittleEndian2int16u(Buffer+Buffer_Offset+24);
*/
Element_Info1("major_sync");
Element_Begin1("major_sync_info");
int32u format_sync;
Get_B4(format_sync, "major_sync");
HD_StreamType=(int8u)format_sync; Param_Info1(AC3_HD_StreamType(HD_StreamType));
if ((HD_StreamType&0xFE)!=0xBA)
{
Skip_XX(Element_Size-Element_Offset, "Data");
return;
}
HD_format_info();
Skip_B2( "signature");
Get_B2 (HD_flags, "flags");
Skip_B2( "reserved");
BS_Begin();
Get_SB ( HD_IsVBR, "variable_rate");
Get_S2 (15, HD_BitRate_Max, "peak_data_rate"); Param_Info2((HD_BitRate_Max*(AC3_HD_SamplingRate(HD_SamplingRate2)?AC3_HD_SamplingRate(HD_SamplingRate2):AC3_HD_SamplingRate(HD_SamplingRate1))+8)>>4, " bps");
Get_S1 ( 4, HD_SubStreams_Count, "substreams");
Skip_S1( 2, "reserved");
Skip_S1( 2, "extended_substream_info");
if (HD_StreamType==0xBA)
{
Element_Begin1("substream_info");
Get_SB ( HD_HasAtmos, "16-channel presentation is present");
Skip_S1(3, "8-ch presentation");
Skip_S1(2, "6-ch presentation");
Skip_S1(2, "reserved");
Element_End0();
}
else
Skip_S1(8, "Unknown");
BS_End();
Element_Begin1("channel_meaning");
Skip_B1( "Unknown");
Skip_B1( "Unknown");
Skip_B1( "Unknown");
Skip_B1( "Unknown");
Skip_B1( "Unknown");
Skip_B1( "Unknown");
Skip_B1( "Unknown");
if (HD_StreamType==0xBA)
{
BS_Begin();
Skip_S1( 7, "Unknown");
bool HasExtend;
Get_SB ( HasExtend, "extra_channel_meaning_present");
BS_End();
if (HasExtend)
{
unsigned char Extend = 0;
unsigned char Unknown = 0;
bool HasContent = false;
BS_Begin();
Get_S1( 4, Extend, "extra_channel_meaning_length");
size_t After=(((size_t)Extend)+1)*16-4;
if (After>=Data_BS_Remain())
After=0;
else
After=Data_BS_Remain()-After;
if (HD_HasAtmos)
{
Element_Begin1("16ch_channel_meaning");
Skip_S1(5, "16ch_dialogue_norm");
Skip_S1(6, "16ch_mix_level");
Get_S1 (5, num_dynamic_objects, "16ch_channel_count");
num_dynamic_objects++;
program_assignment();
Element_End0();
}
size_t RemainginBits=Data_BS_Remain();
if (RemainginBits>After)
Skip_BS(RemainginBits-After, "(Unparsed bits)");
BS_End();
}
}
else
Skip_B1( "Unknown");
Element_End0();
Skip_B2( "major_sync_info_CRC");
Element_End0();
}
else if (!HD_MajorSync_Parsed)
{
return; // Wait for major sync
}
int64u PosBeforeDirectory=Element_Offset;
BS_Begin();
for (int8u i=0; i<HD_SubStreams_Count; i++)
{
Element_Begin1("substream_directory");
bool extra_substream_word, restart_nonexistent;
Get_SB (extra_substream_word, "extra_substream_word");
Get_SB (restart_nonexistent, "restart_nonexistent");
if ((!restart_nonexistent && Synch!=0xF8726F) || (restart_nonexistent && Synch==0xF8726F))
{
Element_End0();
return;
}
Skip_SB( "crc_present");
Skip_SB( "reserved");
Skip_S2(12, "substream_end_ptr");
if (extra_substream_word)
{
Skip_S2(9, "drc_gain_update");
Skip_S1(3, "drc_time_update");
Skip_S1(4, "reserved");
}
Element_End0();
}
BS_End();
FILLING_BEGIN();
//CRC compute
size_t Size=(size_t)(Element_Offset-PosBeforeDirectory);
int8u crc=0;
for (int8u i=0; i<4; i++)
{
int8u Value=Buffer[Buffer_Offset-4+i];
crc^=(Value&0xF);
Value>>=4;
crc^=Value;
}
for (int8u i=0; i<Size; i++)
{
int8u Value=Buffer[Buffer_Offset+(size_t)(Element_Offset-Size+i)];
crc^=(Value&0xF);
Value>>=4;
crc^=Value;
}
if (crc!=0xF)
{
return;
}
HD_MajorSync_Parsed=true;
if (HD_SubStreams_Count==1 && HD_StreamType==0xBB) //MLP with only 1 stream
{
HD_Resolution2=HD_Resolution1;
HD_SamplingRate2=HD_SamplingRate1;
}
FILLING_END();
/*
if (HD_MajorSync_Parsed)
{
Element_Begin1("Sizes");
std::vector<int16u> Sizes;
for (int8u Pos=0; Pos<HD_SubStreams_Count; Pos++)
{
Element_Begin1("Size");
int16u Size;
bool HD_Unknown1_Present, HD_NoRestart, HD_ExtraParity;
BS_Begin();
Get_SB ( HD_Unknown1_Present, "Unknown present"); //Only TrueHD
Get_SB ( HD_NoRestart, "No restart"); //Not present if MajorSync, present if no MajorSync
Get_SB ( HD_ExtraParity, "Extra parity information");
Skip_SB( "Unknown");
Get_S2 (12, Size, "Size");
BS_End();
if (HD_Unknown1_Present)
Skip_B2( "Unknown");
Sizes.push_back(Size);
Element_End0();
}
Element_End0();
int64u Element_Offset_Begin=Element_Offset;
for (int8u Pos=0; Pos<HD_SubStreams_Count; Pos++)
{
Element_Begin1("Block");
bool DecodingParameterBlockPresent;
BS_Begin();
Get_SB (DecodingParameterBlockPresent, "Decoding parameter block is present");
if (DecodingParameterBlockPresent)
{
TEST_SB_SKIP( "Restart header");
int16u SyncWord;
int8u max_matrix_channel;
Get_S2(13, SyncWord, "SyncWord");
if (SyncWord==0x18F5)
{
Skip_SB( "noise_type"); //Only for TrueHD
Skip_S2(16, "Output timestamp");
Skip_S1( 4, "min_channel");
Skip_S1( 4, "max_channel");
Get_S1 ( 4, max_matrix_channel, "max_matrix_channel");
Skip_S1( 4, "noise_shift");
Skip_S3(23, "noisegen_seed");
Skip_S3(19, "unknown");
Skip_SB( "data_check_present");
Skip_S1( 8, "lossless_check");
Skip_S2(16, "unknown");
for (int8u matrix_channel=0; matrix_channel<max_matrix_channel; matrix_channel++)
Skip_S1(6, "ch_assign");
Skip_S1( 8, "checksum");
}
TEST_SB_END();
}
BS_End();
Skip_XX(Element_Offset_Begin+Sizes[Pos]*2-Element_Offset, "Data");
Element_End0();
}
}
else
Skip_XX(Element_Size-Element_Offset, "Waiting for MajorSync...");
*/
Skip_XX(Element_Size-Element_Offset, "(Data)");
FILLING_BEGIN_PRECISE();
if (Frame_Count==0)
PTS_Begin=FrameInfo.PTS;
Frame_Count++;
Frame_Count_InThisBlock++;
if (Frame_Count_NotParsedIncluded!=(int64u)-1)
Frame_Count_NotParsedIncluded++;
FrameInfo.DUR=833333;
int64u HD_SamplingRate=AC3_HD_SamplingRate(HD_SamplingRate1);
if (HD_SamplingRate && HD_SamplingRate!=48000)
{
FrameInfo.DUR*=48000;
FrameInfo.DUR/=HD_SamplingRate;
}
if (FrameInfo.DTS!=(int64u)-1)
FrameInfo.DTS+=FrameInfo.DUR;
if (FrameInfo.PTS!=(int64u)-1)
FrameInfo.PTS+=FrameInfo.DUR;
//Filling
if (!Status[IsAccepted])
{
Accept("AC-3");
if (Frame_Count_Valid>1 && Frame_Count_Valid<10000)
Frame_Count_Valid*=32;
}
if (!Status[IsFilled] && !Core_IsPresent && Frame_Count>=Frame_Count_Valid)
{
Fill("AC-3");
//No more need data
if (!IsSub && Config->ParseSpeed<1.0)
Finish("AC-3");
}
FILLING_END();
}
void File_Ac3::HD_format_info()
{
if (HD_StreamType==0xBA)
{
Element_Begin1("format_info");
BS_Begin();
Get_S1 ( 4, HD_SamplingRate1, "audio_sampling_frequency"); Param_Info2(AC3_HD_SamplingRate(HD_SamplingRate1), " Hz");
Skip_SB( "6ch_multichannel_type");
Skip_SB( "8ch_multichannel_typ");
Skip_S1( 2, "reserved");
Skip_S1( 2, "2ch_presentation_channel_modifier");
Skip_S1( 2, "6ch_presentation_channel_modifier");
Get_S1 ( 5, HD_Channels1, "6ch_presentation_channel_assignment"); Param_Info1(AC3_TrueHD_Channels(HD_Channels1)); Param_Info1(Ztring().From_UTF8(AC3_TrueHD_Channels_Positions(HD_Channels1)));
Skip_S1( 2, "8ch_presentation_channel_modifier");
Get_S2 (13, HD_Channels2, "8ch_presentation_channel_assignment"); Param_Info1(AC3_TrueHD_Channels(HD_Channels2)); Param_Info1(Ztring().From_UTF8(AC3_TrueHD_Channels_Positions(HD_Channels2)));
BS_End();
HD_Resolution2=HD_Resolution1=24; //Not sure
HD_SamplingRate2=HD_SamplingRate1;
Element_End0();
}
if (HD_StreamType==0xBB)
{
BS_Begin();
Get_S1 ( 4, HD_Resolution1, "Resolution1"); Param_Info2(AC3_MLP_Resolution[HD_Resolution1], " bits");
Get_S1 ( 4, HD_Resolution2, "Resolution2"); Param_Info2(AC3_MLP_Resolution[HD_Resolution2], " bits");
Get_S1 ( 4, HD_SamplingRate1, "Sampling rate"); Param_Info2(AC3_HD_SamplingRate(HD_SamplingRate1), " Hz");
Get_S1 ( 4, HD_SamplingRate2, "Sampling rate"); Param_Info2(AC3_HD_SamplingRate(HD_SamplingRate2), " Hz");
Skip_S1(11, "Unknown");
Get_S1 ( 5, HD_Channels1, "Channels"); Param_Info1(AC3_MLP_Channels[HD_Channels1]);
BS_End();
HD_Channels2=HD_Channels1;
}
}
//---------------------------------------------------------------------------
void File_Ac3::TimeStamp()
{
// Format looks like a Sync word 0x0110 then SMPTE ST 339 Time stamp
//Parsing
int16u SampleNumber;
int8u H1, H2, M1, M2, S1, S2, F1, F2, FrameRate;
bool DropFrame;
Skip_B2( "Sync word");
BS_Begin();
Skip_S2(10, "H");
Get_S1 ( 2, H1, "H");
Get_S1 ( 4, H2, "H");
Skip_S2( 9, "M");
Get_S1 ( 3, M1, "M");
Get_S1 ( 4, M2, "M");
Skip_S2( 9, "S");
Get_S1 ( 3, S1, "S");
Get_S1 ( 4, S2, "S");
Skip_S2( 9, "F");
Get_SB ( DropFrame, "Drop frame");
Get_S1 ( 2, F1, "F");
Get_S1 ( 4, F2, "F");
Get_S2 (16, SampleNumber, "Sample number");
Skip_S2( 9, "Unknown");
Skip_SB( "Status");
Get_S1 ( 4, FrameRate, "Frame rate"); Param_Info1(Mpegv_frame_rate[FrameRate]);
Skip_SB( "Status");
Skip_SB( "Drop frame");
BS_End();
Skip_B2( "User private");
FILLING_BEGIN();
TimeCode Temp(H1*10+H2, M1*10+M2, S1*10+S2, F1*10+F2, (int8u)float64_int64s(Mpegv_frame_rate[FrameRate]), DropFrame);
if (float64_int64s(Mpegv_frame_rate[FrameRate])!=Mpegv_frame_rate[FrameRate])
Temp.FramesPerSecond_Is1001=true;
Temp.MoreSamples=SampleNumber;
#ifdef MEDIAINFO_TRACE
Element_Info1(Temp.ToString());
#endif //MEDIAINFO_TRACE
if (TimeStamp_Count==0)
{
TimeStamp_FirstFrame=Temp;
}
TimeStamp_IsParsing=false;
TimeStamp_Parsed=true;
TimeStamp_Count++;
FILLING_END();
}
//---------------------------------------------------------------------------
void File_Ac3::dac3()
{
BS_Begin();
Get_S1 (2, fscod, "fscod");
Get_S1 (5, bsid, "bsid");
Get_S1 (3, bsmod_Max[0][0], "bsmod");
Get_S1 (3, acmod_Max[0][0], "acmod");
Get_SB ( lfeon_Max[0][0], "lfeon");
Get_S1 (5, frmsizecod, "bit_rate_code"); frmsizecod*=2;
Skip_S1(5, "reserved");
BS_End();
MustParse_dac3=false;
dxc3_Parsed=true;
}
//---------------------------------------------------------------------------
void File_Ac3::dec3()
{
//Parsing
BS_Begin();
int8u num_ind_sub;
Skip_S2(13, "data_rate");
Get_S1 ( 3, num_ind_sub, "num_ind_sub");
for (int8u Pos=0; Pos<=num_ind_sub; Pos++)
{
Element_Begin1("independent substream");
int8u num_dep_sub;
Get_S1 (2, fscod, "fscod");
Get_S1 (5, bsid, "bsid");
Skip_SB( "reserved");
Skip_SB( "asvc");
Get_S1 (3, bsmod_Max[Pos][0], "bsmod");
Get_S1 (3, acmod_Max[Pos][0], "acmod");
Get_SB ( lfeon_Max[Pos][0], "lfeon");
Skip_S1(3, "reserved");
Get_S1 (4, num_dep_sub, "num_dep_sub");
if (num_dep_sub>0)
Skip_S2(9, "chan_loc");
else
Skip_SB( "reserved");
Element_End0();
}
if (Data_BS_Remain())
{
Skip_S1( 7, "reserved");
TEST_SB_SKIP( "flag_ec3_extension_type_joc");
Get_S1 ( 8, joc_complexity_index_Container, "joc_complexity_index");
TEST_SB_END();
}
BS_End();
if (Element_Offset<Element_Size)
Skip_XX(Element_Size-Element_Offset, "reserved");
MustParse_dec3=false;
dxc3_Parsed=true;
}
//---------------------------------------------------------------------------
void File_Ac3::dmlp()
{
//Parsing
HD_StreamType=0xBA;
HD_format_info();
BS_Begin();
Get_S2 (15, HD_BitRate_Max, "peak_data_rate"); Param_Info2((HD_BitRate_Max*(AC3_HD_SamplingRate(HD_SamplingRate2)?AC3_HD_SamplingRate(HD_SamplingRate2):AC3_HD_SamplingRate(HD_SamplingRate1))+8)>>4, " bps");
Skip_S8(33, "reserved");
BS_End();
if (Element_Offset<Element_Size)
Skip_XX(Element_Size-Element_Offset, "unknown");
FILLING_BEGIN()
//Configure
MustParse_dmlp=false;
MustSynchronize=true;
Frame_Count_Valid=1;
FILLING_ELSE()
Reject();
FILLING_END()
}
//---------------------------------------------------------------------------
bool File_Ac3::FrameSynchPoint_Test()
{
if (Save_Buffer)
return true; //Test already made by Synchronize()
if (Buffer[Buffer_Offset ]==0x0B
&& Buffer[Buffer_Offset+1]==0x77) //AC-3
{
bsid=CC1(Buffer+Buffer_Offset+5)>>3;
int16u Size=0;
if (bsid<=0x09)
{
int8u fscod =(CC1(Buffer+Buffer_Offset+4)>>6)&0x03;
int8u frmsizecod=(CC1(Buffer+Buffer_Offset+4) )&0x3F;
Size=AC3_FrameSize_Get(frmsizecod, fscod);
}
else if (bsid>0x0A && bsid<=0x10)
{
int16u frmsiz=CC2(Buffer+Buffer_Offset+2)&0x07FF;
Size=2+frmsiz*2;
}
if (Size>=6)
{
if (Buffer_Offset+Size>Buffer_Size)
return false; //Need more data
if (CRC_Compute(Size))
{
Synched=true;
return true;
}
}
}
if (Buffer[Buffer_Offset+0]==0x77
&& Buffer[Buffer_Offset+1]==0x0B) //AC-3 LE
{
bsid=CC1(Buffer+Buffer_Offset+4)>>3;
int16u Size=0;
if (bsid<=0x09)
{
int8u fscod =(CC1(Buffer+Buffer_Offset+5)>>6)&0x03;
int8u frmsizecod=(CC1(Buffer+Buffer_Offset+5) )&0x3F;
Size=AC3_FrameSize_Get(frmsizecod, fscod);
}
else if (bsid>0x0A && bsid<=0x10)
{
int16u frmsiz=LittleEndian2int16u(Buffer+Buffer_Offset+2)&0x07FF;
Size=2+frmsiz*2;
//TODO: case with multiple substreams
}
if (Size>=6)
{
size_t Size_Total=Core_Size_Get();
if (Element_IsWaitingForMoreData())
return false; //Need more data
Save_Buffer=Buffer;
Save_Buffer_Offset=Buffer_Offset;
Save_Buffer_Size=Buffer_Size;
{
int8u* Buffer_Little=new int8u[Size_Total];
for (size_t Pos=0; Pos+1<Size_Total; Pos+=2)
{
Buffer_Little[Pos+1]=Save_Buffer[Buffer_Offset+Pos ];
Buffer_Little[Pos ]=Save_Buffer[Buffer_Offset+Pos+1];
}
Buffer=Buffer_Little;
Buffer_Offset=0;
Buffer_Size=Size_Total;
Synched=CRC_Compute(Size);
if (Synched)
{
BigEndian=false;
swap(Buffer, Save_Buffer);
swap(Buffer_Offset, Save_Buffer_Offset);
swap(Buffer_Size, Save_Buffer_Size);
return true;
}
delete[] Buffer_Little;
}
Buffer=Save_Buffer; Save_Buffer=NULL;
Buffer_Offset=Save_Buffer_Offset;
Buffer_Size=Save_Buffer_Size;
}
}
if (HD_MajorSync_Parsed
|| (Buffer[Buffer_Offset+4]==0xF8
&& Buffer[Buffer_Offset+5]==0x72
&& Buffer[Buffer_Offset+6]==0x6F
&& (Buffer[Buffer_Offset+7]&0xFE)==0xBA)) //TrueHD or MLP
{
HD_IsPresent=true;
Synched=true;
return true;
}
Synched=false;
return true;
}
//---------------------------------------------------------------------------
bool File_Ac3::CRC_Compute(size_t Size)
{
//Config
if (!IgnoreCrc_Done)
{
IgnoreCrc=Config->File_Ac3_IgnoreCrc_Get();
IgnoreCrc_Done=true;
}
if (IgnoreCrc && !Status[IsAccepted]) //Else there are some wrong synchronizations
{
MediaInfo_Internal MI;
Ztring ParseSpeed_Save=MI.Option(__T("ParseSpeed_Get"), __T(""));
Ztring Demux_Save=MI.Option(__T("Demux_Get"), __T(""));
MI.Option(__T("ParseSpeed"), __T("0"));
MI.Option(__T("Demux"), Ztring());
size_t MiOpenResult=MI.Open(File_Name);
MI.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value
MI.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value
if (MiOpenResult)
{
Ztring Format=MI.Get(Stream_General, 0, General_Format);
if (Format!=__T("AC-3") && Format!=__T("E-AC-3"))
IgnoreCrc=false;
}
else
IgnoreCrc=false; // Problem
}
if (IgnoreCrc)
return true;
int16u CRC_16=0x0000;
const int8u* CRC_16_Buffer=Buffer+Buffer_Offset+2; //After syncword
const int8u* CRC_16_Buffer_5_8=Buffer+Buffer_Offset+(((Size>>2)+(Size>>4))<<1); //Magic formula to meet 5/8 frame size from Dolby
const int8u* CRC_16_Buffer_EndMinus3=Buffer+Buffer_Offset+Size-3; //End of frame minus 3
const int8u* CRC_16_Buffer_End=Buffer+Buffer_Offset+Size; //End of frame
while(CRC_16_Buffer<CRC_16_Buffer_End)
{
CRC_16=(CRC_16<<8) ^ CRC_16_Table[(CRC_16>>8)^(*CRC_16_Buffer)];
//CRC bytes inversion
if (CRC_16_Buffer==CRC_16_Buffer_EndMinus3 && bsid<=0x09 && ((*CRC_16_Buffer)&0x01)) //CRC inversion bit
{
CRC_16_Buffer++;
CRC_16=(CRC_16<<8) ^ CRC_16_Table[(CRC_16>>8)^((int8u)(~(*CRC_16_Buffer)))];
CRC_16_Buffer++;
CRC_16=(CRC_16<<8) ^ CRC_16_Table[(CRC_16>>8)^((int8u)(~(*CRC_16_Buffer)))];
}
CRC_16_Buffer++;
//5/8 intermediate test
if (CRC_16_Buffer==CRC_16_Buffer_5_8 && bsid<=0x09 && CRC_16!=0x0000)
break;
}
return (CRC_16==0x0000);
}
//---------------------------------------------------------------------------
size_t File_Ac3::Core_Size_Get()
{
bool IsLE=(Buffer[Buffer_Offset+0]==0x77);
int16u Size=1;
bsid=(Buffer[(size_t)(Buffer_Offset+5-IsLE)]&0xF8)>>3;
if (bsid<=0x09)
{
fscod =(Buffer[(size_t)(Buffer_Offset+4+IsLE)]&0xC0)>>6;
frmsizecod= Buffer[(size_t)(Buffer_Offset+4+IsLE)]&0x3F;
//Filling
fscods[fscod]++;
frmsizecods[frmsizecod]++;
Size=AC3_FrameSize_Get(frmsizecod, fscod);
}
else if (bsid>0x0A && bsid<=0x10)
{
int16u frmsiz =((int16u)(Buffer[(size_t)(Buffer_Offset+2+IsLE)]&0x07)<<8)
| ( Buffer[(size_t)(Buffer_Offset+3-IsLE)] );
//Filling
Size=2+frmsiz*2;
}
substreams_Count=0;
int8u substreams_Count_Independant=0;
int8u substreams_Count_Dependant=0;
for (;;)
{
if (Buffer_Offset+Size+6>Buffer_Size)
{
if (!IsSub && !Save_Buffer && File_Offset+Buffer_Offset+Size<File_Size)
Element_WaitForMoreData();
break;
}
int8u bsid=Buffer[Buffer_Offset+Size+5-IsLE]>>3;
if (bsid<=0x09 || bsid>0x10)
break; //Not E-AC-3
int8u substreamid=(Buffer[Buffer_Offset+Size+2+IsLE]>>3)&0x07;
if (substreamid!=substreams_Count_Independant)
break; //Problem
if (substreamid!=substreams_Count_Dependant)
break; //Problem
int8u strmtyp = Buffer[Buffer_Offset+Size+2+IsLE]>>6;
if (substreamid==0 && strmtyp==0)
break; //Next block
int16u frmsiz =((int16u)(Buffer[(size_t)(Buffer_Offset+Size+2+IsLE)]&0x07)<<8)
| ( Buffer[(size_t)(Buffer_Offset+Size+3-IsLE)] );
//Filling
Size+=2+frmsiz*2;
if (strmtyp == 0)
{
substreams_Count_Independant++;
substreams_Count_Dependant=0;
}
else
substreams_Count_Dependant++;
substreams_Count++;
}
return Size;
}
//---------------------------------------------------------------------------
size_t File_Ac3::HD_Size_Get()
{
size_t Size=BigEndian2int16u(Buffer+Buffer_Offset)&0x0FFF;
Size*=2;
return Size;
}
//---------------------------------------------------------------------------
void File_Ac3::Get_V4(int8u Bits, int32u &Info, const char* Name)
{
Info = 0;
#if MEDIAINFO_TRACE
int8u Count = 0;
#endif //MEDIAINFO_TRACE
for (;;)
{
Info += BS->Get4(Bits);
#if MEDIAINFO_TRACE
Count += Bits;
#endif //MEDIAINFO_TRACE
if (!BS->GetB())
break;
Info <<= Bits;
Info += (1 << Bits);
}
#if MEDIAINFO_TRACE
if (Trace_Activated)
{
Param(Name, Info, Count);
Param_Info(__T("(") + Ztring::ToZtring(Count) + __T(" bits)"));
}
#endif //MEDIAINFO_TRACE
}
//---------------------------------------------------------------------------
void File_Ac3::Skip_V4(int8u Bits, const char* Name)
{
#if MEDIAINFO_TRACE
if (Trace_Activated)
{
int32u Info = 0;
Get_V4(Bits, Info, Name);
}
else
#endif //MEDIAINFO_TRACE
{
do
BS->Skip(Bits);
while (BS->GetB());
}
}
} //NameSpace
#endif //MEDIAINFO_AC3_YES
↑ V640 The code's operational logic does not correspond with its formatting. The second statement will always be executed. It is possible that curly brackets are missing.
↑ V1020 The function exited without calling the 'BS_End' function. Check lines: 3759, 2267.
↑ V1020 The function exited without calling the 'BS_End' function. Check lines: 3759, 2408.
↑ V1020 The function exited without calling the 'BS_End' function. Check lines: 3820, 2267.
↑ V1020 The function exited without calling the 'BS_End' function. Check lines: 3820, 2408.
↑ V1020 The function exited without calling the 'Element_End' function. Check lines: 4238, 4230.
↑ V1020 The function exited without calling the 'BS_End' function. Check lines: 4327, 4317.
↑ V1048 The 'protection_bits_secondary' variable was assigned the same value.
↑ V1048 The 'TimeStamp_Parsed' variable was assigned the same value.
↑ V547 Expression 'HD_SamplingRate < 44100' is always false.
↑ V547 Expression 'Synched' is always true.
↑ V547 Expression 'padding' is always true.
↑ V560 A part of conditional expression is always true: BitRate > 0.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: Save_Buffer_Offset, Save_Buffer_Size, EMDF_RemainPos, RemainAfterEMDF, joc_num_objects, joc_ext_config_idx, ...
↑ V525 The code contains the collection of similar blocks. Check items '1', '1', '3' in lines 2478, 2479, 2480.
↑ V525 The code contains the collection of similar blocks. Check items 'Get_S1_', 'Get_S1_', 'Get_S2_' in lines 4164, 4165, 4166.
↑ V525 The code contains the collection of similar blocks. Check items 'Skip_S2_', 'Skip_S1_', 'Skip_S1_' in lines 4334, 4335, 4336.
↑ V550 An odd precise comparison. It's probably better to use a comparison with defined precision: fabs(FrameDuration) > Epsilon.
↑ V550 An odd precise comparison. It's probably better to use a comparison with defined precision: fabs(FrameDuration) > Epsilon.
↑ V550 An odd precise comparison. It's probably better to use a comparison with defined precision: fabs(A - B) > Epsilon.
↑ V688 The 'b_lfe_present' local variable possesses the same name as one of the class members, which can result in a confusion.
↑ V688 The 'fscod' local variable possesses the same name as one of the class members, which can result in a confusion.
↑ V688 The 'frmsizecod' local variable possesses the same name as one of the class members, which can result in a confusion.
↑ V688 The 'fscod' local variable possesses the same name as one of the class members, which can result in a confusion.
↑ V688 The 'frmsizecod' local variable possesses the same name as one of the class members, which can result in a confusion.
↑ V688 The 'bsid' local variable possesses the same name as one of the class members, which can result in a confusion.