/* 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.
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Information about DVD objects
// (.ifo files on DVD-Video)
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Mainly from http://dvd.sourceforge.net/dvdinfo/ifo.html
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//---------------------------------------------------------------------------
// Pre-compilation
#include "MediaInfo/PreComp.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "MediaInfo/Setup.h"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include <vector>
using namespace std;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#if defined(MEDIAINFO_DVDV_YES)
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "MediaInfo/Multiple/File_Dvdv.h"
//---------------------------------------------------------------------------
namespace MediaInfoLib
{
//---------------------------------------------------------------------------
static const char* IFO_VTS_Category[]=
{
"Normal",
"Karaoke",
};
static const char* IFO_Format_V[]=
{
"MPEG Video",
"MPEG Video",
"",
"",
};
static const char* IFO_Format_Version_V[]=
{
"Version 1",
"Version 2",
"",
"",
};
static const char* IFO_CodecV[]=
{
"MPEG-1V",
"MPEG-2V",
"",
"",
};
static const char* IFO_Standard[]=
{
"NTSC",
"PAL",
"",
"",
};
static const float32 IFO_AspectRatio[]=
{
(float32)1.333,
(float32)0.000,
(float32)0.000,
(float32)1.778,
};
static const char* IFO_BitRate_Mode[]=
{
"VBR",
"CBR",
};
static const size_t IFO_Width[]=
{720, 704, 352, 352, 0, 0, 0, 0};
static const size_t IFO_Height[4][8]=
{{480, 480, 480, 240, 0, 0, 0, 0}, //NTSC
{576, 576, 576, 288, 0, 0, 0, 0}, //PAL
{ 0, 0, 0, 0, 0, 0, 0, 0}, //Unknown
{ 0, 0, 0, 0, 0, 0, 0, 0}, //Unknown
};
static const float64 IFO_FrameRate[]=
{29.970, 25.000};
static const char* IFO_Format_A[]=
{
"AC-3",
"",
"MPEG Audio",
"MPEG Audio",
"PCM",
"",
"DTS",
"SDDS",
};
static const char* IFO_Format_Profile_A[]=
{
"",
"",
"Version 1",
"Version 2",
"",
"",
"",
"",
};
static const char* IFO_CodecA[]=
{
"AC3",
"",
"MPEG-1A",
"MPEG-2A",
"LPCM (Big Endian)",
"",
"DTS",
"SDDS",
};
static const char* IFO_ModeA[]=
{
"",
"Karaoke",
"Surround",
"",
};
static const char* IFO_ResolutionA[]=
{
"16",
"20",
"24",
"DRC",
};
static const int16u IFO_SamplingRate[]=
{48000, 0, 0, 0, 0, 0, 0, 0};
static const char* IFO_Language_MoreA[]=
{
"",
"",
"For visually impaired",
"Director's comments",
"Director's comments",
"",
"",
"",
};
static const char* IFO_Format_T[]=
{
"RLE",
"",
"",
"",
"",
"",
"",
"",
};
static const char* IFO_Resolution_T[]=
{
"2",
"",
"",
"",
"",
"",
"",
"",
};
static const char* IFO_CodecT[]=
{
"2-bit RLE",
"",
"",
"",
"",
"",
"",
"",
};
static const char* IFO_Language_MoreT[]=
{
"",
"Normal",
"Large",
"Children",
"",
"",
"Large",
"Children",
"",
"Forced",
"",
"",
"",
"Director comments",
"Director comments large",
"Director comments children",
};
static const size_t IFO_PlaybackTime_FrameRate[]=
{1, 25, 1, 30};
static const char* IFO_MenuType[]=
{
"",
"",
"",
"root",
"sub-picture",
"audio",
"angle",
"PTT (chapter)",
"",
"",
"",
"",
"",
"",
"",
"",
};
//---------------------------------------------------------------------------
extern const char* AC3_ChannelPositions[];
extern const char* AC3_ChannelPositions2[];
//***************************************************************************
// Constructor/Destructor
//***************************************************************************
//---------------------------------------------------------------------------
File_Dvdv::File_Dvdv()
:File__Analyze()
{
//Temp
VTS_Attributes_AreHere=false;
Program_Pos=0;
Time_Pos=0;
}
//***************************************************************************
// Streams management
//***************************************************************************
//---------------------------------------------------------------------------
void File_Dvdv::Streams_Finish()
{
//Purge what is not needed anymore
if (!File_Name.empty()) //Only if this is not a buffer, with buffer we can have more data
Sectors.clear();
}
//***************************************************************************
// Buffer
//***************************************************************************
//---------------------------------------------------------------------------
void File_Dvdv::FileHeader_Parse()
{
//Parsing
int64u Identifier;
int32u Type;
Get_C8 (Identifier, "Identifier");
Get_C4 (Type, "Type");
FILLING_BEGIN();
//Identifier
if (Identifier!=CC8("DVDVIDEO"))
{
Reject("DVD Video");
return;
}
Accept("DVD Video");
Fill(Stream_General, 0, General_Format, "DVD Video");
//Versions
switch (Type)
{
case Dvdv::VMG : VMG(); break;
case Dvdv::VTS : VTS(); break;
default :
Reject("DVD Video");
return;
}
FILLING_END();
}
//---------------------------------------------------------------------------
//***************************************************************************
// Elements
//***************************************************************************
#define SUBELEMENT(_ELEMENT) \
{ \
Element_Begin1(#_ELEMENT); \
_ELEMENT(); \
Element_End0(); \
} \
//---------------------------------------------------------------------------
void File_Dvdv::VMG()
{
int32u Sector_Pointer_LastSector, Sector_Pointer_TT_SRPT, Sector_Pointer_VMGM_PGCI_UT, Sector_Pointer_VMG_PTL_MAIT, Sector_Pointer_VMG_VTS_ATRT, Sector_Pointer_VMG_TXTDT_MG, Sector_Pointer_VMGM_C_ADT, Sector_Pointer_VMGM_VOBU_ADMAP;
int16u Version, Audio_Count, Text_Count;
Element_Info1("DVD Video - VMG");
Element_Begin1("Header");
Info_B4(LastSector, "Last sector of VMG set (last sector of BUP)"); Param_Info2((LastSector+1)*2048, " bytes");
Skip_XX(12, "Unknown");
Get_B4 (Sector_Pointer_LastSector, "last sector of IFO");
Get_B2 (Version, "version number"); Param_Info1(Ztring::ToZtring((Version&0x00F0)>>4)+__T(".")+Ztring::ToZtring(Version&0x000F));
Info_B4(Category, "VMG category");
Skip_B2( "number of volumes");
Skip_B2( "volume number");
Skip_B1( "side ID");
Skip_XX(19, "Unknown");
Skip_B2( "number of title sets");
Skip_Local(32, "Provider ID");
Skip_B8( "VMG POS");
Skip_XX(24, "Unknown");
Skip_B4( "end byte address of VMGI_MAT");
Skip_B4( "start address of FP_PGC (First Play program chain)");
Skip_XX(56, "Unknown");
Info_B4(Sector_Pointer_Menu, "start sector of Menu VOB");
Get_B4 (Sector_Pointer_TT_SRPT, "sector pointer to TT_SRPT (table of titles)");
Get_B4 (Sector_Pointer_VMGM_PGCI_UT, "sector pointer to VMGM_PGCI_UT (Menu Program Chain table)");
Get_B4 (Sector_Pointer_VMG_PTL_MAIT, "sector pointer to VMG_PTL_MAIT (Parental Management masks)");
Get_B4 (Sector_Pointer_VMG_VTS_ATRT, "sector pointer to VMG_VTS_ATRT (copies of VTS audio/sub-picture attributes)");
Get_B4 (Sector_Pointer_VMG_TXTDT_MG, "sector pointer to VMG_TXTDT_MG (text data)");
Get_B4 (Sector_Pointer_VMGM_C_ADT, "sector pointer to VMGM_C_ADT (menu cell address table)");
Get_B4 (Sector_Pointer_VMGM_VOBU_ADMAP, "sector pointer to VMGM_VOBU_ADMAP (menu VOBU address map)");
Skip_XX(32, "Unknown");
Element_End0();
//-VTSM
VTS_Attributes_AreHere=true;
Element_Begin1("VMGM (VMG for Menu)");
Element_Begin1("Video streams");
Element_Info2(1, " streams");
SUBELEMENT(Video)
Element_End0();
Element_Begin1("Audio streams");
Get_B2 (Audio_Count, "number of audio streams in VMGM_VOBS");
Element_Info2(Audio_Count, " streams");
for (int16u Pos=0; Pos<8; Pos++)
{
if (Pos<Audio_Count)
SUBELEMENT(Audio)
else
Skip_XX(8, "Reserved for Audio");
}
Skip_XX(16, "Unknown");
Element_End0();
Element_Begin1("Text streams");
Get_B2 (Text_Count, "number of subpicture streams in VMGM_VOBS");
Element_Info2(Text_Count, " streams");
for (int16u Pos=0; Pos<1; Pos++)
{
if (Pos<Text_Count)
SUBELEMENT(Text)
else
Skip_XX(6, "Reserved for Text");
}
Skip_XX(164, "Unknown");
Element_End0();
Element_End0();
Skip_XX(2048-Element_Offset, "Junk");
//Filling
FILLING_BEGIN();
Fill(Stream_General, 0, General_Format_Profile, "Menu");
if (Version>0x001F)
return;
Sectors.resize(Sector_Pointer_LastSector+1);
if (Sector_Pointer_TT_SRPT<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_TT_SRPT]=Sector_TT_SRPT;
if (Sector_Pointer_VMGM_PGCI_UT<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VMGM_PGCI_UT]=Sector_VMGM_PGCI_UT;
if (Sector_Pointer_VMG_PTL_MAIT<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VMG_PTL_MAIT]=Sector_VMG_PTL_MAIT;
if (Sector_Pointer_VMG_VTS_ATRT<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VMG_VTS_ATRT]=Sector_VMG_VTS_ATRT;
if (Sector_Pointer_VMG_TXTDT_MG<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VMG_TXTDT_MG]=Sector_VMG_TXTDT_MG;
if (Sector_Pointer_VMGM_C_ADT<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VMGM_C_ADT]=Sector_VMGM_C_ADT;
if (Sector_Pointer_VMGM_VOBU_ADMAP<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VMGM_VOBU_ADMAP]=Sector_VMGM_VOBU_ADMAP;
FILLING_END();
}
//---------------------------------------------------------------------------
void File_Dvdv::VTS()
{
//Parsing
int32u Sector_Pointer_LastSector, Sector_Pointer_VTS_PTT_SRPT, Sector_Pointer_VTS_PGCI, Sector_Pointer_VTSM_PGCI_UT, Sector_Pointer_VTS_TMAPTI, Sector_Pointer_VTSM_C_ADT, Sector_Pointer_VTSM_VOBU_ADMAP, Sector_Pointer_VTS_C_ADT, Sector_Pointer_VTS_VOBU_ADMAP;
int16u Version, Audio_Count, Text_Count;
Element_Info1("DVD Video - VTS (Video Title Set)");
Element_Begin1("Header");
Info_B4(LastSector, "Last sector of Title set (last sector of BUP)"); Param_Info2((LastSector+1)*2048, " bytes");
Skip_XX(12, "Unknown");
Get_B4 (Sector_Pointer_LastSector, "last sector of IFO");
Get_B2 (Version, "version number"); Param_Info1(Ztring::ToZtring((Version&0x00F0)>>4)+__T(".")+Ztring::ToZtring(Version&0x000F));
Info_B4(Category, "VTS category");
#if MEDIAINFO_TRACE
if (Category<2) Param_Info1(IFO_VTS_Category[Category]);
#endif //MEDIAINFO_TRACE
Skip_XX(90, "Unknown");
Skip_B4( "end byte address of VTS_MAT");
Skip_XX(60, "Unknown");
Info_B4(StartSector_Menu, "start sector of Menu VOB"); Param_Info2((StartSector_Menu+1)*2048, " bytes");
Info_B4(StartSector_Title, "start sector of Title Vob"); Param_Info2((StartSector_Title+1)*2048, " bytes");
Get_B4 (Sector_Pointer_VTS_PTT_SRPT, "sector pointer to VTS_PTT_SRPT (Table of Titles and Chapters)");
Get_B4 (Sector_Pointer_VTS_PGCI, "sector pointer to VTS_PGCI (Title Program Chain table)");
Get_B4 (Sector_Pointer_VTSM_PGCI_UT, "sector pointer to VTSM_PGCI_UT (Menu Program Chain table)");
Get_B4 (Sector_Pointer_VTS_TMAPTI, "sector pointer to VTS_TMAPTI (Time map)");
Get_B4 (Sector_Pointer_VTSM_C_ADT, "sector pointer to VTSM_C_ADT (Menu cell address table)");
Get_B4 (Sector_Pointer_VTSM_VOBU_ADMAP, "sector pointer to VTSM_VOBU_ADMAP(menu VOBU address map)");
Get_B4 (Sector_Pointer_VTS_C_ADT, "sector pointer to VTS_C_ADT (Title set cell address table)");
Get_B4 (Sector_Pointer_VTS_VOBU_ADMAP, "sector pointer to VTS_VOBU_ADMAP (Title set VOBU address map)");
Skip_XX(24, "Unknown");
Element_End0();
//-VTSM
Element_Begin1("VTSM (VTS for Menu, Vob 0)");
Element_Begin1("Video streams");
Element_Info2(1, " streams");
SUBELEMENT(Video)
Element_End0();
Element_Begin1("Audio streams");
Get_B2 (Audio_Count, "number of audio streams in VTSM_VOBS");
Element_Info2(Audio_Count, " streams");
for (int16u Pos=0; Pos<8; Pos++)
{
if (Pos<Audio_Count)
SUBELEMENT(Audio)
else
Skip_XX(8, "Reserved for Audio");
}
Skip_XX(16, "Unknown");
Element_End0();
Element_Begin1("Text streams");
Get_B2 (Text_Count, "number of subpicture streams in VTSM_VOBS");
Element_Info2(Text_Count, " streams");
for (int16u Pos=0; Pos<1; Pos++)
{
if (Pos<Text_Count)
SUBELEMENT(Text)
else
Skip_XX(6, "Reserved for Text");
}
Skip_XX(164, "Unknown");
Element_End0();
Element_End0();
//-VTS
VTS_Attributes_AreHere=true;
Element_Begin1("VTS (VTS for movie, Vob 1-9)");
Element_Begin1("Video streams");
Element_Info2(1, " streams");
SUBELEMENT(Video)
Element_End0();
Element_Begin1("Audio streams");
Get_B2 (Audio_Count, "number of audio streams in VMGM_VOBS");
Element_Info2(Audio_Count, " streams");
for (int16u Pos=0; Pos<8; Pos++)
{
if (Pos<Audio_Count)
SUBELEMENT(Audio)
else
Skip_XX(8, "Reserved for Audio");
}
Skip_XX(16, "Unknown");
Element_End0();
Element_Begin1("Text streams");
Get_B2 (Text_Count, "number of subpicture streams in VMGM_VOBS");
Element_Info2(Text_Count, " streams");
for (int16u Pos=0; Pos<32; Pos++)
{
if (Pos<Text_Count)
SUBELEMENT(Text)
else
Skip_XX(6, "Reserved for Text");
}
Skip_XX(2, "Unknown");
Element_End0();
Element_Begin1("MultiChannel Info");
Element_Info2(Audio_Count, " streams");
for (int16u Pos=0; Pos<8; Pos++)
{
if (Pos<Audio_Count)
SUBELEMENT(MultiChannel)
else
Skip_XX(24, "Reserved for multichannel extension");
}
Element_End0();
Element_End0();
Skip_XX(2048-Element_Offset, "Junk");
//Filling
FILLING_BEGIN();
Fill(Stream_General, 0, General_Format_Profile, "Program");
if (Version>0x001F)
return;
if (Sector_Pointer_LastSector==(int32u)-1 || Sector_Pointer_LastSector+1>File_Size/2048)
Sector_Pointer_LastSector=(int32u)(File_Size/2048);
Sectors.resize(Sector_Pointer_LastSector+1);
if (Sector_Pointer_VTS_PTT_SRPT<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VTS_PTT_SRPT]=Sector_VTS_PTT_SRPT;
if (Sector_Pointer_VTS_PGCI<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VTS_PGCI]=Sector_VTS_PGCI;
if (Sector_Pointer_VTSM_PGCI_UT<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VTSM_PGCI_UT]=Sector_VTSM_PGCI_UT;
if (Sector_Pointer_VTS_TMAPTI<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VTS_TMAPTI]=Sector_VTS_TMAPTI;
if (Sector_Pointer_VTSM_C_ADT<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VTSM_C_ADT]=Sector_VTSM_C_ADT;
if (Sector_Pointer_VTSM_VOBU_ADMAP<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VTSM_VOBU_ADMAP]=Sector_VTSM_VOBU_ADMAP;
if (Sector_Pointer_VTS_C_ADT<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VTS_C_ADT]=Sector_VTS_C_ADT;
if (Sector_Pointer_VTS_VOBU_ADMAP<=Sector_Pointer_LastSector)
Sectors[Sector_Pointer_VTS_VOBU_ADMAP]=Sector_VTS_VOBU_ADMAP;
FILLING_END();
}
//---------------------------------------------------------------------------
void File_Dvdv::Video()
{
//Parsing
int32u Codec, Standard, AspectRatio, Resolution, BitRate_Mode;
BS_Begin();
Get_BS (2, Codec, "Coding mode"); Param_Info1(IFO_CodecV[Codec]);
Get_BS (2, Standard, "Standard"); Param_Info1(IFO_Standard[Standard]);
Get_BS (2, AspectRatio, "Aspect ratio"); Param_Info1(IFO_AspectRatio[AspectRatio]);
Info_BS(1, Pan, "Automatic Pan/Scan"); Param_Info1(Pan?"No":"Yes");
Info_BS(1, Letter, "Automatic Letterbox"); Param_Info1(Letter?"No":"Yes");
Skip_BS(1, "CC for line 21 field 1 in GOP (NTSC only)");
Skip_BS(1, "CC for line 21 field 2 in GOP (NTSC only)");
Get_BS (3, Resolution, "Resolution"); Param_Info1(Ztring::ToZtring(IFO_Width[Resolution])+__T("x")+Ztring::ToZtring(IFO_Height[Standard][Resolution]));
Info_BS(1, Letterboxed, "Letterboxed"); Param_Info1(Letter?"Yes":"No");
Get_BS (1, BitRate_Mode, "Bitrate mode"); Param_Info1(IFO_BitRate_Mode[BitRate_Mode]);
Info_BS(1, Camera, "Camera/Film"); Param_Info1(Letter?"Film":"Camera");
BS_End();
//Filling
FILLING_BEGIN();
if (VTS_Attributes_AreHere)
{
Stream_Prepare(Stream_Video);
Fill(Stream_Video, StreamPos_Last, Video_Format, IFO_Format_V[Codec]);
Fill(Stream_Video, StreamPos_Last, Video_Format_Version, IFO_Format_Version_V[Codec]);
Fill(Stream_Video, StreamPos_Last, Video_Codec, IFO_CodecV[Codec]);
Fill(Stream_Video, StreamPos_Last, Video_Width, IFO_Width[Resolution]);
Fill(Stream_Video, StreamPos_Last, Video_Height, IFO_Height[Standard][Resolution]);
Fill(Stream_Video, StreamPos_Last, Video_DisplayAspectRatio, IFO_AspectRatio[AspectRatio], 3, true);
Fill(Stream_Video, StreamPos_Last, Video_FrameRate, IFO_FrameRate[Standard]);
Fill(Stream_Video, StreamPos_Last, Video_BitRate_Mode, IFO_BitRate_Mode[BitRate_Mode]);
Fill(Stream_Video, StreamPos_Last, General_ID, __T("224"));
Fill(Stream_Video, StreamPos_Last, General_ID_String, __T("224 (0xE0)"), Unlimited, true);
}
FILLING_END();
}
//---------------------------------------------------------------------------
void File_Dvdv::Audio()
{
//Parsing
Ztring Language;
int32u Codec, LanguageType, Mode, Resolution, SamplingRate, Channels;
int8u Language_Extension, ChannelsK=(int8u)-1;
BS_Begin();
Get_BS (3, Codec, "Coding mode"); Param_Info1(IFO_CodecA[Codec]);
Info_BS(1, MultiChannel, "Multichannel extension present"); Param_Info1(MultiChannel?"Yes":"No");
Get_BS (2, LanguageType, "Language type"); Param_Info1(LanguageType==1?"2CC":"Unknown");
Get_BS (2, Mode, "Application mode"); Param_Info1(IFO_ModeA[Mode]);
Get_BS (2, Resolution, "Resolution"); Param_Info1C((Codec==2 || Codec==3), IFO_ResolutionA[Resolution]); Param_Info1C((Codec==4), Mode?"DRC":"No DRC");
Get_BS (2, SamplingRate, "Sampling rate"); Param_Info1(Ztring::ToZtring(IFO_SamplingRate[SamplingRate]));
Get_BS (4, Channels, "Channels"); Param_Info2(Channels+1, " channels");
BS_End();
Get_UTF8(3, Language, "Language code");
if (!Language.empty() && Language[0]>=0x80)
Language.clear(); //this is 0xFF...
if (Language==__T("iw"))
Language=__T("he"); //Hebrew patch, is "iw" in DVDs
Get_B1 (Language_Extension, "Language extension"); Param_Info1C((Language_Extension<8), IFO_Language_MoreA[Language_Extension]);
Skip_B1( "Unknown");
switch (Mode)
{
case 1 : //Karaoke
{
BS_Begin();
Skip_BS(1, "Zero");
Get_S1 (3, ChannelsK, "Channels");
#ifdef MEDIAINFO_AC3_YES
Param_Info1(AC3_ChannelPositions[ChannelsK]);
#endif //MEDIAINFO_AC3_YES
Skip_BS(2, "Version");
Info_BS(1, MC, "MC intro present"); Param_Info1(MC?"Yes":"No");
Info_BS(1, Duet, "Duet"); Param_Info1(Duet?"Duet":"Solo");
BS_End();
}
break;
case 2 : //Surround
{
BS_Begin();
Skip_BS(4, "Reserved");
Info_BS(1, DolbyDecode, "Suitable for Dolby surround decoding"); Param_Info1(DolbyDecode?"Yes":"No");
Skip_BS(3, "Reserved");
BS_End();
}
break;
default:
{
Skip_B1( "Reserved");
}
}
//Filling
FILLING_BEGIN();
if (VTS_Attributes_AreHere)
{
Stream_Prepare(Stream_Audio);
Fill(Stream_Audio, StreamPos_Last, Audio_Format, IFO_Format_A[Codec]);
Fill(Stream_Audio, StreamPos_Last, Audio_Format_Profile, IFO_Format_Profile_A[Codec]);
Fill(Stream_Audio, StreamPos_Last, Audio_Codec, IFO_CodecA[Codec]);
Fill(Stream_Audio, StreamPos_Last, Audio_SamplingRate, IFO_SamplingRate[SamplingRate]);
Fill(Stream_Audio, StreamPos_Last, Audio_Channel_s_, Channels+1);
if (Codec==3)
Fill(Stream_Audio, StreamPos_Last, Audio_BitDepth, IFO_ResolutionA[Resolution]);
else if (Codec==4 && Mode)
Fill(Stream_Audio, StreamPos_Last, Audio_BitDepth, "DRC");
Fill(Stream_Audio, StreamPos_Last, Audio_Language, Language);
if (Language_Extension<8)
Fill(Stream_Audio, StreamPos_Last, Audio_Language_More, IFO_Language_MoreA[Language_Extension]);
#ifdef MEDIAINFO_AC3_YES
if (Codec==0 && ChannelsK!=(int8u)-1) //AC-3
{
Fill(Stream_Audio, 0, Audio_ChannelPositions, AC3_ChannelPositions[ChannelsK]);
Fill(Stream_Audio, 0, Audio_ChannelPositions_String2, AC3_ChannelPositions2[ChannelsK]);
}
#endif //MEDIAINFO_AC3_YES
}
FILLING_END();
}
//---------------------------------------------------------------------------
void File_Dvdv::Text()
{
//Parsing
Ztring Language;
int32u Codec, LanguageType;
int8u Language_Extension;
BS_Begin();
Get_BS (3, Codec, "Coding mode"); Param_Info1(IFO_CodecT[Codec]);
Skip_BS(3, "Reserved");
Get_BS (2, LanguageType, "Language type"); Param_Info1(LanguageType==1?"2CC":"Unknown");
BS_End();
Skip_B1( "Reserved");
Get_UTF8(3, Language, "Language code");
if (!Language.empty() && Language[0]>=0x80)
Language.clear(); //this is 0xFF...
if (Language==__T("iw"))
Language=__T("he"); //Hebrew patch, is "iw" in DVDs
Get_B1 (Language_Extension, "Language extension"); Param_Info1C((Language_Extension<16), IFO_Language_MoreT[Language_Extension]);
//Filling
FILLING_BEGIN();
if (VTS_Attributes_AreHere)
{
Stream_Prepare(Stream_Text);
Fill(Stream_Text, StreamPos_Last, Text_Format, IFO_Format_T[Codec]);
Fill(Stream_Text, StreamPos_Last, Text_BitDepth, IFO_Resolution_T[Codec]);
Fill(Stream_Text, StreamPos_Last, Text_Codec, IFO_CodecT[Codec]);
Fill(Stream_Text, StreamPos_Last, Text_Language, Language);
if (Language_Extension<16)
Fill(Stream_Text, StreamPos_Last, Text_Language_More, IFO_Language_MoreT[Language_Extension]);
}
FILLING_END();
}
//---------------------------------------------------------------------------
void File_Dvdv::MultiChannel()
{
//Parsing
BS_Begin();
Element_Begin1("ACH0");
Skip_BS(7, "Reserved");
Skip_BS(1, "ACH0 Guide Melody exists");
Element_End0();
Element_Begin1("ACH1");
Skip_BS(7, "Reserved");
Skip_BS(1, "ACH1 Guide Melody exists");
Element_End0();
Element_Begin1("ACH2");
Skip_BS(4, "Reserved");
Skip_BS(1, "ACH2 Guide Vocal 1 exists");
Skip_BS(1, "ACH2 Guide Vocal 2 exists");
Skip_BS(1, "ACH2 Guide Melody 1 exists");
Skip_BS(1, "ACH2 Guide Melody 2 exists");
Element_End0();
Element_Begin1("ACH3");
Skip_BS(4, "Reserved");
Skip_BS(1, "ACH3 Guide Vocal 1 exists");
Skip_BS(1, "ACH3 Guide Vocal 2 exists");
Skip_BS(1, "ACH3 Guide Melody A exists");
Skip_BS(1, "ACH3 Sound Effect A exists");
Element_End0();
Element_Begin1("ACH4");
Skip_BS(4, "Reserved");
Skip_BS(1, "ACH4 Guide Vocal 1 exists");
Skip_BS(1, "ACH4 Guide Vocal 2 exists");
Skip_BS(1, "ACH4 Guide Melody B exists");
Skip_BS(1, "ACH4 Sound Effect B exists");
Element_End0();
BS_End();
Skip_XX(19, "Unknown");
}
//***************************************************************************
// Buffer
//***************************************************************************
//---------------------------------------------------------------------------
void File_Dvdv::Header_Parse()
{
//Calculating
size_t Sector_Pos=(size_t)((File_Offset+Buffer_Offset)/2048);
size_t Sector_Count=1;
while (Sector_Pos+Sector_Count<Sectors.size() && Sectors[Sector_Pos+Sector_Count]==Sector_Nothing)
Sector_Count++;
//Filling
Header_Fill_Size(Sector_Count*2048);
}
//---------------------------------------------------------------------------
void File_Dvdv::Data_Parse()
{
//Parsing
size_t Sector_Pos=(size_t)((File_Offset+Buffer_Offset)/2048);
if (Sector_Pos>=Sectors.size())
{
Accept("DVD Video");
Finish("DVD Video");
return;
}
//Parsing
switch(Sectors[Sector_Pos])
{
case Sector_VTS_PTT_SRPT : VTS_PTT_SRPT(); break;
case Sector_VTS_PGCI : VTS_PGCI(); break;
case Sector_VTSM_PGCI_UT : VTSM_PGCI_UT(); break;
case Sector_VTS_TMAPTI : VTS_TMAPTI(); break;
case Sector_VTSM_C_ADT : VTSM_C_ADT(); break;
case Sector_VTSM_VOBU_ADMAP : VTSM_VOBU_ADMAP(); break;
case Sector_VTS_C_ADT : VTS_C_ADT(); break;
case Sector_VTS_VOBU_ADMAP : VTS_VOBU_ADMAP(); break;
case Sector_TT_SRPT : TT_SRPT(); break;
case Sector_VMGM_PGCI_UT : VMGM_PGCI_UT(); break;
case Sector_VMG_PTL_MAIT : VMG_PTL_MAIT(); break;
case Sector_VMG_VTS_ATRT : VMG_VTS_ATRT(); break;
case Sector_VMG_TXTDT_MG : VMG_TXTDT_MG(); break;
case Sector_VMGM_C_ADT : VMGM_C_ADT(); break;
case Sector_VMGM_VOBU_ADMAP : VMGM_VOBU_ADMAP(); break;
default : ;
}
}
//***************************************************************************
// Elements
//***************************************************************************
//---------------------------------------------------------------------------
void File_Dvdv::VTS_PTT_SRPT ()
{
Element_Name("Table of Titles and Chapters");
//Parsing
int32u Element_RealSize;
Element_Begin1("Header");
Skip_B2( "Count of elements");
Skip_B2( "Unknown");
Get_B4 (Element_RealSize, "End address");
Element_RealSize++; //Last byte
Element_End0();
Element_Begin1("Extra data");
int32u Offset;
Get_B4 (Offset, "Offset of first element");
int64u Extra_Size=Offset-Element_Offset;
if (Extra_Size>0)
Skip_XX(Extra_Size, "Extra data (Unknown)");
Element_End0();
//For each chapter
while (Element_Offset<Element_RealSize)
{
//VTS_PTT
int16u PGCN, PGN;
Element_Begin0();
Get_B2 (PGCN, "Program Chain (PGCN)");
Get_B2 (PGN, "Program (PGN)");
Element_Name("Chapter"); Element_Info1(Ztring::ToZtring(PGCN)); Element_Info1(Ztring::ToZtring(PGN));
Element_End0();
}
}
//---------------------------------------------------------------------------
void File_Dvdv::VTS_PGCI ()
{
Element_Name("Title Program Chain table");
//Parsing
int32u EndAddress;
Element_Begin1("Header");
int32u Offset;
Skip_B2( "Number of Program Chains");
Skip_B2( "Reserved");
Get_B4 (EndAddress, "End address");
if (EndAddress>=Element_Size)
EndAddress=(int32u)Element_Size-1;
Element_Begin1("PGC category");
BS_Begin();
Skip_BS(1, "entry PGC");
Skip_BS(7, "title number");
BS_End();
Skip_B1( "Unknown");
Skip_B2( "parental management mask");
Element_End0();
Get_B4 (Offset, "offset to VTS_PGC - relative to VTS_PGCI");
if (Offset-16>0)
Skip_XX(Offset-16, "Unknown");
Element_End0();
//For each Program
//DETAILLEVEL_SET(1.0);
while (Element_Offset<=EndAddress)
{
PGC(Offset, true);
}
}
//---------------------------------------------------------------------------
void File_Dvdv::VTSM_PGCI_UT ()
{
Element_Name("Menu Program Chain table");
//Parsing
int16u LU_Count;
Element_Begin1("Header");
int32u EndAddress, Offset;
int8u Flags;
Get_B2 (LU_Count, "Number of Language Units");
Skip_B2( "Reserved");
Get_B4 (EndAddress, "End address");
if (EndAddress>=Element_Size)
EndAddress=(int32u)Element_Size-1;
Skip_C3( "Language");
Get_B1 (Flags, "Menu existence flags");
Skip_Flags(Flags, 3, "PTT");
Skip_Flags(Flags, 4, "angle");
Skip_Flags(Flags, 5, "audio");
Skip_Flags(Flags, 6, "sub-picture");
Skip_Flags(Flags, 7, "root");
Get_B4 (Offset, "Offset to VTSM_LU relative to VTSM_PGCI_UT");
if (Offset-16>0)
Skip_XX(Offset-16, "Unknown");
Element_End0();
for (int16u LU_Pos=0; LU_Pos<LU_Count; LU_Pos++)
{
Element_Begin1("Language Unit");
int32u LU_Size;
int16u PGC_Count;
Element_Begin1("Header");
Get_B2 (PGC_Count, "Number of Program Chains");
Skip_B2( "Reserved");
Get_B4 (LU_Size, "end address (last byte of last PGC in this LU) relative to VTSM_LU");
LU_Size++; //Last byte
Element_Begin1("PGC category");
int32u EntryPGC;
BS_Begin();
Get_BS (1, EntryPGC, "Entry PGC");
Skip_BS(3, "Unknown");
if (EntryPGC)
{
Info_BS(4, MenuType, "menu type"); Param_Info1(IFO_MenuType[MenuType]);
}
else
{
Skip_BS(4, "Reserved");
}
BS_End();
Skip_B1( "Unknown");
Skip_B2( "parental management mask");
Element_End0();
Get_B4 (Offset, "offset to VTSM_PGC relative to VTSM_LU");
if (Offset-16>0)
Skip_XX(Offset-16, "Unknown");
Element_End0();
for (int16u PGC_Pos=0; PGC_Pos<PGC_Count; PGC_Pos++)
PGC(Element_Offset);
Element_End0();
}
}
//---------------------------------------------------------------------------
void File_Dvdv::VTS_TMAPTI ()
{
Element_Name("Time map");
//Parsing
Element_Begin1("Header");
int32u EndAddress, Offset;
Skip_B2( "Number of program chains");
Skip_B2( "Reserved");
Get_B4 (EndAddress, "End address");
if (EndAddress>=Element_Size)
EndAddress=(int32u)Element_Size-1;
Get_B4 (Offset, "Offset to VTS_TMAP 1");
if (Offset-12>0)
Skip_XX(Offset-12, "Unknown");
Element_End0();
//DETAILLEVEL_SET(1.0);
while (Element_Offset<=EndAddress)
{
//VTS_TMAP
Element_Begin1("Time Map");
//std::vector<size_t> Sector_Times;
int8u Sector_Times_SecondsPerTime;
int16u Count;
Get_B1 (Sector_Times_SecondsPerTime, "Time unit (seconds)");
Skip_B1( "Unknown");
Get_B2 (Count, "Number of entries in map");
//Sector_Times.resize(Count);
BS_Begin();
for (int16u Pos=0; Pos<Count; Pos++)
{
Element_Begin1("Sector Offset");
int32u SectorOffset;
Skip_BS( 1, "discontinuous with previous");
Get_BS (31, SectorOffset, "Sector offset within VOBS of nearest VOBU");
//Get_B4 (Sector_Times[Pos], Sector offset within VOBS of nearest VOBU);// Param_Info1(Ztring().Duration_From_Milliseconds((Pos+1)*Sectors_Times_SecondsPerTime[Program_Pos]));
//Sector_Times[Pos]&=0x7FFFFFFF; //bit 31 is set if VOBU time codes are discontinuous with previous
Element_Info1(SectorOffset);
Element_End0();
}
BS_End();
Element_End0();
//Filling
//Sectors_Times.push_back(Sector_Times);
//Sectors_Times_SecondsPerTime.push_back(Sector_Times_SecondsPerTime);
}
}
//---------------------------------------------------------------------------
void File_Dvdv::VTSM_C_ADT ()
{
Element_Name("Menu cell address table");
//Parsing
int32u EndAddress;
Element_Begin1("Header");
Skip_B2( "Number of cells");
Skip_B2( "Reserved");
Get_B4 (EndAddress, "End address");
if (EndAddress>=Element_Size)
EndAddress=(int32u)Element_Size-1;
Element_End0();
//DETAILLEVEL_SET(1.0);
while (Element_Offset<=EndAddress)
{
//ADT
Element_Begin1("Entry");
Skip_B2( "VOBidn");
Skip_B1( "CELLidn");
Skip_B1( "Unknown");
Skip_B4( "Starting sector within VOB");
Skip_B4( "Ending sector within VOB");
Element_End0();
}
}
//---------------------------------------------------------------------------
void File_Dvdv::VTSM_VOBU_ADMAP ()
{
Element_Name("Menu VOBU address map");
//Parsing
int32u EndAddress;
Element_Begin1("Header");
Get_B4 (EndAddress, "End address");
if (EndAddress>=Element_Size)
EndAddress=(int32u)Element_Size-1;
Element_End0();
//DETAILLEVEL_SET(1.0);
while (Element_Offset<=EndAddress)
{
//ADMAP
Skip_B4( "Starting sector within VOB of first VOBU");
}
}
//---------------------------------------------------------------------------
void File_Dvdv::VTS_C_ADT ()
{
Element_Name("Title set cell address table");
//Parsing
int32u EndAddress;
Element_Begin1("Header");
Skip_B2( "Number of cells");
Skip_B2( "Reserved");
Get_B4 (EndAddress, "End address");
if (EndAddress>=Element_Size)
EndAddress=(int32u)Element_Size-1;
Element_End0();
//DETAILLEVEL_SET(1.0);
while (Element_Offset<=EndAddress)
{
//ADT
Element_Begin1("Entry");
int32u Start, End;
int16u VOBidn;
int8u CELLidn;
Get_B2 (VOBidn, "VOBidn");
Get_B1 (CELLidn, "CELLidn");
Skip_B1( "Unknown");
Get_B4 (Start, "Starting sector within VOB"); Param_Info1(Time_ADT(Start));
Get_B4 (End, "Ending sector within VOB"); Param_Info1(Time_ADT(End));
Element_End0();
//Filling
FILLING_BEGIN();
FILLING_END();
//Fill(Ztring::ToZtring(CELLidn).To_Local().c_str(), Time_ADT(Start));
}
}
//---------------------------------------------------------------------------
void File_Dvdv::VTS_VOBU_ADMAP ()
{
Element_Name("Title set VOBU address map");
//Parsing
int32u EndAddress;
Element_Begin1("Header");
Get_B4 (EndAddress, "End address");
if (EndAddress>=Element_Size)
EndAddress=(int32u)Element_Size-1;
Element_End0();
//DETAILLEVEL_SET(1.0);
while (Element_Offset<Element_Size)
{
//ADMAP
Skip_B4( "Starting sector within VOB of first VOBU");
}
}
//***************************************************************************
// Helpers
//***************************************************************************
//---------------------------------------------------------------------------
Ztring File_Dvdv::Time_ADT(int32u)
{
return Ztring();
/*
if (Sectors_Times.empty())
return Ztring(); //TODO: it can be empty?
while (Time_Pos<Sectors_Times[Program_Pos].size() && Sectors_Times[Program_Pos][Time_Pos]<Value)
Time_Pos++;
if (Time_Pos<Sectors_Times[Program_Pos].size())
{
int32u Time=(Time_Pos+1)*Sectors_Times_SecondsPerTime[Program_Pos]*1000;
float32 Part;
//True time is between Time and Time+Sectors_Times_SecondsPerTime, finding where...
int32u Sectors_Count;
if (Time_Pos==0)
Sectors_Count=Sectors_Times[Program_Pos][Time_Pos];
else
Sectors_Count=Sectors_Times[Program_Pos][Time_Pos]-Sectors_Times[Program_Pos][Time_Pos-1];
Part=(Sectors_Times[Program_Pos][Time_Pos]-Value); //Count of more sectors after
Part/=Sectors_Count; //Percentage
Time=(int32u)((Time_Pos+1-Part)*Sectors_Times_SecondsPerTime[Program_Pos]*1000);
return Ztring().Duration_From_Milliseconds(Time*1000);
}
else
{
int32u Time=(Time_Pos+1)*Sectors_Times_SecondsPerTime[Program_Pos]*1000;
float32 Part;
//True time is between Time and Time+Sectors_Times_SecondsPerTime, finding where... but with the last offset diffrence
int32u Sectors_Count=Sectors_Times[Program_Pos][Time_Pos-1]-Sectors_Times[Program_Pos][Time_Pos-2];
Part=((int32s)Sectors_Times[Program_Pos][Time_Pos-1])-((int32s)Value); //Count of more sectors after
Part/=Sectors_Count; //Percentage
Part+=1; //We were one offset less
Time=(int32u)((Time_Pos+1-Part)*Sectors_Times_SecondsPerTime[Program_Pos]*1000);
return Ztring().Duration_From_Milliseconds(Time*1000);
}
*/
}
void File_Dvdv::Get_Duration(int64u &Duration, const Ztring &Name)
{
int32u FrameRate, FF;
int8u HH, MM, Sec;
Element_Begin1(Name);
Get_B1 (HH, "Hours (BCD)");
Get_B1 (MM, "Minutes (BCD)");
Get_B1 (Sec, "Seconds (BCD)");
BS_Begin();
Get_BS (2, FrameRate, "Frame rate"); Param_Info2(IFO_PlaybackTime_FrameRate[FrameRate], " fps");
Get_BS (6, FF, "Frames (BCD)");
BS_End();
Duration= Ztring::ToZtring(HH, 16).To_int64u() * 60 * 60 * 1000 //BCD
+ Ztring::ToZtring(MM, 16).To_int64u() * 60 * 1000 //BCD
+ Ztring::ToZtring(Sec, 16).To_int64u() * 1000 //BCD
+ Ztring::ToZtring(FF, 16).To_int64u() * 1000/IFO_PlaybackTime_FrameRate[FrameRate]; //BCD
Element_Info1(Ztring::ToZtring(Duration));
Element_End0();
}
void File_Dvdv::PGC(int64u Offset, bool Title)
{
vector<int8u> Stream_Control_Audio;
vector<int8u> Stream_Control_SubPicture_43;
vector<int8u> Stream_Control_SubPicture_Wide;
vector<int8u> Stream_Control_SubPicture_Letterbox;
vector<int8u> Stream_Control_SubPicture_PanScan;
vector<int64u> CellDurations;
vector<int8u> ProgramMap;
//VTS_PGC
Element_Begin1("PGC");
int16u commands, program_map, cell_playback, cell_position;
int8u Program_Count;
Element_Begin1("Header");
int32u Flags;
int8u Cells;
int64u TotalDuration;
Skip_B2( "Unknown");
Get_B1 (Program_Count, "number of programs");
Get_B1 (Cells, "number of cells");
Get_Duration(TotalDuration, "Duration");
Get_B4 (Flags, "prohibited user ops");
/*Skip_Flags(Flags, 0, "Time play or search");
Skip_Flags(Flags, 1, PTT play or search);
Skip_Flags(Flags, 2, Title play);
Skip_Flags(Flags, 3, Stop);
Skip_Flags(Flags, 4, GoUp);
Skip_Flags(Flags, 5, Time or PTT search);
Skip_Flags(Flags, 6, TopPG or PrevPG search);
Skip_Flags(Flags, 7, NextPG search);
Skip_Flags(Flags, 8, Forward scan);
Skip_Flags(Flags, 9, Backward scan);
Skip_Flags(Flags, 10, Menu call - Title);
Skip_Flags(Flags, 11, Menu call - Root);
Skip_Flags(Flags, 12, Menu call - Subpicture);
Skip_Flags(Flags, 13, Menu call - Audio);
Skip_Flags(Flags, 14, Menu call - Angle);
Skip_Flags(Flags, 15, Menu call - PTT);
Skip_Flags(Flags, 16, Resume);
Skip_Flags(Flags, 17, Button select or activate);
Skip_Flags(Flags, 18, Still off);
Skip_Flags(Flags, 19, Pause on);
Skip_Flags(Flags, 20, Audio stream change);
Skip_Flags(Flags, 21, Subpicture stream change);
Skip_Flags(Flags, 22, Angle change);
Skip_Flags(Flags, 23, Karaoke audio mix change);
Skip_Flags(Flags, 24, Video presentation mode change);
*/
/*
Skip_Flags(Flags, 0, Video presentation mode change);
Skip_Flags(Flags, 1, Karaoke audio mix change);
Skip_Flags(Flags, 2, Angle change);
Skip_Flags(Flags, 3, Subpicture stream change);
Skip_Flags(Flags, 4, Audio stream change);
Skip_Flags(Flags, 5, Pause on);
Skip_Flags(Flags, 6, Still off);
Skip_Flags(Flags, 7, Button select or activate);
Skip_Flags(Flags, 8, Resume);
Skip_Flags(Flags, 9, Menu call - PTT);
Skip_Flags(Flags, 10, Menu call - Angle);
Skip_Flags(Flags, 11, Menu call - Audio);
Skip_Flags(Flags, 12, Menu call - Subpicture);
Skip_Flags(Flags, 13, Menu call - Root);
Skip_Flags(Flags, 14, Menu call - Title);
Skip_Flags(Flags, 15, Backward scan);
Skip_Flags(Flags, 16, Forward scan);
Skip_Flags(Flags, 17, NextPG search);
Skip_Flags(Flags, 18, TopPG or PrevPG search);
Skip_Flags(Flags, 19, Time or PTT search);
Skip_Flags(Flags, 20, GoUp);
Skip_Flags(Flags, 21, Stop);
Skip_Flags(Flags, 22, Title play);
Skip_Flags(Flags, 23, PTT play or search);
Skip_Flags(Flags, 24, Time play or search);
*/
Element_Begin1("Audio Stream Controls");
for (size_t Pos=0; Pos<8; Pos++)
{
Element_Begin1("Audio Stream Control");
Element_Info1(Ztring::ToZtring(Pos));
int8u Number;
bool Available;
BS_Begin();
Get_SB ( Available, "Stream available");
Get_S1 (7, Number, "Stream number");
BS_End();
Skip_B1( "Reserved");
Element_End0();
if (Available)
Stream_Control_Audio.push_back(Number);
if (Available && Retrieve(Stream_Audio, Pos, Text_ID).empty() && Sectors[(size_t)((File_Offset+Buffer_Offset)/2048)]==Sector_VTS_PGCI)
{
while (Pos>Count_Get(Stream_Audio))
Stream_Prepare(Stream_Audio);
int8u ToAdd=0;
if (Retrieve(Stream_Audio, Pos, Audio_Format)==__T("AC-3"))
ToAdd=0x80;
if (Retrieve(Stream_Audio, Pos, Audio_Format)==__T("DTS"))
ToAdd=0x88;
if (Retrieve(Stream_Audio, Pos, Audio_Format)==__T("LPCM"))
ToAdd=0xA0;
Ztring ID_String = Get_Hex_ID(ToAdd + Number);
Fill(Stream_Audio, Pos, Audio_ID, ID_String);
Fill(Stream_Audio, Pos, Audio_ID_String, ID_String, true);
}
}
Element_End0();
Element_Begin1("Subpicture Stream Controls");
for (size_t Pos=0; Pos<32; Pos++)
{
Element_Begin1("Subpicture Stream Control");
Element_Info1(Ztring::ToZtring(Pos));
int8u Number_43, Number_Wide, Number_Letterbox, Number_PanScan;
bool Available;
BS_Begin();
Get_SB ( Available, "Stream available");
Get_S1 (7, Number_43, "Stream number for 4/3");
BS_End();
Get_B1 (Number_Wide, "Stream number for Wide");
Get_B1 (Number_Letterbox, "Stream number for Letterbox");
Get_B1 (Number_PanScan, "Stream number for Pan&Scan");
Element_End0();
if (Available)
{
Stream_Control_SubPicture_43.push_back(Number_43);
Stream_Control_SubPicture_Wide.push_back(Number_Wide);
Stream_Control_SubPicture_Letterbox.push_back(Number_Letterbox);
Stream_Control_SubPicture_PanScan.push_back(Number_PanScan);
}
if (Available && Retrieve(Stream_Text, Pos, Text_ID).empty() && Sectors[(size_t)((File_Offset+Buffer_Offset)/2048)]==Sector_VTS_PGCI)
{
while (Pos>Count_Get(Stream_Text))
Stream_Prepare(Stream_Text);
Ztring ID_String = Get_Hex_ID(0x20 + Number_Wide);
Fill(Stream_Text, Pos, Text_ID, ID_String);
Fill(Stream_Text, Pos, Text_ID_String, ID_String, true);
}
}
Element_End0();
Skip_B2( "next PGCN");
Skip_B2( "previous PGCN");
Skip_B2( "goup PGCN");
Skip_B1( "PGC still time - 255=infinite");
Skip_B1( "PG playback mode");
Element_Begin1("palette");
for (int Pos=0; Pos<16; Pos++)
{
Skip_B4( "palette (0 - Y - Cr - Cb)");
}
Element_End0();
Get_B2 (commands, "offset within PGC to commands");
Get_B2 (program_map, "offset within PGC to program map");
Get_B2 (cell_playback, "offset within PGC to cell playback information table");
Get_B2 (cell_position, "offset within PGC to cell position information table");
Element_End0();
//commands
if (commands>0)
{
if (Element_Offset<Offset+commands)
{
if (Offset+commands>Element_Size)
{
Skip_XX(Element_Size-Element_Offset, "Unknown");
return;
}
Skip_XX(Offset+commands-Element_Offset, "Unknown");
}
Element_Begin1("commands");
int16u PreCommands_Count, PostCommands_Count, CellCommands_Count, EndAdress;
Get_B2 (PreCommands_Count, "Number of pre commands");
Get_B2 (PostCommands_Count, "Number of post commands");
Get_B2 (CellCommands_Count, "Number of cell commands");
Get_B2 (EndAdress, "End address relative to command table");
if (PreCommands_Count>0)
{
Element_Begin1("Pre commands");
for (int16u Pos=0; Pos<PreCommands_Count; Pos++)
{
Element_Begin1("Pre command");
Skip_XX(8, "Pre command");
Element_End0();
}
Element_End0();
}
if (PostCommands_Count>0)
{
Element_Begin1("Post commands");
for (int16u Pos=0; Pos<PostCommands_Count; Pos++)
{
Element_Begin1("Post command");
Skip_XX(8, "Post command");
Element_End0();
}
Element_End0();
}
if (CellCommands_Count>0)
{
Element_Begin1("Cell commands");
for (int16u Pos=0; Pos<CellCommands_Count; Pos++)
{
Element_Begin1("Cell command");
Skip_XX(8, "Cell command");
Element_End0();
}
Element_End0();
}
Element_End0();
}
//program map
if (program_map>0)
{
if (Element_Offset<Offset+program_map)
Skip_XX(Offset+program_map-Element_Offset, "Unknown");
Element_Begin1("program map");
for (int8u Pos=0; Pos<Program_Count; Pos++)
{
Element_Begin1("Entry");
int8u entry;
Get_B1( entry, "Entry cell number");
ProgramMap.push_back(entry);
//Skip_B1( "Entry cell number");
Element_End0();
}
Element_End0();
}
//cell playback
if (cell_playback>0)
{
if (Element_Offset<Offset+cell_playback)
Skip_XX(Offset+cell_playback-Element_Offset, "Unknown");
Element_Begin1("cell playback");
for (int8u Pos=0; Pos<Cells; Pos++)
{
int64u CellDuration;
Element_Begin1("cell");
Skip_XX(4, "ToDo");
Get_Duration(CellDuration, "Time");
Skip_B4( "first VOBU start sector");
Skip_B4( "first ILVU end sector");
Skip_B4( "last VOBU start sector");
Skip_B4( "last VOBU end sector");
Element_Info1(Ztring::ToZtring(Pos)); Element_Info1(Ztring::ToZtring(CellDuration));
Element_End0();
CellDurations.push_back(CellDuration);
}
Element_End0();
}
//cell position
if (cell_position>0)
{
if (Element_Offset<Offset+cell_position)
Skip_XX(Offset+cell_position-Element_Offset, "Unknown");
Element_Begin1("cell position");
for (int8u Pos=0; Pos<Cells; Pos++)
{
Element_Begin1("cell");
Skip_B2( "VOBid");
Skip_B1( "reserved");
Skip_B1( "Cell id");
Element_End0();
}
Element_End0();
}
Element_End0();
FILLING_BEGIN();
if (Title)
{
Stream_Prepare(Stream_Menu);
int64u ProgramTotalDuration=0;
Fill(Stream_Menu, StreamPos_Last, Menu_Chapters_Pos_Begin, Count_Get(Stream_Menu, StreamPos_Last), 10, true);
for (int8u Pos=0; Pos<ProgramMap.size(); Pos++)
{
Fill(StreamKind_Last, StreamPos_Last, Ztring().Duration_From_Milliseconds(ProgramTotalDuration).To_Local().c_str(), Ztring(__T("Chapter "))+Ztring::ToZtring(Pos+1));
int8u End;
if (Pos+1>=Program_Count)
End=Cells+1;
else
End=ProgramMap[Pos+1];
int64u ProgramDuration=0;
if (Pos<ProgramMap.size())
for (int8u CellPos=ProgramMap[Pos]; CellPos<End; CellPos++)
if (CellPos && CellPos<=CellDurations.size())
ProgramDuration+=CellDurations[CellPos-1];
ProgramTotalDuration+=ProgramDuration;
}
Fill(Stream_Menu, StreamPos_Last, Menu_Chapters_Pos_End, Count_Get(Stream_Menu, StreamPos_Last), 10, true);
Fill(Stream_Menu, StreamPos_Last, Menu_Duration, TotalDuration);
for (size_t Pos=0; Pos<Stream_Control_Audio.size(); Pos++)
{
Fill(StreamKind_Last, StreamPos_Last, "List (Audio)", Stream_Control_Audio[Pos]);
}
for (size_t Pos=0; Pos<Stream_Control_SubPicture_43.size(); Pos++)
{
Fill(StreamKind_Last, StreamPos_Last, "List (Subtitles 4/3)", Stream_Control_SubPicture_43[Pos]);
}
for (size_t Pos=0; Pos<Stream_Control_SubPicture_Wide.size(); Pos++)
{
Fill(StreamKind_Last, StreamPos_Last, "List (Subtitles Wide)", Stream_Control_SubPicture_Wide[Pos]);
}
for (size_t Pos=0; Pos<Stream_Control_SubPicture_Letterbox.size(); Pos++)
{
Fill(StreamKind_Last, StreamPos_Last, "List (Subtitles Letterbox)", Stream_Control_SubPicture_Letterbox[Pos]);
}
for (size_t Pos=0; Pos<Stream_Control_SubPicture_PanScan.size(); Pos++)
{
Fill(StreamKind_Last, StreamPos_Last, "List (Subtitles Pan&Scan)", Stream_Control_SubPicture_PanScan[Pos]);
}
}
FILLING_END();
}
//---------------------------------------------------------------------------
void File_Dvdv::TT_SRPT()
{
Element_Name("table of titles");
}
//---------------------------------------------------------------------------
void File_Dvdv::VMGM_PGCI_UT()
{
Element_Name("Menu Program Chain table");
}
//---------------------------------------------------------------------------
void File_Dvdv::VMG_PTL_MAIT()
{
Element_Name("Parental Management masks");
}
//---------------------------------------------------------------------------
void File_Dvdv::VMG_VTS_ATRT()
{
Element_Name("copies of VTS audio/sub-picture attributes");
//Parsing
int32u EndAddress;
Element_Begin1("Header");
int32u Offset;
Skip_B4( "Number of title sets");
Get_B4 (EndAddress, "End address");
if (EndAddress>=Element_Size)
EndAddress=(int32u)Element_Size-1;
Get_B4 (Offset, "Offset to VTSM_LU relative to VTSM_PGCI_UT");
if (Offset-12>0)
Skip_XX(Offset-12, "Unknown");
Element_End0();
while (Element_Offset<=EndAddress)
{
Element_Begin1("VTS_ATRT");
Element_Begin1("Header");
int32u Size;
Get_B4 (Size, "End address");
Size++; //Last byte
Element_End0();
Element_Begin1("Copy of VTS Category");
Skip_B4( "VTS Category");
Element_End0();
Element_Begin1("Copy of VTS attributes");
Skip_XX(Size-8, "VTS attributes");
Element_End0();
Element_End0();
}
}
//---------------------------------------------------------------------------
void File_Dvdv::VMG_TXTDT_MG()
{
Element_Name("text data");
}
//---------------------------------------------------------------------------
void File_Dvdv::VMGM_C_ADT()
{
Element_Name("menu cell address table");
}
//---------------------------------------------------------------------------
void File_Dvdv::VMGM_VOBU_ADMAP()
{
Element_Name("menu VOBU address map");
}
} //NameSpace
#endif //MEDIAINFO_DVDV_YES
↑ V547 Expression 'Pos < ProgramMap.size()' is always true.
↑ V555 The expression 'Offset - 16 > 0' will work as 'Offset != 16'.
↑ V555 The expression 'Offset - 16 > 0' will work as 'Offset != 16'.
↑ V555 The expression 'Offset - 16 > 0' will work as 'Offset != 16'.
↑ V555 The expression 'Offset - 12 > 0' will work as 'Offset != 12'.
↑ V555 The expression 'Offset - 12 > 0' will work as 'Offset != 12'.
↑ V1008 Consider inspecting the 'for' operator. No more than one iteration of the loop will be performed.
↑ V1008 Consider inspecting the 'for' operator. No more than one iteration of the loop will be performed.
↑ V525 The code contains the collection of similar blocks. Check items '4', '2', '2' in lines 350, 351, 352.