/* 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_OGG_YES) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Multiple/File_Ogg.h" #include "MediaInfo/Multiple/File_Ogg_SubElement.h" //--------------------------------------------------------------------------- namespace MediaInfoLib { //*************************************************************************** // Constructor/Destructor //*************************************************************************** //--------------------------------------------------------------------------- File_Ogg::File_Ogg() :File__Analyze() { //Configuration MustSynchronize=true; //In SizedBlocks=false; XiphLacing=false; //Temp - Global StreamsToDo=0; Parsing_End=false; //Temp - Stream Chunk_Sizes_Finished=true; packet_type=0; continued=false; eos=false; } //*************************************************************************** // Streams management //*************************************************************************** //--------------------------------------------------------------------------- void File_Ogg::Streams_Fill() { std::map::iterator Stream_Temp=Stream.begin(); while (Stream_Temp!=Stream.end()) { //Filling if (Stream_Temp->second.Parser) { Stream_Temp->second.Parser->Fill(); Merge(*Stream_Temp->second.Parser); Merge(*Stream_Temp->second.Parser, Stream_General, 0, 0); Stream_Temp->second.StreamKind=((File_Ogg_SubElement*)Stream_Temp->second.Parser)->StreamKind; Stream_Temp->second.StreamPos=Count_Get(Stream_Temp->second.StreamKind)-1; if (!SizedBlocks && !XiphLacing) Stream_Temp->second.absolute_granule_position_Resolution=((File_Ogg_SubElement*)Stream_Temp->second.Parser)->absolute_granule_position_Resolution; if (Stream_Temp->second.StreamKind==Stream_Audio && Stream_Temp->second.absolute_granule_position_Resolution==0) Stream_Temp->second.absolute_granule_position_Resolution=Retrieve(Stream_Audio, Stream_Temp->second.StreamPos, Audio_SamplingRate).To_int64u(); if (!IsSub && Stream_Temp->second.absolute_granule_position && Stream_Temp->second.absolute_granule_position_Resolution) { if (Stream_Temp->second.StreamKind==Stream_Audio) Fill(Stream_Temp->second.StreamKind, Stream_Temp->second.StreamPos, Fill_Parameter(Stream_Temp->second.StreamKind, Generic_Duration), float64_int64s(((float64)(Stream_Temp->second.absolute_granule_position))*1000/Stream_Temp->second.absolute_granule_position_Resolution), 10, true); } if (!IsSub) { if (Stream_Temp->second.StreamKind==Stream_Max) { Stream_Temp->second.StreamKind=Stream_General; Stream_Temp->second.StreamPos=0; } Fill(Stream_Temp->second.StreamKind, Stream_Temp->second.StreamPos, General_ID, Stream_Temp->first); Fill(Stream_Temp->second.StreamKind, Stream_Temp->second.StreamPos, General_ID_String, Get_Hex_ID(Stream_Temp->first), true); } } ++Stream_Temp; } Fill(Stream_General, 0, General_Format, "Ogg", Unlimited, true, true); if (Count_Get(Stream_Video)==0 && Count_Get(Stream_Image)==0) Fill(Stream_General, 0, General_InternetMediaType, "audio/ogg", Unlimited, true, true); else Fill(Stream_General, 0, General_InternetMediaType, "video/ogg", Unlimited, true, true); } //--------------------------------------------------------------------------- void File_Ogg::Streams_Finish() { std::map::iterator Stream_Temp=Stream.begin(); while (Stream_Temp!=Stream.end()) { //Filling if (Stream_Temp->second.Parser) { Finish(Stream_Temp->second.Parser); Merge(*Stream_Temp->second.Parser, Stream_Temp->second.StreamKind, 0, Stream_Temp->second.StreamPos); Merge(*Stream_Temp->second.Parser, Stream_General, 0, 0); } ++Stream_Temp; } //No more need if (!File_Name.empty()) //Only if this is not a buffer, with buffer we can have more data Stream.clear(); } //*************************************************************************** // Buffer - File header //*************************************************************************** //--------------------------------------------------------------------------- bool File_Ogg::FileHeader_Begin() { //Must have enough buffer for having header if (Buffer_Size<4) return false; //Must wait for more data //False positives detection: Detect AVI files, or the parser can synchronize with OggS stream in a AVI chunk if (CC4(Buffer)==0x52494646) //"RIFF" { Finish("OGG"); return false; } //All should be OK... return true; } //*************************************************************************** // Buffer - Synchro //*************************************************************************** //--------------------------------------------------------------------------- bool File_Ogg::Synchronize() { //Synchronizing while (Buffer_Offset+4<=Buffer_Size) { while(Buffer_Offset+4<=Buffer_Size && (Buffer[Buffer_Offset ]!=0x4F || Buffer[Buffer_Offset+1]!=0x67 || Buffer[Buffer_Offset+2]!=0x67 || Buffer[Buffer_Offset+3]!=0x53)) //"OggS" { Buffer_Offset+=1+2; while(Buffer_Offset=Buffer_Size || Buffer[Buffer_Offset-1]==0x67) Buffer_Offset--; Buffer_Offset--; } if (Buffer_Offset+4<=Buffer_Size) //Testing if size is coherant { //Retrieving some info if (Buffer_Offset+27>Buffer_Size) return false; //Need more data int8u page_segments=CC1(Buffer+Buffer_Offset+26); if (Buffer_Offset+27+page_segments>Buffer_Size) return false; //Need more data size_t Size=0; for (int8u Pos=0; PosBuffer_Size) return false; //Need more data if (CC4(Buffer+Buffer_Offset+27+page_segments+Size)!=0x4F676753) //"OggS" Buffer_Offset++; else break; } } //Parsing last bytes if needed if (Buffer_Offset+4>Buffer_Size) { if (Buffer_Offset+3==Buffer_Size && CC3(Buffer+Buffer_Offset)!=0x4F6767) //"Ogg" Buffer_Offset++; if (Buffer_Offset+2==Buffer_Size && CC2(Buffer+Buffer_Offset)!=0x4F67) //"Og" Buffer_Offset++; if (Buffer_Offset+1==Buffer_Size && CC1(Buffer+Buffer_Offset)!=0x4F) //"O" Buffer_Offset++; return false; } //Synched is OK return true; } //--------------------------------------------------------------------------- bool File_Ogg::Synched_Test() { //Must have enough buffer for having header if (Buffer_Offset+4>Buffer_Size) return false; //Quick test of synchro if (CC4(Buffer+Buffer_Offset)!=0x4F676753) //"OggS" Synched=false; //We continue return true; } //*************************************************************************** // Buffer - Per element //*************************************************************************** //--------------------------------------------------------------------------- void File_Ogg::Header_Parse() { //Specific case if (SizedBlocks) { int16u Size; Get_B2 (Size, "Size"); Chunk_Sizes.clear(); Chunk_Sizes.push_back(Size); Header_Fill_Size(2+Size); Header_Fill_Code(0, Ztring::ToZtring(0, 16)); return; } if (XiphLacing) { if (Chunk_Sizes.empty()) { int8u CountMinus1; Get_B1 (CountMinus1, "Number of frames minus one"); int64u UsedSize=0; for (size_t Pos=0; PosInAnotherContainer=IsSub; StreamsToDo++; } ((File_Ogg_SubElement*)Stream_Item.Parser)->MultipleStreams=Stream.size()>1; //has no sens for the first init, must check allways //Parsing File_Ogg_SubElement* Parser=(File_Ogg_SubElement*)Stream_Item.Parser; if (Stream_Item.SearchingPayload) //For each chunk for (size_t Chunk_Sizes_Pos=0; Chunk_Sizes_PosFile_Offset!=Parser->File_Size) { int64u Size=Chunk_Sizes[Chunk_Sizes_Pos]; if (Size>Element_Size-Element_Offset) Size=Element_Size-Element_Offset; // Shcunk size is bigger than content size, buggy file Open_Buffer_Continue(Parser, Buffer+Buffer_Offset+(size_t)Element_Offset, Size); } if (Chunk_Sizes_PosFile_GoTo!=(int64u)-1) Chunk_Sizes_Pos=Chunk_Sizes.size(); if (!Status[IsAccepted] && Parser->Status[IsAccepted]) Accept("OGG"); if (Parser->Status[IsFinished] || (Element_Offset==Element_Size && eos)) { StreamsToDo--; Stream_Item.SearchingPayload=false; break; } } else Skip_XX(Element_Size, "Data"); //End of stream if (!Parsing_End && (StreamsToDo==0 || File_Offset+Buffer_Offset+Element_Offset>256*1024)) { if (IsSub) Finish("OGG"); else GoToFromEnd(256*1024, "OGG"); std::map::iterator Stream_Temp=Stream.begin(); if (File_GoTo!=(int64u)-1) while (Stream_Temp!=Stream.end()) { Stream_Temp->second.absolute_granule_position=0; ++Stream_Temp; } Parsing_End=true; } Element_Show(); } } //NameSpace #endif //MEDIAINFO_OGG_YES