1 /****************************************************************************
2 ** libmatroska : parse Matroska files, see http://www.matroska.org/
3 **
4 ** <file/class description>
5 **
6 ** Copyright (C) 2002-2010 Steve Lhomme. All rights reserved.
7 **
8 ** This library is free software; you can redistribute it and/or
9 ** modify it under the terms of the GNU Lesser General Public
10 ** License as published by the Free Software Foundation; either
11 ** version 2.1 of the License, or (at your option) any later version.
12 **
13 ** This library is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 ** Lesser General Public License for more details.
17 **
18 ** You should have received a copy of the GNU Lesser General Public
19 ** License along with this library; if not, write to the Free Software
20 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 **
22 ** See http://www.gnu.org/licenses/lgpl-2.1.html for LGPL licensing information.**
23 ** Contact license@matroska.org if any conditions of this licensing are
24 ** not clear to you.
25 **
26 **********************************************************************/
27
28 /*!
29 \file
30 \version \$Id: KaxBlock.cpp 1265 2007-01-14 17:20:35Z mosu $
31 \author Steve Lhomme <robux4 @ users.sf.net>
32 \author Julien Coloos <suiryc @ users.sf.net>
33 \author Moritz Bunkus <moritz@bunkus.org>
34 */
35 #include <cassert>
36
37 //#include <streams.h>
38
39 #include "ebml/MemReadIOCallback.h"
40 #include "ebml/SafeReadIOCallback.h"
41 #include "matroska/KaxBlock.h"
42 #include "matroska/KaxContexts.h"
43 #include "matroska/KaxBlockData.h"
44 #include "matroska/KaxCluster.h"
45 #include "matroska/KaxDefines.h"
46
47 START_LIBMATROSKA_NAMESPACE
48
Clone()49 DataBuffer * DataBuffer::Clone()
50 {
51 auto ClonedData = static_cast<binary *>(malloc(mySize * sizeof(binary)));
52 assert(ClonedData != nullptr);
53 memcpy(ClonedData, myBuffer ,mySize );
54
55 auto result = new SimpleDataBuffer(ClonedData, mySize, 0);
56 result->bValidValue = bValidValue;
57 return result;
58 }
59
SimpleDataBuffer(const SimpleDataBuffer & ToClone)60 SimpleDataBuffer::SimpleDataBuffer(const SimpleDataBuffer & ToClone)
61 :DataBuffer(static_cast<binary *>(malloc(ToClone.mySize * sizeof(binary))), ToClone.mySize, myFreeBuffer)
62 {
63 assert(myBuffer != nullptr);
64 memcpy(myBuffer, ToClone.myBuffer ,mySize );
65 bValidValue = ToClone.bValidValue;
66 }
67
ValidateSize() const68 bool KaxInternalBlock::ValidateSize() const
69 {
70 return (GetSize() >= 4); /// for the moment
71 }
72
~KaxInternalBlock()73 KaxInternalBlock::~KaxInternalBlock()
74 {
75 ReleaseFrames();
76 }
77
KaxInternalBlock(const KaxInternalBlock & ElementToClone)78 KaxInternalBlock::KaxInternalBlock(const KaxInternalBlock & ElementToClone)
79 :EbmlBinary(ElementToClone)
80 ,myBuffers(ElementToClone.myBuffers.size())
81 ,Timecode(ElementToClone.Timecode)
82 ,LocalTimecode(ElementToClone.LocalTimecode)
83 ,bLocalTimecodeUsed(ElementToClone.bLocalTimecodeUsed)
84 ,TrackNumber(ElementToClone.TrackNumber)
85 ,ParentCluster(ElementToClone.ParentCluster) ///< \todo not exactly
86 {
87 // add a clone of the list
88 auto Itr = ElementToClone.myBuffers.begin();
89 auto myItr = myBuffers.begin();
90 while (Itr != ElementToClone.myBuffers.end()) {
91 *myItr = (*Itr)->Clone();
92 ++Itr; ++myItr;
93 }
94 }
95
96
97 /* KaxBlockGroup::~KaxBlockGroup()
98 {
99 //NOTE("KaxBlockGroup::~KaxBlockGroup");
100 } */
101
KaxBlockGroup(EBML_EXTRA_DEF)102 KaxBlockGroup::KaxBlockGroup(EBML_EXTRA_DEF)
103 :EbmlMaster(EBML_CLASS_SEMCONTEXT(KaxBlockGroup) EBML_DEF_SEP EBML_EXTRA_CALL)
104 ,ParentCluster(nullptr)
105 ,ParentTrack(nullptr)
106 {}
107
108 /*!
109 \todo handle flags
110 \todo hardcoded limit of the number of frames in a lace should be a parameter
111 \return true if more frames can be added to this Block
112 */
AddFrame(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,LacingType lacing,bool invisible)113 bool KaxInternalBlock::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing, bool invisible)
114 {
115 SetValueIsSet();
116 if (myBuffers.empty()) {
117 // first frame
118 Timecode = timecode;
119 TrackNumber = track.TrackNumber();
120 mInvisible = invisible;
121 mLacing = lacing;
122 }
123 myBuffers.push_back(&buffer);
124
125 // we don't allow more than 8 frames in a Block because the overhead improvement is minimal
126 if (myBuffers.size() >= 8 || lacing == LACING_NONE)
127 return false;
128
129 if (lacing == LACING_XIPH)
130 // decide wether a new frame can be added or not
131 // a frame in a lace is not efficient when the place necessary to code it in a lace is bigger
132 // than the size of a simple Block. That means more than 6 bytes (4 in struct + 2 for EBML) to code the size
133 return (buffer.Size() < 6*0xFF);
134
135 return true;
136 }
137
138 /*!
139 \return Returns the lacing type that produces the smallest footprint.
140 */
GetBestLacingType() const141 LacingType KaxInternalBlock::GetBestLacingType() const {
142 int XiphLacingSize, EbmlLacingSize, i;
143 bool SameSize = true;
144
145 if (myBuffers.size() <= 1)
146 return LACING_NONE;
147
148 XiphLacingSize = 1; // Number of laces is stored in 1 byte.
149 EbmlLacingSize = 1;
150 for (i = 0; i < static_cast<int>(myBuffers.size()) - 1; i++) {
151 if (myBuffers[i]->Size() != myBuffers[i + 1]->Size())
152 SameSize = false;
153 XiphLacingSize += myBuffers[i]->Size() / 255 + 1;
154 }
155 EbmlLacingSize += CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize());
156 for (i = 1; i < static_cast<int>(myBuffers.size()) - 1; i++)
157 EbmlLacingSize += CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i - 1]->Size()), 0);
158 if (SameSize)
159 return LACING_FIXED;
160 if (XiphLacingSize < EbmlLacingSize)
161 return LACING_XIPH;
162
163 return LACING_EBML;
164 }
165
UpdateSize(bool,bool)166 filepos_t KaxInternalBlock::UpdateSize(bool /* bSaveDefault */, bool /* bForceRender */)
167 {
168 LacingType LacingHere;
169 assert(EbmlBinary::GetBuffer() == nullptr); // Data is not used for KaxInternalBlock
170 assert(TrackNumber < 0x4000); // no more allowed for the moment
171 unsigned int i;
172
173 // compute the final size of the data
174 switch (myBuffers.size()) {
175 case 0:
176 SetSize_(0);
177 break;
178 case 1:
179 SetSize_(4 + myBuffers[0]->Size());
180 break;
181 default:
182 SetSize_(4 + 1); // 1 for the lacing head
183 if (mLacing == LACING_AUTO)
184 LacingHere = GetBestLacingType();
185 else
186 LacingHere = mLacing;
187 switch (LacingHere) {
188 case LACING_XIPH:
189 for (i=0; i<myBuffers.size()-1; i++) {
190 SetSize_(GetSize() + myBuffers[i]->Size() + (myBuffers[i]->Size() / 0xFF + 1));
191 }
192 break;
193 case LACING_EBML:
194 SetSize_(GetSize() + myBuffers[0]->Size() + CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize()));
195 for (i=1; i<myBuffers.size()-1; i++) {
196 SetSize_(GetSize() + myBuffers[i]->Size() + CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size()), 0));
197 }
198 break;
199 case LACING_FIXED:
200 for (i=0; i<myBuffers.size()-1; i++) {
201 SetSize_(GetSize() + myBuffers[i]->Size());
202 }
203 break;
204 default:
205 i = 0;
206 assert(0);
207 }
208 // Size of the last frame (not in lace)
209 SetSize_(GetSize() + myBuffers[i]->Size());
210 break;
211 }
212
213 if (TrackNumber >= 0x80)
214 SetSize_(GetSize() + 1); // the size will be coded with one more octet
215
216 return GetSize();
217 }
218
KaxBlockVirtual(const KaxBlockVirtual & ElementToClone)219 KaxBlockVirtual::KaxBlockVirtual(const KaxBlockVirtual & ElementToClone)
220 :EbmlBinary(ElementToClone)
221 ,Timecode(ElementToClone.Timecode)
222 ,TrackNumber(ElementToClone.TrackNumber)
223 ,ParentCluster(ElementToClone.ParentCluster) ///< \todo not exactly
224 {
225 SetBuffer(DataBlock,sizeof(DataBlock));
226 SetValueIsSet(false);
227 }
228
KaxBlockVirtual(EBML_EXTRA_DEF)229 KaxBlockVirtual::KaxBlockVirtual(EBML_EXTRA_DEF)
230 :EBML_DEF_BINARY(KaxBlockVirtual)EBML_DEF_SEP ParentCluster(nullptr)
231 {
232 SetBuffer(DataBlock,sizeof(DataBlock));
233 SetValueIsSet(false);
234 }
235
~KaxBlockVirtual()236 KaxBlockVirtual::~KaxBlockVirtual()
237 {
238 if(GetBuffer() == DataBlock)
239 SetBuffer( nullptr, 0 );
240 }
241
UpdateSize(bool,bool)242 filepos_t KaxBlockVirtual::UpdateSize(bool /* bSaveDefault */, bool /* bForceRender */)
243 {
244 assert(TrackNumber < 0x4000);
245 binary *cursor = EbmlBinary::GetBuffer();
246 // fill data
247 if (TrackNumber < 0x80) {
248 assert(GetSize() >= 4);
249 *cursor++ = TrackNumber | 0x80; // set the first bit to 1
250 } else {
251 assert(GetSize() >= 5);
252 *cursor++ = (TrackNumber >> 8) | 0x40; // set the second bit to 1
253 *cursor++ = TrackNumber & 0xFF;
254 }
255
256 assert(ParentCluster != nullptr);
257 int16 ActualTimecode = ParentCluster->GetBlockLocalTimecode(Timecode);
258 big_int16 b16(ActualTimecode);
259 b16.Fill(cursor);
260 cursor += 2;
261
262 *cursor++ = 0; // flags
263
264 return GetSize();
265 }
266
267 /*!
268 \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)
269 \todo the actual timecode to write should be retrieved from the Cluster from here
270 */
RenderData(IOCallback & output,bool,bool)271 filepos_t KaxInternalBlock::RenderData(IOCallback & output, bool /* bForceRender */, bool /* bSaveDefault */)
272 {
273 if (myBuffers.empty()) {
274 return 0;
275 } else {
276 assert(TrackNumber < 0x4000);
277 binary BlockHead[5], *cursor = BlockHead;
278 unsigned int i;
279
280 if (myBuffers.size() == 1) {
281 SetSize_(4);
282 mLacing = LACING_NONE;
283 } else {
284 if (mLacing == LACING_NONE)
285 mLacing = LACING_EBML; // supposedly the best of all
286 SetSize_(4 + 1); // 1 for the lacing head (number of laced elements)
287 }
288 if (TrackNumber >= 0x80)
289 SetSize_(GetSize() + 1);
290
291 // write Block Head
292 if (TrackNumber < 0x80) {
293 *cursor++ = TrackNumber | 0x80; // set the first bit to 1
294 } else {
295 *cursor++ = (TrackNumber >> 8) | 0x40; // set the second bit to 1
296 *cursor++ = TrackNumber & 0xFF;
297 }
298
299 assert(ParentCluster != nullptr);
300 int16 ActualTimecode = ParentCluster->GetBlockLocalTimecode(Timecode);
301 big_int16 b16(ActualTimecode);
302 b16.Fill(cursor);
303 cursor += 2;
304
305 *cursor = 0; // flags
306
307 if (mLacing == LACING_AUTO) {
308 mLacing = GetBestLacingType();
309 }
310
311 // invisible flag
312 if (mInvisible)
313 *cursor = 0x08;
314
315 if (bIsSimple) {
316 if (bIsKeyframe)
317 *cursor |= 0x80;
318 if (bIsDiscardable)
319 *cursor |= 0x01;
320 }
321
322 // lacing flag
323 switch (mLacing) {
324 case LACING_XIPH:
325 *cursor++ |= 0x02;
326 break;
327 case LACING_EBML:
328 *cursor++ |= 0x06;
329 break;
330 case LACING_FIXED:
331 *cursor++ |= 0x04;
332 break;
333 case LACING_NONE:
334 break;
335 default:
336 assert(0);
337 }
338
339 output.writeFully(BlockHead, 4 + ((TrackNumber >= 0x80) ? 1 : 0));
340
341 binary tmpValue;
342 switch (mLacing) {
343 case LACING_XIPH:
344 // number of laces
345 tmpValue = myBuffers.size()-1;
346 output.writeFully(&tmpValue, 1);
347
348 // set the size of each member in the lace
349 for (i=0; i<myBuffers.size()-1; i++) {
350 tmpValue = 0xFF;
351 uint16 tmpSize = myBuffers[i]->Size();
352 while (tmpSize >= 0xFF) {
353 output.writeFully(&tmpValue, 1);
354 SetSize_(GetSize() + 1);
355 tmpSize -= 0xFF;
356 }
357 tmpValue = binary(tmpSize);
358 output.writeFully(&tmpValue, 1);
359 SetSize_(GetSize() + 1);
360 }
361 break;
362 case LACING_EBML:
363 // number of laces
364 tmpValue = myBuffers.size()-1;
365 output.writeFully(&tmpValue, 1);
366 {
367 int64 _Size;
368 int _CodedSize;
369 binary _FinalHead[8]; // 64 bits max coded size
370
371 _Size = myBuffers[0]->Size();
372
373 _CodedSize = CodedSizeLength(_Size, 0, IsFiniteSize());
374
375 // first size in the lace is not a signed
376 CodedValueLength(_Size, _CodedSize, _FinalHead);
377 output.writeFully(_FinalHead, _CodedSize);
378 SetSize_(GetSize() + _CodedSize);
379
380 // set the size of each member in the lace
381 for (i=1; i<myBuffers.size()-1; i++) {
382 _Size = int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size());
383 _CodedSize = CodedSizeLengthSigned(_Size, 0);
384 CodedValueLengthSigned(_Size, _CodedSize, _FinalHead);
385 output.writeFully(_FinalHead, _CodedSize);
386 SetSize_(GetSize() + _CodedSize);
387 }
388 }
389 break;
390 case LACING_FIXED:
391 // number of laces
392 tmpValue = myBuffers.size()-1;
393 output.writeFully(&tmpValue, 1);
394 break;
395 case LACING_NONE:
396 break;
397 default:
398 assert(0);
399 }
400
401 // put the data of each frame
402 for (i=0; i<myBuffers.size(); i++) {
403 output.writeFully(myBuffers[i]->Buffer(), myBuffers[i]->Size());
404 SetSize_(GetSize() + myBuffers[i]->Size());
405 }
406 }
407
408 return GetSize();
409 }
410
ReadInternalHead(IOCallback & input)411 uint64 KaxInternalBlock::ReadInternalHead(IOCallback & input)
412 {
413 binary Buffer[5], *cursor = Buffer;
414 uint64 Result = input.read(cursor, 4);
415 if (Result != 4)
416 return Result;
417
418 // update internal values
419 TrackNumber = *cursor++;
420 if ((TrackNumber & 0x80) == 0) {
421 // there is extra data
422 if ((TrackNumber & 0x40) == 0) {
423 // We don't support track numbers that large !
424 return Result;
425 }
426 Result += input.read(&Buffer[4], 1);
427 TrackNumber = (TrackNumber & 0x3F) << 8;
428 TrackNumber += *cursor++;
429 } else {
430 TrackNumber &= 0x7F;
431 }
432
433
434 big_int16 b16;
435 b16.Eval(cursor);
436 assert(ParentCluster != nullptr);
437 Timecode = ParentCluster->GetBlockGlobalTimecode(int16(b16));
438 bLocalTimecodeUsed = false;
439 cursor += 2;
440
441 return Result;
442 }
443
444 /*!
445 \todo better zero copy handling
446 */
ReadData(IOCallback & input,ScopeMode ReadFully)447 filepos_t KaxInternalBlock::ReadData(IOCallback & input, ScopeMode ReadFully)
448 {
449 filepos_t Result;
450
451 FirstFrameLocation = input.getFilePointer(); // will be updated accordingly below
452
453 SetValueIsSet(false);
454
455 try {
456 if (ReadFully == SCOPE_ALL_DATA) {
457 Result = EbmlBinary::ReadData(input, ReadFully);
458 if (Result != GetSize())
459 throw SafeReadIOCallback::EndOfStreamX(GetSize() - Result);
460
461 binary *BufferStart = EbmlBinary::GetBuffer();
462
463 SafeReadIOCallback Mem(*this);
464 uint8 BlockHeadSize = 4;
465
466 // update internal values
467 TrackNumber = Mem.GetUInt8();
468 if ((TrackNumber & 0x80) == 0) {
469 // there is extra data
470 if ((TrackNumber & 0x40) == 0) {
471 // We don't support track numbers that large !
472 throw SafeReadIOCallback::EndOfStreamX(0);
473 }
474 TrackNumber = (TrackNumber & 0x3F) << 8;
475 TrackNumber += Mem.GetUInt8();
476 BlockHeadSize++;
477 } else {
478 TrackNumber &= 0x7F;
479 }
480
481 LocalTimecode = int16(Mem.GetUInt16BE());
482 bLocalTimecodeUsed = true;
483
484 uint8 Flags = Mem.GetUInt8();
485 if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) {
486 bIsKeyframe = (Flags & 0x80) != 0;
487 bIsDiscardable = (Flags & 0x01) != 0;
488 }
489 mInvisible = (Flags & 0x08) >> 3;
490 mLacing = LacingType((Flags & 0x06) >> 1);
491
492 // put all Frames in the list
493 if (mLacing == LACING_NONE) {
494 FirstFrameLocation += Mem.GetPosition();
495 auto soloFrame = new DataBuffer(BufferStart + Mem.GetPosition(), GetSize() - BlockHeadSize);
496 myBuffers.push_back(soloFrame);
497 SizeList.resize(1);
498 SizeList[0] = GetSize() - BlockHeadSize;
499 } else {
500 // read the number of frames in the lace
501 uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame
502 uint8 FrameNum = Mem.GetUInt8(); // number of frames in the lace - 1
503 // read the list of frame sizes
504 uint8 Index;
505 int32 FrameSize;
506 uint32 SizeRead;
507 uint64 SizeUnknown;
508
509 SizeList.resize(FrameNum + 1);
510
511 switch (mLacing) {
512 case LACING_XIPH:
513 for (Index=0; Index<FrameNum; Index++) {
514 // get the size of the frame
515 FrameSize = 0;
516 uint8 Value;
517 do {
518 Value = Mem.GetUInt8();
519 FrameSize += Value;
520 LastBufferSize--;
521 } while (Value == 0xFF);
522 SizeList[Index] = FrameSize;
523 LastBufferSize -= FrameSize;
524 }
525 SizeList[Index] = LastBufferSize;
526 break;
527 case LACING_EBML:
528 SizeRead = LastBufferSize;
529 FrameSize = ReadCodedSizeValue(BufferStart + Mem.GetPosition(), SizeRead, SizeUnknown);
530 if (!FrameSize || (static_cast<uint32>(FrameSize + SizeRead) > LastBufferSize))
531 throw SafeReadIOCallback::EndOfStreamX(SizeRead);
532 SizeList[0] = FrameSize;
533 Mem.Skip(SizeRead);
534 LastBufferSize -= FrameSize + SizeRead;
535
536 for (Index=1; Index<FrameNum; Index++) {
537 // get the size of the frame
538 SizeRead = LastBufferSize;
539 FrameSize += ReadCodedSizeSignedValue(BufferStart + Mem.GetPosition(), SizeRead, SizeUnknown);
540 if (!FrameSize || (static_cast<uint32>(FrameSize + SizeRead) > LastBufferSize))
541 throw SafeReadIOCallback::EndOfStreamX(SizeRead);
542 SizeList[Index] = FrameSize;
543 Mem.Skip(SizeRead);
544 LastBufferSize -= FrameSize + SizeRead;
545 }
546 if (Index <= FrameNum) // Safety check if FrameNum == 0
547 SizeList[Index] = LastBufferSize;
548 break;
549 case LACING_FIXED:
550 for (Index=0; Index<=FrameNum; Index++) {
551 // get the size of the frame
552 SizeList[Index] = LastBufferSize / (FrameNum + 1);
553 }
554 break;
555 default: // other lacing not supported
556 assert(0);
557 }
558
559 FirstFrameLocation += Mem.GetPosition();
560
561 for (Index=0; Index<=FrameNum; Index++) {
562 auto lacedFrame = new DataBuffer(BufferStart + Mem.GetPosition(), SizeList[Index]);
563 myBuffers.push_back(lacedFrame);
564 Mem.Skip(SizeList[Index]);
565 }
566 }
567
568 binary *BufferEnd = BufferStart + GetSize();
569 size_t NumFrames = myBuffers.size();
570
571 // Sanity checks for frame pointers and boundaries.
572 for (size_t Index = 0; Index < NumFrames; ++Index) {
573 binary *FrameStart = myBuffers[Index]->Buffer();
574 binary *FrameEnd = FrameStart + myBuffers[Index]->Size();
575 binary *ExpectedEnd = (Index + 1) < NumFrames ? myBuffers[Index + 1]->Buffer() : BufferEnd;
576
577 if ((FrameStart < BufferStart) || (FrameEnd > BufferEnd) || (FrameEnd != ExpectedEnd))
578 throw SafeReadIOCallback::EndOfStreamX(0);
579 }
580
581 SetValueIsSet();
582 } else if (ReadFully == SCOPE_PARTIAL_DATA) {
583 binary _TempHead[5];
584 Result = input.read(_TempHead, 5);
585 if (Result != 5)
586 throw SafeReadIOCallback::EndOfStreamX(0);
587 binary *cursor = _TempHead;
588 binary *_tmpBuf;
589 uint8 BlockHeadSize = 4;
590
591 // update internal values
592 TrackNumber = *cursor++;
593 if ((TrackNumber & 0x80) == 0) {
594 // there is extra data
595 if ((TrackNumber & 0x40) == 0) {
596 // We don't support track numbers that large !
597 return Result;
598 }
599 TrackNumber = (TrackNumber & 0x3F) << 8;
600 TrackNumber += *cursor++;
601 BlockHeadSize++;
602 } else {
603 TrackNumber &= 0x7F;
604 }
605
606 big_int16 b16;
607 b16.Eval(cursor);
608 LocalTimecode = int16(b16);
609 bLocalTimecodeUsed = true;
610 cursor += 2;
611
612 if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) {
613 bIsKeyframe = (*cursor & 0x80) != 0;
614 bIsDiscardable = (*cursor & 0x01) != 0;
615 }
616 mInvisible = (*cursor & 0x08) >> 3;
617 mLacing = LacingType((*cursor++ & 0x06) >> 1);
618 if (cursor == &_TempHead[4]) {
619 _TempHead[0] = _TempHead[4];
620 } else {
621 Result += input.read(_TempHead, 1);
622 }
623
624 FirstFrameLocation += cursor - _TempHead;
625
626 // put all Frames in the list
627 if (mLacing != LACING_NONE) {
628 // read the number of frames in the lace
629 const uint32 TotalLacedSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame
630 uint32 LastBufferSize = TotalLacedSize;
631 uint8 FrameNum = _TempHead[0]; // number of frames in the lace - 1
632 // read the list of frame sizes
633 uint8 Index;
634 uint32 FrameSize;
635 uint32 SizeRead;
636 uint64 SizeUnknown;
637
638 SizeList.resize(FrameNum + 1);
639
640 switch (mLacing) {
641 case LACING_XIPH:
642 for (Index=0; Index<FrameNum; Index++) {
643 // get the size of the frame
644 FrameSize = 0;
645 do {
646 Result += input.read(_TempHead, 1);
647 FrameSize += uint8(_TempHead[0]);
648 if (FrameSize > TotalLacedSize)
649 throw SafeReadIOCallback::EndOfStreamX(0);
650 LastBufferSize--;
651
652 FirstFrameLocation++;
653 } while (_TempHead[0] == 0xFF);
654
655 FirstFrameLocation++;
656 SizeList[Index] = FrameSize;
657 LastBufferSize -= FrameSize;
658 }
659 SizeList[Index] = LastBufferSize;
660 break;
661 case LACING_EBML:
662 SizeRead = LastBufferSize;
663 cursor = _tmpBuf = new binary[FrameNum*4]; /// \warning assume the mean size will be coded in less than 4 bytes
664 Result += input.read(cursor, FrameNum*4);
665 FrameSize = ReadCodedSizeValue(cursor, SizeRead, SizeUnknown);
666 if (FrameSize > TotalLacedSize)
667 throw SafeReadIOCallback::EndOfStreamX(0);
668 SizeList[0] = FrameSize;
669 cursor += SizeRead;
670 LastBufferSize -= FrameSize + SizeRead;
671
672 for (Index=1; Index<FrameNum; Index++) {
673 // get the size of the frame
674 SizeRead = LastBufferSize;
675 FrameSize += ReadCodedSizeSignedValue(cursor, SizeRead, SizeUnknown);
676 if (FrameSize > TotalLacedSize)
677 throw SafeReadIOCallback::EndOfStreamX(0);
678 SizeList[Index] = FrameSize;
679 cursor += SizeRead;
680 LastBufferSize -= FrameSize + SizeRead;
681 }
682
683 FirstFrameLocation += cursor - _tmpBuf;
684
685 SizeList[Index] = LastBufferSize;
686 delete [] _tmpBuf;
687 break;
688 case LACING_FIXED:
689 for (Index=0; Index<=FrameNum; Index++) {
690 // get the size of the frame
691 SizeList[Index] = LastBufferSize / (FrameNum + 1);
692 }
693 break;
694 default: // other lacing not supported
695 assert(0);
696 }
697 } else {
698 SizeList.resize(1);
699 SizeList[0] = GetSize() - BlockHeadSize;
700 }
701 SetValueIsSet(false);
702 Result = GetSize();
703 } else {
704 SetValueIsSet(false);
705 Result = GetSize();
706 }
707
708 } catch (SafeReadIOCallback::EndOfStreamX &) {
709 SetValueIsSet(false);
710
711 myBuffers.clear();
712 SizeList.clear();
713 Timecode = 0;
714 LocalTimecode = 0;
715 TrackNumber = 0;
716 bLocalTimecodeUsed = false;
717 FirstFrameLocation = 0;
718
719 return 0;
720 }
721
722 return Result;
723 }
724
AddFrame(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,LacingType lacing)725 bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing)
726 {
727 auto & theBlock = GetChild<KaxBlock>(*this);
728 assert(ParentCluster != nullptr);
729 theBlock.SetParent(*ParentCluster);
730 ParentTrack = &track;
731 return theBlock.AddFrame(track, timecode, buffer, lacing);
732 }
733
AddFrame(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,const KaxBlockGroup & PastBlock,LacingType lacing)734 bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, LacingType lacing)
735 {
736 // assert(past_timecode < 0);
737
738 auto & theBlock = GetChild<KaxBlock>(*this);
739 assert(ParentCluster != nullptr);
740 theBlock.SetParent(*ParentCluster);
741 ParentTrack = &track;
742 bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);
743
744 auto & thePastRef = GetChild<KaxReferenceBlock>(*this);
745 thePastRef.SetReferencedBlock(PastBlock);
746 thePastRef.SetParentBlock(*this);
747
748 return bRes;
749 }
750
AddFrame(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,const KaxBlockGroup & PastBlock,const KaxBlockGroup & ForwBlock,LacingType lacing)751 bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, const KaxBlockGroup & ForwBlock, LacingType lacing)
752 {
753 // assert(past_timecode < 0);
754
755 // assert(forw_timecode > 0);
756
757 auto & theBlock = GetChild<KaxBlock>(*this);
758 assert(ParentCluster != nullptr);
759 theBlock.SetParent(*ParentCluster);
760 ParentTrack = &track;
761 bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);
762
763 auto & thePastRef = GetChild<KaxReferenceBlock>(*this);
764 thePastRef.SetReferencedBlock(PastBlock);
765 thePastRef.SetParentBlock(*this);
766
767 auto & theFutureRef = AddNewChild<KaxReferenceBlock>(*this);
768 theFutureRef.SetReferencedBlock(ForwBlock);
769 theFutureRef.SetParentBlock(*this);
770
771 return bRes;
772 }
773
AddFrame(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,const KaxBlockBlob * PastBlock,const KaxBlockBlob * ForwBlock,LacingType lacing)774 bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockBlob * PastBlock, const KaxBlockBlob * ForwBlock, LacingType lacing)
775 {
776 auto & theBlock = GetChild<KaxBlock>(*this);
777 assert(ParentCluster != nullptr);
778 theBlock.SetParent(*ParentCluster);
779 ParentTrack = &track;
780 bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);
781
782 if (PastBlock != nullptr) {
783 auto & thePastRef = GetChild<KaxReferenceBlock>(*this);
784 thePastRef.SetReferencedBlock(PastBlock);
785 thePastRef.SetParentBlock(*this);
786 }
787
788 if (ForwBlock != nullptr) {
789 auto & theFutureRef = AddNewChild<KaxReferenceBlock>(*this);
790 theFutureRef.SetReferencedBlock(ForwBlock);
791 theFutureRef.SetParentBlock(*this);
792 }
793
794 return bRes;
795 }
796
797 /*!
798 \todo we may cache the reference to the timecode block
799 */
GlobalTimecode() const800 uint64 KaxBlockGroup::GlobalTimecode() const
801 {
802 assert(ParentCluster != nullptr); // impossible otherwise
803 KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));
804 return MyBlock.GlobalTimecode();
805
806 }
807
TrackNumber() const808 uint16 KaxBlockGroup::TrackNumber() const
809 {
810 KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));
811 return MyBlock.TrackNum();
812 }
813
ClusterPosition() const814 uint64 KaxBlockGroup::ClusterPosition() const
815 {
816 assert(ParentCluster != nullptr); // impossible otherwise
817 return ParentCluster->GetPosition();
818 }
819
ClusterPosition() const820 uint64 KaxInternalBlock::ClusterPosition() const
821 {
822 assert(ParentCluster != nullptr); // impossible otherwise
823 return ParentCluster->GetPosition();
824 }
825
ReferenceCount() const826 unsigned int KaxBlockGroup::ReferenceCount() const
827 {
828 unsigned int Result = 0;
829 auto MyBlockAdds = static_cast<KaxReferenceBlock *>(FindFirstElt(EBML_INFO(KaxReferenceBlock)));
830 if (MyBlockAdds != nullptr) {
831 Result++;
832 while ((MyBlockAdds = static_cast<KaxReferenceBlock *>(FindNextElt(*MyBlockAdds))) != nullptr) {
833 Result++;
834 }
835 }
836 return Result;
837 }
838
Reference(unsigned int Index) const839 const KaxReferenceBlock & KaxBlockGroup::Reference(unsigned int Index) const
840 {
841 auto MyBlockAdds = static_cast<KaxReferenceBlock *>(FindFirstElt(EBML_INFO(KaxReferenceBlock)));
842 assert(MyBlockAdds != nullptr); // call of a non existing reference
843
844 while (Index != 0) {
845 MyBlockAdds = static_cast<KaxReferenceBlock *>(FindNextElt(*MyBlockAdds));
846 assert(MyBlockAdds != nullptr);
847 Index--;
848 }
849 return *MyBlockAdds;
850 }
851
ReleaseFrames()852 void KaxBlockGroup::ReleaseFrames()
853 {
854 KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));
855 MyBlock.ReleaseFrames();
856 }
857
ReleaseFrames()858 void KaxInternalBlock::ReleaseFrames()
859 {
860 // free the allocated Frames
861 int i;
862 for (i=myBuffers.size()-1; i>=0; i--) {
863 if (myBuffers[i] != nullptr) {
864 myBuffers[i]->FreeBuffer(*myBuffers[i]);
865 delete myBuffers[i];
866 myBuffers[i] = nullptr;
867 }
868 }
869 }
870
SetBlockDuration(uint64 TimeLength)871 void KaxBlockGroup::SetBlockDuration(uint64 TimeLength)
872 {
873 assert(ParentTrack != nullptr);
874 int64 scale = ParentTrack->GlobalTimecodeScale();
875 KaxBlockDuration & myDuration = *static_cast<KaxBlockDuration *>(FindFirstElt(EBML_INFO(KaxBlockDuration), true));
876 *(static_cast<EbmlUInteger *>(&myDuration)) = TimeLength / uint64(scale);
877 }
878
GetBlockDuration(uint64 & TheTimecode) const879 bool KaxBlockGroup::GetBlockDuration(uint64 &TheTimecode) const
880 {
881 auto myDuration = static_cast<KaxBlockDuration *>(FindElt(EBML_INFO(KaxBlockDuration)));
882 if (myDuration == nullptr) {
883 return false;
884 }
885
886 assert(ParentTrack != nullptr);
887 TheTimecode = uint64(*myDuration) * ParentTrack->GlobalTimecodeScale();
888 return true;
889 }
890
operator KaxInternalBlock&()891 KaxBlockGroup::operator KaxInternalBlock &() {
892 auto & theBlock = GetChild<KaxBlock>(*this);
893 return theBlock;
894 }
895
SetParent(KaxCluster & aParentCluster)896 void KaxBlockGroup::SetParent(KaxCluster & aParentCluster) {
897 ParentCluster = &aParentCluster;
898 auto & theBlock = GetChild<KaxBlock>(*this);
899 theBlock.SetParent( aParentCluster );
900 }
901
SetParent(KaxCluster & aParentCluster)902 void KaxSimpleBlock::SetParent(KaxCluster & aParentCluster) {
903 KaxInternalBlock::SetParent( aParentCluster );
904 }
905
SetParent(KaxCluster & aParentCluster)906 void KaxInternalBlock::SetParent(KaxCluster & aParentCluster)
907 {
908 ParentCluster = &aParentCluster;
909 if (bLocalTimecodeUsed) {
910 Timecode = aParentCluster.GetBlockGlobalTimecode(LocalTimecode);
911 bLocalTimecodeUsed = false;
912 }
913 }
914
GetDataPosition(size_t FrameNumber)915 int64 KaxInternalBlock::GetDataPosition(size_t FrameNumber)
916 {
917 int64 _Result = -1;
918
919 if (ValueIsSet() && FrameNumber < SizeList.size()) {
920 _Result = FirstFrameLocation;
921
922 size_t _Idx = 0;
923 while(FrameNumber--) {
924 _Result += SizeList[_Idx++];
925 }
926 }
927
928 return _Result;
929 }
930
GetFrameSize(size_t FrameNumber)931 int64 KaxInternalBlock::GetFrameSize(size_t FrameNumber)
932 {
933 int64 _Result = -1;
934
935 if (/*bValueIsSet &&*/ FrameNumber < SizeList.size()) {
936 _Result = SizeList[FrameNumber];
937 }
938
939 return _Result;
940 }
941
operator KaxBlockGroup&()942 KaxBlockBlob::operator KaxBlockGroup &()
943 {
944 assert(!bUseSimpleBlock);
945 assert(Block.group);
946 return *Block.group;
947 }
948
operator const KaxBlockGroup&() const949 KaxBlockBlob::operator const KaxBlockGroup &() const
950 {
951 assert(!bUseSimpleBlock);
952 assert(Block.group);
953 return *Block.group;
954 }
955
operator KaxInternalBlock&()956 KaxBlockBlob::operator KaxInternalBlock &()
957 {
958 assert(Block.group);
959 if (bUseSimpleBlock)
960 return *Block.simpleblock;
961 return *Block.group;
962 }
963
operator const KaxInternalBlock&() const964 KaxBlockBlob::operator const KaxInternalBlock &() const
965 {
966 assert(Block.group);
967 if (bUseSimpleBlock)
968 return *Block.simpleblock;
969 return *Block.group;
970 }
971
operator KaxSimpleBlock&()972 KaxBlockBlob::operator KaxSimpleBlock &()
973 {
974 assert(bUseSimpleBlock);
975 assert(Block.simpleblock);
976 return *Block.simpleblock;
977 }
978
AddFrameAuto(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,LacingType lacing,const KaxBlockBlob * PastBlock,const KaxBlockBlob * ForwBlock)979 bool KaxBlockBlob::AddFrameAuto(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing, const KaxBlockBlob * PastBlock, const KaxBlockBlob * ForwBlock)
980 {
981 bool bResult = false;
982 if ((SimpleBlockMode == BLOCK_BLOB_ALWAYS_SIMPLE) || (SimpleBlockMode == BLOCK_BLOB_SIMPLE_AUTO && PastBlock == nullptr && ForwBlock == nullptr)) {
983 assert(bUseSimpleBlock == true);
984 if (Block.simpleblock == nullptr) {
985 Block.simpleblock = new KaxSimpleBlock();
986 Block.simpleblock->SetParent(*ParentCluster);
987 }
988
989 bResult = Block.simpleblock->AddFrame(track, timecode, buffer, lacing);
990 if (PastBlock == nullptr && ForwBlock == nullptr) {
991 Block.simpleblock->SetKeyframe(true);
992 Block.simpleblock->SetDiscardable(false);
993 } else {
994 Block.simpleblock->SetKeyframe(false);
995 if ((ForwBlock == nullptr || ((const KaxInternalBlock &)*ForwBlock).GlobalTimecode() <= timecode) &&
996 (PastBlock == nullptr || ((const KaxInternalBlock &)*PastBlock).GlobalTimecode() <= timecode))
997 Block.simpleblock->SetDiscardable(false);
998 else
999 Block.simpleblock->SetDiscardable(true);
1000 }
1001 }
1002 else
1003 if (ReplaceSimpleByGroup())
1004 bResult = Block.group->AddFrame(track, timecode, buffer, PastBlock, ForwBlock, lacing);
1005
1006 return bResult;
1007 }
1008
SetParent(KaxCluster & aParentCluster)1009 void KaxBlockBlob::SetParent(KaxCluster & aParentCluster)
1010 {
1011 ParentCluster = &aParentCluster;
1012 }
1013
SetBlockDuration(uint64 TimeLength)1014 void KaxBlockBlob::SetBlockDuration(uint64 TimeLength)
1015 {
1016 if (ReplaceSimpleByGroup())
1017 Block.group->SetBlockDuration(TimeLength);
1018 }
1019
ReplaceSimpleByGroup()1020 bool KaxBlockBlob::ReplaceSimpleByGroup()
1021 {
1022 if (SimpleBlockMode== BLOCK_BLOB_ALWAYS_SIMPLE)
1023 return false;
1024
1025 if (!bUseSimpleBlock) {
1026 if (Block.group == nullptr) {
1027 Block.group = new KaxBlockGroup();
1028 }
1029 }
1030 else {
1031
1032 if (Block.simpleblock != nullptr) {
1033 KaxSimpleBlock *old_simpleblock = Block.simpleblock;
1034 Block.group = new KaxBlockGroup();
1035 // _TODO_ : move all the data to the blockgroup
1036 assert(false);
1037 // -> while(frame) AddFrame(myBuffer)
1038 delete old_simpleblock;
1039 } else {
1040 Block.group = new KaxBlockGroup();
1041 }
1042 }
1043 if (ParentCluster != nullptr)
1044 Block.group->SetParent(*ParentCluster);
1045
1046 bUseSimpleBlock = false;
1047 return true;
1048 }
1049
SetBlockGroup(KaxBlockGroup & BlockRef)1050 void KaxBlockBlob::SetBlockGroup( KaxBlockGroup &BlockRef )
1051 {
1052 assert(!bUseSimpleBlock);
1053 Block.group = &BlockRef;
1054 }
1055
ReadData(IOCallback & input,ScopeMode)1056 filepos_t KaxBlockVirtual::ReadData(IOCallback & input, ScopeMode /* ReadFully */)
1057 {
1058 input.setFilePointer(SizePosition + CodedSizeLength(Size, SizeLength, bSizeIsFinite) + Size, seek_beginning);
1059 return GetSize();
1060 }
1061
1062 END_LIBMATROSKA_NAMESPACE
1063