/* 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 using namespace std; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #if defined(MEDIAINFO_DVDV_YES) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Multiple/File_Dvdv.h" #include "MediaInfo/MediaInfo_Config.h" #include "MediaInfo/MediaInfo_Internal.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[]= {0, 25, 0, 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() { //Manage related VOB files if (!IsSub && !Config->File_IsReferenced_Get() && File_Name.size()>=5 && File_Name.find(__T("0.IFO"), File_Name.size()-5)!=string::npos) { Ztring VOB_File=File_Name.substr(0, File_Name.size()-5)+__T("1.VOB"); MediaInfo_Internal MI; MI.Option(__T("File_IsReferenced"), __T("1")); if (MI.Open(VOB_File)) Merge(MI); auto SeparatorPos=VOB_File.find_last_of(__T("/\\")); if (SeparatorPos!=string::npos) { auto FileSize=Retrieve_Const(Stream_General, 0, General_FileSize).To_int64u(); FileSize+=MI.Get(Stream_General, 0, General_FileSize).To_int64u(); Fill(Stream_General, 0, General_FileSize, FileSize, 10, true); VOB_File.erase(0, SeparatorPos+1); for (size_t StreamKind=Stream_General+1; StreamKind=0) MaxDuration=(int64u)Trigger; else { MaxDuration=0; for (size_t Pos=0; Pos=MaxDuration) Pos++; else Stream_Erase(Stream_Menu, Pos); } //Fill stream duration map Durations; auto Menu_Count=Count_Get(Stream_Menu); for (size_t Pos=0; Possecond, 10, true); } } if (!Durations.empty()) { int64u Duration_Total=0; for (const auto& Duration : Durations) Duration_Total+=Duration.second; Fill(Stream_General, 0, General_Duration, Duration_Total, 10, true); } //Duration offsets TimeCode Duration_Total; for (const auto& Title : Titles) { Fill(Stream_Menu, Title.second.Pos, Menu_Delay, (int64s)Duration_Total.ToMilliseconds(), 10, true); Duration_Total+=Title.second.Duration; } //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 (Pos0x001F) 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 (Pos0x001F) 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()) { 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_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(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_Pos0) Skip_XX(Offset-16, "Unknown"); Element_End0(); for (int16u PGC_Pos=0; PGC_Pos=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 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=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>4; int Units=Value&0xF; if (Tens>=10 || Units>=10) return (unsigned)-1; return Tens*10+Units; } void File_Dvdv::Get_Duration(TimeCode &Duration, const Ztring &Name) { int32u FrameRate, FF; int8u HH, MM, SS; Element_Begin1(Name); Get_C1 (HH, "Hours (BCD)"); Get_C1 (MM, "Minutes (BCD)"); Get_C1 (SS, "Seconds (BCD)"); BS_Begin(); Get_BS (2, FrameRate, "Frame rate"); Param_Info2C(IFO_PlaybackTime_FrameRate[FrameRate], IFO_PlaybackTime_FrameRate[FrameRate], " fps"); Get_BS (6, FF, "Frames (BCD)"); BS_End(); auto hh=BCD_to_Decimal(HH); auto mm=BCD_to_Decimal(MM); auto ss=BCD_to_Decimal(SS); auto ff=BCD_to_Decimal(FF); if (hh==(int8u)-1 || mm==(int8u)-1 || ss==(int8u)-1 || ff==(int8u)-1 || !IFO_PlaybackTime_FrameRate[FrameRate]) { Duration=TimeCode(); return; } bool Drop=IFO_PlaybackTime_FrameRate[FrameRate]==30; Duration=TimeCode((uint32_t)hh, (uint8_t)mm, (uint8_t)ss, (uint8_t)ff, IFO_PlaybackTime_FrameRate[FrameRate]-1); Element_Info1(Duration.ToString()); Element_End0(); } void File_Dvdv::PGC(bool Title) { vector Stream_Control_Audio; vector Stream_Control_SubPicture_43; vector Stream_Control_SubPicture_Wide; vector Stream_Control_SubPicture_Letterbox; vector Stream_Control_SubPicture_PanScan; vector CellDurations; vector ProgramMap; //VTS_PGC int64u Offset = Element_Offset; Element_Begin1("PGC"); int16u commands, program_map, cell_playback, cell_position; int8u Program_Count; Element_Begin1("Header"); int32u Flags; int8u Cells; TimeCode 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; auto ID=ToAdd+Number; Fill(Stream_Audio, Pos, Audio_ID, __T("189-")+Ztring::ToZtring(ID)); Fill(Stream_Audio, Pos, Audio_ID_String, __T("189 (0xBD)-")+Get_Hex_ID(ID), 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); auto ID=0x20+Number_Wide; Fill(Stream_Text, Pos, Text_ID, __T("189-")+Ztring::ToZtring(ID)); Fill(Stream_Text, Pos, Text_ID_String, __T("189 (0xBD)-")+Get_Hex_ID(ID), 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_OffsetElement_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; Pos0) { Element_Begin1("Post commands"); for (int16u Pos=0; Pos0) { Element_Begin1("Cell commands"); for (int16u Pos=0; Pos0) { if (Element_Offset0) { if (Element_Offset0) { if (Element_Offset=Program_Count) End=Cells+1; else End=ProgramMap[Pos+1]; TimeCode ProgramDuration; if (Pos=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