/**************************************************************************** ** libmatroska : parse Matroska files, see http://www.matroska.org/ ** ** ** ** Copyright (C) 2002-2010 Steve Lhomme. All rights reserved. ** ** This library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public ** License as published by the Free Software Foundation; either ** version 2.1 of the License, or (at your option) any later version. ** ** This library is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with this library; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** ** See http://www.matroska.org/license/lgpl/ for LGPL licensing information.** ** Contact license@matroska.org if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ /*! \file \todo add a PureBlock class to group functionalities between Block and BlockVirtual \version \$Id: KaxBlock.h,v 1.24 2004/04/14 23:26:17 robux4 Exp $ \author Steve Lhomme \author Julien Coloos */ #ifndef LIBMATROSKA_BLOCK_H #define LIBMATROSKA_BLOCK_H #include #include "matroska/KaxTypes.h" #include "ebml/EbmlBinary.h" #include "ebml/EbmlMaster.h" #include "matroska/KaxTracks.h" #include "matroska/KaxDefines.h" using namespace LIBEBML_NAMESPACE; START_LIBMATROSKA_NAMESPACE class KaxCluster; class KaxReferenceBlock; class KaxInternalBlock; class KaxBlockBlob; class MATROSKA_DLL_API DataBuffer { protected: binary * myBuffer; uint32 mySize; bool bValidValue; bool (*myFreeBuffer)(const DataBuffer & aBuffer); // method to free the internal buffer bool bInternalBuffer; public: DataBuffer(binary * aBuffer, uint32 aSize, bool (*aFreeBuffer)(const DataBuffer & aBuffer) = NULL, bool _bInternalBuffer = false) :myBuffer(NULL) ,mySize(aSize) ,bValidValue(true) ,myFreeBuffer(aFreeBuffer) ,bInternalBuffer(_bInternalBuffer) { if (bInternalBuffer) { myBuffer = new binary[mySize]; if (myBuffer == NULL) bValidValue = false; else memcpy(myBuffer, aBuffer, mySize); } else myBuffer = aBuffer; } virtual ~DataBuffer() {} virtual binary * Buffer() {assert(bValidValue); return myBuffer;} virtual uint32 & Size() {return mySize;}; virtual const binary * Buffer() const {assert(bValidValue); return myBuffer;} virtual uint32 Size() const {return mySize;}; bool FreeBuffer(const DataBuffer & aBuffer) { bool bResult = true; if (myBuffer != NULL && bValidValue) { if (myFreeBuffer != NULL) bResult = myFreeBuffer(aBuffer); if (bInternalBuffer) delete [] myBuffer; myBuffer = NULL; mySize = 0; bValidValue = false; } return bResult; } virtual DataBuffer * Clone(); }; class MATROSKA_DLL_API SimpleDataBuffer : public DataBuffer { public: SimpleDataBuffer(binary * aBuffer, uint32 aSize, uint32 aOffset, bool (*aFreeBuffer)(const DataBuffer & aBuffer) = myFreeBuffer) :DataBuffer(aBuffer + aOffset, aSize, aFreeBuffer) ,Offset(aOffset) ,BaseBuffer(aBuffer) {} virtual ~SimpleDataBuffer() {} DataBuffer * Clone() {return new SimpleDataBuffer(*this);} protected: uint32 Offset; binary * BaseBuffer; static bool myFreeBuffer(const DataBuffer & aBuffer) { binary *_Buffer = static_cast(&aBuffer)->BaseBuffer; if (_Buffer != NULL) free(_Buffer); return true; } SimpleDataBuffer(const SimpleDataBuffer & ToClone); }; /*! \note the data is copied locally, it can be freed right away * / class MATROSKA_DLL_API NotSoSimpleDataBuffer : public SimpleDataBuffer { public: NotSoSimpleDataBuffer(binary * aBuffer, uint32 aSize, uint32 aOffset) :SimpleDataBuffer(new binary[aSize - aOffset], aSize, 0) { memcpy(BaseBuffer, aBuffer + aOffset, aSize - aOffset); } }; */ DECLARE_MKX_MASTER(KaxBlockGroup) public: ~KaxBlockGroup(); /*! \brief Addition of a frame without references */ bool AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing = LACING_AUTO); /*! \brief Addition of a frame with a backward reference (P frame) */ bool AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, LacingType lacing = LACING_AUTO); /*! \brief Addition of a frame with a backward+forward reference (B frame) */ bool AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, const KaxBlockGroup & ForwBlock, LacingType lacing = LACING_AUTO); bool AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockBlob * PastBlock, const KaxBlockBlob * ForwBlock, LacingType lacing = LACING_AUTO); void SetParent(KaxCluster & aParentCluster); void SetParentTrack(const KaxTrackEntry & aParentTrack) { ParentTrack = &aParentTrack; } /*! \brief Set the duration of the contained frame(s) (for the total number of frames) */ void SetBlockDuration(uint64 TimeLength); bool GetBlockDuration(uint64 &TheTimecode) const; /*! \return the global timecode of this Block (not just the delta to the Cluster) */ uint64 GlobalTimecode() const; uint64 GlobalTimecodeScale() const { assert(ParentTrack != NULL); return ParentTrack->GlobalTimecodeScale(); } uint16 TrackNumber() const; uint64 ClusterPosition() const; /*! \return the number of references to other frames */ unsigned int ReferenceCount() const; const KaxReferenceBlock & Reference(unsigned int Index) const; /*! \brief release all the frames of all Blocks */ void ReleaseFrames(); operator KaxInternalBlock &(); const KaxCluster *GetParentCluster() const { return ParentCluster; } protected: KaxCluster * ParentCluster; const KaxTrackEntry * ParentTrack; }; class KaxInternalBlock : public EbmlBinary { public: KaxInternalBlock(EBML_DEF_CONS EBML_DEF_SEP bool bSimple EBML_DEF_SEP EBML_EXTRA_PARAM) :EBML_DEF_BINARY_INIT EBML_DEF_SEP bLocalTimecodeUsed(false), mLacing(LACING_AUTO), mInvisible(false) ,ParentCluster(NULL), bIsSimple(bSimple), bIsKeyframe(true), bIsDiscardable(false) {} KaxInternalBlock(const KaxInternalBlock & ElementToClone); ~KaxInternalBlock(); virtual bool ValidateSize() const; uint16 TrackNum() const {return TrackNumber;} /*! \todo !!!! This method needs to be changes ! */ uint64 GlobalTimecode() const {return Timecode;} /*! \note override this function to generate the Data/Size on the fly, unlike the usual binary elements */ filepos_t UpdateSize(bool bSaveDefault = false, bool bForceRender = false); filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA); /*! \brief Only read the head of the Block (not internal data) \note convenient when you are parsing the file quickly */ uint64 ReadInternalHead(IOCallback & input); unsigned int NumberFrames() const { return SizeList.size();} DataBuffer & GetBuffer(unsigned int iIndex) {return *myBuffers[iIndex];} bool AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing = LACING_AUTO, bool invisible = false); /*! \brief release all the frames of all Blocks */ void ReleaseFrames(); void SetParent(KaxCluster & aParentCluster); /*! \return Returns the lacing type that produces the smallest footprint. */ LacingType GetBestLacingType() const; /*! \param FrameNumber 0 for the first frame \return the position in the stream for a given frame \note return -1 if the position doesn't exist */ int64 GetDataPosition(size_t FrameNumber = 0); /*! \param FrameNumber 0 for the first frame \return the size of a given frame \note return -1 if the position doesn't exist */ int64 GetFrameSize(size_t FrameNumber = 0); bool IsInvisible() const { return mInvisible; } uint64 ClusterPosition() const; protected: std::vector myBuffers; std::vector SizeList; uint64 Timecode; // temporary timecode of the first frame, non scaled int16 LocalTimecode; bool bLocalTimecodeUsed; uint16 TrackNumber; LacingType mLacing; bool mInvisible; uint64 FirstFrameLocation; filepos_t RenderData(IOCallback & output, bool bForceRender, bool bSaveDefault = false); KaxCluster * ParentCluster; bool bIsSimple; bool bIsKeyframe; bool bIsDiscardable; }; DECLARE_MKX_CONTEXT(KaxBlock); class MATROSKA_DLL_API KaxBlock : public KaxInternalBlock { public: KaxBlock(EBML_EXTRA_PARAM) :KaxInternalBlock(EBML_DEF_BINARY_CTX(KaxBlock)EBML_DEF_SEP false EBML_DEF_SEP EBML_EXTRA_CALL) {} EBML_CONCRETE_CLASS(KaxBlock) }; #if MATROSKA_VERSION >= 2 DECLARE_MKX_CONTEXT(KaxSimpleBlock); class MATROSKA_DLL_API KaxSimpleBlock : public KaxInternalBlock { public: KaxSimpleBlock(EBML_EXTRA_PARAM) :KaxInternalBlock(EBML_DEF_BINARY_CTX(KaxSimpleBlock)EBML_DEF_SEP true EBML_DEF_SEP EBML_EXTRA_CALL) {} void SetKeyframe(bool b_keyframe) { bIsKeyframe = b_keyframe; } void SetDiscardable(bool b_discard) { bIsDiscardable = b_discard; } bool IsKeyframe() const { return bIsKeyframe; } bool IsDiscardable() const { return bIsDiscardable; } operator KaxInternalBlock &() { return *this; } void SetParent(KaxCluster & aParentCluster); EBML_CONCRETE_CLASS(KaxSimpleBlock) }; #endif // MATROSKA_VERSION /// Placeholder class for either a BlockGroup or a SimpleBlock class MATROSKA_DLL_API KaxBlockBlob { public: KaxBlockBlob(BlockBlobType sblock_mode) :ParentCluster(NULL), SimpleBlockMode(sblock_mode) { bUseSimpleBlock = (sblock_mode != BLOCK_BLOB_NO_SIMPLE); Block.group = NULL; } ~KaxBlockBlob() { #if MATROSKA_VERSION >= 2 if (bUseSimpleBlock) delete Block.simpleblock; else #endif // MATROSKA_VERSION delete Block.group; } operator KaxBlockGroup &(); operator const KaxBlockGroup &() const; #if MATROSKA_VERSION >= 2 operator KaxSimpleBlock &(); #endif operator KaxInternalBlock &(); operator const KaxInternalBlock &() const; void SetBlockGroup( KaxBlockGroup &BlockRef ); void SetBlockDuration(uint64 TimeLength); void SetParent(KaxCluster & aParentCluster); bool AddFrameAuto(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing = LACING_AUTO, const KaxBlockBlob * PastBlock = NULL, const KaxBlockBlob * ForwBlock = NULL); bool IsSimpleBlock() const {return bUseSimpleBlock;} bool ReplaceSimpleByGroup(); protected: KaxCluster * ParentCluster; union { KaxBlockGroup *group; #if MATROSKA_VERSION >= 2 KaxSimpleBlock *simpleblock; #endif // MATROSKA_VERSION } Block; bool bUseSimpleBlock; BlockBlobType SimpleBlockMode; }; #if MATROSKA_VERSION >= 2 DECLARE_MKX_BINARY_CONS(KaxBlockVirtual) public: ~KaxBlockVirtual(); /*! \note override this function to generate the Data/Size on the fly, unlike the usual binary elements */ filepos_t UpdateSize(bool bSaveDefault = false, bool bForceRender = false); void SetParent(const KaxCluster & aParentCluster) {ParentCluster = &aParentCluster;} filepos_t RenderData(IOCallback & output, bool bForceRender, bool bSaveDefault); filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA); protected: uint64 Timecode; // temporary timecode of the first frame if there are more than one uint16 TrackNumber; binary DataBlock[5]; const KaxCluster * ParentCluster; }; #endif // MATROSKA_VERSION END_LIBMATROSKA_NAMESPACE #endif // LIBMATROSKA_BLOCK_H