1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8
9 #include "mkvmuxer.hpp"
10
11 #include <climits>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 #include <ctime>
16 #include <new>
17
18 #include "mkvmuxerutil.hpp"
19 #include "mkvparser.hpp"
20 #include "mkvwriter.hpp"
21 #include "webmids.hpp"
22
23 #ifdef _MSC_VER
24 // Disable MSVC warnings that suggest making code non-portable.
25 #pragma warning(disable : 4996)
26 #endif
27
28 namespace mkvmuxer {
29
30 namespace {
31 // Deallocate the string designated by |dst|, and then copy the |src|
32 // string to |dst|. The caller owns both the |src| string and the
33 // |dst| copy (hence the caller is responsible for eventually
34 // deallocating the strings, either directly, or indirectly via
35 // StrCpy). Returns true if the source string was successfully copied
36 // to the destination.
StrCpy(const char * src,char ** dst_ptr)37 bool StrCpy(const char* src, char** dst_ptr) {
38 if (dst_ptr == NULL)
39 return false;
40
41 char*& dst = *dst_ptr;
42
43 delete[] dst;
44 dst = NULL;
45
46 if (src == NULL)
47 return true;
48
49 const size_t size = strlen(src) + 1;
50
51 dst = new (std::nothrow) char[size]; // NOLINT
52 if (dst == NULL)
53 return false;
54
55 strcpy(dst, src); // NOLINT
56 return true;
57 }
58 } // namespace
59
60 ///////////////////////////////////////////////////////////////
61 //
62 // IMkvWriter Class
63
IMkvWriter()64 IMkvWriter::IMkvWriter() {}
65
~IMkvWriter()66 IMkvWriter::~IMkvWriter() {}
67
WriteEbmlHeader(IMkvWriter * writer,uint64 doc_type_version)68 bool WriteEbmlHeader(IMkvWriter* writer, uint64 doc_type_version) {
69 // Level 0
70 uint64 size = EbmlElementSize(kMkvEBMLVersion, 1ULL);
71 size += EbmlElementSize(kMkvEBMLReadVersion, 1ULL);
72 size += EbmlElementSize(kMkvEBMLMaxIDLength, 4ULL);
73 size += EbmlElementSize(kMkvEBMLMaxSizeLength, 8ULL);
74 size += EbmlElementSize(kMkvDocType, "webm");
75 size += EbmlElementSize(kMkvDocTypeVersion, doc_type_version);
76 size += EbmlElementSize(kMkvDocTypeReadVersion, 2ULL);
77
78 if (!WriteEbmlMasterElement(writer, kMkvEBML, size))
79 return false;
80 if (!WriteEbmlElement(writer, kMkvEBMLVersion, 1ULL))
81 return false;
82 if (!WriteEbmlElement(writer, kMkvEBMLReadVersion, 1ULL))
83 return false;
84 if (!WriteEbmlElement(writer, kMkvEBMLMaxIDLength, 4ULL))
85 return false;
86 if (!WriteEbmlElement(writer, kMkvEBMLMaxSizeLength, 8ULL))
87 return false;
88 if (!WriteEbmlElement(writer, kMkvDocType, "webm"))
89 return false;
90 if (!WriteEbmlElement(writer, kMkvDocTypeVersion, doc_type_version))
91 return false;
92 if (!WriteEbmlElement(writer, kMkvDocTypeReadVersion, 2ULL))
93 return false;
94
95 return true;
96 }
97
WriteEbmlHeader(IMkvWriter * writer)98 bool WriteEbmlHeader(IMkvWriter* writer) {
99 return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion);
100 }
101
ChunkedCopy(mkvparser::IMkvReader * source,mkvmuxer::IMkvWriter * dst,mkvmuxer::int64 start,int64 size)102 bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst,
103 mkvmuxer::int64 start, int64 size) {
104 // TODO(vigneshv): Check if this is a reasonable value.
105 const uint32 kBufSize = 2048;
106 uint8* buf = new uint8[kBufSize];
107 int64 offset = start;
108 while (size > 0) {
109 const int64 read_len = (size > kBufSize) ? kBufSize : size;
110 if (source->Read(offset, static_cast<long>(read_len), buf))
111 return false;
112 dst->Write(buf, static_cast<uint32>(read_len));
113 offset += read_len;
114 size -= read_len;
115 }
116 delete[] buf;
117 return true;
118 }
119
120 ///////////////////////////////////////////////////////////////
121 //
122 // Frame Class
123
Frame()124 Frame::Frame()
125 : add_id_(0),
126 additional_(NULL),
127 additional_length_(0),
128 duration_(0),
129 frame_(NULL),
130 is_key_(false),
131 length_(0),
132 track_number_(0),
133 timestamp_(0),
134 discard_padding_(0),
135 reference_block_timestamp_(0),
136 reference_block_timestamp_set_(false) {}
137
~Frame()138 Frame::~Frame() {
139 delete[] frame_;
140 delete[] additional_;
141 }
142
CopyFrom(const Frame & frame)143 bool Frame::CopyFrom(const Frame& frame) {
144 delete[] frame_;
145 frame_ = NULL;
146 length_ = 0;
147 if (frame.length() > 0 && frame.frame() != NULL &&
148 !Init(frame.frame(), frame.length())) {
149 return false;
150 }
151 add_id_ = 0;
152 delete[] additional_;
153 additional_ = NULL;
154 additional_length_ = 0;
155 if (frame.additional_length() > 0 && frame.additional() != NULL &&
156 !AddAdditionalData(frame.additional(), frame.additional_length(),
157 frame.add_id())) {
158 return false;
159 }
160 duration_ = frame.duration();
161 is_key_ = frame.is_key();
162 track_number_ = frame.track_number();
163 timestamp_ = frame.timestamp();
164 discard_padding_ = frame.discard_padding();
165 return true;
166 }
167
Init(const uint8 * frame,uint64 length)168 bool Frame::Init(const uint8* frame, uint64 length) {
169 uint8* const data =
170 new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT
171 if (!data)
172 return false;
173
174 delete[] frame_;
175 frame_ = data;
176 length_ = length;
177
178 memcpy(frame_, frame, static_cast<size_t>(length_));
179 return true;
180 }
181
AddAdditionalData(const uint8 * additional,uint64 length,uint64 add_id)182 bool Frame::AddAdditionalData(const uint8* additional, uint64 length,
183 uint64 add_id) {
184 uint8* const data =
185 new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT
186 if (!data)
187 return false;
188
189 delete[] additional_;
190 additional_ = data;
191 additional_length_ = length;
192 add_id_ = add_id;
193
194 memcpy(additional_, additional, static_cast<size_t>(additional_length_));
195 return true;
196 }
197
IsValid() const198 bool Frame::IsValid() const {
199 if (length_ == 0 || !frame_) {
200 return false;
201 }
202 if ((additional_length_ != 0 && !additional_) ||
203 (additional_ != NULL && additional_length_ == 0)) {
204 return false;
205 }
206 if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
207 return false;
208 }
209 if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
210 return false;
211 }
212 return true;
213 }
214
CanBeSimpleBlock() const215 bool Frame::CanBeSimpleBlock() const {
216 return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
217 }
218
set_reference_block_timestamp(int64 reference_block_timestamp)219 void Frame::set_reference_block_timestamp(int64 reference_block_timestamp) {
220 reference_block_timestamp_ = reference_block_timestamp;
221 reference_block_timestamp_set_ = true;
222 }
223
224 ///////////////////////////////////////////////////////////////
225 //
226 // CuePoint Class
227
CuePoint()228 CuePoint::CuePoint()
229 : time_(0),
230 track_(0),
231 cluster_pos_(0),
232 block_number_(1),
233 output_block_number_(true) {}
234
~CuePoint()235 CuePoint::~CuePoint() {}
236
Write(IMkvWriter * writer) const237 bool CuePoint::Write(IMkvWriter* writer) const {
238 if (!writer || track_ < 1 || cluster_pos_ < 1)
239 return false;
240
241 uint64 size = EbmlElementSize(kMkvCueClusterPosition, cluster_pos_);
242 size += EbmlElementSize(kMkvCueTrack, track_);
243 if (output_block_number_ && block_number_ > 1)
244 size += EbmlElementSize(kMkvCueBlockNumber, block_number_);
245 const uint64 track_pos_size =
246 EbmlMasterElementSize(kMkvCueTrackPositions, size) + size;
247 const uint64 payload_size =
248 EbmlElementSize(kMkvCueTime, time_) + track_pos_size;
249
250 if (!WriteEbmlMasterElement(writer, kMkvCuePoint, payload_size))
251 return false;
252
253 const int64 payload_position = writer->Position();
254 if (payload_position < 0)
255 return false;
256
257 if (!WriteEbmlElement(writer, kMkvCueTime, time_))
258 return false;
259
260 if (!WriteEbmlMasterElement(writer, kMkvCueTrackPositions, size))
261 return false;
262 if (!WriteEbmlElement(writer, kMkvCueTrack, track_))
263 return false;
264 if (!WriteEbmlElement(writer, kMkvCueClusterPosition, cluster_pos_))
265 return false;
266 if (output_block_number_ && block_number_ > 1)
267 if (!WriteEbmlElement(writer, kMkvCueBlockNumber, block_number_))
268 return false;
269
270 const int64 stop_position = writer->Position();
271 if (stop_position < 0)
272 return false;
273
274 if (stop_position - payload_position != static_cast<int64>(payload_size))
275 return false;
276
277 return true;
278 }
279
PayloadSize() const280 uint64 CuePoint::PayloadSize() const {
281 uint64 size = EbmlElementSize(kMkvCueClusterPosition, cluster_pos_);
282 size += EbmlElementSize(kMkvCueTrack, track_);
283 if (output_block_number_ && block_number_ > 1)
284 size += EbmlElementSize(kMkvCueBlockNumber, block_number_);
285 const uint64 track_pos_size =
286 EbmlMasterElementSize(kMkvCueTrackPositions, size) + size;
287 const uint64 payload_size =
288 EbmlElementSize(kMkvCueTime, time_) + track_pos_size;
289
290 return payload_size;
291 }
292
Size() const293 uint64 CuePoint::Size() const {
294 const uint64 payload_size = PayloadSize();
295 return EbmlMasterElementSize(kMkvCuePoint, payload_size) + payload_size;
296 }
297
298 ///////////////////////////////////////////////////////////////
299 //
300 // Cues Class
301
Cues()302 Cues::Cues()
303 : cue_entries_capacity_(0),
304 cue_entries_size_(0),
305 cue_entries_(NULL),
306 output_block_number_(true) {}
307
~Cues()308 Cues::~Cues() {
309 if (cue_entries_) {
310 for (int32 i = 0; i < cue_entries_size_; ++i) {
311 CuePoint* const cue = cue_entries_[i];
312 delete cue;
313 }
314 delete[] cue_entries_;
315 }
316 }
317
AddCue(CuePoint * cue)318 bool Cues::AddCue(CuePoint* cue) {
319 if (!cue)
320 return false;
321
322 if ((cue_entries_size_ + 1) > cue_entries_capacity_) {
323 // Add more CuePoints.
324 const int32 new_capacity =
325 (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2;
326
327 if (new_capacity < 1)
328 return false;
329
330 CuePoint** const cues =
331 new (std::nothrow) CuePoint*[new_capacity]; // NOLINT
332 if (!cues)
333 return false;
334
335 for (int32 i = 0; i < cue_entries_size_; ++i) {
336 cues[i] = cue_entries_[i];
337 }
338
339 delete[] cue_entries_;
340
341 cue_entries_ = cues;
342 cue_entries_capacity_ = new_capacity;
343 }
344
345 cue->set_output_block_number(output_block_number_);
346 cue_entries_[cue_entries_size_++] = cue;
347 return true;
348 }
349
GetCueByIndex(int32 index) const350 CuePoint* Cues::GetCueByIndex(int32 index) const {
351 if (cue_entries_ == NULL)
352 return NULL;
353
354 if (index >= cue_entries_size_)
355 return NULL;
356
357 return cue_entries_[index];
358 }
359
Size()360 uint64 Cues::Size() {
361 uint64 size = 0;
362 for (int32 i = 0; i < cue_entries_size_; ++i)
363 size += GetCueByIndex(i)->Size();
364 size += EbmlMasterElementSize(kMkvCues, size);
365 return size;
366 }
367
Write(IMkvWriter * writer) const368 bool Cues::Write(IMkvWriter* writer) const {
369 if (!writer)
370 return false;
371
372 uint64 size = 0;
373 for (int32 i = 0; i < cue_entries_size_; ++i) {
374 const CuePoint* const cue = GetCueByIndex(i);
375
376 if (!cue)
377 return false;
378
379 size += cue->Size();
380 }
381
382 if (!WriteEbmlMasterElement(writer, kMkvCues, size))
383 return false;
384
385 const int64 payload_position = writer->Position();
386 if (payload_position < 0)
387 return false;
388
389 for (int32 i = 0; i < cue_entries_size_; ++i) {
390 const CuePoint* const cue = GetCueByIndex(i);
391
392 if (!cue->Write(writer))
393 return false;
394 }
395
396 const int64 stop_position = writer->Position();
397 if (stop_position < 0)
398 return false;
399
400 if (stop_position - payload_position != static_cast<int64>(size))
401 return false;
402
403 return true;
404 }
405
406 ///////////////////////////////////////////////////////////////
407 //
408 // ContentEncAESSettings Class
409
ContentEncAESSettings()410 ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}
411
Size() const412 uint64 ContentEncAESSettings::Size() const {
413 const uint64 payload = PayloadSize();
414 const uint64 size =
415 EbmlMasterElementSize(kMkvContentEncAESSettings, payload) + payload;
416 return size;
417 }
418
Write(IMkvWriter * writer) const419 bool ContentEncAESSettings::Write(IMkvWriter* writer) const {
420 const uint64 payload = PayloadSize();
421
422 if (!WriteEbmlMasterElement(writer, kMkvContentEncAESSettings, payload))
423 return false;
424
425 const int64 payload_position = writer->Position();
426 if (payload_position < 0)
427 return false;
428
429 if (!WriteEbmlElement(writer, kMkvAESSettingsCipherMode, cipher_mode_))
430 return false;
431
432 const int64 stop_position = writer->Position();
433 if (stop_position < 0 ||
434 stop_position - payload_position != static_cast<int64>(payload))
435 return false;
436
437 return true;
438 }
439
PayloadSize() const440 uint64 ContentEncAESSettings::PayloadSize() const {
441 uint64 size = EbmlElementSize(kMkvAESSettingsCipherMode, cipher_mode_);
442 return size;
443 }
444
445 ///////////////////////////////////////////////////////////////
446 //
447 // ContentEncoding Class
448
ContentEncoding()449 ContentEncoding::ContentEncoding()
450 : enc_algo_(5),
451 enc_key_id_(NULL),
452 encoding_order_(0),
453 encoding_scope_(1),
454 encoding_type_(1),
455 enc_key_id_length_(0) {}
456
~ContentEncoding()457 ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
458
SetEncryptionID(const uint8 * id,uint64 length)459 bool ContentEncoding::SetEncryptionID(const uint8* id, uint64 length) {
460 if (!id || length < 1)
461 return false;
462
463 delete[] enc_key_id_;
464
465 enc_key_id_ =
466 new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT
467 if (!enc_key_id_)
468 return false;
469
470 memcpy(enc_key_id_, id, static_cast<size_t>(length));
471 enc_key_id_length_ = length;
472
473 return true;
474 }
475
Size() const476 uint64 ContentEncoding::Size() const {
477 const uint64 encryption_size = EncryptionSize();
478 const uint64 encoding_size = EncodingSize(0, encryption_size);
479 const uint64 encodings_size =
480 EbmlMasterElementSize(kMkvContentEncoding, encoding_size) + encoding_size;
481
482 return encodings_size;
483 }
484
Write(IMkvWriter * writer) const485 bool ContentEncoding::Write(IMkvWriter* writer) const {
486 const uint64 encryption_size = EncryptionSize();
487 const uint64 encoding_size = EncodingSize(0, encryption_size);
488 const uint64 size =
489 EbmlMasterElementSize(kMkvContentEncoding, encoding_size) + encoding_size;
490
491 const int64 payload_position = writer->Position();
492 if (payload_position < 0)
493 return false;
494
495 if (!WriteEbmlMasterElement(writer, kMkvContentEncoding, encoding_size))
496 return false;
497 if (!WriteEbmlElement(writer, kMkvContentEncodingOrder, encoding_order_))
498 return false;
499 if (!WriteEbmlElement(writer, kMkvContentEncodingScope, encoding_scope_))
500 return false;
501 if (!WriteEbmlElement(writer, kMkvContentEncodingType, encoding_type_))
502 return false;
503
504 if (!WriteEbmlMasterElement(writer, kMkvContentEncryption, encryption_size))
505 return false;
506 if (!WriteEbmlElement(writer, kMkvContentEncAlgo, enc_algo_))
507 return false;
508 if (!WriteEbmlElement(writer, kMkvContentEncKeyID, enc_key_id_,
509 enc_key_id_length_))
510 return false;
511
512 if (!enc_aes_settings_.Write(writer))
513 return false;
514
515 const int64 stop_position = writer->Position();
516 if (stop_position < 0 ||
517 stop_position - payload_position != static_cast<int64>(size))
518 return false;
519
520 return true;
521 }
522
EncodingSize(uint64 compresion_size,uint64 encryption_size) const523 uint64 ContentEncoding::EncodingSize(uint64 compresion_size,
524 uint64 encryption_size) const {
525 // TODO(fgalligan): Add support for compression settings.
526 if (compresion_size != 0)
527 return 0;
528
529 uint64 encoding_size = 0;
530
531 if (encryption_size > 0) {
532 encoding_size +=
533 EbmlMasterElementSize(kMkvContentEncryption, encryption_size) +
534 encryption_size;
535 }
536 encoding_size += EbmlElementSize(kMkvContentEncodingType, encoding_type_);
537 encoding_size += EbmlElementSize(kMkvContentEncodingScope, encoding_scope_);
538 encoding_size += EbmlElementSize(kMkvContentEncodingOrder, encoding_order_);
539
540 return encoding_size;
541 }
542
EncryptionSize() const543 uint64 ContentEncoding::EncryptionSize() const {
544 const uint64 aes_size = enc_aes_settings_.Size();
545
546 uint64 encryption_size =
547 EbmlElementSize(kMkvContentEncKeyID, enc_key_id_, enc_key_id_length_);
548 encryption_size += EbmlElementSize(kMkvContentEncAlgo, enc_algo_);
549
550 return encryption_size + aes_size;
551 }
552
553 ///////////////////////////////////////////////////////////////
554 //
555 // Track Class
556
Track(unsigned int * seed)557 Track::Track(unsigned int* seed)
558 : codec_id_(NULL),
559 codec_private_(NULL),
560 language_(NULL),
561 max_block_additional_id_(0),
562 name_(NULL),
563 number_(0),
564 type_(0),
565 uid_(MakeUID(seed)),
566 codec_delay_(0),
567 seek_pre_roll_(0),
568 default_duration_(0),
569 codec_private_length_(0),
570 content_encoding_entries_(NULL),
571 content_encoding_entries_size_(0) {}
572
~Track()573 Track::~Track() {
574 delete[] codec_id_;
575 delete[] codec_private_;
576 delete[] language_;
577 delete[] name_;
578
579 if (content_encoding_entries_) {
580 for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
581 ContentEncoding* const encoding = content_encoding_entries_[i];
582 delete encoding;
583 }
584 delete[] content_encoding_entries_;
585 }
586 }
587
AddContentEncoding()588 bool Track::AddContentEncoding() {
589 const uint32 count = content_encoding_entries_size_ + 1;
590
591 ContentEncoding** const content_encoding_entries =
592 new (std::nothrow) ContentEncoding*[count]; // NOLINT
593 if (!content_encoding_entries)
594 return false;
595
596 ContentEncoding* const content_encoding =
597 new (std::nothrow) ContentEncoding(); // NOLINT
598 if (!content_encoding) {
599 delete[] content_encoding_entries;
600 return false;
601 }
602
603 for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
604 content_encoding_entries[i] = content_encoding_entries_[i];
605 }
606
607 delete[] content_encoding_entries_;
608
609 content_encoding_entries_ = content_encoding_entries;
610 content_encoding_entries_[content_encoding_entries_size_] = content_encoding;
611 content_encoding_entries_size_ = count;
612 return true;
613 }
614
GetContentEncodingByIndex(uint32 index) const615 ContentEncoding* Track::GetContentEncodingByIndex(uint32 index) const {
616 if (content_encoding_entries_ == NULL)
617 return NULL;
618
619 if (index >= content_encoding_entries_size_)
620 return NULL;
621
622 return content_encoding_entries_[index];
623 }
624
PayloadSize() const625 uint64 Track::PayloadSize() const {
626 uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
627 size += EbmlElementSize(kMkvTrackUID, uid_);
628 size += EbmlElementSize(kMkvTrackType, type_);
629 if (codec_id_)
630 size += EbmlElementSize(kMkvCodecID, codec_id_);
631 if (codec_private_)
632 size += EbmlElementSize(kMkvCodecPrivate, codec_private_,
633 codec_private_length_);
634 if (language_)
635 size += EbmlElementSize(kMkvLanguage, language_);
636 if (name_)
637 size += EbmlElementSize(kMkvName, name_);
638 if (max_block_additional_id_)
639 size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
640 if (codec_delay_)
641 size += EbmlElementSize(kMkvCodecDelay, codec_delay_);
642 if (seek_pre_roll_)
643 size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_);
644 if (default_duration_)
645 size += EbmlElementSize(kMkvDefaultDuration, default_duration_);
646
647 if (content_encoding_entries_size_ > 0) {
648 uint64 content_encodings_size = 0;
649 for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
650 ContentEncoding* const encoding = content_encoding_entries_[i];
651 content_encodings_size += encoding->Size();
652 }
653
654 size +=
655 EbmlMasterElementSize(kMkvContentEncodings, content_encodings_size) +
656 content_encodings_size;
657 }
658
659 return size;
660 }
661
Size() const662 uint64 Track::Size() const {
663 uint64 size = PayloadSize();
664 size += EbmlMasterElementSize(kMkvTrackEntry, size);
665 return size;
666 }
667
Write(IMkvWriter * writer) const668 bool Track::Write(IMkvWriter* writer) const {
669 if (!writer)
670 return false;
671
672 // mandatory elements without a default value.
673 if (!type_ || !codec_id_)
674 return false;
675
676 // |size| may be bigger than what is written out in this function because
677 // derived classes may write out more data in the Track element.
678 const uint64 payload_size = PayloadSize();
679
680 if (!WriteEbmlMasterElement(writer, kMkvTrackEntry, payload_size))
681 return false;
682
683 uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
684 size += EbmlElementSize(kMkvTrackUID, uid_);
685 size += EbmlElementSize(kMkvTrackType, type_);
686 if (codec_id_)
687 size += EbmlElementSize(kMkvCodecID, codec_id_);
688 if (codec_private_)
689 size += EbmlElementSize(kMkvCodecPrivate, codec_private_,
690 codec_private_length_);
691 if (language_)
692 size += EbmlElementSize(kMkvLanguage, language_);
693 if (name_)
694 size += EbmlElementSize(kMkvName, name_);
695 if (max_block_additional_id_)
696 size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
697 if (codec_delay_)
698 size += EbmlElementSize(kMkvCodecDelay, codec_delay_);
699 if (seek_pre_roll_)
700 size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_);
701 if (default_duration_)
702 size += EbmlElementSize(kMkvDefaultDuration, default_duration_);
703
704 const int64 payload_position = writer->Position();
705 if (payload_position < 0)
706 return false;
707
708 if (!WriteEbmlElement(writer, kMkvTrackNumber, number_))
709 return false;
710 if (!WriteEbmlElement(writer, kMkvTrackUID, uid_))
711 return false;
712 if (!WriteEbmlElement(writer, kMkvTrackType, type_))
713 return false;
714 if (max_block_additional_id_) {
715 if (!WriteEbmlElement(writer, kMkvMaxBlockAdditionID,
716 max_block_additional_id_)) {
717 return false;
718 }
719 }
720 if (codec_delay_) {
721 if (!WriteEbmlElement(writer, kMkvCodecDelay, codec_delay_))
722 return false;
723 }
724 if (seek_pre_roll_) {
725 if (!WriteEbmlElement(writer, kMkvSeekPreRoll, seek_pre_roll_))
726 return false;
727 }
728 if (default_duration_) {
729 if (!WriteEbmlElement(writer, kMkvDefaultDuration, default_duration_))
730 return false;
731 }
732 if (codec_id_) {
733 if (!WriteEbmlElement(writer, kMkvCodecID, codec_id_))
734 return false;
735 }
736 if (codec_private_) {
737 if (!WriteEbmlElement(writer, kMkvCodecPrivate, codec_private_,
738 codec_private_length_))
739 return false;
740 }
741 if (language_) {
742 if (!WriteEbmlElement(writer, kMkvLanguage, language_))
743 return false;
744 }
745 if (name_) {
746 if (!WriteEbmlElement(writer, kMkvName, name_))
747 return false;
748 }
749
750 int64 stop_position = writer->Position();
751 if (stop_position < 0 ||
752 stop_position - payload_position != static_cast<int64>(size))
753 return false;
754
755 if (content_encoding_entries_size_ > 0) {
756 uint64 content_encodings_size = 0;
757 for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
758 ContentEncoding* const encoding = content_encoding_entries_[i];
759 content_encodings_size += encoding->Size();
760 }
761
762 if (!WriteEbmlMasterElement(writer, kMkvContentEncodings,
763 content_encodings_size))
764 return false;
765
766 for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
767 ContentEncoding* const encoding = content_encoding_entries_[i];
768 if (!encoding->Write(writer))
769 return false;
770 }
771 }
772
773 stop_position = writer->Position();
774 if (stop_position < 0)
775 return false;
776 return true;
777 }
778
SetCodecPrivate(const uint8 * codec_private,uint64 length)779 bool Track::SetCodecPrivate(const uint8* codec_private, uint64 length) {
780 if (!codec_private || length < 1)
781 return false;
782
783 delete[] codec_private_;
784
785 codec_private_ =
786 new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT
787 if (!codec_private_)
788 return false;
789
790 memcpy(codec_private_, codec_private, static_cast<size_t>(length));
791 codec_private_length_ = length;
792
793 return true;
794 }
795
set_codec_id(const char * codec_id)796 void Track::set_codec_id(const char* codec_id) {
797 if (codec_id) {
798 delete[] codec_id_;
799
800 const size_t length = strlen(codec_id) + 1;
801 codec_id_ = new (std::nothrow) char[length]; // NOLINT
802 if (codec_id_) {
803 #ifdef _MSC_VER
804 strcpy_s(codec_id_, length, codec_id);
805 #else
806 strcpy(codec_id_, codec_id);
807 #endif
808 }
809 }
810 }
811
812 // TODO(fgalligan): Vet the language parameter.
set_language(const char * language)813 void Track::set_language(const char* language) {
814 if (language) {
815 delete[] language_;
816
817 const size_t length = strlen(language) + 1;
818 language_ = new (std::nothrow) char[length]; // NOLINT
819 if (language_) {
820 #ifdef _MSC_VER
821 strcpy_s(language_, length, language);
822 #else
823 strcpy(language_, language);
824 #endif
825 }
826 }
827 }
828
set_name(const char * name)829 void Track::set_name(const char* name) {
830 if (name) {
831 delete[] name_;
832
833 const size_t length = strlen(name) + 1;
834 name_ = new (std::nothrow) char[length]; // NOLINT
835 if (name_) {
836 #ifdef _MSC_VER
837 strcpy_s(name_, length, name);
838 #else
839 strcpy(name_, name);
840 #endif
841 }
842 }
843 }
844
845 ///////////////////////////////////////////////////////////////
846 //
847 // VideoTrack Class
848
VideoTrack(unsigned int * seed)849 VideoTrack::VideoTrack(unsigned int* seed)
850 : Track(seed),
851 display_height_(0),
852 display_width_(0),
853 crop_left_(0),
854 crop_right_(0),
855 crop_top_(0),
856 crop_bottom_(0),
857 frame_rate_(0.0),
858 height_(0),
859 stereo_mode_(0),
860 alpha_mode_(0),
861 width_(0) {}
862
~VideoTrack()863 VideoTrack::~VideoTrack() {}
864
SetStereoMode(uint64 stereo_mode)865 bool VideoTrack::SetStereoMode(uint64 stereo_mode) {
866 if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
867 stereo_mode != kTopBottomRightIsFirst &&
868 stereo_mode != kTopBottomLeftIsFirst &&
869 stereo_mode != kSideBySideRightIsFirst)
870 return false;
871
872 stereo_mode_ = stereo_mode;
873 return true;
874 }
875
SetAlphaMode(uint64 alpha_mode)876 bool VideoTrack::SetAlphaMode(uint64 alpha_mode) {
877 if (alpha_mode != kNoAlpha && alpha_mode != kAlpha)
878 return false;
879
880 alpha_mode_ = alpha_mode;
881 return true;
882 }
883
PayloadSize() const884 uint64 VideoTrack::PayloadSize() const {
885 const uint64 parent_size = Track::PayloadSize();
886
887 uint64 size = VideoPayloadSize();
888 size += EbmlMasterElementSize(kMkvVideo, size);
889
890 return parent_size + size;
891 }
892
Write(IMkvWriter * writer) const893 bool VideoTrack::Write(IMkvWriter* writer) const {
894 if (!Track::Write(writer))
895 return false;
896
897 const uint64 size = VideoPayloadSize();
898
899 if (!WriteEbmlMasterElement(writer, kMkvVideo, size))
900 return false;
901
902 const int64 payload_position = writer->Position();
903 if (payload_position < 0)
904 return false;
905
906 if (!WriteEbmlElement(writer, kMkvPixelWidth, width_))
907 return false;
908 if (!WriteEbmlElement(writer, kMkvPixelHeight, height_))
909 return false;
910 if (display_width_ > 0) {
911 if (!WriteEbmlElement(writer, kMkvDisplayWidth, display_width_))
912 return false;
913 }
914 if (display_height_ > 0) {
915 if (!WriteEbmlElement(writer, kMkvDisplayHeight, display_height_))
916 return false;
917 }
918 if (crop_left_ > 0) {
919 if (!WriteEbmlElement(writer, kMkvPixelCropLeft, crop_left_))
920 return false;
921 }
922 if (crop_right_ > 0) {
923 if (!WriteEbmlElement(writer, kMkvPixelCropRight, crop_right_))
924 return false;
925 }
926 if (crop_top_ > 0) {
927 if (!WriteEbmlElement(writer, kMkvPixelCropTop, crop_top_))
928 return false;
929 }
930 if (crop_bottom_ > 0) {
931 if (!WriteEbmlElement(writer, kMkvPixelCropBottom, crop_bottom_))
932 return false;
933 }
934 if (stereo_mode_ > kMono) {
935 if (!WriteEbmlElement(writer, kMkvStereoMode, stereo_mode_))
936 return false;
937 }
938 if (alpha_mode_ > kNoAlpha) {
939 if (!WriteEbmlElement(writer, kMkvAlphaMode, alpha_mode_))
940 return false;
941 }
942 if (frame_rate_ > 0.0) {
943 if (!WriteEbmlElement(writer, kMkvFrameRate,
944 static_cast<float>(frame_rate_))) {
945 return false;
946 }
947 }
948
949 const int64 stop_position = writer->Position();
950 if (stop_position < 0 ||
951 stop_position - payload_position != static_cast<int64>(size)) {
952 return false;
953 }
954
955 return true;
956 }
957
VideoPayloadSize() const958 uint64 VideoTrack::VideoPayloadSize() const {
959 uint64 size = EbmlElementSize(kMkvPixelWidth, width_);
960 size += EbmlElementSize(kMkvPixelHeight, height_);
961 if (display_width_ > 0)
962 size += EbmlElementSize(kMkvDisplayWidth, display_width_);
963 if (display_height_ > 0)
964 size += EbmlElementSize(kMkvDisplayHeight, display_height_);
965 if (crop_left_ > 0)
966 size += EbmlElementSize(kMkvPixelCropLeft, crop_left_);
967 if (crop_right_ > 0)
968 size += EbmlElementSize(kMkvPixelCropRight, crop_right_);
969 if (crop_top_ > 0)
970 size += EbmlElementSize(kMkvPixelCropTop, crop_top_);
971 if (crop_bottom_ > 0)
972 size += EbmlElementSize(kMkvPixelCropBottom, crop_bottom_);
973 if (stereo_mode_ > kMono)
974 size += EbmlElementSize(kMkvStereoMode, stereo_mode_);
975 if (alpha_mode_ > kNoAlpha)
976 size += EbmlElementSize(kMkvAlphaMode, alpha_mode_);
977 if (frame_rate_ > 0.0)
978 size += EbmlElementSize(kMkvFrameRate, static_cast<float>(frame_rate_));
979
980 return size;
981 }
982
983 ///////////////////////////////////////////////////////////////
984 //
985 // AudioTrack Class
986
AudioTrack(unsigned int * seed)987 AudioTrack::AudioTrack(unsigned int* seed)
988 : Track(seed), bit_depth_(0), channels_(1), sample_rate_(0.0) {}
989
~AudioTrack()990 AudioTrack::~AudioTrack() {}
991
PayloadSize() const992 uint64 AudioTrack::PayloadSize() const {
993 const uint64 parent_size = Track::PayloadSize();
994
995 uint64 size =
996 EbmlElementSize(kMkvSamplingFrequency, static_cast<float>(sample_rate_));
997 size += EbmlElementSize(kMkvChannels, channels_);
998 if (bit_depth_ > 0)
999 size += EbmlElementSize(kMkvBitDepth, bit_depth_);
1000 size += EbmlMasterElementSize(kMkvAudio, size);
1001
1002 return parent_size + size;
1003 }
1004
Write(IMkvWriter * writer) const1005 bool AudioTrack::Write(IMkvWriter* writer) const {
1006 if (!Track::Write(writer))
1007 return false;
1008
1009 // Calculate AudioSettings size.
1010 uint64 size =
1011 EbmlElementSize(kMkvSamplingFrequency, static_cast<float>(sample_rate_));
1012 size += EbmlElementSize(kMkvChannels, channels_);
1013 if (bit_depth_ > 0)
1014 size += EbmlElementSize(kMkvBitDepth, bit_depth_);
1015
1016 if (!WriteEbmlMasterElement(writer, kMkvAudio, size))
1017 return false;
1018
1019 const int64 payload_position = writer->Position();
1020 if (payload_position < 0)
1021 return false;
1022
1023 if (!WriteEbmlElement(writer, kMkvSamplingFrequency,
1024 static_cast<float>(sample_rate_)))
1025 return false;
1026 if (!WriteEbmlElement(writer, kMkvChannels, channels_))
1027 return false;
1028 if (bit_depth_ > 0)
1029 if (!WriteEbmlElement(writer, kMkvBitDepth, bit_depth_))
1030 return false;
1031
1032 const int64 stop_position = writer->Position();
1033 if (stop_position < 0 ||
1034 stop_position - payload_position != static_cast<int64>(size))
1035 return false;
1036
1037 return true;
1038 }
1039
1040 ///////////////////////////////////////////////////////////////
1041 //
1042 // Tracks Class
1043
1044 const char Tracks::kOpusCodecId[] = "A_OPUS";
1045 const char Tracks::kVorbisCodecId[] = "A_VORBIS";
1046 const char Tracks::kVp8CodecId[] = "V_VP8";
1047 const char Tracks::kVp9CodecId[] = "V_VP9";
1048 const char Tracks::kVp10CodecId[] = "V_VP10";
1049
Tracks()1050 Tracks::Tracks() : track_entries_(NULL), track_entries_size_(0) {}
1051
~Tracks()1052 Tracks::~Tracks() {
1053 if (track_entries_) {
1054 for (uint32 i = 0; i < track_entries_size_; ++i) {
1055 Track* const track = track_entries_[i];
1056 delete track;
1057 }
1058 delete[] track_entries_;
1059 }
1060 }
1061
AddTrack(Track * track,int32 number)1062 bool Tracks::AddTrack(Track* track, int32 number) {
1063 if (number < 0)
1064 return false;
1065
1066 // This muxer only supports track numbers in the range [1, 126], in
1067 // order to be able (to use Matroska integer representation) to
1068 // serialize the block header (of which the track number is a part)
1069 // for a frame using exactly 4 bytes.
1070
1071 if (number > 0x7E)
1072 return false;
1073
1074 uint32 track_num = number;
1075
1076 if (track_num > 0) {
1077 // Check to make sure a track does not already have |track_num|.
1078 for (uint32 i = 0; i < track_entries_size_; ++i) {
1079 if (track_entries_[i]->number() == track_num)
1080 return false;
1081 }
1082 }
1083
1084 const uint32 count = track_entries_size_ + 1;
1085
1086 Track** const track_entries = new (std::nothrow) Track*[count]; // NOLINT
1087 if (!track_entries)
1088 return false;
1089
1090 for (uint32 i = 0; i < track_entries_size_; ++i) {
1091 track_entries[i] = track_entries_[i];
1092 }
1093
1094 delete[] track_entries_;
1095
1096 // Find the lowest availible track number > 0.
1097 if (track_num == 0) {
1098 track_num = count;
1099
1100 // Check to make sure a track does not already have |track_num|.
1101 bool exit = false;
1102 do {
1103 exit = true;
1104 for (uint32 i = 0; i < track_entries_size_; ++i) {
1105 if (track_entries[i]->number() == track_num) {
1106 track_num++;
1107 exit = false;
1108 break;
1109 }
1110 }
1111 } while (!exit);
1112 }
1113 track->set_number(track_num);
1114
1115 track_entries_ = track_entries;
1116 track_entries_[track_entries_size_] = track;
1117 track_entries_size_ = count;
1118 return true;
1119 }
1120
GetTrackByIndex(uint32 index) const1121 const Track* Tracks::GetTrackByIndex(uint32 index) const {
1122 if (track_entries_ == NULL)
1123 return NULL;
1124
1125 if (index >= track_entries_size_)
1126 return NULL;
1127
1128 return track_entries_[index];
1129 }
1130
GetTrackByNumber(uint64 track_number) const1131 Track* Tracks::GetTrackByNumber(uint64 track_number) const {
1132 const int32 count = track_entries_size();
1133 for (int32 i = 0; i < count; ++i) {
1134 if (track_entries_[i]->number() == track_number)
1135 return track_entries_[i];
1136 }
1137
1138 return NULL;
1139 }
1140
TrackIsAudio(uint64 track_number) const1141 bool Tracks::TrackIsAudio(uint64 track_number) const {
1142 const Track* const track = GetTrackByNumber(track_number);
1143
1144 if (track->type() == kAudio)
1145 return true;
1146
1147 return false;
1148 }
1149
TrackIsVideo(uint64 track_number) const1150 bool Tracks::TrackIsVideo(uint64 track_number) const {
1151 const Track* const track = GetTrackByNumber(track_number);
1152
1153 if (track->type() == kVideo)
1154 return true;
1155
1156 return false;
1157 }
1158
Write(IMkvWriter * writer) const1159 bool Tracks::Write(IMkvWriter* writer) const {
1160 uint64 size = 0;
1161 const int32 count = track_entries_size();
1162 for (int32 i = 0; i < count; ++i) {
1163 const Track* const track = GetTrackByIndex(i);
1164
1165 if (!track)
1166 return false;
1167
1168 size += track->Size();
1169 }
1170
1171 if (!WriteEbmlMasterElement(writer, kMkvTracks, size))
1172 return false;
1173
1174 const int64 payload_position = writer->Position();
1175 if (payload_position < 0)
1176 return false;
1177
1178 for (int32 i = 0; i < count; ++i) {
1179 const Track* const track = GetTrackByIndex(i);
1180 if (!track->Write(writer))
1181 return false;
1182 }
1183
1184 const int64 stop_position = writer->Position();
1185 if (stop_position < 0 ||
1186 stop_position - payload_position != static_cast<int64>(size))
1187 return false;
1188
1189 return true;
1190 }
1191
1192 ///////////////////////////////////////////////////////////////
1193 //
1194 // Chapter Class
1195
set_id(const char * id)1196 bool Chapter::set_id(const char* id) { return StrCpy(id, &id_); }
1197
set_time(const Segment & segment,uint64 start_ns,uint64 end_ns)1198 void Chapter::set_time(const Segment& segment, uint64 start_ns, uint64 end_ns) {
1199 const SegmentInfo* const info = segment.GetSegmentInfo();
1200 const uint64 timecode_scale = info->timecode_scale();
1201 start_timecode_ = start_ns / timecode_scale;
1202 end_timecode_ = end_ns / timecode_scale;
1203 }
1204
add_string(const char * title,const char * language,const char * country)1205 bool Chapter::add_string(const char* title, const char* language,
1206 const char* country) {
1207 if (!ExpandDisplaysArray())
1208 return false;
1209
1210 Display& d = displays_[displays_count_++];
1211 d.Init();
1212
1213 if (!d.set_title(title))
1214 return false;
1215
1216 if (!d.set_language(language))
1217 return false;
1218
1219 if (!d.set_country(country))
1220 return false;
1221
1222 return true;
1223 }
1224
Chapter()1225 Chapter::Chapter() {
1226 // This ctor only constructs the object. Proper initialization is
1227 // done in Init() (called in Chapters::AddChapter()). The only
1228 // reason we bother implementing this ctor is because we had to
1229 // declare it as private (along with the dtor), in order to prevent
1230 // clients from creating Chapter instances (a privelege we grant
1231 // only to the Chapters class). Doing no initialization here also
1232 // means that creating arrays of chapter objects is more efficient,
1233 // because we only initialize each new chapter object as it becomes
1234 // active on the array.
1235 }
1236
~Chapter()1237 Chapter::~Chapter() {}
1238
Init(unsigned int * seed)1239 void Chapter::Init(unsigned int* seed) {
1240 id_ = NULL;
1241 start_timecode_ = 0;
1242 end_timecode_ = 0;
1243 displays_ = NULL;
1244 displays_size_ = 0;
1245 displays_count_ = 0;
1246 uid_ = MakeUID(seed);
1247 }
1248
ShallowCopy(Chapter * dst) const1249 void Chapter::ShallowCopy(Chapter* dst) const {
1250 dst->id_ = id_;
1251 dst->start_timecode_ = start_timecode_;
1252 dst->end_timecode_ = end_timecode_;
1253 dst->uid_ = uid_;
1254 dst->displays_ = displays_;
1255 dst->displays_size_ = displays_size_;
1256 dst->displays_count_ = displays_count_;
1257 }
1258
Clear()1259 void Chapter::Clear() {
1260 StrCpy(NULL, &id_);
1261
1262 while (displays_count_ > 0) {
1263 Display& d = displays_[--displays_count_];
1264 d.Clear();
1265 }
1266
1267 delete[] displays_;
1268 displays_ = NULL;
1269
1270 displays_size_ = 0;
1271 }
1272
ExpandDisplaysArray()1273 bool Chapter::ExpandDisplaysArray() {
1274 if (displays_size_ > displays_count_)
1275 return true; // nothing to do yet
1276
1277 const int size = (displays_size_ == 0) ? 1 : 2 * displays_size_;
1278
1279 Display* const displays = new (std::nothrow) Display[size]; // NOLINT
1280 if (displays == NULL)
1281 return false;
1282
1283 for (int idx = 0; idx < displays_count_; ++idx) {
1284 displays[idx] = displays_[idx]; // shallow copy
1285 }
1286
1287 delete[] displays_;
1288
1289 displays_ = displays;
1290 displays_size_ = size;
1291
1292 return true;
1293 }
1294
WriteAtom(IMkvWriter * writer) const1295 uint64 Chapter::WriteAtom(IMkvWriter* writer) const {
1296 uint64 payload_size = EbmlElementSize(kMkvChapterStringUID, id_) +
1297 EbmlElementSize(kMkvChapterUID, uid_) +
1298 EbmlElementSize(kMkvChapterTimeStart, start_timecode_) +
1299 EbmlElementSize(kMkvChapterTimeEnd, end_timecode_);
1300
1301 for (int idx = 0; idx < displays_count_; ++idx) {
1302 const Display& d = displays_[idx];
1303 payload_size += d.WriteDisplay(NULL);
1304 }
1305
1306 const uint64 atom_size =
1307 EbmlMasterElementSize(kMkvChapterAtom, payload_size) + payload_size;
1308
1309 if (writer == NULL)
1310 return atom_size;
1311
1312 const int64 start = writer->Position();
1313
1314 if (!WriteEbmlMasterElement(writer, kMkvChapterAtom, payload_size))
1315 return 0;
1316
1317 if (!WriteEbmlElement(writer, kMkvChapterStringUID, id_))
1318 return 0;
1319
1320 if (!WriteEbmlElement(writer, kMkvChapterUID, uid_))
1321 return 0;
1322
1323 if (!WriteEbmlElement(writer, kMkvChapterTimeStart, start_timecode_))
1324 return 0;
1325
1326 if (!WriteEbmlElement(writer, kMkvChapterTimeEnd, end_timecode_))
1327 return 0;
1328
1329 for (int idx = 0; idx < displays_count_; ++idx) {
1330 const Display& d = displays_[idx];
1331
1332 if (!d.WriteDisplay(writer))
1333 return 0;
1334 }
1335
1336 const int64 stop = writer->Position();
1337
1338 if (stop >= start && uint64(stop - start) != atom_size)
1339 return 0;
1340
1341 return atom_size;
1342 }
1343
Init()1344 void Chapter::Display::Init() {
1345 title_ = NULL;
1346 language_ = NULL;
1347 country_ = NULL;
1348 }
1349
Clear()1350 void Chapter::Display::Clear() {
1351 StrCpy(NULL, &title_);
1352 StrCpy(NULL, &language_);
1353 StrCpy(NULL, &country_);
1354 }
1355
set_title(const char * title)1356 bool Chapter::Display::set_title(const char* title) {
1357 return StrCpy(title, &title_);
1358 }
1359
set_language(const char * language)1360 bool Chapter::Display::set_language(const char* language) {
1361 return StrCpy(language, &language_);
1362 }
1363
set_country(const char * country)1364 bool Chapter::Display::set_country(const char* country) {
1365 return StrCpy(country, &country_);
1366 }
1367
WriteDisplay(IMkvWriter * writer) const1368 uint64 Chapter::Display::WriteDisplay(IMkvWriter* writer) const {
1369 uint64 payload_size = EbmlElementSize(kMkvChapString, title_);
1370
1371 if (language_)
1372 payload_size += EbmlElementSize(kMkvChapLanguage, language_);
1373
1374 if (country_)
1375 payload_size += EbmlElementSize(kMkvChapCountry, country_);
1376
1377 const uint64 display_size =
1378 EbmlMasterElementSize(kMkvChapterDisplay, payload_size) + payload_size;
1379
1380 if (writer == NULL)
1381 return display_size;
1382
1383 const int64 start = writer->Position();
1384
1385 if (!WriteEbmlMasterElement(writer, kMkvChapterDisplay, payload_size))
1386 return 0;
1387
1388 if (!WriteEbmlElement(writer, kMkvChapString, title_))
1389 return 0;
1390
1391 if (language_) {
1392 if (!WriteEbmlElement(writer, kMkvChapLanguage, language_))
1393 return 0;
1394 }
1395
1396 if (country_) {
1397 if (!WriteEbmlElement(writer, kMkvChapCountry, country_))
1398 return 0;
1399 }
1400
1401 const int64 stop = writer->Position();
1402
1403 if (stop >= start && uint64(stop - start) != display_size)
1404 return 0;
1405
1406 return display_size;
1407 }
1408
1409 ///////////////////////////////////////////////////////////////
1410 //
1411 // Chapters Class
1412
Chapters()1413 Chapters::Chapters() : chapters_size_(0), chapters_count_(0), chapters_(NULL) {}
1414
~Chapters()1415 Chapters::~Chapters() {
1416 while (chapters_count_ > 0) {
1417 Chapter& chapter = chapters_[--chapters_count_];
1418 chapter.Clear();
1419 }
1420
1421 delete[] chapters_;
1422 chapters_ = NULL;
1423 }
1424
Count() const1425 int Chapters::Count() const { return chapters_count_; }
1426
AddChapter(unsigned int * seed)1427 Chapter* Chapters::AddChapter(unsigned int* seed) {
1428 if (!ExpandChaptersArray())
1429 return NULL;
1430
1431 Chapter& chapter = chapters_[chapters_count_++];
1432 chapter.Init(seed);
1433
1434 return &chapter;
1435 }
1436
Write(IMkvWriter * writer) const1437 bool Chapters::Write(IMkvWriter* writer) const {
1438 if (writer == NULL)
1439 return false;
1440
1441 const uint64 payload_size = WriteEdition(NULL); // return size only
1442
1443 if (!WriteEbmlMasterElement(writer, kMkvChapters, payload_size))
1444 return false;
1445
1446 const int64 start = writer->Position();
1447
1448 if (WriteEdition(writer) == 0) // error
1449 return false;
1450
1451 const int64 stop = writer->Position();
1452
1453 if (stop >= start && uint64(stop - start) != payload_size)
1454 return false;
1455
1456 return true;
1457 }
1458
ExpandChaptersArray()1459 bool Chapters::ExpandChaptersArray() {
1460 if (chapters_size_ > chapters_count_)
1461 return true; // nothing to do yet
1462
1463 const int size = (chapters_size_ == 0) ? 1 : 2 * chapters_size_;
1464
1465 Chapter* const chapters = new (std::nothrow) Chapter[size]; // NOLINT
1466 if (chapters == NULL)
1467 return false;
1468
1469 for (int idx = 0; idx < chapters_count_; ++idx) {
1470 const Chapter& src = chapters_[idx];
1471 Chapter* const dst = chapters + idx;
1472 src.ShallowCopy(dst);
1473 }
1474
1475 delete[] chapters_;
1476
1477 chapters_ = chapters;
1478 chapters_size_ = size;
1479
1480 return true;
1481 }
1482
WriteEdition(IMkvWriter * writer) const1483 uint64 Chapters::WriteEdition(IMkvWriter* writer) const {
1484 uint64 payload_size = 0;
1485
1486 for (int idx = 0; idx < chapters_count_; ++idx) {
1487 const Chapter& chapter = chapters_[idx];
1488 payload_size += chapter.WriteAtom(NULL);
1489 }
1490
1491 const uint64 edition_size =
1492 EbmlMasterElementSize(kMkvEditionEntry, payload_size) + payload_size;
1493
1494 if (writer == NULL) // return size only
1495 return edition_size;
1496
1497 const int64 start = writer->Position();
1498
1499 if (!WriteEbmlMasterElement(writer, kMkvEditionEntry, payload_size))
1500 return 0; // error
1501
1502 for (int idx = 0; idx < chapters_count_; ++idx) {
1503 const Chapter& chapter = chapters_[idx];
1504
1505 const uint64 chapter_size = chapter.WriteAtom(writer);
1506 if (chapter_size == 0) // error
1507 return 0;
1508 }
1509
1510 const int64 stop = writer->Position();
1511
1512 if (stop >= start && uint64(stop - start) != edition_size)
1513 return 0;
1514
1515 return edition_size;
1516 }
1517
1518 // Tag Class
1519
add_simple_tag(const char * tag_name,const char * tag_string)1520 bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) {
1521 if (!ExpandSimpleTagsArray())
1522 return false;
1523
1524 SimpleTag& st = simple_tags_[simple_tags_count_++];
1525 st.Init();
1526
1527 if (!st.set_tag_name(tag_name))
1528 return false;
1529
1530 if (!st.set_tag_string(tag_string))
1531 return false;
1532
1533 return true;
1534 }
1535
Tag()1536 Tag::Tag() {
1537 simple_tags_ = NULL;
1538 simple_tags_size_ = 0;
1539 simple_tags_count_ = 0;
1540 }
1541
~Tag()1542 Tag::~Tag() {}
1543
ShallowCopy(Tag * dst) const1544 void Tag::ShallowCopy(Tag* dst) const {
1545 dst->simple_tags_ = simple_tags_;
1546 dst->simple_tags_size_ = simple_tags_size_;
1547 dst->simple_tags_count_ = simple_tags_count_;
1548 }
1549
Clear()1550 void Tag::Clear() {
1551 while (simple_tags_count_ > 0) {
1552 SimpleTag& st = simple_tags_[--simple_tags_count_];
1553 st.Clear();
1554 }
1555
1556 delete[] simple_tags_;
1557 simple_tags_ = NULL;
1558
1559 simple_tags_size_ = 0;
1560 }
1561
ExpandSimpleTagsArray()1562 bool Tag::ExpandSimpleTagsArray() {
1563 if (simple_tags_size_ > simple_tags_count_)
1564 return true; // nothing to do yet
1565
1566 const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_;
1567
1568 SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size]; // NOLINT
1569 if (simple_tags == NULL)
1570 return false;
1571
1572 for (int idx = 0; idx < simple_tags_count_; ++idx) {
1573 simple_tags[idx] = simple_tags_[idx]; // shallow copy
1574 }
1575
1576 delete[] simple_tags_;
1577
1578 simple_tags_ = simple_tags;
1579 simple_tags_size_ = size;
1580
1581 return true;
1582 }
1583
Write(IMkvWriter * writer) const1584 uint64 Tag::Write(IMkvWriter* writer) const {
1585 uint64 payload_size = 0;
1586
1587 for (int idx = 0; idx < simple_tags_count_; ++idx) {
1588 const SimpleTag& st = simple_tags_[idx];
1589 payload_size += st.Write(NULL);
1590 }
1591
1592 const uint64 tag_size =
1593 EbmlMasterElementSize(kMkvTag, payload_size) + payload_size;
1594
1595 if (writer == NULL)
1596 return tag_size;
1597
1598 const int64 start = writer->Position();
1599
1600 if (!WriteEbmlMasterElement(writer, kMkvTag, payload_size))
1601 return 0;
1602
1603 for (int idx = 0; idx < simple_tags_count_; ++idx) {
1604 const SimpleTag& st = simple_tags_[idx];
1605
1606 if (!st.Write(writer))
1607 return 0;
1608 }
1609
1610 const int64 stop = writer->Position();
1611
1612 if (stop >= start && uint64(stop - start) != tag_size)
1613 return 0;
1614
1615 return tag_size;
1616 }
1617
1618 // Tag::SimpleTag
1619
Init()1620 void Tag::SimpleTag::Init() {
1621 tag_name_ = NULL;
1622 tag_string_ = NULL;
1623 }
1624
Clear()1625 void Tag::SimpleTag::Clear() {
1626 StrCpy(NULL, &tag_name_);
1627 StrCpy(NULL, &tag_string_);
1628 }
1629
set_tag_name(const char * tag_name)1630 bool Tag::SimpleTag::set_tag_name(const char* tag_name) {
1631 return StrCpy(tag_name, &tag_name_);
1632 }
1633
set_tag_string(const char * tag_string)1634 bool Tag::SimpleTag::set_tag_string(const char* tag_string) {
1635 return StrCpy(tag_string, &tag_string_);
1636 }
1637
Write(IMkvWriter * writer) const1638 uint64 Tag::SimpleTag::Write(IMkvWriter* writer) const {
1639 uint64 payload_size = EbmlElementSize(kMkvTagName, tag_name_);
1640
1641 payload_size += EbmlElementSize(kMkvTagString, tag_string_);
1642
1643 const uint64 simple_tag_size =
1644 EbmlMasterElementSize(kMkvSimpleTag, payload_size) + payload_size;
1645
1646 if (writer == NULL)
1647 return simple_tag_size;
1648
1649 const int64 start = writer->Position();
1650
1651 if (!WriteEbmlMasterElement(writer, kMkvSimpleTag, payload_size))
1652 return 0;
1653
1654 if (!WriteEbmlElement(writer, kMkvTagName, tag_name_))
1655 return 0;
1656
1657 if (!WriteEbmlElement(writer, kMkvTagString, tag_string_))
1658 return 0;
1659
1660 const int64 stop = writer->Position();
1661
1662 if (stop >= start && uint64(stop - start) != simple_tag_size)
1663 return 0;
1664
1665 return simple_tag_size;
1666 }
1667
1668 // Tags Class
1669
Tags()1670 Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {}
1671
~Tags()1672 Tags::~Tags() {
1673 while (tags_count_ > 0) {
1674 Tag& tag = tags_[--tags_count_];
1675 tag.Clear();
1676 }
1677
1678 delete[] tags_;
1679 tags_ = NULL;
1680 }
1681
Count() const1682 int Tags::Count() const { return tags_count_; }
1683
AddTag()1684 Tag* Tags::AddTag() {
1685 if (!ExpandTagsArray())
1686 return NULL;
1687
1688 Tag& tag = tags_[tags_count_++];
1689
1690 return &tag;
1691 }
1692
Write(IMkvWriter * writer) const1693 bool Tags::Write(IMkvWriter* writer) const {
1694 if (writer == NULL)
1695 return false;
1696
1697 uint64 payload_size = 0;
1698
1699 for (int idx = 0; idx < tags_count_; ++idx) {
1700 const Tag& tag = tags_[idx];
1701 payload_size += tag.Write(NULL);
1702 }
1703
1704 if (!WriteEbmlMasterElement(writer, kMkvTags, payload_size))
1705 return false;
1706
1707 const int64 start = writer->Position();
1708
1709 for (int idx = 0; idx < tags_count_; ++idx) {
1710 const Tag& tag = tags_[idx];
1711
1712 const uint64 tag_size = tag.Write(writer);
1713 if (tag_size == 0) // error
1714 return 0;
1715 }
1716
1717 const int64 stop = writer->Position();
1718
1719 if (stop >= start && uint64(stop - start) != payload_size)
1720 return false;
1721
1722 return true;
1723 }
1724
ExpandTagsArray()1725 bool Tags::ExpandTagsArray() {
1726 if (tags_size_ > tags_count_)
1727 return true; // nothing to do yet
1728
1729 const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_;
1730
1731 Tag* const tags = new (std::nothrow) Tag[size]; // NOLINT
1732 if (tags == NULL)
1733 return false;
1734
1735 for (int idx = 0; idx < tags_count_; ++idx) {
1736 const Tag& src = tags_[idx];
1737 Tag* const dst = tags + idx;
1738 src.ShallowCopy(dst);
1739 }
1740
1741 delete[] tags_;
1742
1743 tags_ = tags;
1744 tags_size_ = size;
1745
1746 return true;
1747 }
1748
1749 ///////////////////////////////////////////////////////////////
1750 //
1751 // Cluster class
1752
Cluster(uint64 timecode,int64 cues_pos,uint64 timecode_scale)1753 Cluster::Cluster(uint64 timecode, int64 cues_pos, uint64 timecode_scale)
1754 : blocks_added_(0),
1755 finalized_(false),
1756 header_written_(false),
1757 payload_size_(0),
1758 position_for_cues_(cues_pos),
1759 size_position_(-1),
1760 timecode_(timecode),
1761 timecode_scale_(timecode_scale),
1762 writer_(NULL) {}
1763
~Cluster()1764 Cluster::~Cluster() {}
1765
Init(IMkvWriter * ptr_writer)1766 bool Cluster::Init(IMkvWriter* ptr_writer) {
1767 if (!ptr_writer) {
1768 return false;
1769 }
1770 writer_ = ptr_writer;
1771 return true;
1772 }
1773
AddFrame(const Frame * const frame)1774 bool Cluster::AddFrame(const Frame* const frame) { return DoWriteFrame(frame); }
1775
AddFrame(const uint8 * data,uint64 length,uint64 track_number,uint64 abs_timecode,bool is_key)1776 bool Cluster::AddFrame(const uint8* data, uint64 length, uint64 track_number,
1777 uint64 abs_timecode, bool is_key) {
1778 Frame frame;
1779 if (!frame.Init(data, length))
1780 return false;
1781 frame.set_track_number(track_number);
1782 frame.set_timestamp(abs_timecode);
1783 frame.set_is_key(is_key);
1784 return DoWriteFrame(&frame);
1785 }
1786
AddFrameWithAdditional(const uint8 * data,uint64 length,const uint8 * additional,uint64 additional_length,uint64 add_id,uint64 track_number,uint64 abs_timecode,bool is_key)1787 bool Cluster::AddFrameWithAdditional(const uint8* data, uint64 length,
1788 const uint8* additional,
1789 uint64 additional_length, uint64 add_id,
1790 uint64 track_number, uint64 abs_timecode,
1791 bool is_key) {
1792 if (!additional || additional_length == 0) {
1793 return false;
1794 }
1795 Frame frame;
1796 if (!frame.Init(data, length) ||
1797 !frame.AddAdditionalData(additional, additional_length, add_id)) {
1798 return false;
1799 }
1800 frame.set_track_number(track_number);
1801 frame.set_timestamp(abs_timecode);
1802 frame.set_is_key(is_key);
1803 return DoWriteFrame(&frame);
1804 }
1805
AddFrameWithDiscardPadding(const uint8 * data,uint64 length,int64 discard_padding,uint64 track_number,uint64 abs_timecode,bool is_key)1806 bool Cluster::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
1807 int64 discard_padding,
1808 uint64 track_number,
1809 uint64 abs_timecode, bool is_key) {
1810 Frame frame;
1811 if (!frame.Init(data, length))
1812 return false;
1813 frame.set_discard_padding(discard_padding);
1814 frame.set_track_number(track_number);
1815 frame.set_timestamp(abs_timecode);
1816 frame.set_is_key(is_key);
1817 return DoWriteFrame(&frame);
1818 }
1819
AddMetadata(const uint8 * data,uint64 length,uint64 track_number,uint64 abs_timecode,uint64 duration_timecode)1820 bool Cluster::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
1821 uint64 abs_timecode, uint64 duration_timecode) {
1822 Frame frame;
1823 if (!frame.Init(data, length))
1824 return false;
1825 frame.set_track_number(track_number);
1826 frame.set_timestamp(abs_timecode);
1827 frame.set_duration(duration_timecode);
1828 frame.set_is_key(true); // All metadata blocks are keyframes.
1829 return DoWriteFrame(&frame);
1830 }
1831
AddPayloadSize(uint64 size)1832 void Cluster::AddPayloadSize(uint64 size) { payload_size_ += size; }
1833
Finalize()1834 bool Cluster::Finalize() {
1835 if (!writer_ || finalized_ || size_position_ == -1)
1836 return false;
1837
1838 if (writer_->Seekable()) {
1839 const int64 pos = writer_->Position();
1840
1841 if (writer_->Position(size_position_))
1842 return false;
1843
1844 if (WriteUIntSize(writer_, payload_size(), 8))
1845 return false;
1846
1847 if (writer_->Position(pos))
1848 return false;
1849 }
1850
1851 finalized_ = true;
1852
1853 return true;
1854 }
1855
Size() const1856 uint64 Cluster::Size() const {
1857 const uint64 element_size =
1858 EbmlMasterElementSize(kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) + payload_size_;
1859 return element_size;
1860 }
1861
PreWriteBlock()1862 bool Cluster::PreWriteBlock() {
1863 if (finalized_)
1864 return false;
1865
1866 if (!header_written_) {
1867 if (!WriteClusterHeader())
1868 return false;
1869 }
1870
1871 return true;
1872 }
1873
PostWriteBlock(uint64 element_size)1874 void Cluster::PostWriteBlock(uint64 element_size) {
1875 AddPayloadSize(element_size);
1876 ++blocks_added_;
1877 }
1878
GetRelativeTimecode(int64 abs_timecode) const1879 int64 Cluster::GetRelativeTimecode(int64 abs_timecode) const {
1880 const int64 cluster_timecode = this->Cluster::timecode();
1881 const int64 rel_timecode =
1882 static_cast<int64>(abs_timecode) - cluster_timecode;
1883
1884 if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode)
1885 return -1;
1886
1887 return rel_timecode;
1888 }
1889
DoWriteFrame(const Frame * const frame)1890 bool Cluster::DoWriteFrame(const Frame* const frame) {
1891 if (!frame || !frame->IsValid())
1892 return false;
1893
1894 if (!PreWriteBlock())
1895 return false;
1896
1897 const uint64 element_size = WriteFrame(writer_, frame, this);
1898 if (element_size == 0)
1899 return false;
1900
1901 PostWriteBlock(element_size);
1902 return true;
1903 }
1904
WriteClusterHeader()1905 bool Cluster::WriteClusterHeader() {
1906 if (finalized_)
1907 return false;
1908
1909 if (WriteID(writer_, kMkvCluster))
1910 return false;
1911
1912 // Save for later.
1913 size_position_ = writer_->Position();
1914
1915 // Write "unknown" (EBML coded -1) as cluster size value. We need to write 8
1916 // bytes because we do not know how big our cluster will be.
1917 if (SerializeInt(writer_, kEbmlUnknownValue, 8))
1918 return false;
1919
1920 if (!WriteEbmlElement(writer_, kMkvTimecode, timecode()))
1921 return false;
1922 AddPayloadSize(EbmlElementSize(kMkvTimecode, timecode()));
1923 header_written_ = true;
1924
1925 return true;
1926 }
1927
1928 ///////////////////////////////////////////////////////////////
1929 //
1930 // SeekHead Class
1931
SeekHead()1932 SeekHead::SeekHead() : start_pos_(0ULL) {
1933 for (int32 i = 0; i < kSeekEntryCount; ++i) {
1934 seek_entry_id_[i] = 0;
1935 seek_entry_pos_[i] = 0;
1936 }
1937 }
1938
~SeekHead()1939 SeekHead::~SeekHead() {}
1940
Finalize(IMkvWriter * writer) const1941 bool SeekHead::Finalize(IMkvWriter* writer) const {
1942 if (writer->Seekable()) {
1943 if (start_pos_ == -1)
1944 return false;
1945
1946 uint64 payload_size = 0;
1947 uint64 entry_size[kSeekEntryCount];
1948
1949 for (int32 i = 0; i < kSeekEntryCount; ++i) {
1950 if (seek_entry_id_[i] != 0) {
1951 entry_size[i] =
1952 EbmlElementSize(kMkvSeekID, static_cast<uint64>(seek_entry_id_[i]));
1953 entry_size[i] += EbmlElementSize(kMkvSeekPosition, seek_entry_pos_[i]);
1954
1955 payload_size +=
1956 EbmlMasterElementSize(kMkvSeek, entry_size[i]) + entry_size[i];
1957 }
1958 }
1959
1960 // No SeekHead elements
1961 if (payload_size == 0)
1962 return true;
1963
1964 const int64 pos = writer->Position();
1965 if (writer->Position(start_pos_))
1966 return false;
1967
1968 if (!WriteEbmlMasterElement(writer, kMkvSeekHead, payload_size))
1969 return false;
1970
1971 for (int32 i = 0; i < kSeekEntryCount; ++i) {
1972 if (seek_entry_id_[i] != 0) {
1973 if (!WriteEbmlMasterElement(writer, kMkvSeek, entry_size[i]))
1974 return false;
1975
1976 if (!WriteEbmlElement(writer, kMkvSeekID,
1977 static_cast<uint64>(seek_entry_id_[i])))
1978 return false;
1979
1980 if (!WriteEbmlElement(writer, kMkvSeekPosition, seek_entry_pos_[i]))
1981 return false;
1982 }
1983 }
1984
1985 const uint64 total_entry_size = kSeekEntryCount * MaxEntrySize();
1986 const uint64 total_size =
1987 EbmlMasterElementSize(kMkvSeekHead, total_entry_size) +
1988 total_entry_size;
1989 const int64 size_left = total_size - (writer->Position() - start_pos_);
1990
1991 const uint64 bytes_written = WriteVoidElement(writer, size_left);
1992 if (!bytes_written)
1993 return false;
1994
1995 if (writer->Position(pos))
1996 return false;
1997 }
1998
1999 return true;
2000 }
2001
Write(IMkvWriter * writer)2002 bool SeekHead::Write(IMkvWriter* writer) {
2003 const uint64 entry_size = kSeekEntryCount * MaxEntrySize();
2004 const uint64 size = EbmlMasterElementSize(kMkvSeekHead, entry_size);
2005
2006 start_pos_ = writer->Position();
2007
2008 const uint64 bytes_written = WriteVoidElement(writer, size + entry_size);
2009 if (!bytes_written)
2010 return false;
2011
2012 return true;
2013 }
2014
AddSeekEntry(uint32 id,uint64 pos)2015 bool SeekHead::AddSeekEntry(uint32 id, uint64 pos) {
2016 for (int32 i = 0; i < kSeekEntryCount; ++i) {
2017 if (seek_entry_id_[i] == 0) {
2018 seek_entry_id_[i] = id;
2019 seek_entry_pos_[i] = pos;
2020 return true;
2021 }
2022 }
2023 return false;
2024 }
2025
GetId(int index) const2026 uint32 SeekHead::GetId(int index) const {
2027 if (index < 0 || index >= kSeekEntryCount)
2028 return UINT_MAX;
2029 return seek_entry_id_[index];
2030 }
2031
GetPosition(int index) const2032 uint64 SeekHead::GetPosition(int index) const {
2033 if (index < 0 || index >= kSeekEntryCount)
2034 return ULLONG_MAX;
2035 return seek_entry_pos_[index];
2036 }
2037
SetSeekEntry(int index,uint32 id,uint64 position)2038 bool SeekHead::SetSeekEntry(int index, uint32 id, uint64 position) {
2039 if (index < 0 || index >= kSeekEntryCount)
2040 return false;
2041 seek_entry_id_[index] = id;
2042 seek_entry_pos_[index] = position;
2043 return true;
2044 }
2045
MaxEntrySize() const2046 uint64 SeekHead::MaxEntrySize() const {
2047 const uint64 max_entry_payload_size =
2048 EbmlElementSize(kMkvSeekID, 0xffffffffULL) +
2049 EbmlElementSize(kMkvSeekPosition, 0xffffffffffffffffULL);
2050 const uint64 max_entry_size =
2051 EbmlMasterElementSize(kMkvSeek, max_entry_payload_size) +
2052 max_entry_payload_size;
2053
2054 return max_entry_size;
2055 }
2056
2057 ///////////////////////////////////////////////////////////////
2058 //
2059 // SegmentInfo Class
2060
SegmentInfo()2061 SegmentInfo::SegmentInfo()
2062 : duration_(-1.0),
2063 muxing_app_(NULL),
2064 timecode_scale_(1000000ULL),
2065 writing_app_(NULL),
2066 date_utc_(LLONG_MIN),
2067 duration_pos_(-1) {}
2068
~SegmentInfo()2069 SegmentInfo::~SegmentInfo() {
2070 delete[] muxing_app_;
2071 delete[] writing_app_;
2072 }
2073
Init()2074 bool SegmentInfo::Init() {
2075 int32 major;
2076 int32 minor;
2077 int32 build;
2078 int32 revision;
2079 GetVersion(&major, &minor, &build, &revision);
2080 char temp[256];
2081 #ifdef _MSC_VER
2082 sprintf_s(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
2083 minor, build, revision);
2084 #else
2085 snprintf(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
2086 minor, build, revision);
2087 #endif
2088
2089 const size_t app_len = strlen(temp) + 1;
2090
2091 delete[] muxing_app_;
2092
2093 muxing_app_ = new (std::nothrow) char[app_len]; // NOLINT
2094 if (!muxing_app_)
2095 return false;
2096
2097 #ifdef _MSC_VER
2098 strcpy_s(muxing_app_, app_len, temp);
2099 #else
2100 strcpy(muxing_app_, temp);
2101 #endif
2102
2103 set_writing_app(temp);
2104 if (!writing_app_)
2105 return false;
2106 return true;
2107 }
2108
Finalize(IMkvWriter * writer) const2109 bool SegmentInfo::Finalize(IMkvWriter* writer) const {
2110 if (!writer)
2111 return false;
2112
2113 if (duration_ > 0.0) {
2114 if (writer->Seekable()) {
2115 if (duration_pos_ == -1)
2116 return false;
2117
2118 const int64 pos = writer->Position();
2119
2120 if (writer->Position(duration_pos_))
2121 return false;
2122
2123 if (!WriteEbmlElement(writer, kMkvDuration,
2124 static_cast<float>(duration_)))
2125 return false;
2126
2127 if (writer->Position(pos))
2128 return false;
2129 }
2130 }
2131
2132 return true;
2133 }
2134
Write(IMkvWriter * writer)2135 bool SegmentInfo::Write(IMkvWriter* writer) {
2136 if (!writer || !muxing_app_ || !writing_app_)
2137 return false;
2138
2139 uint64 size = EbmlElementSize(kMkvTimecodeScale, timecode_scale_);
2140 if (duration_ > 0.0)
2141 size += EbmlElementSize(kMkvDuration, static_cast<float>(duration_));
2142 if (date_utc_ != LLONG_MIN)
2143 size += EbmlDateElementSize(kMkvDateUTC);
2144 size += EbmlElementSize(kMkvMuxingApp, muxing_app_);
2145 size += EbmlElementSize(kMkvWritingApp, writing_app_);
2146
2147 if (!WriteEbmlMasterElement(writer, kMkvInfo, size))
2148 return false;
2149
2150 const int64 payload_position = writer->Position();
2151 if (payload_position < 0)
2152 return false;
2153
2154 if (!WriteEbmlElement(writer, kMkvTimecodeScale, timecode_scale_))
2155 return false;
2156
2157 if (duration_ > 0.0) {
2158 // Save for later
2159 duration_pos_ = writer->Position();
2160
2161 if (!WriteEbmlElement(writer, kMkvDuration, static_cast<float>(duration_)))
2162 return false;
2163 }
2164
2165 if (date_utc_ != LLONG_MIN)
2166 WriteEbmlDateElement(writer, kMkvDateUTC, date_utc_);
2167
2168 if (!WriteEbmlElement(writer, kMkvMuxingApp, muxing_app_))
2169 return false;
2170 if (!WriteEbmlElement(writer, kMkvWritingApp, writing_app_))
2171 return false;
2172
2173 const int64 stop_position = writer->Position();
2174 if (stop_position < 0 ||
2175 stop_position - payload_position != static_cast<int64>(size))
2176 return false;
2177
2178 return true;
2179 }
2180
set_muxing_app(const char * app)2181 void SegmentInfo::set_muxing_app(const char* app) {
2182 if (app) {
2183 const size_t length = strlen(app) + 1;
2184 char* temp_str = new (std::nothrow) char[length]; // NOLINT
2185 if (!temp_str)
2186 return;
2187
2188 #ifdef _MSC_VER
2189 strcpy_s(temp_str, length, app);
2190 #else
2191 strcpy(temp_str, app);
2192 #endif
2193
2194 delete[] muxing_app_;
2195 muxing_app_ = temp_str;
2196 }
2197 }
2198
set_writing_app(const char * app)2199 void SegmentInfo::set_writing_app(const char* app) {
2200 if (app) {
2201 const size_t length = strlen(app) + 1;
2202 char* temp_str = new (std::nothrow) char[length]; // NOLINT
2203 if (!temp_str)
2204 return;
2205
2206 #ifdef _MSC_VER
2207 strcpy_s(temp_str, length, app);
2208 #else
2209 strcpy(temp_str, app);
2210 #endif
2211
2212 delete[] writing_app_;
2213 writing_app_ = temp_str;
2214 }
2215 }
2216
2217 ///////////////////////////////////////////////////////////////
2218 //
2219 // Segment Class
2220
Segment()2221 Segment::Segment()
2222 : chunk_count_(0),
2223 chunk_name_(NULL),
2224 chunk_writer_cluster_(NULL),
2225 chunk_writer_cues_(NULL),
2226 chunk_writer_header_(NULL),
2227 chunking_(false),
2228 chunking_base_name_(NULL),
2229 cluster_list_(NULL),
2230 cluster_list_capacity_(0),
2231 cluster_list_size_(0),
2232 cues_position_(kAfterClusters),
2233 cues_track_(0),
2234 force_new_cluster_(false),
2235 frames_(NULL),
2236 frames_capacity_(0),
2237 frames_size_(0),
2238 has_video_(false),
2239 header_written_(false),
2240 last_block_duration_(0),
2241 last_timestamp_(0),
2242 max_cluster_duration_(kDefaultMaxClusterDuration),
2243 max_cluster_size_(0),
2244 mode_(kFile),
2245 new_cuepoint_(false),
2246 output_cues_(true),
2247 payload_pos_(0),
2248 size_position_(0),
2249 doc_type_version_(kDefaultDocTypeVersion),
2250 doc_type_version_written_(0),
2251 writer_cluster_(NULL),
2252 writer_cues_(NULL),
2253 writer_header_(NULL) {
2254 const time_t curr_time = time(NULL);
2255 seed_ = static_cast<unsigned int>(curr_time);
2256 #ifdef _WIN32
2257 srand(seed_);
2258 #endif
2259 }
2260
~Segment()2261 Segment::~Segment() {
2262 if (cluster_list_) {
2263 for (int32 i = 0; i < cluster_list_size_; ++i) {
2264 Cluster* const cluster = cluster_list_[i];
2265 delete cluster;
2266 }
2267 delete[] cluster_list_;
2268 }
2269
2270 if (frames_) {
2271 for (int32 i = 0; i < frames_size_; ++i) {
2272 Frame* const frame = frames_[i];
2273 delete frame;
2274 }
2275 delete[] frames_;
2276 }
2277
2278 delete[] chunk_name_;
2279 delete[] chunking_base_name_;
2280
2281 if (chunk_writer_cluster_) {
2282 chunk_writer_cluster_->Close();
2283 delete chunk_writer_cluster_;
2284 }
2285 if (chunk_writer_cues_) {
2286 chunk_writer_cues_->Close();
2287 delete chunk_writer_cues_;
2288 }
2289 if (chunk_writer_header_) {
2290 chunk_writer_header_->Close();
2291 delete chunk_writer_header_;
2292 }
2293 }
2294
MoveCuesBeforeClustersHelper(uint64 diff,int32 index,uint64 * cues_size)2295 void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index,
2296 uint64* cues_size) {
2297 CuePoint* const cue_point = cues_.GetCueByIndex(index);
2298 if (cue_point == NULL)
2299 return;
2300 const uint64 old_cue_point_size = cue_point->Size();
2301 const uint64 cluster_pos = cue_point->cluster_pos() + diff;
2302 cue_point->set_cluster_pos(cluster_pos); // update the new cluster position
2303 // New size of the cue is computed as follows
2304 // Let a = current sum of size of all CuePoints
2305 // Let b = Increase in Cue Point's size due to this iteration
2306 // Let c = Increase in size of Cues Element's length due to this iteration
2307 // (This is computed as CodedSize(a + b) - CodedSize(a))
2308 // Let d = b + c. Now d is the |diff| passed to the next recursive call.
2309 // Let e = a + b. Now e is the |cues_size| passed to the next recursive
2310 // call.
2311 const uint64 cue_point_size_diff = cue_point->Size() - old_cue_point_size;
2312 const uint64 cue_size_diff =
2313 GetCodedUIntSize(*cues_size + cue_point_size_diff) -
2314 GetCodedUIntSize(*cues_size);
2315 *cues_size += cue_point_size_diff;
2316 diff = cue_size_diff + cue_point_size_diff;
2317 if (diff > 0) {
2318 for (int32 i = 0; i < cues_.cue_entries_size(); ++i) {
2319 MoveCuesBeforeClustersHelper(diff, i, cues_size);
2320 }
2321 }
2322 }
2323
MoveCuesBeforeClusters()2324 void Segment::MoveCuesBeforeClusters() {
2325 const uint64 current_cue_size = cues_.Size();
2326 uint64 cue_size = 0;
2327 for (int32 i = 0; i < cues_.cue_entries_size(); ++i)
2328 cue_size += cues_.GetCueByIndex(i)->Size();
2329 for (int32 i = 0; i < cues_.cue_entries_size(); ++i)
2330 MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size);
2331
2332 // Adjust the Seek Entry to reflect the change in position
2333 // of Cluster and Cues
2334 int32 cluster_index = 0;
2335 int32 cues_index = 0;
2336 for (int32 i = 0; i < SeekHead::kSeekEntryCount; ++i) {
2337 if (seek_head_.GetId(i) == kMkvCluster)
2338 cluster_index = i;
2339 if (seek_head_.GetId(i) == kMkvCues)
2340 cues_index = i;
2341 }
2342 seek_head_.SetSeekEntry(cues_index, kMkvCues,
2343 seek_head_.GetPosition(cluster_index));
2344 seek_head_.SetSeekEntry(cluster_index, kMkvCluster,
2345 cues_.Size() + seek_head_.GetPosition(cues_index));
2346 }
2347
Init(IMkvWriter * ptr_writer)2348 bool Segment::Init(IMkvWriter* ptr_writer) {
2349 if (!ptr_writer) {
2350 return false;
2351 }
2352 writer_cluster_ = ptr_writer;
2353 writer_cues_ = ptr_writer;
2354 writer_header_ = ptr_writer;
2355 return segment_info_.Init();
2356 }
2357
CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader * reader,IMkvWriter * writer)2358 bool Segment::CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
2359 IMkvWriter* writer) {
2360 if (!writer->Seekable() || chunking_)
2361 return false;
2362 const int64 cluster_offset =
2363 cluster_list_[0]->size_position() - GetUIntSize(kMkvCluster);
2364
2365 // Copy the headers.
2366 if (!ChunkedCopy(reader, writer, 0, cluster_offset))
2367 return false;
2368
2369 // Recompute cue positions and seek entries.
2370 MoveCuesBeforeClusters();
2371
2372 // Write cues and seek entries.
2373 // TODO(vigneshv): As of now, it's safe to call seek_head_.Finalize() for the
2374 // second time with a different writer object. But the name Finalize() doesn't
2375 // indicate something we want to call more than once. So consider renaming it
2376 // to write() or some such.
2377 if (!cues_.Write(writer) || !seek_head_.Finalize(writer))
2378 return false;
2379
2380 // Copy the Clusters.
2381 if (!ChunkedCopy(reader, writer, cluster_offset,
2382 cluster_end_offset_ - cluster_offset))
2383 return false;
2384
2385 // Update the Segment size in case the Cues size has changed.
2386 const int64 pos = writer->Position();
2387 const int64 segment_size = writer->Position() - payload_pos_;
2388 if (writer->Position(size_position_) ||
2389 WriteUIntSize(writer, segment_size, 8) || writer->Position(pos))
2390 return false;
2391 return true;
2392 }
2393
Finalize()2394 bool Segment::Finalize() {
2395 if (WriteFramesAll() < 0)
2396 return false;
2397
2398 if (mode_ == kFile) {
2399 if (cluster_list_size_ > 0) {
2400 // Update last cluster's size
2401 Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
2402
2403 if (!old_cluster || !old_cluster->Finalize())
2404 return false;
2405 }
2406
2407 if (chunking_ && chunk_writer_cluster_) {
2408 chunk_writer_cluster_->Close();
2409 chunk_count_++;
2410 }
2411
2412 const double duration =
2413 (static_cast<double>(last_timestamp_) + last_block_duration_) /
2414 segment_info_.timecode_scale();
2415 segment_info_.set_duration(duration);
2416 if (!segment_info_.Finalize(writer_header_))
2417 return false;
2418
2419 if (output_cues_)
2420 if (!seek_head_.AddSeekEntry(kMkvCues, MaxOffset()))
2421 return false;
2422
2423 if (chunking_) {
2424 if (!chunk_writer_cues_)
2425 return false;
2426
2427 char* name = NULL;
2428 if (!UpdateChunkName("cues", &name))
2429 return false;
2430
2431 const bool cues_open = chunk_writer_cues_->Open(name);
2432 delete[] name;
2433 if (!cues_open)
2434 return false;
2435 }
2436
2437 cluster_end_offset_ = writer_cluster_->Position();
2438
2439 // Write the seek headers and cues
2440 if (output_cues_)
2441 if (!cues_.Write(writer_cues_))
2442 return false;
2443
2444 if (!seek_head_.Finalize(writer_header_))
2445 return false;
2446
2447 if (writer_header_->Seekable()) {
2448 if (size_position_ == -1)
2449 return false;
2450
2451 const int64 segment_size = MaxOffset();
2452 if (segment_size < 1)
2453 return false;
2454
2455 const int64 pos = writer_header_->Position();
2456 UpdateDocTypeVersion();
2457 if (doc_type_version_ != doc_type_version_written_) {
2458 if (writer_header_->Position(0))
2459 return false;
2460
2461 if (!WriteEbmlHeader(writer_header_, doc_type_version_))
2462 return false;
2463 if (writer_header_->Position() != ebml_header_size_)
2464 return false;
2465
2466 doc_type_version_written_ = doc_type_version_;
2467 }
2468
2469 if (writer_header_->Position(size_position_))
2470 return false;
2471
2472 if (WriteUIntSize(writer_header_, segment_size, 8))
2473 return false;
2474
2475 if (writer_header_->Position(pos))
2476 return false;
2477 }
2478
2479 if (chunking_) {
2480 // Do not close any writers until the segment size has been written,
2481 // otherwise the size may be off.
2482 if (!chunk_writer_cues_ || !chunk_writer_header_)
2483 return false;
2484
2485 chunk_writer_cues_->Close();
2486 chunk_writer_header_->Close();
2487 }
2488 }
2489
2490 return true;
2491 }
2492
AddTrack(int32 number)2493 Track* Segment::AddTrack(int32 number) {
2494 Track* const track = new (std::nothrow) Track(&seed_); // NOLINT
2495
2496 if (!track)
2497 return NULL;
2498
2499 if (!tracks_.AddTrack(track, number)) {
2500 delete track;
2501 return NULL;
2502 }
2503
2504 return track;
2505 }
2506
AddChapter()2507 Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
2508
AddTag()2509 Tag* Segment::AddTag() { return tags_.AddTag(); }
2510
AddVideoTrack(int32 width,int32 height,int32 number)2511 uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) {
2512 VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_); // NOLINT
2513 if (!track)
2514 return 0;
2515
2516 track->set_type(Tracks::kVideo);
2517 track->set_codec_id(Tracks::kVp8CodecId);
2518 track->set_width(width);
2519 track->set_height(height);
2520
2521 tracks_.AddTrack(track, number);
2522 has_video_ = true;
2523
2524 return track->number();
2525 }
2526
AddCuePoint(uint64 timestamp,uint64 track)2527 bool Segment::AddCuePoint(uint64 timestamp, uint64 track) {
2528 if (cluster_list_size_ < 1)
2529 return false;
2530
2531 const Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
2532 if (!cluster)
2533 return false;
2534
2535 CuePoint* const cue = new (std::nothrow) CuePoint(); // NOLINT
2536 if (!cue)
2537 return false;
2538
2539 cue->set_time(timestamp / segment_info_.timecode_scale());
2540 cue->set_block_number(cluster->blocks_added());
2541 cue->set_cluster_pos(cluster->position_for_cues());
2542 cue->set_track(track);
2543 if (!cues_.AddCue(cue))
2544 return false;
2545
2546 new_cuepoint_ = false;
2547 return true;
2548 }
2549
AddAudioTrack(int32 sample_rate,int32 channels,int32 number)2550 uint64 Segment::AddAudioTrack(int32 sample_rate, int32 channels, int32 number) {
2551 AudioTrack* const track = new (std::nothrow) AudioTrack(&seed_); // NOLINT
2552 if (!track)
2553 return 0;
2554
2555 track->set_type(Tracks::kAudio);
2556 track->set_codec_id(Tracks::kVorbisCodecId);
2557 track->set_sample_rate(sample_rate);
2558 track->set_channels(channels);
2559
2560 tracks_.AddTrack(track, number);
2561
2562 return track->number();
2563 }
2564
AddFrame(const uint8 * data,uint64 length,uint64 track_number,uint64 timestamp,bool is_key)2565 bool Segment::AddFrame(const uint8* data, uint64 length, uint64 track_number,
2566 uint64 timestamp, bool is_key) {
2567 if (!data)
2568 return false;
2569
2570 Frame frame;
2571 if (!frame.Init(data, length))
2572 return false;
2573 frame.set_track_number(track_number);
2574 frame.set_timestamp(timestamp);
2575 frame.set_is_key(is_key);
2576 return AddGenericFrame(&frame);
2577 }
2578
AddFrameWithAdditional(const uint8 * data,uint64 length,const uint8 * additional,uint64 additional_length,uint64 add_id,uint64 track_number,uint64 timestamp,bool is_key)2579 bool Segment::AddFrameWithAdditional(const uint8* data, uint64 length,
2580 const uint8* additional,
2581 uint64 additional_length, uint64 add_id,
2582 uint64 track_number, uint64 timestamp,
2583 bool is_key) {
2584 if (!data || !additional)
2585 return false;
2586
2587 Frame frame;
2588 if (!frame.Init(data, length) ||
2589 !frame.AddAdditionalData(additional, additional_length, add_id)) {
2590 return false;
2591 }
2592 frame.set_track_number(track_number);
2593 frame.set_timestamp(timestamp);
2594 frame.set_is_key(is_key);
2595 return AddGenericFrame(&frame);
2596 }
2597
AddFrameWithDiscardPadding(const uint8 * data,uint64 length,int64 discard_padding,uint64 track_number,uint64 timestamp,bool is_key)2598 bool Segment::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
2599 int64 discard_padding,
2600 uint64 track_number, uint64 timestamp,
2601 bool is_key) {
2602 if (!data)
2603 return false;
2604
2605 Frame frame;
2606 if (!frame.Init(data, length))
2607 return false;
2608 frame.set_discard_padding(discard_padding);
2609 frame.set_track_number(track_number);
2610 frame.set_timestamp(timestamp);
2611 frame.set_is_key(is_key);
2612 return AddGenericFrame(&frame);
2613 }
2614
AddMetadata(const uint8 * data,uint64 length,uint64 track_number,uint64 timestamp_ns,uint64 duration_ns)2615 bool Segment::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
2616 uint64 timestamp_ns, uint64 duration_ns) {
2617 if (!data)
2618 return false;
2619
2620 Frame frame;
2621 if (!frame.Init(data, length))
2622 return false;
2623 frame.set_track_number(track_number);
2624 frame.set_timestamp(timestamp_ns);
2625 frame.set_duration(duration_ns);
2626 frame.set_is_key(true); // All metadata blocks are keyframes.
2627 return AddGenericFrame(&frame);
2628 }
2629
AddGenericFrame(const Frame * frame)2630 bool Segment::AddGenericFrame(const Frame* frame) {
2631 if (!frame)
2632 return false;
2633
2634 if (!CheckHeaderInfo())
2635 return false;
2636
2637 // Check for non-monotonically increasing timestamps.
2638 if (frame->timestamp() < last_timestamp_)
2639 return false;
2640
2641 // Check if the track number is valid.
2642 if (!tracks_.GetTrackByNumber(frame->track_number()))
2643 return false;
2644
2645 if (frame->discard_padding() != 0)
2646 doc_type_version_ = 4;
2647
2648 // If the segment has a video track hold onto audio frames to make sure the
2649 // audio that is associated with the start time of a video key-frame is
2650 // muxed into the same cluster.
2651 if (has_video_ && tracks_.TrackIsAudio(frame->track_number()) &&
2652 !force_new_cluster_) {
2653 Frame* const new_frame = new (std::nothrow) Frame();
2654 if (!new_frame || !new_frame->CopyFrom(*frame))
2655 return false;
2656 return QueueFrame(new_frame);
2657 }
2658
2659 if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(),
2660 frame->is_key())) {
2661 return false;
2662 }
2663
2664 if (cluster_list_size_ < 1)
2665 return false;
2666
2667 Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
2668 if (!cluster)
2669 return false;
2670
2671 // If the Frame is not a SimpleBlock, then set the reference_block_timestamp
2672 // if it is not set already.
2673 bool frame_created = false;
2674 if (!frame->CanBeSimpleBlock() && !frame->is_key() &&
2675 !frame->reference_block_timestamp_set()) {
2676 Frame* const new_frame = new (std::nothrow) Frame();
2677 if (!new_frame->CopyFrom(*frame))
2678 return false;
2679 new_frame->set_reference_block_timestamp(
2680 last_track_timestamp_[frame->track_number() - 1]);
2681 frame = new_frame;
2682 frame_created = true;
2683 }
2684
2685 if (!cluster->AddFrame(frame))
2686 return false;
2687
2688 if (new_cuepoint_ && cues_track_ == frame->track_number()) {
2689 if (!AddCuePoint(frame->timestamp(), cues_track_))
2690 return false;
2691 }
2692
2693 last_timestamp_ = frame->timestamp();
2694 last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
2695 last_block_duration_ = frame->duration();
2696
2697 if (frame_created)
2698 delete frame;
2699
2700 return true;
2701 }
2702
OutputCues(bool output_cues)2703 void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; }
2704
SetChunking(bool chunking,const char * filename)2705 bool Segment::SetChunking(bool chunking, const char* filename) {
2706 if (chunk_count_ > 0)
2707 return false;
2708
2709 if (chunking) {
2710 if (!filename)
2711 return false;
2712
2713 // Check if we are being set to what is already set.
2714 if (chunking_ && !strcmp(filename, chunking_base_name_))
2715 return true;
2716
2717 const size_t name_length = strlen(filename) + 1;
2718 char* const temp = new (std::nothrow) char[name_length]; // NOLINT
2719 if (!temp)
2720 return false;
2721
2722 #ifdef _MSC_VER
2723 strcpy_s(temp, name_length, filename);
2724 #else
2725 strcpy(temp, filename);
2726 #endif
2727
2728 delete[] chunking_base_name_;
2729 chunking_base_name_ = temp;
2730
2731 if (!UpdateChunkName("chk", &chunk_name_))
2732 return false;
2733
2734 if (!chunk_writer_cluster_) {
2735 chunk_writer_cluster_ = new (std::nothrow) MkvWriter(); // NOLINT
2736 if (!chunk_writer_cluster_)
2737 return false;
2738 }
2739
2740 if (!chunk_writer_cues_) {
2741 chunk_writer_cues_ = new (std::nothrow) MkvWriter(); // NOLINT
2742 if (!chunk_writer_cues_)
2743 return false;
2744 }
2745
2746 if (!chunk_writer_header_) {
2747 chunk_writer_header_ = new (std::nothrow) MkvWriter(); // NOLINT
2748 if (!chunk_writer_header_)
2749 return false;
2750 }
2751
2752 if (!chunk_writer_cluster_->Open(chunk_name_))
2753 return false;
2754
2755 const size_t header_length = strlen(filename) + strlen(".hdr") + 1;
2756 char* const header = new (std::nothrow) char[header_length]; // NOLINT
2757 if (!header)
2758 return false;
2759
2760 #ifdef _MSC_VER
2761 strcpy_s(header, header_length - strlen(".hdr"), chunking_base_name_);
2762 strcat_s(header, header_length, ".hdr");
2763 #else
2764 strcpy(header, chunking_base_name_);
2765 strcat(header, ".hdr");
2766 #endif
2767 if (!chunk_writer_header_->Open(header)) {
2768 delete[] header;
2769 return false;
2770 }
2771
2772 writer_cluster_ = chunk_writer_cluster_;
2773 writer_cues_ = chunk_writer_cues_;
2774 writer_header_ = chunk_writer_header_;
2775
2776 delete[] header;
2777 }
2778
2779 chunking_ = chunking;
2780
2781 return true;
2782 }
2783
CuesTrack(uint64 track_number)2784 bool Segment::CuesTrack(uint64 track_number) {
2785 const Track* const track = GetTrackByNumber(track_number);
2786 if (!track)
2787 return false;
2788
2789 cues_track_ = track_number;
2790 return true;
2791 }
2792
ForceNewClusterOnNextFrame()2793 void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; }
2794
GetTrackByNumber(uint64 track_number) const2795 Track* Segment::GetTrackByNumber(uint64 track_number) const {
2796 return tracks_.GetTrackByNumber(track_number);
2797 }
2798
WriteSegmentHeader()2799 bool Segment::WriteSegmentHeader() {
2800 UpdateDocTypeVersion();
2801
2802 // TODO(fgalligan): Support more than one segment.
2803 if (!WriteEbmlHeader(writer_header_, doc_type_version_))
2804 return false;
2805 doc_type_version_written_ = doc_type_version_;
2806 ebml_header_size_ = static_cast<int32>(writer_header_->Position());
2807
2808 // Write "unknown" (-1) as segment size value. If mode is kFile, Segment
2809 // will write over duration when the file is finalized.
2810 if (WriteID(writer_header_, kMkvSegment))
2811 return false;
2812
2813 // Save for later.
2814 size_position_ = writer_header_->Position();
2815
2816 // Write "unknown" (EBML coded -1) as segment size value. We need to write 8
2817 // bytes because if we are going to overwrite the segment size later we do
2818 // not know how big our segment will be.
2819 if (SerializeInt(writer_header_, kEbmlUnknownValue, 8))
2820 return false;
2821
2822 payload_pos_ = writer_header_->Position();
2823
2824 if (mode_ == kFile && writer_header_->Seekable()) {
2825 // Set the duration > 0.0 so SegmentInfo will write out the duration. When
2826 // the muxer is done writing we will set the correct duration and have
2827 // SegmentInfo upadte it.
2828 segment_info_.set_duration(1.0);
2829
2830 if (!seek_head_.Write(writer_header_))
2831 return false;
2832 }
2833
2834 if (!seek_head_.AddSeekEntry(kMkvInfo, MaxOffset()))
2835 return false;
2836 if (!segment_info_.Write(writer_header_))
2837 return false;
2838
2839 if (!seek_head_.AddSeekEntry(kMkvTracks, MaxOffset()))
2840 return false;
2841 if (!tracks_.Write(writer_header_))
2842 return false;
2843
2844 if (chapters_.Count() > 0) {
2845 if (!seek_head_.AddSeekEntry(kMkvChapters, MaxOffset()))
2846 return false;
2847 if (!chapters_.Write(writer_header_))
2848 return false;
2849 }
2850
2851 if (tags_.Count() > 0) {
2852 if (!seek_head_.AddSeekEntry(kMkvTags, MaxOffset()))
2853 return false;
2854 if (!tags_.Write(writer_header_))
2855 return false;
2856 }
2857
2858 if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) {
2859 if (!chunk_writer_header_)
2860 return false;
2861
2862 chunk_writer_header_->Close();
2863 }
2864
2865 header_written_ = true;
2866
2867 return true;
2868 }
2869
2870 // Here we are testing whether to create a new cluster, given a frame
2871 // having time frame_timestamp_ns.
2872 //
TestFrame(uint64 track_number,uint64 frame_timestamp_ns,bool is_key) const2873 int Segment::TestFrame(uint64 track_number, uint64 frame_timestamp_ns,
2874 bool is_key) const {
2875 if (force_new_cluster_)
2876 return 1;
2877
2878 // If no clusters have been created yet, then create a new cluster
2879 // and write this frame immediately, in the new cluster. This path
2880 // should only be followed once, the first time we attempt to write
2881 // a frame.
2882
2883 if (cluster_list_size_ <= 0)
2884 return 1;
2885
2886 // There exists at least one cluster. We must compare the frame to
2887 // the last cluster, in order to determine whether the frame is
2888 // written to the existing cluster, or that a new cluster should be
2889 // created.
2890
2891 const uint64 timecode_scale = segment_info_.timecode_scale();
2892 const uint64 frame_timecode = frame_timestamp_ns / timecode_scale;
2893
2894 const Cluster* const last_cluster = cluster_list_[cluster_list_size_ - 1];
2895 const uint64 last_cluster_timecode = last_cluster->timecode();
2896
2897 // For completeness we test for the case when the frame's timecode
2898 // is less than the cluster's timecode. Although in principle that
2899 // is allowed, this muxer doesn't actually write clusters like that,
2900 // so this indicates a bug somewhere in our algorithm.
2901
2902 if (frame_timecode < last_cluster_timecode) // should never happen
2903 return -1;
2904
2905 // If the frame has a timestamp significantly larger than the last
2906 // cluster (in Matroska, cluster-relative timestamps are serialized
2907 // using a 16-bit signed integer), then we cannot write this frame
2908 // to that cluster, and so we must create a new cluster.
2909
2910 const int64 delta_timecode = frame_timecode - last_cluster_timecode;
2911
2912 if (delta_timecode > kMaxBlockTimecode)
2913 return 2;
2914
2915 // We decide to create a new cluster when we have a video keyframe.
2916 // This will flush queued (audio) frames, and write the keyframe
2917 // immediately, in the newly-created cluster.
2918
2919 if (is_key && tracks_.TrackIsVideo(track_number))
2920 return 1;
2921
2922 // Create a new cluster if we have accumulated too many frames
2923 // already, where "too many" is defined as "the total time of frames
2924 // in the cluster exceeds a threshold".
2925
2926 const uint64 delta_ns = delta_timecode * timecode_scale;
2927
2928 if (max_cluster_duration_ > 0 && delta_ns >= max_cluster_duration_)
2929 return 1;
2930
2931 // This is similar to the case above, with the difference that a new
2932 // cluster is created when the size of the current cluster exceeds a
2933 // threshold.
2934
2935 const uint64 cluster_size = last_cluster->payload_size();
2936
2937 if (max_cluster_size_ > 0 && cluster_size >= max_cluster_size_)
2938 return 1;
2939
2940 // There's no need to create a new cluster, so emit this frame now.
2941
2942 return 0;
2943 }
2944
MakeNewCluster(uint64 frame_timestamp_ns)2945 bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) {
2946 const int32 new_size = cluster_list_size_ + 1;
2947
2948 if (new_size > cluster_list_capacity_) {
2949 // Add more clusters.
2950 const int32 new_capacity =
2951 (cluster_list_capacity_ <= 0) ? 1 : cluster_list_capacity_ * 2;
2952 Cluster** const clusters =
2953 new (std::nothrow) Cluster*[new_capacity]; // NOLINT
2954 if (!clusters)
2955 return false;
2956
2957 for (int32 i = 0; i < cluster_list_size_; ++i) {
2958 clusters[i] = cluster_list_[i];
2959 }
2960
2961 delete[] cluster_list_;
2962
2963 cluster_list_ = clusters;
2964 cluster_list_capacity_ = new_capacity;
2965 }
2966
2967 if (!WriteFramesLessThan(frame_timestamp_ns))
2968 return false;
2969
2970 if (mode_ == kFile) {
2971 if (cluster_list_size_ > 0) {
2972 // Update old cluster's size
2973 Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
2974
2975 if (!old_cluster || !old_cluster->Finalize())
2976 return false;
2977 }
2978
2979 if (output_cues_)
2980 new_cuepoint_ = true;
2981 }
2982
2983 if (chunking_ && cluster_list_size_ > 0) {
2984 chunk_writer_cluster_->Close();
2985 chunk_count_++;
2986
2987 if (!UpdateChunkName("chk", &chunk_name_))
2988 return false;
2989 if (!chunk_writer_cluster_->Open(chunk_name_))
2990 return false;
2991 }
2992
2993 const uint64 timecode_scale = segment_info_.timecode_scale();
2994 const uint64 frame_timecode = frame_timestamp_ns / timecode_scale;
2995
2996 uint64 cluster_timecode = frame_timecode;
2997
2998 if (frames_size_ > 0) {
2999 const Frame* const f = frames_[0]; // earliest queued frame
3000 const uint64 ns = f->timestamp();
3001 const uint64 tc = ns / timecode_scale;
3002
3003 if (tc < cluster_timecode)
3004 cluster_timecode = tc;
3005 }
3006
3007 Cluster*& cluster = cluster_list_[cluster_list_size_];
3008 const int64 offset = MaxOffset();
3009 cluster = new (std::nothrow) Cluster(cluster_timecode, // NOLINT
3010 offset, segment_info_.timecode_scale());
3011 if (!cluster)
3012 return false;
3013
3014 if (!cluster->Init(writer_cluster_))
3015 return false;
3016
3017 cluster_list_size_ = new_size;
3018 return true;
3019 }
3020
DoNewClusterProcessing(uint64 track_number,uint64 frame_timestamp_ns,bool is_key)3021 bool Segment::DoNewClusterProcessing(uint64 track_number,
3022 uint64 frame_timestamp_ns, bool is_key) {
3023 for (;;) {
3024 // Based on the characteristics of the current frame and current
3025 // cluster, decide whether to create a new cluster.
3026 const int result = TestFrame(track_number, frame_timestamp_ns, is_key);
3027 if (result < 0) // error
3028 return false;
3029
3030 // Always set force_new_cluster_ to false after TestFrame.
3031 force_new_cluster_ = false;
3032
3033 // A non-zero result means create a new cluster.
3034 if (result > 0 && !MakeNewCluster(frame_timestamp_ns))
3035 return false;
3036
3037 // Write queued (audio) frames.
3038 const int frame_count = WriteFramesAll();
3039 if (frame_count < 0) // error
3040 return false;
3041
3042 // Write the current frame to the current cluster (if TestFrame
3043 // returns 0) or to a newly created cluster (TestFrame returns 1).
3044 if (result <= 1)
3045 return true;
3046
3047 // TestFrame returned 2, which means there was a large time
3048 // difference between the cluster and the frame itself. Do the
3049 // test again, comparing the frame to the new cluster.
3050 }
3051 }
3052
CheckHeaderInfo()3053 bool Segment::CheckHeaderInfo() {
3054 if (!header_written_) {
3055 if (!WriteSegmentHeader())
3056 return false;
3057
3058 if (!seek_head_.AddSeekEntry(kMkvCluster, MaxOffset()))
3059 return false;
3060
3061 if (output_cues_ && cues_track_ == 0) {
3062 // Check for a video track
3063 for (uint32 i = 0; i < tracks_.track_entries_size(); ++i) {
3064 const Track* const track = tracks_.GetTrackByIndex(i);
3065 if (!track)
3066 return false;
3067
3068 if (tracks_.TrackIsVideo(track->number())) {
3069 cues_track_ = track->number();
3070 break;
3071 }
3072 }
3073
3074 // Set first track found
3075 if (cues_track_ == 0) {
3076 const Track* const track = tracks_.GetTrackByIndex(0);
3077 if (!track)
3078 return false;
3079
3080 cues_track_ = track->number();
3081 }
3082 }
3083 }
3084 return true;
3085 }
3086
UpdateDocTypeVersion()3087 void Segment::UpdateDocTypeVersion() {
3088 for (uint32 index = 0; index < tracks_.track_entries_size(); ++index) {
3089 const Track* track = tracks_.GetTrackByIndex(index);
3090 if (track == NULL)
3091 break;
3092 if ((track->codec_delay() || track->seek_pre_roll()) &&
3093 doc_type_version_ < 4) {
3094 doc_type_version_ = 4;
3095 break;
3096 }
3097 }
3098 }
3099
UpdateChunkName(const char * ext,char ** name) const3100 bool Segment::UpdateChunkName(const char* ext, char** name) const {
3101 if (!name || !ext)
3102 return false;
3103
3104 char ext_chk[64];
3105 #ifdef _MSC_VER
3106 sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
3107 #else
3108 snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
3109 #endif
3110
3111 const size_t length = strlen(chunking_base_name_) + strlen(ext_chk) + 1;
3112 char* const str = new (std::nothrow) char[length]; // NOLINT
3113 if (!str)
3114 return false;
3115
3116 #ifdef _MSC_VER
3117 strcpy_s(str, length - strlen(ext_chk), chunking_base_name_);
3118 strcat_s(str, length, ext_chk);
3119 #else
3120 strcpy(str, chunking_base_name_);
3121 strcat(str, ext_chk);
3122 #endif
3123
3124 delete[] * name;
3125 *name = str;
3126
3127 return true;
3128 }
3129
MaxOffset()3130 int64 Segment::MaxOffset() {
3131 if (!writer_header_)
3132 return -1;
3133
3134 int64 offset = writer_header_->Position() - payload_pos_;
3135
3136 if (chunking_) {
3137 for (int32 i = 0; i < cluster_list_size_; ++i) {
3138 Cluster* const cluster = cluster_list_[i];
3139 offset += cluster->Size();
3140 }
3141
3142 if (writer_cues_)
3143 offset += writer_cues_->Position();
3144 }
3145
3146 return offset;
3147 }
3148
QueueFrame(Frame * frame)3149 bool Segment::QueueFrame(Frame* frame) {
3150 const int32 new_size = frames_size_ + 1;
3151
3152 if (new_size > frames_capacity_) {
3153 // Add more frames.
3154 const int32 new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2;
3155
3156 if (new_capacity < 1)
3157 return false;
3158
3159 Frame** const frames = new (std::nothrow) Frame*[new_capacity]; // NOLINT
3160 if (!frames)
3161 return false;
3162
3163 for (int32 i = 0; i < frames_size_; ++i) {
3164 frames[i] = frames_[i];
3165 }
3166
3167 delete[] frames_;
3168 frames_ = frames;
3169 frames_capacity_ = new_capacity;
3170 }
3171
3172 frames_[frames_size_++] = frame;
3173
3174 return true;
3175 }
3176
WriteFramesAll()3177 int Segment::WriteFramesAll() {
3178 if (frames_ == NULL)
3179 return 0;
3180
3181 if (cluster_list_size_ < 1)
3182 return -1;
3183
3184 Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
3185
3186 if (!cluster)
3187 return -1;
3188
3189 for (int32 i = 0; i < frames_size_; ++i) {
3190 Frame*& frame = frames_[i];
3191 // TODO(jzern/vigneshv): using Segment::AddGenericFrame here would limit the
3192 // places where |doc_type_version_| needs to be updated.
3193 if (frame->discard_padding() != 0)
3194 doc_type_version_ = 4;
3195 if (!cluster->AddFrame(frame))
3196 return -1;
3197
3198 if (new_cuepoint_ && cues_track_ == frame->track_number()) {
3199 if (!AddCuePoint(frame->timestamp(), cues_track_))
3200 return -1;
3201 }
3202
3203 if (frame->timestamp() > last_timestamp_) {
3204 last_timestamp_ = frame->timestamp();
3205 last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
3206 }
3207
3208 delete frame;
3209 frame = NULL;
3210 }
3211
3212 const int result = frames_size_;
3213 frames_size_ = 0;
3214
3215 return result;
3216 }
3217
WriteFramesLessThan(uint64 timestamp)3218 bool Segment::WriteFramesLessThan(uint64 timestamp) {
3219 // Check |cluster_list_size_| to see if this is the first cluster. If it is
3220 // the first cluster the audio frames that are less than the first video
3221 // timesatmp will be written in a later step.
3222 if (frames_size_ > 0 && cluster_list_size_ > 0) {
3223 if (!frames_)
3224 return false;
3225
3226 Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
3227 if (!cluster)
3228 return false;
3229
3230 int32 shift_left = 0;
3231
3232 // TODO(fgalligan): Change this to use the durations of frames instead of
3233 // the next frame's start time if the duration is accurate.
3234 for (int32 i = 1; i < frames_size_; ++i) {
3235 const Frame* const frame_curr = frames_[i];
3236
3237 if (frame_curr->timestamp() > timestamp)
3238 break;
3239
3240 const Frame* const frame_prev = frames_[i - 1];
3241 if (frame_prev->discard_padding() != 0)
3242 doc_type_version_ = 4;
3243 if (!cluster->AddFrame(frame_prev))
3244 return false;
3245
3246 if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
3247 if (!AddCuePoint(frame_prev->timestamp(), cues_track_))
3248 return false;
3249 }
3250
3251 ++shift_left;
3252 if (frame_prev->timestamp() > last_timestamp_) {
3253 last_timestamp_ = frame_prev->timestamp();
3254 last_track_timestamp_[frame_prev->track_number() - 1] =
3255 frame_prev->timestamp();
3256 }
3257
3258 delete frame_prev;
3259 }
3260
3261 if (shift_left > 0) {
3262 if (shift_left >= frames_size_)
3263 return false;
3264
3265 const int32 new_frames_size = frames_size_ - shift_left;
3266 for (int32 i = 0; i < new_frames_size; ++i) {
3267 frames_[i] = frames_[i + shift_left];
3268 }
3269
3270 frames_size_ = new_frames_size;
3271 }
3272 }
3273
3274 return true;
3275 }
3276
3277 } // namespace mkvmuxer
3278