/* 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" //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #ifdef MEDIAINFO_RIFF_YES //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Multiple/File_Riff.h" #include "MediaInfo/Audio/File_DolbyAudioMetadata.h" #if defined(MEDIAINFO_MPEG4V_YES) #include "MediaInfo/Video/File_Mpeg4v.h" #endif #if defined(MEDIAINFO_MPEGA_YES) #include "MediaInfo/Audio/File_Mpega.h" #endif #if defined(MEDIAINFO_AC3_YES) #include "MediaInfo/Audio/File_Ac3.h" #endif #if defined(MEDIAINFO_ADM_YES) #include "MediaInfo/Audio/File_Adm.h" #endif #if defined(MEDIAINFO_DTS_YES) #include "MediaInfo/Audio/File_Dts.h" #endif #if defined(MEDIAINFO_DVDIF_YES) #include "MediaInfo/Multiple/File_DvDif.h" #endif #if MEDIAINFO_EVENTS #include "MediaInfo/MediaInfo_Events.h" #endif //MEDIAINFO_EVENTS #include "MediaInfo/MediaInfo_Config_MediaInfo.h" #if defined(MEDIAINFO_FILE_YES) #include #endif //defined(MEDIAINFO_FILE_YES) #include using namespace ZenLib; //--------------------------------------------------------------------------- namespace MediaInfoLib { //*************************************************************************** // Const //*************************************************************************** namespace Elements { const int32u AIFF_SSND=0x53534E44; const int32u AVI_=0x41564920; const int32u AVI__hdlr_strl_strh_txts=0x74787473; const int32u BW64=0x42573634; const int32u FORM=0x464F524D; const int32u LIST=0x4C495354; const int32u MThd=0x4D546864; const int32u ON2_=0x4F4E3220; const int32u ON2f=0x4F4E3266; const int32u RIFF=0x52494646; const int32u riff=0x72696666; const int32u RF64=0x52463634; const int32u SMV0=0x534D5630; const int32u SMV0_xxxx=0x534D563A; const int32u W3DI=0x57334449; const int32u WAVE=0x57415645; const int32u WAVE_axml=0x61786D6C; const int32u WAVE_data=0x64617461; const int32u WAVE_ds64=0x64733634; } //--------------------------------------------------------------------------- const char* Format_Settings_Names_Video[]= { "BitmapInfoHeader", // BITMAPINFOHEADER, https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader }; const char* Format_Settings_Names_Audio[]= { "WaveFormat", // WAVEFORMAT, https://learn.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformat "PcmWaveformat", // PCMWAVEFORMAT, https://learn.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-pcmwaveformat "WaveFormatEx", // WAVEFORMATEX, https://learn.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformatex "WaveFormatExtensible", // WAVEFORMATEXTENSIBLE, https://learn.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformatextensible }; const char** Format_Settings_Names[] = { Format_Settings_Names_Video, Format_Settings_Names_Audio, }; //*************************************************************************** // Format //*************************************************************************** //--------------------------------------------------------------------------- File_Riff::File_Riff() :File__Analyze() { //Configuration #if MEDIAINFO_EVENTS ParserIDs[0]=MediaInfo_Parser_Riff; StreamIDs_Width[0]=4; #endif //MEDIAINFO_EVENTS #if MEDIAINFO_DEMUX Demux_Level=2; //Container #endif //MEDIAINFO_DEMUX DataMustAlwaysBeComplete=false; //In/Out #if defined(MEDIAINFO_ANCILLARY_YES) Ancillary=NULL; #endif //defined(MEDIAINFO_ANCILLARY_YES) //Data Interleaved0_1=0; Interleaved0_10=0; Interleaved1_1=0; Interleaved1_10=0; //Temp DolbyAudioMetadata=NULL; #if defined(MEDIAINFO_ADM_YES) Adm=NULL; Adm_chna=NULL; #endif WAVE_data_Size=(int64u)-1; WAVE_fact_samplesCount=(int64u)-1; Buffer_DataToParse_Begin=(int64u)-1; Buffer_DataToParse_End=0; #if MEDIAINFO_DEMUX AvgBytesPerSec=0; #endif //!MEDIAINFO_DEMUX avih_FrameRate=0; avih_TotalFrame=0; dmlh_TotalFrame=0; Idx1_Offset=(int64u)-1; movi_Size=0; TimeReference=(int64u)-1; SMV_BlockSize=0; SamplesPerSec=0; stream_Count=0; Format_Settings[0]=0; Format_Settings[1]=0; BlockAlign=0; rec__Present=false; NeedOldIndex=true; IsBigEndian=false; IsWave64=false; IsRIFF64=false; IsBW64=false; IsWaveBroken=false; IsNotWordAligned=false; IsNotWordAligned_Tested=false; SecondPass=false; DV_FromHeader=NULL; Kind=Kind_None; #if MEDIAINFO_DEMUX Demux_Parser=NULL; #endif //MEDIAINFO_DEMUX //Pointers Stream_Structure_Temp=Stream_Structure.end(); } //--------------------------------------------------------------------------- File_Riff::~File_Riff() { #ifdef MEDIAINFO_DVDIF_YES delete (File_DvDif*)DV_FromHeader; //DV_FromHeader=NULL #endif //MEDIAINFO_DVDIF_YES delete DolbyAudioMetadata; #if defined(MEDIAINFO_ADM_YES) delete Adm; delete Adm_chna; #endif } //*************************************************************************** // Streams management //*************************************************************************** //--------------------------------------------------------------------------- void File_Riff::Streams_Finish () { //Ancillary specific #if defined(MEDIAINFO_ANCILLARY_YES) if (Ancillary && (*Ancillary)) { Clear(); Stream_Prepare(Stream_General); Finish(*Ancillary); Merge(**Ancillary); Ztring LawRating=(*Ancillary)->Retrieve(Stream_General, 0, General_LawRating); if (!LawRating.empty()) Fill(Stream_General, 0, General_LawRating, LawRating, true); Ztring Title=(*Ancillary)->Retrieve(Stream_General, 0, General_Title); if (!Title.empty() && Retrieve(Stream_General, 0, General_Title).empty()) Fill(Stream_General, 0, General_Title, Title); return; } #endif //defined(MEDIAINFO_ANCILLARY_YES) //Global if (IsRIFF64) Fill(Stream_General, 0, General_Format_Profile, IsBW64?"BW64":"RF64"); if (DolbyAudioMetadata) //Before ADM for having content before all ADM stuff Merge(*DolbyAudioMetadata, Stream_Audio, 0, 0); if (Adm) { if (Adm_chna) { Adm->chna_Move(Adm_chna); delete Adm_chna; Adm_chna=NULL; } Finish(Adm); Merge(*Adm, Stream_Audio, 0, 0); } if (DolbyAudioMetadata) //After ADM for having content inside ADM stuff DolbyAudioMetadata->Merge(*this, 0); if (Adm && (!DolbyAudioMetadata || !DolbyAudioMetadata->HasSegment9) && Retrieve_Const(Stream_Audio, 0, "AdmProfile_Format")==__T("Dolby Atmos Master")) { Clear(Stream_Audio, 0, "AdmProfile"); Clear(Stream_Audio, 0, "AdmProfile_Format"); Clear(Stream_Audio, 0, "AdmProfile_Version"); } //Time codes TimeCode_Fill(__T("ISMP"), INFO_ISMP); TimeCode_Fill(__T("Adobe tc_A"), Tdat_tc_A); TimeCode_Fill(__T("Adobe tc_O"), Tdat_tc_O); //For each stream std::map::iterator Temp=Stream.begin(); while (Temp!=Stream.end()) { //Preparing StreamKind_Last=Temp->second.StreamKind; StreamPos_Last=Temp->second.StreamPos; //StreamSize if (Temp->second.StreamSize>0) Fill(StreamKind_Last, StreamPos_Last, Fill_Parameter(StreamKind_Last, Generic_StreamSize), Temp->second.StreamSize); //When there are few frames, difficult to detect PCM if (Temp->second.IsPcm && !Temp->second.Parsers.empty() && !Temp->second.Parsers[0]->Status[IsAccepted]) { for (size_t Pos=0; Possecond.Parsers.size()-1; Pos++) delete Temp->second.Parsers[Pos]; Temp->second.Parsers.erase(Temp->second.Parsers.begin(), Temp->second.Parsers.begin()+Temp->second.Parsers.size()-1); Temp->second.Parsers[0]->Accept(); } //PAR if (PAR && StreamKind_Last==Stream_Video) Fill(Stream_Video, StreamPos_Last, Video_PixelAspectRatio, PAR); Ztring ID; if (Temp->first!=(int32u)-1) ID.From_Number(((Temp->first>>24)-'0')*10+(((Temp->first>>16)&0xFF)-'0')); //Parser specific if (Temp->second.Parsers.size()==1) { //Finalizing and Merging (except Video codec and 120 fps hack) Temp->second.Parsers[0]->ShouldContinueParsing=false; //Hack - Before Ztring StreamSize, Codec_Temp; if (StreamKind_Last==Stream_Video) Codec_Temp=Retrieve(Stream_Video, StreamPos_Last, Video_Codec); //We want to keep the 4CC of AVI StreamSize=Retrieve(StreamKind_Last, StreamPos_Last, Fill_Parameter(StreamKind_Last, Generic_StreamSize)); //We want to keep the 4CC of AVI //Merging if (Config->ParseSpeed<=1.0) { Fill(Temp->second.Parsers[0]); Temp->second.Parsers[0]->Open_Buffer_Unsynch(); } Finish(Temp->second.Parsers[0]); if (!Temp->second.Parsers.empty() && Temp->second.Parsers[0]->Count_Get(StreamKind_Last)) { //Special case: Compressed audio hidden in PCM if (StreamKind_Last==Stream_Audio && Temp->second.Compression==1 && Retrieve(Stream_General, 0, General_Format)==__T("Wave") && Temp->second.Parsers[0]->Get(Stream_Audio, 0, Audio_Format)!=__T("PCM")) //Some DTS or SMPTE ST 337 streams are coded "1" Clear(Stream_Audio, 0, Audio_Channel_s_); size_t StreamPos_Base=StreamPos_Last; if (StreamKind_Last==Stream_Audio && (Temp->second.Parsers[0]->Count_Get(Stream_Audio)>1 || (!Temp->second.Parsers[0]->Get(Stream_Audio, 0, Audio_MuxingMode).empty() && Temp->second.Parsers[0]->Get(Stream_Audio, 0, Audio_MuxingMode)!=__T("ADTS")))) { //Content from underlying format is preffered Clear(Stream_Audio, StreamPos_Last, Audio_Channel_s_); Fill(Stream_Audio, StreamPos_Last, Audio_BitRate_Encoded, Retrieve(Stream_Audio, StreamPos_Last, Audio_BitRate), true); Clear(Stream_Audio, StreamPos_Last, Audio_BitRate); Clear(Stream_Audio, StreamPos_Last, Audio_SamplingRate); Fill(Stream_Audio, StreamPos_Last, Audio_StreamSize_Encoded, Retrieve(Stream_Audio, StreamPos_Last, Audio_StreamSize), true); Clear(Stream_Audio, StreamPos_Last, Audio_StreamSize); } for (size_t Pos=0; Possecond.Parsers[0]->Count_Get(StreamKind_Last); Pos++) { Ztring Temp_ID=ID; Merge(*Temp->second.Parsers[0], StreamKind_Last, Pos, StreamPos_Base+Pos); if (!Retrieve(StreamKind_Last, StreamPos_Last, General_ID).empty()) { if (!Temp_ID.empty()) Temp_ID+=__T('-'); Temp_ID+=Retrieve(StreamKind_Last, StreamPos_Last, General_ID); } Fill(StreamKind_Last, StreamPos_Last, General_ID, Temp_ID, true); auto Temp_ID_DashPos=Temp_ID.find(__T('-')); if (Temp_ID_DashPos!=string::npos) Temp_ID.resize(Temp_ID_DashPos); Fill(StreamKind_Last, StreamPos_Last, General_StreamOrder, Temp_ID, true); //Special case: multiple fmt/data chunks in WAV if (StreamKind_Last==Stream_Audio //TODO: smarter merge && Temp->second.Compression==1 && Retrieve(Stream_General, 0, General_Format)==__T("Wave") && Temp->second.Parsers[0]->Get(Stream_Audio, 0, Audio_Format)==__T("PCM")) { for (size_t i=0; isecond.Parsers[0], Stream_Audio, i, i); } //Special case - MPEG Video + Captions if (StreamKind_Last==Stream_Video && Temp->second.Parsers[0]->Count_Get(Stream_Text)) { //Video and Text are together size_t Parser_Text_Count=Temp->second.Parsers[0]->Count_Get(Stream_Text); for (size_t Parser_Text_Pos=0; Parser_Text_Possecond.Parsers[0]->Finish(); Merge(*Temp->second.Parsers[0], Stream_Text, Parser_Text_Pos, StreamPos_Last); Fill(Stream_Text, StreamPos_Last, Text_Duration, Retrieve(Stream_Video, StreamPos_Video, Video_Duration)); Ztring ID=Retrieve(Stream_Text, StreamPos_Last, Text_ID); Fill(Stream_Text, StreamPos_Last, Text_ID, Retrieve(Stream_Video, Count_Get(Stream_Video)-1, Video_ID)+__T("-")+ID, true); Fill(Stream_Text, StreamPos_Last, Text_ID_String, Retrieve(Stream_Video, Count_Get(Stream_Video)-1, Video_ID_String)+__T("-")+ID, true); Fill(Stream_Text, StreamPos_Last, Text_Title, Retrieve(Stream_Video, Count_Get(Stream_Video)-1, Video_Title), true); Fill(Stream_Text, StreamPos_Last, "MuxingMode_MoreInfo", __T("Muxed in Video #")+Ztring().From_Number(Count_Get(Stream_Video)), true); } StreamKind_Last=Stream_Video; StreamPos_Last=Count_Get(Stream_Video)-1; } } //Special case - Multiple Audio if (StreamKind_Last==Stream_Audio) { for (size_t Pos=0; Possecond.Parsers[0]->Count_Get(Stream_Audio); Pos++) { if (Retrieve(Stream_Audio, StreamPos_Base+Pos, Audio_CodecID).empty()) Fill(Stream_Audio, StreamPos_Base+Pos, Audio_CodecID, Retrieve(Stream_Audio, StreamPos_Base, Audio_CodecID)); if (Retrieve(Stream_Audio, StreamPos_Base+Pos, Audio_Duration).empty()) Fill(Stream_Audio, StreamPos_Base+Pos, Audio_Duration, Retrieve(Stream_Audio, StreamPos_Base, Audio_Duration)); if (Pos) Fill(Stream_Audio, StreamPos_Base+Pos, Audio_StreamSize_Encoded, 0, 10, true); } } } else { Fill(StreamKind_Last, StreamPos_Last, General_ID, ID, true); Fill(StreamKind_Last, StreamPos_Last, General_StreamOrder, ID, true); } //Hacks - After if (!Temp->second.Parsers.empty() && Temp->second.Parsers[0]->Count_Get(StreamKind_Last)==1) Fill(StreamKind_Last, StreamPos_Last, Fill_Parameter(StreamKind_Last, Retrieve(StreamKind_Last, StreamPos_Last, Fill_Parameter(StreamKind_Last, Generic_StreamSize_Encoded)).empty()?Generic_StreamSize:Generic_StreamSize_Encoded), StreamSize, true); if (StreamKind_Last==Stream_Video) { if (!Codec_Temp.empty()) Fill(Stream_Video, StreamPos_Last, Video_Codec, Codec_Temp, true); //120 fps hack const Ztring &FrameRate=Retrieve(Stream_Video, StreamPos_Last, Video_FrameRate); if (FrameRate.To_int32u()==120) { float32 FrameRateF=FrameRate.To_float32(); Fill(Stream_Video, StreamPos_Last, Video_FrameRate_Minimum, FrameRateF/5, 3, true); Fill(Stream_Video, StreamPos_Last, Video_FrameRate_Maximum, FrameRateF/4, 3, true); Fill(Stream_Video, StreamPos_Last, Video_FrameRate_Mode, "VFR"); } } //Hack - SMPTE ST 337, RIFF channels count is wrong if (StreamKind_Last==Stream_Audio && Retrieve(Stream_Audio, StreamPos_Last, Audio_MuxingMode)==__T("SMPTE ST 337") && Temp->second.Parsers[0]->Get(Stream_Audio, 0, Audio_Channel_s_).empty()) Clear(Stream_Audio, StreamPos_Last, Audio_Channel_s_); //Alignment if (StreamKind_Last==Stream_Audio && Count_Get(Stream_Video)>0) //Only if this is not a WAV file { Fill(Stream_Audio, StreamPos_Last, Audio_Alignment, Temp->second.ChunksAreComplete?"Aligned":"Split"); Fill(Stream_Audio, StreamPos_Last, Audio_Alignment_String, MediaInfoLib::Config.Language_Get(Temp->second.ChunksAreComplete?__T("Alignment_Aligned"):__T("Alignment_Split"))); } //Delay if (StreamKind_Last==Stream_Audio && Count_Get(Stream_Video)==1 && Temp->second.Rate!=0 && Temp->second.Parsers[0]->Status[IsAccepted]) { float Delay=0; bool Delay_IsValid=false; if (Temp->second.Parsers[0]->Buffer_TotalBytes_FirstSynched==0) { Delay=0; Delay_IsValid=true; } else if (Temp->second.Rate!=0) { Delay=((float)Temp->second.Parsers[0]->Buffer_TotalBytes_FirstSynched)*1000/Temp->second.Rate; Delay_IsValid=true; } else if (Temp->second.Parsers[0]->Retrieve(Stream_Audio, 0, Audio_BitRate).To_int64u()!=0) { Delay=((float)Temp->second.Parsers[0]->Buffer_TotalBytes_FirstSynched)*1000/Temp->second.Parsers[0]->Retrieve(Stream_Audio, 0, Audio_BitRate).To_int64u(); Delay_IsValid=true; } else if (Temp->second.Parsers[0]->Retrieve(Stream_Audio, 0, Audio_BitRate_Nominal).To_int64u()!=0) { Delay=((float)Temp->second.Parsers[0]->Buffer_TotalBytes_FirstSynched)*1000/Temp->second.Parsers[0]->Retrieve(Stream_Audio, 0, Audio_BitRate_Nominal).To_int64u(); Delay_IsValid=true; } if (Delay_IsValid) { Delay+=((float)Temp->second.Start)*1000/Temp->second.Rate; Fill(Stream_Audio, StreamPos_Last, Audio_Delay, Delay, 0, true); Fill(Stream_Audio, StreamPos_Last, Audio_Delay_Source, "Stream", Unlimited, true, true); for (size_t StreamPos=0; StreamPossecond.Compression), InfoCodec_KindofCodec).find(__T("DV"))==0 || Retrieve(Stream_Video, StreamPos_Last, Video_Format)==__T("DV") || Retrieve(Stream_Video, StreamPos_Last, Video_Codec)==__T("DV"))) { if (Retrieve(Stream_General, 0, General_Recorded_Date).empty()) Fill(Stream_General, 0, General_Recorded_Date, Temp->second.Parsers[0]->Retrieve(Stream_General, 0, General_Recorded_Date)); //Video and Audio are together size_t Audio_Count=Temp->second.Parsers[0]->Count_Get(Stream_Audio); for (size_t Audio_Pos=0; Audio_Possecond.Parsers[0], Stream_Audio, Audio_Pos, StreamPos_Last); Fill(Stream_Audio, Pos, Audio_MuxingMode, "DV"); Fill(Stream_Audio, Pos, Audio_Duration, Retrieve(Stream_Video, Temp->second.StreamPos, Video_Duration)); Fill(Stream_Audio, Pos, "MuxingMode_MoreInfo", __T("Muxed in Video #")+Ztring().From_Number(Temp->second.StreamPos+1)); Fill(Stream_Audio, Pos, Audio_StreamSize_Encoded, 0); //Included in the DV stream size Ztring ID=Retrieve(Stream_Audio, Pos, Audio_ID); Fill(Stream_Audio, Pos, Audio_ID, Retrieve(Stream_Video, Temp->second.StreamPos, Video_ID)+__T("-")+ID, true); } StreamKind_Last=Stream_Video; StreamPos_Last=Temp->second.StreamPos; } #endif } else if (StreamKind_Last!=Stream_General) Fill(StreamKind_Last, StreamPos_Last, General_ID, ID); //Duration if (Temp->second.PacketCount>0) { if (StreamKind_Last==Stream_Video) // && Retrieve(Stream_Video, StreamPos_Last, Video_Duration).empty()) { //Duration in case it is missing from header (malformed header...) if (Temp->second.indx_Duration && Temp->second.Rate) Fill(Stream_Video, StreamPos_Last, Video_Duration, ((float64)Temp->second.indx_Duration)*1000*Temp->second.Scale/Temp->second.Rate, 0, true); else Fill(Stream_Video, StreamPos_Last, Video_FrameCount, Temp->second.PacketCount, 10, true); } if (StreamKind_Last==Stream_Audio) { //Duration in case it is missing from header (malformed header...) int64u SamplingCount=0; #if defined(MEDIAINFO_MPEGA_YES) if (Retrieve(Stream_Audio, StreamPos_Last, Audio_Format)==__T("MPEG Audio")) { if (Temp->second.Parsers[0] && Temp->second.PacketPos==((File_Mpega*)Temp->second.Parsers[0])->Frame_Count_Valid) //Only for stream with one frame per chunk { Ztring Version=Retrieve(Stream_Audio, StreamPos_Last, Audio_Format_Version); Ztring Layer=Retrieve(Stream_Audio, StreamPos_Last, Audio_Format_Profile); if (Version==__T("Version 1") && Layer==__T("Layer 1")) SamplingCount = (int64u)Temp->second.PacketCount * 384; //MPEG-1 Layer 1 else if ((Version==__T("Version 2") || Version==__T("Version 2.5")) && Layer==__T("Layer 1")) SamplingCount = (int64u)Temp->second.PacketCount * 192; //MPEG-2 or 2.5 Layer 1 else if ((Version==__T("Version 2") || Version==__T("Version 2.5")) && Layer==__T("Layer 3")) SamplingCount = (int64u)Temp->second.PacketCount * 576; //MPEG-2 or 2.5 Layer 3 else SamplingCount = (int64u)Temp->second.PacketCount * 1152; } } #endif if (Retrieve(Stream_Audio, StreamPos_Last, Audio_Format)==__T("PCM")) { int64u Resolution=Retrieve(Stream_Audio, StreamPos_Last, Audio_BitDepth).To_int64u(); int64u Channels=Retrieve(Stream_Audio, StreamPos_Last, Audio_Channel_s_).To_int64u(); if (Resolution>0 && Channels>0) SamplingCount=Temp->second.StreamSize*8/Resolution/Channels; } if (Retrieve(Stream_Audio, StreamPos_Last, Audio_Format)==__T("ADPCM")) { int64u Resolution=Retrieve(Stream_Audio, StreamPos_Last, Audio_BitDepth).To_int64u(); int64u Channels=Retrieve(Stream_Audio, StreamPos_Last, Audio_Channel_s_).To_int64u(); if (Resolution>0 && Channels>0) SamplingCount=(int64u)(Temp->second.StreamSize*8/Resolution/Channels*0.98); //0.98 is not precise! //ADPCM estimation is not precise, if container sampling count is around our value, using it rather than the estimation float32 SamplingRate=Retrieve(Stream_Audio, StreamPos_Last, Audio_SamplingRate).To_float32(); if (SamplingRate>0 && SamplingCount*1000/SamplingRate<((float32)avih_TotalFrame)/avih_FrameRate*1000*1.10 && SamplingCount*1000/SamplingRate>((float32)avih_TotalFrame)/avih_FrameRate*1000*0.10) SamplingCount=0; //Value disabled } //One AC-3 frame is 32 ms //One DTS frame is 21 ms float32 SamplingRate=Retrieve(Stream_Audio, StreamPos_Last, Audio_SamplingRate).To_float32(); if (SamplingCount>0 && SamplingRate>0) Fill(Stream_Audio, StreamPos_Last, Audio_Duration, SamplingCount*1000/SamplingRate, 0, true); else if (Temp->second.indx_Duration && Temp->second.Rate) Fill(Stream_Audio, StreamPos_Last, Audio_Duration, ((float64)Temp->second.indx_Duration)*1000*Temp->second.Scale/Temp->second.Rate, 0, true); else if (Temp->second.Rate && Temp->second.Scale!=1) //Note: some files with Scale==1 are buggy Fill(Stream_Audio, StreamPos_Last, Audio_Duration, ((float64)Temp->second.Length)*1000*Temp->second.Scale/Temp->second.Rate, 0, true); //Interleave if (Stream[0x30300000].PacketCount && Temp->second.PacketCount) { Fill(Stream_Audio, StreamPos_Last, "Interleave_VideoFrames", (float)Stream[0x30300000].PacketCount/Temp->second.PacketCount, 2); if (Retrieve(Stream_Video, 0, Video_FrameRate).To_float32()) { Fill(Stream_Audio, StreamPos_Last, "Interleave_Duration", (float)Stream[0x30300000].PacketCount/Temp->second.PacketCount*1000/Retrieve(Stream_Video, 0, Video_FrameRate).To_float32(), 0); Ztring Interleave_Duration_String; Interleave_Duration_String+=Retrieve(Stream_Audio, StreamPos_Last, "Interleave_Duration"); Interleave_Duration_String+=__T(" "); Interleave_Duration_String+=MediaInfoLib::Config.Language_Get(__T("ms")); if (!Retrieve(Stream_Audio, StreamPos_Last, "Interleave_VideoFrames").empty()) { Interleave_Duration_String+=__T(" ("); Interleave_Duration_String+=MediaInfoLib::Config.Language_Get(Retrieve(Stream_Audio, StreamPos_Last, "Interleave_VideoFrames"), __T(" video frames")); Interleave_Duration_String+=__T(")"); } Fill(Stream_Audio, StreamPos_Last, "Interleave_Duration/String", Interleave_Duration_String); } int64u Audio_FirstBytes=0; for (std::map::iterator Stream_Structure_Temp=Stream_Structure.begin(); Stream_Structure_Temp!=Stream_Structure.end(); ++Stream_Structure_Temp) { if (Stream_Structure_Temp->second.Name==0x30300000) break; if (Stream_Structure_Temp->second.Name==Temp->first) Audio_FirstBytes+=Stream_Structure_Temp->second.Size; } if (Audio_FirstBytes && Temp->second.AvgBytesPerSec) { Fill(Stream_Audio, StreamPos_Last, "Interleave_Preload", Audio_FirstBytes*1000/Temp->second.AvgBytesPerSec); Fill(Stream_Audio, StreamPos_Last, "Interleave_Preload/String", Retrieve(Stream_Audio, StreamPos_Last, "Interleave_Preload")+__T(" ")+MediaInfoLib::Config.Language_Get(__T("ms"))); } } } //Source duration if (Temp->second.PacketCount && Temp->second.Length!=Temp->second.PacketCount) { if (StreamKind_Last==Stream_Video && Temp->second.Rate) Fill(Stream_Video, StreamPos_Last, "Source_Duration", ((float64)Temp->second.PacketCount)*1000*Temp->second.Scale/Temp->second.Rate, 0); if (StreamKind_Last==Stream_Audio && Temp->second.Rate) { float64 Duration_Source=((float64)Temp->second.StreamSize)*1000/Temp->second.AvgBytesPerSec; float64 Duration_Header=Retrieve(Stream_Audio, StreamPos_Last, Audio_Duration).To_float64(); float64 Difference=Duration_Source-Duration_Header; if (Temp->second.Scale!=1 && float64_int64s(Duration_Header/Duration_Source)==Temp->second.Scale) Fill(Stream_Audio, StreamPos_Last, Audio_Duration, Duration_Source, 0, true); //Found 1 stream with Scale not being right else if (Difference<-2 || Difference>2) //+/- 2 ms Fill(Stream_Audio, StreamPos_Last, "Source_Duration", Duration_Source, 0); } } } if (StreamKind_Last==Stream_Audio && Retrieve(Stream_Audio, StreamPos_Last, Audio_Format)==__T("MPEG Audio")) { Ztring Delay = Retrieve(Stream_Audio, StreamPos_Last, Audio_Delay); Ztring Delay_Original = Retrieve(Stream_Audio, StreamPos_Last, Audio_Delay_Original); if (!Delay.empty() && !Delay_Original.empty()) { Fill(Stream_Audio, StreamPos_Last, Audio_Delay, Delay.To_float64()+ Delay_Original.To_float64(), 0, true); Ztring Delay_Source = Retrieve(Stream_Audio, StreamPos_Last, Audio_Delay_Source); Ztring Delay_Original_Source = Retrieve(Stream_Audio, StreamPos_Last, Audio_Delay_Original_Source); Fill(Stream_Audio, StreamPos_Last, Audio_Delay_Source, Delay_Source+__T(" + ")+Delay_Original_Source, true); Clear(Stream_Audio, StreamPos_Last, Audio_Delay_Original); Clear(Stream_Audio, StreamPos_Last, Audio_Delay_Original_Source); } } ++Temp; } //Some work on the first video stream if (Count_Get(Stream_Video)) { //ODML if (dmlh_TotalFrame!=0 && Retrieve(Stream_Video, 0, Video_Duration).empty()) for (size_t StreamPos=0; StreamPosInterleaved1_1) || (Interleaved1_1Interleaved0_1))?"Yes":"No"); //Settings for (size_t i=0; i<2; i++) if (Format_Settings[i]) Fill(Stream_General, 0, General_Format_Settings, Format_Settings_Names[i][Format_Settings[i]-1]); //MD5 size_t Pos=0; for (size_t StreamKind=Stream_General+1; StreamKindDemux_Unpacketize_Get(); Demux_Rate=Config->Demux_Rate_Get(); if (Demux_UnpacketizeContainer && Demux_Rate==0) Demux_Rate=25; //Default value #endif //MEDIAINFO_DEMUX PAR=0; } //--------------------------------------------------------------------------- #if MEDIAINFO_SEEK size_t File_Riff::Read_Buffer_Seek (size_t Method, int64u Value, int64u /*ID*/) { //Only Wave and AIFF switch (Kind) { case Kind_Wave : case Kind_Aiff : break; default : return (size_t)-1; } //Parsing switch (Method) { case 0 : if (ValueBuffer_DataToParse_End) Value=Buffer_DataToParse_End; GoTo(Value); Open_Buffer_Unsynch(); return 1; case 1 : GoTo(Buffer_DataToParse_Begin+(Buffer_DataToParse_End-Buffer_DataToParse_Begin)*Value/10000); Open_Buffer_Unsynch(); return 1; case 2 : //Timestamp { if (AvgBytesPerSec==0) return (size_t)-1; float64 ValueF=(float64)Value; ValueF/=1000000000; //Value is in ns ValueF*=AvgBytesPerSec; GoTo(Buffer_DataToParse_Begin+float64_int64s(ValueF)); return 1; } case 3 : //FrameNumber { if (AvgBytesPerSec==0 || Demux_Rate==0 || BlockAlign==0) return (size_t)-1; float64 BytesPerFrame=AvgBytesPerSec/Demux_Rate; int64u StreamOffset=(int64u)(Value*BytesPerFrame); StreamOffset/=BlockAlign; StreamOffset*=BlockAlign; GoTo(Buffer_DataToParse_Begin+StreamOffset); return 1; } default : return (size_t)-1; //Not supported } } #endif //MEDIAINFO_SEEK //--------------------------------------------------------------------------- void File_Riff::Read_Buffer_Unsynched() { for (std::map::iterator Stream_Item=Stream.begin(); Stream_Item!=Stream.end(); ++Stream_Item) for (size_t Pos=0; Possecond.Parsers.size(); Pos++) Stream_Item->second.Parsers[Pos]->Open_Buffer_Unsynch(); if (IsSub) { while(Element_Level) Element_End0(); #if defined(MEDIAINFO_ANCILLARY_YES) //Ancillary specific if (Ancillary && (*Ancillary)) (*Ancillary)->Open_Buffer_Unsynch(); #endif //defined(MEDIAINFO_ANCILLARY_YES) } } //--------------------------------------------------------------------------- #if MEDIAINFO_DEMUX void File_Riff::Read_Buffer_Continue() { if (Demux_Parser) { Open_Buffer_Continue(Demux_Parser, Buffer+Buffer_Offset, 0, false); if (Config->Demux_EventWasSent) return; Demux_Parser=NULL; } } #endif //MEDIAINFO_DEMUX //*************************************************************************** // Buffer //*************************************************************************** //--------------------------------------------------------------------------- bool File_Riff::Header_Begin() { while (File_Offset+Buffer_OffsetBuffer_DataToParse_End) Element_Size-=BlockAlign; if (Element_Size==0) Element_Size=BlockAlign; if (Buffer_Offset+Element_Size>Buffer_Size) return false; } else #endif //MEDIAINFO_DEMUX if (File_Offset+Buffer_Size<=Buffer_DataToParse_End) { Element_Size=Buffer_Size; //All the buffer is used Alignement_ExtraByte=0; } else { Element_Size=Buffer_DataToParse_End-(File_Offset+Buffer_Offset); //Alignment if (Element_Size%2 && File_Offset+Buffer_Size>=Buffer_DataToParse_End && Buffer_DataToParse_EndBuffer_Size) return false; // Fake header Element_Begin1("...Continued"); //TODO: better method Element_ThisIsAList(); Element_Begin1("...Continued"); Element_ThisIsAList(); if (Buffer_DataToParse_End) { Header_Fill_Code(0x64617461); Header_Fill_Size(Buffer_DataToParse_End-(File_Offset+Buffer_Offset)); if (Buffer_DataToParse_End>File_Size) Buffer_DataToParse_End=File_Size; // Done here for at least one conformance check of the value. TODO: better handling } else Header_Fill_Size(Element_Size); Element_End(); //Alignement specific if (Alignement_ExtraByte && Alignement_ExtraByte<=Element_Size) Element_Size-=Alignement_ExtraByte; switch (Kind) { case Kind_Wave : WAVE_data_Continue(); break; case Kind_Aiff : AIFF_SSND_Continue(); break; case Kind_Rmp3 : RMP3_data_Continue(); break; case Kind_Axml : WAVE_axml_Continue(); break; default : AVI__movi_xxxx(); } //Alignement specific if (Alignement_ExtraByte) { Element_Size+=Alignement_ExtraByte; if (Element_Offset+Alignement_ExtraByte==Element_Size) Skip_XX(Alignement_ExtraByte, "Alignement"); } bool ShouldStop=false; if (Kind!=Kind_Axml && Config->ParseSpeed<1.0 && File_Offset+Buffer_Offset+Element_Offset-Buffer_DataToParse_Begin>=256*1024) { ShouldStop=true; for (std::map::iterator StreamItem=Stream.begin(); StreamItem!=Stream.end(); ++StreamItem) if (StreamItem->second.Parsers.size()>1 || (!StreamItem->second.Parsers.empty() && !StreamItem->second.Parsers[0]->Status[IsFilled])) ShouldStop=false; } if (ShouldStop && Buffer_DataToParse_End) { //Alignment if (Buffer_DataToParse_End%2) Buffer_DataToParse_End++; //Always 2-byte aligned File_GoTo=Buffer_DataToParse_End; Buffer_Offset=Buffer_Size; Element_Size=0; } else { Buffer_Offset+=(size_t)Element_Size; Element_Size-=Element_Offset; } Element_Offset=0; Element_End0(); if (Status[IsFinished] || (File_GoTo!=(int64u)-1 && (File_GoTo<=Buffer_DataToParse_Begin || File_GoTo>=Buffer_DataToParse_End))) { Buffer_DataToParse_Begin=(int64u)-1; Buffer_DataToParse_End=0; return false; } if (Buffer_Offset>=Buffer_Size) return false; #if MEDIAINFO_DEMUX if (Config->Demux_EventWasSent) return false; #endif //MEDIAINFO_DEMUX } return true; } //--------------------------------------------------------------------------- void File_Riff::Header_Parse() { //Special case : W3DI tags (unknown format!) are at the end of the file if (Element_Level==2 && File_Offset+Buffer_Size==File_Size && Buffer_Size>8) { if (CC4(Buffer+Buffer_Size-4)==Elements::W3DI) { int32u Size=LittleEndian2int32u(Buffer+Buffer_Size-8); if (Size>8 && Size<=Buffer_Size && Buffer_Offset+Size==Buffer_Size) { //Filling Header_Fill_Code(Elements::W3DI, "W3DI"); Header_Fill_Size(Size); return; } } } //Special case : SMV file detected if (SMV_BlockSize) { //Filling Header_Fill_Code(Elements::SMV0_xxxx, "SMV Block"); Header_Fill_Size(SMV_BlockSize); return; } //Parsing int32u Size, Name; Get_C4 (Name, "Name"); if (Name==Elements::SMV0) { //SMV specific //Filling Header_Fill_Code(Elements::SMV0, "SMV header"); Header_Fill_Size(51); return; } if (Name==Elements::riff) IsWave64=true; if (IsWave64) { //Wave64 specific int64u Size_Complete; Skip_XX(12, "Name (GUID)"); Get_L8 (Size_Complete, "Size"); //Alignment if (Name!=Elements::riff && Size_Complete%8) { Alignement_ExtraByte=Size_Complete%8; Size_Complete+=Alignement_ExtraByte; //Always 8-byte aligned } else Alignement_ExtraByte=0; //Top level chunks if (Name==Elements::riff) { Get_C4 (Name, "Real Name"); Skip_XX(12, "Real Name (GUID)"); } //Special case: we don't need the full data if (Name==Elements::WAVE_data) { Buffer_DataToParse_Begin=File_Offset+Buffer_Offset; if (Size_Complete) Buffer_DataToParse_End=File_Offset+Buffer_Offset+Size_Complete; else Buffer_DataToParse_End=File_Size; //Found one file with 0 as size of data part Size_Complete=Element_Offset; } //Filling Header_Fill_Code(Name, Ztring().From_CC4(Name)); Header_Fill_Size(Size_Complete); return; } if (Name==Elements::FORM || Name==Elements::MThd) IsBigEndian=true; //Swap from Little to Big Endian for "FORM" files (AIFF...) if (IsBigEndian) Get_B4 (Size, "Size"); else Get_L4 (Size, "Size"); //RF64 int64u Size_Complete=Size; if (Size==0 && Name==Elements::RIFF) Size_Complete=File_Size-8; else if (Size==0xFFFFFFFF) { if (Element_Size<0x1C) { Element_WaitForMoreData(); return; } if (Name==Elements::RF64 && CC4(Buffer+Buffer_Offset+0x0C)==Elements::WAVE_ds64) { Size_Complete=LittleEndian2int64u(Buffer+Buffer_Offset+0x14); Param_Info1(Size_Complete); } else if (Name==Elements::WAVE_data) { Size_Complete=WAVE_data_Size; Param_Info1(Size_Complete); } else if (Element_Level==3) // Only the chunks directly under the main RIFF chunk { for (const chunk_size_64& DS64_Table_Temp : DS64_Table) { if (DS64_Table_Temp.ChunkId==Name) { Size_Complete=DS64_Table_Temp.Size; Param_Info1(Size_Complete); } } } } //Testing malformed (not word aligned) if (!IsNotWordAligned_Tested && !IsBigEndian && Size_Complete %2) { if (File_Offset+Buffer_Offset+8+Size_Complete==File_Size) IsNotWordAligned=true; #if defined(MEDIAINFO_FILE_YES) //TODO: seek if file API is not available else if (!File_Name.empty()) { File F(File_Name); F.GoTo(File_Offset+Buffer_Offset+8+Size); int8u Temp; if (F.Read(&Temp, 1)) { if (!((Temp<'A' || Temp>'z') && Temp!=' ')) IsNotWordAligned=true; } } #endif //defined(MEDIAINFO_FILE_YES) IsNotWordAligned_Tested=true; } //Coherency if (Stream_Structure_Temp!=Stream_Structure.end() && Stream_Structure_Temp->second.Size==0) { Name=(int32u)-1; Size_Complete=0; //Hack in some indexes with Size==0 (why?), ignoring content of header } if (File_Offset+Buffer_Offset+8+Size_Complete>File_Size) { if (Element_Level<=2) //Incoherencies info only at the top level chunk IsTruncated(File_Offset+Buffer_Offset+8+Size_Complete, Element_Offset!=8, Ztring().From_CC4(Name).Trim().To_UTF8().c_str()); } //Alignment if (Size_Complete%2 && !IsNotWordAligned && File_Offset+Buffer_Offset+Element_Offset+Size_Complete=8 && Size_Complete<12) //Not possible (would contain only the name of the RIFF block + the name of the sub-element, no size) { Size_Complete=Element_TotalSize_Get()-8; Fill(Stream_General, 0, "BuggyHeader", Ztring().From_CC4(Name)); } } //Integrity if (Name==0x00000000) { //Filling Header_Fill_Code(0, "Junk"); Header_Fill_Size(File_Size-(File_Offset+Buffer_Offset)); Alignement_ExtraByte=0; return; } //Specific if (Name==Elements::ON2f) Name=Elements::AVI_; //Tests if (Element_Level==2 && Name==Elements::WAVE && !IsRIFF64 && File_Size>0xFFFFFFFF) IsWaveBroken=true; //Non standard big files detection if (IsWaveBroken && (Name==Elements::WAVE || Name==Elements::WAVE_data)) Size_Complete=File_Size-(File_Offset+Buffer_Offset+8); //Non standard big files detection if (movi_Size && Size_Complete>movi_Size/2 && 8+Size_Complete>1024*1024 && !((Name&0xFFFF0000)==0x69780000 || (Name&0x0000FFFF)==0x00006978) && Element_Level==(rec__Present?(size_t)5:(size_t)4) && Buffer_Offset+8+Size_Complete>Buffer_Size) { Buffer_DataToParse_End=File_Offset+Buffer_Offset+8+Size_Complete; Size_Complete=Buffer_Size-(Buffer_Offset+8); } if ((Name==Elements::WAVE_data || Name==Elements::AIFF_SSND || Name==Elements::WAVE_axml)) { int64u End; if (Size_Complete) End=File_Offset+Buffer_Offset+8+Size_Complete; else End=File_Size; //Found one file with 0 as size of data part if (File_Offset+Buffer_SizeFile_Hash_Get().to_ulong()) { GoTo(0); Hash_ParseUpTo=Stream_Structure_Temp->first; } else #endif //MEDIAINFO_HASH GoTo(Stream_Structure_Temp->first); } NeedOldIndex=false; SecondPass=true; Index_Pos.clear(); //We didn't succeed to find theses indexes :( return true; } //--------------------------------------------------------------------------- #if MEDIAINFO_CONFORMANCE string File_Riff::CreateElementName() { string Result; for (size_t i = 1; i < Element_Level; i++) { Result += Ztring().From_CC4(Element[i].Code).Trim().To_UTF8(); if (Result.back() >= '0' && Result.back() <= '9') { Result += '_'; } Result += __T(' '); } if (!Result.empty()) Result.pop_back(); return Result; } #endif //*************************************************************************** // Helpers //*************************************************************************** //--------------------------------------------------------------------------- void File_Riff::TimeCode_Fill(const Ztring &Name, const Ztring &Value) { if (Value.empty()) return; for (size_t StreamPos=0; StreamPos