From: Steve Lhomme Date: Thu, 8 Apr 2010 16:26:35 +0000 (+0000) Subject: use the better constructor for v1 and v2 X-Git-Tag: release-0.9.0~16 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=72291474362e5fed6e0032b971be90204a8c2613;p=libmatroska use the better constructor for v1 and v2 git-svn-id: https://matroska.svn.sourceforge.net/svnroot/matroska/trunk/libmatroska@90 a6f86f6d-0131-4f8e-9e7b-e335508773d5 --- diff --git a/src/KaxAttached.cpp b/src/KaxAttached.cpp index 48c3ac1..c14a25d 100644 --- a/src/KaxAttached.cpp +++ b/src/KaxAttached.cpp @@ -1,72 +1,72 @@ -/**************************************************************************** -** libmatroska : parse Matroska files, see http://www.matroska.org/ -** -** -** -** 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 -*/ -#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(Context_KaxAttached) -{ - SetSizeLength(2); // mandatory min size support (for easier updating) (2^(7*2)-2 = 16Ko) -} - -END_LIBMATROSKA_NAMESPACE +/**************************************************************************** +** libmatroska : parse Matroska files, see http://www.matroska.org/ +** +** +** +** 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 +*/ +#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 diff --git a/src/KaxAttachments.cpp b/src/KaxAttachments.cpp index 6e1de34..e80983d 100644 --- a/src/KaxAttachments.cpp +++ b/src/KaxAttachments.cpp @@ -1,57 +1,57 @@ -/**************************************************************************** -** libmatroska : parse Matroska files, see http://www.matroska.org/ -** -** -** -** 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 -*/ -#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(Context_KaxAttachments) -{ - SetSizeLength(2); // mandatory min size support (for easier updating) (2^(7*2)-2 = 16Ko) -} - -END_LIBMATROSKA_NAMESPACE +/**************************************************************************** +** libmatroska : parse Matroska files, see http://www.matroska.org/ +** +** +** +** 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 +*/ +#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 diff --git a/src/KaxBlock.cpp b/src/KaxBlock.cpp index d982174..94b6066 100644 --- a/src/KaxBlock.cpp +++ b/src/KaxBlock.cpp @@ -1,1070 +1,1070 @@ -/**************************************************************************** -** libmatroska : parse Matroska files, see http://www.matroska.org/ -** -** -** -** Copyright (C) 2002-2010 Steve Lhomme. All rights reserved. -** -** This library is free software; you can redistribute it and/or -** modify it under the terms of the GNU Lesser General Public -** License as published by the Free Software Foundation; either -** version 2.1 of the License, or (at your option) any later version. -** -** This library is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** Lesser General Public License for more details. -** -** You should have received a copy of the GNU Lesser General Public -** License along with this library; if not, write to the Free Software -** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -** -** See http://www.matroska.org/license/lgpl/ for LGPL licensing information.** -** Contact license@matroska.org if any conditions of this licensing are -** not clear to you. -** -**********************************************************************/ - -/*! - \file - \version \$Id: KaxBlock.cpp 1265 2007-01-14 17:20:35Z mosu $ - \author Steve Lhomme - \author Julien Coloos -*/ -#include - -//#include - -#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::const_iterator Itr = ElementToClone.myBuffers.begin(); - std::vector::iterator myItr = myBuffers.begin(); - while (Itr != ElementToClone.myBuffers.end()) - { - *myItr = (*Itr)->Clone(); - Itr++; myItr++; - } -} - - -KaxBlockGroup::~KaxBlockGroup() -{ -//NOTE("KaxBlockGroup::~KaxBlockGroup"); -} - -KaxBlockGroup::KaxBlockGroup() - :EbmlMaster(Context_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; iSize() + (myBuffers[i]->Size() / 0xFF + 1)); - } - break; - case LACING_EBML: - SetSize_(GetSize() + myBuffers[0]->Size() + CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize())); - for (i=1; iSize() + CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size()), 0)); - } - break; - case LACING_FIXED: - for (i=0; iSize()); - } - 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; iSize(); - 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; iSize()) - 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; iBuffer(), 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> 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(*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(*this); - assert(ParentCluster != NULL); - theBlock.SetParent(*ParentCluster); - ParentTrack = &track; - bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing); - - KaxReferenceBlock & thePastRef = GetChild(*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(*this); - assert(ParentCluster != NULL); - theBlock.SetParent(*ParentCluster); - ParentTrack = &track; - bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing); - - KaxReferenceBlock & thePastRef = GetChild(*this); - thePastRef.SetReferencedBlock(PastBlock); - thePastRef.SetParentBlock(*this); - - KaxReferenceBlock & theFutureRef = AddNewChild(*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(*this); - assert(ParentCluster != NULL); - theBlock.SetParent(*ParentCluster); - ParentTrack = &track; - bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing); - - if (PastBlock != NULL) - { - KaxReferenceBlock & thePastRef = GetChild(*this); - thePastRef.SetReferencedBlock(PastBlock); - thePastRef.SetParentBlock(*this); - } - - if (ForwBlock != NULL) - { - KaxReferenceBlock & theFutureRef = AddNewChild(*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(this->FindElt(EBML_INFO(KaxBlock))); - return MyBlock.GlobalTimecode(); - -} - -uint16 KaxBlockGroup::TrackNumber() const -{ - KaxInternalBlock & MyBlock = *static_cast(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(FindFirstElt(EBML_INFO(KaxReferenceBlock))); - if (MyBlockAdds != NULL) { - Result++; - while ((MyBlockAdds = static_cast(FindNextElt(*MyBlockAdds))) != NULL) - { - Result++; - } - } - return Result; -} - -const KaxReferenceBlock & KaxBlockGroup::Reference(unsigned int Index) const -{ - KaxReferenceBlock * MyBlockAdds = static_cast(FindFirstElt(EBML_INFO(KaxReferenceBlock))); - assert(MyBlockAdds != NULL); // call of a non existing reference - - while (Index != 0) { - MyBlockAdds = static_cast(FindNextElt(*MyBlockAdds)); - assert(MyBlockAdds != NULL); - Index--; - } - return *MyBlockAdds; -} - -void KaxBlockGroup::ReleaseFrames() -{ - KaxInternalBlock & MyBlock = *static_cast(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(FindFirstElt(EBML_INFO(KaxBlockDuration), true)); - *(static_cast(&myDuration)) = TimeLength / uint64(scale); -} - -bool KaxBlockGroup::GetBlockDuration(uint64 &TheTimecode) const -{ - KaxBlockDuration * myDuration = static_cast(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(*this); - return theBlock; -} - -void KaxBlockGroup::SetParent(KaxCluster & aParentCluster) { - ParentCluster = &aParentCluster; - KaxBlock & theBlock = GetChild(*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 +/**************************************************************************** +** libmatroska : parse Matroska files, see http://www.matroska.org/ +** +** +** +** Copyright (C) 2002-2010 Steve Lhomme. All rights reserved. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this library; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +** +** See http://www.matroska.org/license/lgpl/ for LGPL licensing information.** +** Contact license@matroska.org if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/*! + \file + \version \$Id: KaxBlock.cpp 1265 2007-01-14 17:20:35Z mosu $ + \author Steve Lhomme + \author Julien Coloos +*/ +#include + +//#include + +#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::const_iterator Itr = ElementToClone.myBuffers.begin(); + std::vector::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; iSize() + (myBuffers[i]->Size() / 0xFF + 1)); + } + break; + case LACING_EBML: + SetSize_(GetSize() + myBuffers[0]->Size() + CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize())); + for (i=1; iSize() + CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size()), 0)); + } + break; + case LACING_FIXED: + for (i=0; iSize()); + } + 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; iSize(); + 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; iSize()) - 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; iBuffer(), 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> 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(*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(*this); + assert(ParentCluster != NULL); + theBlock.SetParent(*ParentCluster); + ParentTrack = &track; + bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing); + + KaxReferenceBlock & thePastRef = GetChild(*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(*this); + assert(ParentCluster != NULL); + theBlock.SetParent(*ParentCluster); + ParentTrack = &track; + bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing); + + KaxReferenceBlock & thePastRef = GetChild(*this); + thePastRef.SetReferencedBlock(PastBlock); + thePastRef.SetParentBlock(*this); + + KaxReferenceBlock & theFutureRef = AddNewChild(*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(*this); + assert(ParentCluster != NULL); + theBlock.SetParent(*ParentCluster); + ParentTrack = &track; + bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing); + + if (PastBlock != NULL) + { + KaxReferenceBlock & thePastRef = GetChild(*this); + thePastRef.SetReferencedBlock(PastBlock); + thePastRef.SetParentBlock(*this); + } + + if (ForwBlock != NULL) + { + KaxReferenceBlock & theFutureRef = AddNewChild(*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(this->FindElt(EBML_INFO(KaxBlock))); + return MyBlock.GlobalTimecode(); + +} + +uint16 KaxBlockGroup::TrackNumber() const +{ + KaxInternalBlock & MyBlock = *static_cast(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(FindFirstElt(EBML_INFO(KaxReferenceBlock))); + if (MyBlockAdds != NULL) { + Result++; + while ((MyBlockAdds = static_cast(FindNextElt(*MyBlockAdds))) != NULL) + { + Result++; + } + } + return Result; +} + +const KaxReferenceBlock & KaxBlockGroup::Reference(unsigned int Index) const +{ + KaxReferenceBlock * MyBlockAdds = static_cast(FindFirstElt(EBML_INFO(KaxReferenceBlock))); + assert(MyBlockAdds != NULL); // call of a non existing reference + + while (Index != 0) { + MyBlockAdds = static_cast(FindNextElt(*MyBlockAdds)); + assert(MyBlockAdds != NULL); + Index--; + } + return *MyBlockAdds; +} + +void KaxBlockGroup::ReleaseFrames() +{ + KaxInternalBlock & MyBlock = *static_cast(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(FindFirstElt(EBML_INFO(KaxBlockDuration), true)); + *(static_cast(&myDuration)) = TimeLength / uint64(scale); +} + +bool KaxBlockGroup::GetBlockDuration(uint64 &TheTimecode) const +{ + KaxBlockDuration * myDuration = static_cast(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(*this); + return theBlock; +} + +void KaxBlockGroup::SetParent(KaxCluster & aParentCluster) { + ParentCluster = &aParentCluster; + KaxBlock & theBlock = GetChild(*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 diff --git a/src/KaxCluster.cpp b/src/KaxCluster.cpp index f292b28..d866c9b 100644 --- a/src/KaxCluster.cpp +++ b/src/KaxCluster.cpp @@ -1,329 +1,329 @@ -/**************************************************************************** -** libmatroska : parse Matroska files, see http://www.matroska.org/ -** -** -** -** Copyright (C) 2002-2010 Steve Lhomme. All rights reserved. -** -** This library is free software; you can redistribute it and/or -** modify it under the terms of the GNU Lesser General Public -** License as published by the Free Software Foundation; either -** version 2.1 of the License, or (at your option) any later version. -** -** This library is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** Lesser General Public License for more details. -** -** You should have received a copy of the GNU Lesser General Public -** License along with this library; if not, write to the Free Software -** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -** -** See http://www.matroska.org/license/lgpl/ for LGPL licensing information.** -** Contact license@matroska.org if any conditions of this licensing are -** not clear to you. -** -**********************************************************************/ - -/*! - \file - \version \$Id: KaxCluster.cpp 1228 2005-10-14 19:36:51Z robux4 $ - \author Steve Lhomme -*/ -#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(Context_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(*Itr)->SetParent(*this); - } else if (EbmlId(**Itr) == EBML_ID(KaxBlock)) { - static_cast(*Itr)->SetParent(*this); -#if MATROSKA_VERSION >= 2 - } else if (EbmlId(**Itr) == EBML_ID(KaxBlockVirtual)) { - static_cast(*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(this->FindElt(EBML_INFO(KaxClusterTimecode))); - *static_cast(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(ParentSegment->FindElt(EBML_INFO(KaxTracks))); - for (TrkIndex = 0; TrkIndex < MyTracks.ListSize(); TrkIndex++) { - if (EbmlId(*MyTracks[TrkIndex]) == EBML_ID(KaxTrackEntry)) - { - KaxTrackEntry & entry = *static_cast(MyTracks[TrkIndex]); - uint32 tracknum = entry.TrackNumber(); - for (Index = 0; Index < ListSize(); Index++) { - if (EbmlId(*(*this)[Index]) == EBML_ID(KaxBlockGroup)) { - KaxBlockGroup & group = *static_cast((*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(this->FindFirstElt(EBML_INFO(KaxClusterSilentTracks))); - assert(SilentTracks != NULL); // the flag bSilentTracksUsed should be set when creating the Cluster - KaxClusterSilentTrackNumber * trackelt = static_cast(SilentTracks->AddNewElt(EBML_INFO(KaxClusterSilentTrackNumber))); - *static_cast(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((*this)[Index])); - } - } - } else { - // new school, using KaxBlockBlob - for (Index = 0; Index= 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(ParentSegment->FindElt(EBML_INFO(KaxTracks))); - for (TrkIndex = 0; TrkIndex < MyTracks.ListSize(); TrkIndex++) { - if (EbmlId(*MyTracks[TrkIndex]) == EBML_ID(KaxTrackEntry)) - { - KaxTrackEntry & entry = *static_cast(MyTracks[TrkIndex]); - uint32 tracknum = entry.TrackNumber(); - for (Index = 0; Index(this->FindFirstElt(EBML_INFO(KaxClusterSilentTracks))); - assert(SilentTracks != NULL); // the flag bSilentTracksUsed should be set when creating the Cluster - KaxClusterSilentTrackNumber * trackelt = static_cast(SilentTracks->AddNewElt(EBML_INFO(KaxClusterSilentTrackNumber))); - *static_cast(trackelt) = tracknum; - } - } - } - } - - Result = EbmlMaster::Render(output, bSaveDefault); - - // For all Blocks add their position on the CueEntry - for (Index = 0; Index= int16(0x8000) && TimecodeDelay <= int16(0x7FFF)); - return int16(TimecodeDelay); -} - -uint64 KaxCluster::GetBlockGlobalTimecode(int16 GlobalSavedTimecode) -{ - if (!bFirstFrameInside) { - KaxClusterTimecode * Timecode = static_cast(this->FindElt(EBML_INFO(KaxClusterTimecode))); - assert (bFirstFrameInside); // use the InitTimecode() hack for now - MinTimecode = MaxTimecode = PreviousTimecode = *static_cast(Timecode); - bFirstFrameInside = true; - bPreviousTimecodeIsSet = true; - } - return int64(GlobalSavedTimecode * GlobalTimecodeScale()) + GlobalTimecode(); -} - -KaxBlockGroup & KaxCluster::GetNewBlock() -{ - KaxBlockGroup & MyBlock = AddNewChild(*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((*this)[Index])->ReleaseFrames(); - } - } -} - -uint64 KaxCluster::GetPosition() const -{ - assert(ParentSegment != NULL); - return ParentSegment->GetRelativePosition(*this); -} - -END_LIBMATROSKA_NAMESPACE +/**************************************************************************** +** libmatroska : parse Matroska files, see http://www.matroska.org/ +** +** +** +** Copyright (C) 2002-2010 Steve Lhomme. All rights reserved. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this library; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +** +** See http://www.matroska.org/license/lgpl/ for LGPL licensing information.** +** Contact license@matroska.org if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/*! + \file + \version \$Id: KaxCluster.cpp 1228 2005-10-14 19:36:51Z robux4 $ + \author Steve Lhomme +*/ +#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(*Itr)->SetParent(*this); + } else if (EbmlId(**Itr) == EBML_ID(KaxBlock)) { + static_cast(*Itr)->SetParent(*this); +#if MATROSKA_VERSION >= 2 + } else if (EbmlId(**Itr) == EBML_ID(KaxBlockVirtual)) { + static_cast(*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(this->FindElt(EBML_INFO(KaxClusterTimecode))); + *static_cast(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(ParentSegment->FindElt(EBML_INFO(KaxTracks))); + for (TrkIndex = 0; TrkIndex < MyTracks.ListSize(); TrkIndex++) { + if (EbmlId(*MyTracks[TrkIndex]) == EBML_ID(KaxTrackEntry)) + { + KaxTrackEntry & entry = *static_cast(MyTracks[TrkIndex]); + uint32 tracknum = entry.TrackNumber(); + for (Index = 0; Index < ListSize(); Index++) { + if (EbmlId(*(*this)[Index]) == EBML_ID(KaxBlockGroup)) { + KaxBlockGroup & group = *static_cast((*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(this->FindFirstElt(EBML_INFO(KaxClusterSilentTracks))); + assert(SilentTracks != NULL); // the flag bSilentTracksUsed should be set when creating the Cluster + KaxClusterSilentTrackNumber * trackelt = static_cast(SilentTracks->AddNewElt(EBML_INFO(KaxClusterSilentTrackNumber))); + *static_cast(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((*this)[Index])); + } + } + } else { + // new school, using KaxBlockBlob + for (Index = 0; Index= 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(ParentSegment->FindElt(EBML_INFO(KaxTracks))); + for (TrkIndex = 0; TrkIndex < MyTracks.ListSize(); TrkIndex++) { + if (EbmlId(*MyTracks[TrkIndex]) == EBML_ID(KaxTrackEntry)) + { + KaxTrackEntry & entry = *static_cast(MyTracks[TrkIndex]); + uint32 tracknum = entry.TrackNumber(); + for (Index = 0; Index(this->FindFirstElt(EBML_INFO(KaxClusterSilentTracks))); + assert(SilentTracks != NULL); // the flag bSilentTracksUsed should be set when creating the Cluster + KaxClusterSilentTrackNumber * trackelt = static_cast(SilentTracks->AddNewElt(EBML_INFO(KaxClusterSilentTrackNumber))); + *static_cast(trackelt) = tracknum; + } + } + } + } + + Result = EbmlMaster::Render(output, bSaveDefault); + + // For all Blocks add their position on the CueEntry + for (Index = 0; Index= int16(0x8000) && TimecodeDelay <= int16(0x7FFF)); + return int16(TimecodeDelay); +} + +uint64 KaxCluster::GetBlockGlobalTimecode(int16 GlobalSavedTimecode) +{ + if (!bFirstFrameInside) { + KaxClusterTimecode * Timecode = static_cast(this->FindElt(EBML_INFO(KaxClusterTimecode))); + assert (bFirstFrameInside); // use the InitTimecode() hack for now + MinTimecode = MaxTimecode = PreviousTimecode = *static_cast(Timecode); + bFirstFrameInside = true; + bPreviousTimecodeIsSet = true; + } + return int64(GlobalSavedTimecode * GlobalTimecodeScale()) + GlobalTimecode(); +} + +KaxBlockGroup & KaxCluster::GetNewBlock() +{ + KaxBlockGroup & MyBlock = AddNewChild(*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((*this)[Index])->ReleaseFrames(); + } + } +} + +uint64 KaxCluster::GetPosition() const +{ + assert(ParentSegment != NULL); + return ParentSegment->GetRelativePosition(*this); +} + +END_LIBMATROSKA_NAMESPACE diff --git a/src/KaxSegment.cpp b/src/KaxSegment.cpp index bbd020a..39eab37 100644 --- a/src/KaxSegment.cpp +++ b/src/KaxSegment.cpp @@ -1,109 +1,109 @@ -/**************************************************************************** -** libmatroska : parse Matroska files, see http://www.matroska.org/ -** -** -** -** 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 -*/ -#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(KaxSegment_Context) -{ - 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(*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 +/**************************************************************************** +** libmatroska : parse Matroska files, see http://www.matroska.org/ +** +** +** +** 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 +*/ +#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(*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 diff --git a/src/KaxTracks.cpp b/src/KaxTracks.cpp index 0ca2b32..f6d3be6 100644 --- a/src/KaxTracks.cpp +++ b/src/KaxTracks.cpp @@ -1,99 +1,99 @@ -/**************************************************************************** -** libmatroska : parse Matroska files, see http://www.matroska.org/ -** -** -** -** 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 -*/ -#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(Context_KaxTrackEntry) - ,bGlobalTimecodeScaleIsSet(false) -{} - -void KaxTrackEntry::EnableLacing(bool bEnable) -{ - KaxTrackFlagLacing & myLacing = GetChild(*this); - *(static_cast(&myLacing)) = bEnable ? 1 : 0; -} - -END_LIBMATROSKA_NAMESPACE +/**************************************************************************** +** libmatroska : parse Matroska files, see http://www.matroska.org/ +** +** +** +** 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 +*/ +#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(*this); + *(static_cast(&myLacing)) = bEnable ? 1 : 0; +} + +END_LIBMATROSKA_NAMESPACE