]> granicus.if.org Git - libmatroska/commitdiff
libmatroska: give access to the SetParent to KaxSimpleBlock as well
authorSteve Lhomme <slhomme@matroska.org>
Thu, 24 Jun 2010 16:21:14 +0000 (16:21 +0000)
committerSteve Lhomme <slhomme@matroska.org>
Thu, 24 Jun 2010 16:21:14 +0000 (16:21 +0000)
git-svn-id: https://matroska.svn.sourceforge.net/svnroot/matroska/trunk/libmatroska@336 a6f86f6d-0131-4f8e-9e7b-e335508773d5

libmatroska.proj
matroska/KaxBlock.h
src/KaxBlock.cpp

index 769c701c51f3a31bc75c46b976077e313639ccaf..559a95e344545a5a3771f9f9d775aa6b8e2c9c4c 100644 (file)
@@ -2,7 +2,7 @@ Include "*/*.proj"
 
 LIB matroska
 {
-  PROJECT_VERSION 1.0.0
+  PROJECT_VERSION 1.1.0
 
   INCLUDE .
   EXPINCLUDE .
index 1c62152de37d8dbb9ea79e73453428aabadcf448..a60a4f288412e36dcac48c7f824804144715046c 100644 (file)
-/****************************************************************************\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
index be00985e5dc2318400bb0a1850ea7ccb9263a4e6..ec8cc3f1c16cf48d6f6afd3d1a50f46f9d5cca70 100644 (file)
-/****************************************************************************\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