/* 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 "tinyxml2.h" #include "MediaInfo/OutputHelpers.h" #include "MediaInfo/File__Analyse_Automatic.h" #include using namespace std; using namespace ZenLib; using namespace tinyxml2; namespace MediaInfoLib { //--------------------------------------------------------------------------- Ztring XML_Encode (const Ztring& Data) { Ztring Result; tstring::size_type Pos; for (Pos=0; Pos'): Result+=__T(">"); break; case __T('\n'): Result+=__T(" "); break; case __T('\r'): Result+=__T(" "); if (Pos+1=0x20) Result+=Data[Pos]; // Ignore others control characters } } return Result; } //--------------------------------------------------------------------------- string XML_Encode (const string& Data) { string Result; for (string::size_type Pos=0; Pos': Result+=">"; break; case '\n': Result+=" "; break; case '\r': Result+=" "; if (Pos+1=0x20) Result+=Data[Pos]; // Ignore others control characters } } return Result; } //--------------------------------------------------------------------------- string To_XML (Node& Cur_Node, const int& Level, bool Print_Header, bool Indent) { string Result; if (!Cur_Node.RawContent.empty()) { // if (Level) // Result+="\n"; Result+=Cur_Node.RawContent; return Result; } if (Print_Header) { Result+="\n"; Result+="\n"; } if (Cur_Node.Name.empty() && Cur_Node.XmlCommentOut.empty()) return Result; if (Level) Result+="\n"; bool CommentedNow; if (!Cur_Node.XmlCommentOut.empty()) { Result+=(Indent?string(Level, '\t'):string())+(Cur_Node.AlreadyCommented?"":" -->"; return Result; } Result+="\n"; CommentedNow=!Cur_Node.AlreadyCommented; Cur_Node.AlreadyCommented=true; } else CommentedNow=false; Result+=(Indent?string(Level, '\t'):string())+"<"+Cur_Node.Name; for (size_t Pos=0; Pos":" -->"); if (Cur_Node.XmlCommentOut.size()) Result+="\n"+(Indent?string(Level, '\t'):string())+((Cur_Node.AlreadyCommented && !CommentedNow)?"->":"-->"); return Result; } Result+=">"; if (Cur_Node.Value.size()) { if (Cur_Node.Childs.size()) Result+="\n"+(Indent?string(Level+1, '\t'):string()); Result+=XML_Encode(Cur_Node.Value); } bool CanDisplayXmlComment; if (Cur_Node.Childs.size()) { CanDisplayXmlComment=false; if (!Cur_Node.XmlComment.empty() && Cur_Node.XmlCommentOut.empty()) Result+=(Cur_Node.AlreadyCommented?" ":" -->"); for (size_t Pos=0; PosAlreadyCommented=Cur_Node.AlreadyCommented; Result+=To_XML(*Cur_Node.Childs[Pos], Level+1, false, Indent); delete Cur_Node.Childs[Pos]; Cur_Node.Childs[Pos]=NULL; } Cur_Node.Childs.clear(); //Free memory Result+="\n"+(Indent?string(Level, '\t'):string()); } else CanDisplayXmlComment=true; Result+=""; if (Cur_Node.XmlCommentOut.size()) Result+="\n"+(Indent?string(Level, '\t'):string())+((Cur_Node.AlreadyCommented && !CommentedNow)?"->":"-->"); else if (!Cur_Node.XmlComment.empty() && CanDisplayXmlComment) Result+=(Cur_Node.AlreadyCommented?" ":" -->"); if (!Level) Result+="\n"; return Result; } //--------------------------------------------------------------------------- string JSON_Encode (const string& Data) { string Result; for (string::size_type Pos=0; PosRawContent.empty()) { if (Level && Carriage_Returns) Result+='\n'; Result+=Cur_Node.Childs[Pos]->RawContent; delete Cur_Node.Childs[Pos]; Cur_Node.Childs[Pos]=NULL; continue; } if (Cur_Node.Name.empty()) continue; Result+=(Carriage_Returns?("\n"+(Indent?string(Level, '\t'):string())):string())+"\""+Cur_Node.Childs[Pos]->Name+(Carriage_Returns?"\": ":"\":"); bool Multiple=Cur_Node.Childs[Pos]->Multiple; if (Multiple) { Result+='['; if (Carriage_Returns) Result+='\n'; } string Name=Cur_Node.Childs[Pos]->Name; for (size_t Pos2=Pos; Pos2Name==Name; Pos2++) { if (!Cur_Node.Childs[Pos2]) continue; if (Cur_Node.Childs[Pos2]->Attrs.empty() && Cur_Node.Childs[Pos2]->Childs.empty() && !Cur_Node.Childs[Pos2]->Multiple) { if (Cur_Node.Childs[Pos2]->Value.empty()) Result+="null"; else Result+="\""+JSON_Encode(Cur_Node.Childs[Pos2]->Value)+"\""; } else { Result+=(Indent?string(Level+1, '\t'):string())+"{"; Result+=To_JSON_Attributes(*Cur_Node.Childs[Pos2], Level+2, Indent, Carriage_Returns); Result+=To_JSON_Elements(*Cur_Node.Childs[Pos2], Level+2, Indent, Carriage_Returns); if (Carriage_Returns) Result+='\n'; if(!Cur_Node.Childs[Pos2]->Value.empty()) { Result+=(Indent?string(Level+2, '\t'):string())+(Carriage_Returns?"\"#value\": \"":"\"#value\":\"")+JSON_Encode(Cur_Node.Childs[Pos2]->Value)+'\"'; if (Carriage_Returns) Result+='\n'; } Result+=(Indent?string(Level+1, '\t'):string())+"}"; } if (Pos2Name==Cur_Node.Childs[Pos2+1]->Name) Result+=","; if (Multiple && Carriage_Returns) Result+='\n'; delete Cur_Node.Childs[Pos2]; Cur_Node.Childs[Pos2]=NULL; Pos=Pos2; } if (Multiple) Result+=(Indent?string(Level, '\t'):string())+"]"; if (PosToElement(); if (!Element) return ToReturn; if (Parents.Find(Ztring(Element->Value()))==string::npos) { if (PlaceHolder==Ztring(Element->Value()) && Element->FirstChild() == NULL && _MI_Info && *_MI_Info) { //Replace placeholder by MediaInfo report _Node->Childs.push_back(*_MI_Info); *_MI_Info=NULL; } else { Ztring Value=Ztring(Element->GetText()?Element->GetText():""); if (Value.length()>3 && Value.at(0)=='%' && Value.at(1)!='%' && Value.at(Value.length()-1)=='%') { Value=Values.FindValue(FileName, Values(0).Find(Value.substr(1, Value.length()-2)), 0, 1); if (Value.empty()) return false; } Current=new Node(Element->Value(), Value.To_UTF8(), true); for (const XMLAttribute* Attribute = Element->FirstAttribute(); Attribute; Attribute = Attribute->Next()) { Ztring Value=Ztring(Attribute->Value()); if (Value.length()>3 && Value.at(0)=='%' && Value.at(1)!='%' && Value.at(Value.length()-1)=='%') { Value=Values.FindValue(FileName, Values(0).Find(Value.substr(1, Value.length()-2)), 0, 1); if (Value.empty()) return false; } Current->Add_Attribute(Attribute->Name(), Value); } } } for (const XMLNode* El = Element->FirstChild(); El; El = El->NextSibling()) ToReturn=Parse_XML(Parents, PlaceHolder, El, Current?Current:_Node, _MI_Info, FileName, Values); if (Current) { if (ToReturn) _Node->Childs.push_back(Current); else delete Current; } return ToReturn; } //--------------------------------------------------------------------------- bool ExternalMetadata(const Ztring& FileName, const Ztring& ExternalMetadata, const Ztring& ExternalMetaDataConfig, const ZtringList& Parents, const Ztring& PlaceHolder, Node* Main, Node* MI_Info) { if (ExternalMetaDataConfig.empty()) // ExternalMetadata is used in export only if there is ExternalMetadata config (= else it is another format) return true; ZtringListList CSV; CSV.Separator_Set(0, EOL); CSV.Separator_Set(1, __T(";")); CSV.Write(ExternalMetadata); //Check if the CSV contains at least the header + one entry if (CSV.size()<2) { MediaInfoLib::Config.Log_Send(0xC0, 0xFF, 0, "Invalid CSV for external metadata"); return false; } //Check if the file is present in the CSV if (CSV.FindValue(FileName, 0, 0, 1).empty()) { MediaInfoLib::Config.Log_Send(0xC0, 0xFF, 0, "File name not found in external metadata file"); return false; } //Parse XML template XMLDocument Template; if (Template.Parse(ExternalMetaDataConfig.To_UTF8().c_str()) != XML_SUCCESS) { MediaInfoLib::Config.Log_Send(0xC0, 0xFF, 0, "Invalid XML template for external metadata"); return false; } Parse_XML(Parents, PlaceHolder, Template.RootElement(), Main, &MI_Info, FileName, CSV); return true; } //--------------------------------------------------------------------------- #if defined(MEDIAINFO_EBUCORE_YES) || defined(MEDIAINFO_FIMS_YES) || defined(MEDIAINFO_MPEG7_YES) extern const char* Avc_profile_idc_Name(size_t Index); extern string Avc_level_idc_Name(size_t Index); extern const char* ProRes_Profile_Name(size_t Index); Ztring VideoCompressionCodeCS_Name(int32u termID, MediaInfo_Internal& MI, size_t StreamPos) //xxyyzz: xx=main number, yy=sub-number, zz=sub-sub-number { switch (termID/10000) { case 1 : return __T("MPEG-1 Video"); case 2 : switch ((termID%10000)/100) { case 1 : switch (termID%100) { case 1 : return __T("MPEG-2 Video Simple Profile @ Main Level"); default: return __T("MPEG-2 Video Simple Profile"); } case 2 : switch (termID%100) { case 1 : return __T("MPEG-2 Video Main Profile @ Low Level"); case 2 : return __T("MPEG-2 Video Main Profile @ Main Level"); case 3 : return __T("MPEG-2 Video Main Profile @ High 1440 Level"); case 4 : return __T("MPEG-2 Video Main Profile @ High Level"); default: return __T("MPEG-2 Video Main Profile"); } case 3 : switch (termID%100) { case 1 : return __T("MPEG-2 Video SNR Scalable Profile @ Low Level"); case 2 : return __T("MPEG-2 Video SNR Scalable Profile @ Main Level"); default: return __T("MPEG-2 Video SNR Scalable Profile"); } case 4 : switch (termID%100) { case 1 : return __T("MPEG-2 Video Spatial Scalable Profile @ Main Level"); case 2 : return __T("MPEG-2 Video Spatial Scalable Profile @ High 1440 Level"); case 3 : return __T("MPEG-2 Video Spatial Scalable Profile @ High Level"); default: return __T("MPEG-2 Video Spatial Scalable Profile"); } case 5 : switch (termID%100) { case 1 : return __T("MPEG-2 Video High Profile @ Main Level"); case 2 : return __T("MPEG-2 Video High Profile @ High 1440 Level"); case 3 : return __T("MPEG-2 Video High Profile @ High Level"); default: return __T("MPEG-2 Video High Profile"); } case 6 : switch (termID%100) { case 1 : return __T("MPEG-2 Video Multiview Profile @ Main Level"); default: return __T("MPEG-2 Video Multiview Profile"); } case 7 : switch (termID%100) { case 1 : return __T("MPEG-2 Video 4:2:2 Profile @ Main Level"); default: return __T("MPEG-2 Video 4:2:2 Profile"); } default: return __T("MPEG-2 Video"); } case 3 : switch ((termID%10000)/100) { case 1 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Simple Profile @ Level 0"); case 2 : return __T("MPEG-4 Visual Simple Profile @ Level 1"); case 3 : return __T("MPEG-4 Visual Simple Profile @ Level 2"); case 4 : return __T("MPEG-4 Visual Simple Profile @ Level 3"); default: return __T("MPEG-4 Visual Simple Profile"); } case 2 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Simple Scalable Profile @ Level 1"); case 2 : return __T("MPEG-4 Visual Simple Scalable Profile @ Level 2"); default: return __T("MPEG-4 Visual Simple Scalable Profile"); } case 3 : switch (termID%100) { case 1 : return __T("MPEG-4 Advanced Visual Simple Profile @ Level 0"); case 2 : return __T("MPEG-4 Advanced Visual Simple Profile @ Level 1"); case 3 : return __T("MPEG-4 Advanced Visual Simple Profile @ Level 2"); case 4 : return __T("MPEG-4 Advanced Visual Simple Profile @ Level 3"); case 5 : return __T("MPEG-4 Advanced Visual Simple Profile @ Level 4"); case 6 : return __T("MPEG-4 Advanced Visual Simple Profile @ Level 5"); default: return __T("MPEG-4 Advanced Visual Simple Profile"); } case 4 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Core Profile @ Level 1"); case 2 : return __T("MPEG-4 Visual Core Profile @ Level 2"); default: return __T("MPEG-4 Visual Core Profile"); } case 5 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Core-Scalable Profile @ Level 1"); case 2 : return __T("MPEG-4 Visual Core-Scalable Profile @ Level 2"); case 3 : return __T("MPEG-4 Visual Core-Scalable Profile @ Level 3"); default: return __T("MPEG-4 Visual Core-Scalable Profile"); } case 6 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual AdvancedCore Profile @ Level 1"); case 2 : return __T("MPEG-4 Visual AdvancedCore Profile @ Level 2"); default: return __T("MPEG-4 Visual AdvancedCore Profile"); } case 7 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Main Profile @ Level 2"); case 2 : return __T("MPEG-4 Visual Main Profile @ Level 3"); case 3 : return __T("MPEG-4 Visual Main Profile @ Level 4"); default: return __T("MPEG-4 Visual Main Profile"); } case 8 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual N-bit Profile @ Level 2"); default: return __T("MPEG-4 Visual Main Profile"); } case 9 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Advanced Real Time Simple Profile @ Level 1"); case 2 : return __T("MPEG-4 Visual Advanced Real Time Simple Profile @ Level 2"); case 3 : return __T("MPEG-4 Visual Advanced Real Time Simple Profile @ Level 3"); case 4 : return __T("MPEG-4 Visual Advanced Real Time Simple Profile @ Level 4"); default: return __T("MPEG-4 Visual Advanced Real Time Simple Profile"); } case 10 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Advanced Coding Efficiency Profile @ Level 1"); case 2 : return __T("MPEG-4 Visual Advanced Coding Efficiency Profile @ Level 2"); case 3 : return __T("MPEG-4 Visual Advanced Coding Efficiency Profile @ Level 3"); case 4 : return __T("MPEG-4 Visual Advanced Coding Efficiency Profile @ Level 4"); default: return __T("MPEG-4 Visual Advanced Coding Efficiency Profile"); } case 11 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Simple Studio Profile @ Level 1"); case 2 : return __T("MPEG-4 Visual Simple Studio Profile @ Level 2"); case 3 : return __T("MPEG-4 Visual Simple Studio Profile @ Level 3"); case 4 : return __T("MPEG-4 Visual Simple Studio Profile @ Level 4"); default: return __T("MPEG-4 Visual Simple Studio Profile"); } case 12 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Core Studio Profile @ Level 1"); case 2 : return __T("MPEG-4 Visual Core Studio Profile @ Level 2"); case 3 : return __T("MPEG-4 Visual Core Studio Profile @ Level 3"); case 4 : return __T("MPEG-4 Visual Core Studio Profile @ Level 4"); default: return __T("MPEG-4 Visual Core Studio Profile"); } case 13 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Fine Granularity Scalable Profile @ Level 0"); case 2 : return __T("MPEG-4 Visual Fine Granularity Scalable Profile @ Level 1"); case 3 : return __T("MPEG-4 Visual Fine Granularity Scalable Profile @ Level 2"); case 4 : return __T("MPEG-4 Visual Fine Granularity Scalable Profile @ Level 3"); case 5 : return __T("MPEG-4 Visual Fine Granularity Scalable Profile @ Level 4"); case 6 : return __T("MPEG-4 Visual Fine Granularity Scalable Profile @ Level 5"); default: return __T("MPEG-4 Visual Fine Granularity Scalable Profile"); } case 14 : switch (termID%100) { case 1 : return __T("MPEG-4 Simple Face Animation Profile @ Level 1"); case 2 : return __T("MPEG-4 Simple Face Animation Profile @ Level 2"); default: return __T("MPEG-4 Simple Face Animation Profile"); } case 15 : switch (termID%100) { case 1 : return __T("MPEG-4 Simple FBA Profile @ Level 1"); case 2 : return __T("MPEG-4 Simple FBA Profile @ Level 2"); default: return __T("MPEG-4 Simple FBA Profile"); } case 16 : switch (termID%100) { case 1 : return __T("MPEG-4 Basic Animated Texture Profile @ Level 1"); case 2 : return __T("MPEG-4 Basic Animated Texture Profile @ Level 2"); default: return __T("MPEG-4 Basic Animated Texture Profile"); } case 17 : switch (termID%100) { case 1 : return __T("MPEG-4 Advanced Scalable Texture Profile @ Level 1"); default: return __T("MPEG-4 Advanced Scalable Texture Profile"); } case 18 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Advanced Scalable Texture Profile @ Level 1"); case 2 : return __T("MPEG-4 Visual Advanced Scalable Texture Profile @ Level 2"); case 3 : return __T("MPEG-4 Visual Advanced Scalable Texture Profile @ Level 3"); default: return __T("MPEG-4 Visual Advanced Scalable Texture Profile"); } case 19 : switch (termID%100) { case 1 : return __T("MPEG-4 Visual Hybrid Profile @ Level 1"); case 2 : return __T("MPEG-4 Visual Hybrid Profile @ Level 2"); default: return __T("MPEG-4 Visual Hybrid Profile"); } default: return __T("MPEG-4 Visual"); } case 4 : return __T("JPEG"); case 5 : return __T("MJPEG"); case 6 : return __T("JPEG2000"); case 7 : return __T("H261"); case 8 : return __T("H263"); default: { auto Result=MI.Get(Stream_Video, StreamPos, Video_Format); auto Profile=((termID%10000)/100); if (Profile) { Profile--; Result+=__T(' '); switch (termID/10000) { case 50: Result+=Ztring().From_UTF8(Avc_profile_idc_Name(Profile)); if (auto Level=termID%100) { Level--; Result+=Ztring().From_UTF8(" @ Level "+Avc_level_idc_Name(Level)); } break; case 54: Result+=Ztring().From_UTF8(ProRes_Profile_Name(Profile)); break; } } return Result; } } } #endif } //NameSpace