/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license that can
* be found in the License.html file in the root of the source tree.
*/
//---------------------------------------------------------------------------
// https://developer.dolby.com/globalassets/professional/dolby-e/dolby-e-high-level-frame-description.pdf
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Pre-compilation
#include "MediaInfo/PreComp.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "MediaInfo/Setup.h"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#if defined(MEDIAINFO_DOLBYE_YES)
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "MediaInfo/Audio/File_DolbyE.h"
#include "MediaInfo/Audio/File_Aac.h"
#include <cmath>
#if !defined(INT8_MAX)
#define INT8_MAX (127)
#endif //!defined(INT8_MAX)
#if !defined(INT8_MIN)
#define INT8_MIN (-128)
#endif //!defined(INT8_MIN)
using namespace std;
//---------------------------------------------------------------------------
namespace MediaInfoLib
{
//---------------------------------------------------------------------------
//CRC computing, with incomplete first and last bytes
//Inspired by http://zorc.breitbandkatze.de/crc.html
extern const int16u CRC_16_Table[256];
int16u CRC_16_Compute(const int8u* Buffer_Begin, size_t Buffer_Size, int8u SkipBits_Begin, int8u SkipBits_End)
{
int16u CRC_16=0x0000;
const int8u* Buffer=Buffer_Begin;
const int8u* Buffer_End=Buffer+Buffer_Size;
if (SkipBits_End)
Buffer_End--; //Not handling completely the last byte
//First partial byte
if (SkipBits_Begin)
{
for (int8u Mask=(1<<(7-SkipBits_Begin)); Mask; Mask>>=1)
{
bool NewBit=(CRC_16&0x8000)?true:false;
CRC_16<<=1;
if ((*Buffer)&Mask)
NewBit=!NewBit;
if (NewBit)
CRC_16^=0x8005;
}
Buffer++;
}
//Complete bytes
while (Buffer<Buffer_End)
{
CRC_16=(CRC_16<<8) ^ CRC_16_Table[(CRC_16>>8)^(*Buffer)];
Buffer++;
}
//Last partial byte
if (SkipBits_End)
{
for (int8u Mask=0x80; Mask>(1<<(SkipBits_End-1)); Mask>>=1)
{
bool NewBit=(CRC_16&0x8000)?true:false;
CRC_16<<=1;
if ((*Buffer)&Mask)
NewBit=!NewBit;
if (NewBit)
CRC_16^=0x8005;
}
Buffer++;
}
return CRC_16;
}
//***************************************************************************
// Infos
//***************************************************************************
//---------------------------------------------------------------------------
static const int8u DolbyE_Programs[64]=
{2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 8, 1, 2, 3, 3, 4, 5, 6, 1, 2, 3, 4, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
//---------------------------------------------------------------------------
static const int8u DolbyE_Channels[64]=
{8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
//---------------------------------------------------------------------------
const int8u DolbyE_Channels_PerProgram(int8u program_config, int8u program)
{
switch (program_config)
{
case 0 : switch (program)
{
case 0 : return 6;
default : return 2;
}
case 1 : switch (program)
{
case 0 : return 6;
default : return 1;
}
case 2 :
case 18 : return 4;
case 3 :
case 12 : switch (program)
{
case 0 : return 4;
default : return 2;
}
case 4 : switch (program)
{
case 0 : return 4;
case 1 : return 2;
default : return 1;
}
case 5 :
case 13 : switch (program)
{
case 0 : return 4;
default : return 1;
}
case 6 :
case 14 :
case 19 : return 2;
case 7 : switch (program)
{
case 0 :
case 1 :
case 2 : return 2;
default : return 1;
}
case 8 :
case 15 : switch (program)
{
case 0 :
case 1 : return 2;
default : return 1;
}
case 9 :
case 16 :
case 20 : switch (program)
{
case 0 : return 2;
default : return 1;
}
case 10 :
case 17 :
case 21 : return 1;
case 11 : return 6;
case 22 : return 8;
case 23 : return 8;
default : return 0;
}
};
//---------------------------------------------------------------------------
const char* DolbyE_ChannelPositions[64]=
{
"Front: L C R, Side: L R, LFE / Front: L R",
"Front: L C R, Side: L R, LFE / Front: C / Front: C",
"Front: L C R, LFE / Front: L C R, LFE",
"Front: L C R, LFE / Front: L R / Front: L R",
"Front: L C R, LFE / Front: L R / Front: C / Front: C",
"Front: L C R, LFE / Front: C / Front: C / Front: C / Front: C",
"Front: L R / Front: L R / Front: L R / Front: L R",
"Front: L R / Front: L R / Front: L R / Front: C / Front: C",
"Front: L R / Front: L R / Front: C / Front: C / Front: C / Front: C",
"Front: L R / Front: C / Front: C / Front: C / Front: C / Front: C / Front: C",
"Front: C / Front: C / Front: C / Front: C / Front: C / Front: C / Front: C / Front: C",
"Front: L C R, Side: L R, LFE",
"Front: L C R, LFE / Front: L R",
"Front: L C R, LFE / Front: C / Front: C",
"Front: L R / Front: L R / Front: L R",
"Front: L R / Front: L R / Front: C / Front: C",
"Front: L R / Front: C / Front: C / Front: C / Front: C",
"Front: C / Front: C / Front: C / Front: C / Front: C / Front: C",
"Front: L C R, LFE",
"Front: L R / Front: L R",
"Front: L R / Front: C / Front: C",
"Front: C / Front: C / Front: C / Front: C",
"Front: L C R, Side: L R, Rear: L R, LFE",
"Front: L C C C R, Side: L R, LFE",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
};
//---------------------------------------------------------------------------
const char* DolbyE_ChannelPositions_PerProgram(int8u program_config, int8u program)
{
switch (program_config)
{
case 0 : switch (program)
{
case 0 : return "Front: L C R, Side: L R, LFE";
default : return "Front: L R";
}
case 1 : switch (program)
{
case 0 : return "Front: L C R, Side: L R, LFE";
default : return "Front: C";
}
case 2 :
case 18 : return "Front: L C R, LFE";
case 3 :
case 12 : switch (program)
{
case 0 : return "Front: L C R, LFE";
default : return "Front: L R";
}
case 4 : switch (program)
{
case 0 : return "Front: L C R, LFE";
case 1 : return "Front: L R";
default : return "Front: C";
}
case 5 :
case 13 : switch (program)
{
case 0 : return "Front: L C R, LFE";
default : return "Front: C";
}
case 6 :
case 14 :
case 19 : return "Front: L R";
case 7 : switch (program)
{
case 0 :
case 1 :
case 2 : return "Front: L R";
default : return "Front: C";
}
case 8 :
case 15 : switch (program)
{
case 0 :
case 1 : return "Front: L R";
default : return "Front: C";
}
case 9 :
case 16 :
case 20 : switch (program)
{
case 0 : return "Front: L R";
default : return "Front: C";
}
case 10 :
case 17 :
case 21 : return "Front: C";
case 11 : return "Front: L C R, Side: L R, LFE";
case 22 : return "Front: L C R, Side: L R, Rear: L R, LFE";
case 23 : return "Front: L C C C R, Side: L R, LFE";
default : return "";
}
};
//---------------------------------------------------------------------------
const char* DolbyE_ChannelPositions2[64]=
{
"3/2/0.1 / 2/0/0",
"3/2/0.1 / 1/0/0 / 1/0/0",
"3/0/0.1 / 3/0/0.1",
"3/0/0.1 / 2/0/0 / 2/0/0",
"3/0/0.1 / 2/0/0 / 1/0/0 / 1/0/0",
"3/0/0.1 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0",
"2/0/0 / 2/0/0 / 2/0/0 / 2/0/0",
"2/0/0 / 2/0/0 / 2/0/0 / 1/0/0 / 1/0/0",
"2/0/0 / 2/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0",
"2/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0",
"1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0",
"3/2/0.1",
"3/0/0.1 / 2/0/0",
"3/0/0.1 / 1/0/0 / 1/0/0",
"2/0/0 / 2/0/0 / 2/0/0",
"2/0/0 / 2/0/0 / 1/0/0 / 1/0/0",
"2/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0",
"1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0 / 1/0/0",
"3/0/0.1",
"2/0/0 / 2/0/0",
"2/0/0 / 1/0/0 / 1/0/0",
"1/0/0 / 1/0/0 / 1/0/0 / 1/0/0",
"3/2/2.1",
"5/2/0.1",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
};
//---------------------------------------------------------------------------
const char* DolbyE_ChannelPositions2_PerProgram(int8u program_config, int8u program)
{
switch (program_config)
{
case 0 : switch (program)
{
case 0 : return "3/2/0.1";
default : return "2/0/0";
}
case 1 : switch (program)
{
case 0 : return "3/2/0.1";
default : return "1/0/0";
}
case 2 :
case 18 : return "3/0/0.1";
case 3 :
case 12 : switch (program)
{
case 0 : return "3/0/0.1";
default : return "2/0/0";
}
case 4 : switch (program)
{
case 0 : return "3/0/0.1";
case 1 : return "2/0/0";
default : return "1/0/0";
}
case 5 :
case 13 : switch (program)
{
case 0 : return "3/0/0.1";
default : return "1/0/0";
}
case 6 :
case 14 :
case 19 : return "Front: L R";
case 7 : switch (program)
{
case 0 :
case 1 :
case 2 : return "2/0/0";
default : return "1/0/0";
}
case 8 :
case 15 : switch (program)
{
case 0 :
case 1 : return "2/0/0";
default : return "1/0/0";
}
case 9 :
case 16 :
case 20 : switch (program)
{
case 0 : return "2/0/0";
default : return "1/0/0";
}
case 10 :
case 17 :
case 21 : return "1/0/0";
case 11 : return "3/2/0.1";
case 22 : return "3/2/2.1";
case 23 : return "5/2/0.1";
default : return "";
}
};
extern const char* AC3_Surround[];
//---------------------------------------------------------------------------
const char* DolbyE_ChannelLayout_PerProgram(int8u program_config, int8u ProgramNumber)
{
switch (program_config)
{
case 0 : switch (ProgramNumber)
{
case 0 : return "L C Ls X R LFE Rs X";
default : return "X X X L X X X R";
}
case 1 : switch (ProgramNumber)
{
case 0 : return "L C Ls X R LFE Rs X";
case 1 : return "X X X C X X X X";
default : return "X X X X X X X C";
}
case 2 : switch (ProgramNumber)
{
case 0 : return "L C X X R S X X";
default : return "X X L C X X R S";
}
case 3 : switch (ProgramNumber)
{
case 0 : return "L C X X R S X X";
case 1 : return "X X L X X X R X";
default : return "X X X L X X X R";
}
case 4 : switch (ProgramNumber)
{
case 0 : return "L C X X R S X X";
case 1 : return "X X L X X X R X";
case 2 : return "X X X C X X X X";
default : return "X X X X X X X C";
}
case 5 : switch (ProgramNumber)
{
case 0 : return "L C X X R S X X";
case 1 : return "X X C X X X X X";
case 2 : return "X X X X X X C X";
case 3 : return "X X X C X X X X";
default : return "X X X X X X X C";
}
case 6 : switch (ProgramNumber)
{
case 0 : return "L X X X R X X X";
case 1 : return "X L X X X R X X";
case 2 : return "X X L X X X R X";
default : return "X X X L X X X R";
}
case 7 : switch (ProgramNumber)
{
case 0 : return "L X X X R X X X";
case 1 : return "X L X X X R X X";
case 2 : return "X X L X X X R X";
case 3 : return "X X X C X X X X";
default : return "X X X X X X X C";
}
case 8 : switch (ProgramNumber)
{
case 0 : return "L X X X R X X X";
case 1 : return "X L X X X R X X";
case 2 : return "X X C X X X X X";
case 3 : return "X X X X X X C X";
case 4 : return "X X X C X X X X";
default : return "X X X X X X X C";
}
case 9 : switch (ProgramNumber)
{
case 0 : return "L X X X R X X X";
case 1 : return "X C X X X X X X";
case 2 : return "X X X X X C X X";
case 3 : return "X X C X X X X X";
case 4 : return "X X X X X X C X";
case 5 : return "X X X C X X X X";
default : return "X X X X X X X C";
}
case 10 : switch (ProgramNumber)
{
case 0 : return "C X X X X X X X";
case 1 : return "X X X X C X X X";
case 2 : return "X C X X X X X X";
case 3 : return "X X X X X C X X";
case 4 : return "X X C X X X X X";
case 5 : return "X X X X X X C X";
case 6 : return "X X X C X X X X";
default : return "X X X X X X X C";
}
case 11 : return "L C Ls R LFE Rs";
case 12 : switch (ProgramNumber)
{
case 0 : return "L C X R S X";
default : return "X X L X X R";
}
case 13 : switch (ProgramNumber)
{
case 0 : return "L C X R S X";
case 1 : return "X X C X X X";
default : return "X X X X X C";
}
case 14 : switch (ProgramNumber)
{
case 0 : return "L X X R X X";
case 1 : return "X L X X R X";
default : return "X X L X X R";
}
case 15 : switch (ProgramNumber)
{
case 0 : return "L X X R X X";
case 1 : return "X L X R X";
case 2 : return "X X C X X X";
default : return "X X X X X C";
}
case 16 : switch (ProgramNumber)
{
case 0 : return "L X X R X X";
case 1 : return "X C X X X X";
case 2 : return "X X X X C X";
case 3 : return "X X C X X X";
default : return "X X X X X C";
}
case 17 : switch (ProgramNumber)
{
case 0 : return "C X X X X X";
case 1 : return "X X X C X X";
case 2 : return "X C X X X X";
case 3 : return "X X X X C X";
case 4 : return "X X C X X X";
default : return "X X X X X C";
}
case 18 : return "L C R S";
case 19 : switch (ProgramNumber)
{
case 0 : return "L X R X";
default : return "X L X R";
}
case 20 : switch (ProgramNumber)
{
case 0 : return "L X R X";
case 1 : return "X C X X";
default : return "X X X C";
}
case 21 : switch (ProgramNumber)
{
case 0 : return "C X X X";
case 1 : return "X X C X";
case 2 : return "X C X X";
default : return "X X X C";
}
case 22 : return "L C Ls Lrs R LFE Rs Rrs";
case 23 : return "L C Ls Lc R LFE Rs Rc";
default : return "";
}
};
extern const float64 Mpegv_frame_rate[16];
const bool Mpegv_frame_rate_type[16]=
{false, false, false, false, false, false, true, true, true, false, false, false, false, false, false, false};
//---------------------------------------------------------------------------
static const int8u intermediate_spatial_format_object_count[8]=
{
4,
8,
10,
14,
15,
30,
0,
0,
};
const char* sound_category_Values[4]=
{
"",
"Dialog",
"",
"",
};
const char* hp_render_mode_Values[4]=
{
"Bypassed",
"Near",
"Far",
"",
};
string default_target_device_config_Value(int32u config)
{
string Value;
if (config&0x1)
Value+="Stereo / ";
if (config&0x2)
Value+="Surround / ";
if (config&0x4)
Value+="Immersive / ";
if (!Value.empty())
Value.resize(Value.size()-3);
return Value;
}
struct pos3d
{
int8u x;
int8u y;
int8u z;
const char* Value;
};
int16u mgi_6bit_unsigned_to_oari_Q15[0x40]=
{
0, 529, 1057, 1586, 2114, 2643, 3171, 3700,
4228, 4757, 5285, 5814, 6342, 6871, 7399, 7928,
8456, 8985, 9513, 10042, 10570, 11099, 11627, 12156,
12684, 13213, 13741, 14270, 14798, 15327, 15855, 16384,
16913, 17441, 17970, 18498, 19027, 19555, 20084, 20612,
21141, 21669, 22198, 22726, 23255, 23783, 24312, 24840,
25369, 25897, 26426, 26954, 27483, 28011, 28540, 29068,
29597, 30125, 30654, 31182, 31711, 32239, 32767, 32767
};
int16u mgi_4bit_unsigned_to_oari_Q15[0x10]=
{
0, 2185, 4369, 6554, 8738, 10923, 13107, 15292,
17476, 19661, 21845, 24030, 26214, 28399, 30583, 32767
};
int mgi_bitstream_val_to_Q15(int value, int8u num_bits)
{
bool sign;
if (value<0)
{
sign=true;
value=-value;
}
else
sign=false;
int16u* Table;
switch (num_bits)
{
case 4: Table=mgi_4bit_unsigned_to_oari_Q15; break;
case 6: Table=mgi_6bit_unsigned_to_oari_Q15; break;
default: return 0; //Problem
}
int decoded=Table[value];
return sign?-decoded:decoded;
}
int mgi_bitstream_pos_z_to_Q15(bool pos_z_sign, int8u pos_z_bits)
{
if (pos_z_bits == 0xf) {
if (pos_z_sign == 1) /* +1 */ {
return(32767);
}
else /* -1 */ {
return(-32768);
}
}
else {
/* Negative number */
if (pos_z_sign == 1) {
return(mgi_bitstream_val_to_Q15(pos_z_bits, 4));
}
else {
return(mgi_bitstream_val_to_Q15(-pos_z_bits, 4));
}
}
}
//---------------------------------------------------------------------------
struct speaker_info
{
int8u AzimuthAngle; //0 to 180 (right, if AzimuthDirection is false) or 179 (left, if AzimuthDirection is true)
int8s ElevationDirectionAngle; //-90 (bottom) to 90 (top)
enum flag
{
None = 0,
AzimuthDirection = 1<<0, // true = right
isLFE = 1<<1,
};
int8u Flags;
};
bool operator== (const speaker_info& L, const speaker_info& R)
{
return L.AzimuthAngle==R.AzimuthAngle
&& L.ElevationDirectionAngle==R.ElevationDirectionAngle
&& L.Flags==R.Flags;
}
extern string Aac_ChannelLayout_GetString(const Aac_OutputChannel* const OutputChannels, size_t OutputChannels_Size);
static const size_t SpeakerInfos_Size=43;
static const speaker_info SpeakerInfos[SpeakerInfos_Size] =
{
{ 30, 0, speaker_info::AzimuthDirection },
{ 30, 0, speaker_info::None },
{ 0, 0, speaker_info::None },
{ 0, -15, speaker_info::isLFE },
{ 110, 0, speaker_info::AzimuthDirection },
{ 110, 0, speaker_info::None },
{ 22, 0, speaker_info::AzimuthDirection },
{ 22, 0, speaker_info::None },
{ 135, 0, speaker_info::AzimuthDirection },
{ 135, 0, speaker_info::None },
{ 180, 0, speaker_info::None },
{ 135, 0, speaker_info::AzimuthDirection },
{ 135, 0, speaker_info::None },
{ 90, 0, speaker_info::AzimuthDirection },
{ 90, 0, speaker_info::None },
{ 60, 0, speaker_info::AzimuthDirection },
{ 60, 0, speaker_info::None },
{ 30, 35, speaker_info::AzimuthDirection },
{ 30, 35, speaker_info::None },
{ 0, 35, speaker_info::None },
{ 135, 35, speaker_info::AzimuthDirection },
{ 135, 35, speaker_info::None },
{ 180, 35, speaker_info::None },
{ 90, 35, speaker_info::AzimuthDirection },
{ 90, 35, speaker_info::None },
{ 0, 90, speaker_info::None },
{ 45, -15, speaker_info::isLFE },
{ 45, -15, speaker_info::AzimuthDirection },
{ 45, -15, speaker_info::None },
{ 0, -15, speaker_info::None },
{ 110, 35, speaker_info::AzimuthDirection },
{ 110, 35, speaker_info::None },
{ 45, 35, speaker_info::AzimuthDirection },
{ 45, 35, speaker_info::None },
{ 45, 0, speaker_info::AzimuthDirection },
{ 45, 0, speaker_info::None },
{ 45, -15, speaker_info::None | speaker_info::isLFE },
{ 2, 0, speaker_info::AzimuthDirection },
{ 2, 0, speaker_info::None },
{ 1, 0, speaker_info::AzimuthDirection },
{ 1, 0, speaker_info::None },
{ 150, 0, speaker_info::AzimuthDirection },
{ 150, 0, speaker_info::None },
};
struct angles
{
int Azimuth;
int Elevation;
angles()
{}
angles(int theta, int phi) :
Azimuth(theta),
Elevation(phi)
{}
};
Aac_OutputChannel AnglesToChannelName(angles Angles)
{
speaker_info SpeakerInfo;
if (Angles.Azimuth<0)
{
SpeakerInfo.AzimuthAngle=(int8u)-Angles.Azimuth;
SpeakerInfo.Flags=speaker_info::AzimuthDirection;
}
else
{
SpeakerInfo.AzimuthAngle=Angles.Azimuth;
SpeakerInfo.Flags=speaker_info::None;
}
SpeakerInfo.ElevationDirectionAngle=Angles.Elevation;
for (size_t i=0; i<SpeakerInfos_Size; i++)
if (SpeakerInfos[i]==SpeakerInfo)
return (Aac_OutputChannel)i;
return CH_MAX;
}
string ToAngle3Digits(int Value)
{
string ToReturn=Ztring::ToZtring(Value).To_UTF8();
ToReturn.insert(0, 3-ToReturn.size(), '0');
return ToReturn;
}
angles mgi_bitstream_pos_ToAngles(int x_int, int y_int, int z_int)
{
//Center becomes 0 and edges +/-1
float x=(((float)x_int)*2-32768)/32768;
float y=(((float)y_int)*2-32768)/32768;
float z=((float)z_int)/32768;
if (!x && !y)
{
if (z>0)
return angles(0, 90);
else if (z<0)
return angles(0, -90);
return angles(0, 0); // Should not happen (is the center in practice)
}
else
{
angles ToReturn;
float radius=sqrt(x*x+y*y+z*z);
float theta_float=round(atan2(y, x)*180/3.14159265359/5)*5;
ToReturn.Azimuth=float32_int32s(theta_float);
float phi_float=round(acos(z/radius)*180/3.14159265359);
ToReturn.Elevation=float32_int32s(phi_float);
//Reference is front of viewer
if (ToReturn.Azimuth<90)
ToReturn.Azimuth+=90;
else
ToReturn.Azimuth-=270;
ToReturn.Elevation=90-ToReturn.Elevation;
return ToReturn;
}
}
string Angles2String(angles Angles)
{
string ToReturn;
//Elevation
switch (Angles.Elevation)
{
case 0: ToReturn+='M'; break;
case 90: ToReturn+='T'; break;
case -90: ToReturn+='X'; break; //No standard for that
default : ToReturn+=(Angles.Elevation>0?'U':'B');
//if (Angles.phi!=35 && Angles.phi!=-15)
ToReturn+=ToAngle3Digits(Angles.Elevation);
}
ToReturn+='_';
//Azimuth
if (Angles.Azimuth<0)
ToReturn+='L';
else if (Angles.Azimuth>0 && Angles.Azimuth!=180)
ToReturn+='R';
ToReturn+=ToAngle3Digits(Angles.Azimuth<0?-Angles.Azimuth:Angles.Azimuth);
return ToReturn;
}
string Angles2KnownChannelName(angles& Angles)
{
//Exception handling
int Azimuth;
if (Angles.Azimuth==-180)
Azimuth=180;
else
Azimuth=Angles.Azimuth;
int Elevation;
if (Angles.Elevation>=35 && Angles.Elevation<=45)
Elevation=35;
else
Elevation=Angles.Elevation;
Aac_OutputChannel KnownChannel=AnglesToChannelName(angles(Azimuth, Elevation));
if (KnownChannel!=CH_MAX)
return Aac_ChannelLayout_GetString(&KnownChannel, 1);
else
return Angles2String(Angles);
}
//---------------------------------------------------------------------------
extern int32u AC3_bed_channel_assignment_mask_2_nonstd(int16u bed_channel_assignment_mask);
extern Ztring AC3_nonstd_bed_channel_assignment_mask_ChannelLayout(int32u nonstd_bed_channel_assignment_mask);
size_t BedChannelConfiguration_ChannelCount(int32u nonstd_bed_channel_assignment_mask)
{
Ztring BedChannelConfiguration=AC3_nonstd_bed_channel_assignment_mask_ChannelLayout(nonstd_bed_channel_assignment_mask);
size_t BedChannelCount=0;
if (!BedChannelConfiguration.empty())
for (size_t i=0; i<BedChannelConfiguration.size();)
{
BedChannelCount++;
i=BedChannelConfiguration.find(__T(' '), i+1);
}
return BedChannelCount;
}
//***************************************************************************
// Constructor/Destructor
//***************************************************************************
//---------------------------------------------------------------------------
File_DolbyE::File_DolbyE()
:File__Analyze()
{
//Configuration
#if MEDIAINFO_EVENTS
ParserIDs[0]=MediaInfo_Parser_DolbyE;
#endif //MEDIAINFO_EVENTS
//Configuration
MustSynchronize=true;
Buffer_TotalBytes_FirstSynched_Max=32*1024;
//In
GuardBand_Before=0;
//Out
GuardBand_After=0;
//ED2
Guardband_EMDF_PresentAndSize=0;
num_desc_packets_m1=(int32u)-1;
//Temp
SMPTE_time_code_StartTimecode=(int64u)-1;
FrameInfo.DTS=0;
}
//***************************************************************************
// Streams management
//***************************************************************************
//---------------------------------------------------------------------------
void File_DolbyE::Streams_Fill()
{
Fill(Stream_General, 0, General_Format, "Dolby E");
if (!Presets.empty())
{
Streams_Fill_ED2();
return;
}
int8u DolbyE_Audio_Pos=0;
for (size_t i=0; i<8; i++)
if (channel_subsegment_sizes[i].size()>1)
DolbyE_Audio_Pos=(int8u)-1;
for (int8u program=0; program<DolbyE_Programs[program_config]; program++)
{
Stream_Prepare(Stream_Audio);
Fill(Stream_Audio, StreamPos_Last, Audio_Format, "Dolby E");
if (DolbyE_Programs[program_config]>1)
Fill(Stream_Audio, StreamPos_Last, Audio_ID, Count_Get(Stream_Audio));
Fill(Stream_Audio, StreamPos_Last, Audio_Channel_s_, DolbyE_Channels_PerProgram(program_config, program));
Fill(Stream_Audio, StreamPos_Last, Audio_ChannelPositions, DolbyE_ChannelPositions_PerProgram(program_config, program));
Fill(Stream_Audio, StreamPos_Last, Audio_ChannelPositions_String2, DolbyE_ChannelPositions2_PerProgram(program_config, program));
Fill(Stream_Audio, StreamPos_Last, Audio_ChannelLayout, DolbyE_ChannelLayout_PerProgram(program_config, program));
int32u Program_Size=0;
if (DolbyE_Audio_Pos!=(int8u)-1)
for (int8u Pos=0; Pos<DolbyE_Channels_PerProgram(program_config, program); Pos++)
Program_Size+=channel_subsegment_size[DolbyE_Audio_Pos+Pos];
if (!Mpegv_frame_rate_type[frame_rate_code])
Program_Size*=2; //Low bit rate, 2 channel component per block
Program_Size*=bit_depth;
Fill(Stream_Audio, StreamPos_Last, Audio_BitRate, Program_Size*Mpegv_frame_rate[frame_rate_code], 0);
if (DolbyE_Audio_Pos!=(int8u)-1)
DolbyE_Audio_Pos+=DolbyE_Channels_PerProgram(program_config, program);
Streams_Fill_PerProgram();
if (program<description_text_Values.size())
{
Fill(Stream_Audio, StreamPos_Last, Audio_Title, description_text_Values[program].Previous);
Fill(Stream_Audio, StreamPos_Last, "Title_FromStream", description_text_Values[program].Previous);
Fill_SetOptions(Stream_Audio, StreamPos_Last, "Title_FromStream", "N NT");
}
}
}
//---------------------------------------------------------------------------
void File_DolbyE::Streams_Fill_PerProgram()
{
Fill(Stream_Audio, StreamPos_Last, Audio_SamplingRate, 48000);
Fill(Stream_Audio, StreamPos_Last, Audio_BitDepth, bit_depth);
if (SMPTE_time_code_StartTimecode!=(int64u)-1)
{
Fill(StreamKind_Last, StreamPos_Last, Audio_Delay, SMPTE_time_code_StartTimecode);
Fill(StreamKind_Last, StreamPos_Last, Audio_Delay_Source, "Stream");
}
Fill(Stream_Audio, StreamPos_Last, Audio_FrameRate, Mpegv_frame_rate[frame_rate_code]);
if (FrameInfo.PTS!=(int64u)-1 && bit_depth)
{
float BitRate=(float)(96000*bit_depth);
if (GuardBand_Before_Initial)
{
float GuardBand_Before_Initial_Duration=GuardBand_Before_Initial*8/BitRate;
Fill(Stream_Audio, StreamPos_Last, "GuardBand_Before", GuardBand_Before_Initial_Duration, 9);
Fill(Stream_Audio, StreamPos_Last, "GuardBand_Before/String", Ztring::ToZtring(GuardBand_Before_Initial_Duration*1000000, 0)+Ztring().From_UTF8(" \xC2xB5s")); //0xC2 0xB5 = micro sign
Fill_SetOptions(Stream_Audio, StreamPos_Last, "GuardBand_Before", "N NT");
Fill_SetOptions(Stream_Audio, StreamPos_Last, "GuardBand_Before/String", "N NT");
float GuardBand_After_Initial_Duration=GuardBand_After_Initial*8/BitRate;
Fill(Stream_Audio, StreamPos_Last, "GuardBand_After", GuardBand_After_Initial_Duration, 9);
Fill(Stream_Audio, StreamPos_Last, "GuardBand_After/String", Ztring::ToZtring(GuardBand_After_Initial_Duration*1000000, 0)+Ztring().From_UTF8(" \xC2xB5s")); //0xC2 0xB5 = micro sign
Fill_SetOptions(Stream_Audio, StreamPos_Last, "GuardBand_After", "N NT");
Fill_SetOptions(Stream_Audio, StreamPos_Last, "GuardBand_After/String", "N NT");
}
}
if (FrameSizes.size()==1)
{
if (StreamPos_Last)
Fill(Stream_Audio, StreamPos_Last, Audio_BitRate_Encoded, 0, 0, true);
else
{
Fill(Stream_General, 0, General_OverallBitRate, FrameSizes.begin()->first*8*Mpegv_frame_rate[frame_rate_code], 0);
Fill(Stream_Audio, 0, Audio_BitRate_Encoded, FrameSizes.begin()->first*8*Mpegv_frame_rate[frame_rate_code], 0);
}
}
}
//---------------------------------------------------------------------------
void File_DolbyE::Streams_Fill_ED2()
{
Stream_Prepare(Stream_Audio);
Fill(Stream_Audio, StreamPos_Last, Audio_Format, "Dolby ED2");
if (Guardband_EMDF_PresentAndSize)
Fill(Stream_Audio, StreamPos_Last, Audio_BitRate, Guardband_EMDF_PresentAndSize*8*Mpegv_frame_rate[frame_rate_code], 0);
size_t ChannelCount=DynObjects.size();
for (size_t p=0; p<BedInstances.size(); p++)
if (p<nonstd_bed_channel_assignment_masks.size())
ChannelCount+=BedChannelConfiguration_ChannelCount(nonstd_bed_channel_assignment_masks[p]);
if (ChannelCount)
Fill(Stream_Audio, StreamPos_Last, Audio_Channel_s_, ChannelCount);
Streams_Fill_PerProgram();
if (!Presets.empty())
{
Fill(Stream_Audio, 0, "NumberOfPresentations", Presets.size());
Fill_SetOptions(Stream_Audio, 0, "NumberOfPresentations", "N NIY");
}
if (!BedInstances.empty())
{
Fill(Stream_Audio, 0, "NumberOfBeds", BedInstances.size());
Fill_SetOptions(Stream_Audio, 0, "NumberOfBeds", "N NIY");
}
if (!DynObjects.empty())
{
Fill(Stream_Audio, 0, "NumberOfObjects", DynObjects.size());
Fill_SetOptions(Stream_Audio, 0, "NumberOfObjects", "N NIY");
}
for (size_t p=0; p<Presets.size(); p++)
{
const preset& Presentation_Current=Presets[p];
string Title;
if (p<Presets_More.size() && !Presets_More[p].description.empty())
Title=Presets_More[p].description;
string Summary=Title;
if (Summary.empty())
Summary="Yes";
string P="Presentation"+Ztring::ToZtring(p).To_UTF8();
Fill(Stream_Audio, 0, P.c_str(), Summary);
if (!Title.empty())
{
Fill(Stream_Audio, 0, (P+" Title").c_str(), Title);
Fill_SetOptions(Stream_Audio, 0, (P+" Title").c_str(), "N NTY");
}
Fill(Stream_Audio, 0, (P+" DefaultTargetDeviceConfig").c_str(), default_target_device_config_Value(Presentation_Current.default_target_device_config));
Fill_SetOptions(Stream_Audio, 0, (P+" DefaultTargetDeviceConfig").c_str(), "Y NTY");
if (!Presentation_Current.target_device_configs.empty())
{
Fill(Stream_Audio, 0, (P+" NumberOfTargets").c_str(), Presentation_Current.target_device_configs.size());
Fill_SetOptions(Stream_Audio, 0, (P+" NumberOfTargets").c_str(), "N NIY");
}
for (size_t t=0; t<Presentation_Current.target_device_configs.size(); t++)
{
const preset::target_device_config& Target_Current=Presentation_Current.target_device_configs[t];
string Summary2=default_target_device_config_Value(Target_Current.target_devices_mask);
if (Summary2.empty())
Summary2="Yes";
string T=P+" Target"+Ztring::ToZtring(t).To_UTF8();
Fill(Stream_Audio, 0, T.c_str(), Summary2);
Fill(Stream_Audio, 0, (T+" TargetDeviceConfig").c_str(), default_target_device_config_Value(Target_Current.target_devices_mask));
Fill_SetOptions(Stream_Audio, 0, (T+" TargetDeviceConfig").c_str(), "N NTY");
ZtringList GroupPos[2], GroupNum[2];
for (size_t i=0; i<Target_Current.md_indexes.size(); i++)
{
if (Target_Current.md_indexes[i]!=(int32u)-1)
{
size_t I1, I2;
if (i<DynObjects.size())
{
I1=i;
I2=Target_Current.md_indexes[i];
if (I2 && I2>DynObjects[I1].Alts.size()) // 0 = OAMD, else Alt - 1
I2=0; // There is a problem
}
else
{
I1=i-DynObjects.size();
I2=Target_Current.md_indexes[i];
if (I2 && I2>BedInstances[I1].Alts.size()) // 0 = OAMD, else Alt - 1
I2=0; // There is a problem
}
int j=i<DynObjects.size()?1:0;
GroupPos[j].push_back(Ztring::ToZtring(I1));
GroupNum[j].push_back(Ztring::ToZtring(I1+1));
if (I2 )
{
GroupPos[j][GroupPos[j].size()-1]+=__T('-');
GroupNum[j][GroupNum[j].size()-1]+=__T('-');
GroupPos[j][GroupPos[j].size()-1]+=Ztring::ToZtring(I2-1);
GroupNum[j][GroupNum[j].size()-1]+=Ztring::ToZtring(I2);
}
}
}
for (size_t i=0; i<2; i++)
{
GroupPos[i].Separator_Set(0, __T(" + "));
Fill(Stream_Audio, 0, (T+(!i?" LinkedTo_Bed_Pos":" LinkedTo_Object_Pos")).c_str(), GroupPos[i].Read());
Fill_SetOptions(Stream_Audio, 0, (T+(!i?" LinkedTo_Bed_Pos":" LinkedTo_Object_Pos")).c_str(), "N NIY");
GroupNum[i].Separator_Set(0, __T(" + "));
Fill(Stream_Audio, 0, (T+(!i?" LinkedTo_Bed_Pos/String":" LinkedTo_Object_Pos/String")).c_str(), GroupNum[i].Read());
Fill_SetOptions(Stream_Audio, 0, (T+(!i?" LinkedTo_Bed_Pos/String":" LinkedTo_Object_Pos/String")).c_str(), "Y NIN");
}
}
}
// Computing the count of objects in bed instances
size_t Bed_Object_Count=0;
// Beds
for (size_t p=0; p<BedInstances.size(); p++)
{
const bed_instance& BedInstance=BedInstances[p];
string Summary;
if (Summary.empty())
Summary=AC3_nonstd_bed_channel_assignment_mask_ChannelLayout(nonstd_bed_channel_assignment_masks[p]).To_UTF8();
if (Summary.empty())
Summary="Yes";
string P=Ztring(__T("Bed")+Ztring::ToZtring(p)).To_UTF8();
Fill(Stream_Audio, 0, P.c_str(), Summary);
if (p<nonstd_bed_channel_assignment_masks.size())
{
Fill(Stream_Audio, StreamPos_Last, (P+" Channel(s)").c_str(), BedChannelConfiguration_ChannelCount(nonstd_bed_channel_assignment_masks[p]));
Fill_SetOptions(Stream_Audio, 0, (P+" Channel(s)").c_str(), "Y NTY");
Fill(Stream_Audio, 0, (P+" ChannelLayout").c_str(), AC3_nonstd_bed_channel_assignment_mask_ChannelLayout(nonstd_bed_channel_assignment_masks[p]));
Fill_SetOptions(Stream_Audio, 0, (P+" ChannelLayout").c_str(), "Y NTY");
// From OAMD
if (Bed_Object_Count<ObjectElements.size() && !ObjectElements[Bed_Object_Count].Alts.empty())
{
string A=P;
// Computing the count of objects in bed instances
size_t ThisBed_Object_Count=BedChannelConfiguration_ChannelCount(nonstd_bed_channel_assignment_masks[p]);
if (ThisBed_Object_Count)
{
// Check if all same
int8s obj_gain_db_Ref=ObjectElements[Bed_Object_Count].Alts[0].obj_gain_db;
for (size_t o=1; o<ThisBed_Object_Count; o++)
{
int8s obj_gain_db=ObjectElements[Bed_Object_Count+o].Alts[0].obj_gain_db;
if (obj_gain_db!=obj_gain_db_Ref)
{
obj_gain_db_Ref=INT8_MAX;
break;
}
}
if (obj_gain_db_Ref!=INT8_MAX)
{
// Same
if (obj_gain_db_Ref==INT8_MIN)
Fill_Measure(Stream_Audio, 0, (A+" Gain").c_str(), string("-infinite"), " dB");
else
Fill_Measure(Stream_Audio, 0, (A+" Gain").c_str(), obj_gain_db_Ref, " dB");
}
else
{
// Not same
for (size_t o=0; o<ThisBed_Object_Count; o++)
{
const dyn_object::dyn_object_alt& DynObject_Current=ObjectElements[Bed_Object_Count+o].Alts[0];
if (DynObject_Current.obj_gain_db!=INT8_MAX)
{
if (DynObject_Current.obj_gain_db==INT8_MIN)
Fill_Measure(Stream_Audio, 0, (A+" Gain").c_str(), string("-infinite"), " dB");
else
Fill_Measure(Stream_Audio, 0, (A+" Gain").c_str(), DynObject_Current.obj_gain_db, " dB");
}
}
}
}
Bed_Object_Count+=ThisBed_Object_Count;
}
}
if (!BedInstance.Alts.empty())
{
Fill(Stream_Audio, 0, (P+" NumberOfAlts").c_str(), BedInstance.Alts.size());
Fill_SetOptions(Stream_Audio, 0, (P+" NumberOfAlts").c_str(), "N NIY");
}
for (size_t a=0; a<BedInstance.Alts.size(); a++)
{
const bed_instance::bed_alt& BedInstance_Current=BedInstance.Alts[a];
string Summary2;
if (Summary2.empty())
Summary2="Yes";
string A=P+Ztring(__T(" Alt")+Ztring::ToZtring(a)).To_UTF8();
Fill(Stream_Audio, 0, A.c_str(), Summary2);
if (BedInstance_Current.bed_gain_db!=INT8_MAX)
{
Fill_Measure(Stream_Audio, 0, (A+" Gain").c_str(), BedInstance_Current.bed_gain_db, " dB");
}
}
const substream_mapping& S=substream_mappings[DynObjects.size()+p];
{
Fill(Stream_Audio, 0, (P+" SubtstreamIdChannel").c_str(), Ztring::ToZtring(S.substream_id)+__T('-')+Ztring::ToZtring(S.channel_index));
Fill_SetOptions(Stream_Audio, 0, (P+" SubtstreamIdChannel").c_str(), "Y NTY");
}
}
// Dynamic objects
for (size_t p=0; p<DynObjects.size(); p++)
{
const dyn_object& DynObject=DynObjects[p];
string P=Ztring(__T("Object")+Ztring::ToZtring(p)).To_UTF8();
// From OAMD
Ztring Position_Cartesian;
string Position_Polar;
string ChannelLayout;
if (Bed_Object_Count<ObjectElements.size() && p<ObjectElements.size()-Bed_Object_Count && !ObjectElements[Bed_Object_Count+p].Alts.empty())
{
string A=P;
const dyn_object::dyn_object_alt& DynObject_Current=ObjectElements[Bed_Object_Count+p].Alts[0];
if (DynObject_Current.pos3d_x_bits!=(int8u)-1)
{
int x_32k=mgi_bitstream_val_to_Q15(DynObject_Current.pos3d_x_bits, 6);
int y_32k=mgi_bitstream_val_to_Q15(DynObject_Current.pos3d_y_bits, 6);
int z_32k=mgi_bitstream_pos_z_to_Q15(DynObject_Current.pos3d_z_sig, DynObject_Current.pos3d_z_bits);
Position_Cartesian=__T("x=")+Ztring::ToZtring((((float)x_32k)*2-32768)/32768, 1)+__T(" y=")+Ztring::ToZtring((((float)y_32k)*2-32768)/32768, 1)+__T(" z=")+Ztring::ToZtring(((float)z_32k)/32768, 1);
angles Angles=mgi_bitstream_pos_ToAngles(x_32k, y_32k, z_32k);
Position_Polar=Angles2String(Angles);
ChannelLayout=Angles2KnownChannelName(Angles);
if (ChannelLayout==Position_Polar)
ChannelLayout.clear();
}
}
string Summary;
if (Summary.empty())
Summary=sound_category_Values[DynObject.sound_category];
/*
if (Summary.empty())
Summary=ChannelLayout;
if (Summary.empty())
Summary=Position_Polar;
*/
if (Summary.empty())
Summary="Yes";
Fill(Stream_Audio, 0, P.c_str(), Summary);
if (sound_category_Values[DynObject.sound_category][0])
{
Fill(Stream_Audio, 0, (P+" SoundCategory").c_str(), sound_category_Values[DynObject.sound_category]);
Fill_SetOptions(Stream_Audio, 0, (P+" SoundCategory").c_str(), "Y NTY");
}
// From OAMD
if (Bed_Object_Count<ObjectElements.size() && p<ObjectElements.size()-Bed_Object_Count && !ObjectElements[Bed_Object_Count+p].Alts.empty())
{
string A=P;
const dyn_object::dyn_object_alt& DynObject_Current=ObjectElements[Bed_Object_Count+p].Alts[0];
/*
if (!ChannelLayout.empty())
{
Fill(Stream_Audio, 0, (A+" ChannelLayout").c_str(), ChannelLayout);
Fill_SetOptions(Stream_Audio, 0, (A+" ChannelLayout").c_str(), "Y NTY");
}
*/
if (!Position_Polar.empty())
{
Fill(Stream_Audio, 0, (A+" Position_Polar").c_str(), Position_Polar);
Fill_SetOptions(Stream_Audio, 0, (A+" Position_Polar").c_str(), "Y NTY");
}
if (!Position_Cartesian.empty())
{
Fill(Stream_Audio, 0, (A+" Position_Cartesian").c_str(), Position_Cartesian);
Fill_SetOptions(Stream_Audio, 0, (A+" Position_Cartesian").c_str(), "Y NTY");
}
if (DynObject_Current.obj_gain_db!=INT8_MAX)
{
if (DynObject_Current.obj_gain_db==INT8_MIN)
Fill_Measure(Stream_Audio, 0, (A+" Gain").c_str(), string("-infinite"), " dB");
else
Fill_Measure(Stream_Audio, 0, (A+" Gain").c_str(), DynObject_Current.obj_gain_db, " dB");
}
}
if (!DynObject.Alts.empty())
{
Fill(Stream_Audio, 0, (P+" NumberOfAlts").c_str(), DynObject.Alts.size());
Fill_SetOptions(Stream_Audio, 0, (P+" NumberOfAlts").c_str(), "N NIY");
}
for (size_t a=0; a<DynObject.Alts.size(); a++)
{
const dyn_object::dyn_object_alt& DynObject_Current=DynObject.Alts[a];
Ztring Position_Cartesian;
string Position_Polar;
string ChannelLayout;
if (DynObject_Current.pos3d_x_bits!=(int8u)-1)
{
int x_32k=mgi_bitstream_val_to_Q15(DynObject_Current.pos3d_x_bits, 6);
int y_32k=mgi_bitstream_val_to_Q15(DynObject_Current.pos3d_y_bits, 6);
int z_32k=mgi_bitstream_pos_z_to_Q15(DynObject_Current.pos3d_z_sig, DynObject_Current.pos3d_z_bits);
Position_Cartesian=__T("x=")+Ztring::ToZtring((((float)x_32k)*2-32768)/32768, 1)+__T(" y=")+Ztring::ToZtring((((float)y_32k)*2-32768)/32768, 1)+__T(" z=")+Ztring::ToZtring(((float)z_32k)/32768, 1);
angles Angles=mgi_bitstream_pos_ToAngles(x_32k, y_32k, z_32k);
Position_Polar=Angles2String(Angles);
ChannelLayout=Angles2KnownChannelName(Angles);
if (ChannelLayout==Position_Polar)
ChannelLayout.clear();
}
string Summary2;
if (Summary2.empty())
Summary2=sound_category_Values[DynObject.sound_category];
/*
if (Summary2.empty())
Summary2=ChannelLayout;
if (Summary2.empty())
Summary2=Position_Polar;
*/
if (Summary2.empty())
Summary2="Yes";
string A=P+Ztring(__T(" Alt")+Ztring::ToZtring(a)).To_UTF8();
Fill(Stream_Audio, 0, A.c_str(), Summary2);
/*
if (!ChannelLayout.empty())
{
Fill(Stream_Audio, 0, (A+" ChannelLayout").c_str(), ChannelLayout);
Fill_SetOptions(Stream_Audio, 0, (A+" ChannelLayout").c_str(), "Y NTY");
}
*/
if (!Position_Polar.empty())
{
Fill(Stream_Audio, 0, (A+" Position_Polar").c_str(), Position_Polar);
Fill_SetOptions(Stream_Audio, 0, (A+" Position_Polar").c_str(), "Y NTY");
}
if (!Position_Cartesian.empty())
{
Fill(Stream_Audio, 0, (A+" Position_Cartesian").c_str(), Position_Cartesian);
Fill_SetOptions(Stream_Audio, 0, (A+" Position_Cartesian").c_str(), "Y NTY");
}
if (DynObject_Current.obj_gain_db!=INT8_MAX)
{
if (DynObject_Current.obj_gain_db==INT8_MIN)
Fill_Measure(Stream_Audio, 0, (A+" Gain").c_str(), string("-infinite"), " dB");
else
Fill_Measure(Stream_Audio, 0, (A+" Gain").c_str(), DynObject_Current.obj_gain_db, " dB");
}
if (DynObject_Current.hp_render_mode!=(int8u)-1)
{
Fill(Stream_Audio, 0, (A+" RenderMode").c_str(), hp_render_mode_Values[DynObject_Current.hp_render_mode]);
Fill_SetOptions(Stream_Audio, 0, (P + " RenderMode").c_str(), "Y NTY");
}
}
const substream_mapping& S=substream_mappings[p];
{
Fill(Stream_Audio, 0, (P+" SubtstreamIdChannel").c_str(), Ztring::ToZtring(S.substream_id)+__T('-')+Ztring::ToZtring(S.channel_index));
Fill_SetOptions(Stream_Audio, 0, (P+" SubtstreamIdChannel").c_str(), "Y NTY");
}
}
}
//---------------------------------------------------------------------------
void File_DolbyE::Streams_Finish()
{
if (FrameInfo.PTS!=(int64u)-1 && FrameInfo.PTS>PTS_Begin)
{
int64s Duration=float64_int64s(((float64)(FrameInfo.PTS-PTS_Begin))/1000000);
int64s FrameCount;
if (Mpegv_frame_rate[frame_rate_code])
FrameCount=float64_int64s(((float64)(FrameInfo.PTS-PTS_Begin))/1000000000*Mpegv_frame_rate[frame_rate_code]);
else
FrameCount=0;
for (size_t Pos=0; Pos<Count_Get(Stream_Audio); Pos++)
{
Fill(Stream_Audio, Pos, Audio_Duration, Duration);
if (FrameCount)
Fill(Stream_Audio, Pos, Audio_FrameCount, FrameCount);
}
}
}
//***************************************************************************
// Buffer - Synchro
//***************************************************************************
//---------------------------------------------------------------------------
bool File_DolbyE::Synchronize()
{
//Synchronizing
while (Buffer_Offset+3<=Buffer_Size)
{
if ((CC2(Buffer+Buffer_Offset_Temp)&0xFFFE)==0x078E) //16-bit
{
bit_depth=16;
key_present=(CC2(Buffer+Buffer_Offset)&0x0001)?true:false;
break; //while()
}
if ((CC3(Buffer+Buffer_Offset)&0xFFFFE0)==0x0788E0) //20-bit
{
bit_depth=20;
key_present=(CC3(Buffer+Buffer_Offset)&0x000010)?true:false;
break; //while()
}
if ((CC3(Buffer+Buffer_Offset)&0xFFFFFE)==0x07888E) //24-bit
{
bit_depth=24;
key_present=(CC3(Buffer+Buffer_Offset)&0x000001)?true:false;
break; //while()
}
Buffer_Offset++;
}
//Parsing last bytes if needed
if (Buffer_Offset+3>Buffer_Size)
return false;
//Synched
return true;
}
//---------------------------------------------------------------------------
bool File_DolbyE::Synched_Test()
{
//Must have enough buffer for having header
if (Buffer_Offset+3>Buffer_Size)
return false;
//Quick test of synchro
switch (bit_depth)
{
case 16 : if ((CC2(Buffer+Buffer_Offset)&0xFFFE )!=0x078E ) {Synched=false; return true;} break;
case 20 : if ((CC3(Buffer+Buffer_Offset)&0xFFFFE0)!=0x0788E0) {Synched=false; return true;} break;
case 24 : if ((CC3(Buffer+Buffer_Offset)&0xFFFFFE)!=0x07888E) {Synched=false; return true;} break;
default : ;
}
//We continue
return true;
}
//***************************************************************************
// Buffer - Global
//***************************************************************************
//---------------------------------------------------------------------------
void File_DolbyE::Read_Buffer_Unsynched()
{
description_text_Values.clear();
num_desc_packets_m1=(int32u)-1;
description_packet_data.clear();
}
//***************************************************************************
// Buffer - Per element
//***************************************************************************
//---------------------------------------------------------------------------
void File_DolbyE::Header_Parse()
{
//Filling
if (IsSub)
Header_Fill_Size(Buffer_Size-Buffer_Offset);
else
{
//Looking for synchro
//Synchronizing
Buffer_Offset_Temp=Buffer_Offset+3;
if (bit_depth==16)
while (Buffer_Offset_Temp+2<=Buffer_Size)
{
if ((CC2(Buffer+Buffer_Offset_Temp)&0xFFFE)==0x078E) //16-bit
break; //while()
Buffer_Offset_Temp++;
}
if (bit_depth==20)
while (Buffer_Offset_Temp+3<=Buffer_Size)
{
if ((CC3(Buffer+Buffer_Offset_Temp)&0xFFFFE0)==0x0788E0) //20-bit
break; //while()
Buffer_Offset_Temp++;
}
if (bit_depth==24)
while (Buffer_Offset_Temp+3<=Buffer_Size)
{
if ((CC3(Buffer+Buffer_Offset_Temp)&0xFFFFFE)==0x07888E) //24-bit
break; //while()
Buffer_Offset_Temp++;
}
if (Buffer_Offset_Temp+(bit_depth>16?3:2)>Buffer_Size)
{
if (File_Offset+Buffer_Size==File_Size)
Buffer_Offset_Temp=Buffer_Size;
else
{
Element_WaitForMoreData();
return;
}
}
Header_Fill_Size(Buffer_Offset_Temp-Buffer_Offset);
}
Header_Fill_Code(0, "Dolby_E_frame");
}
//---------------------------------------------------------------------------
void File_DolbyE::Data_Parse()
{
FrameSizes[Element_Size]++;
//In case of scrambling
const int8u* Save_Buffer=NULL;
size_t Save_Buffer_Offset=0;
int64u Save_File_Offset=0;
if (key_present)
{
//We must change the buffer,
Save_Buffer=Buffer;
Save_Buffer_Offset=Buffer_Offset;
Save_File_Offset=File_Offset;
File_Offset+=Buffer_Offset;
Buffer_Offset=0;
Descrambled_Buffer=new int8u[(size_t)Element_Size];
std::memcpy(Descrambled_Buffer, Save_Buffer+Save_Buffer_Offset, (size_t)Element_Size);
Buffer=Descrambled_Buffer;
}
//Parsing
BS_Begin();
sync_segment();
metadata_segment();
audio_segment();
metadata_extension_segment();
audio_extension_segment();
meter_segment();
BS_End();
//Check if there is content in padding
int16u Padding;
if (Element_Size-Element_Offset>=2)
{
Peek_B2(Padding);
if (Padding==0x5838)
guard_band();
}
if (Element_Offset<Element_Size)
Skip_XX(Element_Size-Element_Offset, "Unknown");
//In case of scrambling
if (key_present)
{
delete[] Buffer; Buffer=Save_Buffer;
Buffer_Offset=Save_Buffer_Offset;
File_Offset=Save_File_Offset;
}
FILLING_BEGIN();
{
//Guard band
if (Mpegv_frame_rate[frame_rate_code])
{
int64u BytesPerSecond=96000*bit_depth/8;
float64 BytesPerFrame=BytesPerSecond/Mpegv_frame_rate[frame_rate_code];
int64u BytesUpToLastFrame;
int64u BytesUpToNextFrame;
for (;;)
{
BytesUpToLastFrame=(int64u)(BytesPerFrame*Frame_Count);
BytesUpToLastFrame/=bit_depth/4;
BytesUpToLastFrame*=bit_depth/4;
BytesUpToNextFrame=(int64u)(BytesPerFrame*(Frame_Count+1));
BytesUpToNextFrame/=bit_depth/4;
BytesUpToNextFrame*=bit_depth/4;
if (BytesUpToLastFrame+GuardBand_Before<BytesUpToNextFrame)
break;
// In case previous frame was PCM
Frame_Count++;
GuardBand_Before-=BytesUpToNextFrame-BytesUpToLastFrame;
}
GuardBand_After=BytesUpToNextFrame-BytesUpToLastFrame;
int64u ToRemove=GuardBand_Before+(bit_depth>>1)+Element_Size; // Guardband + AES3 header + Dolby E frame
if (ToRemove<(int64u)GuardBand_After)
GuardBand_After-=ToRemove;
else
GuardBand_After=0;
GuardBand_After/=bit_depth/4;
GuardBand_After*=bit_depth/4;
Element_Info1(GuardBand_Before);
float64 GuardBand_Before_Duration=((float64)GuardBand_Before)/BytesPerSecond;
Ztring GuardBand_Before_String=__T("GuardBand_Begin ")+Ztring::ToZtring(GuardBand_Before)+__T(" (")+Ztring::ToZtring(GuardBand_Before_Duration*1000000, 0)+Ztring().From_UTF8(" \0xC20xB5s"); //0xC20xB5 = micro sign
Element_Info1(GuardBand_Before_String);
}
}
if (!Status[IsAccepted])
{
Accept("Dolby E");
PTS_Begin=FrameInfo.PTS;
//Guard band
GuardBand_Before_Initial=GuardBand_Before;
GuardBand_After_Initial=GuardBand_After;
}
Frame_Count++;
if (Frame_Count_NotParsedIncluded!=(int64u)-1)
Frame_Count_NotParsedIncluded++;
if (Mpegv_frame_rate[frame_rate_code])
FrameInfo.DUR=float64_int64s(1000000000/Mpegv_frame_rate[frame_rate_code]);
else
FrameInfo.DUR=(int64u)-1;
if (FrameInfo.DTS!=(int64u)-1)
FrameInfo.DTS+=FrameInfo.DUR;
if (FrameInfo.PTS!=(int64u)-1)
FrameInfo.PTS+=FrameInfo.DUR;
if (!Status[IsFilled] && ((description_packet_data.empty() && description_text_Values.empty()) || Frame_Count>=32+1+1+32+1)) // max 32 chars (discarded) + ETX (discarded) + STX + max 32 chars + ETX
Fill("Dolby E");
FILLING_END();
if (Frame_Count==0 && Buffer_TotalBytes>Buffer_TotalBytes_FirstSynched_Max)
Reject("Dolby E");
}
//---------------------------------------------------------------------------
void File_DolbyE::sync_segment()
{
//Parsing
Element_Begin1("sync_segment");
Skip_S3(bit_depth, "sync_word");
Element_End0();
}
//---------------------------------------------------------------------------
void File_DolbyE::metadata_segment()
{
//Parsing
Element_Begin1("metadata_segment");
if (key_present)
{
//We must change the buffer
switch (bit_depth)
{
case 16 :
{
int16u metadata_key;
Get_S2 (16, metadata_key, "metadata_key");
int16u metadata_segment_size=((BigEndian2int16u(Buffer+Buffer_Offset+(size_t)Element_Size-Data_BS_Remain()/8)^metadata_key)>>2)&0x3FF;
if (Data_BS_Remain()<((size_t)metadata_segment_size+1)*(size_t)bit_depth) //+1 for CRC
return; //There is a problem
int8u* Temp=Descrambled_Buffer+(size_t)Element_Size-Data_BS_Remain()/8;
for (int16u Pos=0; Pos<metadata_segment_size+1; Pos++)
int16u2BigEndian(Temp+Pos*2, BigEndian2int16u(Temp+Pos*2)^metadata_key);
}
break;
case 20 :
{
int32u metadata_key;
Get_S3 (20, metadata_key, "metadata_key");
int16u metadata_segment_size=((BigEndian2int16u(Buffer+Buffer_Offset+(size_t)Element_Size-Data_BS_Remain()/8)^(metadata_key>>4))>>2)&0x3FF;
if (Data_BS_Remain()<((size_t)metadata_segment_size+1)*(size_t)bit_depth) //+1 for CRC
return; //There is a problem
Descramble_20bit(metadata_key, metadata_segment_size);
}
break;
case 24 :
{
int32u metadata_key;
Get_S3 (24, metadata_key, "metadata_key");
int32u metadata_segment_size=((BigEndian2int16u(Buffer+Buffer_Offset+(size_t)Element_Size-Data_BS_Remain()/8)^metadata_key)>>2)&0x3FF;
if (Data_BS_Remain()<((size_t)metadata_segment_size+1)*bit_depth) //+1 for CRC
return; //There is a problem
int8u* Temp=Descrambled_Buffer+(size_t)Element_Size-Data_BS_Remain()/8;
for (int16u Pos=0; Pos<metadata_segment_size+1; Pos++)
int24u2BigEndian(Temp+Pos*2, BigEndian2int24u(Temp+Pos*2)^metadata_key);
}
break;
default : ;
}
}
size_t metadata_segment_BitCountAfter=Data_BS_Remain();
int16u metadata_segment_size;
Skip_S1( 4, "metadata_revision_id");
Get_S2 (10, metadata_segment_size, "metadata_segment_size");
metadata_segment_BitCountAfter-=metadata_segment_size*bit_depth;
Get_S1 ( 6, program_config, "program_config"); Param_Info1(DolbyE_ChannelPositions[program_config]);
Get_S1 ( 4, frame_rate_code, "frame_rate_code"); Param_Info3(Mpegv_frame_rate[frame_rate_code], " fps", 3);
Info_S1( 4, original_frame_rate_code, "original_frame_rate_code"); Param_Info3(Mpegv_frame_rate[original_frame_rate_code], " fps", 3);
Skip_S2(16, "frame_count");
Element_Begin1("SMPTE_time_code");
int8u Frames_Units, Frames_Tens, Seconds_Units, Seconds_Tens, Minutes_Units, Minutes_Tens, Hours_Units, Hours_Tens;
bool DropFrame;
Skip_S1(4, "BG8");
Skip_S1(4, "BG7");
Skip_SB( "BGF2 / Field Phase");
Skip_SB( "BGF1");
Get_S1 (2, Hours_Tens, "Hours (Tens)");
Get_S1 (4, Hours_Units, "Hours (Units)");
Skip_S1(4, "BG6");
Skip_S1(4, "BG5");
Skip_SB( "BGF0 / BGF2");
Get_S1 (3, Minutes_Tens, "Minutes (Tens)");
Get_S1 (4, Minutes_Units, "Minutes (Units)");
Skip_S1(4, "BG4");
Skip_S1(4, "BG3");
Skip_SB( "FP - Field Phase / BGF0");
Get_S1 (3, Seconds_Tens, "Seconds (Tens)");
Get_S1 (4, Seconds_Units, "Seconds (Units)");
Skip_S1(4, "BG2");
Skip_S1(4, "BG1");
Skip_SB( "CF - Color fame");
Get_SB ( DropFrame, "DP - Drop frame");
Get_S1 (2, Frames_Tens, "Frames (Tens)");
Get_S1 (4, Frames_Units, "Frames (Units)");
if (Hours_Tens<3)
{
int64u TimeCode=(int64u)(Hours_Tens *10*60*60*1000
+ Hours_Units *60*60*1000
+ Minutes_Tens *10*60*1000
+ Minutes_Units *60*1000
+ Seconds_Tens *10*1000
+ Seconds_Units *1000
+ (Mpegv_frame_rate[frame_rate_code]?float64_int32s((Frames_Tens*10+Frames_Units)*1000/Mpegv_frame_rate[frame_rate_code]):0));
Element_Info1(Ztring().Duration_From_Milliseconds(TimeCode));
//TimeCode
if (SMPTE_time_code_StartTimecode==(int64u)-1)
SMPTE_time_code_StartTimecode=TimeCode;
}
Element_End0();
bool evolution_data_exists;
Get_SB ( evolution_data_exists, "evolution_data_exists");
Skip_S1( 7, "metadata_reserved_bits");
for (int8u Channel=0; Channel<DolbyE_Channels[program_config]; Channel++)
{
Get_S2 (10, channel_subsegment_size[Channel], "channel_subsegment_size");
channel_subsegment_sizes[Channel][channel_subsegment_size[Channel]]++;
}
if (!Mpegv_frame_rate_type[frame_rate_code])
Get_S1 ( 8, metadata_extension_segment_size, "metadata_extension_segment_size");
else
metadata_extension_segment_size=0;
Get_S1 ( 8, meter_segment_size, "meter_segment_size");
for (int8u Program=0; Program<DolbyE_Programs[program_config]; Program++)
{
Element_Begin1("per program");
int8u description_text;
Get_S1 ( 8, description_text, "description_text"); Element_Info1(description_text);
Info_S1( 2, bandwidth_id, "bandwidth_id"); Element_Info1(bandwidth_id);
if (description_text && Program>=description_text_Values.size())
description_text_Values.resize(Program+1);
switch (description_text)
{
case 0x00: // No text
if (Program<description_text_Values.size())
{
description_text_Values[Program].Previous.clear();
description_text_Values[Program].Current.clear();
}
break;
case 0x02: // STX
description_text_Values[Program].Current.clear();
description_text_Values[Program].Current.push_back(description_text);
break;
case 0x03: // ETX
if (!description_text_Values[Program].Current.empty() && description_text_Values[Program].Current[0]==0x02)
description_text_Values[Program].Previous= description_text_Values[Program].Current.substr(1);
else
description_text_Values[Program].Previous.clear();
description_text_Values[Program].Current.clear();
break;
default: if (description_text>=0x20 && description_text<=0x7E)
description_text_Values[Program].Current.push_back(description_text);
}
Element_End0();
}
for (int8u Channel=0; Channel<DolbyE_Channels[program_config]; Channel++)
{
Element_Begin1("per channel");
Info_S1( 4, revision_id, "revision_id"); Element_Info1(revision_id);
Info_SB( bitpool_type, "bitpool_type");
Info_S2(10, begin_gain, "begin_gain"); Element_Info1(begin_gain);
Info_S2(10, end_gain, "end_gain"); Element_Info1(end_gain);
Element_End0();
}
for(;;)
{
Element_Begin1("metadata_subsegment");
int16u metadata_subsegment_length;
int8u metadata_subsegment_id;
Get_S1 ( 4, metadata_subsegment_id, "metadata_subsegment_id");
if (metadata_subsegment_id==0)
{
Element_End0();
break;
}
Get_S2 (12, metadata_subsegment_length, "metadata_subsegment_length");
size_t End=Data_BS_Remain()-metadata_subsegment_length;
switch (metadata_subsegment_id)
{
case 1 : ac3_metadata_subsegment(true); break;
case 2 : ac3_metadata_subsegment(false); break;
default: Skip_BS(metadata_subsegment_length, "metadata_subsegment (unknown)");
}
if (Data_BS_Remain()>End)
Skip_BS(Data_BS_Remain()-End, "unknown");
Element_End0();
}
if (evolution_data_exists)
{
for (;;)
{
const size_t evolution_data_segment_id_Name_Size=2;
const char* const evolution_data_segment_id_Name[evolution_data_segment_id_Name_Size]=
{
"End",
"intelligent_loudness_evolution_data_segment",
};
Element_Begin1("evolution_data_segment");
int16u evolution_data_segment_length;
int8u evolution_data_segment_id;
Get_S1 ( 4, evolution_data_segment_id, "evolution_data_segment_id"); Param_Info1C(evolution_data_segment_id<evolution_data_segment_id_Name_Size, evolution_data_segment_id_Name[evolution_data_segment_id]);
if (!evolution_data_segment_id)
{
Element_End0();
break;
}
Get_S2 (12, evolution_data_segment_length, "evolution_data_segment_length");
size_t End=Data_BS_Remain()-evolution_data_segment_length;
switch (evolution_data_segment_id)
{
case 1: intelligent_loudness_evolution_data_segment(); break;
default: Skip_BS(evolution_data_segment_length, "evolution_data_segment (unknown)");
}
if (Data_BS_Remain()>End)
Skip_BS(Data_BS_Remain()-End, "unknown");
Element_End0();
}
}
if (Data_BS_Remain()>metadata_segment_BitCountAfter)
Skip_BS(Data_BS_Remain()-metadata_segment_BitCountAfter,"reserved_metadata_bits");
Skip_S3(bit_depth, "metadata_crc");
{
//CRC test
size_t Pos_End=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain();
size_t Pos_Begin=Pos_End-(metadata_segment_size+1)*bit_depth; //+1 for CRC
int8u BitSkip_Begin=Pos_Begin%8;
Pos_Begin/=8;
int8u BitSkip_End=0; // Pos_End%8; Looks like that the last bits must not be in the CRC computing
Pos_End/=8;
if (BitSkip_End)
Pos_End++;
int16u CRC=CRC_16_Compute(Buffer+Pos_Begin, Pos_End-Pos_Begin, BitSkip_Begin, BitSkip_End);
if (CRC)
{
// CRC is wrong
Param_Info1("metadata_crc NOK");
}
}
Element_End0();
}
//---------------------------------------------------------------------------
void File_DolbyE::guard_band()
{
int8u* NewBuffer=NULL;
size_t Buffer_Offset_Save;
size_t Buffer_Size_Save;
int64u Element_Offset_Save;
int64u Element_Size_Save;
Element_Begin1("guard_band (with data)");
int16u element_length;
int8u element_id;
bool escape_code_valid;
Skip_B2( "sync_word");
BS_Begin();
Skip_S1( 3, "reserved");
Get_SB ( escape_code_valid, "escape_code_valid");
if (escape_code_valid)
{
int16u escape_code;
Get_S2 (12, escape_code, "escape_code");
BS_End();
for (int64u i=Element_Offset; i+1<Element_Size; i++)
{
if ( Buffer[Buffer_Offset+i ] ==(escape_code>>4) && (Buffer[Buffer_Offset+i+1]>>4)==(escape_code&0x0F))
{
//0xABCD --> 0x078D
if (!NewBuffer)
{
NewBuffer=new int8u[Element_Size-Element_Offset];
memcpy(NewBuffer, Buffer+Buffer_Offset+Element_Offset, Element_Size-Element_Offset);
}
NewBuffer[i -Element_Offset]=0x07;
NewBuffer[i+1-Element_Offset]=(NewBuffer[i+1-Element_Offset]&0x0F)|0x80;
}
if ((Buffer[Buffer_Offset+i ]&0xF)==(escape_code>>8) && Buffer[Buffer_Offset+i+1] ==(escape_code&0xFF))
{
//0xABCD --> 0xA078
if (!NewBuffer)
{
NewBuffer=new int8u[Element_Size-Element_Offset];
memcpy(NewBuffer, Buffer+Buffer_Offset+Element_Offset, Element_Size-Element_Offset);
}
NewBuffer[i -Element_Offset]=(NewBuffer[i -Element_Offset]&0xF0);
NewBuffer[i+1-Element_Offset]=0x78;
}
}
if (NewBuffer)
{
Buffer=NewBuffer;
Buffer_Offset_Save=Buffer_Offset;
Buffer_Size_Save=Buffer_Offset;
Element_Offset_Save=Element_Offset;
Element_Size_Save=Element_Size;
File_Offset+=Buffer_Offset+Element_Offset;
Buffer_Offset=0;
Buffer_Size=Element_Size-Element_Offset;
Element_Offset=0;
Element_Size=Buffer_Size;
}
}
else
{
Skip_S2(12, "escape_code");
BS_End();
}
Get_B1 ( element_id, "element_id");
Get_B2 ( element_length, "element_length");
int64u After=Element_Offset+element_length;
switch (element_id)
{
case 0xBB: evo_frame(); break;
default: Skip_XX(element_length, "Unknown");
}
if (Element_Offset<After)
Skip_XX(After-Element_Offset, "Unknown");
else if (Element_Offset>After)
{
Param_Info1("Problem");
Element_Offset=After;
}
Skip_B2( "crc");
{
//CRC test
size_t Pos_End=Buffer_Offset+Element_Offset;
size_t Pos_Begin=Pos_End-(element_length+2); //+2 for CRC
int16u CRC=CRC_16_Compute(Buffer+Pos_Begin, Pos_End-Pos_Begin, 0, 0);
if (CRC)
{
// CRC is wrong
Param_Info1("crc NOK");
}
Element_End0();
int64u RemainingBytes=Element_Size-Element_Offset;
if (RemainingBytes && RemainingBytes<bit_depth/4)
{
bool HasContent=false;
size_t Offset=Buffer_Offset+(size_t)Element_Offset;
size_t Size=Buffer_Offset+(size_t)Element_Size;
for (; Offset<Size; Offset++)
if (Buffer[Offset])
HasContent=true;
if (!HasContent)
Skip_XX(Element_Size-Element_Offset, "Padding");
}
}
if (NewBuffer)
{
delete[] Buffer;
Buffer_Offset=Buffer_Offset_Save;
Buffer_Size=Buffer_Offset_Save;
Element_Offset=Element_Offset_Save;
Element_Size=Element_Size_Save;
File_Offset-=Buffer_Offset+Element_Offset;
}
}
//---------------------------------------------------------------------------
void File_DolbyE::intelligent_loudness_evolution_data_segment()
{
Element_Begin1("intelligent_loudness_evolution_data_segment");
for (int8u program=0; program<DolbyE_Programs[program_config]; program++)
{
Element_Begin1("per program");
Skip_S1(4, "loudness_reg_type");
Skip_SB( "dialogue_corrected");
Skip_S1(1, "loudness_corr_type");
Element_End0();
}
Element_End0();
}
//---------------------------------------------------------------------------
extern const char* Ac3_emdf_payload_id[16];
void File_DolbyE::evo_frame()
{
if (!Guardband_EMDF_PresentAndSize)
Guardband_EMDF_PresentAndSize=Element_Size;
Element_Begin1("evo_frame");
BS_Begin();
int8u evo_version, key_id;
Get_S1 (2, evo_version, "evo_version");
if (evo_version==3)
{
int32u evo_version32;
Get_V4 (2, evo_version32, "evo_version");
evo_version32+=3;
evo_version=(int8u)evo_version32;
}
if (evo_version)
{
Skip_BS(Data_BS_Remain(), "(Unparsed evo_frame data)");
Element_End0();
return;
}
Get_S1 (3, key_id, "key_id");
if (key_id==7)
Skip_V4(3, "key_id");
int32u payload_id = 0;
for(;;)
{
Element_Begin1("evo_payload");
Get_S4 (5, payload_id, "payload_id");
if (payload_id==0x1F)
{
int32u add;
Get_V4 (5, add, "payload_id");
payload_id += add;
}
if (payload_id<16)
Element_Info1(Ac3_emdf_payload_id[payload_id]);
if (!payload_id)
{
Element_End0();
break;
}
evo_payload_config();
int32u payload_size = 0;
Get_V4 (8, payload_size, "payload_size");
size_t payload_End=(Data_BS_Remain()>payload_size*8)?(Data_BS_Remain()-payload_size*8):0;
Element_Begin1("payload");
switch (payload_id)
{
case 11: object_audio_metadata_payload(); break;
case 13: mgi_payload(); break;
default: Skip_BS(payload_size*8, "(Unknown)");
}
size_t Remaining=Data_BS_Remain()-payload_End;
if (Remaining && Remaining<8)
{
int8u padding;
Peek_S1(Remaining, padding);
if (!padding)
Skip_S1(Remaining, "padding");
}
if (Data_BS_Remain()>payload_End)
{
Skip_BS(Data_BS_Remain()-payload_End, "(Unparsed payload bytes)");
}
else if (Data_BS_Remain()<payload_End)
{
//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()>=payload_End)
Skip_BS(Data_BS_Remain()-payload_End, "(Problem during emdf_payload parsing)");
else
Skip_BS(Data_BS_Remain(), "(Problem during payload parsing, going to end directly)");
Element_End0();
Element_End0();
break;
}
Element_End0();
Element_End0();
}
evo_protection();
BS_End();
Element_End0();
}
//---------------------------------------------------------------------------
void File_DolbyE::evo_payload_config()
{
Element_Begin1("payload_config");
bool timestamp_present;
TEST_SB_GET (timestamp_present, "timestamp_present");
Skip_V4(11, "timestamp");
TEST_SB_END();
TEST_SB_SKIP( "duration_present");
Skip_V4(11, "duration");
TEST_SB_END();
TEST_SB_SKIP( "group_id_present");
Skip_V4(2, "group_id");
TEST_SB_END();
TEST_SB_SKIP( "codec_specific_id_present");
Skip_S1(8, "codec_specific_id");
TEST_SB_END();
bool dont_transcode;
Get_SB(dont_transcode, "dont_transcode");
if (!dont_transcode)
{
bool now_or_never = false;
if (!timestamp_present)
{
Get_SB (now_or_never, "now_or_never");
if (now_or_never)
{
Skip_SB( "create_duplicate");
Skip_SB( "remove_duplicate");
}
}
if (timestamp_present || now_or_never)
{
Skip_S1(5, "priority");
Skip_S1(2, "tight_coupling");
}
}
Element_End0();
}
//---------------------------------------------------------------------------
void File_DolbyE::evo_protection()
{
Element_Begin1("protection");
int8u len_primary, len_second;
Get_S1(2, len_primary, "protection_length_primary");
Get_S1(2, len_second, "protection_length_secondary");
switch (len_primary)
{
case 0: len_primary = 0; break;
case 1: len_primary = 8; break;
case 2: len_primary = 32; break;
case 3: len_primary = 128; break;
default:; //Cannot append, read only 2 bits
};
switch (len_second)
{
case 0: len_second = 0; break;
case 1: len_second = 8; break;
case 2: len_second = 32; break;
case 3: len_second = 128; break;
default:; //Cannot append, read only 2 bits
};
Skip_BS(len_primary, "protection_bits_primary");
if (len_second)
Skip_BS(len_primary, "protection_bits_secondary");
Element_End0();
}
//---------------------------------------------------------------------------
void File_DolbyE::object_audio_metadata_payload()
{
nonstd_bed_channel_assignment_masks.clear();
ObjectElements.clear();
Element_Begin1("object_audio_metadata_payload");
int8u oa_md_version_bits;
Get_S1 (2, oa_md_version_bits, "oa_md_version_bits");
if (oa_md_version_bits == 0x3)
{
int8u oa_md_version_bits_ext;
Get_S1 (3, oa_md_version_bits_ext, "oa_md_version_bits_ext");
oa_md_version_bits += oa_md_version_bits_ext;
}
int8u object_count_bits;
Get_S1 (5, object_count_bits, "object_count_bits");
if (object_count_bits==0x1F)
{
int8u object_count_bits_ext;
Get_S1 (7, object_count_bits_ext, "object_count_bits_ext");
object_count_bits=0x1F+object_count_bits_ext;
}
object_count=object_count_bits+1;
Param_Info2(object_count, " objects");
program_assignment();
bool b_alternate_object_data_present;
Get_SB(b_alternate_object_data_present, "b_alternate_object_data_present");
int8u oa_element_count_bits;
Get_S1(4, oa_element_count_bits, "oa_element_count_bits");
if (oa_element_count_bits==0xF)
{
Get_S1(5, oa_element_count_bits, "oa_element_count_bits_ext");
oa_element_count_bits+=0xF;
}
for (int8u i=0; i<oa_element_count_bits; i++)
oa_element_md(b_alternate_object_data_present);
Element_End0();
}
void File_DolbyE::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_masks.push_back(1<<3);
b_object_in_bed_or_isf.push_back(true);
}
}
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");
int32u nonstd_bed_channel_assignment_mask;
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
{
int32u nonstd_bed_channel_assignment_mask;
Get_S3 (17, nonstd_bed_channel_assignment_mask, "nonstd_bed_channel_assignment_mask");
}
Param_Info1(AC3_nonstd_bed_channel_assignment_mask_ChannelLayout(nonstd_bed_channel_assignment_mask));
nonstd_bed_channel_assignment_masks.push_back(nonstd_bed_channel_assignment_mask);
size_t BedChannelCount=BedChannelConfiguration_ChannelCount(nonstd_bed_channel_assignment_mask);
b_object_in_bed_or_isf.resize(b_object_in_bed_or_isf.size()+BedChannelCount, true);
}
else
b_object_in_bed_or_isf.push_back(true);
Element_End0();
}
}
if (content_description_mask & 0x2)
{
int8u intermediate_spatial_format_idx;
Get_S1 (3, intermediate_spatial_format_idx, "intermediate_spatial_format_idx");
b_object_in_bed_or_isf.resize(b_object_in_bed_or_isf.size()+intermediate_spatial_format_object_count[intermediate_spatial_format_idx], true);
}
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=0x1F+num_dynamic_objects_bits_ext;
}
num_dynamic_objects_bits++;
Param_Info2(object_count-num_dynamic_objects_bits, " static objects");
Param_Info2(num_dynamic_objects_bits, " dynamic objects");
b_object_in_bed_or_isf.resize(b_object_in_bed_or_isf.size()+num_dynamic_objects_bits, false);
}
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()");
Skip_S1(padding, "padding");
}
}
Element_End0();
}
void File_DolbyE::oa_element_md(bool b_alternate_object_data_present)
{
Element_Begin1("oa_element_md");
int8u oa_element_id_idx;
int32u oa_element_size_bits;
Get_S1 (4, oa_element_id_idx, "oa_element_id_idx");
Get_V4 (4, 4, oa_element_size_bits, "oa_element_size_bits");
oa_element_size_bits++;
oa_element_size_bits*=8;
int32u b_alternate_object_data_present_Reduced=b_alternate_object_data_present*4+1;
if (oa_element_size_bits<b_alternate_object_data_present_Reduced || oa_element_size_bits>Data_BS_Remain())
{
Skip_BS(oa_element_size_bits, "?");
Element_End0();
return;
}
oa_element_size_bits-=b_alternate_object_data_present_Reduced;
if (b_alternate_object_data_present)
Skip_S1(4, "alternate_object_data_id_idx");
Skip_SB( "b_discard_unknown_element");
size_t End=Data_BS_Remain()-oa_element_size_bits;
switch (oa_element_id_idx)
{
case 1: object_element(); break;
default: Skip_BS(oa_element_size_bits, "oa_element");
}
if (Data_BS_Remain()>End)
Skip_BS(Data_BS_Remain()-End, "padding");
Element_End0();
}
void File_DolbyE::object_element()
{
Element_Begin1("object_element");
int8u num_obj_info_blocks_bits;
md_update_info(num_obj_info_blocks_bits);
bool b_reserved_data_not_present;
Get_SB (b_reserved_data_not_present, "b_reserved_data_not_present");
if (!b_reserved_data_not_present)
Skip_S1(5, "reserved");
for (int8u i=0; i<object_count; i++)
object_data(i, num_obj_info_blocks_bits);
Element_End0();
}
void File_DolbyE::md_update_info(int8u& num_obj_info_blocks_bits)
{
Element_Begin1("md_update_info");
int8u sample_offset_code;
Get_S1 (2, sample_offset_code, "sample_offset_code");
switch (sample_offset_code)
{
case 1 : Skip_S1(2, "sample_offset_idx"); break;
case 2 : Skip_S1(5, "sample_offset_bits"); break;
default:;
}
Get_S1 (3, num_obj_info_blocks_bits, "num_obj_info_blocks_bits");
for (int8u blk=0; blk<=num_obj_info_blocks_bits; blk++)
block_update_info();
Element_End0();
}
void File_DolbyE::block_update_info()
{
Element_Begin1("block_update_info");
int8u block_offset_factor_bits, ramp_duration_code;
Get_S1 (6, block_offset_factor_bits, "block_offset_factor_bits");
Get_S1 (2, ramp_duration_code, "ramp_duration_code");
switch (ramp_duration_code)
{
case 3 :
{
bool b_use_ramp_duration_idx;
Get_SB (b_use_ramp_duration_idx, "b_use_ramp_duration_idx");
if (b_use_ramp_duration_idx)
Skip_S1( 4, "ramp_duration_idx");
else
Skip_S1(11, "ramp_duration_bits");
}
break;
default:;
}
Element_End0();
}
void File_DolbyE::object_data(int8u obj_idx, int8u num_obj_info_blocks_bits)
{
ObjectElements.resize(ObjectElements.size()+1);
ObjectElements[ObjectElements.size()-1].Alts.resize(num_obj_info_blocks_bits+1);
Element_Begin1("object_data");
for (int8u blk=0; blk<=num_obj_info_blocks_bits; blk++)
object_info_block(obj_idx, blk);
Element_End0();
}
void File_DolbyE::object_info_block(int8u obj_idx, int8u blk)
{
Element_Begin1("object_info_block");
int8u object_basic_info_status_idx, object_render_info_status_idx;
bool b_object_not_active;
Get_SB (b_object_not_active, "b_object_not_active");
if (b_object_not_active)
object_basic_info_status_idx=0;
else if (!blk)
object_basic_info_status_idx=1;
else
Get_S1 (2, object_basic_info_status_idx, "object_basic_info_status_idx");
if (object_basic_info_status_idx&1) // 1 or 3
object_basic_info(object_basic_info_status_idx>>1, blk); // Use bit 1
else
{
dyn_object& D=ObjectElements[ObjectElements.size()-1];
dyn_object::dyn_object_alt& A=D.Alts[blk];
A.obj_gain_db=INT8_MAX;
}
if (b_object_not_active || (obj_idx<b_object_in_bed_or_isf.size() && b_object_in_bed_or_isf[obj_idx]))
object_render_info_status_idx=0;
else if (!blk)
object_render_info_status_idx=1;
else
Get_S1 (2, object_render_info_status_idx, "object_render_info_status_idx");
if (object_render_info_status_idx&1) // 1 or 3
object_render_info(object_render_info_status_idx>>1, blk); // Use bit 1
else
{
dyn_object& D=ObjectElements[ObjectElements.size()-1];
dyn_object::dyn_object_alt& A=D.Alts[blk];
A.pos3d_x_bits=(int8u)-1;
}
bool b_additional_table_data_exists;
Get_SB (b_additional_table_data_exists, "b_additional_table_data_exists");
if (b_additional_table_data_exists)
{
int8u additional_table_data_size_bits;
Get_S1(4, additional_table_data_size_bits, "additional_table_data_size_bits");
additional_table_data_size_bits++;
additional_table_data_size_bits*=8;
Skip_BS(additional_table_data_size_bits, "additional_table_data");
}
Element_End0();
}
void File_DolbyE::object_basic_info(int8u object_basic_info_array, int8u blk)
{
Element_Begin1("object_basic_info");
if (!object_basic_info_array) // object_basic_info_array is "reuse" info at this point
object_basic_info_array=3; // 2x 1
else
Get_S1 (2, object_basic_info_array, "object_basic_info[]");
dyn_object& D=ObjectElements[ObjectElements.size()-1];
dyn_object::dyn_object_alt& A=D.Alts[blk];
if (object_basic_info_array>>1) // bit 1
{
int8u object_gain_idx;
Get_S1 (2, object_gain_idx, "object_gain_idx");
switch (object_gain_idx)
{
case 0 :
A.obj_gain_db=0;
break;
case 1 :
A.obj_gain_db=INT8_MIN;
break;
case 2 :
{
int8u object_gain_bits;
Get_S1 (6, object_gain_bits, "object_gain_bits");
A.obj_gain_db=(object_gain_bits<15?15:14)-object_gain_bits;
}
break;
default:
if (ObjectElements.size()>=2)
A.obj_gain_db=ObjectElements[ObjectElements.size()-2].Alts[blk].obj_gain_db;
else
A.obj_gain_db=0;
}
}
else
A.obj_gain_db=INT8_MAX;
if (object_basic_info_array&1) // bit 0
{
bool b_default_object_priority;
Get_SB ( b_default_object_priority, "b_default_object_priority");
if (!b_default_object_priority)
Skip_S1(5, "b_default_object_priority");
}
Element_End0();
}
void File_DolbyE::object_render_info(int8u object_render_info_array, int8u blk)
{
Element_Begin1("object_render_info");
if (!object_render_info_array) // object_render_info_array is "reuse" info at this point
object_render_info_array=0xF; // 4x 1
else
Get_S1 (4, object_render_info_array, "object_render_info[]");
dyn_object& D=ObjectElements[ObjectElements.size()-1];
dyn_object::dyn_object_alt& A=D.Alts[blk];
if (object_render_info_array&1) // bit 0
{
bool b_differential_position_specified;
if (!blk)
b_differential_position_specified=0;
else
Get_SB(b_differential_position_specified, "b_differential_position_specified");
if (b_differential_position_specified)
{
Skip_S1(3, "diff_pos3D_X_bits");
Skip_S1(3, "diff_pos3D_Y_bits");
Skip_S1(3, "diff_pos3D_Z_bits");
A.pos3d_x_bits=(int8u)-1; // Not supported
}
else
{
bool b_object_distance_specified;
Get_S1 (6, A.pos3d_x_bits, "pos3d_x_bits"); Param_Info3(mgi_bitstream_val_to_Q15(A.pos3d_x_bits, 6)/32768.0*100, "%", 0);
Get_S1 (6, A.pos3d_y_bits, "pos3d_y_bits"); Param_Info3(mgi_bitstream_val_to_Q15(A.pos3d_y_bits, 6)/32768.0*100, "%", 0);
Get_SB ( A.pos3d_z_sig, "pos3d_z_sig");
Get_S1 (4, A.pos3d_z_bits, "pos3d_z_bits"); Param_Info3(mgi_bitstream_pos_z_to_Q15(A.pos3d_z_sig, A.pos3d_z_bits)/32768.0*100, "%", 0);
Get_SB ( b_object_distance_specified, "b_object_distance_specified");
if (b_object_distance_specified)
{
bool b_object_at_infinity;
Get_SB ( b_object_at_infinity, "b_object_at_infinity");
if (!b_object_at_infinity)
Skip_S1(4, "distance_factor_idx");
}
}
}
else
A.pos3d_x_bits=(int8u)-1;
A.hp_render_mode=(int8u)-1;
if ((object_render_info_array>>1)&1) // bit 1
{
Skip_S1(3, "zone_constraints_idx");
Skip_SB( "b_enable_elevation");
}
if ((object_render_info_array>>2)&1) // bit 2
{
int8u object_size_idx;
Get_S1 (2, object_size_idx, "object_size_idx");
switch (object_size_idx)
{
case 1:
{
Skip_S1(5, "object_size_bits");
}
break;
case 2:
{
Skip_S1(5, "object_width_bits");
Skip_S1(5, "object_depth_bits");
Skip_S1(5, "object_height_bits");
}
break;
default:;
}
}
if (object_render_info_array>>3) // bit 3
{
bool b_object_use_screen_ref;
Get_SB ( b_object_use_screen_ref, "b_object_use_screen_ref");
if (b_object_use_screen_ref)
{
Skip_S1(3, "screen_factor_bits");
Skip_S1(2, "depth_factor_idx");
}
Skip_SB( "b_object_snap");
}
Element_End0();
}
int8u bits_needed(size_t value)
{
if (!value)
return 0;
int8u res = 0;
while (value) {
res += 1;
value >>= 1;
}
return res;
}
void File_DolbyE::mgi_payload()
{
DynObjects.clear();
BedInstances.clear();
Presets.clear();
substream_mappings.clear();
Element_Begin1("mgi_payload");
size_t BS_Start=Data_BS_Remain();
int8u mgi_version, num_presets_m1, num_dyn_objects, num_bed_instances;
bool program_id_available, is_substream_mapping_present, mini_mixgraph_extension_present, mini_mixgraph_description_present;
Get_S1 (2, mgi_version, "mgi_version");
if (mgi_version ==3)
{
int32u mgi_version32;
Get_V4 (2, mgi_version32, "mgi_version");
mgi_version32+=3;
mgi_version=(int8u)mgi_version32;
}
if (mgi_version!=5)
{
Skip_BS(1, "(Unparsed mgi_payload data)"); //TODO: exact count of bits
Element_End0();
return;
}
Get_SB (program_id_available, "program_id_available");
Get_SB (is_substream_mapping_present, "is_substream_mapping_present");
Get_SB (mini_mixgraph_extension_present, "mini_mixgraph_extension_present");
Get_SB (mini_mixgraph_description_present, "mini_mixgraph_description_present");
if (program_id_available)
{
Skip_S1( 3, "program_uuid_segment_number");
Skip_S2(16, "program_uuid_segment");
}
{
size_t ToPadd=(BS_Start-Data_BS_Remain())%8;
if (ToPadd<8)
Skip_BS(8-ToPadd, "byte_align");
}
Skip_S2(16, "short_program_id");
Get_S1 (4, num_presets_m1, "num_presets_m1");
Get_S1 (7, num_dyn_objects, "num_dyn_objects");
Get_S1 (4, num_bed_instances, "num_bed_instances");
DynObjects.resize(num_dyn_objects);
for (int8u i=0; i<num_dyn_objects; i++)
{
dyn_object& D=DynObjects[i];
Element_Begin1("dyn_object");
int32u num_dyn_obj_alt_md;
Get_V4 (2, num_dyn_obj_alt_md, "num_dyn_obj_alt_md");
Get_S1 (2, D.sound_category, "sound_category"); Param_Info1(sound_category_Values[D.sound_category]);
D.Alts.resize(num_dyn_obj_alt_md);
for (int32u j=0; j<num_dyn_obj_alt_md; j++)
{
dyn_object::dyn_object_alt& A=D.Alts[j];
Element_Begin1("dyn_obj_alt_md");
int32u object_info_mask, object_info_size_bytes;
Get_V4 (3, object_info_mask, "object_info_mask");
//Get_V4 (3, object_info_size_bytes, "object_info_size_bytes"); //TODO
Get_S4 (4, object_info_size_bytes, "object_info_size_bytes, variable_bits ignored");
object_info_size_bytes=4;
size_t Begin=Data_BS_Remain();
if (object_info_size_bytes)
{
if (object_info_mask & 0x1)
{
int8u dyn_obj_gain_db_bits;
Get_S1(6, dyn_obj_gain_db_bits, "dyn_obj_gain_db_bits");
if (dyn_obj_gain_db_bits==63)
A.obj_gain_db=INT8_MIN;
else
A.obj_gain_db=15-dyn_obj_gain_db_bits;
}
else
A.obj_gain_db=INT8_MAX;
if (object_info_mask & 0x2)
{
Get_S1 (6, A.pos3d_x_bits, "pos3d_x_bits"); Param_Info3(mgi_bitstream_val_to_Q15(A.pos3d_x_bits, 6)/32768.0*100, "%", 0);
Get_S1 (6, A.pos3d_y_bits, "pos3d_y_bits"); Param_Info3(mgi_bitstream_val_to_Q15(A.pos3d_y_bits, 6)/32768.0*100, "%", 0);
Get_SB ( A.pos3d_z_sig, "pos3d_z_sig");
Get_S1 (4, A.pos3d_z_bits, "pos3d_z_bits"); Param_Info3(mgi_bitstream_pos_z_to_Q15(A.pos3d_z_sig, A.pos3d_z_bits)/32768.0*100, "%", 0);
Element_Level--;
Element_Info1(Angles2String(mgi_bitstream_pos_ToAngles(mgi_bitstream_val_to_Q15(A.pos3d_x_bits, 6), mgi_bitstream_val_to_Q15(A.pos3d_y_bits, 6), mgi_bitstream_pos_z_to_Q15(A.pos3d_z_sig, A.pos3d_z_bits))));
Element_Level++;
}
else
A.pos3d_x_bits=(int8u)-1;
if (object_info_mask & 0x4)
{
Skip_SB( "hp_md_state");
Get_S1 (2, A.hp_render_mode, "hp_render_mode"); Param_Info1(hp_render_mode_Values[A.hp_render_mode]);
Skip_SB( "hp_headtrack_state");
}
else
A.hp_render_mode=(int8u)-1;
size_t Parsed=Begin-Data_BS_Remain();
int8u Padding=8-(Parsed%8);
Skip_BS(Padding, "padding");
}
Element_End0();
}
Element_End0();
}
BedInstances.resize(num_bed_instances);
for (int8u i=0; i<num_bed_instances; i++)
{
bed_instance& B=BedInstances[i];
Element_Begin1("bed_instance");
int32u num_bed_alt_md;
Get_V4 (2, num_bed_alt_md, "num_bed_alt_md");
B.Alts.resize(num_bed_alt_md);
for (int8u j=0; j<num_bed_alt_md; j++)
{
bed_instance::bed_alt& A=B.Alts[j];
Element_Begin1("bed_alt_md");
int32u bed_info_mask, bed_info_size_bytes;
Get_V4 (2, bed_info_mask, "bed_info_mask");
Get_V4 (2, bed_info_size_bytes, "bed_info_size_bytes");
size_t End=Data_BS_Remain()-bed_info_size_bytes*8;
if (bed_info_mask&1)
{
int8u bed_gain_db_bits;
Get_S1(6, bed_gain_db_bits, "bed_gain_db_bits");
A.bed_gain_db=15-bed_gain_db_bits;
}
else
A.bed_gain_db=INT8_MAX;
if (Data_BS_Remain()>End)
Skip_BS(Data_BS_Remain()-End, "padding");
Element_End0();
}
Element_End0();
}
Presets.resize(num_presets_m1 + 1);
for (int8u i=0; i<=num_presets_m1; i++)
{
preset& P=Presets[i];
Element_Begin1("preset");
int32u num_target_device_configs_m1;
Get_V4 (2, num_target_device_configs_m1, "num_target_device_configs_m1");
Get_V4 (2, P.default_target_device_config, "default_target_device_config"); Param_Info1(default_target_device_config_Value(P.default_target_device_config));
P.target_device_configs.resize(num_target_device_configs_m1+1);
for (int32u j=0; j<=num_target_device_configs_m1; j++)
{
preset::target_device_config& T=P.target_device_configs[j];
Element_Begin1("target_device_config");
Get_V4 (3, T.target_devices_mask, "target_devices_mask"); Param_Info1(default_target_device_config_Value(T.target_devices_mask));
for (int32u k=0; k<num_dyn_objects+num_bed_instances; k++)
{
Element_Begin1(k<num_dyn_objects?"object":"bed");
bool active;
Get_SB (active, k<num_dyn_objects?"object_active":"bed_active");
if (active)
{
int32u md_index;
size_t Size=k<num_dyn_objects?DynObjects[k].Alts.size():BedInstances[k-num_dyn_objects].Alts.size();
Get_S4 (bits_needed(Size+1), md_index, k<num_dyn_objects?"obj_md_index":"bed_md_index");
T.md_indexes.push_back(md_index);
}
else
T.md_indexes.push_back((int32u)-1);
Element_End0();
}
Element_End0();
}
TEST_SB_SKIP( "preset_extension");
int32u extension_size;
Get_V4 (4, extension_size, "extension_size");
Skip_BS(extension_size, "extension");
TEST_SB_END();
Element_End0();
}
substream_mappings.resize(num_dyn_objects+num_bed_instances);
if (is_substream_mapping_present)
{
Element_Begin1("substream_mapping");
for (int8u i=0; i<substream_mappings.size(); i++)
{
substream_mapping& S=substream_mappings[i];
Element_Begin1(i<num_dyn_objects?"dyn_object":"bed_instance");
bool standard_index;
Get_S1(4, S.substream_id, "substream_id");
Get_SB( standard_index, "standard_index");
if (standard_index)
Get_S4 (3, S.channel_index, "channel_index");
else
{
Get_S4(5, S.channel_index, "channel_index");
if (S.channel_index==0x1F)
{
Get_V4(3, S.channel_index, "channel_index");
S.channel_index+=0x1F;
}
}
Element_End0();
}
Element_End0();
}
int8u byte_align_Content=0;
{
size_t ToPadd=(BS_Start-Data_BS_Remain())%8;
if (ToPadd)
Get_S1(8-ToPadd, byte_align_Content, "byte_align");
}
if (mini_mixgraph_extension_present)
{
Element_Begin1("mini_mixgraph_extension");
TEST_SB_SKIP( "mgi_extension");
int32u extension_size;
Get_V4 (4, extension_size, "extension_size");
Skip_BS(extension_size, "extension");
TEST_SB_END();
Element_End0();
}
if (mini_mixgraph_description_present)
{
Element_Begin1("mini_mixgraph_description");
int32u desc_packet_idx, desc_pkt_size_bits;
if (!byte_align_Content)
{
Get_V4 (5, desc_packet_idx, "desc_packet_idx");
}
else
{
Skip_S1(6, "0x3F?");
desc_packet_idx = 30; //Not in spec. Bug in the stream here?
}
if (!desc_packet_idx)
{
Get_V4 (5, num_desc_packets_m1, "num_desc_packets_m1");
}
if (desc_packet_idx==num_desc_packets_m1)
{
Get_V4 (7, desc_pkt_size_bits, "desc_pkt_size_bits");
}
else
{
Get_V4 (4, desc_pkt_size_bits, "desc_pkt_size_bytes");
desc_pkt_size_bits<<=3; //bits to bytes
}
while (desc_pkt_size_bits)
{
int8u bits8=desc_pkt_size_bits>8?8:desc_pkt_size_bits;
int8u data;
Get_S1(bits8, data, "description_packet_data");
if (num_desc_packets_m1!=(int32u)-1)
description_packet_data.push_back(data<<(8-bits8));
desc_pkt_size_bits-=bits8;
}
if (desc_packet_idx==num_desc_packets_m1 && !description_packet_data.empty())
{
Presets_More.clear();
BitStream_Fast* BS_Save=BS;
BS=new BitStream_Fast(&*description_packet_data.begin(), description_packet_data.size()); //In bytes, we can not provide a precise count of bits
Element_Begin1("packet_description");
int8u preset_description_id_bits;
Get_S1(3, preset_description_id_bits, "preset_description_id_bits");
for (int8u i=0; i <=num_presets_m1; i++)
{
Skip_BS(preset_description_id_bits, "preset_description_id[i]");
}
TEST_SB_SKIP("preset_description_text_present");
Presets_More.resize(num_presets_m1+1);
for (int8u i=0; i<=num_presets_m1; i++)
{
preset_more& P=Presets_More[i];
int8u desc_text_len;
Get_S1(5, desc_text_len, "desc_text_len");
Element_Begin1("preset_description");
for (int8u j=0; j<desc_text_len; j++)
{
int8u preset_description_char;
Get_S1(8, preset_description_char, "preset_description_char");
P.description+=(char)preset_description_char;
}
if (Ztring().From_UTF8(P.description).empty())
P.description.clear(); // Problem while parsing
Element_Info1(P.description);
Element_End0();
}
TEST_SB_END();
Element_End0();
delete BS; BS=BS_Save;
description_packet_data.clear();
mini_mixgraph_description_present=false; //Indicates that the stream is ready for data filling
}
Element_End0();
{
size_t ToPadd=(BS_Start-Data_BS_Remain())%8;
if (ToPadd<8)
Skip_BS(8-ToPadd, "byte_align");
}
}
Element_End0();
}
//---------------------------------------------------------------------------
void File_DolbyE::Get_V4(int8u Bits, int8u MaxLoops, int32u& Info, const char* Name)
{
Info=0;
#if MEDIAINFO_TRACE
if (Trace_Activated)
{
int8u Count=0;
for (;;)
{
Info+=BS->Get4(Bits);
Count+=1+Bits;
if (!BS->GetB() || !(--MaxLoops))
break;
Info<<=Bits;
Info+=(1<<Bits);
}
Param(Name, Info, Count);
Param_Info(__T("(")+Ztring::ToZtring(Count)+__T(" bits)"));
}
else
#endif //MEDIAINFO_TRACE
{
for (;;)
{
Info+=BS->Get4(Bits);
if (!BS->GetB() || !(--MaxLoops))
break;
Info<<=Bits;
Info+=(1<<Bits);
}
}
}
//---------------------------------------------------------------------------
void File_DolbyE::Get_V4(int8u Bits, int32u& Info, const char* Name)
{
Info=0;
#if MEDIAINFO_TRACE
if (Trace_Activated)
{
int8u Count=0;
for (;;)
{
Info+=BS->Get4(Bits);
Count+=1+Bits;
if (!BS->GetB())
break;
Info<<=Bits;
Info+=(1<<Bits);
}
Param(Name, Info, Count);
Param_Info(__T("(")+Ztring::ToZtring(Count)+__T(" bits)"));
}
else
#endif //MEDIAINFO_TRACE
{
for (;;)
{
Info+=BS->Get4(Bits);
if (!BS->GetB())
break;
Info<<=Bits;
Info+=(1<<Bits);
}
}
}
//---------------------------------------------------------------------------
void File_DolbyE::Skip_V4(int8u Bits, const char* Name)
{
#if MEDIAINFO_TRACE
if (Trace_Activated)
{
int32u Info=0;
int8u Count=0;
for (;;)
{
Info+=BS->Get4(Bits);
Count+=1+Bits;
if (!BS->GetB())
break;
Info<<=Bits;
Info+=(1<<Bits);
}
Param(Name, Info, Count);
Param_Info(__T("(")+Ztring::ToZtring(Count)+__T(" bits)"));
}
else
#endif //MEDIAINFO_TRACE
{
for (;;)
{
BS->Skip(Bits);
if (!BS->GetB())
break;
}
}
}
//---------------------------------------------------------------------------
void File_DolbyE::audio_segment()
{
//Parsing
Element_Begin1("audio_segment");
#if MEDIAINFO_TRACE
//CRC test
size_t Pos_Begin=0;
#endif //MEDIAINFO_TRACE
for (int8u Channel=0; Channel<DolbyE_Channels[program_config]; Channel++)
{
if ((Channel%(DolbyE_Channels[program_config]/2))==0 && key_present)
{
int16u audio_subsegment_size=0;
for (int8u ChannelForSize=0; ChannelForSize<DolbyE_Channels[program_config]/2; ChannelForSize++)
audio_subsegment_size+=channel_subsegment_size[((Channel<DolbyE_Channels[program_config]/2)?0:(DolbyE_Channels[program_config]/2))+ChannelForSize];
if (Data_BS_Remain()<(audio_subsegment_size+1)*(size_t)bit_depth)
return; //There is a problem
//We must change the buffer
switch (bit_depth)
{
case 16 :
{
int16u audio_subsegment_key;
Get_S2 (16, audio_subsegment_key, (Channel+1==DolbyE_Channels[program_config])?"audio_subsegment1_key":"audio_subsegment0_key");
int8u* Temp=Descrambled_Buffer+(size_t)Element_Size-Data_BS_Remain()/8;
for (int16u Pos=0; Pos<audio_subsegment_size+1; Pos++)
int16u2BigEndian(Temp+Pos*2, BigEndian2int16u(Temp+Pos*2)^audio_subsegment_key);
}
break;
case 20 :
{
int32u audio_subsegment_key;
Get_S3 (20, audio_subsegment_key, (Channel+1==DolbyE_Channels[program_config])?"audio_subsegment1_key":"audio_subsegment0_key");
Descramble_20bit(audio_subsegment_key, audio_subsegment_size);
}
break;
default : ;
}
}
#if MEDIAINFO_TRACE
//CRC test
if ((Channel%(DolbyE_Channels[program_config]/2))==0)
Pos_Begin=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain();
#endif //MEDIAINFO_TRACE
Element_Begin1(__T("Channel ")+Ztring::ToZtring(Channel));
Element_Info1(Ztring::ToZtring(channel_subsegment_size[Channel])+__T(" words"));
Skip_BS(channel_subsegment_size[Channel]*bit_depth, "channel_subsegment");
Element_End0();
if ((Channel%(DolbyE_Channels[program_config]/2))==DolbyE_Channels[program_config]/2-1)
{
Skip_S3(bit_depth, (Channel+1==DolbyE_Channels[program_config])?"audio_subsegment1_crc":"audio_subsegment0_crc");
#if MEDIAINFO_TRACE
//CRC test
size_t Pos_End=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain();
int8u BitSkip_Begin=Pos_Begin%8;
Pos_Begin/=8;
int8u BitSkip_End=0; // Pos_End%8; Looks like that the last bits must not be in the CRC computing
Pos_End/=8;
if (BitSkip_End)
Pos_End++;
int16u CRC=CRC_16_Compute(Buffer+Pos_Begin, Pos_End-Pos_Begin, BitSkip_Begin, BitSkip_End);
if (CRC)
{
//CRC is wrong
Param_Info1("NOK");
}
#endif //MEDIAINFO_TRACE
}
}
Element_End0();
}
//---------------------------------------------------------------------------
void File_DolbyE::metadata_extension_segment()
{
//Parsing
Element_Begin1("metadata_extension_segment");
if (key_present)
{
if (Data_BS_Remain()<((size_t)metadata_extension_segment_size+1)*(size_t)bit_depth) //+1 for CRC
return; //There is a problem
//We must change the buffer
switch (bit_depth)
{
case 16 :
{
int16u metadata_extension_segment_key;
Get_S2 (16, metadata_extension_segment_key, "metadata_extension_segment_key");
int8u* Temp=Descrambled_Buffer+(size_t)Element_Size-Data_BS_Remain()/8;
for (int16u Pos=0; Pos<metadata_extension_segment_size+1; Pos++)
int16u2BigEndian(Temp+Pos*2, BigEndian2int16u(Temp+Pos*2)^metadata_extension_segment_key);
}
break;
case 20 :
{
int32u metadata_extension_segment_key;
Get_S3 (20, metadata_extension_segment_key, "metadata_extension_segment_key");
Descramble_20bit(metadata_extension_segment_key, metadata_extension_segment_size);
}
break;
default : ;
}
}
#if MEDIAINFO_TRACE
//CRC test
size_t Pos_Begin=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain();
#endif //MEDIAINFO_TRACE
size_t metadata_extension_segment_BitCountAfter=Data_BS_Remain();
metadata_extension_segment_BitCountAfter-=metadata_extension_segment_size*bit_depth;
if (metadata_extension_segment_size)
{
for(;;)
{
Element_Begin1("metadata_extension_subsegment");
int16u metadata_extension_subsegment_length;
int8u metadata_extension_subsegment_id;
Get_S1 ( 4, metadata_extension_subsegment_id, "metadata_extension_subsegment_id");
if (metadata_extension_subsegment_id==0)
{
Element_End0();
break;
}
Get_S2 (12, metadata_extension_subsegment_length, "metadata_extension_subsegment_length");
switch (metadata_extension_subsegment_id)
{
default: Skip_BS(metadata_extension_subsegment_length,"metadata_extension_subsegment (unknown)");
}
Element_End0();
}
Param_Info1(metadata_extension_segment_BitCountAfter);
Param_Info1(Data_BS_Remain());
Param_Info1(Data_BS_Remain()-metadata_extension_segment_BitCountAfter);
if (Data_BS_Remain()>metadata_extension_segment_BitCountAfter)
Skip_BS(Data_BS_Remain()-metadata_extension_segment_BitCountAfter,"reserved_metadata_extension_bits");
}
Skip_S3(bit_depth, "metadata_extension_crc");
#if MEDIAINFO_TRACE
//CRC test
size_t Pos_End=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain();
int8u BitSkip_Begin=Pos_Begin%8;
Pos_Begin/=8;
int8u BitSkip_End=0; // Pos_End%8; Looks like that the last bits must not be in the CRC computing
Pos_End/=8;
if (BitSkip_End)
Pos_End++;
int16u CRC=CRC_16_Compute(Buffer+Pos_Begin, Pos_End-Pos_Begin, BitSkip_Begin, BitSkip_End);
if (CRC)
{
//CRC is wrong
Param_Info1("NOK");
}
#endif //MEDIAINFO_TRACE
Element_End0();
}
//---------------------------------------------------------------------------
void File_DolbyE::audio_extension_segment()
{
//Parsing
Element_Begin1("audio_extension_segment");
#if MEDIAINFO_TRACE
//CRC test
size_t Pos_Begin=0;
#endif //MEDIAINFO_TRACE
for (int8u Channel=0; Channel<DolbyE_Channels[program_config]; Channel++)
{
if ((Channel%(DolbyE_Channels[program_config]/2))==0 && key_present)
{
int16u audio_extension_subsegment_size=0;
for (int8u ChannelForSize=0; ChannelForSize<DolbyE_Channels[program_config]/2; ChannelForSize++)
audio_extension_subsegment_size+=channel_subsegment_size[((Channel<DolbyE_Channels[program_config]/2)?0:(DolbyE_Channels[program_config]/2))+ChannelForSize];
if (Data_BS_Remain()<((size_t)audio_extension_subsegment_size+1)*(size_t)bit_depth)
return; //There is a problem
//We must change the buffer
switch (bit_depth)
{
case 16 :
{
int16u audio_extension_subsegment_key;
Get_S2 (16, audio_extension_subsegment_key, (Channel+1==DolbyE_Channels[program_config])?"audio_extension_subsegment1_key":"audio_extension_subsegment0_key");
int8u* Temp=Descrambled_Buffer+(size_t)Element_Size-Data_BS_Remain()/8;
for (int16u Pos=0; Pos<audio_extension_subsegment_size+1; Pos++)
int16u2BigEndian(Temp+Pos*2, BigEndian2int16u(Temp+Pos*2)^audio_extension_subsegment_key);
}
break;
case 20 :
{
int32u audio_extension_subsegment_key;
Get_S3 (20, audio_extension_subsegment_key, (Channel+1==DolbyE_Channels[program_config])?"audio_extension_subsegment1_key":"audio_extension_subsegment0_key");
Descramble_20bit(audio_extension_subsegment_key, audio_extension_subsegment_size);
}
break;
default : ;
}
}
#if MEDIAINFO_TRACE
//CRC test
if ((Channel%(DolbyE_Channels[program_config]/2))==0)
Pos_Begin=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain();
#endif //MEDIAINFO_TRACE
Element_Begin1(__T("Channel ")+Ztring::ToZtring(Channel));
Element_Info1(Ztring::ToZtring(channel_subsegment_size[Channel])+__T(" words"));
Skip_BS(channel_subsegment_size[Channel]*bit_depth, "channel_subsegment");
Element_End0();
if ((Channel%(DolbyE_Channels[program_config]/2))==DolbyE_Channels[program_config]/2-1)
{
Skip_S3(bit_depth, (Channel+1==DolbyE_Channels[program_config])?"audio_extension_subsegment1_crc":"audio_extension_subsegment0_crc");
#if MEDIAINFO_TRACE
//CRC test
size_t Pos_End=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain();
int8u BitSkip_Begin=Pos_Begin%8;
Pos_Begin/=8;
int8u BitSkip_End=0; // Pos_End%8; Looks like that the last bits must not be in the CRC computing
Pos_End/=8;
if (BitSkip_End)
Pos_End++;
int16u CRC=CRC_16_Compute(Buffer+Pos_Begin, Pos_End-Pos_Begin, BitSkip_Begin, BitSkip_End);
if (CRC)
{
//CRC is wrong
Param_Info1("NOK");
}
#endif //MEDIAINFO_TRACE
}
}
Element_End0();
}
//---------------------------------------------------------------------------
void File_DolbyE::meter_segment()
{
//Parsing
Element_Begin1("meter_segment");
if (key_present)
{
if (Data_BS_Remain()<((size_t)meter_segment_size+1)*(size_t)bit_depth) //+1 for CRC
return; //There is a problem
//We must change the buffer
switch (bit_depth)
{
case 16 :
{
int16u meter_segment_key;
Get_S2 (16, meter_segment_key, "meter_segment_key");
int8u* Temp=Descrambled_Buffer+(size_t)Element_Size-Data_BS_Remain()/8;
for (int16u Pos=0; Pos<meter_segment_size+1; Pos++)
int16u2BigEndian(Temp+Pos*2, BigEndian2int16u(Temp+Pos*2)^meter_segment_key);
}
break;
case 20 :
{
int32u meter_segment_key;
Get_S3 (20, meter_segment_key, "meter_segment_key");
Descramble_20bit(meter_segment_key, meter_segment_size);
}
break;
default : ;
}
}
size_t meter_segment_BitCountAfter=Data_BS_Remain();
meter_segment_BitCountAfter-=meter_segment_size*bit_depth;
for (int8u Channel=0; Channel<DolbyE_Channels[program_config]; Channel++)
Skip_S2(10, "peak_meter");
for (int8u Channel=0; Channel<DolbyE_Channels[program_config]; Channel++)
Skip_S2(10, "rms_meter");
if (Data_BS_Remain()>meter_segment_BitCountAfter)
Skip_BS(Data_BS_Remain()>meter_segment_BitCountAfter, "reserved_meter_bits");
Skip_S3(bit_depth, "meter_crc");
#if MEDIAINFO_TRACE
//CRC test
size_t Pos_End=Buffer_Offset*8+(size_t)Element_Size*8-Data_BS_Remain();
size_t Pos_Begin=Pos_End-(meter_segment_size+1)*bit_depth; //+1 for CRC
int8u BitSkip_Begin=Pos_Begin%8;
Pos_Begin/=8;
int8u BitSkip_End=0; // Pos_End%8; Looks like that the last bits must not be in the CRC computing
Pos_End/=8;
if (BitSkip_End)
Pos_End++;
int16u CRC=CRC_16_Compute(Buffer+Pos_Begin, Pos_End-Pos_Begin, BitSkip_Begin, BitSkip_End);
if (CRC)
{
//CRC is wrong
Param_Info1("NOK");
}
#endif //MEDIAINFO_TRACE
Element_End0();
}
//---------------------------------------------------------------------------
void File_DolbyE::ac3_metadata_subsegment(bool xbsi)
{
for (int8u program=0; program<DolbyE_Programs[program_config]; program++)
{
Element_Begin1("per program");
Skip_S1(5, "ac3_datarate");
Skip_S1(3, "ac3_bsmod");
Skip_S1(3, "ac3_acmod");
Skip_S1(2, "ac3_cmixlev");
Skip_S1(2, "ac3_surmixlev");
Skip_S1(2, "ac3_dsurmod");
Skip_S1(1, "ac3_lfeon");
Skip_S1(5, "ac3_dialnorm");
Skip_S1(1, "ac3_langcode");
Skip_S1(8, "ac3_langcod");
Skip_S1(1, "ac3_audprodie");
Skip_S1(5, "ac3_mixlevel");
Skip_S1(2, "ac3_roomtyp");
Skip_S1(1, "ac3_copyrightb");
Skip_S1(1, "ac3_origbs");
if (xbsi)
{
Skip_S1(1, "ac3_xbsi1e");
Skip_S1(2, "ac3_dmixmod");
Skip_S1(3, "ac3_ltrtcmixlev");
Skip_S1(3, "ac3_ltrtsurmixlev");
Skip_S1(3, "ac3_lorocmixlev");
Skip_S1(3, "ac3_lorosurmixlev");
Skip_S1(1, "ac3_xbsi2e");
Skip_S1(2, "ac3_dsurexmod");
Skip_S1(2, "ac3_dheadphonmod");
Skip_S1(1, "ac3_adconvtyp");
Skip_S1(8, "ac3_xbsi2");
Skip_S1(1, "ac3_encinfo");
}
else
{
Skip_S1(1, "ac3_timecode1e");
Skip_S2(14, "ac3_timecode1");
Skip_S1(1, "ac3_timecode2e");
Skip_S2(14, "ac3_timecode2");
}
Skip_S1(1, "ac3_hpfon");
Skip_S1(1, "ac3_bwlpfon");
Skip_S1(1, "ac3_lfelpfon");
Skip_S1(1, "ac3_sur90on");
Skip_S1(1, "ac3_suratton");
Skip_S1(1, "ac3_rfpremphon");
Skip_S1(1, "ac3_compre");
Skip_S1(8, "ac3_compr1");
Skip_S1(1, "ac3_dynrnge");
Skip_S1(8, "ac3_dynrng1");
Skip_S1(8, "ac3_dynrng2");
Skip_S1(8, "ac3_dynrng3");
Skip_S1(8, "ac3_dynrng4");
Element_End0();
}
for (int8u program=0; program<DolbyE_Programs[program_config]; program++)
{
Element_Begin1("per program");
bool ac3_addbsie;
Get_SB ( ac3_addbsie, "ac3_addbsie");
if (ac3_addbsie)
{
int8u ac3_addbsil;
Get_S1 (6, ac3_addbsil, "ac3_addbsil");
for (int8u Pos=0; Pos<ac3_addbsil+1; Pos++)
Skip_S1(8, "ac3_addbsi[x]");
}
Element_End0();
}
}
//***************************************************************************
// Helpers
//***************************************************************************
//---------------------------------------------------------------------------
void File_DolbyE::Descramble_20bit (int32u key, int16u size)
{
int8u* Temp=Descrambled_Buffer+(size_t)Element_Size-Data_BS_Remain()/8;
int64u keys=(((int64u)key)<<20)|key;
bool Half;
if (Data_BS_Remain()%8)
{
Temp--;
int24u2BigEndian(Temp, BigEndian2int24u(Temp)^(key));
Half=true;
}
else
Half=false;
for (int16u Pos=0; Pos<size-(Half?1:0); Pos+=2)
int40u2BigEndian(Temp+(Half?3:0)+Pos*5/2, BigEndian2int40u(Temp+(Half?3:0)+Pos*5/2)^keys);
if ((size-((size && Half)?1:0))%2==0)
int24u2BigEndian(Temp+(Half?3:0)+(size-((size && Half)?1:0))*5/2, BigEndian2int24u(Temp+(Half?3:0)+(size-((size && Half)?1:0))*5/2)^(key<<4));
}
//***************************************************************************
// C++
//***************************************************************************
} //NameSpace
#endif //MEDIAINFO_DOLBYE_YES
↑ V1028 Possible overflow. Consider casting operands, not the result.
↑ V547 Expression 'ToPadd < 8' is always true.
↑ V547 Expression 'ToPadd < 8' is always true.
↑ V638 A terminal null is present inside a string. The '\0xC2' characters were encountered. Probably meant: '\xC2'.
↑ V1020 The function exited without calling the 'Element_End' function. Check lines: 1727, 1714.
↑ V1020 The function exited without calling the 'Element_End' function. Check lines: 1741, 1714.
↑ V1020 The function exited without calling the 'Element_End' function. Check lines: 1753, 1714.
↑ V1020 The function exited without calling the 'BS_End' function. Check lines: 2115, 2101.
↑ V1020 The function exited without calling the 'Element_End' function. Check lines: 3115, 3101.
↑ V1020 The function exited without calling the 'Element_End' function. Check lines: 3186, 3182.
↑ V1020 The function exited without calling the 'Element_End' function. Check lines: 3287, 3273.
↑ V1020 The function exited without calling the 'Element_End' function. Check lines: 3358, 3354.
↑ V1048 The 'len_primary' variable was assigned the same value.
↑ V1048 The 'len_second' variable was assigned the same value.
↑ V547 Expression 'Summary.empty()' is always true.
↑ V547 Expression 'Summary2.empty()' is always true.
↑ V547 Expression 'Summary.empty()' is always true.
↑ V547 Expression 'Summary2.empty()' is always true.
↑ V547 Expression 'BitSkip_End' is always false.
↑ V547 Expression 'object_info_size_bytes' is always true.
↑ V614 Potentially uninitialized variable 'nonstd_bed_channel_assignment_mask' used. Consider checking the first actual argument of the 'push_back' function.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: Azimuth, Elevation.
↑ V1037 Two or more case-branches perform the same actions. Check lines: 174, 175
↑ V1051 Consider checking for misprints. It's possible that the 'metadata_extension_segment_BitCountAfter' should be checked here.
↑ V525 The code contains the collection of similar blocks. Check items '1', '6', '8', '8' in lines 172, 173, 174, 175.
↑ V525 The code contains the collection of similar blocks. Check items 'CC2', 'CC3', 'CC3' in lines 1506, 1507, 1508.
↑ V525 The code contains the collection of similar blocks. Check items '2', '3', '3' in lines 1781, 1788, 1795.
↑ V525 The code contains the collection of similar blocks. Check items '1', '2', '3', '3', '3', '3', '1', '2', '2', '1', '8', '1' in lines 3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448, 3449, 3450.
↑ V550 An odd precise comparison. It's probably better to use a comparison with defined precision: fabs(Mpegv_frame_rate[frame_rate_code]) > Epsilon.
↑ V550 An odd precise comparison. It's probably better to use a comparison with defined precision: fabs(Mpegv_frame_rate[frame_rate_code]) > Epsilon.
↑ V550 An odd precise comparison. It's probably better to use a comparison with defined precision: fabs(Mpegv_frame_rate[frame_rate_code]) > Epsilon.
↑ V550 An odd precise comparison. It's probably better to use a comparison with defined precision: fabs(Mpegv_frame_rate[frame_rate_code]) > Epsilon.
↑ V624 The constant 3.14159265359 is being utilized. The resulting value could be inaccurate. Consider using the M_PI constant from
↑ V624 The constant 3.14159265359 is being utilized. The resulting value could be inaccurate. Consider using the M_PI constant from
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: object_count, channel_subsegment_size, program_config, metadata_extension_segment_size, meter_segment_size, frame_rate_code, ...
↑ V808 'A' object of 'basic_string' type was created but was not utilized.
↑ V832 It's better to use '= default;' syntax instead of empty constructor body.
↑ V808 'evolution_data_segment_id_Name' array was declared but was not utilized.
↑ V823 Decreased performance. Object may be created in-place in the 'GroupPos[j]' container. Consider replacing methods: 'push_back' -> 'emplace_back'.
↑ V823 Decreased performance. Object may be created in-place in the 'GroupNum[j]' container. Consider replacing methods: 'push_back' -> 'emplace_back'.
↑ V807 Decreased performance. Consider creating a reference to avoid using the 'description_text_Values[Program].Current' expression repeatedly.