-/****************************************************************************\r
-** libmatroska : parse Matroska files, see http://www.matroska.org/\r
-**\r
-** <file/class description>\r
-**\r
-** Copyright (C) 2002-2010 Steve Lhomme. All rights reserved.\r
-**\r
-** This library is free software; you can redistribute it and/or\r
-** modify it under the terms of the GNU Lesser General Public\r
-** License as published by the Free Software Foundation; either\r
-** version 2.1 of the License, or (at your option) any later version.\r
-** \r
-** This library is distributed in the hope that it will be useful,\r
-** but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-** Lesser General Public License for more details.\r
-** \r
-** You should have received a copy of the GNU Lesser General Public\r
-** License along with this library; if not, write to the Free Software\r
-** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-**\r
-** See http://www.matroska.org/license/lgpl/ for LGPL licensing information.**\r
-** Contact license@matroska.org if any conditions of this licensing are\r
-** not clear to you.\r
-**\r
-**********************************************************************/\r
-\r
-/*!\r
- \file\r
- \todo add a PureBlock class to group functionalities between Block and BlockVirtual\r
- \version \$Id: KaxBlock.h,v 1.24 2004/04/14 23:26:17 robux4 Exp $\r
- \author Steve Lhomme <robux4 @ users.sf.net>\r
- \author Julien Coloos <suiryc @ users.sf.net>\r
-*/\r
-#ifndef LIBMATROSKA_BLOCK_H\r
-#define LIBMATROSKA_BLOCK_H\r
-\r
-#include <vector>\r
-\r
-#include "matroska/KaxTypes.h"\r
-#include "ebml/EbmlBinary.h"\r
-#include "ebml/EbmlMaster.h"\r
-#include "matroska/KaxTracks.h"\r
-#include "matroska/KaxDefines.h"\r
-\r
-using namespace LIBEBML_NAMESPACE;\r
-\r
-START_LIBMATROSKA_NAMESPACE\r
-\r
-class KaxCluster;\r
-class KaxReferenceBlock;\r
-class KaxInternalBlock;\r
-class KaxBlockBlob;\r
-\r
-class MATROSKA_DLL_API DataBuffer {\r
- protected:\r
- binary * myBuffer;\r
- uint32 mySize;\r
- bool bValidValue;\r
- bool (*myFreeBuffer)(const DataBuffer & aBuffer); // method to free the internal buffer\r
-\r
- public:\r
- DataBuffer(binary * aBuffer, uint32 aSize, bool (*aFreeBuffer)(const DataBuffer & aBuffer) = NULL)\r
- :myBuffer(aBuffer)\r
- ,mySize(aSize)\r
- ,bValidValue(true) \r
- ,myFreeBuffer(aFreeBuffer)\r
- {}\r
- virtual ~DataBuffer() {}\r
- virtual binary * Buffer() {return myBuffer;}\r
- virtual uint32 & Size() {return mySize;};\r
- virtual const binary * Buffer() const {return myBuffer;}\r
- virtual const uint32 Size() const {return mySize;};\r
- bool FreeBuffer(const DataBuffer & aBuffer) {\r
- bool bResult = true;\r
- if (myBuffer != NULL && myFreeBuffer != NULL && bValidValue) {\r
- bResult = myFreeBuffer(aBuffer);\r
- myBuffer = NULL;\r
- bValidValue = false;\r
- }\r
- return bResult;\r
- }\r
-\r
- virtual DataBuffer * Clone();\r
-};\r
-\r
-class MATROSKA_DLL_API SimpleDataBuffer : public DataBuffer {\r
- public:\r
- SimpleDataBuffer(binary * aBuffer, uint32 aSize, uint32 aOffset, bool (*aFreeBuffer)(const DataBuffer & aBuffer) = myFreeBuffer)\r
- :DataBuffer(aBuffer + aOffset, aSize, aFreeBuffer)\r
- ,Offset(aOffset)\r
- ,BaseBuffer(aBuffer)\r
- {}\r
- virtual ~SimpleDataBuffer() {}\r
-\r
- DataBuffer * Clone() {return new SimpleDataBuffer(*this);}\r
-\r
- protected:\r
- uint32 Offset;\r
- binary * BaseBuffer;\r
-\r
- static bool myFreeBuffer(const DataBuffer & aBuffer)\r
- {\r
- binary *_Buffer = static_cast<const SimpleDataBuffer*>(&aBuffer)->BaseBuffer;\r
- if (_Buffer != NULL)\r
- free(_Buffer);\r
- return true;\r
- }\r
-\r
- SimpleDataBuffer(const SimpleDataBuffer & ToClone);\r
-};\r
-\r
-/*!\r
- \note the data is copied locally, it can be freed right away\r
-* /\r
-class MATROSKA_DLL_API NotSoSimpleDataBuffer : public SimpleDataBuffer {\r
- public:\r
- NotSoSimpleDataBuffer(binary * aBuffer, uint32 aSize, uint32 aOffset)\r
- :SimpleDataBuffer(new binary[aSize - aOffset], aSize, 0)\r
- {\r
- memcpy(BaseBuffer, aBuffer + aOffset, aSize - aOffset);\r
- }\r
-};\r
-*/\r
-\r
-DECLARE_MKX_MASTER(KaxBlockGroup)\r
- public:\r
- ~KaxBlockGroup();\r
-\r
- /*!\r
- \brief Addition of a frame without references\r
- */\r
- bool AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing = LACING_AUTO);\r
- /*!\r
- \brief Addition of a frame with a backward reference (P frame)\r
- */\r
- bool AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, LacingType lacing = LACING_AUTO);\r
-\r
- /*!\r
- \brief Addition of a frame with a backward+forward reference (B frame)\r
- */\r
- bool AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, const KaxBlockGroup & ForwBlock, LacingType lacing = LACING_AUTO);\r
- bool AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockBlob * PastBlock, const KaxBlockBlob * ForwBlock, LacingType lacing = LACING_AUTO);\r
-\r
- void SetParent(KaxCluster & aParentCluster);\r
-\r
- void SetParentTrack(const KaxTrackEntry & aParentTrack) {\r
- ParentTrack = &aParentTrack;\r
- }\r
-\r
- /*!\r
- \brief Set the duration of the contained frame(s) (for the total number of frames)\r
- */\r
- void SetBlockDuration(uint64 TimeLength);\r
- bool GetBlockDuration(uint64 &TheTimecode) const;\r
-\r
- /*!\r
- \return the global timecode of this Block (not just the delta to the Cluster)\r
- */\r
- uint64 GlobalTimecode() const;\r
- uint64 GlobalTimecodeScale() const {\r
- assert(ParentTrack != NULL);\r
- return ParentTrack->GlobalTimecodeScale();\r
- }\r
-\r
- uint16 TrackNumber() const;\r
-\r
- uint64 ClusterPosition() const;\r
- \r
- /*!\r
- \return the number of references to other frames\r
- */\r
- unsigned int ReferenceCount() const;\r
- const KaxReferenceBlock & Reference(unsigned int Index) const;\r
-\r
- /*!\r
- \brief release all the frames of all Blocks\r
- */\r
- void ReleaseFrames();\r
-\r
- operator KaxInternalBlock &();\r
-\r
- const KaxCluster *GetParentCluster() const { return ParentCluster; }\r
-\r
- protected:\r
- KaxCluster * ParentCluster;\r
- const KaxTrackEntry * ParentTrack;\r
-};\r
-\r
-class KaxInternalBlock : public EbmlBinary {\r
- public:\r
- 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)\r
- ,ParentCluster(NULL), bIsSimple(bSimple), bIsKeyframe(true), bIsDiscardable(false)\r
- {}\r
- KaxInternalBlock(const KaxInternalBlock & ElementToClone);\r
- ~KaxInternalBlock();\r
- virtual bool ValidateSize() const;\r
-\r
- uint16 TrackNum() const {return TrackNumber;}\r
- /*!\r
- \todo !!!! This method needs to be changes !\r
- */\r
- uint64 GlobalTimecode() const {return Timecode;}\r
-\r
- /*!\r
- \note override this function to generate the Data/Size on the fly, unlike the usual binary elements\r
- */\r
- filepos_t UpdateSize(bool bSaveDefault = false, bool bForceRender = false);\r
- filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA);\r
- \r
- /*!\r
- \brief Only read the head of the Block (not internal data)\r
- \note convenient when you are parsing the file quickly\r
- */\r
- uint64 ReadInternalHead(IOCallback & input);\r
- \r
- unsigned int NumberFrames() const { return SizeList.size();}\r
- DataBuffer & GetBuffer(unsigned int iIndex) {return *myBuffers[iIndex];}\r
-\r
- bool AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing = LACING_AUTO, bool invisible = false);\r
-\r
- /*!\r
- \brief release all the frames of all Blocks\r
- */\r
- void ReleaseFrames();\r
-\r
- void SetParent(KaxCluster & aParentCluster);\r
-\r
- /*!\r
- \return Returns the lacing type that produces the smallest footprint.\r
- */\r
- LacingType GetBestLacingType() const;\r
-\r
- /*!\r
- \param FrameNumber 0 for the first frame\r
- \return the position in the stream for a given frame\r
- \note return -1 if the position doesn't exist\r
- */\r
- int64 GetDataPosition(size_t FrameNumber = 0);\r
-\r
- /*!\r
- \param FrameNumber 0 for the first frame\r
- \return the size of a given frame\r
- \note return -1 if the position doesn't exist\r
- */\r
- int64 GetFrameSize(size_t FrameNumber = 0);\r
- \r
- bool IsInvisible() const { return mInvisible; }\r
-\r
- uint64 ClusterPosition() const;\r
-\r
- protected:\r
- std::vector<DataBuffer *> myBuffers;\r
- std::vector<int32> SizeList;\r
- uint64 Timecode; // temporary timecode of the first frame, non scaled\r
- int16 LocalTimecode;\r
- bool bLocalTimecodeUsed;\r
- uint16 TrackNumber;\r
- LacingType mLacing;\r
- bool mInvisible;\r
- uint64 FirstFrameLocation;\r
-\r
- filepos_t RenderData(IOCallback & output, bool bForceRender, bool bSaveDefault = false);\r
-\r
- KaxCluster * ParentCluster;\r
- bool bIsSimple;\r
- bool bIsKeyframe;\r
- bool bIsDiscardable;\r
-};\r
-\r
-DECLARE_MKX_CONTEXT(KaxBlock);\r
-class MATROSKA_DLL_API KaxBlock : public KaxInternalBlock {\r
- public:\r
- KaxBlock(EBML_EXTRA_PARAM) :KaxInternalBlock(EBML_DEF_BINARY_CTX(KaxBlock)EBML_DEF_SEP false EBML_DEF_SEP EBML_EXTRA_CALL) {}\r
- EBML_CONCRETE_CLASS(KaxBlock)\r
-};\r
-\r
-#if MATROSKA_VERSION >= 2\r
-DECLARE_MKX_CONTEXT(KaxSimpleBlock);\r
-class MATROSKA_DLL_API KaxSimpleBlock : public KaxInternalBlock {\r
- public:\r
- KaxSimpleBlock(EBML_EXTRA_PARAM) :KaxInternalBlock(EBML_DEF_BINARY_CTX(KaxSimpleBlock)EBML_DEF_SEP true EBML_DEF_SEP EBML_EXTRA_CALL) {}\r
-\r
- void SetKeyframe(bool b_keyframe) { bIsKeyframe = b_keyframe; }\r
- void SetDiscardable(bool b_discard) { bIsDiscardable = b_discard; }\r
-\r
- bool IsKeyframe() const { return bIsKeyframe; }\r
- bool IsDiscardable() const { return bIsDiscardable; }\r
-\r
- operator KaxInternalBlock &() { return *this; }\r
- \r
- EBML_CONCRETE_CLASS(KaxSimpleBlock)\r
-};\r
-#endif // MATROSKA_VERSION\r
-\r
-class MATROSKA_DLL_API KaxBlockBlob {\r
-public:\r
- KaxBlockBlob(BlockBlobType sblock_mode) :ParentCluster(NULL), SimpleBlockMode(sblock_mode) {\r
- bUseSimpleBlock = (sblock_mode != BLOCK_BLOB_NO_SIMPLE);\r
- Block.group = NULL;\r
- }\r
-\r
- ~KaxBlockBlob() {\r
-#if MATROSKA_VERSION >= 2\r
- if (bUseSimpleBlock)\r
- delete Block.simpleblock;\r
- else\r
-#endif // MATROSKA_VERSION\r
- delete Block.group;\r
- }\r
-\r
- operator KaxBlockGroup &();\r
- operator const KaxBlockGroup &() const;\r
-#if MATROSKA_VERSION >= 2\r
- operator KaxSimpleBlock &();\r
-#endif\r
- operator KaxInternalBlock &();\r
- operator const KaxInternalBlock &() const;\r
-\r
- void SetBlockGroup( KaxBlockGroup &BlockRef );\r
-\r
- void SetBlockDuration(uint64 TimeLength);\r
-\r
- void SetParent(KaxCluster & aParentCluster);\r
- bool AddFrameAuto(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing = LACING_AUTO, const KaxBlockBlob * PastBlock = NULL, const KaxBlockBlob * ForwBlock = NULL);\r
-\r
- bool IsSimpleBlock() const {return bUseSimpleBlock;}\r
-\r
- bool ReplaceSimpleByGroup();\r
-protected:\r
- KaxCluster * ParentCluster;\r
- union {\r
- KaxBlockGroup *group;\r
-#if MATROSKA_VERSION >= 2\r
- KaxSimpleBlock *simpleblock;\r
-#endif // MATROSKA_VERSION\r
- } Block;\r
- bool bUseSimpleBlock;\r
- BlockBlobType SimpleBlockMode;\r
-};\r
-\r
-DECLARE_MKX_UINTEGER(KaxBlockDuration)\r
-};\r
-\r
-#if MATROSKA_VERSION >= 2\r
-DECLARE_MKX_BINARY_CONS(KaxBlockVirtual)\r
- public:\r
- ~KaxBlockVirtual();\r
-\r
- /*!\r
- \note override this function to generate the Data/Size on the fly, unlike the usual binary elements\r
- */\r
- filepos_t UpdateSize(bool bSaveDefault = false, bool bForceRender = false);\r
-\r
- void SetParent(const KaxCluster & aParentCluster) {ParentCluster = &aParentCluster;}\r
-\r
- protected:\r
- uint64 Timecode; // temporary timecode of the first frame if there are more than one\r
- uint16 TrackNumber;\r
- binary DataBlock[5];\r
-\r
- const KaxCluster * ParentCluster;\r
-};\r
-#endif // MATROSKA_VERSION\r
-\r
-DECLARE_MKX_BINARY(KaxBlockAdditional)\r
-};\r
-\r
-DECLARE_MKX_MASTER(KaxBlockAdditions)\r
-};\r
-\r
-DECLARE_MKX_MASTER(KaxBlockMore)\r
-};\r
-\r
-DECLARE_MKX_UINTEGER(KaxBlockAddID)\r
-};\r
-\r
-DECLARE_MKX_BINARY(KaxCodecState)\r
-};\r
-\r
-END_LIBMATROSKA_NAMESPACE\r
-\r
-#endif // LIBMATROSKA_BLOCK_H\r
+/****************************************************************************
+** libmatroska : parse Matroska files, see http://www.matroska.org/
+**
+** <file/class description>
+**
+** 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 <robux4 @ users.sf.net>
+ \author Julien Coloos <suiryc @ users.sf.net>
+*/
+#ifndef LIBMATROSKA_BLOCK_H
+#define LIBMATROSKA_BLOCK_H
+
+#include <vector>
+
+#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
+
+ public:
+ DataBuffer(binary * aBuffer, uint32 aSize, bool (*aFreeBuffer)(const DataBuffer & aBuffer) = NULL)
+ :myBuffer(aBuffer)
+ ,mySize(aSize)
+ ,bValidValue(true)
+ ,myFreeBuffer(aFreeBuffer)
+ {}
+ virtual ~DataBuffer() {}
+ virtual binary * Buffer() {return myBuffer;}
+ virtual uint32 & Size() {return mySize;};
+ virtual const binary * Buffer() const {return myBuffer;}
+ virtual const uint32 Size() const {return mySize;};
+ bool FreeBuffer(const DataBuffer & aBuffer) {
+ bool bResult = true;
+ if (myBuffer != NULL && myFreeBuffer != NULL && bValidValue) {
+ bResult = myFreeBuffer(aBuffer);
+ myBuffer = NULL;
+ 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<const SimpleDataBuffer*>(&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<DataBuffer *> myBuffers;
+ std::vector<int32> 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
+
+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;
+};
+
+DECLARE_MKX_UINTEGER(KaxBlockDuration)
+};
+
+#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;}
+
+ 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
+
+DECLARE_MKX_BINARY(KaxBlockAdditional)
+};
+
+DECLARE_MKX_MASTER(KaxBlockAdditions)
+};
+
+DECLARE_MKX_MASTER(KaxBlockMore)
+};
+
+DECLARE_MKX_UINTEGER(KaxBlockAddID)
+};
+
+DECLARE_MKX_BINARY(KaxCodecState)
+};
+
+END_LIBMATROSKA_NAMESPACE
+
+#endif // LIBMATROSKA_BLOCK_H
-/****************************************************************************\r
-** libmatroska : parse Matroska files, see http://www.matroska.org/\r
-**\r
-** <file/class description>\r
-**\r
-** Copyright (C) 2002-2010 Steve Lhomme. All rights reserved.\r
-**\r
-** This library is free software; you can redistribute it and/or\r
-** modify it under the terms of the GNU Lesser General Public\r
-** License as published by the Free Software Foundation; either\r
-** version 2.1 of the License, or (at your option) any later version.\r
-** \r
-** This library is distributed in the hope that it will be useful,\r
-** but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-** Lesser General Public License for more details.\r
-** \r
-** You should have received a copy of the GNU Lesser General Public\r
-** License along with this library; if not, write to the Free Software\r
-** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-**\r
-** See http://www.matroska.org/license/lgpl/ for LGPL licensing information.**\r
-** Contact license@matroska.org if any conditions of this licensing are\r
-** not clear to you.\r
-**\r
-**********************************************************************/\r
-\r
-/*!\r
- \file\r
- \version \$Id: KaxBlock.cpp 1265 2007-01-14 17:20:35Z mosu $\r
- \author Steve Lhomme <robux4 @ users.sf.net>\r
- \author Julien Coloos <suiryc @ users.sf.net>\r
-*/\r
-#include <cassert>\r
-\r
-//#include <streams.h>\r
-\r
-#include "matroska/KaxBlock.h"\r
-#include "matroska/KaxContexts.h"\r
-#include "matroska/KaxBlockData.h"\r
-#include "matroska/KaxCluster.h"\r
-#include "matroska/KaxDefines.h"\r
-\r
-START_LIBMATROSKA_NAMESPACE\r
-\r
-DEFINE_START_SEMANTIC(KaxBlockGroup)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxBlock)\r
-#if MATROSKA_VERSION >= 2\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxBlockVirtual)\r
-#endif // MATROSKA_VERSION\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxBlockDuration)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxSlices)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxReferencePriority)\r
-DEFINE_SEMANTIC_ITEM(false, false, KaxReferenceBlock)\r
-#if MATROSKA_VERSION >= 2\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxReferenceVirtual)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxCodecState)\r
-#endif // MATROSKA_VERSION\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxBlockAdditions)\r
-DEFINE_END_SEMANTIC(KaxBlockGroup)\r
-\r
-DEFINE_START_SEMANTIC(KaxBlockAdditions)\r
-DEFINE_SEMANTIC_ITEM(true, false, KaxBlockMore)\r
-DEFINE_END_SEMANTIC(KaxBlockAdditions)\r
-\r
-DEFINE_START_SEMANTIC(KaxBlockMore)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxBlockAddID)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxBlockAdditional)\r
-DEFINE_END_SEMANTIC(KaxBlockMore)\r
-\r
-DEFINE_MKX_MASTER_CONS (KaxBlockGroup, 0xA0, 1, KaxCluster, "BlockGroup");\r
-DEFINE_MKX_BINARY_CONS (KaxBlock, 0xA1, 1, KaxBlockGroup, "Block");\r
-DEFINE_MKX_UINTEGER (KaxBlockDuration, 0x9B, 1, KaxBlockGroup, "BlockDuration");\r
-#if MATROSKA_VERSION >= 2\r
-DEFINE_MKX_BINARY_CONS (KaxSimpleBlock, 0xA3, 1, KaxCluster, "SimpleBlock");\r
-DEFINE_MKX_BINARY_CONS (KaxBlockVirtual, 0xA2, 1, KaxBlockGroup, "BlockVirtual");\r
-DEFINE_MKX_BINARY (KaxCodecState, 0xA4, 1, KaxBlockGroup, "CodecState");\r
-#endif\r
-DEFINE_MKX_MASTER (KaxBlockAdditions, 0x75A1, 2, KaxBlockGroup, "BlockAdditions");\r
-DEFINE_MKX_MASTER (KaxBlockMore, 0xA6, 1, KaxBlockAdditions, "BlockMore");\r
-DEFINE_MKX_UINTEGER_DEF(KaxBlockAddID, 0xEE, 1, KaxBlockMore, "BlockAddID", 1);\r
-DEFINE_MKX_BINARY (KaxBlockAdditional, 0xA5, 1, KaxBlockMore, "BlockAdditional");\r
-\r
-\r
-DataBuffer * DataBuffer::Clone()\r
-{\r
- binary *ClonedData = (binary *)malloc(mySize * sizeof(binary));\r
- assert(ClonedData != NULL);\r
- memcpy(ClonedData, myBuffer ,mySize );\r
-\r
- SimpleDataBuffer * result = new SimpleDataBuffer(ClonedData, mySize, 0);\r
- result->bValidValue = bValidValue;\r
- return result;\r
-}\r
-\r
-SimpleDataBuffer::SimpleDataBuffer(const SimpleDataBuffer & ToClone)\r
- :DataBuffer((binary *)malloc(ToClone.mySize * sizeof(binary)), ToClone.mySize, myFreeBuffer)\r
-{\r
- assert(myBuffer != NULL);\r
- memcpy(myBuffer, ToClone.myBuffer ,mySize );\r
- bValidValue = ToClone.bValidValue;\r
-}\r
-\r
-bool KaxInternalBlock::ValidateSize() const\r
-{\r
- return (GetSize() >= 4); /// for the moment\r
-}\r
-\r
-KaxInternalBlock::~KaxInternalBlock()\r
-{\r
- ReleaseFrames();\r
-}\r
-\r
-KaxInternalBlock::KaxInternalBlock(const KaxInternalBlock & ElementToClone)\r
- :EbmlBinary(ElementToClone)\r
- ,myBuffers(ElementToClone.myBuffers.size())\r
- ,Timecode(ElementToClone.Timecode)\r
- ,LocalTimecode(ElementToClone.LocalTimecode)\r
- ,bLocalTimecodeUsed(ElementToClone.bLocalTimecodeUsed)\r
- ,TrackNumber(ElementToClone.TrackNumber)\r
- ,ParentCluster(ElementToClone.ParentCluster) ///< \todo not exactly\r
-{\r
- // add a clone of the list\r
- std::vector<DataBuffer *>::const_iterator Itr = ElementToClone.myBuffers.begin();\r
- std::vector<DataBuffer *>::iterator myItr = myBuffers.begin();\r
- while (Itr != ElementToClone.myBuffers.end())\r
- {\r
- *myItr = (*Itr)->Clone();\r
- Itr++; myItr++;\r
- }\r
-}\r
-\r
-\r
-KaxBlockGroup::~KaxBlockGroup()\r
-{\r
-//NOTE("KaxBlockGroup::~KaxBlockGroup");\r
-}\r
-\r
-KaxBlockGroup::KaxBlockGroup(EBML_EXTRA_DEF)\r
- :EbmlMaster(EBML_CLASS_SEMCONTEXT(KaxBlockGroup) EBML_DEF_SEP EBML_EXTRA_CALL)\r
- ,ParentCluster(NULL)\r
- ,ParentTrack(NULL)\r
-{}\r
-\r
-/*!\r
- \todo handle flags\r
- \todo hardcoded limit of the number of frames in a lace should be a parameter\r
- \return true if more frames can be added to this Block\r
-*/\r
-bool KaxInternalBlock::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing, bool invisible)\r
-{\r
- SetValueIsSet();\r
- if (myBuffers.size() == 0) {\r
- // first frame\r
- Timecode = timecode;\r
- TrackNumber = track.TrackNumber();\r
- mInvisible = invisible;\r
- mLacing = lacing;\r
- }\r
- myBuffers.push_back(&buffer);\r
-\r
- // we don't allow more than 8 frames in a Block because the overhead improvement is minimal\r
- if (myBuffers.size() >= 8 || lacing == LACING_NONE)\r
- return false;\r
-\r
- if (lacing == LACING_XIPH)\r
- // decide wether a new frame can be added or not\r
- // a frame in a lace is not efficient when the place necessary to code it in a lace is bigger \r
- // than the size of a simple Block. That means more than 6 bytes (4 in struct + 2 for EBML) to code the size\r
- return (buffer.Size() < 6*0xFF);\r
- else\r
- return true;\r
-}\r
-\r
-/*!\r
- \return Returns the lacing type that produces the smallest footprint.\r
-*/\r
-LacingType KaxInternalBlock::GetBestLacingType() const {\r
- int XiphLacingSize, EbmlLacingSize, i;\r
- bool SameSize = true;\r
-\r
- if (myBuffers.size() <= 1)\r
- return LACING_NONE;\r
-\r
- XiphLacingSize = 1; // Number of laces is stored in 1 byte.\r
- EbmlLacingSize = 1;\r
- for (i = 0; i < (int)myBuffers.size() - 1; i++) {\r
- if (myBuffers[i]->Size() != myBuffers[i + 1]->Size())\r
- SameSize = false;\r
- XiphLacingSize += myBuffers[i]->Size() / 255 + 1;\r
- }\r
- EbmlLacingSize += CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize());\r
- for (i = 1; i < (int)myBuffers.size() - 1; i++)\r
- EbmlLacingSize += CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i - 1]->Size()), 0);\r
- if (SameSize)\r
- return LACING_FIXED;\r
- else if (XiphLacingSize < EbmlLacingSize)\r
- return LACING_XIPH;\r
- else\r
- return LACING_EBML;\r
-}\r
-\r
-filepos_t KaxInternalBlock::UpdateSize(bool bSaveDefault, bool bForceRender)\r
-{\r
- LacingType LacingHere;\r
- assert(EbmlBinary::GetBuffer() == NULL); // Data is not used for KaxInternalBlock\r
- assert(TrackNumber < 0x4000); // no more allowed for the moment\r
- unsigned int i;\r
-\r
- // compute the final size of the data\r
- switch (myBuffers.size()) {\r
- case 0:\r
- SetSize_(0);\r
- break;\r
- case 1:\r
- SetSize_(4 + myBuffers[0]->Size());\r
- break;\r
- default:\r
- SetSize_(4 + 1); // 1 for the lacing head\r
- if (mLacing == LACING_AUTO)\r
- LacingHere = GetBestLacingType();\r
- else\r
- LacingHere = mLacing;\r
- switch (LacingHere)\r
- {\r
- case LACING_XIPH:\r
- for (i=0; i<myBuffers.size()-1; i++) {\r
- SetSize_(GetSize() + myBuffers[i]->Size() + (myBuffers[i]->Size() / 0xFF + 1));\r
- }\r
- break;\r
- case LACING_EBML:\r
- SetSize_(GetSize() + myBuffers[0]->Size() + CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize()));\r
- for (i=1; i<myBuffers.size()-1; i++) {\r
- SetSize_(GetSize() + myBuffers[i]->Size() + CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size()), 0));\r
- }\r
- break;\r
- case LACING_FIXED:\r
- for (i=0; i<myBuffers.size()-1; i++) {\r
- SetSize_(GetSize() + myBuffers[i]->Size());\r
- }\r
- break;\r
- default:\r
- assert(0);\r
- }\r
- // Size of the last frame (not in lace)\r
- SetSize_(GetSize() + myBuffers[i]->Size());\r
- break;\r
- }\r
-\r
- if (TrackNumber >= 0x80)\r
- SetSize_(GetSize() + 1); // the size will be coded with one more octet\r
-\r
- return GetSize();\r
-}\r
-\r
-#if MATROSKA_VERSION >= 2\r
-KaxBlockVirtual::KaxBlockVirtual(const KaxBlockVirtual & ElementToClone)\r
- :EbmlBinary(ElementToClone)\r
- ,Timecode(ElementToClone.Timecode)\r
- ,TrackNumber(ElementToClone.TrackNumber)\r
- ,ParentCluster(ElementToClone.ParentCluster) ///< \todo not exactly\r
-{\r
- SetBuffer(DataBlock,sizeof(DataBlock));\r
- SetValueIsSet(false);\r
-}\r
-\r
-KaxBlockVirtual::KaxBlockVirtual(EBML_EXTRA_DEF)\r
-:EBML_DEF_BINARY(KaxBlockVirtual)EBML_DEF_SEP ParentCluster(NULL)\r
-{\r
- SetBuffer(DataBlock,sizeof(DataBlock));\r
- SetValueIsSet(false);\r
-}\r
-\r
-KaxBlockVirtual::~KaxBlockVirtual()\r
-{\r
- if(GetBuffer() == DataBlock)\r
- SetBuffer( NULL, 0 ); \r
-}\r
-\r
-filepos_t KaxBlockVirtual::UpdateSize(bool bSaveDefault, bool bForceRender)\r
-{\r
- assert(TrackNumber < 0x4000);\r
- binary *cursor = EbmlBinary::GetBuffer();\r
- // fill data\r
- if (TrackNumber < 0x80) {\r
- assert(GetSize() >= 4);\r
- *cursor++ = TrackNumber | 0x80; // set the first bit to 1 \r
- } else {\r
- assert(GetSize() >= 5);\r
- *cursor++ = (TrackNumber >> 8) | 0x40; // set the second bit to 1\r
- *cursor++ = TrackNumber & 0xFF;\r
- }\r
-\r
- assert(ParentCluster != NULL);\r
- int16 ActualTimecode = ParentCluster->GetBlockLocalTimecode(Timecode);\r
- big_int16 b16(ActualTimecode);\r
- b16.Fill(cursor);\r
- cursor += 2;\r
-\r
- *cursor++ = 0; // flags\r
-\r
- return GetSize();\r
-}\r
-#endif // MATROSKA_VERSION\r
-\r
-/*!\r
- \todo more optimisation is possible (render the Block head and don't copy the buffer in memory, care should be taken with the allocation of Data)\r
- \todo the actual timecode to write should be retrieved from the Cluster from here\r
-*/\r
-filepos_t KaxInternalBlock::RenderData(IOCallback & output, bool bForceRender, bool bSaveDefault)\r
-{\r
- if (myBuffers.size() == 0) {\r
- return 0;\r
- } else {\r
- assert(TrackNumber < 0x4000);\r
- binary BlockHead[5], *cursor = BlockHead;\r
- unsigned int i;\r
-\r
- if (myBuffers.size() == 1) {\r
- SetSize_(4);\r
- mLacing = LACING_NONE;\r
- } else {\r
- if (mLacing == LACING_NONE)\r
- mLacing = LACING_EBML; // supposedly the best of all\r
- SetSize_(4 + 1); // 1 for the lacing head (number of laced elements)\r
- }\r
- if (TrackNumber > 0x80)\r
- SetSize_(GetSize() + 1);\r
-\r
- // write Block Head\r
- if (TrackNumber < 0x80) {\r
- *cursor++ = TrackNumber | 0x80; // set the first bit to 1 \r
- } else {\r
- *cursor++ = (TrackNumber >> 8) | 0x40; // set the second bit to 1\r
- *cursor++ = TrackNumber & 0xFF;\r
- }\r
-\r
- assert(ParentCluster != NULL);\r
- int16 ActualTimecode = ParentCluster->GetBlockLocalTimecode(Timecode);\r
- big_int16 b16(ActualTimecode);\r
- b16.Fill(cursor);\r
- cursor += 2;\r
-\r
- *cursor = 0; // flags\r
-\r
- if (mLacing == LACING_AUTO) {\r
- mLacing = GetBestLacingType();\r
- }\r
-\r
- // invisible flag\r
- if (mInvisible)\r
- *cursor = 0x08;\r
-\r
- if (bIsSimple) {\r
- if (bIsKeyframe)\r
- *cursor |= 0x80;\r
- if (bIsDiscardable)\r
- *cursor |= 0x01;\r
- }\r
- \r
- // lacing flag\r
- switch (mLacing)\r
- {\r
- case LACING_XIPH:\r
- *cursor++ |= 0x02;\r
- break;\r
- case LACING_EBML:\r
- *cursor++ |= 0x06;\r
- break;\r
- case LACING_FIXED:\r
- *cursor++ |= 0x04;\r
- break;\r
- case LACING_NONE:\r
- break;\r
- default:\r
- assert(0);\r
- }\r
-\r
- output.writeFully(BlockHead, 4 + ((TrackNumber > 0x80) ? 1 : 0));\r
-\r
- binary tmpValue;\r
- switch (mLacing)\r
- {\r
- case LACING_XIPH:\r
- // number of laces\r
- tmpValue = myBuffers.size()-1;\r
- output.writeFully(&tmpValue, 1);\r
-\r
- // set the size of each member in the lace\r
- for (i=0; i<myBuffers.size()-1; i++) {\r
- tmpValue = 0xFF;\r
- uint16 tmpSize = myBuffers[i]->Size();\r
- while (tmpSize >= 0xFF) {\r
- output.writeFully(&tmpValue, 1);\r
- SetSize_(GetSize() + 1);\r
- tmpSize -= 0xFF;\r
- }\r
- tmpValue = binary(tmpSize);\r
- output.writeFully(&tmpValue, 1);\r
- SetSize_(GetSize() + 1);\r
- }\r
- break;\r
- case LACING_EBML:\r
- // number of laces\r
- tmpValue = myBuffers.size()-1;\r
- output.writeFully(&tmpValue, 1);\r
-\r
- {\r
- int64 _Size;\r
- int _CodedSize;\r
- binary _FinalHead[8]; // 64 bits max coded size\r
-\r
- _Size = myBuffers[0]->Size();\r
-\r
- _CodedSize = CodedSizeLength(_Size, 0, IsFiniteSize());\r
-\r
- // first size in the lace is not a signed\r
- CodedValueLength(_Size, _CodedSize, _FinalHead);\r
- output.writeFully(_FinalHead, _CodedSize);\r
- SetSize_(GetSize() + _CodedSize);\r
-\r
- // set the size of each member in the lace\r
- for (i=1; i<myBuffers.size()-1; i++) {\r
- _Size = int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size());\r
- _CodedSize = CodedSizeLengthSigned(_Size, 0);\r
- CodedValueLengthSigned(_Size, _CodedSize, _FinalHead);\r
- output.writeFully(_FinalHead, _CodedSize);\r
- SetSize_(GetSize() + _CodedSize);\r
- }\r
- }\r
- break;\r
- case LACING_FIXED:\r
- // number of laces\r
- tmpValue = myBuffers.size()-1;\r
- output.writeFully(&tmpValue, 1);\r
- break;\r
- case LACING_NONE:\r
- break;\r
- default:\r
- assert(0);\r
- }\r
-\r
- // put the data of each frame\r
- for (i=0; i<myBuffers.size(); i++) {\r
- output.writeFully(myBuffers[i]->Buffer(), myBuffers[i]->Size());\r
- SetSize_(GetSize() + myBuffers[i]->Size());\r
- }\r
- }\r
-\r
- return GetSize();\r
-}\r
-\r
-uint64 KaxInternalBlock::ReadInternalHead(IOCallback & input)\r
-{\r
- binary Buffer[5], *cursor = Buffer;\r
- uint64 Result = input.read(cursor, 4);\r
- if (Result != 4)\r
- return Result;\r
- \r
- // update internal values\r
- TrackNumber = *cursor++;\r
- if ((TrackNumber & 0x80) == 0) {\r
- // there is extra data\r
- if ((TrackNumber & 0x40) == 0) {\r
- // We don't support track numbers that large !\r
- return Result;\r
- }\r
- Result += input.read(&Buffer[4], 1);\r
- TrackNumber = (TrackNumber & 0x3F) << 8;\r
- TrackNumber += *cursor++;\r
- } else {\r
- TrackNumber &= 0x7F;\r
- }\r
-\r
- \r
- big_int16 b16;\r
- b16.Eval(cursor);\r
- assert(ParentCluster != NULL);\r
- Timecode = ParentCluster->GetBlockGlobalTimecode(int16(b16));\r
- bLocalTimecodeUsed = false;\r
- cursor += 2;\r
-\r
- return Result;\r
-}\r
-\r
-/*!\r
- \todo better zero copy handling\r
-*/\r
-filepos_t KaxInternalBlock::ReadData(IOCallback & input, ScopeMode ReadFully)\r
-{\r
- filepos_t Result;\r
-\r
- FirstFrameLocation = input.getFilePointer(); // will be updated accordingly below\r
-\r
- if (ReadFully == SCOPE_ALL_DATA)\r
- {\r
- Result = EbmlBinary::ReadData(input, ReadFully);\r
- binary *cursor = EbmlBinary::GetBuffer();\r
- uint8 BlockHeadSize = 4;\r
-\r
- // update internal values\r
- TrackNumber = *cursor++;\r
- if ((TrackNumber & 0x80) == 0) {\r
- // there is extra data\r
- if ((TrackNumber & 0x40) == 0) {\r
- // We don't support track numbers that large !\r
- return Result;\r
- }\r
- TrackNumber = (TrackNumber & 0x3F) << 8;\r
- TrackNumber += *cursor++;\r
- BlockHeadSize++;\r
- } else {\r
- TrackNumber &= 0x7F;\r
- }\r
-\r
- big_int16 b16;\r
- b16.Eval(cursor);\r
- LocalTimecode = int16(b16);\r
- bLocalTimecodeUsed = true;\r
- cursor += 2;\r
-\r
- if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) {\r
- bIsKeyframe = (*cursor & 0x80) != 0;\r
- bIsDiscardable = (*cursor & 0x01) != 0;\r
- }\r
- mInvisible = (*cursor & 0x08) >> 3;\r
- mLacing = LacingType((*cursor++ & 0x06) >> 1);\r
-\r
- // put all Frames in the list\r
- if (mLacing == LACING_NONE) {\r
- FirstFrameLocation += cursor - EbmlBinary::GetBuffer();\r
- DataBuffer * soloFrame = new DataBuffer(cursor, GetSize() - BlockHeadSize);\r
- myBuffers.push_back(soloFrame);\r
- SizeList.resize(1);\r
- SizeList[0] = GetSize() - BlockHeadSize;\r
- } else {\r
- // read the number of frames in the lace\r
- uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame\r
- uint8 FrameNum = *cursor++; // number of frames in the lace - 1\r
- // read the list of frame sizes\r
- uint8 Index;\r
- int32 FrameSize;\r
- uint32 SizeRead;\r
- uint64 SizeUnknown;\r
-\r
- SizeList.resize(FrameNum + 1);\r
-\r
- switch (mLacing)\r
- {\r
- case LACING_XIPH:\r
- for (Index=0; Index<FrameNum; Index++) {\r
- // get the size of the frame\r
- FrameSize = 0;\r
- do {\r
- FrameSize += uint8(*cursor);\r
- LastBufferSize--;\r
- } while (*cursor++ == 0xFF);\r
- SizeList[Index] = FrameSize;\r
- LastBufferSize -= FrameSize;\r
- }\r
- SizeList[Index] = LastBufferSize;\r
- break;\r
- case LACING_EBML:\r
- SizeRead = LastBufferSize;\r
- FrameSize = ReadCodedSizeValue(cursor, SizeRead, SizeUnknown);\r
- SizeList[0] = FrameSize;\r
- cursor += SizeRead;\r
- LastBufferSize -= FrameSize + SizeRead;\r
-\r
- for (Index=1; Index<FrameNum; Index++) {\r
- // get the size of the frame\r
- SizeRead = LastBufferSize;\r
- FrameSize += ReadCodedSizeSignedValue(cursor, SizeRead, SizeUnknown);\r
- SizeList[Index] = FrameSize;\r
- cursor += SizeRead;\r
- LastBufferSize -= FrameSize + SizeRead;\r
- }\r
- SizeList[Index] = LastBufferSize;\r
- break;\r
- case LACING_FIXED:\r
- for (Index=0; Index<=FrameNum; Index++) {\r
- // get the size of the frame\r
- SizeList[Index] = LastBufferSize / (FrameNum + 1);\r
- }\r
- break;\r
- default: // other lacing not supported\r
- assert(0);\r
- }\r
-\r
- FirstFrameLocation += cursor - EbmlBinary::GetBuffer();\r
-\r
- for (Index=0; Index<=FrameNum; Index++) {\r
- DataBuffer * lacedFrame = new DataBuffer(cursor, SizeList[Index]);\r
- myBuffers.push_back(lacedFrame);\r
- cursor += SizeList[Index];\r
- }\r
- }\r
- SetValueIsSet();\r
- }\r
- else if (ReadFully == SCOPE_PARTIAL_DATA)\r
- {\r
- binary _TempHead[5];\r
- Result = input.read(_TempHead, 5);\r
- binary *cursor = _TempHead;\r
- binary *_tmpBuf;\r
- uint8 BlockHeadSize = 4;\r
-\r
- // update internal values\r
- TrackNumber = *cursor++;\r
- if ((TrackNumber & 0x80) == 0) {\r
- // there is extra data\r
- if ((TrackNumber & 0x40) == 0) {\r
- // We don't support track numbers that large !\r
- return Result;\r
- }\r
- TrackNumber = (TrackNumber & 0x3F) << 8;\r
- TrackNumber += *cursor++;\r
- BlockHeadSize++;\r
- } else {\r
- TrackNumber &= 0x7F;\r
- }\r
-\r
- big_int16 b16;\r
- b16.Eval(cursor);\r
- LocalTimecode = int16(b16);\r
- bLocalTimecodeUsed = true;\r
- cursor += 2;\r
-\r
- if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) {\r
- bIsKeyframe = (*cursor & 0x80) != 0;\r
- bIsDiscardable = (*cursor & 0x01) != 0;\r
- }\r
- mInvisible = (*cursor & 0x08) >> 3;\r
- mLacing = LacingType((*cursor++ & 0x06) >> 1);\r
- if (cursor == &_TempHead[4])\r
- {\r
- _TempHead[0] = _TempHead[4];\r
- } else {\r
- Result += input.read(_TempHead, 1);\r
- }\r
-\r
- FirstFrameLocation += cursor - _TempHead;\r
-\r
- // put all Frames in the list\r
- if (mLacing != LACING_NONE) {\r
- // read the number of frames in the lace\r
- uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame\r
- uint8 FrameNum = _TempHead[0]; // number of frames in the lace - 1\r
- // read the list of frame sizes\r
- uint8 Index;\r
- int32 FrameSize;\r
- uint32 SizeRead;\r
- uint64 SizeUnknown;\r
-\r
- SizeList.resize(FrameNum + 1);\r
-\r
- switch (mLacing)\r
- {\r
- case LACING_XIPH:\r
- for (Index=0; Index<FrameNum; Index++) {\r
- // get the size of the frame\r
- FrameSize = 0;\r
- do {\r
- Result += input.read(_TempHead, 1);\r
- FrameSize += uint8(_TempHead[0]);\r
- LastBufferSize--;\r
-\r
- FirstFrameLocation++;\r
- } while (_TempHead[0] == 0xFF);\r
-\r
- FirstFrameLocation++;\r
- SizeList[Index] = FrameSize;\r
- LastBufferSize -= FrameSize;\r
- }\r
- SizeList[Index] = LastBufferSize;\r
- break;\r
- case LACING_EBML:\r
- SizeRead = LastBufferSize;\r
- cursor = _tmpBuf = new binary[FrameNum*4]; /// \warning assume the mean size will be coded in less than 4 bytes\r
- Result += input.read(cursor, FrameNum*4);\r
- FrameSize = ReadCodedSizeValue(cursor, SizeRead, SizeUnknown);\r
- SizeList[0] = FrameSize;\r
- cursor += SizeRead;\r
- LastBufferSize -= FrameSize + SizeRead;\r
-\r
- for (Index=1; Index<FrameNum; Index++) {\r
- // get the size of the frame\r
- SizeRead = LastBufferSize;\r
- FrameSize += ReadCodedSizeSignedValue(cursor, SizeRead, SizeUnknown);\r
- SizeList[Index] = FrameSize;\r
- cursor += SizeRead;\r
- LastBufferSize -= FrameSize + SizeRead;\r
- }\r
-\r
- FirstFrameLocation += cursor - _tmpBuf;\r
-\r
- SizeList[Index] = LastBufferSize;\r
- delete [] _tmpBuf;\r
- break;\r
- case LACING_FIXED:\r
- for (Index=0; Index<=FrameNum; Index++) {\r
- // get the size of the frame\r
- SizeList[Index] = LastBufferSize / (FrameNum + 1);\r
- }\r
- break;\r
- default: // other lacing not supported\r
- assert(0);\r
- }\r
- } else {\r
- SizeList.resize(1);\r
- SizeList[0] = GetSize() - BlockHeadSize;\r
- }\r
- SetValueIsSet(false);\r
- Result = GetSize();\r
- } else {\r
- SetValueIsSet(false);\r
- Result = GetSize();\r
- }\r
-\r
- return Result;\r
-}\r
-\r
-bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing)\r
-{\r
- KaxBlock & theBlock = GetChild<KaxBlock>(*this);\r
- assert(ParentCluster != NULL);\r
- theBlock.SetParent(*ParentCluster);\r
- ParentTrack = &track;\r
- return theBlock.AddFrame(track, timecode, buffer, lacing);\r
-}\r
-\r
-bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, LacingType lacing)\r
-{\r
-// assert(past_timecode < 0);\r
-\r
- KaxBlock & theBlock = GetChild<KaxBlock>(*this);\r
- assert(ParentCluster != NULL);\r
- theBlock.SetParent(*ParentCluster);\r
- ParentTrack = &track;\r
- bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);\r
-\r
- KaxReferenceBlock & thePastRef = GetChild<KaxReferenceBlock>(*this);\r
- thePastRef.SetReferencedBlock(PastBlock);\r
- thePastRef.SetParentBlock(*this);\r
-\r
- return bRes;\r
-}\r
-\r
-bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, const KaxBlockGroup & ForwBlock, LacingType lacing)\r
-{\r
-// assert(past_timecode < 0);\r
-\r
-// assert(forw_timecode > 0);\r
- \r
- KaxBlock & theBlock = GetChild<KaxBlock>(*this);\r
- assert(ParentCluster != NULL);\r
- theBlock.SetParent(*ParentCluster);\r
- ParentTrack = &track;\r
- bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);\r
-\r
- KaxReferenceBlock & thePastRef = GetChild<KaxReferenceBlock>(*this);\r
- thePastRef.SetReferencedBlock(PastBlock);\r
- thePastRef.SetParentBlock(*this);\r
-\r
- KaxReferenceBlock & theFutureRef = AddNewChild<KaxReferenceBlock>(*this);\r
- theFutureRef.SetReferencedBlock(ForwBlock);\r
- theFutureRef.SetParentBlock(*this);\r
-\r
- return bRes;\r
-}\r
-\r
-bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockBlob * PastBlock, const KaxBlockBlob * ForwBlock, LacingType lacing)\r
-{\r
- KaxBlock & theBlock = GetChild<KaxBlock>(*this);\r
- assert(ParentCluster != NULL);\r
- theBlock.SetParent(*ParentCluster);\r
- ParentTrack = &track;\r
- bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);\r
-\r
- if (PastBlock != NULL)\r
- {\r
- KaxReferenceBlock & thePastRef = GetChild<KaxReferenceBlock>(*this);\r
- thePastRef.SetReferencedBlock(PastBlock);\r
- thePastRef.SetParentBlock(*this);\r
- }\r
-\r
- if (ForwBlock != NULL)\r
- {\r
- KaxReferenceBlock & theFutureRef = AddNewChild<KaxReferenceBlock>(*this);\r
- theFutureRef.SetReferencedBlock(ForwBlock);\r
- theFutureRef.SetParentBlock(*this);\r
- }\r
-\r
- return bRes;\r
-}\r
-\r
-/*!\r
- \todo we may cache the reference to the timecode block\r
-*/\r
-uint64 KaxBlockGroup::GlobalTimecode() const\r
-{\r
- assert(ParentCluster != NULL); // impossible otherwise\r
- KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));\r
- return MyBlock.GlobalTimecode();\r
-\r
-}\r
-\r
-uint16 KaxBlockGroup::TrackNumber() const\r
-{\r
- KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));\r
- return MyBlock.TrackNum();\r
-}\r
-\r
-uint64 KaxBlockGroup::ClusterPosition() const\r
-{\r
- assert(ParentCluster != NULL); // impossible otherwise\r
- return ParentCluster->GetPosition();\r
-}\r
-\r
-uint64 KaxInternalBlock::ClusterPosition() const\r
-{\r
- assert(ParentCluster != NULL); // impossible otherwise\r
- return ParentCluster->GetPosition();\r
-}\r
-\r
-unsigned int KaxBlockGroup::ReferenceCount() const\r
-{\r
- unsigned int Result = 0;\r
- KaxReferenceBlock * MyBlockAdds = static_cast<KaxReferenceBlock *>(FindFirstElt(EBML_INFO(KaxReferenceBlock)));\r
- if (MyBlockAdds != NULL) {\r
- Result++;\r
- while ((MyBlockAdds = static_cast<KaxReferenceBlock *>(FindNextElt(*MyBlockAdds))) != NULL)\r
- {\r
- Result++;\r
- }\r
- }\r
- return Result;\r
-}\r
-\r
-const KaxReferenceBlock & KaxBlockGroup::Reference(unsigned int Index) const\r
-{\r
- KaxReferenceBlock * MyBlockAdds = static_cast<KaxReferenceBlock *>(FindFirstElt(EBML_INFO(KaxReferenceBlock)));\r
- assert(MyBlockAdds != NULL); // call of a non existing reference\r
- \r
- while (Index != 0) {\r
- MyBlockAdds = static_cast<KaxReferenceBlock *>(FindNextElt(*MyBlockAdds));\r
- assert(MyBlockAdds != NULL);\r
- Index--;\r
- }\r
- return *MyBlockAdds;\r
-}\r
-\r
-void KaxBlockGroup::ReleaseFrames()\r
-{\r
- KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));\r
- MyBlock.ReleaseFrames();\r
-}\r
-\r
-void KaxInternalBlock::ReleaseFrames()\r
-{\r
- // free the allocated Frames\r
- int i;\r
- for (i=myBuffers.size()-1; i>=0; i--) {\r
- if (myBuffers[i] != NULL) {\r
- myBuffers[i]->FreeBuffer(*myBuffers[i]);\r
- delete myBuffers[i];\r
- myBuffers[i] = NULL;\r
- }\r
- }\r
-}\r
-\r
-void KaxBlockGroup::SetBlockDuration(uint64 TimeLength)\r
-{\r
- assert(ParentTrack != NULL);\r
- int64 scale = ParentTrack->GlobalTimecodeScale();\r
- KaxBlockDuration & myDuration = *static_cast<KaxBlockDuration *>(FindFirstElt(EBML_INFO(KaxBlockDuration), true));\r
- *(static_cast<EbmlUInteger *>(&myDuration)) = TimeLength / uint64(scale);\r
-}\r
-\r
-bool KaxBlockGroup::GetBlockDuration(uint64 &TheTimecode) const\r
-{\r
- KaxBlockDuration * myDuration = static_cast<KaxBlockDuration *>(FindElt(EBML_INFO(KaxBlockDuration)));\r
- if (myDuration == NULL) {\r
- return false;\r
- }\r
-\r
- assert(ParentTrack != NULL);\r
- TheTimecode = uint64(*myDuration) * ParentTrack->GlobalTimecodeScale();\r
- return true;\r
-}\r
-\r
-KaxBlockGroup::operator KaxInternalBlock &() {\r
- KaxBlock & theBlock = GetChild<KaxBlock>(*this);\r
- return theBlock;\r
-}\r
-\r
-void KaxBlockGroup::SetParent(KaxCluster & aParentCluster) {\r
- ParentCluster = &aParentCluster;\r
- KaxBlock & theBlock = GetChild<KaxBlock>(*this);\r
- theBlock.SetParent( aParentCluster );\r
-}\r
-\r
-void KaxInternalBlock::SetParent(KaxCluster & aParentCluster)\r
-{\r
- ParentCluster = &aParentCluster;\r
- if (bLocalTimecodeUsed) {\r
- Timecode = aParentCluster.GetBlockGlobalTimecode(LocalTimecode);\r
- bLocalTimecodeUsed = false;\r
- }\r
-}\r
-\r
-int64 KaxInternalBlock::GetDataPosition(size_t FrameNumber)\r
-{\r
- int64 _Result = -1;\r
-\r
- if (ValueIsSet() && FrameNumber < SizeList.size())\r
- {\r
- _Result = FirstFrameLocation;\r
- \r
- size_t _Idx = 0;\r
- while(FrameNumber--)\r
- {\r
- _Result += SizeList[_Idx++];\r
- }\r
- }\r
-\r
- return _Result;\r
-}\r
-\r
-int64 KaxInternalBlock::GetFrameSize(size_t FrameNumber)\r
-{\r
- int64 _Result = -1;\r
-\r
- if (/*bValueIsSet &&*/ FrameNumber < SizeList.size())\r
- {\r
- _Result = SizeList[FrameNumber];\r
- }\r
-\r
- return _Result;\r
-}\r
-\r
-KaxBlockBlob::operator KaxBlockGroup &()\r
-{\r
- assert(!bUseSimpleBlock);\r
- assert(Block.group);\r
- return *Block.group;\r
-}\r
-\r
-KaxBlockBlob::operator const KaxBlockGroup &() const\r
-{\r
- assert(!bUseSimpleBlock);\r
- assert(Block.group);\r
- return *Block.group;\r
-}\r
-\r
-KaxBlockBlob::operator KaxInternalBlock &()\r
-{\r
- assert(Block.group);\r
-#if MATROSKA_VERSION >= 2\r
- if (bUseSimpleBlock)\r
- return *Block.simpleblock;\r
- else\r
-#endif\r
- return *Block.group;\r
-}\r
-\r
-KaxBlockBlob::operator const KaxInternalBlock &() const\r
-{\r
- assert(Block.group);\r
-#if MATROSKA_VERSION >= 2\r
- if (bUseSimpleBlock)\r
- return *Block.simpleblock;\r
- else\r
-#endif\r
- return *Block.group;\r
-}\r
-\r
-#if MATROSKA_VERSION >= 2\r
-KaxBlockBlob::operator KaxSimpleBlock &()\r
-{\r
- assert(bUseSimpleBlock);\r
- assert(Block.simpleblock);\r
- return *Block.simpleblock;\r
-}\r
-#endif\r
-\r
-bool KaxBlockBlob::AddFrameAuto(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing, const KaxBlockBlob * PastBlock, const KaxBlockBlob * ForwBlock)\r
-{\r
- bool bResult = false;\r
-#if MATROSKA_VERSION >= 2\r
- if ((SimpleBlockMode == BLOCK_BLOB_ALWAYS_SIMPLE) || (SimpleBlockMode == BLOCK_BLOB_SIMPLE_AUTO && PastBlock == NULL && ForwBlock == NULL)) {\r
- assert(bUseSimpleBlock == true);\r
- if (Block.simpleblock == NULL) {\r
- Block.simpleblock = new KaxSimpleBlock();\r
- Block.simpleblock->SetParent(*ParentCluster);\r
- }\r
-\r
- bResult = Block.simpleblock->AddFrame(track, timecode, buffer, lacing);\r
- if (PastBlock == NULL && ForwBlock == NULL) {\r
- Block.simpleblock->SetKeyframe(true);\r
- Block.simpleblock->SetDiscardable(false);\r
- } else {\r
- Block.simpleblock->SetKeyframe(false);\r
- if ((ForwBlock == NULL || ((const KaxInternalBlock &)*ForwBlock).GlobalTimecode() <= timecode) &&\r
- (PastBlock == NULL || ((const KaxInternalBlock &)*PastBlock).GlobalTimecode() <= timecode))\r
- Block.simpleblock->SetDiscardable(false);\r
- else\r
- Block.simpleblock->SetDiscardable(true);\r
- }\r
- }\r
- else\r
-#endif\r
- {\r
- if (ReplaceSimpleByGroup()) {\r
- bResult = Block.group->AddFrame(track, timecode, buffer, PastBlock, ForwBlock, lacing);\r
- }\r
- }\r
-\r
- return bResult;\r
-}\r
-\r
-void KaxBlockBlob::SetParent(KaxCluster & parent_clust)\r
-{\r
- ParentCluster = &parent_clust;\r
-}\r
-\r
-void KaxBlockBlob::SetBlockDuration(uint64 TimeLength)\r
-{\r
- if (ReplaceSimpleByGroup())\r
- Block.group->SetBlockDuration(TimeLength);\r
-}\r
-\r
-bool KaxBlockBlob::ReplaceSimpleByGroup()\r
-{\r
- if (SimpleBlockMode== BLOCK_BLOB_ALWAYS_SIMPLE)\r
- return false;\r
-\r
- if (!bUseSimpleBlock) {\r
- if (Block.group == NULL) {\r
- Block.group = new KaxBlockGroup();\r
- }\r
- }\r
-#if MATROSKA_VERSION >= 2\r
- else \r
- {\r
-\r
- if (Block.simpleblock != NULL) {\r
- KaxSimpleBlock *old_simpleblock = Block.simpleblock;\r
- Block.group = new KaxBlockGroup();\r
- // _TODO_ : move all the data to the blockgroup\r
- assert(false);\r
- // -> while(frame) AddFrame(myBuffer)\r
- delete old_simpleblock;\r
- } else {\r
- Block.group = new KaxBlockGroup();\r
- }\r
- }\r
-#endif\r
- if (ParentCluster != NULL)\r
- Block.group->SetParent(*ParentCluster);\r
-\r
- bUseSimpleBlock = false;\r
- return true;\r
-}\r
-\r
-void KaxBlockBlob::SetBlockGroup( KaxBlockGroup &BlockRef )\r
-{\r
- assert(!bUseSimpleBlock);\r
- Block.group = &BlockRef;\r
-}\r
-\r
-END_LIBMATROSKA_NAMESPACE\r
+/****************************************************************************
+** libmatroska : parse Matroska files, see http://www.matroska.org/
+**
+** <file/class description>
+**
+** 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
+ \version \$Id: KaxBlock.cpp 1265 2007-01-14 17:20:35Z mosu $
+ \author Steve Lhomme <robux4 @ users.sf.net>
+ \author Julien Coloos <suiryc @ users.sf.net>
+*/
+#include <cassert>
+
+//#include <streams.h>
+
+#include "matroska/KaxBlock.h"
+#include "matroska/KaxContexts.h"
+#include "matroska/KaxBlockData.h"
+#include "matroska/KaxCluster.h"
+#include "matroska/KaxDefines.h"
+
+START_LIBMATROSKA_NAMESPACE
+
+DEFINE_START_SEMANTIC(KaxBlockGroup)
+DEFINE_SEMANTIC_ITEM(true, true, KaxBlock)
+#if MATROSKA_VERSION >= 2
+DEFINE_SEMANTIC_ITEM(false, true, KaxBlockVirtual)
+#endif // MATROSKA_VERSION
+DEFINE_SEMANTIC_ITEM(false, true, KaxBlockDuration)
+DEFINE_SEMANTIC_ITEM(false, true, KaxSlices)
+DEFINE_SEMANTIC_ITEM(true, true, KaxReferencePriority)
+DEFINE_SEMANTIC_ITEM(false, false, KaxReferenceBlock)
+#if MATROSKA_VERSION >= 2
+DEFINE_SEMANTIC_ITEM(false, true, KaxReferenceVirtual)
+DEFINE_SEMANTIC_ITEM(false, true, KaxCodecState)
+#endif // MATROSKA_VERSION
+DEFINE_SEMANTIC_ITEM(false, true, KaxBlockAdditions)
+DEFINE_END_SEMANTIC(KaxBlockGroup)
+
+DEFINE_START_SEMANTIC(KaxBlockAdditions)
+DEFINE_SEMANTIC_ITEM(true, false, KaxBlockMore)
+DEFINE_END_SEMANTIC(KaxBlockAdditions)
+
+DEFINE_START_SEMANTIC(KaxBlockMore)
+DEFINE_SEMANTIC_ITEM(true, true, KaxBlockAddID)
+DEFINE_SEMANTIC_ITEM(true, true, KaxBlockAdditional)
+DEFINE_END_SEMANTIC(KaxBlockMore)
+
+DEFINE_MKX_MASTER_CONS (KaxBlockGroup, 0xA0, 1, KaxCluster, "BlockGroup");
+DEFINE_MKX_BINARY_CONS (KaxBlock, 0xA1, 1, KaxBlockGroup, "Block");
+DEFINE_MKX_UINTEGER (KaxBlockDuration, 0x9B, 1, KaxBlockGroup, "BlockDuration");
+#if MATROSKA_VERSION >= 2
+DEFINE_MKX_BINARY_CONS (KaxSimpleBlock, 0xA3, 1, KaxCluster, "SimpleBlock");
+DEFINE_MKX_BINARY_CONS (KaxBlockVirtual, 0xA2, 1, KaxBlockGroup, "BlockVirtual");
+DEFINE_MKX_BINARY (KaxCodecState, 0xA4, 1, KaxBlockGroup, "CodecState");
+#endif
+DEFINE_MKX_MASTER (KaxBlockAdditions, 0x75A1, 2, KaxBlockGroup, "BlockAdditions");
+DEFINE_MKX_MASTER (KaxBlockMore, 0xA6, 1, KaxBlockAdditions, "BlockMore");
+DEFINE_MKX_UINTEGER_DEF(KaxBlockAddID, 0xEE, 1, KaxBlockMore, "BlockAddID", 1);
+DEFINE_MKX_BINARY (KaxBlockAdditional, 0xA5, 1, KaxBlockMore, "BlockAdditional");
+
+
+DataBuffer * DataBuffer::Clone()
+{
+ binary *ClonedData = (binary *)malloc(mySize * sizeof(binary));
+ assert(ClonedData != NULL);
+ memcpy(ClonedData, myBuffer ,mySize );
+
+ SimpleDataBuffer * result = new SimpleDataBuffer(ClonedData, mySize, 0);
+ result->bValidValue = bValidValue;
+ return result;
+}
+
+SimpleDataBuffer::SimpleDataBuffer(const SimpleDataBuffer & ToClone)
+ :DataBuffer((binary *)malloc(ToClone.mySize * sizeof(binary)), ToClone.mySize, myFreeBuffer)
+{
+ assert(myBuffer != NULL);
+ memcpy(myBuffer, ToClone.myBuffer ,mySize );
+ bValidValue = ToClone.bValidValue;
+}
+
+bool KaxInternalBlock::ValidateSize() const
+{
+ return (GetSize() >= 4); /// for the moment
+}
+
+KaxInternalBlock::~KaxInternalBlock()
+{
+ ReleaseFrames();
+}
+
+KaxInternalBlock::KaxInternalBlock(const KaxInternalBlock & ElementToClone)
+ :EbmlBinary(ElementToClone)
+ ,myBuffers(ElementToClone.myBuffers.size())
+ ,Timecode(ElementToClone.Timecode)
+ ,LocalTimecode(ElementToClone.LocalTimecode)
+ ,bLocalTimecodeUsed(ElementToClone.bLocalTimecodeUsed)
+ ,TrackNumber(ElementToClone.TrackNumber)
+ ,ParentCluster(ElementToClone.ParentCluster) ///< \todo not exactly
+{
+ // add a clone of the list
+ std::vector<DataBuffer *>::const_iterator Itr = ElementToClone.myBuffers.begin();
+ std::vector<DataBuffer *>::iterator myItr = myBuffers.begin();
+ while (Itr != ElementToClone.myBuffers.end())
+ {
+ *myItr = (*Itr)->Clone();
+ Itr++; myItr++;
+ }
+}
+
+
+KaxBlockGroup::~KaxBlockGroup()
+{
+//NOTE("KaxBlockGroup::~KaxBlockGroup");
+}
+
+KaxBlockGroup::KaxBlockGroup(EBML_EXTRA_DEF)
+ :EbmlMaster(EBML_CLASS_SEMCONTEXT(KaxBlockGroup) EBML_DEF_SEP EBML_EXTRA_CALL)
+ ,ParentCluster(NULL)
+ ,ParentTrack(NULL)
+{}
+
+/*!
+ \todo handle flags
+ \todo hardcoded limit of the number of frames in a lace should be a parameter
+ \return true if more frames can be added to this Block
+*/
+bool KaxInternalBlock::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing, bool invisible)
+{
+ SetValueIsSet();
+ if (myBuffers.size() == 0) {
+ // first frame
+ Timecode = timecode;
+ TrackNumber = track.TrackNumber();
+ mInvisible = invisible;
+ mLacing = lacing;
+ }
+ myBuffers.push_back(&buffer);
+
+ // we don't allow more than 8 frames in a Block because the overhead improvement is minimal
+ if (myBuffers.size() >= 8 || lacing == LACING_NONE)
+ return false;
+
+ if (lacing == LACING_XIPH)
+ // decide wether a new frame can be added or not
+ // a frame in a lace is not efficient when the place necessary to code it in a lace is bigger
+ // than the size of a simple Block. That means more than 6 bytes (4 in struct + 2 for EBML) to code the size
+ return (buffer.Size() < 6*0xFF);
+ else
+ return true;
+}
+
+/*!
+ \return Returns the lacing type that produces the smallest footprint.
+*/
+LacingType KaxInternalBlock::GetBestLacingType() const {
+ int XiphLacingSize, EbmlLacingSize, i;
+ bool SameSize = true;
+
+ if (myBuffers.size() <= 1)
+ return LACING_NONE;
+
+ XiphLacingSize = 1; // Number of laces is stored in 1 byte.
+ EbmlLacingSize = 1;
+ for (i = 0; i < (int)myBuffers.size() - 1; i++) {
+ if (myBuffers[i]->Size() != myBuffers[i + 1]->Size())
+ SameSize = false;
+ XiphLacingSize += myBuffers[i]->Size() / 255 + 1;
+ }
+ EbmlLacingSize += CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize());
+ for (i = 1; i < (int)myBuffers.size() - 1; i++)
+ EbmlLacingSize += CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i - 1]->Size()), 0);
+ if (SameSize)
+ return LACING_FIXED;
+ else if (XiphLacingSize < EbmlLacingSize)
+ return LACING_XIPH;
+ else
+ return LACING_EBML;
+}
+
+filepos_t KaxInternalBlock::UpdateSize(bool bSaveDefault, bool bForceRender)
+{
+ LacingType LacingHere;
+ assert(EbmlBinary::GetBuffer() == NULL); // Data is not used for KaxInternalBlock
+ assert(TrackNumber < 0x4000); // no more allowed for the moment
+ unsigned int i;
+
+ // compute the final size of the data
+ switch (myBuffers.size()) {
+ case 0:
+ SetSize_(0);
+ break;
+ case 1:
+ SetSize_(4 + myBuffers[0]->Size());
+ break;
+ default:
+ SetSize_(4 + 1); // 1 for the lacing head
+ if (mLacing == LACING_AUTO)
+ LacingHere = GetBestLacingType();
+ else
+ LacingHere = mLacing;
+ switch (LacingHere)
+ {
+ case LACING_XIPH:
+ for (i=0; i<myBuffers.size()-1; i++) {
+ SetSize_(GetSize() + myBuffers[i]->Size() + (myBuffers[i]->Size() / 0xFF + 1));
+ }
+ break;
+ case LACING_EBML:
+ SetSize_(GetSize() + myBuffers[0]->Size() + CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize()));
+ for (i=1; i<myBuffers.size()-1; i++) {
+ SetSize_(GetSize() + myBuffers[i]->Size() + CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size()), 0));
+ }
+ break;
+ case LACING_FIXED:
+ for (i=0; i<myBuffers.size()-1; i++) {
+ SetSize_(GetSize() + myBuffers[i]->Size());
+ }
+ break;
+ default:
+ assert(0);
+ }
+ // Size of the last frame (not in lace)
+ SetSize_(GetSize() + myBuffers[i]->Size());
+ break;
+ }
+
+ if (TrackNumber >= 0x80)
+ SetSize_(GetSize() + 1); // the size will be coded with one more octet
+
+ return GetSize();
+}
+
+#if MATROSKA_VERSION >= 2
+KaxBlockVirtual::KaxBlockVirtual(const KaxBlockVirtual & ElementToClone)
+ :EbmlBinary(ElementToClone)
+ ,Timecode(ElementToClone.Timecode)
+ ,TrackNumber(ElementToClone.TrackNumber)
+ ,ParentCluster(ElementToClone.ParentCluster) ///< \todo not exactly
+{
+ SetBuffer(DataBlock,sizeof(DataBlock));
+ SetValueIsSet(false);
+}
+
+KaxBlockVirtual::KaxBlockVirtual(EBML_EXTRA_DEF)
+:EBML_DEF_BINARY(KaxBlockVirtual)EBML_DEF_SEP ParentCluster(NULL)
+{
+ SetBuffer(DataBlock,sizeof(DataBlock));
+ SetValueIsSet(false);
+}
+
+KaxBlockVirtual::~KaxBlockVirtual()
+{
+ if(GetBuffer() == DataBlock)
+ SetBuffer( NULL, 0 );
+}
+
+filepos_t KaxBlockVirtual::UpdateSize(bool bSaveDefault, bool bForceRender)
+{
+ assert(TrackNumber < 0x4000);
+ binary *cursor = EbmlBinary::GetBuffer();
+ // fill data
+ if (TrackNumber < 0x80) {
+ assert(GetSize() >= 4);
+ *cursor++ = TrackNumber | 0x80; // set the first bit to 1
+ } else {
+ assert(GetSize() >= 5);
+ *cursor++ = (TrackNumber >> 8) | 0x40; // set the second bit to 1
+ *cursor++ = TrackNumber & 0xFF;
+ }
+
+ assert(ParentCluster != NULL);
+ int16 ActualTimecode = ParentCluster->GetBlockLocalTimecode(Timecode);
+ big_int16 b16(ActualTimecode);
+ b16.Fill(cursor);
+ cursor += 2;
+
+ *cursor++ = 0; // flags
+
+ return GetSize();
+}
+#endif // MATROSKA_VERSION
+
+/*!
+ \todo more optimisation is possible (render the Block head and don't copy the buffer in memory, care should be taken with the allocation of Data)
+ \todo the actual timecode to write should be retrieved from the Cluster from here
+*/
+filepos_t KaxInternalBlock::RenderData(IOCallback & output, bool bForceRender, bool bSaveDefault)
+{
+ if (myBuffers.size() == 0) {
+ return 0;
+ } else {
+ assert(TrackNumber < 0x4000);
+ binary BlockHead[5], *cursor = BlockHead;
+ unsigned int i;
+
+ if (myBuffers.size() == 1) {
+ SetSize_(4);
+ mLacing = LACING_NONE;
+ } else {
+ if (mLacing == LACING_NONE)
+ mLacing = LACING_EBML; // supposedly the best of all
+ SetSize_(4 + 1); // 1 for the lacing head (number of laced elements)
+ }
+ if (TrackNumber > 0x80)
+ SetSize_(GetSize() + 1);
+
+ // write Block Head
+ if (TrackNumber < 0x80) {
+ *cursor++ = TrackNumber | 0x80; // set the first bit to 1
+ } else {
+ *cursor++ = (TrackNumber >> 8) | 0x40; // set the second bit to 1
+ *cursor++ = TrackNumber & 0xFF;
+ }
+
+ assert(ParentCluster != NULL);
+ int16 ActualTimecode = ParentCluster->GetBlockLocalTimecode(Timecode);
+ big_int16 b16(ActualTimecode);
+ b16.Fill(cursor);
+ cursor += 2;
+
+ *cursor = 0; // flags
+
+ if (mLacing == LACING_AUTO) {
+ mLacing = GetBestLacingType();
+ }
+
+ // invisible flag
+ if (mInvisible)
+ *cursor = 0x08;
+
+ if (bIsSimple) {
+ if (bIsKeyframe)
+ *cursor |= 0x80;
+ if (bIsDiscardable)
+ *cursor |= 0x01;
+ }
+
+ // lacing flag
+ switch (mLacing)
+ {
+ case LACING_XIPH:
+ *cursor++ |= 0x02;
+ break;
+ case LACING_EBML:
+ *cursor++ |= 0x06;
+ break;
+ case LACING_FIXED:
+ *cursor++ |= 0x04;
+ break;
+ case LACING_NONE:
+ break;
+ default:
+ assert(0);
+ }
+
+ output.writeFully(BlockHead, 4 + ((TrackNumber > 0x80) ? 1 : 0));
+
+ binary tmpValue;
+ switch (mLacing)
+ {
+ case LACING_XIPH:
+ // number of laces
+ tmpValue = myBuffers.size()-1;
+ output.writeFully(&tmpValue, 1);
+
+ // set the size of each member in the lace
+ for (i=0; i<myBuffers.size()-1; i++) {
+ tmpValue = 0xFF;
+ uint16 tmpSize = myBuffers[i]->Size();
+ while (tmpSize >= 0xFF) {
+ output.writeFully(&tmpValue, 1);
+ SetSize_(GetSize() + 1);
+ tmpSize -= 0xFF;
+ }
+ tmpValue = binary(tmpSize);
+ output.writeFully(&tmpValue, 1);
+ SetSize_(GetSize() + 1);
+ }
+ break;
+ case LACING_EBML:
+ // number of laces
+ tmpValue = myBuffers.size()-1;
+ output.writeFully(&tmpValue, 1);
+
+ {
+ int64 _Size;
+ int _CodedSize;
+ binary _FinalHead[8]; // 64 bits max coded size
+
+ _Size = myBuffers[0]->Size();
+
+ _CodedSize = CodedSizeLength(_Size, 0, IsFiniteSize());
+
+ // first size in the lace is not a signed
+ CodedValueLength(_Size, _CodedSize, _FinalHead);
+ output.writeFully(_FinalHead, _CodedSize);
+ SetSize_(GetSize() + _CodedSize);
+
+ // set the size of each member in the lace
+ for (i=1; i<myBuffers.size()-1; i++) {
+ _Size = int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size());
+ _CodedSize = CodedSizeLengthSigned(_Size, 0);
+ CodedValueLengthSigned(_Size, _CodedSize, _FinalHead);
+ output.writeFully(_FinalHead, _CodedSize);
+ SetSize_(GetSize() + _CodedSize);
+ }
+ }
+ break;
+ case LACING_FIXED:
+ // number of laces
+ tmpValue = myBuffers.size()-1;
+ output.writeFully(&tmpValue, 1);
+ break;
+ case LACING_NONE:
+ break;
+ default:
+ assert(0);
+ }
+
+ // put the data of each frame
+ for (i=0; i<myBuffers.size(); i++) {
+ output.writeFully(myBuffers[i]->Buffer(), myBuffers[i]->Size());
+ SetSize_(GetSize() + myBuffers[i]->Size());
+ }
+ }
+
+ return GetSize();
+}
+
+uint64 KaxInternalBlock::ReadInternalHead(IOCallback & input)
+{
+ binary Buffer[5], *cursor = Buffer;
+ uint64 Result = input.read(cursor, 4);
+ if (Result != 4)
+ return Result;
+
+ // update internal values
+ TrackNumber = *cursor++;
+ if ((TrackNumber & 0x80) == 0) {
+ // there is extra data
+ if ((TrackNumber & 0x40) == 0) {
+ // We don't support track numbers that large !
+ return Result;
+ }
+ Result += input.read(&Buffer[4], 1);
+ TrackNumber = (TrackNumber & 0x3F) << 8;
+ TrackNumber += *cursor++;
+ } else {
+ TrackNumber &= 0x7F;
+ }
+
+
+ big_int16 b16;
+ b16.Eval(cursor);
+ assert(ParentCluster != NULL);
+ Timecode = ParentCluster->GetBlockGlobalTimecode(int16(b16));
+ bLocalTimecodeUsed = false;
+ cursor += 2;
+
+ return Result;
+}
+
+/*!
+ \todo better zero copy handling
+*/
+filepos_t KaxInternalBlock::ReadData(IOCallback & input, ScopeMode ReadFully)
+{
+ filepos_t Result;
+
+ FirstFrameLocation = input.getFilePointer(); // will be updated accordingly below
+
+ if (ReadFully == SCOPE_ALL_DATA)
+ {
+ Result = EbmlBinary::ReadData(input, ReadFully);
+ binary *cursor = EbmlBinary::GetBuffer();
+ uint8 BlockHeadSize = 4;
+
+ // update internal values
+ TrackNumber = *cursor++;
+ if ((TrackNumber & 0x80) == 0) {
+ // there is extra data
+ if ((TrackNumber & 0x40) == 0) {
+ // We don't support track numbers that large !
+ return Result;
+ }
+ TrackNumber = (TrackNumber & 0x3F) << 8;
+ TrackNumber += *cursor++;
+ BlockHeadSize++;
+ } else {
+ TrackNumber &= 0x7F;
+ }
+
+ big_int16 b16;
+ b16.Eval(cursor);
+ LocalTimecode = int16(b16);
+ bLocalTimecodeUsed = true;
+ cursor += 2;
+
+ if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) {
+ bIsKeyframe = (*cursor & 0x80) != 0;
+ bIsDiscardable = (*cursor & 0x01) != 0;
+ }
+ mInvisible = (*cursor & 0x08) >> 3;
+ mLacing = LacingType((*cursor++ & 0x06) >> 1);
+
+ // put all Frames in the list
+ if (mLacing == LACING_NONE) {
+ FirstFrameLocation += cursor - EbmlBinary::GetBuffer();
+ DataBuffer * soloFrame = new DataBuffer(cursor, GetSize() - BlockHeadSize);
+ myBuffers.push_back(soloFrame);
+ SizeList.resize(1);
+ SizeList[0] = GetSize() - BlockHeadSize;
+ } else {
+ // read the number of frames in the lace
+ uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame
+ uint8 FrameNum = *cursor++; // number of frames in the lace - 1
+ // read the list of frame sizes
+ uint8 Index;
+ int32 FrameSize;
+ uint32 SizeRead;
+ uint64 SizeUnknown;
+
+ SizeList.resize(FrameNum + 1);
+
+ switch (mLacing)
+ {
+ case LACING_XIPH:
+ for (Index=0; Index<FrameNum; Index++) {
+ // get the size of the frame
+ FrameSize = 0;
+ do {
+ FrameSize += uint8(*cursor);
+ LastBufferSize--;
+ } while (*cursor++ == 0xFF);
+ SizeList[Index] = FrameSize;
+ LastBufferSize -= FrameSize;
+ }
+ SizeList[Index] = LastBufferSize;
+ break;
+ case LACING_EBML:
+ SizeRead = LastBufferSize;
+ FrameSize = ReadCodedSizeValue(cursor, SizeRead, SizeUnknown);
+ SizeList[0] = FrameSize;
+ cursor += SizeRead;
+ LastBufferSize -= FrameSize + SizeRead;
+
+ for (Index=1; Index<FrameNum; Index++) {
+ // get the size of the frame
+ SizeRead = LastBufferSize;
+ FrameSize += ReadCodedSizeSignedValue(cursor, SizeRead, SizeUnknown);
+ SizeList[Index] = FrameSize;
+ cursor += SizeRead;
+ LastBufferSize -= FrameSize + SizeRead;
+ }
+ SizeList[Index] = LastBufferSize;
+ break;
+ case LACING_FIXED:
+ for (Index=0; Index<=FrameNum; Index++) {
+ // get the size of the frame
+ SizeList[Index] = LastBufferSize / (FrameNum + 1);
+ }
+ break;
+ default: // other lacing not supported
+ assert(0);
+ }
+
+ FirstFrameLocation += cursor - EbmlBinary::GetBuffer();
+
+ for (Index=0; Index<=FrameNum; Index++) {
+ DataBuffer * lacedFrame = new DataBuffer(cursor, SizeList[Index]);
+ myBuffers.push_back(lacedFrame);
+ cursor += SizeList[Index];
+ }
+ }
+ SetValueIsSet();
+ }
+ else if (ReadFully == SCOPE_PARTIAL_DATA)
+ {
+ binary _TempHead[5];
+ Result = input.read(_TempHead, 5);
+ binary *cursor = _TempHead;
+ binary *_tmpBuf;
+ uint8 BlockHeadSize = 4;
+
+ // update internal values
+ TrackNumber = *cursor++;
+ if ((TrackNumber & 0x80) == 0) {
+ // there is extra data
+ if ((TrackNumber & 0x40) == 0) {
+ // We don't support track numbers that large !
+ return Result;
+ }
+ TrackNumber = (TrackNumber & 0x3F) << 8;
+ TrackNumber += *cursor++;
+ BlockHeadSize++;
+ } else {
+ TrackNumber &= 0x7F;
+ }
+
+ big_int16 b16;
+ b16.Eval(cursor);
+ LocalTimecode = int16(b16);
+ bLocalTimecodeUsed = true;
+ cursor += 2;
+
+ if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) {
+ bIsKeyframe = (*cursor & 0x80) != 0;
+ bIsDiscardable = (*cursor & 0x01) != 0;
+ }
+ mInvisible = (*cursor & 0x08) >> 3;
+ mLacing = LacingType((*cursor++ & 0x06) >> 1);
+ if (cursor == &_TempHead[4])
+ {
+ _TempHead[0] = _TempHead[4];
+ } else {
+ Result += input.read(_TempHead, 1);
+ }
+
+ FirstFrameLocation += cursor - _TempHead;
+
+ // put all Frames in the list
+ if (mLacing != LACING_NONE) {
+ // read the number of frames in the lace
+ uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame
+ uint8 FrameNum = _TempHead[0]; // number of frames in the lace - 1
+ // read the list of frame sizes
+ uint8 Index;
+ int32 FrameSize;
+ uint32 SizeRead;
+ uint64 SizeUnknown;
+
+ SizeList.resize(FrameNum + 1);
+
+ switch (mLacing)
+ {
+ case LACING_XIPH:
+ for (Index=0; Index<FrameNum; Index++) {
+ // get the size of the frame
+ FrameSize = 0;
+ do {
+ Result += input.read(_TempHead, 1);
+ FrameSize += uint8(_TempHead[0]);
+ LastBufferSize--;
+
+ FirstFrameLocation++;
+ } while (_TempHead[0] == 0xFF);
+
+ FirstFrameLocation++;
+ SizeList[Index] = FrameSize;
+ LastBufferSize -= FrameSize;
+ }
+ SizeList[Index] = LastBufferSize;
+ break;
+ case LACING_EBML:
+ SizeRead = LastBufferSize;
+ cursor = _tmpBuf = new binary[FrameNum*4]; /// \warning assume the mean size will be coded in less than 4 bytes
+ Result += input.read(cursor, FrameNum*4);
+ FrameSize = ReadCodedSizeValue(cursor, SizeRead, SizeUnknown);
+ SizeList[0] = FrameSize;
+ cursor += SizeRead;
+ LastBufferSize -= FrameSize + SizeRead;
+
+ for (Index=1; Index<FrameNum; Index++) {
+ // get the size of the frame
+ SizeRead = LastBufferSize;
+ FrameSize += ReadCodedSizeSignedValue(cursor, SizeRead, SizeUnknown);
+ SizeList[Index] = FrameSize;
+ cursor += SizeRead;
+ LastBufferSize -= FrameSize + SizeRead;
+ }
+
+ FirstFrameLocation += cursor - _tmpBuf;
+
+ SizeList[Index] = LastBufferSize;
+ delete [] _tmpBuf;
+ break;
+ case LACING_FIXED:
+ for (Index=0; Index<=FrameNum; Index++) {
+ // get the size of the frame
+ SizeList[Index] = LastBufferSize / (FrameNum + 1);
+ }
+ break;
+ default: // other lacing not supported
+ assert(0);
+ }
+ } else {
+ SizeList.resize(1);
+ SizeList[0] = GetSize() - BlockHeadSize;
+ }
+ SetValueIsSet(false);
+ Result = GetSize();
+ } else {
+ SetValueIsSet(false);
+ Result = GetSize();
+ }
+
+ return Result;
+}
+
+bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing)
+{
+ KaxBlock & theBlock = GetChild<KaxBlock>(*this);
+ assert(ParentCluster != NULL);
+ theBlock.SetParent(*ParentCluster);
+ ParentTrack = &track;
+ return theBlock.AddFrame(track, timecode, buffer, lacing);
+}
+
+bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, LacingType lacing)
+{
+// assert(past_timecode < 0);
+
+ KaxBlock & theBlock = GetChild<KaxBlock>(*this);
+ assert(ParentCluster != NULL);
+ theBlock.SetParent(*ParentCluster);
+ ParentTrack = &track;
+ bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);
+
+ KaxReferenceBlock & thePastRef = GetChild<KaxReferenceBlock>(*this);
+ thePastRef.SetReferencedBlock(PastBlock);
+ thePastRef.SetParentBlock(*this);
+
+ return bRes;
+}
+
+bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, const KaxBlockGroup & ForwBlock, LacingType lacing)
+{
+// assert(past_timecode < 0);
+
+// assert(forw_timecode > 0);
+
+ KaxBlock & theBlock = GetChild<KaxBlock>(*this);
+ assert(ParentCluster != NULL);
+ theBlock.SetParent(*ParentCluster);
+ ParentTrack = &track;
+ bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);
+
+ KaxReferenceBlock & thePastRef = GetChild<KaxReferenceBlock>(*this);
+ thePastRef.SetReferencedBlock(PastBlock);
+ thePastRef.SetParentBlock(*this);
+
+ KaxReferenceBlock & theFutureRef = AddNewChild<KaxReferenceBlock>(*this);
+ theFutureRef.SetReferencedBlock(ForwBlock);
+ theFutureRef.SetParentBlock(*this);
+
+ return bRes;
+}
+
+bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockBlob * PastBlock, const KaxBlockBlob * ForwBlock, LacingType lacing)
+{
+ KaxBlock & theBlock = GetChild<KaxBlock>(*this);
+ assert(ParentCluster != NULL);
+ theBlock.SetParent(*ParentCluster);
+ ParentTrack = &track;
+ bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);
+
+ if (PastBlock != NULL)
+ {
+ KaxReferenceBlock & thePastRef = GetChild<KaxReferenceBlock>(*this);
+ thePastRef.SetReferencedBlock(PastBlock);
+ thePastRef.SetParentBlock(*this);
+ }
+
+ if (ForwBlock != NULL)
+ {
+ KaxReferenceBlock & theFutureRef = AddNewChild<KaxReferenceBlock>(*this);
+ theFutureRef.SetReferencedBlock(ForwBlock);
+ theFutureRef.SetParentBlock(*this);
+ }
+
+ return bRes;
+}
+
+/*!
+ \todo we may cache the reference to the timecode block
+*/
+uint64 KaxBlockGroup::GlobalTimecode() const
+{
+ assert(ParentCluster != NULL); // impossible otherwise
+ KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));
+ return MyBlock.GlobalTimecode();
+
+}
+
+uint16 KaxBlockGroup::TrackNumber() const
+{
+ KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));
+ return MyBlock.TrackNum();
+}
+
+uint64 KaxBlockGroup::ClusterPosition() const
+{
+ assert(ParentCluster != NULL); // impossible otherwise
+ return ParentCluster->GetPosition();
+}
+
+uint64 KaxInternalBlock::ClusterPosition() const
+{
+ assert(ParentCluster != NULL); // impossible otherwise
+ return ParentCluster->GetPosition();
+}
+
+unsigned int KaxBlockGroup::ReferenceCount() const
+{
+ unsigned int Result = 0;
+ KaxReferenceBlock * MyBlockAdds = static_cast<KaxReferenceBlock *>(FindFirstElt(EBML_INFO(KaxReferenceBlock)));
+ if (MyBlockAdds != NULL) {
+ Result++;
+ while ((MyBlockAdds = static_cast<KaxReferenceBlock *>(FindNextElt(*MyBlockAdds))) != NULL)
+ {
+ Result++;
+ }
+ }
+ return Result;
+}
+
+const KaxReferenceBlock & KaxBlockGroup::Reference(unsigned int Index) const
+{
+ KaxReferenceBlock * MyBlockAdds = static_cast<KaxReferenceBlock *>(FindFirstElt(EBML_INFO(KaxReferenceBlock)));
+ assert(MyBlockAdds != NULL); // call of a non existing reference
+
+ while (Index != 0) {
+ MyBlockAdds = static_cast<KaxReferenceBlock *>(FindNextElt(*MyBlockAdds));
+ assert(MyBlockAdds != NULL);
+ Index--;
+ }
+ return *MyBlockAdds;
+}
+
+void KaxBlockGroup::ReleaseFrames()
+{
+ KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));
+ MyBlock.ReleaseFrames();
+}
+
+void KaxInternalBlock::ReleaseFrames()
+{
+ // free the allocated Frames
+ int i;
+ for (i=myBuffers.size()-1; i>=0; i--) {
+ if (myBuffers[i] != NULL) {
+ myBuffers[i]->FreeBuffer(*myBuffers[i]);
+ delete myBuffers[i];
+ myBuffers[i] = NULL;
+ }
+ }
+}
+
+void KaxBlockGroup::SetBlockDuration(uint64 TimeLength)
+{
+ assert(ParentTrack != NULL);
+ int64 scale = ParentTrack->GlobalTimecodeScale();
+ KaxBlockDuration & myDuration = *static_cast<KaxBlockDuration *>(FindFirstElt(EBML_INFO(KaxBlockDuration), true));
+ *(static_cast<EbmlUInteger *>(&myDuration)) = TimeLength / uint64(scale);
+}
+
+bool KaxBlockGroup::GetBlockDuration(uint64 &TheTimecode) const
+{
+ KaxBlockDuration * myDuration = static_cast<KaxBlockDuration *>(FindElt(EBML_INFO(KaxBlockDuration)));
+ if (myDuration == NULL) {
+ return false;
+ }
+
+ assert(ParentTrack != NULL);
+ TheTimecode = uint64(*myDuration) * ParentTrack->GlobalTimecodeScale();
+ return true;
+}
+
+KaxBlockGroup::operator KaxInternalBlock &() {
+ KaxBlock & theBlock = GetChild<KaxBlock>(*this);
+ return theBlock;
+}
+
+void KaxBlockGroup::SetParent(KaxCluster & aParentCluster) {
+ ParentCluster = &aParentCluster;
+ KaxBlock & theBlock = GetChild<KaxBlock>(*this);
+ theBlock.SetParent( aParentCluster );
+}
+
+void KaxSimpleBlock::SetParent(KaxCluster & aParentCluster) {
+ KaxInternalBlock::SetParent( aParentCluster );
+}
+
+void KaxInternalBlock::SetParent(KaxCluster & aParentCluster)
+{
+ ParentCluster = &aParentCluster;
+ if (bLocalTimecodeUsed) {
+ Timecode = aParentCluster.GetBlockGlobalTimecode(LocalTimecode);
+ bLocalTimecodeUsed = false;
+ }
+}
+
+int64 KaxInternalBlock::GetDataPosition(size_t FrameNumber)
+{
+ int64 _Result = -1;
+
+ if (ValueIsSet() && FrameNumber < SizeList.size())
+ {
+ _Result = FirstFrameLocation;
+
+ size_t _Idx = 0;
+ while(FrameNumber--)
+ {
+ _Result += SizeList[_Idx++];
+ }
+ }
+
+ return _Result;
+}
+
+int64 KaxInternalBlock::GetFrameSize(size_t FrameNumber)
+{
+ int64 _Result = -1;
+
+ if (/*bValueIsSet &&*/ FrameNumber < SizeList.size())
+ {
+ _Result = SizeList[FrameNumber];
+ }
+
+ return _Result;
+}
+
+KaxBlockBlob::operator KaxBlockGroup &()
+{
+ assert(!bUseSimpleBlock);
+ assert(Block.group);
+ return *Block.group;
+}
+
+KaxBlockBlob::operator const KaxBlockGroup &() const
+{
+ assert(!bUseSimpleBlock);
+ assert(Block.group);
+ return *Block.group;
+}
+
+KaxBlockBlob::operator KaxInternalBlock &()
+{
+ assert(Block.group);
+#if MATROSKA_VERSION >= 2
+ if (bUseSimpleBlock)
+ return *Block.simpleblock;
+ else
+#endif
+ return *Block.group;
+}
+
+KaxBlockBlob::operator const KaxInternalBlock &() const
+{
+ assert(Block.group);
+#if MATROSKA_VERSION >= 2
+ if (bUseSimpleBlock)
+ return *Block.simpleblock;
+ else
+#endif
+ return *Block.group;
+}
+
+#if MATROSKA_VERSION >= 2
+KaxBlockBlob::operator KaxSimpleBlock &()
+{
+ assert(bUseSimpleBlock);
+ assert(Block.simpleblock);
+ return *Block.simpleblock;
+}
+#endif
+
+bool KaxBlockBlob::AddFrameAuto(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing, const KaxBlockBlob * PastBlock, const KaxBlockBlob * ForwBlock)
+{
+ bool bResult = false;
+#if MATROSKA_VERSION >= 2
+ if ((SimpleBlockMode == BLOCK_BLOB_ALWAYS_SIMPLE) || (SimpleBlockMode == BLOCK_BLOB_SIMPLE_AUTO && PastBlock == NULL && ForwBlock == NULL)) {
+ assert(bUseSimpleBlock == true);
+ if (Block.simpleblock == NULL) {
+ Block.simpleblock = new KaxSimpleBlock();
+ Block.simpleblock->SetParent(*ParentCluster);
+ }
+
+ bResult = Block.simpleblock->AddFrame(track, timecode, buffer, lacing);
+ if (PastBlock == NULL && ForwBlock == NULL) {
+ Block.simpleblock->SetKeyframe(true);
+ Block.simpleblock->SetDiscardable(false);
+ } else {
+ Block.simpleblock->SetKeyframe(false);
+ if ((ForwBlock == NULL || ((const KaxInternalBlock &)*ForwBlock).GlobalTimecode() <= timecode) &&
+ (PastBlock == NULL || ((const KaxInternalBlock &)*PastBlock).GlobalTimecode() <= timecode))
+ Block.simpleblock->SetDiscardable(false);
+ else
+ Block.simpleblock->SetDiscardable(true);
+ }
+ }
+ else
+#endif
+ {
+ if (ReplaceSimpleByGroup()) {
+ bResult = Block.group->AddFrame(track, timecode, buffer, PastBlock, ForwBlock, lacing);
+ }
+ }
+
+ return bResult;
+}
+
+void KaxBlockBlob::SetParent(KaxCluster & parent_clust)
+{
+ ParentCluster = &parent_clust;
+}
+
+void KaxBlockBlob::SetBlockDuration(uint64 TimeLength)
+{
+ if (ReplaceSimpleByGroup())
+ Block.group->SetBlockDuration(TimeLength);
+}
+
+bool KaxBlockBlob::ReplaceSimpleByGroup()
+{
+ if (SimpleBlockMode== BLOCK_BLOB_ALWAYS_SIMPLE)
+ return false;
+
+ if (!bUseSimpleBlock) {
+ if (Block.group == NULL) {
+ Block.group = new KaxBlockGroup();
+ }
+ }
+#if MATROSKA_VERSION >= 2
+ else
+ {
+
+ if (Block.simpleblock != NULL) {
+ KaxSimpleBlock *old_simpleblock = Block.simpleblock;
+ Block.group = new KaxBlockGroup();
+ // _TODO_ : move all the data to the blockgroup
+ assert(false);
+ // -> while(frame) AddFrame(myBuffer)
+ delete old_simpleblock;
+ } else {
+ Block.group = new KaxBlockGroup();
+ }
+ }
+#endif
+ if (ParentCluster != NULL)
+ Block.group->SetParent(*ParentCluster);
+
+ bUseSimpleBlock = false;
+ return true;
+}
+
+void KaxBlockBlob::SetBlockGroup( KaxBlockGroup &BlockRef )
+{
+ assert(!bUseSimpleBlock);
+ Block.group = &BlockRef;
+}
+
+END_LIBMATROSKA_NAMESPACE