filepos_t KaxInternalBlock::UpdateSize(bool bSaveDefault, bool bForceRender) { LacingType LacingHere; assert(EbmlBinary::GetBuffer() == NULL); // Data is not used for KaxInternalBlock assert(TrackNumber < 0x4000); // no more allowed for the moment unsigned int i; // compute the final size of the data switch (myBuffers.size()) { case 0: SetSize_(0); break; case 1: SetSize_(4 + myBuffers[0]->Size()); break; default: SetSize_(4 + 1); // 1 for the lacing head if (mLacing == LACING_AUTO) LacingHere = GetBestLacingType(); else LacingHere = mLacing; switch (LacingHere) { case LACING_XIPH: for (i=0; i<myBuffers.size()-1; i++) { SetSize_(GetSize() + myBuffers[i]->Size() + (myBuffers[i]->Size() / 0xFF + 1)); } break; case LACING_EBML: SetSize_(GetSize() + myBuffers[0]->Size() + CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize())); for (i=1; i<myBuffers.size()-1; i++) { SetSize_(GetSize() + myBuffers[i]->Size() + CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size()), 0)); } break; case LACING_FIXED: for (i=0; i<myBuffers.size()-1; i++) { SetSize_(GetSize() + myBuffers[i]->Size()); } break; default: assert(0); } // Size of the last frame (not in lace) SetSize_(GetSize() + myBuffers[i]->Size()); break; } if (TrackNumber >= 0x80) SetSize_(GetSize() + 1); // the size will be coded with one more octet return GetSize(); }
uint64 EbmlVoid::Overwrite(const EbmlElement & EltToVoid, IOCallback & output, bool ComeBackAfterward, bool bWithDefault) { // EltToVoid.UpdateSize(bWithDefault); if (EltToVoid.GetElementPosition() == 0) { // this element has never been written return 0; } if (EltToVoid.GetSize() + EltToVoid.HeadSize() <2) { // the element can't be written here ! return 0; } uint64 CurrentPosition = output.getFilePointer(); output.setFilePointer(EltToVoid.GetElementPosition()); // compute the size of the voided data based on the original one SetSize(EltToVoid.GetSize() + EltToVoid.HeadSize() - 1); // 1 for the ID SetSize(GetSize() - CodedSizeLength(GetSize(), GetSizeLength(), IsFiniteSize())); // make sure we handle even the strange cases //uint32 A1 = GetSize() + HeadSize(); //uint32 A2 = EltToVoid.GetSize() + EltToVoid.HeadSize(); if (GetSize() + HeadSize() != EltToVoid.GetSize() + EltToVoid.HeadSize()) { SetSize(GetSize()-1); SetSizeLength(CodedSizeLength(GetSize(), GetSizeLength(), IsFiniteSize()) + 1); } if (GetSize() != 0) { RenderHead(output, false, bWithDefault); // the rest of the data is not rewritten } if (ComeBackAfterward) { output.setFilePointer(CurrentPosition); } return EltToVoid.GetSize() + EltToVoid.HeadSize(); }
uint64 EbmlVoid::ReplaceWith(EbmlElement & EltToReplaceWith, IOCallback & output, bool ComeBackAfterward, bool bWithDefault) { EltToReplaceWith.UpdateSize(bWithDefault); if (HeadSize() + GetSize() < EltToReplaceWith.GetSize() + EltToReplaceWith.HeadSize()) { // the element can't be written here ! return INVALID_FILEPOS_T; } if (HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() == 1) { // there is not enough space to put a filling element return INVALID_FILEPOS_T; } uint64 CurrentPosition = output.getFilePointer(); output.setFilePointer(GetElementPosition()); EltToReplaceWith.Render(output, bWithDefault); if (HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() > 1) { // fill the rest with another void element EbmlVoid aTmp; aTmp.SetSize_(HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() - 1); // 1 is the length of the Void ID int HeadBefore = aTmp.HeadSize(); aTmp.SetSize_(aTmp.GetSize() - CodedSizeLength(aTmp.GetSize(), aTmp.GetSizeLength(), aTmp.IsFiniteSize())); int HeadAfter = aTmp.HeadSize(); if (HeadBefore != HeadAfter) { aTmp.SetSizeLength(CodedSizeLength(aTmp.GetSize(), aTmp.GetSizeLength(), aTmp.IsFiniteSize()) - (HeadAfter - HeadBefore)); } aTmp.RenderHead(output, false, bWithDefault); // the rest of the data is not rewritten } if (ComeBackAfterward) { output.setFilePointer(CurrentPosition); } return GetSize() + HeadSize(); }
/*! \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; }
/*! \todo more optimisation is possible (render the Block head and don't copy the buffer in memory, care should be taken with the allocation of Data) \todo the actual timecode to write should be retrieved from the Cluster from here */ filepos_t KaxInternalBlock::RenderData(IOCallback & output, bool bForceRender, bool bSaveDefault) { if (myBuffers.size() == 0) { return 0; } else { assert(TrackNumber < 0x4000); binary BlockHead[5], *cursor = BlockHead; unsigned int i; if (myBuffers.size() == 1) { SetSize_(4); mLacing = LACING_NONE; } else { if (mLacing == LACING_NONE) mLacing = LACING_EBML; // supposedly the best of all SetSize_(4 + 1); // 1 for the lacing head (number of laced elements) } if (TrackNumber > 0x80) SetSize_(GetSize() + 1); // write Block Head if (TrackNumber < 0x80) { *cursor++ = TrackNumber | 0x80; // set the first bit to 1 } else { *cursor++ = (TrackNumber >> 8) | 0x40; // set the second bit to 1 *cursor++ = TrackNumber & 0xFF; } assert(ParentCluster != NULL); int16 ActualTimecode = ParentCluster->GetBlockLocalTimecode(Timecode); big_int16 b16(ActualTimecode); b16.Fill(cursor); cursor += 2; *cursor = 0; // flags if (mLacing == LACING_AUTO) { mLacing = GetBestLacingType(); } // invisible flag if (mInvisible) *cursor = 0x08; if (bIsSimple) { if (bIsKeyframe) *cursor |= 0x80; if (bIsDiscardable) *cursor |= 0x01; } // lacing flag switch (mLacing) { case LACING_XIPH: *cursor++ |= 0x02; break; case LACING_EBML: *cursor++ |= 0x06; break; case LACING_FIXED: *cursor++ |= 0x04; break; case LACING_NONE: break; default: assert(0); } output.writeFully(BlockHead, 4 + ((TrackNumber > 0x80) ? 1 : 0)); binary tmpValue; switch (mLacing) { case LACING_XIPH: // number of laces tmpValue = myBuffers.size()-1; output.writeFully(&tmpValue, 1); // set the size of each member in the lace for (i=0; i<myBuffers.size()-1; i++) { tmpValue = 0xFF; uint16 tmpSize = myBuffers[i]->Size(); while (tmpSize >= 0xFF) { output.writeFully(&tmpValue, 1); SetSize_(GetSize() + 1); tmpSize -= 0xFF; } tmpValue = binary(tmpSize); output.writeFully(&tmpValue, 1); SetSize_(GetSize() + 1); } break; case LACING_EBML: // number of laces tmpValue = myBuffers.size()-1; output.writeFully(&tmpValue, 1); { int64 _Size; int _CodedSize; binary _FinalHead[8]; // 64 bits max coded size _Size = myBuffers[0]->Size(); _CodedSize = CodedSizeLength(_Size, 0, IsFiniteSize()); // first size in the lace is not a signed CodedValueLength(_Size, _CodedSize, _FinalHead); output.writeFully(_FinalHead, _CodedSize); SetSize_(GetSize() + _CodedSize); // set the size of each member in the lace for (i=1; i<myBuffers.size()-1; i++) { _Size = int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size()); _CodedSize = CodedSizeLengthSigned(_Size, 0); CodedValueLengthSigned(_Size, _CodedSize, _FinalHead); output.writeFully(_FinalHead, _CodedSize); SetSize_(GetSize() + _CodedSize); } } break; case LACING_FIXED: // number of laces tmpValue = myBuffers.size()-1; output.writeFully(&tmpValue, 1); break; case LACING_NONE: break; default: assert(0); } // put the data of each frame for (i=0; i<myBuffers.size(); i++) { output.writeFully(myBuffers[i]->Buffer(), myBuffers[i]->Size()); SetSize_(GetSize() + myBuffers[i]->Size()); } } return GetSize(); }