/* 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_GXF_YES) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Multiple/File_Gxf.h" #include "MediaInfo/Multiple/File_Gxf_TimeCode.h" #if defined(MEDIAINFO_DVDIF_YES) #include "MediaInfo/Multiple/File_DvDif.h" #endif #if defined(MEDIAINFO_RIFF_YES) #include "MediaInfo/Multiple/File_Riff.h" #endif #if defined(MEDIAINFO_GXF_YES) #include "MediaInfo/Multiple/File_Umf.h" #endif #if defined(MEDIAINFO_AVC_YES) #include "MediaInfo/Video/File_Avc.h" #endif #if defined(MEDIAINFO_MPEGV_YES) #include "MediaInfo/Video/File_Mpegv.h" #endif #if defined(MEDIAINFO_VC3_YES) #include "MediaInfo/Video/File_Vc3.h" #endif #if defined(MEDIAINFO_AC3_YES) #include "MediaInfo/Audio/File_Ac3.h" #endif #if defined(MEDIAINFO_PCM_YES) #include "MediaInfo/Audio/File_Pcm.h" #endif #if defined(MEDIAINFO_SMPTEST0337_YES) #include "MediaInfo/Audio/File_ChannelGrouping.h" #endif #if MEDIAINFO_EVENTS #include "MediaInfo/MediaInfo_Events.h" #endif //MEDIAINFO_EVENTS #include "MediaInfo/MediaInfo_Config_MediaInfo.h" #include "ZenLib/Utils.h" //--------------------------------------------------------------------------- namespace MediaInfoLib { //*************************************************************************** // Constants //*************************************************************************** //--------------------------------------------------------------------------- static const char* Gxf_Tag_Name(int8u Tag) { switch (Tag) { case 0x40 : return "Media file name of material"; case 0x41 : return "First field of material in stream"; case 0x42 : return "Last field of material in stream"; case 0x43 : return "Mark in for the stream"; case 0x44 : return "Mark out for the stream"; case 0x45 : return "Estimated size of stream in 1024 byte units"; case 0x46 : case 0x47 : case 0x48 : case 0x49 : case 0x4A : case 0x4B : return "Reserved"; case 0x4C : return "Media file name"; case 0x4D : return "Auxiliary Information"; case 0x4E : return "Media file system version"; case 0x4F : return "MPEG auxiliary information"; case 0x50 : return "Frame rate"; case 0x51 : return "Lines per frame"; case 0x52 : return "Fields per frame"; default : return ""; } } //--------------------------------------------------------------------------- static const char* Gxf_MediaTypes(int8u Type) { switch (Type) { case 3 : return "JPEG"; //525 lines case 4 : return "JPEG"; //625 lines case 7 : return "SMPTE 12M"; //525 lines case 8 : return "SMPTE 12M"; //625 lines case 9 : return "PCM"; //24-bit case 10 : return "PCM"; //16-bit case 11 : return "MPEG-2 Video"; //525 lines case 12 : return "MPEG-2 Video"; //625 lines case 13 : return "DV"; //25 Mbps, 525 lines case 14 : return "DV"; //25 Mbps, 625 lines case 15 : return "DV"; //50 Mbps, 525 lines case 16 : return "DV"; //50 Mbps, 625 lines case 17 : return "AC-3"; //16-bit case 18 : return "AES"; //non-PCM case 19 : return "Reserved"; case 20 : return "MPEG-2 Video"; //HD, Main Profile at High Level case 21 : return "Ancillary data"; //SMPTE 291M 10-bit type 2 component ancillary data case 22 : return "MPEG-1 Video"; //525 lines case 23 : return "MPEG-1 Video"; //625 lines case 24 : return "SMPTE 12M"; //HD case 25 : return "DV"; //DVCPRO HD case 26 : return "AVC"; case 29 : return "AVC"; case 30 : return "VC-3"; default : return ""; } } //--------------------------------------------------------------------------- static stream_t Gxf_MediaTypes_StreamKind(int8u Type) { switch (Type) { case 3 : return Stream_Video; case 4 : return Stream_Video; case 7 : return Stream_Max; case 8 : return Stream_Max; case 9 : return Stream_Audio; case 10 : return Stream_Audio; case 11 : return Stream_Video; case 12 : return Stream_Video; case 13 : return Stream_Video; case 14 : return Stream_Video; case 15 : return Stream_Video; case 16 : return Stream_Video; case 17 : return Stream_Audio; case 18 : return Stream_Audio; case 19 : return Stream_Max; case 20 : return Stream_Video; case 21 : return Stream_Max; case 22 : return Stream_Video; case 23 : return Stream_Video; case 24 : return Stream_Max; case 25 : return Stream_Video; case 26 : return Stream_Video; case 29 : return Stream_Video; case 30 : return Stream_Video; default : return Stream_Max; } } //--------------------------------------------------------------------------- double Gxf_FrameRate(int32u Content) { switch (Content) { case 1 : return 60.000; case 2 : return 59.940; case 3 : return 50.000; case 4 : return 30.000; case 5 : return 29.970; case 6 : return 25.000; case 7 : return 24.000; case 8 : return 23.976; default: return 0.000; } } //--------------------------------------------------------------------------- static int32u Gxf_LinesPerFrame_Height(int32u Content) { switch (Content) { case 1 : return 480; case 2 : return 576; case 4 : return 1080; case 6 : return 720; default: return 0; } } //--------------------------------------------------------------------------- static const char* Gxf_FieldsPerFrame(int32u Tag) { switch (Tag) { case 1 : return "Progressive"; case 2 : return "Interlaced"; default: return ""; } } //*************************************************************************** // Constructor/Destructor //*************************************************************************** //--------------------------------------------------------------------------- File_Gxf::File_Gxf() :File__Analyze() { //Configuration ParserName="GXF"; #if MEDIAINFO_EVENTS ParserIDs[0]=MediaInfo_Parser_Gxf; StreamIDs_Width[0]=2; #endif //MEDIAINFO_EVENTS #if MEDIAINFO_DEMUX Demux_Level=2; //Container #endif //MEDIAINFO_DEMUX MustSynchronize=true; Buffer_TotalBytes_Fill_Max=(int64u)-1; //Disabling this feature for this format, this is done in the parser #if MEDIAINFO_DEMUX Demux_EventWasSent_Accept_Specific=true; #endif //MEDIAINFO_DEMUX //Temp Material_Fields_FieldsPerFrame=1; //Progressive by default Parsers_Count=0; AncillaryData_StreamID=(int8u)-1; Material_Fields_First_IsValid=false; Material_Fields_Last_IsValid=false; Material_File_Size_IsValid=false; UMF_File=NULL; #if defined(MEDIAINFO_ANCILLARY_YES) Ancillary=NULL; #endif //defined(MEDIAINFO_ANCILLARY_YES) SizeToAnalyze=16*1024*1024; IsParsingMiddle_MaxOffset=(int64u)-1; Audio_Count=0; Element_Code=0x00; //Element_Code is used as a test for pre-existing parsing, it must be initialized #if MEDIAINFO_DEMUX Demux_HeaderParsed=false; #endif //MEDIAINFO_DEMUX #if MEDIAINFO_SEEK Flt_FieldPerEntry=(int32u)-1; IFrame_IsParsed=false; #endif //MEDIAINFO_SEEK } //--------------------------------------------------------------------------- File_Gxf::~File_Gxf() { //Temp delete Ancillary; //Ancillary=NULL; delete UMF_File; //UMF_File=NULL; } //*************************************************************************** // Streams management //*************************************************************************** //--------------------------------------------------------------------------- void File_Gxf::Streams_Finish() { //Merging audio if Title are same for (size_t StreamID=0; StreamIDFile_Audio_MergeMonoStreams_Get()) { Ztring Title=Streams[StreamID].MediaName; size_t Title_Extension_Offset=Title.find(__T(".A0")); if (Title_Extension_Offset!=std::string::npos && Title_Extension_Offset==Title.size()-3) { Title.resize(Title.size()-3); for (size_t StreamID2=StreamID+1; StreamID2Retrieve(Stream_Audio, 0, Audio_Channel_s_).To_int32u()+Streams[StreamID2].Parsers[0]->Retrieve(Stream_Audio, 0, Audio_Channel_s_).To_int32u(); Streams[StreamID].Parsers[0]->Fill(Stream_Audio, 0, Audio_Channel_s_, Channels, 10, true); int32u BitRate=Streams[StreamID].Parsers[0]->Retrieve(Stream_Audio, 0, Audio_BitRate).To_int32u()+Streams[StreamID2].Parsers[0]->Retrieve(Stream_Audio, 0, Audio_BitRate).To_int32u(); Streams[StreamID].Parsers[0]->Fill(Stream_Audio, 0, Audio_BitRate, BitRate, 10, true); } Streams[StreamID2].MediaType=(int8u)-1; } } } } } //For each Streams for (size_t StreamID=0; StreamID::iterator TimeCode=TimeCodes.begin(); TimeCode!=TimeCodes.end(); ++TimeCode) { int64u TimeCode_FirstFrame_ms=((File_Gxf_TimeCode*)Streams[TimeCode->first].Parsers[0])->TimeCode_FirstFrame_ms; string TimeCode_FirstFrame=((File_Gxf_TimeCode*)Streams[TimeCode->first].Parsers[0])->TimeCode_FirstFrame; bool TimeCode_FirstFrame_Stripped=false; if (TimeCode_FirstFrame_ms==(int64u)-1) { TimeCode_FirstFrame_ms=TimeCode->second.Milliseconds; TimeCode_FirstFrame=TimeCode->second.String; TimeCode_FirstFrame_Stripped=true; } if (TimeCode_FirstFrame_ms!=(int64u)-1) { Stream_Prepare(Stream_Other); Fill(Stream_Other, StreamPos_Last, Other_CodecID, Streams[TimeCode->first].MediaType); Fill(Stream_Other, StreamPos_Last, Other_ID, TimeCode->first); Fill(Stream_Other, StreamPos_Last, Other_Type, "Time code"); Fill(Stream_Other, StreamPos_Last, Other_Format, "SMPTE TC"); Fill(Stream_Other, StreamPos_Last, Other_TimeCode_FirstFrame, TimeCode_FirstFrame.c_str()); if (TimeCode_FirstFrame_Stripped) Fill(Stream_Other, StreamPos_Last, Other_TimeCode_Stripped, "Yes"); if (TimeCode->firstfirst].MediaName); } } } //--------------------------------------------------------------------------- void File_Gxf::Streams_Finish_PerStream(size_t StreamID, stream &Temp) { if (Temp.MediaType==(int8u)-1) return; //By the parser if (Temp.Parsers.size()==1 && Temp.Parsers[0]->Status[IsAccepted]) { StreamKind_Last=Stream_Max; StreamPos_Last=(size_t)-1; if (Config->ParseSpeed<=1.0) { Fill(Temp.Parsers[0]); Temp.Parsers[0]->Open_Buffer_Unsynch(); } Finish(Temp.Parsers[0]); //Video bool IsTimeCode=false; for (std::map::iterator TimeCode=TimeCodes.begin(); TimeCode!=TimeCodes.end(); ++TimeCode) if (StreamID==TimeCode->first) IsTimeCode=true; if (!IsTimeCode && Temp.DisplayInfo) { if (Temp.Parsers[0]->Count_Get(Stream_Video)) { Stream_Prepare(Stream_Video); if (TimeCodes.empty()) { Fill(Stream_Video, StreamPos_Last, Video_Delay, ((float64)(Material_Fields_First/Material_Fields_FieldsPerFrame))/Gxf_FrameRate(Streams[0x00].FrameRate_Code)*1000, 0); Fill(Stream_Video, StreamPos_Last, Video_Delay_Source, "Container"); } else for (std::map::iterator TimeCode=TimeCodes.begin(); TimeCode!=TimeCodes.end(); ++TimeCode) { int64u TimeCode_FirstFrame_ms=((File_Gxf_TimeCode*)Streams[TimeCode->first].Parsers[0])->TimeCode_FirstFrame_ms; string TimeCode_FirstFrame=((File_Gxf_TimeCode*)Streams[TimeCode->first].Parsers[0])->TimeCode_FirstFrame; if (TimeCode_FirstFrame_ms==(int64u)-1) { TimeCode_FirstFrame_ms=TimeCode->second.Milliseconds; TimeCode_FirstFrame=TimeCode->second.String; } if (TimeCode_FirstFrame_ms!=(int64u)-1) { Fill(Stream_Video, StreamPos_Last, Video_Delay, TimeCode_FirstFrame_ms, 0); if (TimeCode_FirstFrame.size()==11) Fill(Stream_Video, StreamPos_Last, Video_Delay_DropFrame, TimeCode_FirstFrame[8]==';'?"Yes":"No"); Fill(Stream_Video, StreamPos_Last, Video_Delay_Source, "Container"); //Fill(Stream_Video, StreamPos_Last, Video_TimeCode_FirstFrame, TimeCode_FirstFrame.c_str()); //Fill(Stream_Video, StreamPos_Last, Video_TimeCode_Source, "Time code track"); } } Merge(*Temp.Parsers[0], Stream_Video, 0, StreamPos_Last); Fill(Stream_Video, StreamPos_Last, Video_CodecID, Temp.MediaType); Fill(Stream_Video, StreamPos_Last, Video_ID, StreamID, 10, true); Fill(Stream_Video, StreamPos_Last, "Title", Temp.MediaName); Ztring LawRating=Temp.Parsers[0]->Retrieve(Stream_General, 0, General_LawRating); if (!LawRating.empty()) Fill(Stream_General, 0, General_LawRating, LawRating, true); Ztring Title=Temp.Parsers[0]->Retrieve(Stream_General, 0, General_Title); if (!Title.empty() && Retrieve(Stream_General, 0, General_Title).empty()) Fill(Stream_General, 0, General_Title, Title); //Special cases if (Temp.Parsers[0]->Count_Get(Stream_Text)) { //Video and Text are together size_t Parser_Text_Count=Temp.Parsers[0]->Count_Get(Stream_Text); for (size_t Parser_Text_Pos=0; Parser_Text_PosCount_Get(Stream_Audio); Pos++) { Stream_Prepare(Stream_Audio); Fill(Stream_Audio, StreamPos_Last, Audio_CodecID, Temp.MediaType); if (TimeCodes.empty()) { Fill(Stream_Audio, StreamPos_Last, Audio_Delay, ((float64)(Material_Fields_First/Material_Fields_FieldsPerFrame))/Gxf_FrameRate(Streams[0x00].FrameRate_Code)*1000, 0); Fill(Stream_Audio, StreamPos_Last, Audio_Delay_Source, "Container"); } else for (std::map::iterator TimeCode=TimeCodes.begin(); TimeCode!=TimeCodes.end(); ++TimeCode) { int64u TimeCode_FirstFrame_ms=((File_Gxf_TimeCode*)Streams[TimeCode->first].Parsers[0])->TimeCode_FirstFrame_ms; string TimeCode_FirstFrame=((File_Gxf_TimeCode*)Streams[TimeCode->first].Parsers[0])->TimeCode_FirstFrame; if (TimeCode_FirstFrame_ms==(int64u)-1) { TimeCode_FirstFrame_ms=TimeCode->second.Milliseconds; TimeCode_FirstFrame=TimeCode->second.String; } if (TimeCode_FirstFrame_ms!=(int64u)-1) { Fill(Stream_Audio, StreamPos_Last, Audio_Delay, TimeCode_FirstFrame_ms, 0); if (TimeCode_FirstFrame.size()==11) Fill(Stream_Audio, StreamPos_Last, Audio_Delay_DropFrame, TimeCode_FirstFrame[8]==';'?"Yes":"No"); Fill(Stream_Audio, StreamPos_Last, Audio_Delay_Source, "Container"); //Fill(Stream_Audio, StreamPos_Last, Audio_TimeCode_FirstFrame, TimeCode_FirstFrame.c_str()); //Fill(Stream_Audio, StreamPos_Last, Audio_TimeCode_Source, "Time code track"); } } if (Temp.IsChannelGrouping) Fill(Stream_Audio, StreamPos_Last, "Title", Streams[StreamID-1].MediaName); //First half of the channel grouping Fill(StreamKind_Last, StreamPos_Last, "Title", Temp.MediaName); //Second half of the channel grouping or standalone Merge(*Temp.Parsers[0], Stream_Audio, Pos, StreamPos_Last, false); Ztring ID; if (Temp.IsChannelGrouping) ID=Ztring::ToZtring(StreamID-1)+__T(" / "); //First half of the channel grouping ID+=Ztring::ToZtring(StreamID); //Second half of the channel grouping or standalone Ztring ID_String=ID; if (!Retrieve(Stream_Audio, StreamPos_Last, Audio_ID).empty()) { ID+=__T('-')+Retrieve(Stream_Audio, StreamPos_Last, Audio_ID); ID_String+=__T('-')+Retrieve(Stream_Audio, StreamPos_Last, Audio_ID_String); } Fill(Stream_Audio, StreamPos_Last, Audio_ID, ID, true); Fill(Stream_Audio, StreamPos_Last, Audio_ID_String, ID_String, true); for (std::map::iterator Info=Temp.Infos.begin(); Info!=Temp.Infos.end(); ++Info) if (Info->first=="BitRate" && Temp.Parsers[0]->Count_Get(Stream_Audio)>1) Fill(Stream_Audio, StreamPos_Last, Audio_BitRate_Encoded, Pos?Ztring(__T("0")):Info->second, true); // In case of more than 1 audio sub-stream Encoded bit rate is the bit rate of all streams + overhead else if (Retrieve(Stream_Audio, StreamPos_Last, Info->first.c_str()).empty()) Fill(Stream_Audio, StreamPos_Last, Info->first.c_str(), Info->second); } //Text if (Temp.Parsers[0]->Count_Get(Stream_Text)) { size_t Parser_Text_Count=Temp.Parsers[0]->Count_Get(Stream_Text); for (size_t Parser_Text_Pos=0; Parser_Text_PosRetrieve(Stream_General, 0, General_LawRating); if (!LawRating.empty()) Fill(Stream_General, 0, General_LawRating, LawRating, true); Ztring Title=Temp.Parsers[0]->Retrieve(Stream_General, 0, General_Title); if (!Title.empty() && Retrieve(Stream_General, 0, General_Title).empty()) Fill(Stream_General, 0, General_Title, Title); StreamKind_Last=Stream_Max; StreamPos_Last=(size_t)-1; } //Other if (Temp.Parsers[0]->Count_Get(Stream_Other)) { size_t Parser_Other_Count=Temp.Parsers[0]->Count_Get(Stream_Other); for (size_t Parser_Other_Pos=0; Parser_Other_Pos=Buffer_Size || Buffer[Buffer_Offset-1]==0x00) Buffer_Offset--; } if (Buffer_Offset+16<=Buffer_Size) //Testing if size is coherant { //Retrieving some info int32u Size=BigEndian2int32u(Buffer+Buffer_Offset+6); //Testing if (Buffer_Offset+Size+16>Buffer_Size) return false; //Need more data if (Buffer[Buffer_Offset+Size ]!=0x00 || Buffer[Buffer_Offset+Size+1]!=0x00 || Buffer[Buffer_Offset+Size+2]!=0x00 || Buffer[Buffer_Offset+Size+3]!=0x00 || Buffer[Buffer_Offset+Size+4]!=0x01 || Buffer[Buffer_Offset+Size+14]!=0xE1 || Buffer[Buffer_Offset+Size+15]!=0xE2) Buffer_Offset++; else break; } } //Parsing last bytes if needed if (Buffer_Offset+16>Buffer_Size) { return false; } if (!Status[IsAccepted]) { Accept("GXF"); Fill(Stream_General, 0, General_Format, "GXF"); Streams.resize(0x40); } //Synched is OK return true; } //--------------------------------------------------------------------------- bool File_Gxf::Synched_Test() { //Must have enough buffer for having header if (Buffer_Offset+16>Buffer_Size) return false; //Quick test of synchro if (CC5(Buffer+Buffer_Offset )!=0x0000000001 || CC2(Buffer+Buffer_Offset+14)!=0xE1E2) Synched=false; //Test if the next synchro is available int32u PacketLength=BigEndian2int32u(Buffer+Buffer_Offset+6); if (File_Offset+Buffer_Offset+PacketLength+16<=File_Size) { if (Buffer_Offset+PacketLength+16>Buffer_Size) return false; if (CC5(Buffer+Buffer_Offset+PacketLength )!=0x0000000001 || CC2(Buffer+Buffer_Offset+PacketLength+14)!=0xE1E2) Synched=false; } //We continue return true; } //*************************************************************************** // Buffer - Global //*************************************************************************** //--------------------------------------------------------------------------- void File_Gxf::Read_Buffer_Unsynched() { for (size_t Pos=0; PosOpen_Buffer_Unsynch(); #if MEDIAINFO_SEEK IFrame_IsParsed=false; #endif //MEDIAINFO_SEEK } //--------------------------------------------------------------------------- #if MEDIAINFO_SEEK size_t File_Gxf::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 { //We transform TimeStamp to a frame number if (Streams.empty() || Gxf_FrameRate(Streams[0x00].FrameRate_Code)==0) return (size_t)-1; //Not supported int64u Delay=0; if (TimeCodes.empty()) { if (Material_Fields_First_IsValid) Delay=float64_int64s(((float64)(Material_Fields_First/Material_Fields_FieldsPerFrame))/Gxf_FrameRate(Streams[0x00].FrameRate_Code)*1000000000); else Delay=0; } else { for (std::map::iterator TimeCode=TimeCodes.begin(); TimeCode!=TimeCodes.end(); ++TimeCode) { int64u TimeCode_First=((File_Gxf_TimeCode*)Streams[TimeCode->first].Parsers[0])->TimeCode_FirstFrame_ms; if (TimeCode_First==(int64u)-1) TimeCode_First=TimeCode->second.Milliseconds; if (TimeCode_First==(int64u)-1) Delay=0; else { Delay=TimeCode_First*1000000; break; } } } if (ValueGopSize!=(int64u)-1) { Value/=((File_Umf*)UMF_File)->GopSize; Value*=((File_Umf*)UMF_File)->GopSize; } Value*=Material_Fields_FieldsPerFrame; for (size_t Pos=0; Pos=IsParsingMiddle_MaxOffset) { Fill(); Open_Buffer_Unsynch(); Finish(); return; } } //*************************************************************************** // Buffer - Per element //*************************************************************************** //--------------------------------------------------------------------------- bool File_Gxf::Header_Begin() { #if MEDIAINFO_DEMUX //Handling of multiple frames in one block if (Element_Code==0xBF && Config->Demux_Unpacketize_Get() && Streams[TrackNumber].Demux_EventWasSent) //media block { Open_Buffer_Continue(Streams[TrackNumber].Parsers[0], Buffer+Buffer_Offset, 0); if (Config->Demux_EventWasSent) return false; Streams[TrackNumber].Demux_EventWasSent=false; } #endif //MEDIAINFO_DEMUX return true; } //--------------------------------------------------------------------------- void File_Gxf::Header_Parse() { //Parsing int32u PacketLength; int8u PacketType; Skip_B5( "Packet leader"); Get_B1 (PacketType, "Packet type"); Get_B4 (PacketLength, "Packet length"); Skip_B4( "Reserved"); Skip_B2( "Packet trailer"); //Filling Header_Fill_Size(PacketLength); Header_Fill_Code(PacketType); #if MEDIAINFO_DEMUX if (!Demux_HeaderParsed) { if (PacketType==0xBF) //media { #if MEDIAINFO_NEXTPACKET if (Config->NextPacket_Get() && Config->Event_CallBackFunction_IsSet()) Config->Demux_EventWasSent=true; //First set is to indicate the user that header is parsed #endif Demux_HeaderParsed=true; } } #endif //MEDIAINFO_DEMUX } //--------------------------------------------------------------------------- void File_Gxf::Data_Parse() { //Counting Frame_Count++; switch (Element_Code) { case 0x00 : Finish("GXF"); break; case 0xBC : map(); break; case 0xBF : media(); break; case 0xFB : end_of_stream(); break; case 0xFC : field_locator_table(); break; case 0xFD : UMF_file(); break; default: ; } } //--------------------------------------------------------------------------- void File_Gxf::map() { Element_Name("map"); //Parsing int8u Version; Element_Begin1("Preamble"); BS_Begin(); Mark_1(); Mark_1(); Mark_1(); Get_S1(5, Version, "Version"); BS_End(); Skip_B1( "Reserved"); Element_End0(); Element_Begin1("Material Data"); int16u SectionLength; Get_B2 (SectionLength, "Section Length"); if (Element_Offset+SectionLength>=Element_Size) SectionLength=(int16u)(Element_Size-Element_Offset); int64u Material_Data_End=Element_Offset+SectionLength; while (Element_Offset=Element_Size) SectionLength=(int16u)(Element_Size-Element_Offset); int64u Track_Data_End=Element_Offset+SectionLength; while (Element_Offset=Track_Data_End) TrackLength=(int16u)(Track_Data_End-Element_Offset); int64u Track_End=Element_Offset+TrackLength; Element_Info1(TrackID&0x3F); Element_Info1(Gxf_MediaTypes(MediaType&0x7F)); FILLING_BEGIN(); MediaType&=0x7F; //Remove the last bit TrackID&=0x3F; //Remove the 2 last bits Streams[TrackID].MediaType=MediaType; Streams[TrackID].TrackID=TrackID; if (Streams[TrackID].Parsers.empty()) { Streams[TrackID].MediaType=MediaType; Streams[TrackID].TrackID=TrackID; //Parsers #if MEDIAINFO_DEMUX Element_Code=TrackID; #endif //MEDIAINFO_DEMUX switch (MediaType) { case 3 : case 4 : //JPEG { File__Analyze* Parser=new File__Analyze; Open_Buffer_Init(Parser); Parser->Accept(); Parser->Fill(); Parser->Stream_Prepare(Stream_Video); Parser->Fill(Stream_Video, 0, Video_Format, "JPEG"); Streams[TrackID].Parsers.push_back(Parser); } break; case 7 : case 8 : case 24 : //TimeCode { File__Analyze* Parser=new File_Gxf_TimeCode; Open_Buffer_Init(Parser); Streams[TrackID].Parsers.push_back(Parser); Parsers_Count++; Streams[TrackID].Searching_Payload=true; TimeCodes[TrackID].Milliseconds=(int64u)-1; } break; case 9 : case 10 : { File__Analyze* Parser=new File__Analyze; Open_Buffer_Init(Parser); Parser->Accept(); Parser->Fill(); Parser->Stream_Prepare(Stream_Audio); Parser->Fill(Stream_Audio, 0, Audio_Format, "PCM"); Parser->Fill(Stream_Audio, 0, Audio_Format_Settings_Endianness, "Little"); Streams[TrackID].Parsers.push_back(Parser); Audio_Count++; } break; case 11 : case 12 : case 20 : case 22 : case 23 : //MPEG Video { #ifdef MEDIAINFO_MPEGV_YES File__Analyze* Parser=new File_Mpegv(); ((File_Mpegv*)Parser)->FrameIsAlwaysComplete=true; ((File_Mpegv*)Parser)->Ancillary=&Ancillary; Open_Buffer_Init(Parser); Streams[TrackID].Parsers.push_back(Parser); Parsers_Count++; Streams[TrackID].Searching_Payload=true; #endif //MEDIAINFO_MPEGV_YES } break; case 13 : case 14 : case 15 : case 16 : case 25 : // was found for DVCPro HD in some files (not in SMPTE ST 360-2009, maybe it is present in a later version) //DV { File__Analyze* Parser=new File_DvDif(); Open_Buffer_Init(Parser); Streams[TrackID].Parsers.push_back(Parser); Parsers_Count++; Streams[TrackID].Searching_Payload=true; } break; case 17 : //AC-3 in AES3 (half) case 18 : //Dolby E in AES3 (half) { File__Analyze* Parser=ChooseParser_ChannelGrouping(TrackID); if (Parser) { Open_Buffer_Init(Parser); Streams[TrackID].Parsers.push_back(Parser); Parsers_Count++; Audio_Count++; Streams[TrackID].Searching_Payload=true; } } break; case 21 : //Ancillary Metadata { #ifdef MEDIAINFO_RIFF_YES File__Analyze* Parser=new File_Riff(); ((File_Riff*)Parser)->Ancillary=&Ancillary; Open_Buffer_Init(Parser); Streams[TrackID].Parsers.push_back(Parser); Parsers_Count++; Streams[TrackID].Searching_Payload=true; Ancillary=new File_Ancillary; Ancillary->WithTenBit=true; Ancillary->WithChecksum=true; Open_Buffer_Init(Ancillary); AncillaryData_StreamID=TrackID; if (SizeToAnalyze<8*16*1024*1024) SizeToAnalyze*=8; //10x more, to be sure to find captions #endif //MEDIAINFO_RIFF_YES } break; case 26 : case 29 : //AVC { File__Analyze* Parser=new File_Avc(); Open_Buffer_Init(Parser); Streams[TrackID].Parsers.push_back(Parser); Parsers_Count++; Streams[TrackID].Searching_Payload=true; } break; case 30 : //VC-3 { File__Analyze* Parser=new File_Vc3(); Open_Buffer_Init(Parser); Streams[TrackID].Parsers.push_back(Parser); Parsers_Count++; Streams[TrackID].Searching_Payload=true; } break; default : ; } if (Gxf_MediaTypes_StreamKind(MediaType)==Stream_Audio) { //Resolution switch (MediaType) { case 9 : case 18 : //24-bit Streams[TrackID].Infos["BitDepth"].From_Number(24); break; case 10 : case 17 : //16-bit Streams[TrackID].Infos["BitDepth"].From_Number(16); break; default : ; } //Channels switch (MediaType) { case 9 : case 10 : //Mono Streams[TrackID].Infos["Channel(s)"].From_Number(1); break; case 18 : //Stereo Streams[TrackID].Infos["Channel(s)"].From_Number(2); break; default : ; } //Sampling rate switch (MediaType) { case 9 : case 10 : case 17 : case 18 : //48000 Streams[TrackID].Infos["SamplingRate"].From_Number(48000); break; default : ; } //Bit rate switch (MediaType) { case 9 : //Mono, 48 KHz, 24-bit (or padded up to 24-bit) Streams[TrackID].Infos["BitRate"].From_Number(1*48000*24); break; case 10 : //Mono, 48 KHz, 16-bit Streams[TrackID].Infos["BitRate"].From_Number(1*48000*16); break; case 18 : //Stereo, 48 KHz, 24-bit (or padded up to 24-bit) Streams[TrackID].Infos["BitRate"].From_Number(2*48000*24); break; default : ; } } } FILLING_END(); int8u Hours=(int8u)-1, Minutes=(int8u)-1, Seconds=(int8u)-1, Fields=(int8u)-1; bool Invalid=true, DropFrame=true; bool TimeCode_Parsed=false; while (Element_Offset::iterator TimeCode=TimeCodes.begin(); TimeCode!=TimeCodes.end(); ++TimeCode) if (TrackID==TimeCode->first) for (size_t Pos=0; PosFrameRate_Code=Streams[0x00].FrameRate_Code; if (Gxf_MediaTypes_StreamKind(MediaType)==Stream_Video) Stream_Video_FrameRate_Code=Streams[TrackID].FrameRate_Code; } else Skip_XX(DataLength, "Unknown"); break; case 0x51 : //Lines per frame if (DataLength==4) { Get_B4 (Streams[TrackID].LinesPerFrame_Code, "Content"); Param_Info1(Gxf_LinesPerFrame_Height(Streams[TrackID].LinesPerFrame_Code)); Element_Info1(Gxf_LinesPerFrame_Height(Streams[TrackID].LinesPerFrame_Code)); } else Skip_XX(DataLength, "Unknown"); break; case 0x52 : //Fields per frame if (DataLength==4) { Get_B4 (Streams[TrackID].FieldsPerFrame_Code, "Content"); Param_Info1(Gxf_FieldsPerFrame(Streams[TrackID].FieldsPerFrame_Code)); Element_Info1(Gxf_FieldsPerFrame(Streams[TrackID].FieldsPerFrame_Code)); if (Gxf_MediaTypes_StreamKind(MediaType)==Stream_Video) { Stream_Video_FieldsPerFrame_Code=Streams[TrackID].FieldsPerFrame_Code; Material_Fields_FieldsPerFrame=Streams[TrackID].FieldsPerFrame_Code; } for (std::map::iterator TimeCode=TimeCodes.begin(); TimeCode!=TimeCodes.end(); ++TimeCode) if (TrackID==TimeCode->first) for (size_t Pos=0; PosFieldsPerFrame_Code=Streams[0x00].FieldsPerFrame_Code; } else Skip_XX(DataLength, "Unknown"); break; default : Skip_XX(DataLength, "Unknown"); } Element_End0(); } Element_End0(); //Test on TimeCode if (TimeCode_Parsed && !Invalid) { std::map::iterator TimeCode_Item=TimeCodes.find(TrackID); if (TimeCode_Item==TimeCodes.end() || TimeCode_Item->second.Milliseconds==(int64u)-1) { float64 FrameRate=Gxf_FrameRate(Streams[TrackID].FrameRate_Code); TimeCodes[TrackID].Milliseconds=Hours *60*60*1000 +Minutes *60*1000 +Seconds *1000; TimeCodes[TrackID].String=TimeCode(Hours, Minutes, Seconds, Fields/2, 99, TimeCode::DropFrame(DropFrame).Field(Fields%2)).ToString(); if (!FrameRate) { //Time code frame rate is missing, using the video frame rate for (size_t Pos=0; PosGopSize!=(int64u)-1) IFrame_IsParsed=(((MediaFieldNumber-(Material_Fields_First_IsValid?Material_Fields_First:0))/Material_Fields_FieldsPerFrame)%((File_Umf*)UMF_File)->GopSize)==0; else if (Gxf_MediaTypes_StreamKind(Streams[TrackNumber].MediaType)==Stream_Video) IFrame_IsParsed=true; } #endif //MEDIAINFO_SEEK #if MEDIAINFO_DEMUX if (Streams[TrackNumber].MediaType!=8) //Not a TimeCode stream { Element_Code=TrackNumber; int64u TimeCode_First=0; if (!TimeCodes.empty()) { TimeCode_First=((File_Gxf_TimeCode*)Streams[TimeCodes.begin()->first].Parsers[0])->TimeCode_FirstFrame_ms; if (TimeCode_First==(int64u)-1) TimeCode_First=TimeCodes.begin()->second.Milliseconds; } if (TimeCode_First!=(int64u)-1) TimeCode_First*=1000000; if (Gxf_MediaTypes_StreamKind(Streams[TrackNumber].MediaType)==Stream_Video) { if (Gxf_FrameRate(Streams[TrackNumber].FrameRate_Code)) { FrameInfo.DTS=TimeCode_First+float64_int64s(((float64)MediaFieldNumber-(Material_Fields_First_IsValid?Material_Fields_First:0))/Material_Fields_FieldsPerFrame*1000000000/Gxf_FrameRate(Streams[TrackNumber].FrameRate_Code)); FrameInfo.PTS=(int64u)-1; FrameInfo.DUR=float64_int64s(((float64)1000000000)/Gxf_FrameRate(Streams[TrackNumber].FrameRate_Code)); } else FrameInfo.DTS=FrameInfo.PTS=FrameInfo.DUR=(int64u)-1; if (MediaFieldNumber-(Material_Fields_First_IsValid?Material_Fields_First:0)==0) Demux_random_access=true; else { if (UMF_File && ((File_Umf*)UMF_File)->GopSize!=(int64u)-1) Demux_random_access=(((MediaFieldNumber-(Material_Fields_First_IsValid?Material_Fields_First:0))/Material_Fields_FieldsPerFrame)%((File_Umf*)UMF_File)->GopSize)==0; else Demux_random_access=false; } } else if (Gxf_MediaTypes_StreamKind(Streams[TrackNumber].MediaType)==Stream_Audio) { if (Gxf_FrameRate(Streams[TrackNumber].FrameRate_Code)) { Frame_Count_NotParsedIncluded=(int64u)((MediaFieldNumber-(Material_Fields_First_IsValid?Material_Fields_First:0))/Gxf_FrameRate(Streams[TrackNumber].FrameRate_Code)*48000/32768/Material_Fields_FieldsPerFrame); //A block is 32768 samples at 48 KHz FrameInfo.PTS=TimeCode_First+Frame_Count_NotParsedIncluded*1000000000*32768/48000; //A block is 32768 samples at 48 KHz if (Material_Fields_First_IsValid && MediaFieldNumber!=Material_Fields_First && Streams[TrackNumber].FirstFrameDuration) //In case of offset, MediaFieldNumber-Material_Fields_First is not well rounded { FrameInfo.PTS+=Streams[TrackNumber].FirstFrameDuration; Frame_Count_NotParsedIncluded++; } FrameInfo.DTS=FrameInfo.PTS; } else FrameInfo.DTS=FrameInfo.PTS=(int64u)-1; FrameInfo.DUR=float64_int64s(((float64)1000000000)*32768/48000); Demux_random_access=true; } else { if (Gxf_FrameRate(Streams[0x00].FrameRate_Code)) FrameInfo.DTS=FrameInfo.PTS=TimeCode_First+float64_int64s(((float64)(MediaFieldNumber-(Material_Fields_First_IsValid?Material_Fields_First:0)))*1000000000/Gxf_FrameRate(Streams[0x00].FrameRate_Code)/Material_Fields_FieldsPerFrame); else FrameInfo.DTS=FrameInfo.PTS=(int64u)-1; FrameInfo.DUR=(int64u)-1; Demux_random_access=true; } #if MEDIAINFO_SEEK if (Gxf_MediaTypes_StreamKind(Streams[TrackNumber].MediaType)!=Stream_Video || IFrame_IsParsed) #endif //MEDIAINFO_SEEK { if (Gxf_MediaTypes_StreamKind(Streams[TrackNumber].MediaType)!=Stream_Audio) Frame_Count_NotParsedIncluded=(MediaFieldNumber-(Material_Fields_First_IsValid?Material_Fields_First:0))/Material_Fields_FieldsPerFrame; Demux_Level=(!Streams[TrackNumber].Parsers.empty() && (Streams[TrackNumber].Parsers[0]->Demux_UnpacketizeContainer || Streams[TrackNumber].Parsers[0]->Demux_Level==2))?4:2; //Intermediate (D-10 Audio) / Container Demux(Buffer+Buffer_Offset+(size_t)Element_Offset, (size_t)(Element_Size-Element_Offset), ContentType_MainStream); } Element_Code=0xBF; //media } #endif //MEDIAINFO_DEMUX //Needed? if (!Streams[TrackNumber].Searching_Payload && IsParsingMiddle_MaxOffset==(int64u)-1) { Skip_XX(Element_Size-Element_Offset, "data"); //Element_DoNotShow(); return; } for (size_t Pos=0; PosFrameInfo.DTS=FrameInfo.DTS; Open_Buffer_Continue(Streams[TrackNumber].Parsers[Pos], Buffer+Buffer_Offset+(size_t)Element_Offset, (size_t)(Element_Size-Element_Offset)); #if MEDIAINFO_DEMUX if (Config->Demux_EventWasSent && Config->Demux_Unpacketize_Get()) Streams[TrackNumber].Demux_EventWasSent=true; #endif //MEDIAINFO_DEMUX //Multiple parsers if (Streams[TrackNumber].Parsers.size()>1) { if (!Streams[TrackNumber].Parsers[Pos]->Status[IsAccepted] && Streams[TrackNumber].Parsers[Pos]->Status[IsFinished]) { delete *(Streams[TrackNumber].Parsers.begin()+Pos); Streams[TrackNumber].Parsers.erase(Streams[TrackNumber].Parsers.begin()+Pos); Pos--; } else if (Streams[TrackNumber].Parsers.size()>1 && Streams[TrackNumber].Parsers[Pos]->Status[IsAccepted]) { File__Analyze* Parser=Streams[TrackNumber].Parsers[Pos]; for (size_t Pos2=0; Pos2ParseSpeed<1 && Streams[TrackNumber].Parsers.size()==1 && Streams[TrackNumber].Parsers[0]->Status[IsFilled]) { Streams[TrackNumber].Searching_Payload=false; if (Parsers_Count>0) Parsers_Count--; if (Parsers_Count==0) { TryToFinish(); } } } //--------------------------------------------------------------------------- void File_Gxf::end_of_stream() { Element_Name("end of stream"); } //--------------------------------------------------------------------------- void File_Gxf::field_locator_table() { Element_Name("field locator table"); //Parsing int32u Entries; #if MEDIAINFO_SEEK Get_L4 (Flt_FieldPerEntry, "Number of fields per FLT entry"); #else //MEDIAINFO_SEEK Skip_L4( "Number of fields per FLT entry"); #endif //MEDIAINFO_SEEK Get_L4 (Entries, "Number of FLT entries"); for (size_t Pos=0; PosGopSize!=(int64u)-1) { size_t NextIFrame=0; for (size_t Pos=0; Pos=NextIFrame) { seek Seek; Seek.FrameNumber=(Material_Fields_First_IsValid?Material_Fields_First:0)+Pos*Flt_FieldPerEntry; Seek.StreamOffset=Flt_Offsets[Pos]; Seeks.push_back(Seek); NextIFrame+=(size_t)((File_Umf*)UMF_File)->GopSize*Material_Fields_FieldsPerFrame; } Flt_Offsets.clear(); } #endif //MEDIAINFO_SEEK } //*************************************************************************** // Helpers //*************************************************************************** //--------------------------------------------------------------------------- void File_Gxf::Detect_EOF() { if (File_Offset+Buffer_Size>=SizeToAnalyze) { TryToFinish(); } } //--------------------------------------------------------------------------- File__Analyze* File_Gxf::ChooseParser_ChannelGrouping(int8u TrackID) { #ifdef MEDIAINFO_SMPTEST0337_YES File_ChannelGrouping* Parser; if (Audio_Count%2) { if (!TrackID || !Streams[TrackID-1].IsChannelGrouping) return NULL; //Not a channel grouping Parser=new File_ChannelGrouping; Parser->CanBePcm=true; Parser->Channel_Pos=1; Parser->Common=((File_ChannelGrouping*)Streams[TrackID-1].Parsers[0])->Common; Parser->StreamID=TrackID-1; Streams[TrackID].IsChannelGrouping=true; } else { Parser=new File_ChannelGrouping; Parser->CanBePcm=true; Parser->Channel_Pos=0; //if (Descriptor->second.Infos.find("SamplingRate")!=Descriptor->second.Infos.end()) Streams[TrackID].IsChannelGrouping=true; Streams[TrackID].DisplayInfo=false; } Parser->BitDepth=24; Parser->Channel_Total=2; Parser->SamplingRate=48000; //TODO: find where this piece of info is avaialble Parser->Endianness='L'; #if MEDIAINFO_DEMUX if (Demux_UnpacketizeContainer) { Parser->Demux_Level=2; //Container Parser->Demux_UnpacketizeContainer=true; } #endif //MEDIAINFO_DEMUX return Parser; #else return NULL; #endif // MEDIAINFO_SMPTEST0337_YES } //--------------------------------------------------------------------------- void File_Gxf::TryToFinish() { if (!IsSub && File_Size!=(int64u)-1 && Config->ParseSpeed<1 && IsParsingMiddle_MaxOffset==(int64u)-1 && File_Size/2>SizeToAnalyze*4) { IsParsingMiddle_MaxOffset=File_Size/2+SizeToAnalyze*4; GoTo(File_Size/2); Open_Buffer_Unsynch(); Parsers_Count=(int8u)-1; return; } Finish(); } } //NameSpace #endif //MEDIAINFO_GXF_YES