/* Copyright (c) MediaArea.net SARL. All Rights Reserved. * * Use of this source code is governed by a BSD-style license that can * be found in the License.html file in the root of the source tree. */ //--------------------------------------------------------------------------- // Pre-compilation #include "MediaInfo/PreComp.h" #ifdef __BORLANDC__ #pragma hdrstop #endif //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Setup.h" //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #if defined(MEDIAINFO_REFERENCES_YES) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Multiple/File__ReferenceFilesHelper.h" #include "MediaInfo/MediaInfo_Internal.h" #include "ZenLib/File.h" #include "ZenLib/FileName.h" #include "ZenLib/Format/Http/Http_Utils.h" #include #include #include #if MEDIAINFO_EVENTS #include "MediaInfo/MediaInfo_Events_Internal.h" #include "MediaInfo/MediaInfo_Config_PerPackage.h" #endif //MEDIAINFO_EVENTS #if MEDIAINFO_AES #include "ThirdParty/base64/base64.h" #endif //MEDIAINFO_AES using namespace std; //--------------------------------------------------------------------------- namespace MediaInfoLib { //*************************************************************************** // Constructor/Destructor //*************************************************************************** //--------------------------------------------------------------------------- File__ReferenceFilesHelper::File__ReferenceFilesHelper(File__Analyze* MI_, MediaInfo_Config_MediaInfo* Config_) { //In TestContinuousFileNames=false; ContainerHasNoId=false; ID_Max=0; //Private Sequences_Current=0; MI=MI_; Config=Config_; Init_Done=false; FrameRate=0; Duration=0; #if MEDIAINFO_DEMUX Demux_Interleave=false; DTS_Minimal=(int64u)-1; #endif //MEDIAINFO_DEMUX #if MEDIAINFO_EVENTS StreamID_Previous=(int64u)-1; #endif //MEDIAINFO_EVENTS #if MEDIAINFO_DEMUX Offset_Video_DTS=0; #endif //MEDIAINFO_DEMUX //Temp FilesForStorage=false; HasMainFile=false; HasMainFile_Filled=false; #if MEDIAINFO_NEXTPACKET DTS_Interval=(int64u)-1; #endif //MEDIAINFO_NEXTPACKET } //--------------------------------------------------------------------------- File__ReferenceFilesHelper::~File__ReferenceFilesHelper() { size_t Sequences_Size=Sequences.size(); for (size_t Sequences_Pos=0; Sequences_PosStreamIDStreamID);} bool File__ReferenceFilesHelper_Algo2 (const sequence* Ref1, const sequence* Ref2) { return (Ref1->StreamPosStreamPos);} bool File__ReferenceFilesHelper_Algo3 (const sequence* Ref1, const sequence* Ref2) { return (Ref1->StreamKindStreamKind);} void File__ReferenceFilesHelper_InfoFromFileName (sequences &Sequences) { ZtringListList List; vector Iterators; size_t ItemsValid=0; for (size_t Sequences_Pos=0; Sequences_PosStreamKind==Stream_Audio && !Sequences[Sequences_Pos]->FileNames.empty()) { Ztring Name=Sequences[Sequences_Pos]->FileNames[0]; while (Name.FindAndReplace(__T("51 "), Ztring())); while (Name.FindAndReplace(__T("_"), __T(" "))); while (Name.FindAndReplace(__T("."), __T(" "))); while (Name.FindAndReplace(__T(" "), __T(" "))); size_t PathSeparator_Pos=Name.rfind(PathSeparator); if (PathSeparator_Pos!=(size_t)-1) Name.erase(0, PathSeparator_Pos+1); //Removing extension if (Name.size()>4 && Name.rfind(__T('.'))==Name.size()) Name.resize(Name.size()-4); List2.Write(Name); for (size_t Pos=0; Pos=List[Pos2].size()) break; //Maybe begin of title const Ztring &Test=List[Pos2][List[Pos2].size()-1-Pos]; //ChannelLayout if (ChannelLayout_Pos==(size_t)-1 && (Test==__T("l") || Test==__T("r") || Test==__T("lt") || Test==__T("rt") || Test==__T("c") || Test==__T("lf") || Test==__T("lfe") || Test==__T("sub") || Test==__T("ls") || Test==__T("rs") || Test==__T("lsr") || Test==__T("rsr") || Test==__T("b") || Test==__T("mono"))) { ChannelLayout_Pos = Pos; } //Language if (Language_Pos==(size_t)-1 && (Test==__T("ara") || Test==__T("deu") || Test==__T("eng") || Test==__T("fra") || Test==__T("fre") || Test==__T("ger") || Test==__T("ita") || Test==__T("jpn") || Test==__T("las") //Latin America Spanish || Test==__T("rus") || Test==__T("spa"))) { Language_Pos = Pos; } if (ChannelLayout_Pos!=(size_t)-1 && Language_Pos!=(size_t)-1) break; } //ChannelLayout if (ChannelLayout_Pos!=(size_t)-1) { Ztring ChannelPositions, ChannelPositions2, ChannelLayout; if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("l")) { ChannelPositions=__T("Front: L"); ChannelPositions2=__T("1/0/0"); ChannelLayout=__T("L"); } else if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("lt")) { ChannelPositions=__T("Front: Lt"); ChannelPositions2=__T("1/0/0"); ChannelLayout=__T("Lt"); } else if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("rt")) { ChannelPositions=__T("Front: Rt"); ChannelPositions2=__T("1/0/0"); ChannelLayout=__T("Rt"); } else if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("r")) { ChannelPositions=__T("Front: R"); ChannelPositions2=__T("1/0/0"); ChannelLayout=__T("R"); } else if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("c") || List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("mono")) { ChannelPositions=__T("Front: C"); ChannelPositions2=__T("1/0/0"); ChannelLayout=__T("C"); } else if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("lf") || List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("lfe") || List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("sub")) { ChannelPositions=__T("LFE"); ChannelPositions2=__T(".1"); ChannelLayout=__T("LFE"); } else if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("ls")) { ChannelPositions=__T("Side: L"); ChannelPositions2=__T("0/1/0"); ChannelLayout=__T("Ls"); } else if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("rs")) { ChannelPositions=__T("Side: R"); ChannelPositions2=__T("0/1/0"); ChannelLayout=__T("Rs"); } else if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("lsr")) { ChannelPositions=__T("Back: L"); ChannelPositions2=__T("0/0/1"); ChannelLayout=__T("Lsr"); } else if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("rsr")) { ChannelPositions=__T("Back: R"); ChannelPositions2=__T("0/0/1"); ChannelLayout=__T("Rsr"); } else if (List[Pos2][List[Pos2].size()-1-ChannelLayout_Pos]==__T("b")) { ChannelPositions=__T("Back: C"); ChannelPositions2=__T("0/0/1"); ChannelLayout=__T("Cs"); } Sequences[Pos2]->Infos["ChannelPositions"]=ChannelPositions; Sequences[Pos2]->Infos["ChannelPositions/String2"]=ChannelPositions2; Sequences[Pos2]->Infos["ChannelLayout"]=ChannelLayout; } //Language if (Language_Pos!=(size_t)-1) if (1+Language_PosInfos["Language"]=Language.empty()?List[Pos2][List[Pos2].size()-1-Language_Pos]:Language; } } } //*************************************************************************** // In //*************************************************************************** //--------------------------------------------------------------------------- void File__ReferenceFilesHelper::AddSequence(sequence* NewSequence) { Sequences.push_back(NewSequence); } //--------------------------------------------------------------------------- void File__ReferenceFilesHelper::DetectSameReels(vector &ReelCount) { if (ReelCount.size()<=1) return; // Finding the max count of streams per stream kind size_t StreamCounts_Max[Stream_Max+1]; size_t StreamCounts[Stream_Max+1]; vector Sequence_Pos_PerKind[Stream_Max+1]; memset(StreamCounts_Max, 0x00, (Stream_Max+1)*sizeof(size_t)); size_t Sequence_Pos=0; for (size_t r=0; rStreamKind].size()<=StreamCounts[Sequences[Sequence_Pos]->StreamKind]) Sequence_Pos_PerKind[Sequences[Sequence_Pos]->StreamKind].push_back(Sequence_Pos); StreamCounts[Sequences[Sequence_Pos]->StreamKind]++; Sequence_Pos++; } for (size_t i=0; i Sequence_Pos_toDelete; for (size_t r=1; rStreamKind!=Stream_Max) { size_t Sequence_Pos_First=Sequence_Pos_PerKind[Sequences[Sequence_Pos]->StreamKind][StreamCounts[Sequences[Sequence_Pos]->StreamKind]]; if (Sequence_Pos!=Sequence_Pos_First) { Sequences[Sequence_Pos_First]->Resources.insert(Sequences[Sequence_Pos_First]->Resources.end(), Sequences[Sequence_Pos]->Resources.begin(), Sequences[Sequence_Pos]->Resources.end()); Sequence_Pos_toDelete.push_back(Sequence_Pos); } } StreamCounts[Sequences[Sequence_Pos]->StreamKind]++; Sequence_Pos++; } } // Remove other reels for (size_t i=Sequence_Pos_toDelete.size()-1; i!=(size_t)-1; i--) { delete Sequences[Sequence_Pos_toDelete[i]]; Sequences.erase(Sequences.begin()+Sequence_Pos_toDelete[i]); } // Fake StreamIDs for (size_t i=0; iStreamID=i+1; } //--------------------------------------------------------------------------- void File__ReferenceFilesHelper::UpdateFileName(const Ztring& OldFileName, const Ztring& NewFileName) { size_t Sequences_Size=Sequences.size(); for (size_t Sequences_Pos=0; Sequences_PosUpdateFileName(OldFileName, NewFileName); } } //--------------------------------------------------------------------------- #if MEDIAINFO_ADVANCED void File__ReferenceFilesHelper::UpdateMetaDataFromSourceEncoding(const string& SourceEncoding, const string& Name, const string& Value) { size_t Sequences_Size=Sequences.size(); for (size_t Sequences_Pos=0; Sequences_PosUpdateMetaDataFromSourceEncoding(SourceEncoding, Name, Value); } } #endif //MEDIAINFO_ADVANCED //*************************************************************************** // Streams management //*************************************************************************** void File__ReferenceFilesHelper::ParseReferences() { if (!Init_Done) { #if MEDIAINFO_FILTER if (MI->Config->File_Filter_Audio_Get()) { for (size_t Pos=0; PosStreamKind!=Stream_Audio) { Sequences.erase(Sequences.begin()+Pos); Pos--; } } #endif //MEDIAINFO_FILTER //Filling Filenames from the more complete version and Edit rates float64 EditRate=DBL_MAX; size_t EditRate_Count=0; for (Sequences_Current=0; Sequences_CurrentFileNames.empty()) for (size_t Pos=0; PosResources.size(); Pos++) { for (size_t Resource_FileNames_Pos=0; Resource_FileNames_PosResources[Pos]->FileNames.size(); Resource_FileNames_Pos++) Sequences[Sequences_Current]->FileNames.push_back(Sequences[Sequences_Current]->Resources[Pos]->FileNames[Resource_FileNames_Pos]); if (Sequences[Sequences_Current]->Resources[Pos]->EditRate && EditRate!=Sequences[Sequences_Current]->Resources[Pos]->EditRate) { if (EditRate>Sequences[Sequences_Current]->Resources[Pos]->EditRate) EditRate=Sequences[Sequences_Current]->Resources[Pos]->EditRate; EditRate_Count++; } } if (EditRate_Count>1) //Multiple rates, using only one rate for (Sequences_Current=0; Sequences_CurrentResources.size(); Pos++) if (Sequences[Sequences_Current]->Resources[Pos]->EditRate && EditRate!=Sequences[Sequences_Current]->Resources[Pos]->EditRate) { if (Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsBefore) { float64 Temp=(float64)Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsBefore; Temp/=Sequences[Sequences_Current]->Resources[Pos]->EditRate; Temp*=EditRate; Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsBefore=float64_int64s(Temp); } if (Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfter!=(int64u)-1) { float64 Temp=(float64)Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfter; Temp/=Sequences[Sequences_Current]->Resources[Pos]->EditRate; Temp*=EditRate; Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfter=float64_int64s(Temp); } if (Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfterDuration!=(int64u)-1) { float64 Temp=(float64)Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfterDuration; Temp/=Sequences[Sequences_Current]->Resources[Pos]->EditRate; Temp*=EditRate; Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfterDuration=float64_int64s(Temp); } Sequences[Sequences_Current]->Resources[Pos]->EditRate=EditRate; } //Testing IDs std::set StreamList; bool StreamList_DuplicatedIds=false; for (Sequences_Current=0; Sequences_CurrentStreamID)==StreamList.end()) StreamList.insert(Sequences[Sequences_Current]->StreamID); else { StreamList_DuplicatedIds=true; break; } if (StreamList_DuplicatedIds) for (Sequences_Current=0; Sequences_CurrentStreamID=Sequences_Current+1; if (Sequences.size()==1 && (*Sequences.begin())->StreamID==(int64u)-1) { ContainerHasNoId=true; #if MEDIAINFO_EVENTS MI->StreamIDs_Width[MI->StreamIDs_Size-1]=0; #endif //MEDIAINFO_EVENTS } std::sort(Sequences.begin(), Sequences.end(), File__ReferenceFilesHelper_Algo1); std::sort(Sequences.begin(), Sequences.end(), File__ReferenceFilesHelper_Algo2); std::sort(Sequences.begin(), Sequences.end(), File__ReferenceFilesHelper_Algo3); //InfoFromFileName File__ReferenceFilesHelper_InfoFromFileName(Sequences); #if MEDIAINFO_EVENTS if (MI->Config->Config_PerPackage==NULL) { MI->Config->Config_PerPackage=new MediaInfo_Config_PerPackage; MI->Config->Config_PerPackage->CountOfPackages=Sequences.size(); } #endif //MEDIAINFO_EVENTS //Configuring file names Sequences_Current=0; while (Sequences_CurrentFileNames; ZtringList AbsoluteNames; AbsoluteNames.Separator_Set(0, ","); for (size_t Pos=0; PosFile_Name.find(__T("://"))==string::npos) AbsoluteName=ZenLib::FileName::Path_Get(MI->File_Name); else { size_t Pos_Path=MI->File_Name.find_last_of('/'); if (Pos_Path!=Ztring::npos) AbsoluteName=MI->File_Name.substr(0, Pos_Path); } if (!AbsoluteName.empty()) AbsoluteName+=ZenLib::PathSeparator; } AbsoluteName+=Names[Pos]; #ifdef __WINDOWS__ if (AbsoluteName.find(__T("://"))==string::npos) AbsoluteName.FindAndReplace(__T("/"), __T("\\"), 0, Ztring_Recursive); //Names[Pos] normalization local file else AbsoluteName.FindAndReplace(__T("\\"), __T("/"), 0, Ztring_Recursive); //Names[Pos] normalization with protocol (so "/" in all cases) #endif //__WINDOWS__ AbsoluteNames.push_back(AbsoluteName); } if (AbsoluteNames.empty() || !(AbsoluteNames[0].find(__T("://"))!=string::npos || File::Exists(AbsoluteNames[0]))) { AbsoluteNames.clear(); //Configuring file name (this time, we try to force URL decode in all cases) for (size_t Pos=0; PosFile_Name.find(__T("://"))==string::npos) AbsoluteName=ZenLib::FileName::Path_Get(MI->File_Name); else { size_t Pos_Path=MI->File_Name.find_last_of('/'); if (Pos_Path!=Ztring::npos) AbsoluteName=MI->File_Name.substr(0, Pos_Path); } if (!AbsoluteName.empty()) AbsoluteName+=ZenLib::PathSeparator; } AbsoluteName+=Names[Pos]; #ifdef __WINDOWS__ AbsoluteName.FindAndReplace(__T("/"), __T("\\"), 0, Ztring_Recursive); //Names[Pos] normalization #endif //__WINDOWS__ AbsoluteNames.push_back(AbsoluteName); } if (AbsoluteNames.empty() || !File::Exists(AbsoluteNames[0])) { AbsoluteNames.clear(); Names=Sequences[Sequences_Current]->FileNames; //Configuring file name (this time, we try to test local files) size_t PathSeparator_Pos=Names.empty()?string::npos:Names[0].find_last_of(__T("\\/")); if (PathSeparator_Pos!=string::npos && PathSeparator_Pos) { Ztring PathToRemove=Names[0].substr(0, PathSeparator_Pos); bool IsOk=true; for (size_t Pos=0; PosFile_Name.find(__T("://"))==string::npos) AbsoluteName=ZenLib::FileName::Path_Get(MI->File_Name); else { size_t Pos_Path=MI->File_Name.find_last_of('/'); if (Pos_Path!=Ztring::npos) AbsoluteName=MI->File_Name.substr(0, Pos_Path); } if (!AbsoluteName.empty()) AbsoluteName+=ZenLib::PathSeparator; AbsoluteName+=Names[Pos]; #ifdef __WINDOWS__ if (AbsoluteName.find(__T("://"))==string::npos) AbsoluteName.FindAndReplace(__T("/"), __T("\\"), 0, Ztring_Recursive); //Names[Pos] normalization local file else AbsoluteName.FindAndReplace(__T("\\"), __T("/"), 0, Ztring_Recursive); //Names[Pos] normalization with protocol (so "/" in all cases) #endif //__WINDOWS__ AbsoluteNames.push_back(AbsoluteName); } if (!File::Exists(AbsoluteNames[0])) { AbsoluteNames.clear(); Names=Sequences[Sequences_Current]->FileNames; //Configuring file name (this time, we try to test local files) size_t PathSeparator_Pos=Names[0].find_last_of(__T("\\/")); if (PathSeparator_Pos!=string::npos && PathSeparator_Pos) PathSeparator_Pos=Names[0].find_last_of(__T("\\/"), PathSeparator_Pos-1); if (PathSeparator_Pos!=string::npos && PathSeparator_Pos) { Ztring PathToRemove=Names[0].substr(0, PathSeparator_Pos); bool IsOk=true; for (size_t Pos=0; PosFile_Name.find(__T("://"))==string::npos) AbsoluteName=ZenLib::FileName::Path_Get(MI->File_Name); else { size_t Pos_Path=MI->File_Name.find_last_of('/'); if (Pos_Path!=Ztring::npos) AbsoluteName=MI->File_Name.substr(0, Pos_Path); } if (!AbsoluteName.empty()) AbsoluteName+=ZenLib::PathSeparator; AbsoluteName+=Names[Pos]; #ifdef __WINDOWS__ AbsoluteName.FindAndReplace(__T("/"), __T("\\"), 0, Ztring_Recursive); //Names[Pos] normalization #endif //__WINDOWS__ AbsoluteNames.push_back(AbsoluteName); } } if (!AbsoluteNames.empty() && !File::Exists(AbsoluteNames[0])) AbsoluteNames.clear(); } } } } } Sequences[Sequences_Current]->Source=Sequences[Sequences_Current]->FileNames.Read(0); if (Sequences[Sequences_Current]->StreamKind!=Stream_Max && !Sequences[Sequences_Current]->Source.empty()) { if (Sequences[Sequences_Current]->StreamPos==(size_t)-1) Sequences[Sequences_Current]->StreamPos=Stream_Prepare(Sequences[Sequences_Current]->StreamKind); MI->Fill(Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos, "Source", Sequences[Sequences_Current]->Source); } if (!AbsoluteNames.empty()) Sequences[Sequences_Current]->FileNames=AbsoluteNames; if (!AbsoluteNames.empty() && AbsoluteNames[0]==MI->File_Name) { Sequences[Sequences_Current]->IsCircular=true; Sequences[Sequences_Current]->FileNames.clear(); Sequences[Sequences_Current]->Status.set(File__Analyze::IsFinished); } else if (!AbsoluteNames.empty()) Sequences[Sequences_Current]->FileNames=AbsoluteNames; else { Sequences[Sequences_Current]->Status.set(File__Analyze::IsFinished); #if MEDIAINFO_EVENTS Config->Event_SubFile_Missing(Sequences[Sequences_Current]->Source); #endif //MEDIAINFO_EVENTS if (Sequences[Sequences_Current]->StreamKind!=Stream_Max && !Sequences[Sequences_Current]->Source.empty()) { MI->Fill(Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos, "Source_Info", "Missing"); if (MI->Retrieve(Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos, General_ID).empty() && Sequences[Sequences_Current]->StreamID!=(int64u)-1) MI->Fill(Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos, General_ID, Sequences[Sequences_Current]->StreamID); for (std::map::iterator Info=Sequences[Sequences_Current]->Infos.begin(); Info!=Sequences[Sequences_Current]->Infos.end(); ++Info) { if (Info->first=="CodecID") MI->CodecID_Fill(Info->second, Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos, InfoCodecID_Format_Mpeg4); else MI->Fill(Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos, Info->first.c_str(), Info->second); } } } if (FilesForStorage) { for (size_t Pos=0; PosFileNames.size(); Pos++) { if (Pos==Sequences[Sequences_Current]->Resources.size()) Sequences[Sequences_Current]->Resources.push_back(new resource); Sequences[Sequences_Current]->Resources[Pos]->FileNames.clear(); Sequences[Sequences_Current]->Resources[Pos]->FileNames.push_back(Sequences[Sequences_Current]->FileNames[Pos]); } Sequences[Sequences_Current]->FileNames.resize(1); } Sequences_Current++; } CountOfReferencesToParse=Sequences.size(); #if MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET if (Config->NextPacket_Get()) { Demux_Interleave=Config->File_Demux_Interleave_Get(); if (Demux_Interleave) { for (sequences::iterator ReferenceSource=Sequences.begin(); ReferenceSource!=Sequences.end(); ++ReferenceSource) if ((*ReferenceSource)->FileNames.empty()) CountOfReferencesToParse--; DTS_Interval=250000000LL; // 250 milliseconds } } else Demux_Interleave=false; //Using the frame rate from the first stream having a frame rate if (!FrameRate) for (sequences::iterator ReferenceFrameRate=Sequences.begin(); ReferenceFrameRate!=Sequences.end(); ++ReferenceFrameRate) if ((*ReferenceFrameRate)->FrameRate) { FrameRate=(*ReferenceFrameRate)->FrameRate; break; } if (Config->NextPacket_Get()) { Sequences_Current=0; while (Sequences_CurrentStatus[File__Analyze::IsFinished]) { Sequences.erase(Sequences.begin()+Pos); Pos--; } CountOfReferencesToParse=Sequences.size(); if (Sequences.empty()) return; //File size handling if (MI->Config->File_Size!=MI->File_Size) { MI->Fill(Stream_General, 0, General_FileSize, MI->Config->File_Size, 10, true); MI->Fill(Stream_General, 0, General_StreamSize, MI->File_Size, 10, true); } } #endif //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET FileSize_Compute(); Sequences_Current=0; CountOfReferences_ForReadSize=Sequences.size(); Init_Done=true; #if MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET if (Config->NextPacket_Get() && MI->Demux_EventWasSent_Accept_Specific) { MI->Config->Demux_EventWasSent=true; return; } #endif //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET } while (Sequences_CurrentStatus[File__Analyze::IsFinished]) #endif //MEDIAINFO_NEXTPACKET ParseReference(); //State int64u FileSize_Parsed=0; #if MEDIAINFO_NEXTPACKET DTS_Minimal=(int64u)-1; #endif //MEDIAINFO_NEXTPACKET for (sequences::iterator ReferenceTemp=Sequences.begin(); ReferenceTemp!=Sequences.end(); ++ReferenceTemp) { if ((*ReferenceTemp)->MI) { if ((*ReferenceTemp)->State<10000) { (*ReferenceTemp)->State=(*ReferenceTemp)->MI->State_Get(); if ((*ReferenceTemp)->State && (*ReferenceTemp)->MI->Config.File_Size!=(int64u)-1) FileSize_Parsed+=(int64u)((*ReferenceTemp)->MI->Config.File_Size*(((float)(*ReferenceTemp)->State)/10000)); } else FileSize_Parsed+=(*ReferenceTemp)->MI->Config.File_Size; #if MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET //Minimal DTS if (DTS_Interval!=(int64u)-1 && !Sequences[Sequences_Current]->Status[File__Analyze::IsFinished] && ((*ReferenceTemp)->Resources.empty() || (*ReferenceTemp)->Resources_Current<(*ReferenceTemp)->Resources.size())) { int64u DTS_Temp; if (!(*ReferenceTemp)->Resources.empty() && (*ReferenceTemp)->Resources_Current) { if ((*ReferenceTemp)->Resources[(*ReferenceTemp)->Resources_Current]->MI->Info->FrameInfo.DTS!=(int64u)-1) DTS_Temp=(*ReferenceTemp)->Resources[(*ReferenceTemp)->Resources_Current]->MI->Info->FrameInfo.DTS-(*ReferenceTemp)->Resources[(*ReferenceTemp)->Resources_Current]->MI->Info->Config->Demux_Offset_DTS_FromStream; else DTS_Temp=0; } else { if ((*ReferenceTemp)->MI->Info->FrameInfo.DTS!=(int64u)-1) DTS_Temp=(*ReferenceTemp)->MI->Info->FrameInfo.DTS-(*ReferenceTemp)->MI->Info->Config->Demux_Offset_DTS_FromStream; else DTS_Temp=0; } if ((*ReferenceTemp)->Resources_Current<(*ReferenceTemp)->Resources.size()) DTS_Temp+=(*ReferenceTemp)->Resources[(*ReferenceTemp)->Resources_Current]->Demux_Offset_DTS; if (DTS_Minimal>DTS_Temp) DTS_Minimal=DTS_Temp; } #endif //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET } else FileSize_Parsed+=(*ReferenceTemp)->FileSize; } Config->State_Set(((float)FileSize_Parsed)/MI->Config->File_Size); #if MEDIAINFO_EVENTS struct MediaInfo_Event_General_SubFile_End_0 Event; MI->Event_Prepare((struct MediaInfo_Event_Generic*)&Event, MediaInfo_EventCode_Create(0, MediaInfo_Event_General_SubFile_End, 0), sizeof(struct MediaInfo_Event_General_SubFile_End_0)); MI->Config->Event_Send(NULL, (const int8u*)&Event, Event.EventSize, MI->File_Name); #endif //MEDIAINFO_EVENTS #if MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET if (Demux_Interleave && (Sequences[Sequences_Current]->MI==NULL || Sequences[Sequences_Current]->MI->Info==NULL || Sequences[Sequences_Current]->MI->Info->Demux_CurrentParser==NULL || Sequences[Sequences_Current]->MI->Info->Demux_CurrentParser->Demux_TotalBytes>=Sequences[Sequences_Current]->MI->Info->Demux_CurrentParser->Buffer_TotalBytes+Sequences[Sequences_Current]->MI->Info->Demux_CurrentParser->Buffer_Size)) { size_t Reference_Next=Sequences_Current; ++Reference_Next; if (Reference_Next==Sequences.size() && Config->NextPacket_Get() && CountOfReferencesToParse) Sequences_Current=0; else Sequences_Current=Reference_Next; if (Config->Demux_EventWasSent) return; } else { if (Config->Demux_EventWasSent) return; Sequences_Current++; if (Demux_Interleave && Sequences_Current == Sequences.size() && Config->NextPacket_Get() && CountOfReferencesToParse) Sequences_Current = 0; } #else //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET Sequences_Current++; #endif //MEDIAINFO_DEMUX } //File size handling FileSize_Compute(); if (MI->Config->File_Size!=MI->File_Size #if MEDIAINFO_ADVANCED && !Config->File_IgnoreSequenceFileSize_Get() #endif //MEDIAINFO_ADVANCED ) { MI->Fill(Stream_General, 0, General_FileSize, MI->Config->File_Size, 10, true); MI->Fill(Stream_General, 0, General_StreamSize, MI->File_Size, 10, true); } #if MEDIAINFO_ADVANCED if (Config->File_IgnoreSequenceFileSize_Get()) MI->Clear(Stream_General, 0, General_FileSize); #endif //MEDIAINFO_ADVANCED } //--------------------------------------------------------------------------- bool File__ReferenceFilesHelper::ParseReference_Init() { //Configuration Sequences[Sequences_Current]->MI=MI_Create(); if (Config->ParseSpeed>=1) { for (size_t Pos=0; PosResources.size(); Pos++) { if (Sequences[Sequences_Current]->Resources[0]->EditRate) { #if MEDIAINFO_DEMUX if (Pos==0) { Sequences[Sequences_Current]->Resources[0]->Demux_Offset_DTS=0; Sequences[Sequences_Current]->Resources[0]->Demux_Offset_Frame=0; } if (Pos+1Resources.size()) { Sequences[Sequences_Current]->Resources[Pos+1]->Demux_Offset_DTS=float64_int64s(Sequences[Sequences_Current]->Resources[Pos]->Demux_Offset_DTS+(Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfter-Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsBefore)/Sequences[Sequences_Current]->Resources[0]->EditRate*1000000000); Sequences[Sequences_Current]->Resources[Pos+1]->Demux_Offset_Frame=Sequences[Sequences_Current]->Resources[Pos]->Demux_Offset_Frame+Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfter-Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsBefore; } #endif //MEDIAINFO_DEMUX } else { MediaInfo_Internal MI2; MI2.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI2.Option(__T("ParseSpeed_Get"), __T("0")); Ztring Demux_Save=MI2.Option(__T("Demux_Get"), __T("")); MI2.Option(__T("ParseSpeed"), __T("0")); MI2.Option(__T("Demux"), Ztring()); Sequences[Sequences_Current]->Resources[Pos]->FileNames.Separator_Set(0, ","); size_t MiOpenResult=MI2.Open(Sequences[Sequences_Current]->Resources[Pos]->FileNames.Read()); MI2.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI2.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (MiOpenResult) { #if MEDIAINFO_DEMUX int64u Duration=MI2.Get(Sequences[Sequences_Current]->StreamKind, 0, __T("Duration")).To_int64u()*1000000; int64u FrameCount=MI2.Get(Sequences[Sequences_Current]->StreamKind, 0, __T("FrameCount")).To_int64u(); if (Pos==0) { int64u Delay=MI2.Get(Stream_Video, 0, Video_Delay).To_int64u()*1000000; if (Sequences[Sequences_Current]->StreamKind==Stream_Video && Offset_Video_DTS==0) Offset_Video_DTS=Delay; Sequences[Sequences_Current]->Resources[0]->Demux_Offset_DTS=Offset_Video_DTS; Sequences[Sequences_Current]->Resources[0]->Demux_Offset_Frame=0; } if (Pos+1Resources.size()) { Sequences[Sequences_Current]->Resources[Pos+1]->Demux_Offset_DTS=Sequences[Sequences_Current]->Resources[Pos]->Demux_Offset_DTS+Duration; Sequences[Sequences_Current]->Resources[Pos+1]->Demux_Offset_Frame=Sequences[Sequences_Current]->Resources[Pos]->Demux_Offset_Frame+FrameCount; } else Duration=Sequences[Sequences_Current]->Resources[Pos]->Demux_Offset_DTS+Duration-Sequences[Sequences_Current]->Resources[0]->Demux_Offset_DTS; #endif //MEDIAINFO_DEMUX } } if (Pos) { Sequences[Sequences_Current]->Resources[Pos]->MI=MI_Create(); Sequences[Sequences_Current]->Resources[Pos]->MI->Config.File_IgnoreEditsBefore=Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsBefore; if (Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfter==(int64u)-1 && Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfterDuration!=(int64u)-1) Sequences[Sequences_Current]->Resources[Pos]->MI->Config.File_IgnoreEditsAfter=Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsBefore+Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfterDuration; else Sequences[Sequences_Current]->Resources[Pos]->MI->Config.File_IgnoreEditsAfter=Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfter; Sequences[Sequences_Current]->Resources[Pos]->MI->Config.File_EditRate=Sequences[Sequences_Current]->Resources[Pos]->EditRate; #if MEDIAINFO_DEMUX Sequences[Sequences_Current]->Resources[Pos]->MI->Config.Demux_Offset_Frame=Sequences[Sequences_Current]->Resources[Pos]->Demux_Offset_Frame; Sequences[Sequences_Current]->Resources[Pos]->MI->Config.Demux_Offset_DTS=Sequences[Sequences_Current]->Resources[Pos]->Demux_Offset_DTS; #endif //MEDIAINFO_DEMUX } } if (!Sequences[Sequences_Current]->Resources.empty()) { Sequences[Sequences_Current]->MI->Config.File_IgnoreEditsBefore=Sequences[Sequences_Current]->Resources[0]->IgnoreEditsBefore; if (Sequences[Sequences_Current]->Resources[0]->IgnoreEditsAfter==(int64u)-1 && Sequences[Sequences_Current]->Resources[0]->IgnoreEditsAfterDuration!=(int64u)-1) Sequences[Sequences_Current]->MI->Config.File_IgnoreEditsAfter=Sequences[Sequences_Current]->Resources[0]->IgnoreEditsBefore+Sequences[Sequences_Current]->Resources[0]->IgnoreEditsAfterDuration; else Sequences[Sequences_Current]->MI->Config.File_IgnoreEditsAfter=Sequences[Sequences_Current]->Resources[0]->IgnoreEditsAfter; Sequences[Sequences_Current]->MI->Config.File_EditRate=Sequences[Sequences_Current]->Resources[0]->EditRate; #if MEDIAINFO_DEMUX Sequences[Sequences_Current]->MI->Config.Demux_Offset_Frame=Sequences[Sequences_Current]->Resources[0]->Demux_Offset_Frame; Sequences[Sequences_Current]->MI->Config.Demux_Offset_DTS=Sequences[Sequences_Current]->Resources[0]->Demux_Offset_DTS; #endif //MEDIAINFO_DEMUX } } if (Sequences[Sequences_Current]->IsCircular) { MI->Fill(Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos, "Source_Info", "Circular"); if (!Config->File_KeepInfo_Get()) { #if MEDIAINFO_DEMUX if (CountOfReferencesToParse) CountOfReferencesToParse--; #endif //MEDIAINFO_DEMUX Sequences[Sequences_Current]->StreamKind=Stream_Max; Sequences[Sequences_Current]->StreamPos=(size_t)-1; Sequences[Sequences_Current]->FileSize=Sequences[Sequences_Current]->MI->Config.File_Size; delete Sequences[Sequences_Current]->MI; Sequences[Sequences_Current]->MI=NULL; } Sequences[Sequences_Current]->FileNames.clear(); Sequences[Sequences_Current]->Status.set(File__Analyze::IsFinished); } else { //Run #if MEDIAINFO_EVENTS SubFile_Start(); #endif //MEDIAINFO_EVENTS if (!Sequences[Sequences_Current]->MI->Open(Sequences[Sequences_Current]->FileNames.Read())) { #if MEDIAINFO_EVENTS Config->Event_SubFile_Missing(Sequences[Sequences_Current]->Source); #endif //MEDIAINFO_EVENTS if (Sequences[Sequences_Current]->StreamKind!=Stream_Max) MI->Fill(Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos, "Source_Info", "Missing", Unlimited, true, true); if (!Config->File_KeepInfo_Get()) { #if MEDIAINFO_DEMUX if (CountOfReferencesToParse) CountOfReferencesToParse--; #endif //MEDIAINFO_DEMUX Sequences[Sequences_Current]->StreamKind=Stream_Max; Sequences[Sequences_Current]->StreamPos=(size_t)-1; Sequences[Sequences_Current]->FileSize=Sequences[Sequences_Current]->MI->Config.File_Size; delete Sequences[Sequences_Current]->MI; Sequences[Sequences_Current]->MI=NULL; } Sequences[Sequences_Current]->Status.set(File__Analyze::IsFinished); } if (Config->ParseSpeed>=1) for (size_t Pos=1; PosResources.size(); Pos++) { Sequences[Sequences_Current]->Resources[Pos]->FileNames.Separator_Set(0, ","); Sequences[Sequences_Current]->Resources[Pos]->MI->Open(Sequences[Sequences_Current]->Resources[Pos]->FileNames.Read()); } #if MEDIAINFO_NEXTPACKET && MEDIAINFO_DEMUX if (Config->NextPacket_Get()) return false; #endif //MEDIAINFO_NEXTPACKET } return true; } //--------------------------------------------------------------------------- void File__ReferenceFilesHelper::ParseReference() { if (Sequences[Sequences_Current]->MI==NULL && !Sequences[Sequences_Current]->FileNames.empty()) { if (!ParseReference_Init()) return; } if (Sequences[Sequences_Current]->MI) { #if MEDIAINFO_EVENTS && MEDIAINFO_NEXTPACKET if (DTS_Interval!=(int64u)-1 && !Sequences[Sequences_Current]->Status[File__Analyze::IsFinished] && Sequences[Sequences_Current]->MI->Info->FrameInfo.DTS!=(int64u)-1 && DTS_Minimal!=(int64u)-1 && (Sequences[Sequences_Current]->Resources.empty() || Sequences[Sequences_Current]->Resources_CurrentResources.size())) { int64u DTS_Temp = 0; #if MEDIAINFO_DEMUX if (!Sequences[Sequences_Current]->Resources.empty() && Sequences[Sequences_Current]->Resources_Current) { if (Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->MI->Info->FrameInfo.DTS!=(int64u)-1) DTS_Temp=Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->MI->Info->FrameInfo.DTS-Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->MI->Info->Config->Demux_Offset_DTS_FromStream;; } else { if (Sequences[Sequences_Current]->MI->Info->FrameInfo.DTS!=(int64u)-1) DTS_Temp=Sequences[Sequences_Current]->MI->Info->FrameInfo.DTS-Sequences[Sequences_Current]->MI->Info->Config->Demux_Offset_DTS_FromStream; } #endif //MEDIAINFO_DEMUX DTS_Temp+=Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->Demux_Offset_DTS; if (!Sequences[Sequences_Current]->Resources.empty() && Sequences[Sequences_Current]->Resources_CurrentResources.size() && Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->EditRate && Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->IgnoreEditsBefore) { int64u TimeOffset=float64_int64s(((float64)Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->IgnoreEditsBefore)/Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->EditRate*1000000000); if (DTS_Temp>TimeOffset) DTS_Temp-=TimeOffset; else DTS_Temp=0; } if (DTS_Temp>DTS_Minimal+DTS_Interval) return; } if (Config->Event_CallBackFunction_IsSet() && !Sequences[Sequences_Current]->Status[File__Analyze::IsFinished]) { #if MEDIAINFO_DEMUX SubFile_Start(); if (Sequences[Sequences_Current]->Resources_Current==0) { while ((Sequences[Sequences_Current]->Status=Sequences[Sequences_Current]->MI->Open_NextPacket())[8]) { if (!Sequences[Sequences_Current]->FileSize_IsPresent && Sequences[Sequences_Current]->MI->Config.File_Size!=(int64u)-1) { Sequences[Sequences_Current]->FileSize_IsPresent=true; if (CountOfReferences_ForReadSize) { CountOfReferences_ForReadSize--; if (!CountOfReferences_ForReadSize) CountOfReferences_ForReadSize_Run(); } } if (Config->Event_CallBackFunction_IsSet()) { Config->Demux_EventWasSent=true; return; } } Sequences[Sequences_Current]->Resources_Current++; if (Sequences[Sequences_Current]->Resources_CurrentResources.size() && Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->MI) Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->MI->Open_Buffer_Seek(0, 0, (int64u)-1); } #if MEDIAINFO_NEXTPACKET && MEDIAINFO_DEMUX if (Config->ParseSpeed<1.0) Sequences[Sequences_Current]->Resources_Current=Sequences[Sequences_Current]->Resources.size(); //No need to parse all files #endif //MEDIAINFO_NEXTPACKET while (Sequences[Sequences_Current]->Resources_CurrentResources.size()) { while ((Sequences[Sequences_Current]->Status=Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->MI->Open_NextPacket())[8]) { if (!Sequences[Sequences_Current]->FileSize_IsPresent && Sequences[Sequences_Current]->MI->Config.File_Size!=(int64u)-1) { Sequences[Sequences_Current]->FileSize_IsPresent=true; if (CountOfReferences_ForReadSize) { CountOfReferences_ForReadSize--; if (!CountOfReferences_ForReadSize) CountOfReferences_ForReadSize_Run(); } } if (Config->Event_CallBackFunction_IsSet()) { Config->Demux_EventWasSent=true; return; } } Sequences[Sequences_Current]->Resources_Current++; if (Sequences[Sequences_Current]->Resources_CurrentResources.size() && Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->MI) Sequences[Sequences_Current]->Resources[Sequences[Sequences_Current]->Resources_Current]->MI->Open_Buffer_Seek(0, 0, (int64u)-1); } if (CountOfReferencesToParse) CountOfReferencesToParse--; #endif //MEDIAINFO_DEMUX } #endif //MEDIAINFO_EVENTS && MEDIAINFO_NEXTPACKET ParseReference_Finalize(); if (!Config->File_KeepInfo_Get()) { Sequences[Sequences_Current]->StreamKind=Stream_Max; Sequences[Sequences_Current]->StreamPos=(size_t)-1; Sequences[Sequences_Current]->State=10000; if (Sequences[Sequences_Current]->Resources.empty()) Sequences[Sequences_Current]->FileSize=Sequences[Sequences_Current]->MI->Config.File_Size; else if (Sequences[Sequences_Current]->FileSize==(int64u)-1) { Sequences[Sequences_Current]->FileSize=0; for (size_t Pos=0; PosResources.size(); Pos++) for (size_t Resource_FileNames_Pos=0; Resource_FileNames_PosResources[Pos]->FileNames.size(); Resource_FileNames_Pos++) Sequences[Sequences_Current]->FileSize+=File::Size_Get(Sequences[Sequences_Current]->Resources[Pos]->FileNames[Resource_FileNames_Pos]); } delete Sequences[Sequences_Current]->MI; Sequences[Sequences_Current]->MI=NULL; } } } //--------------------------------------------------------------------------- void File__ReferenceFilesHelper::ParseReference_Finalize () { //Removing wrong initial value if (Sequences[Sequences_Current]->MI->Count_Get(Sequences[Sequences_Current]->StreamKind)==0 && Sequences[Sequences_Current]->StreamPos!=(size_t)-1 && Sequences[Sequences_Current]->MI->Count_Get(Stream_Video)+Sequences[Sequences_Current]->MI->Count_Get(Stream_Audio)+Sequences[Sequences_Current]->MI->Count_Get(Stream_Image)+Sequences[Sequences_Current]->MI->Count_Get(Stream_Text)+Sequences[Sequences_Current]->MI->Count_Get(Stream_Other)) { MI->Stream_Erase(Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos); for (sequences::iterator ReferenceTemp=Sequences.begin(); ReferenceTemp!=Sequences.end(); ++ReferenceTemp) if ((*ReferenceTemp)->StreamKind==Sequences[Sequences_Current]->StreamKind && (*ReferenceTemp)->StreamPos!=(size_t)-1 && (*ReferenceTemp)->StreamPos>Sequences[Sequences_Current]->StreamPos) (*ReferenceTemp)->StreamPos--; Sequences[Sequences_Current]->StreamPos=(size_t)-1; } bool StreamFound=false; for (size_t StreamKind=Stream_General+1; StreamKindMI->Count_Get((stream_t)StreamKind); StreamPos++) { StreamKind_Last=(stream_t)StreamKind; if (Sequences[Sequences_Current]->StreamPos!=(size_t)-1 && StreamKind_Last==Sequences[Sequences_Current]->StreamKind && StreamPos==0) { StreamPos_To=Sequences[Sequences_Current]->StreamPos; StreamFound=true; Title_Temp=MI->Retrieve_Const(StreamKind_Last, StreamPos_To-StreamPos, "Title"); } else { size_t ToInsert=(size_t)-1; for (sequences::iterator ReferencePos=Sequences.begin(); ReferencePos!=Sequences.end(); ++ReferencePos) if ((*ReferencePos)->StreamKind==StreamKind_Last && Sequences[Sequences_Current]->StreamID<(*ReferencePos)->StreamID) { ToInsert=(*ReferencePos)->StreamPos; break; } StreamPos_To=Stream_Prepare((stream_t)StreamKind, ToInsert); if (StreamPos) MI->Fill(StreamKind_Last, StreamPos_To, "Title", Title_Temp); } StreamPos_From=StreamPos; ParseReference_Finalize_PerStream(); } } if (!StreamFound && Sequences[Sequences_Current]->StreamKind!=Stream_Max && Sequences[Sequences_Current]->StreamPos!=(size_t)-1 && Sequences[Sequences_Current]->MI->Info) { Ztring MuxingMode=MI->Retrieve(Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos, "MuxingMode"); if (!MuxingMode.empty()) MuxingMode.insert(0, __T(" / ")); MI->Fill(Sequences[Sequences_Current]->StreamKind, Sequences[Sequences_Current]->StreamPos, "MuxingMode", Sequences[Sequences_Current]->MI->Info->Get(Stream_General, 0, General_Format)+MuxingMode, true); } } //--------------------------------------------------------------------------- void File__ReferenceFilesHelper::ParseReference_Finalize_PerStream () { //Hacks - Before Ztring CodecID=MI->Retrieve(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_CodecID)); Ztring ID_Base; if (HasMainFile_Filled && !Sequences[Sequences_Current]->IsMain) { ID_Base=Ztring::ToZtring(ID_Max+Sequences[Sequences_Current]->StreamID-1); MI->Fill(StreamKind_Last, StreamPos_To, "SideCar_FilePos", Sequences[Sequences_Current]->StreamID-1); MI->Fill_SetOptions(StreamKind_Last, StreamPos_To, "SideCar_FilePos", "N NT"); } else if (Sequences[Sequences_Current]->StreamID!=(int64u)-1) ID_Base=Ztring::ToZtring(Sequences[Sequences_Current]->StreamID); Ztring ID=ID_Base; Ztring ID_String=ID_Base; Ztring MenuID; Ztring MenuID_String; if (!HasMainFile_Filled && Sequences[Sequences_Current]->IsMain) { MI->Fill(Stream_General, 0, General_Format, Sequences[Sequences_Current]->MI->Get(Stream_General, 0, General_Format) , true); MI->Fill(Stream_General, 0, General_CompleteName, Sequences[Sequences_Current]->MI->Get(Stream_General, 0, General_CompleteName) , true); MI->Fill(Stream_General, 0, General_FileExtension, Sequences[Sequences_Current]->MI->Get(Stream_General, 0, General_FileExtension) , true); HasMainFile=true; HasMainFile_Filled=true; } if (Sequences[Sequences_Current]->IsMain) { int64u ID_New=Sequences[Sequences_Current]->MI->Get(StreamKind_Last, StreamPos_From, General_ID).To_int64u(); if (ID_MaxClear(StreamKind_Last, StreamPos_To, General_ID); MI->Merge(*Sequences[Sequences_Current]->MI->Info, StreamKind_Last, StreamPos_From, StreamPos_To); if (!Sequences[Sequences_Current]->Resources.empty()) { MI->Clear(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_BitRate)); MI->Clear(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_Duration)); MI->Clear(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_FrameCount)); MI->Clear(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_StreamSize)); float64 BitRate_Before=0; int64u Duration_Temp=0; int64u FrameCount_Temp=0; int64u StreamSize_Temp=0; int64u FileSize_Temp=0; #if MEDIAINFO_ADVANCED std::vector Format_Profiles_FromStream, Format_Profiles_FromContainer, Format_Profiles_FromPlaylist; #endif //MEDIAINFO_ADVANCED for (size_t Pos=0; PosResources.size(); Pos++) { MediaInfo_Internal MI2; MI2.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI2.Option(__T("ParseSpeed_Get"), __T("")); Ztring Demux_Save=MI2.Option(__T("Demux_Get"), __T("")); MI2.Option(__T("ParseSpeed"), __T("0")); MI2.Option(__T("Demux"), Ztring()); MI2.Config.File_IgnoreEditsBefore=Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsBefore; if (Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfter==(int64u)-1 && Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfterDuration!=(int64u)-1) MI2.Config.File_IgnoreEditsAfter=Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsBefore+Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfterDuration; else MI2.Config.File_IgnoreEditsAfter=Sequences[Sequences_Current]->Resources[Pos]->IgnoreEditsAfter; MI2.Config.File_EditRate=Sequences[Sequences_Current]->Resources[Pos]->EditRate; Sequences[Sequences_Current]->Resources[Pos]->FileNames.Separator_Set(0, ","); size_t MiOpenResult=MI2.Open(Sequences[Sequences_Current]->Resources[Pos]->FileNames.Read()); MI2.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI2.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (MiOpenResult) { BitRate_Before=MI2.Get(StreamKind_Last, StreamPos_From, MI->Fill_Parameter(StreamKind_Last, Generic_BitRate)).To_float64(); Ztring Duration_Temp2=MI2.Get(StreamKind_Last, StreamPos_From, MI->Fill_Parameter(StreamKind_Last, Generic_Duration)); if (!Duration_Temp2.empty() && Duration_Temp!=(int64u)-1) Duration_Temp+=Duration_Temp2.To_int64u(); else Duration_Temp=(int64u)-1; Ztring FrameCount_Temp2=MI2.Get(StreamKind_Last, StreamPos_From, MI->Fill_Parameter(StreamKind_Last, Generic_FrameCount)); if (!FrameCount_Temp2.empty() && FrameCount_Temp!=(int64u)-1) FrameCount_Temp+=FrameCount_Temp2.To_int64u(); else FrameCount_Temp=(int64u)-1; Ztring StreamSize_Temp2=MI2.Get(StreamKind_Last, StreamPos_From, MI->Fill_Parameter(StreamKind_Last, Generic_StreamSize)); if (!StreamSize_Temp2.empty() && StreamSize_Temp!=(int64u)-1) StreamSize_Temp+=StreamSize_Temp2.To_int64u(); else StreamSize_Temp=(int64u)-1; Ztring FileSize_Temp2=MI2.Get(Stream_General, 0, General_FileSize); if (!FileSize_Temp2.empty() && FileSize_Temp!=(int64u)-1) FileSize_Temp+=FileSize_Temp2.To_int64u(); else FileSize_Temp=(int64u)-1; } else { Duration_Temp=(int64u)-1; FrameCount_Temp=(int64u)-1; StreamSize_Temp=(int64u)-1; FileSize_Temp=(int64u)-1; break; } #if MEDIAINFO_ADVANCED //Profile map::iterator MetadataFromPlaylist_Item=Sequences[Sequences_Current]->Resources[Pos]->MetadataFromPlaylist.find("Format_Profile"); if (MetadataFromPlaylist_Item!=Sequences[Sequences_Current]->Resources[Pos]->MetadataFromPlaylist.end()) Format_Profiles_FromPlaylist.push_back(MetadataFromPlaylist_Item->second); else Format_Profiles_FromPlaylist.push_back(string()); Format_Profiles_FromContainer.push_back(MI2.Get(StreamKind_Last, StreamPos_From, __T("Format_Profile_FromContainer")).To_UTF8()); Format_Profiles_FromStream.push_back(MI2.Get(StreamKind_Last, StreamPos_From, MI->Fill_Parameter(StreamKind_Last, Generic_Format_Profile)).To_UTF8()); #endif //MEDIAINFO_ADVANCED } #if MEDIAINFO_ADVANCED //Test of coherency between Playlist and Stream //Test of same values for all resources bool Format_Profile_NotSame=false; bool Format_Profile_CoherencyIssue=false; bool Format_Profile_FromContainer_IsPresent=false; for (size_t Pos=0; PosClear(StreamKind_Last, StreamPos_To, "Format_Profile"); for (size_t Pos=0; PosFill(StreamKind_Last, StreamPos_To, "Format_Profile", Format_Profiles_FromStream[Pos]); MI->Fill(StreamKind_Last, StreamPos_To, "Format_Profile_EssencesMismatch", "Yes"); } if (Format_Profile_CoherencyIssue) { MI->Clear(StreamKind_Last, StreamPos_To, "Format_Profile_FromStream"); if (Format_Profile_FromContainer_IsPresent) MI->Clear(StreamKind_Last, StreamPos_To, "Format_Profile_FromContainer"); MI->Clear(StreamKind_Last, StreamPos_To, "Format_Profile_FromPlaylist"); for (size_t Pos=0; PosFill(StreamKind_Last, StreamPos_To, "Format_Profile_FromStream", Format_Profiles_FromStream[Pos]); if (Format_Profile_FromContainer_IsPresent) MI->Fill(StreamKind_Last, StreamPos_To, "Format_Profile_FromContainer", Format_Profiles_FromContainer[Pos].empty()?Format_Profiles_FromStream[Pos]:Format_Profiles_FromContainer[Pos]); MI->Fill(StreamKind_Last, StreamPos_To, "Format_Profile_FromPlaylist", Format_Profiles_FromPlaylist[Pos]); } } else if (Format_Profile_FromContainer_IsPresent) { MI->Clear(StreamKind_Last, StreamPos_To, "Format_Profile_FromStream"); MI->Clear(StreamKind_Last, StreamPos_To, "Format_Profile_FromContainer"); for (size_t Pos=0; PosFill(StreamKind_Last, StreamPos_To, "Format_Profile_FromStream", Format_Profiles_FromStream[Pos]); MI->Fill(StreamKind_Last, StreamPos_To, "Format_Profile_FromContainer", Format_Profiles_FromContainer[Pos].empty()?Format_Profiles_FromStream[Pos]:Format_Profiles_FromContainer[Pos]); } } #endif //MEDIAINFO_ADVANCED if (Duration_Temp!=(int64u)-1) MI->Fill(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_Duration), Duration_Temp, 10, true); if (FrameCount_Temp!=(int64u)-1) MI->Fill(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_FrameCount), FrameCount_Temp, 10, true); if (StreamSize_Temp!=(int64u)-1) MI->Fill(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_StreamSize), StreamSize_Temp, 10, true); if (FileSize_Temp!=(int64u)-1) Sequences[Sequences_Current]->FileSize=FileSize_Temp; if (BitRate_Before && Duration_Temp) { float64 BitRate_After=((float64)StreamSize_Temp)*8000/Duration_Temp; if (BitRate_Before>BitRate_After*0.999 && BitRate_BeforeFill(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_BitRate), BitRate_Before, 0, true); //In case of similar bitrate, there is great chance hte compute bit rate is different due to aproximation errors only, using the previous one. TODO: find a better way to detect it } } //Frame rate if available from container if (StreamKind_Last==Stream_Video && Sequences[Sequences_Current]->FrameRate) MI->Fill(Stream_Video, StreamPos_To, Video_FrameRate, Sequences[Sequences_Current]->FrameRate, 3 , true); //Hacks - After if (!Sequences[Sequences_Current]->IsMain && CodecID!=MI->Retrieve(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_CodecID))) { if (!CodecID.empty()) CodecID+=__T(" / "); CodecID+=MI->Retrieve(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_CodecID)); MI->Fill(StreamKind_Last, StreamPos_To, MI->Fill_Parameter(StreamKind_Last, Generic_CodecID), CodecID, true); } if (!Sequences[Sequences_Current]->IsMain && Sequences[Sequences_Current]->MI->Count_Get(Stream_Video)+Sequences[Sequences_Current]->MI->Count_Get(Stream_Audio)>1 && Sequences[Sequences_Current]->MI->Get(Stream_Video, 0, Video_Format)!=__T("DV") && Sequences[Sequences_Current]->MI->Get(Stream_Audio, 0, Audio_Format)!=__T("Dolby E")) { if (StreamKind_Last==Stream_Menu) { ZtringList List; List.Separator_Set(0, __T(" / ")); List.Write(MI->Retrieve(StreamKind_Last, StreamPos_To, "List")); ZtringList List_String; List_String.Separator_Set(0, __T(" / ")); List_String.Write(MI->Retrieve(StreamKind_Last, StreamPos_To, "List/String")); if (!ID_Base.empty()) for (size_t Pos=0; PosFill(Stream_Menu, StreamPos_To, Menu_List, List.Read(), true); MI->Fill(Stream_Menu, StreamPos_To, Menu_List_String, List_String.Read(), true); } else if (Sequences.size()>1 && Sequences[Sequences_Current]->MI->Count_Get(Stream_Menu)==0) { if (Sequences[Sequences_Current]->MenuPos==(size_t)-1) { Sequences[Sequences_Current]->MenuPos=MI->Stream_Prepare(Stream_Menu); MI->Fill(Stream_Menu, Sequences[Sequences_Current]->MenuPos, General_ID, ID_Base); MI->Fill(Stream_Menu, Sequences[Sequences_Current]->MenuPos, "Source", Sequences[Sequences_Current]->Source); } Ztring List=Sequences[Sequences_Current]->MI->Get(StreamKind_Last, StreamPos_From, General_ID); Ztring List_String=Sequences[Sequences_Current]->MI->Get(StreamKind_Last, StreamPos_From, General_ID_String); if (!ID_Base.empty()) { List.insert(0, ID_Base+__T("-")); List_String.insert(0, ID_Base+__T("-")); } MI->Fill(Stream_Menu, Sequences[Sequences_Current]->MenuPos, Menu_List, List); MI->Fill(Stream_Menu, Sequences[Sequences_Current]->MenuPos, Menu_List_String, List_String); } } if (!Sequences[Sequences_Current]->IsMain && (ContainerHasNoId || !Config->File_ID_OnlyRoot_Get() || Sequences[Sequences_Current]->MI->Get(Stream_General, 0, General_Format)==__T("SCC") || Sequences[Sequences_Current]->MI->Count_Get(Stream_Video)+Sequences[Sequences_Current]->MI->Count_Get(Stream_Audio)>1) && !MI->Retrieve(StreamKind_Last, StreamPos_To, General_ID).empty()) { if (!ID.empty()) ID+=__T('-'); ID+=MI->Retrieve(StreamKind_Last, StreamPos_To, General_ID); if (!ID_String.empty()) ID_String+=__T('-'); ID_String+=MI->Retrieve(StreamKind_Last, StreamPos_To, General_ID_String); if (!MI->Retrieve(StreamKind_Last, StreamPos_To, "MenuID").empty()) { if (!ID_Base.empty()) MenuID=ID_Base+__T('-'); MenuID+=MI->Retrieve(StreamKind_Last, StreamPos_To, "MenuID"); if (!ID_Base.empty()) MenuID_String=ID_Base+__T('-'); MenuID_String+=MI->Retrieve(StreamKind_Last, StreamPos_To, "MenuID/String"); } else if (Sequences[Sequences_Current]->MenuPos!=(size_t)-1) { MenuID=ID_Base; MenuID_String=ID_Base; } } if (!Sequences[Sequences_Current]->IsMain) { MI->Fill(StreamKind_Last, StreamPos_To, General_ID, ID, true); MI->Fill(StreamKind_Last, StreamPos_To, General_ID_String, ID_String, true); MI->Fill(StreamKind_Last, StreamPos_To, "MenuID", MenuID, true); MI->Fill(StreamKind_Last, StreamPos_To, "MenuID/String", MenuID_String, true); if (!MI->Retrieve(StreamKind_Last, StreamPos_To, "Source").empty()) { if (MI->Retrieve(StreamKind_Last, StreamPos_To, "Source_Original").empty() && Sequences[Sequences_Current]->Source!=MI->Retrieve(StreamKind_Last, StreamPos_To, "Source")) // TODO: better handling { MI->Fill(StreamKind_Last, StreamPos_To, "Source_Original", MI->Retrieve(StreamKind_Last, StreamPos_To, "Source")); MI->Fill(StreamKind_Last, StreamPos_To, "Source_Original_Kind", MI->Retrieve(StreamKind_Last, StreamPos_To, "Source_Kind")); MI->Fill(StreamKind_Last, StreamPos_To, "Source_Original_Info", MI->Retrieve(StreamKind_Last, StreamPos_To, "Source_Info")); } MI->Clear(StreamKind_Last, StreamPos_To, "Source"); MI->Clear(StreamKind_Last, StreamPos_To, "Source_Kind"); MI->Clear(StreamKind_Last, StreamPos_To, "Source_Info"); } MI->Fill(StreamKind_Last, StreamPos_To, "Source", Sequences[Sequences_Current]->Source); } for (std::map::iterator Info=Sequences[Sequences_Current]->Infos.begin(); Info!=Sequences[Sequences_Current]->Infos.end(); ++Info) if (MI->Retrieve(StreamKind_Last, StreamPos_To, Info->first.c_str()).empty()) MI->Fill(StreamKind_Last, StreamPos_To, Info->first.c_str(), Info->second); //Others if (!Sequences[Sequences_Current]->IsMain && Sequences[Sequences_Current]->MI->Info && MI->Retrieve(StreamKind_Last, StreamPos_To, Sequences[Sequences_Current]->MI->Info->Fill_Parameter(StreamKind_Last, Generic_Format))!=Sequences[Sequences_Current]->MI->Info->Get(Stream_General, 0, General_Format)) { Ztring MuxingMode=MI->Retrieve(StreamKind_Last, StreamPos_To, "MuxingMode"); if (!MuxingMode.empty()) MuxingMode.insert(0, __T(" / ")); MI->Fill(StreamKind_Last, StreamPos_To, "MuxingMode", Sequences[Sequences_Current]->MI->Info->Get(Stream_General, 0, General_Format)+MuxingMode, true); } //Lists #if MEDIAINFO_ADVANCED || MEDIAINFO_HASH if (!Sequences[Sequences_Current]->List_Compute_Done && (Sequences[Sequences_Current]->MI->Count_Get(Stream_Menu)==0 || StreamKind_Last==Stream_Menu)) { List_Compute(); Sequences[Sequences_Current]->List_Compute_Done=true; } #endif //MEDIAINFO_ADVANCED || MEDIAINFO_HASH } //--------------------------------------------------------------------------- #if MEDIAINFO_ADVANCED || MEDIAINFO_HASH void File__ReferenceFilesHelper::List_Compute() { stream_t StreamKind=Sequences.size()>1?StreamKind_Last:Stream_General; size_t StreamPos=Sequences.size()>1?StreamPos_To:0; stream_t StreamKind_Target=Sequences[Sequences_Current]->MenuPos==(size_t)-1?StreamKind:Stream_Menu; size_t StreamPos_Target=Sequences[Sequences_Current]->MenuPos==(size_t)-1?StreamPos:Sequences[Sequences_Current]->MenuPos; //Hash #if MEDIAINFO_HASH if (!HasMainFile && Config->File_Hash_Get().to_ulong()) { for (size_t Hash_Pos=0; Hash_PosMI->Get(Stream_General, 0, Hash_NameU+__T("_Generated")).empty()) { if (Sequences[Sequences_Current]->MI->Config.File_Names.size()==1) { if (MI->Retrieve(StreamKind_Target, StreamPos_Target, "Source").empty()) { Ztring SourcePath; Ztring SourceName=MI->Retrieve(Stream_General, 0, General_CompleteName); if (SourceName.find(__T("://"))==string::npos) SourcePath=ZenLib::FileName::Path_Get(SourceName); else { size_t Pos_Path=SourceName.find_last_of('/'); if (Pos_Path!=Ztring::npos) SourcePath=SourceName.substr(0, Pos_Path); } size_t SourcePath_Size=SourcePath.size()+1; //Path size + path separator size Ztring Temp=Sequences[Sequences_Current]->MI->Config.File_Names[0]; if (!Config->File_IsReferenced_Get()) Temp.erase(0, SourcePath_Size); MI->Fill(StreamKind_Target, StreamPos_Target, "Source", Temp); } MI->Fill(StreamKind_Target, StreamPos_Target, ("Source_"+Hash_Name+"_Generated").c_str(), Sequences[Sequences_Current]->MI->Get(Stream_General, 0, Hash_NameU+__T("_Generated"))); MI->Fill_SetOptions(StreamKind_Target, StreamPos_Target, ("Source_"+Hash_Name+"_Generated").c_str(), "N NT"); } MI->Fill(StreamKind_Target, StreamPos_Target, ("Source_List_"+Hash_Name+"_Generated").c_str(), Sequences[Sequences_Current]->MI->Get(Stream_General, 0, Hash_NameU+__T("_Generated"))); MI->Fill_SetOptions(StreamKind_Target, StreamPos_Target, ("Source_List_"+Hash_Name+"_Generated").c_str(), "N NT"); } if (!Sequences[Sequences_Current]->MI->Get(Stream_General, 0, __T("Source_List_")+Hash_NameU+__T("_Generated")).empty()) { MI->Fill(StreamKind_Target, StreamPos_Target, ("Source_List_"+Hash_Name+"_Generated").c_str(), Sequences[Sequences_Current]->MI->Get(Stream_General, 0, __T("Source_List_")+Hash_NameU+__T("_Generated"))); MI->Fill_SetOptions(StreamKind_Target, StreamPos_Target, ("Source_List_"+Hash_Name+"_Generated").c_str(), "N NT"); } else if (!Sequences[Sequences_Current]->MI->Get(StreamKind, StreamPos, __T("Source_List_")+Hash_NameU+__T("_Generated")).empty()) { MI->Fill(StreamKind_Target, StreamPos_Target, ("Source_List_"+Hash_Name+"_Generated").c_str(), Sequences[Sequences_Current]->MI->Get(StreamKind, StreamPos, __T("Source_List_")+Hash_NameU+__T("_Generated"))); MI->Fill_SetOptions(StreamKind_Target, StreamPos_Target, ("Source_List_"+Hash_Name+"_Generated").c_str(), "N NT"); } } } #endif //MEDIAINFO_HASH //Source_List #if MEDIAINFO_ADVANCED if (!HasMainFile && Config->File_Source_List_Get()) { Ztring SourcePath; Ztring SourceName=MI->Retrieve(Stream_General, 0, General_CompleteName); if (SourceName.find(__T("://"))==string::npos) SourcePath=ZenLib::FileName::Path_Get(SourceName); else { size_t Pos_Path=SourceName.find_last_of('/'); if (Pos_Path!=Ztring::npos) SourcePath=SourceName.substr(0, Pos_Path); } size_t SourcePath_Size=SourcePath.size()+1; //Path size + path separator size for (size_t Pos=0; PosFileNames.size(); Pos++) { Ztring Temp=Sequences[Sequences_Current]->FileNames[Pos]; if (!Config->File_IsReferenced_Get()) Temp.erase(0, SourcePath_Size); MI->Fill(StreamKind_Target, StreamPos_Target, "Source_List", Temp); } if (!Sequences[Sequences_Current]->MI->Get(Stream_General, 0, __T("Source_List")).empty()) { ZtringList List; List.Separator_Set(0, __T(" / ")); List.Write(Sequences[Sequences_Current]->MI->Get(Stream_General, 0, __T("Source_List"))); for (size_t Pos=0; PosFile_IsReferenced_Get()) Temp.erase(0, SourcePath_Size); MI->Fill(StreamKind_Target, StreamPos_Target, "Source_List", Temp); } } MI->Fill_SetOptions(StreamKind_Target, StreamPos_Target, "Source_List", "N NT"); } #endif //MEDIAINFO_ADVANCED } #endif //MEDIAINFO_ADVANCED || MEDIAINFO_HASH //--------------------------------------------------------------------------- MediaInfo_Internal* File__ReferenceFilesHelper::MI_Create() { //Configuration MediaInfo_Internal* MI_Temp=new MediaInfo_Internal(); for (std::map::iterator Config_Item=Sequences[Sequences_Current]->Config.begin(); Config_Item!=Sequences[Sequences_Current]->Config.end(); ++Config_Item) MI_Temp->Option(Ztring().From_UTF8(Config_Item->first.c_str()), Config_Item->second); MI_Temp->Option(__T("File_IsReferenced"), __T("1")); MI_Temp->Option(__T("File_FileNameFormat"), __T("CSV")); MI_Temp->Option(__T("File_KeepInfo"), __T("1")); MI_Temp->Option(__T("File_ID_OnlyRoot"), Config->File_ID_OnlyRoot_Get()?__T("1"):__T("0")); #if defined(MEDIAINFO_DVDIF_YES) MI_Temp->Option(__T("File_DvDif_DisableAudioIfIsInContainer"), Config->File_DvDif_DisableAudioIfIsInContainer_Get()?__T("1"):__T("0")); #endif if ((Sequences.size()>1 || Config->File_MpegTs_ForceMenu_Get()) && !Sequences[Sequences_Current]->IsMain && !HasMainFile) MI_Temp->Option(__T("File_MpegTs_ForceMenu"), __T("1")); #if MEDIAINFO_AES MI_Temp->Option(__T("File_Encryption_Format"), MI->Retrieve(Stream_General, 0, "Encryption_Format")); MI_Temp->Option(__T("File_Encryption_Key"), Ztring().From_UTF8(Base64::encode(MI->Config->Encryption_Key_Get()))); MI_Temp->Option(__T("File_Encryption_Method"), MI->Retrieve(Stream_General, 0, "Encryption_Method")); MI_Temp->Option(__T("File_Encryption_Mode"), MI->Retrieve(Stream_General, 0, "Encryption_Mode")); MI_Temp->Option(__T("File_Encryption_Padding"), MI->Retrieve(Stream_General, 0, "Encryption_Padding")); MI_Temp->Option(__T("File_Encryption_InitializationVector"), MI->Retrieve(Stream_General, 0, "Encryption_InitializationVector")); #endif //AES #if MEDIAINFO_NEXTPACKET if (Config->NextPacket_Get()) MI_Temp->Option(__T("File_NextPacket"), __T("1")); if (Config->File_Demux_Interleave_Get()) MI_Temp->Option(__T("File_Demux_Interleave"), __T("1")); #endif //MEDIAINFO_NEXTPACKET #if MEDIAINFO_ADVANCED if (Config->File_IgnoreSequenceFileSize_Get()) MI_Temp->Option(__T("File_IgnoreSequenceFileSize"), __T("1")); if (Config->File_IgnoreSequenceFilesCount_Get()) MI_Temp->Option(__T("File_IgnoreSequenceFilesCount"), __T("1")); if (Config->File_Source_List_Get()) MI_Temp->Option(__T("File_Source_List"), __T("1")); #endif //MEDIAINFO_ADVANCED #if MEDIAINFO_HASH if (Config->File_Hash_Get().to_ulong()) MI_Temp->Option(__T("File_Hash"), Config->Option(__T("File_Hash_Get"), Ztring())); #endif //MEDIAINFO_HASH #if MEDIAINFO_EVENTS MI_Temp->Config.Config_PerPackage=Config->Config_PerPackage; if (Config->Event_CallBackFunction_IsSet()) { MI_Temp->Option(__T("File_Event_CallBackFunction"), Config->Event_CallBackFunction_Get()); MI_Temp->Config.Config_PerPackage->Event_CallBackFunction_Set(Config->Event_CallBackFunction_Get()); } MI_Temp->Config.File_Names_RootDirectory=FileName(MI->File_Name).Path_Get(); if (!Config->File_TestContinuousFileNames_Get() || Sequences[Sequences_Current]->FileNames.size()>1) MI_Temp->Option(__T("File_TestContinuousFileNames"), __T("0")); if (!Config->File_TestDirectory_Get()) MI_Temp->Option(__T("File_TestDirectory"), __T("0")); ZtringListList SubFile_IDs; if (Sequences[Sequences_Current]->IsMain) HasMainFile=true; if (HasMainFile && !Sequences[Sequences_Current]->IsMain) { ZtringList ID; ID.push_back(Ztring::ToZtring((((int64u)MediaInfo_Parser_SideCar)<<56)|(Sequences[Sequences_Current]->StreamID-1))); ID.push_back(Ztring::ToZtring(16)); ID.push_back(Ztring::ToZtring(MediaInfo_Parser_SideCar)); SubFile_IDs.push_back(ID); } else if (!Sequences[Sequences_Current]->IsMain) for (size_t Pos=0; PosStreamIDs_Size; Pos++) { ZtringList ID; if (MI->StreamIDs_Width[Pos]==0) ID.push_back(Ztring::ToZtring(-1)); else if (Pos+1==MI->StreamIDs_Size) ID.push_back(Ztring::ToZtring(Sequences[Sequences_Current]->StreamID)); else ID.push_back(Ztring::ToZtring(MI->StreamIDs[Pos])); ID.push_back(Ztring::ToZtring(MI->StreamIDs_Width[Pos])); ID.push_back(Ztring::ToZtring(MI->ParserIDs[Pos])); SubFile_IDs.push_back(ID); } if (!SubFile_IDs.empty()) { SubFile_IDs.Separator_Set(0, EOL); SubFile_IDs.Separator_Set(1, __T(",")); MI_Temp->Option(__T("File_SubFile_IDs_Set"), SubFile_IDs.Read()); } #endif //MEDIAINFO_EVENTS #if MEDIAINFO_DEMUX if (Config->Demux_Unpacketize_Get()) MI_Temp->Option(__T("File_Demux_Unpacketize"), __T("1")); if (Config->Demux_Avc_Transcode_Iso14496_15_to_Iso14496_10_Get()) MI_Temp->Option(__T("File_Demux_Avc_Transcode_Iso14496_15_to_Iso14496_10"), __T("1")); if (Config->Demux_Hevc_Transcode_Iso14496_15_to_AnnexB_Get()) MI_Temp->Option(__T("File_Demux_Hevc_Transcode_Iso14496_15_to_AnnexB"), __T("1")); if (FrameRate) MI_Temp->Option(__T("File_Demux_Rate"), Ztring::ToZtring(FrameRate)); else if (!Sequences[Sequences_Current]->Resources.empty() && Sequences[Sequences_Current]->Resources[0]->EditRate) //TODO: per Pos MI_Temp->Option(__T("File_Demux_Rate"), Ztring::ToZtring(Sequences[Sequences_Current]->Resources[0]->EditRate)); switch (Config->Demux_InitData_Get()) { case 0 : MI_Temp->Option(__T("File_Demux_InitData"), __T("Event")); break; case 1 : MI_Temp->Option(__T("File_Demux_InitData"), __T("Field")); break; default: ; } #endif //MEDIAINFO_DEMUX #if MEDIAINFO_IBIUSAGE if (!Sequences[Sequences_Current]->IbiStream.Infos.empty()) { ibi Ibi; Ibi.Streams[(int64u)-1]=new ibi::stream(Sequences[Sequences_Current]->IbiStream); //IBI Creation File_Ibi_Creation IbiCreation(Ibi); Ztring IbiText=IbiCreation.Finish(); if (!IbiText.empty()) MI_Temp->Option(__T("File_Ibi"), IbiText); } #endif //MEDIAINFO_IBIUSAGE return MI_Temp; } //--------------------------------------------------------------------------- void File__ReferenceFilesHelper::Read_Buffer_Unsynched() { MI->Open_Buffer_Unsynch(); for (size_t Sequences_Pos=0; Sequences_PosMI) Sequences[Sequences_Pos]->MI->Open_Buffer_Unsynch(); #if MEDIAINFO_DEMUX DTS_Minimal=(int64u)-1; Config->Demux_EventWasSent=true; //We want not try to read new data from the file #endif //MEDIAINFO_DEMUX #if MEDIAINFO_EVENTS if (Config->Config_PerPackage) Config->Config_PerPackage->Unsynch(); #endif //MEDIAINFO_EVENTS } //--------------------------------------------------------------------------- #if MEDIAINFO_SEEK Ztring Duration_Milliseconds2String(int64u DurationM) { Ztring DurationS; DurationS+=L'0'+(Char)(DurationM/(10*60*60*1000)); DurationM%=10*60*60*1000; DurationS+=L'0'+(Char)(DurationM/( 60*60*1000)); DurationM%= 60*60*1000; DurationS+=L':'; DurationS+=L'0'+(Char)(DurationM/( 10*60*1000)); DurationM%= 10*60*1000; DurationS+=L'0'+(Char)(DurationM/( 60*1000)); DurationM%= 60*1000; DurationS+=L':'; DurationS+=L'0'+(Char)(DurationM/( 10*1000)); DurationM%= 10*1000; DurationS+=L'0'+(Char)(DurationM/( 1000)); DurationM%= 1000; DurationS+=L'.'; DurationS+=L'0'+(Char)(DurationM/( 100)); DurationM%= 100; DurationS+=L'0'+(Char)(DurationM/( 10)); DurationM%= 10; DurationS+=L'0'+(Char)(DurationM); return DurationS; } size_t File__ReferenceFilesHelper::Seek (size_t Method, int64u Value, int64u ID) { for (Sequences_Current=0; Sequences_CurrentMI==NULL && !Sequences[Sequences_Current]->FileNames.empty()) ParseReference_Init(); //Parsing switch (Method) { case 0 : #if MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET { if (Value) { if (Value>MI->Config->File_Size) return 2; //Invalid value //Init if (!Duration) { Ztring FileName; if (HasMainFile) for (size_t Sequences_Pos = 0; Sequences_Pos < Sequences.size(); Sequences_Pos++) if (Sequences[Sequences_Pos]->IsMain && !Sequences[Sequences_Pos]->FileNames.empty()) FileName=Sequences[Sequences_Pos]->FileNames[0]; if (FileName.empty()) FileName=MI->File_Name; MediaInfo_Internal MI2; MI2.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI2.Option(__T("ParseSpeed_Get"), __T("")); Ztring Demux_Save=MI2.Option(__T("Demux_Get"), __T("")); MI2.Option(__T("ParseSpeed"), __T("0")); MI2.Option(__T("Demux"), Ztring()); size_t MiOpenResult=MI2.Open(FileName); MI2.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI2.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (!MiOpenResult) return (size_t)-1; Duration=MI2.Get(Stream_General, 0, General_Duration).To_float64()/1000; } //Time percentage float64 DurationF=Duration; DurationF*=Value; DurationF/=MI->Config->File_Size; DurationF*=1000; int64u DurationM=(int64u)DurationF; CountOfReferencesToParse=Sequences.size(); bool HasProblem=false; for (Sequences_Current=0; Sequences_CurrentMI) { Ztring Result; if (Sequences[Sequences_Current]->Resources.size()<=1 || DurationMResources[1]->Demux_Offset_DTS) { Sequences[Sequences_Current]->Resources_Current=0; int64u DurationFTemp=DurationF; if (Sequences[Sequences_Current]->MI->Config.Demux_Offset_DTS_FromStream!=(int64u)-1) DurationFTemp+=Sequences[Sequences_Current]->MI->Config.Demux_Offset_DTS_FromStream/1000000; // From nanoseconds to milliseconds Ztring DurationS=Duration_Milliseconds2String((int64u)DurationFTemp); Result=Sequences[Sequences_Current]->MI->Option(__T("File_Seek"), DurationS); } else { size_t Resources_Current_Temp=1; while (Resources_Current_TempResources.size() && DurationM>=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->Demux_Offset_DTS) Resources_Current_Temp++; Resources_Current_Temp--; int64u DurationFTemp=DurationF; if (Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->MI->Config.Demux_Offset_DTS_FromStream!=(int64u)-1) DurationFTemp+=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->MI->Config.Demux_Offset_DTS_FromStream/1000000; // From nanoseconds to milliseconds Ztring DurationS=Duration_Milliseconds2String((int64u)DurationFTemp); Result=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->MI->Option(__T("File_Seek"), DurationS); if (Result.empty()) Sequences[Sequences_Current]->Resources_Current=Resources_Current_Temp; } if (!Result.empty()) HasProblem=true; } Sequences[Sequences_Current]->Status.reset(); } Sequences_Current=0; Open_Buffer_Unsynch(); return HasProblem?(size_t)-1:1; //Not supported value if there is a problem (TODO: better info) } CountOfReferencesToParse=Sequences.size(); bool HasProblem=false; for (Sequences_Current=0; Sequences_CurrentMI) { Sequences[Sequences_Current]->Resources_Current=0; Ztring Result=Sequences[Sequences_Current]->MI->Option(__T("File_Seek"), Ztring::ToZtring(Value)); if (!Result.empty()) HasProblem=true; } Sequences[Sequences_Current]->Status.reset(); } Sequences_Current=0; Open_Buffer_Unsynch(); return HasProblem?(size_t)-1:1; //Not supported value if there is a problem (TODO: better info) } #else //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET return (size_t)-1; //Not supported #endif //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET case 1 : #if MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET { //Init if (!Duration) { Ztring FileName; if (HasMainFile) for (size_t Sequences_Pos = 0; Sequences_Pos < Sequences.size(); Sequences_Pos++) if (Sequences[Sequences_Pos]->IsMain && !Sequences[Sequences_Pos]->FileNames.empty()) FileName=Sequences[Sequences_Pos]->FileNames[0]; if (FileName.empty()) FileName=MI->File_Name; MediaInfo_Internal MI2; MI2.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI2.Option(__T("ParseSpeed_Get"), __T("")); Ztring Demux_Save=MI2.Option(__T("Demux_Get"), __T("")); MI2.Option(__T("ParseSpeed"), __T("0")); MI2.Option(__T("Demux"), Ztring()); size_t MiOpenResult=MI2.Open(FileName); MI2.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI2.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (!MiOpenResult) return (size_t)-1; Duration=MI2.Get(Stream_General, 0, General_Duration).To_float64()/1000; } //Time percentage float64 DurationF=Duration; DurationF*=Value; DurationF/=10; // divided by 10000 for 0.01 percentage then x1000 for milliseconds CountOfReferencesToParse=Sequences.size(); bool HasProblem=false; for (Sequences_Current=0; Sequences_CurrentMI) { Ztring Result; if (Sequences[Sequences_Current]->Resources.size()<2 || DurationResources[1]->Demux_Offset_DTS) { Sequences[Sequences_Current]->Resources_Current=0; int64u DurationFTemp=DurationF; if (Sequences[Sequences_Current]->MI->Config.Demux_Offset_DTS_FromStream!=(int64u)-1) DurationFTemp+=Sequences[Sequences_Current]->MI->Config.Demux_Offset_DTS_FromStream/1000000; // From nanoseconds to milliseconds Ztring DurationS=Duration_Milliseconds2String((int64u)DurationFTemp); Result=Sequences[Sequences_Current]->MI->Option(__T("File_Seek"), DurationS); } else { size_t Resources_Current_Temp=1; while (Resources_Current_TempResources.size() && Duration>=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->Demux_Offset_DTS) Resources_Current_Temp++; Resources_Current_Temp--; int64u DurationFTemp=DurationF; if (Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->MI->Config.Demux_Offset_DTS_FromStream!=(int64u)-1) DurationFTemp+=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->MI->Config.Demux_Offset_DTS_FromStream/1000000; // From nanoseconds to milliseconds Ztring DurationS=Duration_Milliseconds2String((int64u)DurationFTemp); Result=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->MI->Option(__T("File_Seek"), DurationS); if (Result.empty()) Sequences[Sequences_Current]->Resources_Current=Resources_Current_Temp; } if (!Result.empty()) HasProblem=true; } Sequences[Sequences_Current]->Status.reset(); } Sequences_Current=0; Open_Buffer_Unsynch(); return HasProblem?2:1; //Invalid value if there is a problem (TODO: better info) } #else //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET return (size_t)-1; //Not supported #endif //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET case 2 : //Timestamp #if MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET { CountOfReferencesToParse=Sequences.size(); for (Sequences_Current=0; Sequences_CurrentMI) { Ztring Result; if (Sequences[Sequences_Current]->Resources.size()<2 || ValueResources[1]->Demux_Offset_DTS) { Sequences[Sequences_Current]->Resources_Current=0; int64u ValueTemp=Value; if (Sequences[Sequences_Current]->MI->Config.Demux_Offset_DTS_FromStream!=(int64u)-1) ValueTemp+=Sequences[Sequences_Current]->MI->Config.Demux_Offset_DTS_FromStream; Ztring Time; Time.Duration_From_Milliseconds(ValueTemp/1000000); Result=Sequences[Sequences_Current]->MI->Option(__T("File_Seek"), Time); } else { size_t Resources_Current_Temp=1; while (Resources_Current_TempResources.size() && Value>=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->Demux_Offset_DTS) Resources_Current_Temp++; Resources_Current_Temp--; int64u ValueTemp=Value; if (Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->MI->Config.Demux_Offset_DTS_FromStream!=(int64u)-1) ValueTemp+=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->MI->Config.Demux_Offset_DTS_FromStream; Ztring Time; Time.Duration_From_Milliseconds(ValueTemp/1000000); Result=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->MI->Option(__T("File_Seek"), Time); if (Result.empty()) Sequences[Sequences_Current]->Resources_Current=Resources_Current_Temp; } if (!Result.empty()) return 2; //Invalid value } else { //There was a problem, removing Sequence Sequences.clear(); return Seek(Method, Value, ID); } Sequences[Sequences_Current]->Status.reset(); } Sequences_Current=0; Open_Buffer_Unsynch(); return 1; } #else //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET return (size_t)-1; //Not supported #endif //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET case 3 : //FrameNumber #if MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET CountOfReferencesToParse=Sequences.size(); for (Sequences_Current=0; Sequences_CurrentMI) { Ztring Result; if (Sequences[Sequences_Current]->Resources.size()<2 || ValueResources[1]->Demux_Offset_Frame) { Sequences[Sequences_Current]->Resources_Current=0; Result=Sequences[Sequences_Current]->MI->Option(__T("File_Seek"), __T("Frame=")+Ztring::ToZtring(Value)); } else { size_t Resources_Current_Temp=1; while (Resources_Current_TempResources.size() && Value>=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->Demux_Offset_Frame) Resources_Current_Temp++; Resources_Current_Temp--; Result=Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->MI->Option(__T("File_Seek"), __T("Frame=")+Ztring::ToZtring(Value-Sequences[Sequences_Current]->Resources[Resources_Current_Temp]->Demux_Offset_Frame)); if (Result.empty()) Sequences[Sequences_Current]->Resources_Current=Resources_Current_Temp; } if (!Result.empty()) return 2; //Invalid value } Sequences[Sequences_Current]->Status.reset(); } Sequences_Current=0; Open_Buffer_Unsynch(); return 1; #else //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET return (size_t)-1; //Not supported #endif //MEDIAINFO_DEMUX && MEDIAINFO_NEXTPACKET default : return 0; } } #endif //MEDIAINFO_SEEK //*************************************************************************** // Helpers //*************************************************************************** //--------------------------------------------------------------------------- size_t File__ReferenceFilesHelper::Stream_Prepare (stream_t StreamKind, size_t StreamPos) { size_t StreamPos_Last=MI->Stream_Prepare(StreamKind, StreamPos); for (sequences::iterator ReferencePos=Sequences.begin(); ReferencePos!=Sequences.end(); ++ReferencePos) if ((*ReferencePos)->StreamKind==StreamKind && (*ReferencePos)->StreamPos>=StreamPos_Last) if ((*ReferencePos)->StreamPos!=(size_t)-1) (*ReferencePos)->StreamPos++; return StreamPos_Last; } //--------------------------------------------------------------------------- void File__ReferenceFilesHelper::FileSize_Compute () { if (MI->Config==NULL) return; MI->Config->File_Size=MI->File_Size; for (size_t Sequences_Pos=0; Sequences_PosFileSize!=(int64u)-1) MI->Config->File_Size+=Sequences[Sequences_Pos]->FileSize; else if (Sequences[Sequences_Pos]->MI && Sequences[Sequences_Pos]->MI->Config.File_Size!=(int64u)-1) { MI->Config->File_Size+=Sequences[Sequences_Pos]->MI->Config.File_Size; #if MEDIAINFO_ADVANCED if (!Config->File_IgnoreSequenceFileSize_Get()) #endif //MEDIAINFO_ADVANCED { if (!Sequences[Sequences_Pos]->Resources.empty()) for (size_t Pos=1; PosResources.size(); Pos++) for (size_t Resource_FileNames_Pos=0; Resource_FileNames_PosResources[Pos]->FileNames.size(); Resource_FileNames_Pos++) MI->Config->File_Size+=File::Size_Get(Sequences[Sequences_Pos]->Resources[Pos]->FileNames[Resource_FileNames_Pos]); } } else { #if MEDIAINFO_ADVANCED if (!Config->File_IgnoreSequenceFileSize_Get()) #endif //MEDIAINFO_ADVANCED { if (Sequences[Sequences_Pos]->Resources.empty()) for (size_t Pos=0; PosFileNames.size(); Pos++) MI->Config->File_Size+=File::Size_Get(Sequences[Sequences_Pos]->FileNames[Pos]); else for (size_t Pos=0; PosResources.size(); Pos++) for (size_t Resource_FileNames_Pos=0; Resource_FileNames_PosResources[Pos]->FileNames.size(); Resource_FileNames_Pos++) MI->Config->File_Size+=File::Size_Get(Sequences[Sequences_Pos]->Resources[Pos]->FileNames[Resource_FileNames_Pos]); } } } } //--------------------------------------------------------------------------- void File__ReferenceFilesHelper::CountOfReferences_ForReadSize_Run () { //Computing read buffer size int64u File_Size_Total=0; int64u Buffer_Read_Size_Total=MI->Config->File_Buffer_Read_Size_Get(); for (sequences::iterator Reference_Temp=Sequences.begin(); Reference_Temp!=Sequences.end(); ++Reference_Temp) if ((*Reference_Temp)->MI && (*Reference_Temp)->MI->Config.File_Size!=(int64u)-1) File_Size_Total+=(*Reference_Temp)->MI->Config.File_Size; if (File_Size_Total) for (sequences::iterator Reference_Temp=Sequences.begin(); Reference_Temp!=Sequences.end(); ++Reference_Temp) if ((*Reference_Temp)->MI) { int64u Buffer_Read_Size_Temp=float64_int64s(((float64)(*Reference_Temp)->MI->Config.File_Size)/File_Size_Total*Buffer_Read_Size_Total); int64u Buffer_Read_Size=1; while (Buffer_Read_SizeMI->Config.File_Buffer_Read_Size_Set((size_t)Buffer_Read_Size); } } //--------------------------------------------------------------------------- #if MEDIAINFO_EVENTS void File__ReferenceFilesHelper::SubFile_Start() { if (Sequences[Sequences_Current]->StreamID!=StreamID_Previous) { Ztring FileName_Absolute, FileName_Relative; if (Sequences[Sequences_Current]->MI && Sequences[Sequences_Current]->MI->Config.File_Names_Pos && Sequences[Sequences_Current]->MI->Config.File_Names_PosMI->Config.File_Names.size()) FileName_Absolute=Sequences[Sequences_Current]->MI->Config.File_Names[Sequences[Sequences_Current]->MI->Config.File_Names_Pos-1]; else if (!Sequences[Sequences_Current]->FileNames.empty()) FileName_Absolute=Sequences[Sequences_Current]->FileNames[0]; else FileName_Absolute=Sequences[Sequences_Current]->Source.c_str(); Sequences[Sequences_Current]->MI->Config.Event_SubFile_Start(FileName_Absolute); StreamID_Previous=Sequences[Sequences_Current]->StreamID; } } #endif //MEDIAINFO_EVENTS } //NameSpace #endif //MEDIAINFO_REFERENCES_YES