]> granicus.if.org Git - libmatroska/commitdiff
use the better constructor for v1 and v2
authorSteve Lhomme <slhomme@matroska.org>
Thu, 8 Apr 2010 16:26:35 +0000 (16:26 +0000)
committerSteve Lhomme <slhomme@matroska.org>
Thu, 8 Apr 2010 16:26:35 +0000 (16:26 +0000)
git-svn-id: https://matroska.svn.sourceforge.net/svnroot/matroska/trunk/libmatroska@90 a6f86f6d-0131-4f8e-9e7b-e335508773d5

src/KaxAttached.cpp
src/KaxAttachments.cpp
src/KaxBlock.cpp
src/KaxCluster.cpp
src/KaxSegment.cpp
src/KaxTracks.cpp

index 48c3ac1dfdc4b99e4b95e8782ade8117abb7930b..c14a25d08c07f80ecaaae8a38e6d66d915d92889 100644 (file)
@@ -1,72 +1,72 @@
-/****************************************************************************\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 file is part of libmatroska.\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: KaxAttached.cpp 1202 2005-08-30 14:39:01Z robux4 $\r
-       \author Steve Lhomme     <robux4 @ users.sf.net>\r
-*/\r
-#include "matroska/KaxAttached.h"\r
-#include "matroska/KaxContexts.h"\r
-#include "matroska/KaxDefines.h"\r
-\r
-// sub elements\r
-\r
-using namespace LIBEBML_NAMESPACE;\r
-\r
-START_LIBMATROSKA_NAMESPACE\r
-\r
-DEFINE_START_SEMANTIC(KaxAttached)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxFileName)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxMimeType)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxFileData)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxFileDescription)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxFileUID)\r
-#if MATROSKA_VERSION >= 2\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxFileReferral)\r
-#endif // MATROSKA_VERSION\r
-DEFINE_END_SEMANTIC(KaxAttached)\r
-\r
-DEFINE_MKX_MASTER_CONS(KaxAttached,        0x61A7, 2, KaxAttachments, "AttachedFile");\r
-DEFINE_MKX_UNISTRING  (KaxFileDescription, 0x467E, 2, KaxAttachments, "FileDescription");\r
-DEFINE_MKX_UNISTRING  (KaxFileName,        0x466E, 2, KaxAttachments, "FileName");\r
-DEFINE_MKX_STRING     (KaxMimeType,        0x4660, 2, KaxAttachments, "FileMimeType");\r
-DEFINE_MKX_BINARY     (KaxFileData,        0x465C, 2, KaxAttachments, "FileData");\r
-DEFINE_MKX_UINTEGER   (KaxFileUID,         0x46AE, 2, KaxAttachments, "FileUID");\r
-#if MATROSKA_VERSION >= 2\r
-DEFINE_MKX_BINARY     (KaxFileReferral,    0x4675, 2, KaxAttachments, "FileReferral");\r
-#endif\r
-\r
-KaxAttached::KaxAttached()\r
- :EbmlMaster(Context_KaxAttached)\r
-{\r
-       SetSizeLength(2); // mandatory min size support (for easier updating) (2^(7*2)-2 = 16Ko)\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 file is part of libmatroska.
+**
+** 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: KaxAttached.cpp 1202 2005-08-30 14:39:01Z robux4 $
+       \author Steve Lhomme     <robux4 @ users.sf.net>
+*/
+#include "matroska/KaxAttached.h"
+#include "matroska/KaxContexts.h"
+#include "matroska/KaxDefines.h"
+
+// sub elements
+
+using namespace LIBEBML_NAMESPACE;
+
+START_LIBMATROSKA_NAMESPACE
+
+DEFINE_START_SEMANTIC(KaxAttached)
+DEFINE_SEMANTIC_ITEM(true, true, KaxFileName)
+DEFINE_SEMANTIC_ITEM(true, true, KaxMimeType)
+DEFINE_SEMANTIC_ITEM(true, true, KaxFileData)
+DEFINE_SEMANTIC_ITEM(false, true, KaxFileDescription)
+DEFINE_SEMANTIC_ITEM(true, true, KaxFileUID)
+#if MATROSKA_VERSION >= 2
+DEFINE_SEMANTIC_ITEM(false, true, KaxFileReferral)
+#endif // MATROSKA_VERSION
+DEFINE_END_SEMANTIC(KaxAttached)
+
+DEFINE_MKX_MASTER_CONS(KaxAttached,        0x61A7, 2, KaxAttachments, "AttachedFile");
+DEFINE_MKX_UNISTRING  (KaxFileDescription, 0x467E, 2, KaxAttachments, "FileDescription");
+DEFINE_MKX_UNISTRING  (KaxFileName,        0x466E, 2, KaxAttachments, "FileName");
+DEFINE_MKX_STRING     (KaxMimeType,        0x4660, 2, KaxAttachments, "FileMimeType");
+DEFINE_MKX_BINARY     (KaxFileData,        0x465C, 2, KaxAttachments, "FileData");
+DEFINE_MKX_UINTEGER   (KaxFileUID,         0x46AE, 2, KaxAttachments, "FileUID");
+#if MATROSKA_VERSION >= 2
+DEFINE_MKX_BINARY     (KaxFileReferral,    0x4675, 2, KaxAttachments, "FileReferral");
+#endif
+
+KaxAttached::KaxAttached()
+ :EbmlMaster(EBML_CLASS_SEMCONTEXT(KaxAttached))
+{
+       SetSizeLength(2); // mandatory min size support (for easier updating) (2^(7*2)-2 = 16Ko)
+}
+
+END_LIBMATROSKA_NAMESPACE
index 6e1de34e901e01378145eb03784954f50f531af2..e80983d086a75f98f66ef09142740eec2a9bab3b 100644 (file)
@@ -1,57 +1,57 @@
-/****************************************************************************\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 file is part of libmatroska.\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: KaxAttachments.cpp 640 2004-07-09 21:05:36Z mosu $\r
-       \author Steve Lhomme     <robux4 @ users.sf.net>\r
-*/\r
-#include "matroska/KaxAttachments.h"\r
-#include "matroska/KaxAttached.h"\r
-#include "matroska/KaxContexts.h"\r
-#include "matroska/KaxDefines.h"\r
-\r
-using namespace LIBEBML_NAMESPACE;\r
-\r
-// sub elements\r
-START_LIBMATROSKA_NAMESPACE\r
-\r
-DEFINE_START_SEMANTIC(KaxAttachments)\r
-DEFINE_SEMANTIC_ITEM(true, false, KaxAttached)        ///< EBMLVersion\r
-DEFINE_END_SEMANTIC(KaxAttachments)\r
-\r
-DEFINE_MKX_MASTER_CONS(KaxAttachments, 0x1941A469, 4, KaxSegment, "Attachments");\r
-\r
-KaxAttachments::KaxAttachments()\r
- :EbmlMaster(Context_KaxAttachments)\r
-{\r
-       SetSizeLength(2); // mandatory min size support (for easier updating) (2^(7*2)-2 = 16Ko)\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 file is part of libmatroska.
+**
+** 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: KaxAttachments.cpp 640 2004-07-09 21:05:36Z mosu $
+       \author Steve Lhomme     <robux4 @ users.sf.net>
+*/
+#include "matroska/KaxAttachments.h"
+#include "matroska/KaxAttached.h"
+#include "matroska/KaxContexts.h"
+#include "matroska/KaxDefines.h"
+
+using namespace LIBEBML_NAMESPACE;
+
+// sub elements
+START_LIBMATROSKA_NAMESPACE
+
+DEFINE_START_SEMANTIC(KaxAttachments)
+DEFINE_SEMANTIC_ITEM(true, false, KaxAttached)        ///< EBMLVersion
+DEFINE_END_SEMANTIC(KaxAttachments)
+
+DEFINE_MKX_MASTER_CONS(KaxAttachments, 0x1941A469, 4, KaxSegment, "Attachments");
+
+KaxAttachments::KaxAttachments()
+ :EbmlMaster(EBML_CLASS_SEMCONTEXT(KaxAttachments))
+{
+       SetSizeLength(2); // mandatory min size support (for easier updating) (2^(7*2)-2 = 16Ko)
+}
+
+END_LIBMATROSKA_NAMESPACE
index d98217460b7b8dd05b4a2d6a3b3635145d1f9ef6..94b6066fc1c2d984fd0dc5a3f74fe4e2012364dd 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()\r
- :EbmlMaster(Context_KaxBlockGroup)\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()\r
-: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
-               *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
-       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()
+ :EbmlMaster(EBML_CLASS_SEMCONTEXT(KaxBlockGroup))
+ ,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()
+: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) {
+               *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
+
+       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 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
index f292b28ab385f1eb5a38b7853d8d575045dab94a..d866c9bbd692101a4309c9ff3de99d763874aed4 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: KaxCluster.cpp 1228 2005-10-14 19:36:51Z robux4 $\r
-       \author Steve Lhomme     <robux4 @ users.sf.net>\r
-*/\r
-#include "matroska/KaxCluster.h"\r
-#include "matroska/KaxClusterData.h"\r
-#include "matroska/KaxBlock.h"\r
-#include "matroska/KaxContexts.h"\r
-#include "matroska/KaxSegment.h"\r
-#include "matroska/KaxDefines.h"\r
-\r
-// sub elements\r
-START_LIBMATROSKA_NAMESPACE\r
-\r
-DEFINE_START_SEMANTIC(KaxCluster)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxClusterTimecode)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxClusterSilentTracks)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxClusterPrevSize)\r
-DEFINE_SEMANTIC_ITEM(false, false, KaxBlockGroup)\r
-#if MATROSKA_VERSION == 2\r
-DEFINE_SEMANTIC_ITEM(false, false, KaxSimpleBlock)\r
-#endif\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxClusterPosition)\r
-DEFINE_END_SEMANTIC(KaxCluster)\r
-\r
-DEFINE_MKX_MASTER_CONS(KaxCluster, 0x1F43B675, 4, KaxSegment, "Cluster");\r
-\r
-KaxCluster::KaxCluster()\r
-       :EbmlMaster(Context_KaxCluster)\r
-       ,currentNewBlock(NULL)\r
-       ,ParentSegment(NULL)\r
-       ,bFirstFrameInside(false)\r
-       ,bPreviousTimecodeIsSet(false)\r
-       ,bTimecodeScaleIsSet(false)\r
-       ,bSilentTracksUsed(false)\r
-{}\r
-\r
-KaxCluster::KaxCluster(const KaxCluster & ElementToClone) \r
- :EbmlMaster(ElementToClone)\r
- ,bSilentTracksUsed(ElementToClone.bSilentTracksUsed)\r
-{\r
-       // update the parent of each children\r
-       EBML_MASTER_ITERATOR Itr = begin();\r
-       while (Itr != end())\r
-       {\r
-               if (EbmlId(**Itr) == EBML_ID(KaxBlockGroup)) {\r
-                       static_cast<KaxBlockGroup   *>(*Itr)->SetParent(*this);\r
-               } else if (EbmlId(**Itr) == EBML_ID(KaxBlock)) {\r
-                       static_cast<KaxBlock        *>(*Itr)->SetParent(*this);\r
-#if MATROSKA_VERSION >= 2\r
-               } else if (EbmlId(**Itr) == EBML_ID(KaxBlockVirtual)) {\r
-                       static_cast<KaxBlockVirtual *>(*Itr)->SetParent(*this);\r
-#endif // MATROSKA_VERSION\r
-               }\r
-        ++Itr;\r
-       }\r
-}\r
-\r
-bool KaxCluster::AddBlockBlob(KaxBlockBlob * NewBlob)\r
-{\r
-       Blobs.push_back(NewBlob);\r
-       return true;\r
-}\r
-\r
-bool KaxCluster::AddFrameInternal(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, KaxBlockGroup * & MyNewBlock, const KaxBlockGroup * PastBlock, const KaxBlockGroup * ForwBlock, LacingType lacing)\r
-{\r
-       if (!bFirstFrameInside) {\r
-               bFirstFrameInside = true;\r
-               MinTimecode = MaxTimecode = timecode;\r
-       } else {\r
-               if (timecode < MinTimecode)\r
-                       MinTimecode = timecode;\r
-               if (timecode > MaxTimecode)\r
-                       MaxTimecode = timecode;\r
-       }\r
-\r
-       MyNewBlock = NULL;\r
-\r
-       if (lacing == LACING_NONE || !track.LacingEnabled()) {\r
-               currentNewBlock = NULL;\r
-       }\r
-\r
-       // force creation of a new block\r
-       if (currentNewBlock == NULL || uint32(track.TrackNumber()) != uint32(currentNewBlock->TrackNumber()) || PastBlock != NULL || ForwBlock != NULL) {\r
-               KaxBlockGroup & aNewBlock = GetNewBlock();\r
-               MyNewBlock = currentNewBlock = &aNewBlock;\r
-               currentNewBlock = &aNewBlock;\r
-       }\r
-\r
-       if (PastBlock != NULL) {\r
-               if (ForwBlock != NULL) {\r
-                       if (currentNewBlock->AddFrame(track, timecode, buffer, *PastBlock, *ForwBlock, lacing)) {\r
-                               // more data are allowed in this Block\r
-                               return true;\r
-                       } else {\r
-                               currentNewBlock = NULL;\r
-                               return false;\r
-                       }\r
-               } else {\r
-                       if (currentNewBlock->AddFrame(track, timecode, buffer, *PastBlock, lacing)) {\r
-                               // more data are allowed in this Block\r
-                               return true;\r
-                       } else {\r
-                               currentNewBlock = NULL;\r
-                               return false;\r
-                       }\r
-               }\r
-       } else {\r
-               if (currentNewBlock->AddFrame(track, timecode, buffer, lacing)) {\r
-                       // more data are allowed in this Block\r
-                       return true;\r
-               } else {\r
-                       currentNewBlock = NULL;\r
-                       return false;\r
-               }\r
-       }\r
-}\r
-\r
-bool KaxCluster::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, KaxBlockGroup * & MyNewBlock, LacingType lacing)\r
-{\r
-       assert(Blobs.size() == 0); // mutually exclusive for the moment\r
-       return AddFrameInternal(track, timecode, buffer, MyNewBlock, NULL, NULL, lacing);\r
-}\r
-\r
-bool KaxCluster::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, KaxBlockGroup * & MyNewBlock, const KaxBlockGroup & PastBlock, LacingType lacing)\r
-{\r
-       assert(Blobs.size() == 0); // mutually exclusive for the moment\r
-       return AddFrameInternal(track, timecode, buffer, MyNewBlock, &PastBlock, NULL, lacing);\r
-}\r
-\r
-bool KaxCluster::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, KaxBlockGroup * & MyNewBlock, const KaxBlockGroup & PastBlock, const KaxBlockGroup & ForwBlock, LacingType lacing)\r
-{\r
-       assert(Blobs.size() == 0); // mutually exclusive for the moment\r
-       return AddFrameInternal(track, timecode, buffer, MyNewBlock, &PastBlock, &ForwBlock, lacing);\r
-}\r
-\r
-/*!\r
-       \todo only put the Blocks written in the cue entries\r
-*/\r
-filepos_t KaxCluster::Render(IOCallback & output, KaxCues & CueToUpdate, bool bSaveDefault)\r
-{\r
-       filepos_t Result = 0;\r
-       size_t TrkIndex, Index;\r
-\r
-       // update the Timecode of the Cluster before writing\r
-       KaxClusterTimecode * Timecode = static_cast<KaxClusterTimecode *>(this->FindElt(EBML_INFO(KaxClusterTimecode)));\r
-       *static_cast<EbmlUInteger *>(Timecode) = GlobalTimecode() / GlobalTimecodeScale();\r
-\r
-       if (Blobs.size() == 0) {\r
-               // old-school direct KaxBlockGroup\r
-\r
-               // SilentTracks handling\r
-               // check the parent cluster for existing tracks and see if they are contained in this cluster or not\r
-               if (bSilentTracksUsed)\r
-               {\r
-                       KaxTracks & MyTracks = *static_cast<KaxTracks *>(ParentSegment->FindElt(EBML_INFO(KaxTracks)));\r
-                       for (TrkIndex = 0; TrkIndex < MyTracks.ListSize(); TrkIndex++) {\r
-                               if (EbmlId(*MyTracks[TrkIndex]) == EBML_ID(KaxTrackEntry))\r
-                               {\r
-                                       KaxTrackEntry & entry = *static_cast<KaxTrackEntry *>(MyTracks[TrkIndex]);\r
-                                       uint32 tracknum = entry.TrackNumber();\r
-                                       for (Index = 0; Index < ListSize(); Index++) {\r
-                                               if (EbmlId(*(*this)[Index]) == EBML_ID(KaxBlockGroup)) {\r
-                                                       KaxBlockGroup & group = *static_cast<KaxBlockGroup *>((*this)[Index]);\r
-                                                       if (group.TrackNumber() == tracknum)\r
-                                                               break; // this track is used\r
-                                               }\r
-                                       }\r
-                                       // the track wasn't found in this cluster\r
-                                       if (Index == ListSize())\r
-                                       {\r
-                                               KaxClusterSilentTracks * SilentTracks = static_cast<KaxClusterSilentTracks *>(this->FindFirstElt(EBML_INFO(KaxClusterSilentTracks)));\r
-                                               assert(SilentTracks != NULL); // the flag bSilentTracksUsed should be set when creating the Cluster\r
-                                               KaxClusterSilentTrackNumber * trackelt = static_cast<KaxClusterSilentTrackNumber *>(SilentTracks->AddNewElt(EBML_INFO(KaxClusterSilentTrackNumber)));\r
-                                               *static_cast<EbmlUInteger *>(trackelt) = tracknum;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               Result = EbmlMaster::Render(output, bSaveDefault);\r
-               // For all Blocks add their position on the CueEntry\r
-               \r
-               for (Index = 0; Index < ListSize(); Index++) {\r
-                       if (EbmlId(*(*this)[Index]) == EBML_ID(KaxBlockGroup)) {\r
-                               CueToUpdate.PositionSet(*static_cast<const KaxBlockGroup *>((*this)[Index]));\r
-                       }\r
-               }\r
-       } else {\r
-               // new school, using KaxBlockBlob\r
-               for (Index = 0; Index<Blobs.size(); Index++)\r
-               {\r
-#if MATROSKA_VERSION >= 2\r
-                       if (Blobs[Index]->IsSimpleBlock())\r
-                               PushElement( (KaxSimpleBlock&) *Blobs[Index] );\r
-                       else\r
-#endif\r
-                               PushElement( (KaxBlockGroup&) *Blobs[Index] );\r
-               }\r
-\r
-               // SilentTracks handling\r
-               // check the parent cluster for existing tracks and see if they are contained in this cluster or not\r
-               if (bSilentTracksUsed)\r
-               {\r
-                       KaxTracks & MyTracks = *static_cast<KaxTracks *>(ParentSegment->FindElt(EBML_INFO(KaxTracks)));\r
-                       for (TrkIndex = 0; TrkIndex < MyTracks.ListSize(); TrkIndex++) {\r
-                               if (EbmlId(*MyTracks[TrkIndex]) == EBML_ID(KaxTrackEntry))\r
-                               {\r
-                                       KaxTrackEntry & entry = *static_cast<KaxTrackEntry *>(MyTracks[TrkIndex]);\r
-                                       uint32 tracknum = entry.TrackNumber();\r
-                                       for (Index = 0; Index<Blobs.size(); Index++) {\r
-                                               if (((KaxInternalBlock&)*Blobs[Index]).TrackNum() == tracknum)\r
-                                                               break; // this track is used\r
-                                       }\r
-                                       // the track wasn't found in this cluster\r
-                                       if (Index == ListSize())\r
-                                       {\r
-                                               KaxClusterSilentTracks * SilentTracks = static_cast<KaxClusterSilentTracks *>(this->FindFirstElt(EBML_INFO(KaxClusterSilentTracks)));\r
-                                               assert(SilentTracks != NULL); // the flag bSilentTracksUsed should be set when creating the Cluster\r
-                                               KaxClusterSilentTrackNumber * trackelt = static_cast<KaxClusterSilentTrackNumber *>(SilentTracks->AddNewElt(EBML_INFO(KaxClusterSilentTrackNumber)));\r
-                                               *static_cast<EbmlUInteger *>(trackelt) = tracknum;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               Result = EbmlMaster::Render(output, bSaveDefault);\r
-\r
-               // For all Blocks add their position on the CueEntry\r
-               for (Index = 0; Index<Blobs.size(); Index++) {\r
-                       CueToUpdate.PositionSet(*Blobs[Index]);\r
-               }\r
-\r
-               Blobs.clear();\r
-       }\r
-\r
-       return Result;\r
-}\r
-\r
-/*!\r
-       \todo automatically choose valid timecode for the Cluster based on the previous cluster timecode (must be incremental)\r
-*/\r
-uint64 KaxCluster::GlobalTimecode() const\r
-{\r
-       assert(bPreviousTimecodeIsSet);\r
-       uint64 result = MinTimecode;\r
-\r
-       if (result < PreviousTimecode)\r
-               result = PreviousTimecode + 1;\r
-       \r
-       return result;\r
-}\r
-\r
-/*!\r
-       \brief retrieve the relative \r
-       \todo !!! We need a way to know the TimecodeScale\r
-*/\r
-int16 KaxCluster::GetBlockLocalTimecode(uint64 aGlobalTimecode) const\r
-{\r
-       int64 TimecodeDelay = (int64(aGlobalTimecode) - int64(GlobalTimecode())) / int64(GlobalTimecodeScale());\r
-       assert(TimecodeDelay >= int16(0x8000) && TimecodeDelay <= int16(0x7FFF));\r
-       return int16(TimecodeDelay);\r
-}\r
-\r
-uint64 KaxCluster::GetBlockGlobalTimecode(int16 GlobalSavedTimecode)\r
-{\r
-       if (!bFirstFrameInside) {\r
-               KaxClusterTimecode * Timecode = static_cast<KaxClusterTimecode *>(this->FindElt(EBML_INFO(KaxClusterTimecode)));\r
-               assert (bFirstFrameInside); // use the InitTimecode() hack for now\r
-               MinTimecode = MaxTimecode = PreviousTimecode = *static_cast<EbmlUInteger *>(Timecode);\r
-               bFirstFrameInside = true;\r
-               bPreviousTimecodeIsSet = true;\r
-       }\r
-       return int64(GlobalSavedTimecode * GlobalTimecodeScale()) + GlobalTimecode();\r
-}\r
-\r
-KaxBlockGroup & KaxCluster::GetNewBlock()\r
-{\r
-       KaxBlockGroup & MyBlock = AddNewChild<KaxBlockGroup>(*this);\r
-       MyBlock.SetParent(*this);\r
-       return MyBlock;\r
-}\r
-\r
-void KaxCluster::ReleaseFrames()\r
-{\r
-       size_t Index;\r
-       \r
-       for (Index = 0; Index < ListSize(); Index++) {\r
-               if (EbmlId(*(*this)[Index]) == EBML_ID(KaxBlockGroup)) {\r
-                       static_cast<KaxBlockGroup*>((*this)[Index])->ReleaseFrames();\r
-               }\r
-       }\r
-}\r
-\r
-uint64 KaxCluster::GetPosition() const\r
-{\r
-       assert(ParentSegment != NULL);\r
-       return ParentSegment->GetRelativePosition(*this);\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: KaxCluster.cpp 1228 2005-10-14 19:36:51Z robux4 $
+       \author Steve Lhomme     <robux4 @ users.sf.net>
+*/
+#include "matroska/KaxCluster.h"
+#include "matroska/KaxClusterData.h"
+#include "matroska/KaxBlock.h"
+#include "matroska/KaxContexts.h"
+#include "matroska/KaxSegment.h"
+#include "matroska/KaxDefines.h"
+
+// sub elements
+START_LIBMATROSKA_NAMESPACE
+
+DEFINE_START_SEMANTIC(KaxCluster)
+DEFINE_SEMANTIC_ITEM(true, true, KaxClusterTimecode)
+DEFINE_SEMANTIC_ITEM(false, true, KaxClusterSilentTracks)
+DEFINE_SEMANTIC_ITEM(false, true, KaxClusterPrevSize)
+DEFINE_SEMANTIC_ITEM(false, false, KaxBlockGroup)
+#if MATROSKA_VERSION == 2
+DEFINE_SEMANTIC_ITEM(false, false, KaxSimpleBlock)
+#endif
+DEFINE_SEMANTIC_ITEM(false, true, KaxClusterPosition)
+DEFINE_END_SEMANTIC(KaxCluster)
+
+DEFINE_MKX_MASTER_CONS(KaxCluster, 0x1F43B675, 4, KaxSegment, "Cluster");
+
+KaxCluster::KaxCluster()
+       :EbmlMaster(EBML_CLASS_SEMCONTEXT(KaxCluster))
+       ,currentNewBlock(NULL)
+       ,ParentSegment(NULL)
+       ,bFirstFrameInside(false)
+       ,bPreviousTimecodeIsSet(false)
+       ,bTimecodeScaleIsSet(false)
+       ,bSilentTracksUsed(false)
+{}
+
+KaxCluster::KaxCluster(const KaxCluster & ElementToClone) 
+ :EbmlMaster(ElementToClone)
+ ,bSilentTracksUsed(ElementToClone.bSilentTracksUsed)
+{
+       // update the parent of each children
+       EBML_MASTER_ITERATOR Itr = begin();
+       while (Itr != end())
+       {
+               if (EbmlId(**Itr) == EBML_ID(KaxBlockGroup)) {
+                       static_cast<KaxBlockGroup   *>(*Itr)->SetParent(*this);
+               } else if (EbmlId(**Itr) == EBML_ID(KaxBlock)) {
+                       static_cast<KaxBlock        *>(*Itr)->SetParent(*this);
+#if MATROSKA_VERSION >= 2
+               } else if (EbmlId(**Itr) == EBML_ID(KaxBlockVirtual)) {
+                       static_cast<KaxBlockVirtual *>(*Itr)->SetParent(*this);
+#endif // MATROSKA_VERSION
+               }
+        ++Itr;
+       }
+}
+
+bool KaxCluster::AddBlockBlob(KaxBlockBlob * NewBlob)
+{
+       Blobs.push_back(NewBlob);
+       return true;
+}
+
+bool KaxCluster::AddFrameInternal(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, KaxBlockGroup * & MyNewBlock, const KaxBlockGroup * PastBlock, const KaxBlockGroup * ForwBlock, LacingType lacing)
+{
+       if (!bFirstFrameInside) {
+               bFirstFrameInside = true;
+               MinTimecode = MaxTimecode = timecode;
+       } else {
+               if (timecode < MinTimecode)
+                       MinTimecode = timecode;
+               if (timecode > MaxTimecode)
+                       MaxTimecode = timecode;
+       }
+
+       MyNewBlock = NULL;
+
+       if (lacing == LACING_NONE || !track.LacingEnabled()) {
+               currentNewBlock = NULL;
+       }
+
+       // force creation of a new block
+       if (currentNewBlock == NULL || uint32(track.TrackNumber()) != uint32(currentNewBlock->TrackNumber()) || PastBlock != NULL || ForwBlock != NULL) {
+               KaxBlockGroup & aNewBlock = GetNewBlock();
+               MyNewBlock = currentNewBlock = &aNewBlock;
+               currentNewBlock = &aNewBlock;
+       }
+
+       if (PastBlock != NULL) {
+               if (ForwBlock != NULL) {
+                       if (currentNewBlock->AddFrame(track, timecode, buffer, *PastBlock, *ForwBlock, lacing)) {
+                               // more data are allowed in this Block
+                               return true;
+                       } else {
+                               currentNewBlock = NULL;
+                               return false;
+                       }
+               } else {
+                       if (currentNewBlock->AddFrame(track, timecode, buffer, *PastBlock, lacing)) {
+                               // more data are allowed in this Block
+                               return true;
+                       } else {
+                               currentNewBlock = NULL;
+                               return false;
+                       }
+               }
+       } else {
+               if (currentNewBlock->AddFrame(track, timecode, buffer, lacing)) {
+                       // more data are allowed in this Block
+                       return true;
+               } else {
+                       currentNewBlock = NULL;
+                       return false;
+               }
+       }
+}
+
+bool KaxCluster::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, KaxBlockGroup * & MyNewBlock, LacingType lacing)
+{
+       assert(Blobs.size() == 0); // mutually exclusive for the moment
+       return AddFrameInternal(track, timecode, buffer, MyNewBlock, NULL, NULL, lacing);
+}
+
+bool KaxCluster::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, KaxBlockGroup * & MyNewBlock, const KaxBlockGroup & PastBlock, LacingType lacing)
+{
+       assert(Blobs.size() == 0); // mutually exclusive for the moment
+       return AddFrameInternal(track, timecode, buffer, MyNewBlock, &PastBlock, NULL, lacing);
+}
+
+bool KaxCluster::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, KaxBlockGroup * & MyNewBlock, const KaxBlockGroup & PastBlock, const KaxBlockGroup & ForwBlock, LacingType lacing)
+{
+       assert(Blobs.size() == 0); // mutually exclusive for the moment
+       return AddFrameInternal(track, timecode, buffer, MyNewBlock, &PastBlock, &ForwBlock, lacing);
+}
+
+/*!
+       \todo only put the Blocks written in the cue entries
+*/
+filepos_t KaxCluster::Render(IOCallback & output, KaxCues & CueToUpdate, bool bSaveDefault)
+{
+       filepos_t Result = 0;
+       size_t TrkIndex, Index;
+
+       // update the Timecode of the Cluster before writing
+       KaxClusterTimecode * Timecode = static_cast<KaxClusterTimecode *>(this->FindElt(EBML_INFO(KaxClusterTimecode)));
+       *static_cast<EbmlUInteger *>(Timecode) = GlobalTimecode() / GlobalTimecodeScale();
+
+       if (Blobs.size() == 0) {
+               // old-school direct KaxBlockGroup
+
+               // SilentTracks handling
+               // check the parent cluster for existing tracks and see if they are contained in this cluster or not
+               if (bSilentTracksUsed)
+               {
+                       KaxTracks & MyTracks = *static_cast<KaxTracks *>(ParentSegment->FindElt(EBML_INFO(KaxTracks)));
+                       for (TrkIndex = 0; TrkIndex < MyTracks.ListSize(); TrkIndex++) {
+                               if (EbmlId(*MyTracks[TrkIndex]) == EBML_ID(KaxTrackEntry))
+                               {
+                                       KaxTrackEntry & entry = *static_cast<KaxTrackEntry *>(MyTracks[TrkIndex]);
+                                       uint32 tracknum = entry.TrackNumber();
+                                       for (Index = 0; Index < ListSize(); Index++) {
+                                               if (EbmlId(*(*this)[Index]) == EBML_ID(KaxBlockGroup)) {
+                                                       KaxBlockGroup & group = *static_cast<KaxBlockGroup *>((*this)[Index]);
+                                                       if (group.TrackNumber() == tracknum)
+                                                               break; // this track is used
+                                               }
+                                       }
+                                       // the track wasn't found in this cluster
+                                       if (Index == ListSize())
+                                       {
+                                               KaxClusterSilentTracks * SilentTracks = static_cast<KaxClusterSilentTracks *>(this->FindFirstElt(EBML_INFO(KaxClusterSilentTracks)));
+                                               assert(SilentTracks != NULL); // the flag bSilentTracksUsed should be set when creating the Cluster
+                                               KaxClusterSilentTrackNumber * trackelt = static_cast<KaxClusterSilentTrackNumber *>(SilentTracks->AddNewElt(EBML_INFO(KaxClusterSilentTrackNumber)));
+                                               *static_cast<EbmlUInteger *>(trackelt) = tracknum;
+                                       }
+                               }
+                       }
+               }
+
+               Result = EbmlMaster::Render(output, bSaveDefault);
+               // For all Blocks add their position on the CueEntry
+               
+               for (Index = 0; Index < ListSize(); Index++) {
+                       if (EbmlId(*(*this)[Index]) == EBML_ID(KaxBlockGroup)) {
+                               CueToUpdate.PositionSet(*static_cast<const KaxBlockGroup *>((*this)[Index]));
+                       }
+               }
+       } else {
+               // new school, using KaxBlockBlob
+               for (Index = 0; Index<Blobs.size(); Index++)
+               {
+#if MATROSKA_VERSION >= 2
+                       if (Blobs[Index]->IsSimpleBlock())
+                               PushElement( (KaxSimpleBlock&) *Blobs[Index] );
+                       else
+#endif
+                               PushElement( (KaxBlockGroup&) *Blobs[Index] );
+               }
+
+               // SilentTracks handling
+               // check the parent cluster for existing tracks and see if they are contained in this cluster or not
+               if (bSilentTracksUsed)
+               {
+                       KaxTracks & MyTracks = *static_cast<KaxTracks *>(ParentSegment->FindElt(EBML_INFO(KaxTracks)));
+                       for (TrkIndex = 0; TrkIndex < MyTracks.ListSize(); TrkIndex++) {
+                               if (EbmlId(*MyTracks[TrkIndex]) == EBML_ID(KaxTrackEntry))
+                               {
+                                       KaxTrackEntry & entry = *static_cast<KaxTrackEntry *>(MyTracks[TrkIndex]);
+                                       uint32 tracknum = entry.TrackNumber();
+                                       for (Index = 0; Index<Blobs.size(); Index++) {
+                                               if (((KaxInternalBlock&)*Blobs[Index]).TrackNum() == tracknum)
+                                                               break; // this track is used
+                                       }
+                                       // the track wasn't found in this cluster
+                                       if (Index == ListSize())
+                                       {
+                                               KaxClusterSilentTracks * SilentTracks = static_cast<KaxClusterSilentTracks *>(this->FindFirstElt(EBML_INFO(KaxClusterSilentTracks)));
+                                               assert(SilentTracks != NULL); // the flag bSilentTracksUsed should be set when creating the Cluster
+                                               KaxClusterSilentTrackNumber * trackelt = static_cast<KaxClusterSilentTrackNumber *>(SilentTracks->AddNewElt(EBML_INFO(KaxClusterSilentTrackNumber)));
+                                               *static_cast<EbmlUInteger *>(trackelt) = tracknum;
+                                       }
+                               }
+                       }
+               }
+
+               Result = EbmlMaster::Render(output, bSaveDefault);
+
+               // For all Blocks add their position on the CueEntry
+               for (Index = 0; Index<Blobs.size(); Index++) {
+                       CueToUpdate.PositionSet(*Blobs[Index]);
+               }
+
+               Blobs.clear();
+       }
+
+       return Result;
+}
+
+/*!
+       \todo automatically choose valid timecode for the Cluster based on the previous cluster timecode (must be incremental)
+*/
+uint64 KaxCluster::GlobalTimecode() const
+{
+       assert(bPreviousTimecodeIsSet);
+       uint64 result = MinTimecode;
+
+       if (result < PreviousTimecode)
+               result = PreviousTimecode + 1;
+       
+       return result;
+}
+
+/*!
+       \brief retrieve the relative 
+       \todo !!! We need a way to know the TimecodeScale
+*/
+int16 KaxCluster::GetBlockLocalTimecode(uint64 aGlobalTimecode) const
+{
+       int64 TimecodeDelay = (int64(aGlobalTimecode) - int64(GlobalTimecode())) / int64(GlobalTimecodeScale());
+       assert(TimecodeDelay >= int16(0x8000) && TimecodeDelay <= int16(0x7FFF));
+       return int16(TimecodeDelay);
+}
+
+uint64 KaxCluster::GetBlockGlobalTimecode(int16 GlobalSavedTimecode)
+{
+       if (!bFirstFrameInside) {
+               KaxClusterTimecode * Timecode = static_cast<KaxClusterTimecode *>(this->FindElt(EBML_INFO(KaxClusterTimecode)));
+               assert (bFirstFrameInside); // use the InitTimecode() hack for now
+               MinTimecode = MaxTimecode = PreviousTimecode = *static_cast<EbmlUInteger *>(Timecode);
+               bFirstFrameInside = true;
+               bPreviousTimecodeIsSet = true;
+       }
+       return int64(GlobalSavedTimecode * GlobalTimecodeScale()) + GlobalTimecode();
+}
+
+KaxBlockGroup & KaxCluster::GetNewBlock()
+{
+       KaxBlockGroup & MyBlock = AddNewChild<KaxBlockGroup>(*this);
+       MyBlock.SetParent(*this);
+       return MyBlock;
+}
+
+void KaxCluster::ReleaseFrames()
+{
+       size_t Index;
+       
+       for (Index = 0; Index < ListSize(); Index++) {
+               if (EbmlId(*(*this)[Index]) == EBML_ID(KaxBlockGroup)) {
+                       static_cast<KaxBlockGroup*>((*this)[Index])->ReleaseFrames();
+               }
+       }
+}
+
+uint64 KaxCluster::GetPosition() const
+{
+       assert(ParentSegment != NULL);
+       return ParentSegment->GetRelativePosition(*this);
+}
+
+END_LIBMATROSKA_NAMESPACE
index bbd020ac5f30e2ea2d144f791a1d60f1e61c85cd..39eab37f37ad363e7d0c1e1a4eeea835b82861a9 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 file is part of libmatroska.\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: KaxSegment.cpp 1096 2005-03-17 09:14:52Z robux4 $\r
-       \author Steve Lhomme     <robux4 @ users.sf.net>\r
-*/\r
-#include "matroska/KaxSegment.h"\r
-#include "ebml/EbmlHead.h"\r
-\r
-// sub elements\r
-#include "matroska/KaxCluster.h"\r
-#include "matroska/KaxSeekHead.h"\r
-#include "matroska/KaxCues.h"\r
-#include "matroska/KaxTracks.h"\r
-#include "matroska/KaxInfo.h"\r
-#include "matroska/KaxChapters.h"\r
-#include "matroska/KaxAttachments.h"\r
-#include "matroska/KaxTags.h"\r
-#include "matroska/KaxContexts.h"\r
-#include "matroska/KaxDefines.h"\r
-\r
-START_LIBMATROSKA_NAMESPACE\r
-\r
-DEFINE_START_SEMANTIC(KaxMatroska)\r
-DEFINE_SEMANTIC_ITEM(true, true, EbmlHead)\r
-DEFINE_SEMANTIC_ITEM(true, false, KaxSegment)\r
-DEFINE_END_SEMANTIC(KaxMatroska)\r
-\r
-DEFINE_START_SEMANTIC(KaxSegment)\r
-DEFINE_SEMANTIC_ITEM(false, false, KaxCluster)\r
-DEFINE_SEMANTIC_ITEM(false, false, KaxSeekHead)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxCues)\r
-DEFINE_SEMANTIC_ITEM(false, false, KaxTracks)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxInfo)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxChapters)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxAttachments)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxTags)\r
-DEFINE_END_SEMANTIC(KaxSegment)\r
-\r
-DEFINE_MKX_CONTEXT(KaxMatroska);\r
-\r
-DEFINE_MKX_MASTER_ORPHAN(KaxSegment, 0x18538067, 4, "Segment\0rotomopogo");\r
-\r
-KaxSegment::KaxSegment()\r
-       :EbmlMaster(KaxSegment_Context)\r
-{\r
-       SetSizeLength(5); // mandatory min size support (for easier updating) (2^(7*5)-2 = 32Go)\r
-       SetSizeInfinite(); // by default a segment is big and the size is unknown in advance\r
-}\r
-\r
-KaxSegment::KaxSegment(const KaxSegment & ElementToClone)\r
- :EbmlMaster(ElementToClone)\r
-{\r
-       // update the parent of each children\r
-       EBML_MASTER_ITERATOR Itr = begin();\r
-       while (Itr != end())\r
-       {\r
-               if (EbmlId(**Itr) == EBML_ID(KaxCluster)) {\r
-                       static_cast<KaxCluster *>(*Itr)->SetParent(*this);\r
-               }\r
-        ++Itr;\r
-       }\r
-}\r
-\r
-\r
-uint64 KaxSegment::GetRelativePosition(uint64 aGlobalPosition) const\r
-{\r
-       return aGlobalPosition - GetElementPosition() - HeadSize();\r
-}\r
-\r
-uint64 KaxSegment::GetRelativePosition(const EbmlElement & Elt) const\r
-{\r
-       return GetRelativePosition(Elt.GetElementPosition());\r
-}\r
-\r
-uint64 KaxSegment::GetGlobalPosition(uint64 aRelativePosition) const\r
-{\r
-       return aRelativePosition + GetElementPosition() + HeadSize();\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 file is part of libmatroska.
+**
+** 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: KaxSegment.cpp 1096 2005-03-17 09:14:52Z robux4 $
+       \author Steve Lhomme     <robux4 @ users.sf.net>
+*/
+#include "matroska/KaxSegment.h"
+#include "ebml/EbmlHead.h"
+
+// sub elements
+#include "matroska/KaxCluster.h"
+#include "matroska/KaxSeekHead.h"
+#include "matroska/KaxCues.h"
+#include "matroska/KaxTracks.h"
+#include "matroska/KaxInfo.h"
+#include "matroska/KaxChapters.h"
+#include "matroska/KaxAttachments.h"
+#include "matroska/KaxTags.h"
+#include "matroska/KaxContexts.h"
+#include "matroska/KaxDefines.h"
+
+START_LIBMATROSKA_NAMESPACE
+
+DEFINE_START_SEMANTIC(KaxMatroska)
+DEFINE_SEMANTIC_ITEM(true, true, EbmlHead)
+DEFINE_SEMANTIC_ITEM(true, false, KaxSegment)
+DEFINE_END_SEMANTIC(KaxMatroska)
+
+DEFINE_START_SEMANTIC(KaxSegment)
+DEFINE_SEMANTIC_ITEM(false, false, KaxCluster)
+DEFINE_SEMANTIC_ITEM(false, false, KaxSeekHead)
+DEFINE_SEMANTIC_ITEM(false, true, KaxCues)
+DEFINE_SEMANTIC_ITEM(false, false, KaxTracks)
+DEFINE_SEMANTIC_ITEM(true, true, KaxInfo)
+DEFINE_SEMANTIC_ITEM(false, true, KaxChapters)
+DEFINE_SEMANTIC_ITEM(false, true, KaxAttachments)
+DEFINE_SEMANTIC_ITEM(false, true, KaxTags)
+DEFINE_END_SEMANTIC(KaxSegment)
+
+DEFINE_MKX_CONTEXT(KaxMatroska);
+
+DEFINE_MKX_MASTER_ORPHAN(KaxSegment, 0x18538067, 4, "Segment\0rotomopogo");
+
+KaxSegment::KaxSegment()
+       :EbmlMaster(EBML_CLASS_SEMCONTEXT(KaxSegment))
+{
+       SetSizeLength(5); // mandatory min size support (for easier updating) (2^(7*5)-2 = 32Go)
+       SetSizeInfinite(); // by default a segment is big and the size is unknown in advance
+}
+
+KaxSegment::KaxSegment(const KaxSegment & ElementToClone)
+ :EbmlMaster(ElementToClone)
+{
+       // update the parent of each children
+       EBML_MASTER_ITERATOR Itr = begin();
+       while (Itr != end())
+       {
+               if (EbmlId(**Itr) == EBML_ID(KaxCluster)) {
+                       static_cast<KaxCluster *>(*Itr)->SetParent(*this);
+               }
+        ++Itr;
+       }
+}
+
+
+uint64 KaxSegment::GetRelativePosition(uint64 aGlobalPosition) const
+{
+       return aGlobalPosition - GetElementPosition() - HeadSize();
+}
+
+uint64 KaxSegment::GetRelativePosition(const EbmlElement & Elt) const
+{
+       return GetRelativePosition(Elt.GetElementPosition());
+}
+
+uint64 KaxSegment::GetGlobalPosition(uint64 aRelativePosition) const
+{
+       return aRelativePosition + GetElementPosition() + HeadSize();
+}
+
+END_LIBMATROSKA_NAMESPACE
index 0ca2b3292fb2957ae43b28ce4eb3171a7f5e8b04..f6d3be6fd97ec8c2c472ffc3854b95ca5c0c3dac 100644 (file)
@@ -1,99 +1,99 @@
-/****************************************************************************\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 file is part of libmatroska.\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: KaxTracks.cpp 1202 2005-08-30 14:39:01Z robux4 $\r
-       \author Steve Lhomme     <robux4 @ users.sf.net>\r
-*/\r
-#include "matroska/KaxTracks.h"\r
-\r
-// sub elements\r
-#include "matroska/KaxTrackEntryData.h"\r
-#include "matroska/KaxTrackAudio.h"\r
-#include "matroska/KaxTrackVideo.h"\r
-#include "matroska/KaxContentEncoding.h"\r
-#include "matroska/KaxContexts.h"\r
-#include "matroska/KaxDefines.h"\r
-\r
-START_LIBMATROSKA_NAMESPACE\r
-\r
-DEFINE_START_SEMANTIC(KaxTracks)\r
-DEFINE_SEMANTIC_ITEM(true, false, KaxTrackEntry)\r
-DEFINE_END_SEMANTIC(KaxTracks)\r
-\r
-DEFINE_START_SEMANTIC(KaxTrackEntry)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxTrackNumber)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxTrackUID)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxTrackType)\r
-#if MATROSKA_VERSION >= 2\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxTrackFlagEnabled)\r
-#endif // MATROSKA_VERSION\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxTrackFlagDefault)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxTrackFlagForced)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxTrackFlagLacing)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxTrackMinCache)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxTrackMaxCache)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxTrackDefaultDuration)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxTrackTimecodeScale)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxMaxBlockAdditionID)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxTrackName)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxTrackLanguage)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxCodecID)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxCodecPrivate)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxCodecName)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxTrackAttachmentLink)\r
-#if MATROSKA_VERSION >= 2\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxCodecSettings)\r
-DEFINE_SEMANTIC_ITEM(false, false, KaxCodecInfoURL)\r
-DEFINE_SEMANTIC_ITEM(false, false, KaxCodecDownloadURL)\r
-DEFINE_SEMANTIC_ITEM(true, true, KaxCodecDecodeAll)\r
-#endif // MATROSKA_VERSION\r
-DEFINE_SEMANTIC_ITEM(false, false, KaxTrackOverlay)\r
-DEFINE_SEMANTIC_ITEM(false, false, KaxTrackTranslate)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxTrackAudio)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxTrackVideo)\r
-DEFINE_SEMANTIC_ITEM(false, true, KaxContentEncodings)\r
-DEFINE_END_SEMANTIC(KaxTrackEntry)\r
-\r
-DEFINE_MKX_MASTER     (KaxTracks, 0x1654AE6B, 4, KaxSegment, "Tracks");\r
-DEFINE_MKX_MASTER_CONS(KaxTrackEntry,   0xAE, 1, KaxTracks, "TrackEntry");\r
-\r
-KaxTrackEntry::KaxTrackEntry()\r
-       :EbmlMaster(Context_KaxTrackEntry)\r
-       ,bGlobalTimecodeScaleIsSet(false)\r
-{}\r
-\r
-void KaxTrackEntry::EnableLacing(bool bEnable)\r
-{\r
-       KaxTrackFlagLacing & myLacing = GetChild<KaxTrackFlagLacing>(*this);\r
-       *(static_cast<EbmlUInteger *>(&myLacing)) = bEnable ? 1 : 0;\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 file is part of libmatroska.
+**
+** 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: KaxTracks.cpp 1202 2005-08-30 14:39:01Z robux4 $
+       \author Steve Lhomme     <robux4 @ users.sf.net>
+*/
+#include "matroska/KaxTracks.h"
+
+// sub elements
+#include "matroska/KaxTrackEntryData.h"
+#include "matroska/KaxTrackAudio.h"
+#include "matroska/KaxTrackVideo.h"
+#include "matroska/KaxContentEncoding.h"
+#include "matroska/KaxContexts.h"
+#include "matroska/KaxDefines.h"
+
+START_LIBMATROSKA_NAMESPACE
+
+DEFINE_START_SEMANTIC(KaxTracks)
+DEFINE_SEMANTIC_ITEM(true, false, KaxTrackEntry)
+DEFINE_END_SEMANTIC(KaxTracks)
+
+DEFINE_START_SEMANTIC(KaxTrackEntry)
+DEFINE_SEMANTIC_ITEM(true, true, KaxTrackNumber)
+DEFINE_SEMANTIC_ITEM(true, true, KaxTrackUID)
+DEFINE_SEMANTIC_ITEM(true, true, KaxTrackType)
+#if MATROSKA_VERSION >= 2
+DEFINE_SEMANTIC_ITEM(true, true, KaxTrackFlagEnabled)
+#endif // MATROSKA_VERSION
+DEFINE_SEMANTIC_ITEM(true, true, KaxTrackFlagDefault)
+DEFINE_SEMANTIC_ITEM(true, true, KaxTrackFlagForced)
+DEFINE_SEMANTIC_ITEM(true, true, KaxTrackFlagLacing)
+DEFINE_SEMANTIC_ITEM(true, true, KaxTrackMinCache)
+DEFINE_SEMANTIC_ITEM(false, true, KaxTrackMaxCache)
+DEFINE_SEMANTIC_ITEM(false, true, KaxTrackDefaultDuration)
+DEFINE_SEMANTIC_ITEM(true, true, KaxTrackTimecodeScale)
+DEFINE_SEMANTIC_ITEM(true, true, KaxMaxBlockAdditionID)
+DEFINE_SEMANTIC_ITEM(false, true, KaxTrackName)
+DEFINE_SEMANTIC_ITEM(false, true, KaxTrackLanguage)
+DEFINE_SEMANTIC_ITEM(true, true, KaxCodecID)
+DEFINE_SEMANTIC_ITEM(false, true, KaxCodecPrivate)
+DEFINE_SEMANTIC_ITEM(false, true, KaxCodecName)
+DEFINE_SEMANTIC_ITEM(false, true, KaxTrackAttachmentLink)
+#if MATROSKA_VERSION >= 2
+DEFINE_SEMANTIC_ITEM(false, true, KaxCodecSettings)
+DEFINE_SEMANTIC_ITEM(false, false, KaxCodecInfoURL)
+DEFINE_SEMANTIC_ITEM(false, false, KaxCodecDownloadURL)
+DEFINE_SEMANTIC_ITEM(true, true, KaxCodecDecodeAll)
+#endif // MATROSKA_VERSION
+DEFINE_SEMANTIC_ITEM(false, false, KaxTrackOverlay)
+DEFINE_SEMANTIC_ITEM(false, false, KaxTrackTranslate)
+DEFINE_SEMANTIC_ITEM(false, true, KaxTrackAudio)
+DEFINE_SEMANTIC_ITEM(false, true, KaxTrackVideo)
+DEFINE_SEMANTIC_ITEM(false, true, KaxContentEncodings)
+DEFINE_END_SEMANTIC(KaxTrackEntry)
+
+DEFINE_MKX_MASTER     (KaxTracks, 0x1654AE6B, 4, KaxSegment, "Tracks");
+DEFINE_MKX_MASTER_CONS(KaxTrackEntry,   0xAE, 1, KaxTracks, "TrackEntry");
+
+KaxTrackEntry::KaxTrackEntry()
+       :EbmlMaster(EBML_CLASS_SEMCONTEXT(KaxTrackEntry))
+       ,bGlobalTimecodeScaleIsSet(false)
+{}
+
+void KaxTrackEntry::EnableLacing(bool bEnable)
+{
+       KaxTrackFlagLacing & myLacing = GetChild<KaxTrackFlagLacing>(*this);
+       *(static_cast<EbmlUInteger *>(&myLacing)) = bEnable ? 1 : 0;
+}
+
+END_LIBMATROSKA_NAMESPACE