//--------------------------------------------------------------------------- Ztring PBCore_MediaType(MediaInfo_Internal &MI) { if (MI.Count_Get(Stream_Video)) return __T("Video"); else if (MI.Count_Get(Stream_Audio)) return __T("Sound"); else if (MI.Count_Get(Stream_Image)) return __T("Static Image"); else if (MI.Count_Get(Stream_Text)) return __T("Text"); else return Ztring(); }
//--------------------------------------------------------------------------- void PBCore_Transform__Common_End(Ztring &ToReturn, MediaInfo_Internal &MI, stream_t StreamKind, size_t StreamPos) { //essenceTrackAnnotation - all fields (except *_String*) separated by | Ztring Temp; for (size_t Pos=0; Pos<MI.Count_Get(StreamKind, StreamPos); Pos++) if (MI.Get(StreamKind, StreamPos, Pos, Info_Name).find(__T("String"))==std::string::npos && !MI.Get(StreamKind, StreamPos, Pos).empty()) Temp+=MI.Get(StreamKind, StreamPos, Pos, Info_Name)+__T(": ")+MI.Get(StreamKind, StreamPos, Pos)+__T('|'); if (!Temp.empty()) { Temp.resize(Temp.size()-1); ToReturn+=__T("\t\t\t<essenceTrackAnnotation>"); ToReturn+=Temp; ToReturn+=__T("</essenceTrackAnnotation>\n"); } }
//--------------------------------------------------------------------------- void PBCore_Transform_Video(Ztring &ToReturn, MediaInfo_Internal &MI, size_t StreamPos) { ToReturn+=__T("\t\t<pbcoreEssenceTrack>\n"); //essenceTrackType ToReturn+=__T("\t\t\t<essenceTrackType>Video</essenceTrackType>\n"); //Common PBCore_Transform__Common_Begin(ToReturn, MI, Stream_Video, StreamPos); //essenceTrackFrameSize if (!MI.Get(Stream_Video, StreamPos, Video_Width).empty()) ToReturn+=__T("\t\t\t<essenceTrackFrameSize>")+MI.Get(Stream_Video, StreamPos, Video_Width)+__T('x')+MI.Get(Stream_Video, StreamPos, Video_Height)+__T("</essenceTrackFrameSize>\n"); //essenceTrackAspectRatio if (!MI.Get(Stream_Video, StreamPos, Video_DisplayAspectRatio).empty()) ToReturn+=__T("\t\t\t<essenceTrackAspectRatio>")+MI.Get(Stream_Video, StreamPos, Video_DisplayAspectRatio)+__T("</essenceTrackAspectRatio>\n"); //essenceTrackFrameRate if (!MI.Get(Stream_Video, StreamPos, Video_FrameRate).empty()) { ToReturn+=__T("\t\t\t<essenceTrackFrameRate>"); ToReturn+=MI.Get(Stream_Video, StreamPos, Video_FrameRate); if (!MI.Get(Stream_Video, StreamPos, Video_FrameRate_Mode).empty()) ToReturn+=__T(' ')+MI.Get(Stream_Video, StreamPos, Video_FrameRate_Mode); ToReturn+=__T("</essenceTrackFrameRate>\n"); } //Comon PBCore_Transform__Common_End(ToReturn, MI, Stream_Video, StreamPos); ToReturn+=__T("\t\t</pbcoreEssenceTrack>\n"); }
//--------------------------------------------------------------------------- void PBCore_Transform_Audio(Ztring &ToReturn, MediaInfo_Internal &MI, size_t StreamPos) { ToReturn+=__T("\t\t<pbcoreEssenceTrack>\n"); //essenceTrackType ToReturn+=__T("\t\t\t<essenceTrackType>Audio</essenceTrackType>\n"); //Common PBCore_Transform__Common_Begin(ToReturn, MI, Stream_Audio, StreamPos); if (!MI.Get(Stream_Audio, StreamPos, Audio_SamplingRate).empty()) ToReturn+=__T("\t\t\t<essenceTrackSamplingRate>")+MI.Get(Stream_Audio, StreamPos, Audio_SamplingRate)+__T("</essenceTrackSamplingRate>\n"); //Comon PBCore_Transform__Common_End(ToReturn, MI, Stream_Audio, StreamPos); ToReturn+=__T("\t\t</pbcoreEssenceTrack>\n"); }
//--------------------------------------------------------------------------- void PBCore_Transform_Menu(Ztring &ToReturn, MediaInfo_Internal &MI, size_t StreamPos) { //Only if TimeCode if (MI.Get(Stream_Menu, StreamPos, Menu_Format)!=__T("TimeCode")) return; ToReturn+=__T("\t\t<pbcoreEssenceTrack>\n"); //essenceTrackType ToReturn+=__T("\t\t\t<essenceTrackType>timecode</essenceTrackType>\n"); //Common PBCore_Transform__Common_Begin(ToReturn, MI, Stream_Menu, StreamPos); //Common PBCore_Transform__Common_End(ToReturn, MI, Stream_Menu, StreamPos); ToReturn+=__T("\t\t</pbcoreEssenceTrack>\n"); }
//--------------------------------------------------------------------------- void PBCore_Transform_Text(Ztring &ToReturn, MediaInfo_Internal &MI, size_t StreamPos) { //Init Ztring Format=MI.Get(Stream_Text, StreamPos, Text_Format); ToReturn+=__T("\t\t<pbcoreEssenceTrack>\n"); //essenceTrackType ToReturn+=__T("\t\t\t<essenceTrackType>"); if (Format==__T("EIA-608") || Format==__T("EIA-708")) ToReturn+=__T("caption"); else ToReturn+=__T("text"); ToReturn+=__T("</essenceTrackType>\n"); //Common PBCore_Transform__Common_Begin(ToReturn, MI, Stream_Text, StreamPos); //Common PBCore_Transform__Common_End(ToReturn, MI, Stream_Text, StreamPos); ToReturn+=__T("\t\t</pbcoreEssenceTrack>\n"); }
//--------------------------------------------------------------------------- Ztring Export_PBCore::Transform(MediaInfo_Internal &MI) { //Current date/time is ISO format time_t Time=time(NULL); Ztring TimeS; TimeS.Date_From_Seconds_1970((int32u)Time); TimeS.FindAndReplace(__T("UTC "), __T("")); TimeS.FindAndReplace(__T(" "), __T("T")); TimeS+=__T('Z'); Ztring ToReturn; ToReturn+=__T("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); ToReturn+=__T("<PBCoreDescriptionDocument xsi:schemaLocation=\"http://www.pbcore.org/PBCore/PBCoreNamespace.html http://www.pbcore.org/PBCore/PBCoreXSD_Ver_1-2-1.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.pbcore.org/PBCore/PBCoreNamespace.html\">\n"); ToReturn+=__T("\t<!-- Generated at ")+TimeS+__T(" by ")+MediaInfoLib::Config.Info_Version_Get()+__T(" -->\n"); ToReturn+=__T("\t<!-- Warning: MediaInfo outputs only pbcoreInstantiation, other mandatory PBCore data is junk -->\n"); ToReturn+=__T("\t<pbcoreIdentifier>\n"); ToReturn+=__T("\t\t<identifier>***</identifier>\n"); ToReturn+=__T("\t\t<identifierSource>***</identifierSource>\n"); ToReturn+=__T("\t</pbcoreIdentifier>\n"); ToReturn+=__T("\t<pbcoreTitle>\n"); ToReturn+=__T("\t\t<title>***</title>\n"); ToReturn+=__T("\t</pbcoreTitle>\n"); ToReturn+=__T("\t<pbcoreDescription>\n"); ToReturn+=__T("\t\t<description>***</description>\n"); ToReturn+=__T("\t\t<descriptionType>***</descriptionType>\n"); ToReturn+=__T("\t</pbcoreDescription>\n"); ToReturn+=__T("\t<pbcoreInstantiation>\n"); //pbcoreFormatID ToReturn+=__T("\t\t<pbcoreFormatID>\n"); //formatIdentifier ToReturn+=__T("\t\t\t<formatIdentifier>")+MI.Get(Stream_General, 0, General_FileName)+__T("</formatIdentifier>\n"); //formatIdentifierSource ToReturn+=__T("\t\t\t<formatIdentifierSource version=\"PBCoreXSD_Ver_1.2_D1\">File Name</formatIdentifierSource>\n"); ToReturn+=__T("\t\t</pbcoreFormatID>\n"); //formatDigital if (!MI.Get(Stream_General, 0, General_InternetMediaType).empty()) { ToReturn+=__T("\t\t<formatDigital>"); ToReturn+=MI.Get(Stream_General, 0, General_InternetMediaType); ToReturn+=__T("</formatDigital>\n"); } else { //TODO: how to implement formats without Media Type? ToReturn+=__T("\t\t<formatDigital>"); if (MI.Count_Get(Stream_Video)) ToReturn+=__T("video/x-"); else if (MI.Count_Get(Stream_Image)) ToReturn+=__T("image/x-"); else if (MI.Count_Get(Stream_Audio)) ToReturn+=__T("audio/x-"); else ToReturn+=__T("application/x-"); ToReturn+=Ztring(MI.Get(Stream_General, 0, __T("Format"))).MakeLowerCase(); ToReturn+=__T("</formatDigital>\n"); } //formatLocation ToReturn+=__T("\t\t<formatLocation>")+MI.Get(Stream_General, 0, General_CompleteName)+__T("</formatLocation>\n"); //dateCreated if (!MI.Get(Stream_General, 0, General_Encoded_Date).empty()) { Ztring dateCreated=MI.Get(Stream_General, 0, General_Recorded_Date); dateCreated.FindAndReplace(__T("UTC"), __T("-")); dateCreated.FindAndReplace(__T(" "), __T("T")); dateCreated+=__T('Z'); ToReturn+=__T("\t\t<dateCreated>")+dateCreated+__T("</dateCreated>\n"); } //dateIssued if (!MI.Get(Stream_General, 0, General_Recorded_Date).empty()) { Ztring dateIssued=MI.Get(Stream_General, 0, General_Recorded_Date); dateIssued.FindAndReplace(__T("UTC"), __T("-")); dateIssued.FindAndReplace(__T(" "), __T("T")); dateIssued+=__T('Z'); ToReturn+=__T("\t\t<dateIssued>")+dateIssued+__T("</dateIssued>\n"); } //formatMediaType if (!PBCore_MediaType(MI).empty()) ToReturn+=__T("\t\t<formatMediaType version=\"PBCoreXSD_Ver_1.2_D1\">")+PBCore_MediaType(MI)+__T("</formatMediaType>\n"); else ToReturn+=__T("\t\t<formatMediaType version=\"PBCoreXSD_Ver_1.2_D1\">application/octet-stream</formatMediaType>\n"); //formatGenerations ToReturn+=__T("\t\t<formatGenerations version=\"PBCoreXSD_Ver_1.2_D1\" />\n"); //formatFileSize if (!MI.Get(Stream_General, 0, General_FileSize).empty()) ToReturn+=__T("\t\t<formatFileSize>")+MI.Get(Stream_General, 0, General_FileSize)+__T("</formatFileSize>\n"); //formatTimeStart if (!MI.Get(Stream_Video, 0, Video_Delay_Original_String3).empty()) ToReturn+=__T("\t\t<formatTimeStart>")+MI.Get(Stream_Video, 0, Video_Delay_Original_String3)+__T("</formatTimeStart>\n"); else if (!MI.Get(Stream_Video, 0, Video_Delay_String3).empty()) ToReturn+=__T("\t\t<formatTimeStart>")+MI.Get(Stream_Video, 0, Video_Delay_String3)+__T("</formatTimeStart>\n"); //formatDuration if (!MI.Get(Stream_General, 0, General_Duration_String3).empty()) ToReturn+=__T("\t\t<formatDuration>")+MI.Get(Stream_General, 0, General_Duration_String3)+__T("</formatDuration>\n"); //formatDataRate if (!MI.Get(Stream_General, 0, General_OverallBitRate).empty()) { ToReturn+=__T("\t\t<formatDataRate>"); ToReturn+=MI.Get(Stream_General, 0, General_OverallBitRate); if (!MI.Get(Stream_General, 0, General_OverallBitRate_Mode).empty()) ToReturn+=__T(' ')+MI.Get(Stream_General, 0, General_OverallBitRate_Mode); ToReturn+=__T("</formatDataRate>\n"); } //formatTracks ToReturn+=__T("\t\t<formatTracks>")+Ztring::ToZtring(MI.Count_Get(Stream_Video)+MI.Count_Get(Stream_Audio)+MI.Count_Get(Stream_Image)+MI.Count_Get(Stream_Text))+__T("</formatTracks>\n"); //Streams for (size_t StreamKind=Stream_General+1; StreamKind<Stream_Max; StreamKind++) for (size_t StreamPos=0; StreamPos<MI.Count_Get((stream_t)StreamKind); StreamPos++) PBCore_Transform(ToReturn, MI, (stream_t)StreamKind, StreamPos); ToReturn+=__T("\t</pbcoreInstantiation>\n"); ToReturn+=__T("</PBCoreDescriptionDocument>\n"); //Carriage return ToReturn.FindAndReplace(__T("\n"), EOL, 0, Ztring_Recursive); return ToReturn; }
//--------------------------------------------------------------------------- void PBCore_Transform(Node *Parent, MediaInfo_Internal &MI, stream_t StreamKind, size_t StreamPos) { //Menu: only if TimeCode if (StreamKind==Stream_Menu && MI.Get(Stream_Menu, StreamPos, Menu_Format)!=__T("TimeCode")) return; //essenceTrackType Ztring essenceTrackType; switch (StreamKind) { case Stream_Video: essenceTrackType=__T("Video"); break; case Stream_Audio: essenceTrackType=__T("Audio"); break; case Stream_Text: { Ztring Format=MI.Get(Stream_Text, StreamPos, Text_Format); if (Format==__T("EIA-608") || Format==__T("EIA-708")) essenceTrackType=__T("CC"); else essenceTrackType=__T("Text"); } break; case Stream_Menu: if (MI.Get(Stream_Menu, StreamPos, Menu_Format)==__T("TimeCode")) { essenceTrackType=__T("TimeCode"); break; } else return; //Not supported default: return; //Not supported } Node* Node_EssenceTrack=Parent->Add_Child("pbcoreEssenceTrack"); Node_EssenceTrack->Add_Child("essenceTrackType", essenceTrackType); //essenceTrackIdentifier if (!MI.Get(StreamKind, StreamPos, __T("ID")).empty()) { Node_EssenceTrack->Add_Child("essenceTrackIdentifier", MI.Get(StreamKind, StreamPos, __T("ID"))); Node_EssenceTrack->Add_Child("essenceTrackIdentifierSource", "ID (Mediainfo)"); } else if (!MI.Get(StreamKind, StreamPos, __T("UniqueID")).empty()) { Node_EssenceTrack->Add_Child("essenceTrackIdentifier", MI.Get(StreamKind, StreamPos, __T("UniqueID"))); Node_EssenceTrack->Add_Child("essenceTrackIdentifierSource", "UniqueID (Mediainfo)"); } else if (!MI.Get(StreamKind, StreamPos, __T("StreamKindID")).empty()) { Node_EssenceTrack->Add_Child("essenceTrackIdentifier", MI.Get(StreamKind, StreamPos, __T("StreamKindID"))); Node_EssenceTrack->Add_Child("essenceTrackIdentifierSource", "StreamKindID (Mediainfo)"); } //essenceTrackStandard if (StreamKind==Stream_Video) Node_EssenceTrack->Add_Child_IfNotEmpty(MI, Stream_Video, StreamPos, Video_Standard, "essenceTrackStandard"); //essenceTrackEncoding if (!MI.Get(StreamKind, StreamPos, __T("Format")).empty()) { Ztring Format=MI.Get(StreamKind, StreamPos, __T("Format")); if (!MI.Get(StreamKind, StreamPos, __T("Format_Profile")).empty()) Format+=__T(' ')+MI.Get(StreamKind, StreamPos, __T("Format_Profile")); if (!MI.Get(StreamKind, StreamPos, __T("CodecID")).empty()) Format+=__T(" (")+MI.Get(StreamKind, StreamPos, __T("CodecID"))+__T(')'); Node_EssenceTrack->Add_Child("essenceTrackEncoding", Format); } //essenceTrackDataRate if (!MI.Get(StreamKind, StreamPos, __T("BitRate")).empty()) { Ztring BitRate=MI.Get(StreamKind, StreamPos, __T("BitRate")); if (!MI.Get(StreamKind, StreamPos, __T("BitRate_Mode")).empty()) BitRate+=__T(' ')+MI.Get(StreamKind, StreamPos, __T("BitRate_Mode")); Node_EssenceTrack->Add_Child("essenceTrackDataRate", BitRate); } //essenceTrackFrameRate if (StreamKind==Stream_Video && !MI.Get(Stream_Video, StreamPos, Video_FrameRate).empty()) { Ztring FrameRate=MI.Get(Stream_Video, StreamPos, Video_FrameRate); if (!MI.Get(Stream_Video, StreamPos, Video_FrameRate_Mode).empty()) FrameRate+=__T(' ')+MI.Get(Stream_Video, StreamPos, Video_FrameRate_Mode); Node_EssenceTrack->Add_Child("essenceTrackFrameRate", FrameRate); } //essenceTrackSamplingRate if (StreamKind==Stream_Audio) Node_EssenceTrack->Add_Child_IfNotEmpty(MI, Stream_Audio, StreamPos, Audio_SamplingRate, "essenceTrackSamplingRate"); //essenceTrackBitDepth Node_EssenceTrack->Add_Child_IfNotEmpty(MI, StreamKind, StreamPos, "BitDepth", "essenceTrackBitDepth", "version", std::string("PBCoreXSD_Ver_1.2_D1")); //essenceTrackFrameSize if (StreamKind==Stream_Video && !MI.Get(Stream_Video, StreamPos, Video_Width).empty()) Node_EssenceTrack->Add_Child("essenceTrackFrameSize", MI.Get(Stream_Video, StreamPos, Video_Width)+__T('x')+MI.Get(Stream_Video, StreamPos, Video_Height)); //essenceTrackAspectRatio if (StreamKind==Stream_Video) Node_EssenceTrack->Add_Child_IfNotEmpty(MI, Stream_Video, StreamPos, Video_DisplayAspectRatio, "essenceTrackAspectRatio"); //essenceTrackDuration Node_EssenceTrack->Add_Child_IfNotEmpty(MI, StreamKind, StreamPos, "Duration", "essenceTrackDuration"); //essenceTrackLanguage if (!MI.Get(StreamKind, StreamPos, __T("Language")).empty()) Node_EssenceTrack->Add_Child("essenceTrackLanguage", MediaInfoLib::Config.Iso639_2_Get(MI.Get(StreamKind, StreamPos, __T("Language")))); //essenceTrackAnnotation - all fields (except *_String*) separated by | Ztring Temp; for (size_t Pos=0; Pos<MI.Count_Get(StreamKind, StreamPos); Pos++) if (MI.Get(StreamKind, StreamPos, Pos, Info_Name).find(__T("String"))==std::string::npos && !MI.Get(StreamKind, StreamPos, Pos).empty()) Temp+=MI.Get(StreamKind, StreamPos, Pos, Info_Name)+__T(": ")+MI.Get(StreamKind, StreamPos, Pos)+__T('|'); if (!Temp.empty()) { Temp.resize(Temp.size()-1); Node_EssenceTrack->Add_Child("essenceTrackAnnotation", Temp); } }
//--------------------------------------------------------------------------- Ztring Export_PBCore::Transform(MediaInfo_Internal &MI) { Node Node_Main("PBCoreDescriptionDocument"); Node_Main.Add_Attribute("xsi:schemaLocation", "http://www.pbcore.org/PBCore/PBCoreNamespace.html http://www.pbcore.org/PBCore/PBCoreXSD_Ver_1-2-1.xsd"); Node_Main.Add_Attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); Node_Main.Add_Attribute("xmlns", "http://www.pbcore.org/PBCore/PBCoreNamespace.html"); Node* Node_Identifier = Node_Main.Add_Child("pbcoreIdentifier"); Node_Identifier->Add_Child("identifier", "***"); Node_Identifier->Add_Child("identifierSource", "***"); Node_Main.Add_Child("pbcoreTitle")->Add_Child("title", "***"); Node* Node_Description = Node_Main.Add_Child("pbcoreDescription"); Node_Description->Add_Child("description", "***"); Node_Description->Add_Child("descriptionType", "***"); Node* Node_Instantiation = Node_Main.Add_Child("pbcoreInstantiation"); //pbcoreFormatID Node* Node_FormatID = Node_Instantiation->Add_Child("pbcoreFormatID"); //formatIdentifier Node_FormatID->Add_Child("formatIdentifier", MI.Get(Stream_General, 0, General_FileName)); //formatIdentifierSource Node_FormatID->Add_Child("formatIdentifierSource", "File Name", "version", "PBCoreXSD_Ver_1.2_D1"); //formatDigital //TODO: how to implement formats without Media Type? Ztring Format; if (!MI.Get(Stream_General, 0, General_InternetMediaType).empty()) Format=Ztring(MI.Get(Stream_General, 0, General_InternetMediaType)); else if (MI.Count_Get(Stream_Video)) Format=__T("video/x-")+Ztring(MI.Get(Stream_General, 0, __T("Format"))).MakeLowerCase(); else if (MI.Count_Get(Stream_Image)) Format=__T("image/x-")+Ztring(MI.Get(Stream_General, 0, __T("Format"))).MakeLowerCase(); else if (MI.Count_Get(Stream_Audio)) Format=__T("audio/x-")+Ztring(MI.Get(Stream_General, 0, __T("Format"))).MakeLowerCase(); else Format=__T("application/x-")+Ztring(MI.Get(Stream_General, 0, __T("Format"))).MakeLowerCase(); Node_Instantiation->Add_Child("formatDigital", Format); //formatLocation Node_Instantiation->Add_Child("formatLocation", MI.Get(Stream_General, 0, General_CompleteName)); //dateCreated if (!MI.Get(Stream_General, 0, General_Encoded_Date).empty()) { Ztring dateCreated=MI.Get(Stream_General, 0, General_Recorded_Date); dateCreated.FindAndReplace(__T("UTC"), __T("-")); dateCreated.FindAndReplace(__T(" "), __T("T")); dateCreated+=__T('Z'); Node_Instantiation->Add_Child("dateCreated", dateCreated); } //dateIssued if (!MI.Get(Stream_General, 0, General_Recorded_Date).empty()) { Ztring dateIssued=MI.Get(Stream_General, 0, General_Recorded_Date); dateIssued.FindAndReplace(__T("UTC"), __T("-")); dateIssued.FindAndReplace(__T(" "), __T("T")); dateIssued+=__T('Z'); Node_Instantiation->Add_Child("dateIssued", dateIssued); } //formatMediaType Node_Instantiation->Add_Child("formatMediaType", PBCore_MediaType(MI).empty()?Ztring(__T("application/octet-stream")):PBCore_MediaType(MI), "version", "PBCoreXSD_Ver_1.2_D1"); //formatGenerations Node_Instantiation->Add_Child("formatGenerations", "","version", "PBCoreXSD_Ver_1.2_D1"); //formatFileSize Node_Instantiation->Add_Child_IfNotEmpty(MI, Stream_General, 0, General_FileSize, "formatFileSize"); //formatTimeStart if (!MI.Get(Stream_Video, 0, Video_Delay_Original_String3).empty()) Node_Instantiation->Add_Child("formatTimeStart", MI.Get(Stream_Video, 0, Video_Delay_Original_String3)); else if (!MI.Get(Stream_Video, 0, Video_Delay_String3).empty()) Node_Instantiation->Add_Child("formatTimeStart", MI.Get(Stream_Video, 0, Video_Delay_String3)); //formatDuration Node_Instantiation->Add_Child_IfNotEmpty(MI, Stream_General, 0, General_Duration_String3, "formatDuration"); //formatDataRate if (!MI.Get(Stream_General, 0, General_OverallBitRate).empty()) { Ztring formatDataRate=MI.Get(Stream_General, 0, General_OverallBitRate); if (!MI.Get(Stream_General, 0, General_OverallBitRate_Mode).empty()) formatDataRate+=__T(' ')+MI.Get(Stream_General, 0, General_OverallBitRate_Mode); Node_Instantiation->Add_Child("formatDataRate", formatDataRate); } //formatTracks Node_Instantiation->Add_Child("formatTracks", Ztring::ToZtring(MI.Count_Get(Stream_Video)+MI.Count_Get(Stream_Audio)+MI.Count_Get(Stream_Image)+MI.Count_Get(Stream_Text))); Ztring ToReturn; //Streams for (size_t StreamKind=Stream_General+1; StreamKind<Stream_Max; StreamKind++) for (size_t StreamPos=0; StreamPos<MI.Count_Get((stream_t)StreamKind); StreamPos++) PBCore_Transform(Node_Instantiation, MI, (stream_t)StreamKind, StreamPos); ToReturn+=Ztring().From_UTF8(To_XML(Node_Main, 0, true, true).c_str()); size_t Pos=ToReturn.find(__T("<PBCoreDescriptionDocument")); if(Pos!=Ztring::npos) ToReturn.insert(Pos, __T("<!-- Warning: MediaInfo outputs only pbcoreInstantiation, other mandatory PBCore data is junk -->\n")); //Carriage return if (MediaInfoLib::Config.LineSeparator_Get()!=__T("\n")) ToReturn.FindAndReplace(__T("\n"), MediaInfoLib::Config.LineSeparator_Get(), 0, Ztring_Recursive); return ToReturn; }
//--------------------------------------------------------------------------- bool File_DcpCpl::FileHeader_Begin() { XMLDocument document; if (!FileHeader_Begin_XML(document)) return false; bool IsDcp=false, IsImf=false; XMLElement* Root=document.FirstChildElement("CompositionPlaylist"); if (!Root) { Reject("DcpCpl"); return false; } const char* Attribute=Root->Attribute("xmlns"); if (!Attribute) { Reject("DcpCpl"); return false; } if (!strcmp(Attribute, "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#") ||!strcmp(Attribute, "http://www.smpte-ra.org/schemas/429-7/2006/CPL")) IsDcp=true; if (!strcmp(Attribute, "http://www.smpte-ra.org/schemas/2067-3/XXXX") //Some muxers use XXXX instead of year || !strcmp(Attribute, "http://www.smpte-ra.org/schemas/2067-3/2013")) IsImf=true; if (!IsDcp && !IsImf) { Reject("DcpCpl"); return false; } Accept("DcpCpl"); Fill(Stream_General, 0, General_Format, IsDcp?"DCP CPL":"IMF CPL"); Config->File_ID_OnlyRoot_Set(false); ReferenceFiles=new File__ReferenceFilesHelper(this, Config); //Parsing main elements for (XMLElement* CompositionPlaylist_Item=Root->FirstChildElement(); CompositionPlaylist_Item; CompositionPlaylist_Item=CompositionPlaylist_Item->NextSiblingElement()) { //CompositionTimecode if (IsImf && (!strcmp(CompositionPlaylist_Item->Value(), "CompositionTimecode") || !strcmp(CompositionPlaylist_Item->Value(), "cpl:CompositionTimecode"))) { File__ReferenceFilesHelper::reference ReferenceFile; ReferenceFile.StreamKind=Stream_Other; ReferenceFile.Infos["Type"]=__T("Time code"); ReferenceFile.Infos["Format"]=__T("CPL TC"); ReferenceFile.Infos["TimeCode_Striped"]=__T("Yes"); bool IsDropFrame=false; for (XMLElement* CompositionTimecode_Item=CompositionPlaylist_Item->FirstChildElement(); CompositionTimecode_Item; CompositionTimecode_Item=CompositionTimecode_Item->NextSiblingElement()) { //TimecodeDropFrame if (!strcmp(CompositionTimecode_Item->Value(), "TimecodeDropFrame") || !strcmp(CompositionTimecode_Item->Value(), "cpl:TimecodeDropFrame")) { if (strcmp(CompositionTimecode_Item->GetText(), "") && strcmp(CompositionTimecode_Item->GetText(), "0")) IsDropFrame=true; } //TimecodeRate if (!strcmp(CompositionTimecode_Item->Value(), "TimecodeRate") || !strcmp(CompositionTimecode_Item->Value(), "cpl:TimecodeRate")) ReferenceFile.Infos["FrameRate"].From_UTF8(CompositionTimecode_Item->GetText()); //TimecodeStartAddress if (!strcmp(CompositionTimecode_Item->Value(), "TimecodeStartAddress") || !strcmp(CompositionTimecode_Item->Value(), "cpl:TimecodeStartAddress")) ReferenceFile.Infos["TimeCode_FirstFrame"].From_UTF8(CompositionTimecode_Item->GetText()); } //Adaptation if (IsDropFrame) { std::map<string, Ztring>::iterator Info=ReferenceFile.Infos.find("TimeCode_FirstFrame"); if (Info!=ReferenceFile.Infos.end() && Info->second.size()>=11 && Info->second[8]!=__T(';')) Info->second[8]=__T(';'); } ReferenceFile.StreamID=ReferenceFiles->References.size()+1; ReferenceFiles->References.push_back(ReferenceFile); Stream_Prepare(Stream_Other); Fill(Stream_Other, StreamPos_Last, Other_ID, ReferenceFile.StreamID); for (std::map<string, Ztring>::iterator Info=ReferenceFile.Infos.begin(); Info!=ReferenceFile.Infos.end(); ++Info) Fill(Stream_Other, StreamPos_Last, Info->first.c_str(), Info->second); } //ReelList / SegmentList if ((IsDcp && !strcmp(CompositionPlaylist_Item->Value(), "ReelList")) || (IsImf && !strcmp(CompositionPlaylist_Item->Value(), "SegmentList"))) { for (XMLElement* ReelList_Item=CompositionPlaylist_Item->FirstChildElement(); ReelList_Item; ReelList_Item=ReelList_Item->NextSiblingElement()) { //Reel if ((IsDcp && !strcmp(ReelList_Item->Value(), "Reel")) || (IsImf && !strcmp(ReelList_Item->Value(), "Segment"))) { for (XMLElement* Reel_Item=ReelList_Item->FirstChildElement(); Reel_Item; Reel_Item=Reel_Item->NextSiblingElement()) { //AssetList if ((IsDcp && !strcmp(Reel_Item->Value(), "AssetList")) || (IsImf && !strcmp(Reel_Item->Value(), "SequenceList"))) { for (XMLElement* AssetList_Item=Reel_Item->FirstChildElement(); AssetList_Item; AssetList_Item=AssetList_Item->NextSiblingElement()) { //File //if ((IsDcp && (!strcmp(AssetList_Item->Value(), "MainPicture") || !strcmp(AssetList_Item->Value(), "MainSound"))) // || (IsImf && (!strcmp(AssetList_Item->Value(), "cc:MainImageSequence") || !strcmp(AssetList_Item->Value(), "cc:MainImage")))) { File__ReferenceFilesHelper::reference ReferenceFile; Ztring Asset_Id; if ((IsDcp && !strcmp(AssetList_Item->Value(), "MainPicture")) || (IsImf && !strcmp(AssetList_Item->Value(), "cc:MainImageSequence"))) ReferenceFile.StreamKind=Stream_Video; if ((IsDcp && !strcmp(AssetList_Item->Value(), "MainSound")) || (IsImf && !strcmp(AssetList_Item->Value(), "cc:MainAudioSequence"))) ReferenceFile.StreamKind=Stream_Audio; for (XMLElement* File_Item=AssetList_Item->FirstChildElement(); File_Item; File_Item=File_Item->NextSiblingElement()) { //Id if (!strcmp(File_Item->Value(), "Id") && Asset_Id.empty()) Asset_Id.From_UTF8(File_Item->GetText()); //ResourceList if (IsImf && !strcmp(File_Item->Value(), "ResourceList")) { for (XMLElement* ResourceList_Item=File_Item->FirstChildElement(); ResourceList_Item; ResourceList_Item=ResourceList_Item->NextSiblingElement()) { //Resource if (!strcmp(ResourceList_Item->Value(), "Resource")) { Ztring Resource_Id; File__ReferenceFilesHelper::reference::completeduration Resource; for (XMLElement* Resource_Item=ResourceList_Item->FirstChildElement(); Resource_Item; Resource_Item=Resource_Item->NextSiblingElement()) { //EditRate if (!strcmp(Resource_Item->Value(), "EditRate")) { const char* EditRate=Resource_Item->GetText(); Resource.IgnoreFramesRate=atof(EditRate); const char* EditRate2=strchr(EditRate, ' '); if (EditRate2!=NULL) { float64 EditRate2f=atof(EditRate2); if (EditRate2f) Resource.IgnoreFramesRate/=EditRate2f; } } //EntryPoint if (!strcmp(Resource_Item->Value(), "EntryPoint")) { Resource.IgnoreFramesBefore=atoi(Resource_Item->GetText()); if (Resource.IgnoreFramesAfter!=(int64u)-1) Resource.IgnoreFramesAfter+=Resource.IgnoreFramesBefore; } //Id if (!strcmp(File_Item->Value(), "Id") && Resource_Id.empty()) Resource_Id.From_UTF8(File_Item->GetText()); //SourceDuration if (!strcmp(Resource_Item->Value(), "SourceDuration")) Resource.IgnoreFramesAfter=Resource.IgnoreFramesBefore+atoi(Resource_Item->GetText()); //TrackFileId if (!strcmp(Resource_Item->Value(), "TrackFileId")) Resource.FileName.From_UTF8(Resource_Item->GetText()); } if (Resource.FileName.empty()) Resource.FileName=Resource_Id; ReferenceFile.CompleteDuration.push_back(Resource); } } } } if (ReferenceFile.CompleteDuration.empty()) { File__ReferenceFilesHelper::reference::completeduration Resource; Resource.FileName=Asset_Id; ReferenceFile.CompleteDuration.push_back(Resource); } ReferenceFile.StreamID=ReferenceFiles->References.size()+1; ReferenceFiles->References.push_back(ReferenceFile); } } } } } } } } Element_Offset=File_Size; //Getting files names FileName Directory(File_Name); Ztring Assetmap_FileName=Directory.Path_Get()+PathSeparator+__T("ASSETMAP.xml"); bool IsOk=false; if (File::Exists(Assetmap_FileName)) IsOk=true; else { Assetmap_FileName.resize(Assetmap_FileName.size()-4); //Old fashion, without ".xml" if (File::Exists(Assetmap_FileName)) IsOk=true; } if (IsOk) { MediaInfo_Internal MI; MI.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI.Option(__T("ParseSpeed_Get"), __T("")); Ztring Demux_Save=MI.Option(__T("Demux_Get"), __T("")); MI.Option(__T("ParseSpeed"), __T("0")); MI.Option(__T("Demux"), Ztring()); MI.Option(__T("File_IsReferenced"), __T("1")); size_t MiOpenResult=MI.Open(Assetmap_FileName); MI.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (MiOpenResult && (MI.Get(Stream_General, 0, General_Format)==__T("DCP AM") || MI.Get(Stream_General, 0, General_Format)==__T("IMF AM"))) { MergeFromAm(((File_DcpAm*)MI.Info)->Streams); } } ReferenceFiles->FilesForStorage=true; //All should be OK... return true; }
//--------------------------------------------------------------------------- bool File_Xdcam_Clip::FileHeader_Begin() { XMLDocument document; if (!FileHeader_Begin_XML(document)) return false; { XMLElement* Root=document.FirstChildElement("NonRealTimeMeta"); if (Root) { Accept("Xdcam_Clip"); Fill(Stream_General, 0, General_Format, "XDCAM Clip"); XMLElement* Element; //CreationDate Element=Root->FirstChildElement("CreationDate"); if (Element) Fill(Stream_General, 0, General_Recorded_Date, Element->Attribute("value")); //LastUpdate Element=Root->FirstChildElement("LastUpdate"); if (Element) Fill(Stream_General, 0, General_Tagged_Date, Element->Attribute("value")); //Duration Ztring Duration, EditUnit; Element=Root->FirstChildElement("Duration"); if (Element) Duration=Element->Attribute("value"); Element=Root->FirstChildElement("LtcChangeTable"); if (Element) EditUnit=Element->Attribute("tcFps"); int64u Duration_Frames=Duration.To_int64u(); int64u EditUnit_Denominator=EditUnit.To_int64u(); if (Duration_Frames && EditUnit_Denominator) Fill(Stream_General, 0, General_Duration, ((float32)Duration_Frames)*1000/EditUnit_Denominator, 0); int64u File_Size_Total=File_Size; #if defined(MEDIAINFO_MXF_YES) if (File_Name.size()>12 && File_Name[File_Name.size()-7]==__T('M') && File_Name[File_Name.size()-6]==__T('0') && File_Name[File_Name.size()-5]==__T('1') && File_Name[File_Name.size()-4]==__T('.') && File_Name[File_Name.size()-3]==__T('X') && File_Name[File_Name.size()-2]==__T('M') && File_Name[File_Name.size()-1]==__T('L')) { Ztring file=File_Name.substr(File_Name.size()-12, 5); Ztring MXF_File=File_Name; MXF_File.resize(MXF_File.size()-12); MXF_File+=file; if (File::Exists(MXF_File+__T(".MXF"))) MXF_File+=__T(".MXF"); if (File::Exists(MXF_File+__T(".MP4"))) MXF_File+=__T(".MP4"); //int8u ReadByHuman=Ztring(MediaInfo::Option_Static(__T("ReadByHuman_Get"))).To_int8u(); //MediaInfo::Option_Static(__T("ReadByHuman"), __T("0")); MediaInfo_Internal MI; if (MI.Open(MXF_File)) { //MediaInfo::Option_Static(__T("ReadByHuman"), ReadByHuman?__T("1"):__T("0")); Merge(MI); Fill(Stream_Video, StreamPos_Last, "Source", MXF_File); File_Size_Total+=Ztring(MI.Get(Stream_General, 0, General_FileSize)).To_int64u(); //Commercial names Fill(Stream_General, 0, General_Format_Commercial_IfAny, MI.Get(Stream_General, 0, General_Format_Commercial_IfAny)); Ztring Format_Commercial=MI.Get(Stream_General, 0, General_Format_Commercial_IfAny); if (!Format_Commercial.empty()) { Format_Commercial.FindAndReplace(__T("XDCAM "), Ztring()); Fill(Stream_General, 0, General_Format_Commercial, __T("XDCAM Clip ")+Format_Commercial, true); } } //else // MediaInfo::Option_Static(__T("ReadByHuman"), ReadByHuman?__T("1"):__T("0")); } #endif //defined(MEDIAINFO_MXF_YES) //Device Element=Root->FirstChildElement("Device"); if (Element) Fill(Stream_General, 0, General_Encoded_Application, string(Element->Attribute("manufacturer"))+" "+Element->Attribute("modelName"), true, true); if (File_Size_Total!=File_Size) Fill(Stream_General, 0, General_FileSize, File_Size_Total, 10, true); } else { Reject("Xdcam_Clip"); return false; } } //All should be OK... return true; }
//--------------------------------------------------------------------------- bool File_DcpPkl::FileHeader_Begin() { XMLDocument document; if (!FileHeader_Begin_XML(document)) return false; bool IsDcp=false, IsImf=false; XMLElement* PackingList=document.FirstChildElement("PackingList"); if (!PackingList) { Reject("DcpPkl"); return false; } const char* Attribute=PackingList->Attribute("xmlns"); if (!Attribute) { Reject("DcpPkl"); return false; } if (!strcmp(Attribute, "http://www.digicine.com/PROTO-ASDCP-PKL-20040311#")) IsDcp=true; if (!strcmp(Attribute, "http://www.smpte-ra.org/schemas/429-8/2007/PKL")) IsImf=true; if (!IsDcp && !IsImf) { Reject("DcpPkl"); return false; } Accept("DcpPkl"); Fill(Stream_General, 0, General_Format, IsDcp?"DCP PKL":"IMF PKL"); Config->File_ID_OnlyRoot_Set(false); ReferenceFiles=new File__ReferenceFilesHelper(this, Config); Ztring CPL_FileName; //Parsing main elements for (XMLElement* PackingList_Item=PackingList->FirstChildElement(); PackingList_Item; PackingList_Item=PackingList_Item->NextSiblingElement()) { //AssetList if (!strcmp(PackingList_Item->Value(), "AssetList")) { for (XMLElement* AssetList_Item=PackingList_Item->FirstChildElement(); AssetList_Item; AssetList_Item=AssetList_Item->NextSiblingElement()) { //Asset if (!strcmp(AssetList_Item->Value(), "Asset")) { File__ReferenceFilesHelper::reference ReferenceFile; bool IsCPL=false; bool PreviousFileNameIsAnnotationText=false; for (XMLElement* File_Item=AssetList_Item->FirstChildElement(); File_Item; File_Item=File_Item->NextSiblingElement()) { //Id if (!strcmp(File_Item->Value(), "Id")) ReferenceFile.Infos["UniqueID"].From_UTF8(File_Item->GetText()); //Type if (!strcmp(File_Item->Value(), "Type")) { if (!strcmp(File_Item->GetText(), "application/x-smpte-mxf;asdcpKind=Picture")) ReferenceFile.StreamKind=Stream_Video; else if (!strcmp(File_Item->GetText(), "application/x-smpte-mxf;asdcpKind=Sound")) ReferenceFile.StreamKind=Stream_Audio; else if (!strcmp(File_Item->GetText(), "text/xml;asdcpKind=CPL")) { HasCpl=IsCPL=true; } else ReferenceFile.StreamKind=Stream_Other; } //Id if (!strcmp(File_Item->Value(), "OriginalFileName") || (ReferenceFile.FileNames.empty() && !strcmp(File_Item->Value(), "AnnotationText"))) // Annotation contains file name (buggy IMF file) { if (PreviousFileNameIsAnnotationText) ReferenceFile.FileNames.clear(); // Annotation is something else, no need of it if (!strcmp(File_Item->Value(), "AnnotationText")) PreviousFileNameIsAnnotationText=true; ReferenceFile.FileNames.push_back(Ztring().From_UTF8(File_Item->GetText())); string Text=File_Item->GetText(); if (Text.size()>=8 && (Text.find("_cpl.xml")==Text.size()-8) || (Text.find("CPL_")==0 && Text.find(".xml")==Text.size()-4)) { HasCpl=IsCPL=true; ReferenceFile.StreamKind=Stream_Max; } } } if (IsCPL && CPL_FileName.empty()) for (size_t Pos=0; Pos<ReferenceFile.FileNames.size(); Pos++) { CPL_FileName=ReferenceFile.FileNames[Pos]; //Using only the first CPL file meet break; } ReferenceFile.StreamID=ReferenceFiles->References.size()+1; ReferenceFiles->References.push_back(ReferenceFile); } } } } Element_Offset=File_Size; //Getting links between files if (!CPL_FileName.empty() && !Config->File_IsReferenced_Get()) { FileName Directory(File_Name); if (CPL_FileName.find(__T("file://"))==0 && CPL_FileName.find(__T("file:///"))==string::npos) CPL_FileName.erase(0, 7); //TODO: better handling of relative and absolute file naes MediaInfo_Internal MI; MI.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI.Option(__T("ParseSpeed_Get"), __T("")); Ztring Demux_Save=MI.Option(__T("Demux_Get"), __T("")); MI.Option(__T("ParseSpeed"), __T("0")); MI.Option(__T("Demux"), Ztring()); MI.Option(__T("File_IsReferenced"), __T("1")); size_t MiOpenResult=MI.Open(Directory.Path_Get()+PathSeparator+CPL_FileName); MI.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (MiOpenResult && ((IsDcp && MI.Get(Stream_General, 0, General_Format)==__T("DCP CPL")) || (IsImf && MI.Get(Stream_General, 0, General_Format)==__T("IMF CPL")))) { DcpCpl_MergeFromPkl(((File_DcpCpl*)MI.Info)->ReferenceFiles, ReferenceFiles); ReferenceFiles->References=((File_DcpCpl*)MI.Info)->ReferenceFiles->References; } } ReferenceFiles->FilesForStorage=true; //All should be OK... return true; }
//--------------------------------------------------------------------------- bool File_DcpAm::FileHeader_Begin() { XMLDocument document; if (!FileHeader_Begin_XML(document)) return false; bool IsDcp=false, IsImf=false; std::string NameSpace; XMLElement* AssetMap=document.FirstChildElement("AssetMap"); if (AssetMap==NULL) { NameSpace="am:"; AssetMap=document.FirstChildElement((NameSpace+"AssetMap").c_str()); } if (!AssetMap) { Reject("DcpAm"); return false; } const char* Attribute=AssetMap->Attribute(NameSpace.empty()?"xmlns":"xmlns:am"); if (!Attribute) { Reject("DcpAm"); return false; } if (!strcmp(Attribute, "http://www.digicine.com/PROTO-ASDCP-AM-20040311#")) IsDcp=true; if (!strcmp(Attribute, "http://www.smpte-ra.org/schemas/429-9/2007/AM")) { if (NameSpace.empty()) IsImf=true; else IsDcp=true; } if (!IsDcp && !IsImf) { Reject("DcpAm"); return false; } Accept("DcpAm"); Fill(Stream_General, 0, General_Format, IsDcp?"DCP AM":"IMF AM"); if (IsDcp) Fill(Stream_General, 0, General_Format_Version, NameSpace=="am:"?"SMPTE":"Interop"); Config->File_ID_OnlyRoot_Set(false); ReferenceFiles=new File__ReferenceFilesHelper(this, Config); Ztring CPL_FileName; for (XMLElement* AssetMap_Item=AssetMap->FirstChildElement(); AssetMap_Item; AssetMap_Item=AssetMap_Item->NextSiblingElement()) { //AssetList if (!strcmp(AssetMap_Item->Value(), (NameSpace+"AssetList").c_str())) { for (XMLElement* AssetList_Item=AssetMap_Item->FirstChildElement(); AssetList_Item; AssetList_Item=AssetList_Item->NextSiblingElement()) { //Asset if (!strcmp(AssetList_Item->Value(), (NameSpace+"Asset").c_str())) { File__ReferenceFilesHelper::reference ReferenceFile; bool IsCPL=false; for (XMLElement* Asset_Item=AssetList_Item->FirstChildElement(); Asset_Item; Asset_Item=Asset_Item->NextSiblingElement()) { //Id if (!strcmp(Asset_Item->Value(), (NameSpace+"Id").c_str())) ReferenceFile.Infos["UniqueID"].From_UTF8(Asset_Item->GetText()); //ChunkList if (!strcmp(Asset_Item->Value(), (NameSpace+"ChunkList").c_str())) { for (XMLElement* ChunkList_Item=Asset_Item->FirstChildElement(); ChunkList_Item; ChunkList_Item=ChunkList_Item->NextSiblingElement()) { //Chunk if (!strcmp(ChunkList_Item->Value(), (NameSpace+"Chunk").c_str())) { for (XMLElement* Chunk_Item=ChunkList_Item->FirstChildElement(); Chunk_Item; Chunk_Item=Chunk_Item->NextSiblingElement()) { //Path if (!strcmp(Chunk_Item->Value(), (NameSpace+"Path").c_str())) { ReferenceFile.FileNames.push_back(Ztring().From_UTF8(Chunk_Item->GetText())); string Text=Chunk_Item->GetText(); if (Text.size()>=8 && (Text.find("_cpl.xml")==Text.size()-8) || (Text.find("CPL_")==0 && Text.find(".xml")==Text.size()-4)) IsCPL=true; } } } } } } if (IsCPL) { for (size_t Pos=0; Pos<ReferenceFile.FileNames.size(); Pos++) { if (CPL_FileName.empty()) CPL_FileName=ReferenceFile.FileNames[Pos]; //Using only the first CPL file meet } } ReferenceFile.StreamID=ReferenceFiles->References.size()+1; ReferenceFiles->References.push_back(ReferenceFile); } } } //Creator if (!strcmp(AssetMap_Item->Value(), (NameSpace+"Creator").c_str())) Fill(Stream_General, 0, General_Encoded_Library, AssetMap_Item->GetText()); //IssueDate if (!strcmp(AssetMap_Item->Value(), (NameSpace+"IssueDate").c_str())) Fill(Stream_General, 0, General_Encoded_Date, AssetMap_Item->GetText()); //Issuer if (!strcmp(AssetMap_Item->Value(), (NameSpace+"Issuer").c_str())) Fill(Stream_General, 0, General_EncodedBy, AssetMap_Item->GetText()); } Element_Offset=File_Size; //Getting links between files if (!CPL_FileName.empty() && !Config->File_IsReferenced_Get()) { FileName Directory(File_Name); if (CPL_FileName.find(__T("file://"))==0 && CPL_FileName.find(__T("file:///"))==string::npos) CPL_FileName.erase(0, 7); //TODO: better handling of relative and absolute file naes MediaInfo_Internal MI; MI.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI.Option(__T("ParseSpeed_Get"), __T("")); Ztring Demux_Save=MI.Option(__T("Demux_Get"), __T("")); MI.Option(__T("ParseSpeed"), __T("0")); MI.Option(__T("Demux"), Ztring()); MI.Option(__T("File_IsReferenced"), __T("1")); size_t MiOpenResult=MI.Open(Directory.Path_Get()+PathSeparator+CPL_FileName); MI.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (MiOpenResult && ((IsDcp && MI.Get(Stream_General, 0, General_Format)==__T("DCP CPL")) || (IsImf && MI.Get(Stream_General, 0, General_Format)==__T("IMF CPL")))) { DcpCpl_MergeFromPkl(((File_DcpCpl*)MI.Info)->ReferenceFiles, ReferenceFiles); ReferenceFiles->References=((File_DcpCpl*)MI.Info)->ReferenceFiles->References; } } ReferenceFiles->FilesForStorage=true; //All should be OK... return true; }
//--------------------------------------------------------------------------- bool File_DcpCpl::FileHeader_Begin() { XMLDocument document; if (!FileHeader_Begin_XML(document)) return false; bool IsDcp=false, IsImf=false; XMLElement* Root=document.FirstChildElement("CompositionPlaylist"); if (!Root) { Reject("DcpCpl"); return false; } const char* Attribute=Root->Attribute("xmlns"); if (!Attribute) { Reject("DcpCpl"); return false; } if (!strcmp(Attribute, "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#")) IsDcp=true; if (!strcmp(Attribute, "http://www.smpte-ra.org/schemas/2067-3/XXXX") //Some muxers use XXXX instead of year || !strcmp(Attribute, "http://www.smpte-ra.org/schemas/2067-3/2013")) IsImf=true; if (!IsDcp && !IsImf) { Reject("DcpCpl"); return false; } Accept("DcpCpl"); Fill(Stream_General, 0, General_Format, IsDcp?"DCP CPL":"IMF CPL"); Config->File_ID_OnlyRoot_Set(false); ReferenceFiles=new File__ReferenceFilesHelper(this, Config); //Parsing main elements for (XMLElement* Root_Item=Root->FirstChildElement(); Root_Item; Root_Item=Root_Item->NextSiblingElement()) { //ReelList / SegmentList if ((IsDcp && !strcmp(Root_Item->Value(), "ReelList")) || (IsImf && !strcmp(Root_Item->Value(), "SegmentList"))) { for (XMLElement* ReelList_Item=Root_Item->FirstChildElement(); ReelList_Item; ReelList_Item=ReelList_Item->NextSiblingElement()) { //Reel if ((IsDcp && !strcmp(ReelList_Item->Value(), "Reel")) || (IsImf && !strcmp(ReelList_Item->Value(), "Segment"))) { for (XMLElement* Reel_Item=ReelList_Item->FirstChildElement(); Reel_Item; Reel_Item=Reel_Item->NextSiblingElement()) { //AssetList if ((IsDcp && !strcmp(Reel_Item->Value(), "AssetList")) || (IsImf && !strcmp(Reel_Item->Value(), "SequenceList"))) { for (XMLElement* AssetList_Item=Reel_Item->FirstChildElement(); AssetList_Item; AssetList_Item=AssetList_Item->NextSiblingElement()) { //File //if ((IsDcp && (!strcmp(AssetList_Item->Value(), "MainPicture") || !strcmp(AssetList_Item->Value(), "MainSound"))) // || (IsImf && (!strcmp(AssetList_Item->Value(), "cc:MainImageSequence") || !strcmp(AssetList_Item->Value(), "cc:MainImage")))) { File__ReferenceFilesHelper::reference ReferenceFile; Ztring Asset_Id; if ((IsDcp && !strcmp(AssetList_Item->Value(), "MainPicture")) || (IsImf && !strcmp(AssetList_Item->Value(), "cc:MainImageSequence"))) ReferenceFile.StreamKind=Stream_Video; if ((IsDcp && !strcmp(AssetList_Item->Value(), "MainSound")) || (IsImf && !strcmp(AssetList_Item->Value(), "cc:MainAudioSequence"))) ReferenceFile.StreamKind=Stream_Audio; for (XMLElement* File_Item=AssetList_Item->FirstChildElement(); File_Item; File_Item=File_Item->NextSiblingElement()) { //Id if (!strcmp(File_Item->Value(), "Id") && Asset_Id.empty()) Asset_Id.From_UTF8(File_Item->GetText()); //ResourceList if (IsImf && !strcmp(File_Item->Value(), "ResourceList")) { for (XMLElement* ResourceList_Item=File_Item->FirstChildElement(); ResourceList_Item; ResourceList_Item=ResourceList_Item->NextSiblingElement()) { //Resource if (!strcmp(ResourceList_Item->Value(), "Resource")) { Ztring Resource_Id; File__ReferenceFilesHelper::reference::completeduration Resource; for (XMLElement* Resource_Item=ResourceList_Item->FirstChildElement(); Resource_Item; Resource_Item=Resource_Item->NextSiblingElement()) { //EditRate if (!strcmp(Resource_Item->Value(), "EditRate")) { const char* EditRate=Resource_Item->GetText(); Resource.IgnoreFramesRate=atof(EditRate); const char* EditRate2=strchr(EditRate, ' '); if (EditRate2!=NULL) { float64 EditRate2f=atof(EditRate2); if (EditRate2f) Resource.IgnoreFramesRate/=EditRate2f; } } //EntryPoint if (!strcmp(Resource_Item->Value(), "EntryPoint")) Resource.IgnoreFramesBefore=atoi(Resource_Item->GetText()); //Id if (!strcmp(File_Item->Value(), "Id") && Resource_Id.empty()) Resource_Id.From_UTF8(File_Item->GetText()); //SourceDuration if (!strcmp(Resource_Item->Value(), "SourceDuration")) Resource.IgnoreFramesAfterDuration=atoi(Resource_Item->GetText()); //TrackFileId if (!strcmp(Resource_Item->Value(), "TrackFileId")) Resource.FileName.From_UTF8(Resource_Item->GetText()); } if (Resource.FileName.empty()) Resource.FileName=Resource_Id; ReferenceFile.CompleteDuration.push_back(Resource); } } } } if (ReferenceFile.CompleteDuration.empty()) { File__ReferenceFilesHelper::reference::completeduration Resource; Resource.FileName=Asset_Id; ReferenceFile.CompleteDuration.push_back(Resource); } ReferenceFile.StreamID=ReferenceFiles->References.size()+1; ReferenceFiles->References.push_back(ReferenceFile); } } } } } } } } Element_Offset=File_Size; //Getting files names if (!Config->File_IsReferenced_Get()) { FileName Directory(File_Name); ZtringList List; if (IsImf) List=Dir::GetAllFileNames(Directory.Path_Get()+PathSeparator+__T("PKL_*.xml"), Dir::Include_Files); if (IsDcp || List.empty()) List=Dir::GetAllFileNames(Directory.Path_Get()+PathSeparator+__T("*_pkl.xml"), Dir::Include_Files); for (size_t Pos=0; Pos<List.size(); Pos++) { MediaInfo_Internal MI; MI.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI.Option(__T("ParseSpeed_Get"), __T("")); Ztring Demux_Save=MI.Option(__T("Demux_Get"), __T("")); MI.Option(__T("ParseSpeed"), __T("0")); MI.Option(__T("Demux"), Ztring()); MI.Option(__T("File_IsReferenced"), __T("1")); size_t MiOpenResult=MI.Open(List[Pos]); MI.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (MiOpenResult && ((IsDcp && MI.Get(Stream_General, 0, General_Format)==__T("DCP PKL")) || (IsImf && MI.Get(Stream_General, 0, General_Format)==__T("IMF PKL")))) { DcpCpl_MergeFromPkl(ReferenceFiles, ((File_DcpCpl*)MI.Info)->ReferenceFiles); } } } ReferenceFiles->FilesForStorage=true; //All should be OK... return true; }
size_t File_Lxf::Read_Buffer_Seek (size_t Method, int64u Value, int64u) { //Parsing switch (Method) { case 0 : Open_Buffer_Unsynch(); GoTo(Value); return 1; case 1 : Open_Buffer_Unsynch(); GoTo(File_Size*Value/10000); return 1; case 2 : //Timestamp { //Init if (!Duration_Detected) { MediaInfo_Internal MI; MI.Option(_T("File_KeepInfo"), _T("1")); Ztring ParseSpeed_Save=MI.Option(_T("ParseSpeed_Get"), _T("")); Ztring Demux_Save=MI.Option(_T("Demux_Get"), _T("")); MI.Option(_T("ParseSpeed"), _T("0")); MI.Option(_T("Demux"), Ztring()); size_t MiOpenResult=MI.Open(File_Name); MI.Option(_T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI.Option(_T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (!MiOpenResult || MI.Get(Stream_General, 0, General_Format)!=_T("LXF")) return 0; for (time_offsets::iterator TimeOffset=((File_Lxf*)MI.Info)->TimeOffsets.begin(); TimeOffset!=((File_Lxf*)MI.Info)->TimeOffsets.end(); TimeOffset++) TimeOffsets[TimeOffset->first]=TimeOffset->second; int64u Duration=float64_int64s(Ztring(MI.Get(Stream_General, 0, _T("Duration"))).To_float64()*720); TimeOffsets[File_Size]=stream_header(Duration, Duration, 0, (int8u)-1); SeekRequest_Divider=2; Duration_Detected=true; } if (Value!=(int64u)-1) { Value=float64_int64s((float64)Value*720/1000000); //Convert in LXF unit (1/720000) time_offsets::iterator End=TimeOffsets.end(); End--; if (Value>=End->second.TimeStamp_End) return 2; //Higher than total size SeekRequest=Value; } //Looking if we already have the timestamp int64u SeekRequest_Mini=SeekRequest; if (SeekRequest_Mini>1000000) SeekRequest_Mini-=720; //-1ms int64u SeekRequest_Maxi=SeekRequest+720; //+1ms for (time_offsets::iterator TimeOffset=TimeOffsets.begin(); TimeOffset!=TimeOffsets.end(); TimeOffset++) { if (TimeOffset->second.TimeStamp_Begin<=SeekRequest_Maxi && TimeOffset->second.TimeStamp_End>=SeekRequest_Mini) //If it is found in a frame we know { //Looking for the corresponding I-Frame while (TimeOffset->second.PictureType&0x2 && TimeOffset!=TimeOffsets.begin()) //Not an I-Frame (and not fisrt frame) { time_offsets::iterator Previous=TimeOffset; Previous--; if (Previous->second.TimeStamp_End!=TimeOffset->second.TimeStamp_Begin) //Testing if the previous frame is not known. { SeekRequest=TimeOffset->second.TimeStamp_Begin-(720+1); //1ms+1, so we are sure to not synch on the current frame again Open_Buffer_Unsynch(); GoTo((Previous->first+TimeOffset->first)/2); return 1; //Looking for previous frame } TimeOffset=Previous; } //We got the right I-Frame if (Value==0) { for (size_t Pos=0; Pos<Videos.size(); Pos++) if (Videos[Pos].Parser) Videos[Pos].Parser->Unsynch_Frame_Count=0; } Open_Buffer_Unsynch(); GoTo(TimeOffset->first); SeekRequest=(int64u)-1; return 1; } if (TimeOffset->second.TimeStamp_Begin>SeekRequest_Maxi) //Testing if too far { time_offsets::iterator Previous=TimeOffset; Previous--; int64u ReferenceOffset; if (File_Offset+Buffer_Offset==TimeOffset->first && TimeOffset->second.TimeStamp_Begin>SeekRequest) //If current frame is already too far ReferenceOffset=File_Offset+Buffer_Offset; else ReferenceOffset=TimeOffset->first; if (SeekRequest_Divider==0) { SeekRequest=Previous->second.TimeStamp_Begin-(720+1); //1ms+1, so we are sure to not synch on the current frame again ReferenceOffset=Previous->first; Previous--; SeekRequest_Divider=2; } Open_Buffer_Unsynch(); GoTo(Previous->first+(ReferenceOffset-Previous->first)/SeekRequest_Divider); SeekRequest_Divider*=2; return 1; } } } return 0; default : return (size_t)-1; } }
//--------------------------------------------------------------------------- void PBCore_Transform__Common_Begin(Ztring &ToReturn, MediaInfo_Internal &MI, stream_t StreamKind, size_t StreamPos) { //essenceTrackIdentifier if (!MI.Get(StreamKind, StreamPos, __T("ID")).empty()) { ToReturn+=__T("\t\t\t<essenceTrackIdentifier>")+MI.Get(StreamKind, StreamPos, __T("ID"))+__T("</essenceTrackIdentifier>\n"); ToReturn+=__T("\t\t\t<essenceTrackIdentifierSource>ID (Mediainfo)</essenceTrackIdentifierSource>\n"); } else if (!MI.Get(StreamKind, StreamPos, __T("UniqueID")).empty()) { ToReturn+=__T("\t\t\t<essenceTrackIdentifier>")+MI.Get(StreamKind, StreamPos, __T("UniqueID"))+__T("</essenceTrackIdentifier>\n"); ToReturn+=__T("\t\t\t<essenceTrackIdentifierSource>UniqueID (Mediainfo)</essenceTrackIdentifierSource>\n"); } else if (!MI.Get(StreamKind, StreamPos, __T("StreamKindID")).empty()) { ToReturn+=__T("\t\t\t<essenceTrackIdentifier>")+MI.Get(StreamKind, StreamPos, __T("StreamKindID"))+__T("</essenceTrackIdentifier>\n"); ToReturn+=__T("\t\t\t<essenceTrackIdentifierSource>StreamKindID (Mediainfo)</essenceTrackIdentifierSource>\n"); } //essenceTrackStandard if (StreamKind==Stream_Video && !MI.Get(Stream_Video, StreamPos, Video_Standard).empty()) //Video only, but must be placed here ToReturn+=__T("\t\t\t<essenceTrackStandard>")+MI.Get(Stream_Video, StreamPos, Video_Standard)+__T("</essenceTrackStandard>\n"); //essenceTrackLanguage if (!MI.Get(StreamKind, StreamPos, __T("Language")).empty()) ToReturn+=__T("\t\t\t<essenceTrackLanguage>")+MediaInfoLib::Config.Iso639_2_Get(MI.Get(StreamKind, StreamPos, __T("Language")))+__T("</essenceTrackLanguage>\n"); //essenceTrackEncoding if (!MI.Get(StreamKind, StreamPos, __T("Format")).empty()) { ToReturn+=__T("\t\t\t<essenceTrackEncoding>"); ToReturn+=MI.Get(StreamKind, StreamPos, __T("Format")); if (!MI.Get(StreamKind, StreamPos, __T("Format_Profile")).empty()) ToReturn+=__T(' ')+MI.Get(StreamKind, StreamPos, __T("Format_Profile")); if (!MI.Get(StreamKind, StreamPos, __T("CodecID")).empty()) ToReturn+=__T(" (")+MI.Get(StreamKind, StreamPos, __T("CodecID"))+__T(')'); ToReturn+=__T("</essenceTrackEncoding>\n"); } //essenceTrackDataRate if (!MI.Get(StreamKind, StreamPos, __T("BitRate")).empty()) { ToReturn+=__T("\t\t\t<essenceTrackDataRate>"); ToReturn+=MI.Get(StreamKind, StreamPos, __T("BitRate")); if (!MI.Get(StreamKind, StreamPos, __T("BitRate_Mode")).empty()) ToReturn+=__T(' ')+MI.Get(StreamKind, StreamPos, __T("BitRate_Mode")); ToReturn+=__T("</essenceTrackDataRate>\n"); } //essenceTrackDuration if (!MI.Get(StreamKind, StreamPos, __T("Duration")).empty()) ToReturn+=__T("\t\t\t<essenceTrackDuration>")+MI.Get(StreamKind, StreamPos, __T("Duration"))+__T("</essenceTrackDuration>\n"); //essenceTrackBitDepth if (!MI.Get(StreamKind, StreamPos, __T("Resolution")).empty()) ToReturn+=__T("\t\t\t<essenceTrackBitDepth version=\"PBCoreXSD_Ver_1.2_D1\">")+MI.Get(StreamKind, StreamPos, __T("Resolution"))+__T("</essenceTrackBitDepth>\n"); }
//--------------------------------------------------------------------------- void PBCore_Transform(Ztring &ToReturn, MediaInfo_Internal &MI, stream_t StreamKind, size_t StreamPos) { //Menu: only if TimeCode if (StreamKind==Stream_Menu && MI.Get(Stream_Menu, StreamPos, Menu_Format)!=__T("TimeCode")) return; //essenceTrackType Ztring essenceTrackType; switch (StreamKind) { case Stream_Video: essenceTrackType=__T("Video"); break; case Stream_Audio: essenceTrackType=__T("Audio"); break; case Stream_Text: { Ztring Format=MI.Get(Stream_Text, StreamPos, Text_Format); if (Format==__T("EIA-608") || Format==__T("EIA-708")) essenceTrackType=__T("CC"); else essenceTrackType=__T("Text"); } break; case Stream_Menu: if (MI.Get(Stream_Menu, StreamPos, Menu_Format)==__T("TimeCode")) { essenceTrackType=__T("TimeCode"); break; } else return; //Not supported default: return; //Not supported } ToReturn+=__T("\t\t<pbcoreEssenceTrack>\n"); ToReturn+=__T("\t\t\t<essenceTrackType>")+essenceTrackType+__T("</essenceTrackType>\n"); //essenceTrackIdentifier if (!MI.Get(StreamKind, StreamPos, __T("ID")).empty()) { ToReturn+=__T("\t\t\t<essenceTrackIdentifier>")+MI.Get(StreamKind, StreamPos, __T("ID"))+__T("</essenceTrackIdentifier>\n"); ToReturn+=__T("\t\t\t<essenceTrackIdentifierSource>ID (Mediainfo)</essenceTrackIdentifierSource>\n"); } else if (!MI.Get(StreamKind, StreamPos, __T("UniqueID")).empty()) { ToReturn+=__T("\t\t\t<essenceTrackIdentifier>")+MI.Get(StreamKind, StreamPos, __T("UniqueID"))+__T("</essenceTrackIdentifier>\n"); ToReturn+=__T("\t\t\t<essenceTrackIdentifierSource>UniqueID (Mediainfo)</essenceTrackIdentifierSource>\n"); } else if (!MI.Get(StreamKind, StreamPos, __T("StreamKindID")).empty()) { ToReturn+=__T("\t\t\t<essenceTrackIdentifier>")+MI.Get(StreamKind, StreamPos, __T("StreamKindID"))+__T("</essenceTrackIdentifier>\n"); ToReturn+=__T("\t\t\t<essenceTrackIdentifierSource>StreamKindID (Mediainfo)</essenceTrackIdentifierSource>\n"); } //essenceTrackStandard if (StreamKind==Stream_Video && !MI.Get(Stream_Video, StreamPos, Video_Standard).empty()) ToReturn+=__T("\t\t\t<essenceTrackStandard>")+MI.Get(Stream_Video, StreamPos, Video_Standard)+__T("</essenceTrackStandard>\n"); //essenceTrackEncoding if (!MI.Get(StreamKind, StreamPos, __T("Format")).empty()) { ToReturn+=__T("\t\t\t<essenceTrackEncoding>"); ToReturn+=MI.Get(StreamKind, StreamPos, __T("Format")); if (!MI.Get(StreamKind, StreamPos, __T("Format_Profile")).empty()) ToReturn+=__T(' ')+MI.Get(StreamKind, StreamPos, __T("Format_Profile")); if (!MI.Get(StreamKind, StreamPos, __T("CodecID")).empty()) ToReturn+=__T(" (")+MI.Get(StreamKind, StreamPos, __T("CodecID"))+__T(')'); ToReturn+=__T("</essenceTrackEncoding>\n"); } //essenceTrackDataRate if (!MI.Get(StreamKind, StreamPos, __T("BitRate")).empty()) { ToReturn+=__T("\t\t\t<essenceTrackDataRate>"); ToReturn+=MI.Get(StreamKind, StreamPos, __T("BitRate")); if (!MI.Get(StreamKind, StreamPos, __T("BitRate_Mode")).empty()) ToReturn+=__T(' ')+MI.Get(StreamKind, StreamPos, __T("BitRate_Mode")); ToReturn+=__T("</essenceTrackDataRate>\n"); } //essenceTrackFrameRate if (StreamKind==Stream_Video && !MI.Get(Stream_Video, StreamPos, Video_FrameRate).empty()) { ToReturn+=__T("\t\t\t<essenceTrackFrameRate>"); ToReturn+=MI.Get(Stream_Video, StreamPos, Video_FrameRate); if (!MI.Get(Stream_Video, StreamPos, Video_FrameRate_Mode).empty()) ToReturn+=__T(' ')+MI.Get(Stream_Video, StreamPos, Video_FrameRate_Mode); ToReturn+=__T("</essenceTrackFrameRate>\n"); } //essenceTrackSamplingRate if (StreamKind==Stream_Audio && !MI.Get(Stream_Audio, StreamPos, Audio_SamplingRate).empty()) ToReturn+=__T("\t\t\t<essenceTrackSamplingRate>")+MI.Get(Stream_Audio, StreamPos, Audio_SamplingRate)+__T("</essenceTrackSamplingRate>\n"); //essenceTrackBitDepth if (!MI.Get(StreamKind, StreamPos, __T("BitDepth")).empty()) ToReturn+=__T("\t\t\t<essenceTrackBitDepth version=\"PBCoreXSD_Ver_1.2_D1\">")+MI.Get(StreamKind, StreamPos, __T("BitDepth"))+__T("</essenceTrackBitDepth>\n"); //essenceTrackFrameSize if (StreamKind==Stream_Video && !MI.Get(Stream_Video, StreamPos, Video_Width).empty()) ToReturn+=__T("\t\t\t<essenceTrackFrameSize>")+MI.Get(Stream_Video, StreamPos, Video_Width)+__T('x')+MI.Get(Stream_Video, StreamPos, Video_Height)+__T("</essenceTrackFrameSize>\n"); //essenceTrackAspectRatio if (StreamKind==Stream_Video && !MI.Get(Stream_Video, StreamPos, Video_DisplayAspectRatio).empty()) ToReturn+=__T("\t\t\t<essenceTrackAspectRatio>")+MI.Get(Stream_Video, StreamPos, Video_DisplayAspectRatio)+__T("</essenceTrackAspectRatio>\n"); //essenceTrackDuration if (!MI.Get(StreamKind, StreamPos, __T("Duration")).empty()) ToReturn+=__T("\t\t\t<essenceTrackDuration>")+MI.Get(StreamKind, StreamPos, __T("Duration"))+__T("</essenceTrackDuration>\n"); //essenceTrackLanguage if (!MI.Get(StreamKind, StreamPos, __T("Language")).empty()) ToReturn+=__T("\t\t\t<essenceTrackLanguage>")+MediaInfoLib::Config.Iso639_2_Get(MI.Get(StreamKind, StreamPos, __T("Language")))+__T("</essenceTrackLanguage>\n"); //essenceTrackAnnotation - all fields (except *_String*) separated by | Ztring Temp; for (size_t Pos=0; Pos<MI.Count_Get(StreamKind, StreamPos); Pos++) if (MI.Get(StreamKind, StreamPos, Pos, Info_Name).find(__T("String"))==std::string::npos && !MI.Get(StreamKind, StreamPos, Pos).empty()) Temp+=MI.Get(StreamKind, StreamPos, Pos, Info_Name)+__T(": ")+MI.Get(StreamKind, StreamPos, Pos)+__T('|'); if (!Temp.empty()) { Temp.resize(Temp.size()-1); ToReturn+=__T("\t\t\t<essenceTrackAnnotation>"); ToReturn+=Temp; ToReturn+=__T("</essenceTrackAnnotation>\n"); } ToReturn+=__T("\t\t</pbcoreEssenceTrack>\n"); }
//--------------------------------------------------------------------------- bool File_DcpAm::FileHeader_Begin() { XMLDocument document; if (!FileHeader_Begin_XML(document)) return false; std::string NameSpace; XMLElement* AssetMap=document.FirstChildElement("AssetMap"); if (AssetMap==NULL) { NameSpace="am:"; AssetMap=document.FirstChildElement((NameSpace+"AssetMap").c_str()); } if (!AssetMap) { Reject("DcpAm"); return false; } const char* Attribute=AssetMap->Attribute(NameSpace.empty()?"xmlns":"xmlns:am"); if (!Attribute) { Reject("DcpAm"); return false; } if (strcmp(Attribute, "http://www.digicine.com/PROTO-ASDCP-AM-20040311#") && strcmp(Attribute, "http://www.smpte-ra.org/schemas/429-9/2007/AM")) { Reject("DcpAm"); return false; } Accept("DcpAm"); Fill(Stream_General, 0, General_Format, "DCP AM"); Fill(Stream_General, 0, General_Format_Version, NameSpace=="am:"?"SMPTE":"Interop"); Config->File_ID_OnlyRoot_Set(false); //Parsing main elements for (XMLElement* AssetMap_Item=AssetMap->FirstChildElement(); AssetMap_Item; AssetMap_Item=AssetMap_Item->NextSiblingElement()) { //AssetList if (!strcmp(AssetMap_Item->Value(), (NameSpace+"AssetList").c_str())) { for (XMLElement* AssetList_Item=AssetMap_Item->FirstChildElement(); AssetList_Item; AssetList_Item=AssetList_Item->NextSiblingElement()) { //Asset if (!strcmp(AssetList_Item->Value(), (NameSpace+"Asset").c_str())) { File_DcpPkl::stream Stream; for (XMLElement* Asset_Item=AssetList_Item->FirstChildElement(); Asset_Item; Asset_Item=Asset_Item->NextSiblingElement()) { //ChunkList if (!strcmp(Asset_Item->Value(), (NameSpace+"ChunkList").c_str())) { for (XMLElement* ChunkList_Item=Asset_Item->FirstChildElement(); ChunkList_Item; ChunkList_Item=ChunkList_Item->NextSiblingElement()) { //Chunk if (!strcmp(ChunkList_Item->Value(), (NameSpace+"Chunk").c_str())) { File_DcpPkl::stream::chunk Chunk; for (XMLElement* Chunk_Item=ChunkList_Item->FirstChildElement(); Chunk_Item; Chunk_Item=Chunk_Item->NextSiblingElement()) { //Path if (!strcmp(Chunk_Item->Value(), (NameSpace+"Path").c_str())) Chunk.Path=Chunk_Item->GetText(); } Stream.ChunkList.push_back(Chunk); } } } //Id if (!strcmp(Asset_Item->Value(), (NameSpace+"Id").c_str())) Stream.Id=Asset_Item->GetText(); //PackingList if (!strcmp(Asset_Item->Value(), (NameSpace+"PackingList").c_str())) { PKL_Pos=Streams.size(); Stream.StreamKind=(stream_t)(Stream_Max+2); // Means PKL } } Streams.push_back(Stream); } } } //Creator if (!strcmp(AssetMap_Item->Value(), (NameSpace+"Creator").c_str())) Fill(Stream_General, 0, General_Encoded_Library, AssetMap_Item->GetText()); //IssueDate if (!strcmp(AssetMap_Item->Value(), (NameSpace+"IssueDate").c_str())) Fill(Stream_General, 0, General_Encoded_Date, AssetMap_Item->GetText()); //Issuer if (!strcmp(AssetMap_Item->Value(), (NameSpace+"Issuer").c_str())) Fill(Stream_General, 0, General_EncodedBy, AssetMap_Item->GetText()); } Element_Offset=File_Size; //Merging with PKL if (PKL_Pos<Streams.size() && Streams[PKL_Pos].ChunkList.size()==1) { FileName Directory(File_Name); Ztring PKL_FileName; PKL_FileName.From_UTF8(Streams[PKL_Pos].ChunkList[0].Path); if (PKL_FileName.find(__T("file://"))==0 && PKL_FileName.find(__T("file:///"))==string::npos) PKL_FileName.erase(0, 7); //TODO: better handling of relative and absolute file naes MediaInfo_Internal MI; MI.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI.Option(__T("ParseSpeed_Get"), __T("")); Ztring Demux_Save=MI.Option(__T("Demux_Get"), __T("")); MI.Option(__T("ParseSpeed"), __T("0")); MI.Option(__T("Demux"), Ztring()); MI.Option(__T("File_IsReferenced"), __T("1")); size_t MiOpenResult=MI.Open(Directory.Path_Get()+PathSeparator+PKL_FileName); MI.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (MiOpenResult && (MI.Get(Stream_General, 0, General_Format)==__T("DCP PKL") || MI.Get(Stream_General, 0, General_Format)==__T("IMF PKL"))) { MergeFromPkl(((File_DcpPkl*)MI.Info)->Streams); for (size_t Pos=0; Pos<MI.Count_Get(Stream_Other); ++Pos) { Stream_Prepare(Stream_Other); Merge(*MI.Info, Stream_Other, Pos, StreamPos_Last); } } } //Creating the playlist if (!Config->File_IsReferenced_Get()) { ReferenceFiles=new File__ReferenceFilesHelper(this, Config); for (File_DcpPkl::streams::iterator Stream=Streams.begin(); Stream!=Streams.end(); ++Stream) if (Stream->StreamKind==(stream_t)(Stream_Max+1) && Stream->ChunkList.size()==1) // Means CPL { sequence* Sequence=new sequence; Sequence->FileNames.push_back(Ztring().From_UTF8(Stream->ChunkList[0].Path)); Sequence->StreamID=ReferenceFiles->Sequences_Size()+1; ReferenceFiles->AddSequence(Sequence); } ReferenceFiles->FilesForStorage=true; } //All should be OK... return true; }
//--------------------------------------------------------------------------- bool File_DcpCpl::FileHeader_Begin() { XMLDocument document; if (!FileHeader_Begin_XML(document)) return false; XMLElement* Root=document.FirstChildElement(); const char *NameSpace; if (!Root || strcmp(LocalName(Root, NameSpace), "CompositionPlaylist")) { Reject("DcpCpl"); return false; } bool IsDcp=false, IsImf=false; if (!strcmp(NameSpace, "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#") || !strcmp(NameSpace, "http://www.smpte-ra.org/schemas/429-7/2006/CPL")) { IsDcp=true; } else if (IsSmpteSt2067_3(NameSpace)) { IsImf=true; } else { Reject("DcpCpl"); return false; } Accept("DcpCpl"); Fill(Stream_General, 0, General_Format, IsDcp?"DCP CPL":"IMF CPL"); Config->File_ID_OnlyRoot_Set(false); ReferenceFiles=new File__ReferenceFilesHelper(this, Config); //Parsing main elements for (XMLElement* CompositionPlaylist_Item=Root->FirstChildElement(); CompositionPlaylist_Item; CompositionPlaylist_Item=CompositionPlaylist_Item->NextSiblingElement()) { //CompositionTimecode if (IsImf && MatchQName(CompositionPlaylist_Item, "CompositionTimecode", NameSpace)) { sequence* Sequence=new sequence; Sequence->StreamKind=Stream_Other; Sequence->Infos["Type"]=__T("Time code"); Sequence->Infos["Format"]=__T("CPL TC"); Sequence->Infos["TimeCode_Striped"]=__T("Yes"); bool IsDropFrame=false; for (XMLElement* CompositionTimecode_Item=CompositionPlaylist_Item->FirstChildElement(); CompositionTimecode_Item; CompositionTimecode_Item=CompositionTimecode_Item->NextSiblingElement()) { const char* Text=CompositionTimecode_Item->GetText(); if (!Text) continue; const char *CtItemNs, *CtItemName = LocalName(CompositionTimecode_Item, CtItemNs); if (!CtItemNs || strcmp(CtItemNs, NameSpace)) continue; // item has wrong namespace //TimecodeDropFrame if (!strcmp(CtItemName, "TimecodeDropFrame")) { if (strcmp(Text, "") && strcmp(Text, "0")) IsDropFrame=true; } //TimecodeRate if (!strcmp(CtItemName, "TimecodeRate")) Sequence->Infos["FrameRate"].From_UTF8(Text); //TimecodeStartAddress if (!strcmp(CtItemName, "TimecodeStartAddress")) Sequence->Infos["TimeCode_FirstFrame"].From_UTF8(Text); } //Adaptation if (IsDropFrame) { std::map<string, Ztring>::iterator Info=Sequence->Infos.find("TimeCode_FirstFrame"); if (Info!=Sequence->Infos.end() && Info->second.size()>=11 && Info->second[8]!=__T(';')) Info->second[8]=__T(';'); } Sequence->StreamID=ReferenceFiles->Sequences_Size()+1; ReferenceFiles->AddSequence(Sequence); Stream_Prepare(Stream_Other); Fill(Stream_Other, StreamPos_Last, Other_ID, Sequence->StreamID); for (std::map<string, Ztring>::iterator Info=Sequence->Infos.begin(); Info!=Sequence->Infos.end(); ++Info) Fill(Stream_Other, StreamPos_Last, Info->first.c_str(), Info->second); } //ReelList / SegmentList if (MatchQName(CompositionPlaylist_Item, IsDcp?"ReelList":"SegmentList", NameSpace)) { for (XMLElement* ReelList_Item=CompositionPlaylist_Item->FirstChildElement(); ReelList_Item; ReelList_Item=ReelList_Item->NextSiblingElement()) { //Reel if (MatchQName(ReelList_Item, IsDcp?"Reel":"Segment", NameSpace)) { for (XMLElement* Reel_Item=ReelList_Item->FirstChildElement(); Reel_Item; Reel_Item=Reel_Item->NextSiblingElement()) { //AssetList if (MatchQName(Reel_Item, IsDcp?"AssetList":"SequenceList", NameSpace)) { for (XMLElement* AssetList_Item=Reel_Item->FirstChildElement(); AssetList_Item; AssetList_Item=AssetList_Item->NextSiblingElement()) { const char *AlItemNs, *AlItemName = LocalName(AssetList_Item, AlItemNs); if (!AlItemNs) continue; //File //if ((IsDcp && (!strcmp(AssetList_Item->Value(), "MainPicture") || !strcmp(AssetList_Item->Value(), "MainSound"))) // || (IsImf && (!strcmp(AssetList_Item->Value(), "cc:MainImageSequence") || !strcmp(AssetList_Item->Value(), "cc:MainImage")))) if (strcmp(AlItemName, "MarkerSequence")) //Ignoring MarkerSequence for the moment. TODO: check what to do with MarkerSequence { sequence* Sequence=new sequence; Ztring Asset_Id; if (IsDcp && !strcmp(NameSpace, AlItemNs)) { if (!strcmp(AlItemName, "MainPicture")) Sequence->StreamKind=Stream_Video; else if (!strcmp(AlItemName, "MainSound")) Sequence->StreamKind=Stream_Audio; } else if (IsImf && IsSmpteSt2067_2(AlItemNs)) { if (!strcmp(AlItemName, "MainImageSequence")) Sequence->StreamKind=Stream_Video; else if (!strcmp(AlItemName, "MainAudioSequence")) Sequence->StreamKind=Stream_Audio; } for (XMLElement* File_Item=AssetList_Item->FirstChildElement(); File_Item; File_Item=File_Item->NextSiblingElement()) { //Id if (MatchQName(File_Item, "Id", NameSpace) && Asset_Id.empty()) Asset_Id.From_UTF8(File_Item->GetText()); //ResourceList if (IsImf && MatchQName(File_Item, "ResourceList", NameSpace)) { for (XMLElement* ResourceList_Item=File_Item->FirstChildElement(); ResourceList_Item; ResourceList_Item=ResourceList_Item->NextSiblingElement()) { //Resource if (MatchQName(ResourceList_Item, "Resource", NameSpace)) { Ztring Resource_Id; resource* Resource=new resource; for (XMLElement* Resource_Item=ResourceList_Item->FirstChildElement(); Resource_Item; Resource_Item=Resource_Item->NextSiblingElement()) { const char* ResText=Resource_Item->GetText(); if (!ResText) continue; const char *ResItemNs, *ResItemName = LocalName(Resource_Item, ResItemNs); if (!ResItemNs || strcmp(ResItemNs, NameSpace)) continue; // item has wrong namespace //EditRate if (!strcmp(ResItemName, "EditRate")) { Resource->EditRate=atof(ResText); const char* EditRate2=strchr(ResText, ' '); if (EditRate2!=NULL) { float64 EditRate2f=atof(EditRate2); if (EditRate2f) Resource->EditRate/=EditRate2f; } } //EntryPoint if (!strcmp(ResItemName, "EntryPoint")) { Resource->IgnoreEditsBefore=atoi(ResText); if (Resource->IgnoreEditsAfter!=(int64u)-1) Resource->IgnoreEditsAfter+=Resource->IgnoreEditsBefore; } //Id if (!strcmp(ResItemName, "Id") && Resource_Id.empty()) Resource_Id.From_UTF8(ResText); //SourceDuration if (!strcmp(ResItemName, "SourceDuration")) Resource->IgnoreEditsAfter=Resource->IgnoreEditsBefore+atoi(ResText); //TrackFileId if (!strcmp(ResItemName, "TrackFileId")) Resource->FileNames.push_back(Ztring().From_UTF8(ResText)); } if (Resource->FileNames.empty()) Resource->FileNames.push_back(Resource_Id); Sequence->AddResource(Resource); } } } } if (Sequence->Resources.empty()) { resource* Resource=new resource; Resource->FileNames.push_back(Asset_Id); Sequence->AddResource(Resource); } Sequence->StreamID=ReferenceFiles->Sequences_Size()+1; ReferenceFiles->AddSequence(Sequence); } } } } } } } } Element_Offset=File_Size; //Getting files names FileName Directory(File_Name); Ztring DirPath = Directory.Path_Get(); if (!DirPath.empty()) DirPath += PathSeparator; Ztring Assetmap_FileName=DirPath+__T("ASSETMAP.xml"); bool IsOk=false; if (File::Exists(Assetmap_FileName)) IsOk=true; else { Assetmap_FileName.resize(Assetmap_FileName.size()-4); //Old fashion, without ".xml" if (File::Exists(Assetmap_FileName)) IsOk=true; } if (IsOk) { MediaInfo_Internal MI; MI.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI.Option(__T("ParseSpeed_Get"), __T("")); Ztring Demux_Save=MI.Option(__T("Demux_Get"), __T("")); MI.Option(__T("ParseSpeed"), __T("0")); MI.Option(__T("Demux"), Ztring()); MI.Option(__T("File_IsReferenced"), __T("1")); size_t MiOpenResult=MI.Open(Assetmap_FileName); MI.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (MiOpenResult && (MI.Get(Stream_General, 0, General_Format)==__T("DCP AM") || MI.Get(Stream_General, 0, General_Format)==__T("IMF AM"))) { MergeFromAm(((File_DcpAm*)MI.Info)->Streams); } } ReferenceFiles->FilesForStorage=true; //All should be OK... return true; }
//--------------------------------------------------------------------------- bool File_DcpPkl::FileHeader_Begin() { XMLDocument document; if (!FileHeader_Begin_XML(document)) return false; XMLElement* PackingList=document.FirstChildElement("PackingList"); if (!PackingList) { Reject("DcpPkl"); return false; } const char* Attribute=PackingList->Attribute("xmlns"); if (!Attribute) { Reject("DcpPkl"); return false; } if (strcmp(Attribute, "http://www.digicine.com/PROTO-ASDCP-PKL-20040311#") && strcmp(Attribute, "http://www.smpte-ra.org/schemas/429-8/2007/PKL")) { Reject("DcpPkl"); return false; } Accept("DcpPkl"); Fill(Stream_General, 0, General_Format, "DCP PKL"); Config->File_ID_OnlyRoot_Set(false); //Parsing main elements for (XMLElement* PackingList_Item=PackingList->FirstChildElement(); PackingList_Item; PackingList_Item=PackingList_Item->NextSiblingElement()) { //AssetList if (!strcmp(PackingList_Item->Value(), "AssetList")) { for (XMLElement* AssetList_Item=PackingList_Item->FirstChildElement(); AssetList_Item; AssetList_Item=AssetList_Item->NextSiblingElement()) { //Asset if (!strcmp(AssetList_Item->Value(), "Asset")) { stream Stream; for (XMLElement* File_Item=AssetList_Item->FirstChildElement(); File_Item; File_Item=File_Item->NextSiblingElement()) { //AnnotationText if (!strcmp(File_Item->Value(), "AnnotationText")) Stream.AnnotationText=File_Item->GetText(); //Id if (!strcmp(File_Item->Value(), "Id")) Stream.Id=File_Item->GetText(); //OriginalFileName if (!strcmp(File_Item->Value(), "OriginalFileName")) Stream.OriginalFileName=File_Item->GetText(); //Type if (!strcmp(File_Item->Value(), "Type")) { if (!strcmp(File_Item->GetText(), "application/x-smpte-mxf;asdcpKind=Picture")) Stream.StreamKind=Stream_Video; else if (!strcmp(File_Item->GetText(), "application/x-smpte-mxf;asdcpKind=Sound")) Stream.StreamKind=Stream_Audio; else if (!strcmp(File_Item->GetText(), "text/xml") || !strcmp(File_Item->GetText(), "text/xml;asdcpKind=CPL")) Stream.StreamKind=(stream_t)(Stream_Max+1); // Means CPL else Stream.StreamKind=Stream_Other; } } Streams.push_back(Stream); } } } } Element_Offset=File_Size; //Merging with Assetmap if (!Config->File_IsReferenced_Get()) { FileName Directory(File_Name); Ztring Assetmap_FileName=Directory.Path_Get()+PathSeparator+__T("ASSETMAP.xml"); bool IsOk=false; if (File::Exists(Assetmap_FileName)) IsOk=true; else { Assetmap_FileName.resize(Assetmap_FileName.size()-4); //Old fashion, without ".xml" if (File::Exists(Assetmap_FileName)) IsOk=true; } if (IsOk) { MediaInfo_Internal MI; MI.Option(__T("File_KeepInfo"), __T("1")); Ztring ParseSpeed_Save=MI.Option(__T("ParseSpeed_Get"), __T("")); Ztring Demux_Save=MI.Option(__T("Demux_Get"), __T("")); MI.Option(__T("ParseSpeed"), __T("0")); MI.Option(__T("Demux"), Ztring()); MI.Option(__T("File_IsReferenced"), __T("1")); size_t MiOpenResult=MI.Open(Assetmap_FileName); MI.Option(__T("ParseSpeed"), ParseSpeed_Save); //This is a global value, need to reset it. TODO: local value MI.Option(__T("Demux"), Demux_Save); //This is a global value, need to reset it. TODO: local value if (MiOpenResult && (MI.Get(Stream_General, 0, General_Format)==__T("DCP AM") || MI.Get(Stream_General, 0, General_Format)==__T("IMF AM"))) { MergeFromAm(((File_DcpPkl*)MI.Info)->Streams); } } } //Creating the playlist if (!Config->File_IsReferenced_Get()) { ReferenceFiles=new File__ReferenceFilesHelper(this, Config); for (File_DcpPkl::streams::iterator Stream=Streams.begin(); Stream!=Streams.end(); ++Stream) if (Stream->StreamKind==(stream_t)(Stream_Max+1) && Stream->ChunkList.size()==1) // Means CPL { sequence* Sequence=new sequence; Sequence->FileNames.push_back(Ztring().From_UTF8(Stream->ChunkList[0].Path)); Sequence->StreamID=ReferenceFiles->Sequences_Size()+1; ReferenceFiles->AddSequence(Sequence); } ReferenceFiles->FilesForStorage=true; } //All should be OK... return true; }