]> granicus.if.org Git - libvpx/blob - third_party/libwebm/mkvmuxer.cpp
Merge "third_party/libwebm: pull from upstream"
[libvpx] / third_party / libwebm / mkvmuxer.cpp
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.
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
64 IMkvWriter::IMkvWriter() {}
65
66 IMkvWriter::~IMkvWriter() {}
67
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
98 bool WriteEbmlHeader(IMkvWriter* writer) {
99   return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion);
100 }
101
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
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
138 Frame::~Frame() {
139   delete[] frame_;
140   delete[] additional_;
141 }
142
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
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
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
198 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
215 bool Frame::CanBeSimpleBlock() const {
216   return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
217 }
218
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
228 CuePoint::CuePoint()
229     : time_(0),
230       track_(0),
231       cluster_pos_(0),
232       block_number_(1),
233       output_block_number_(true) {}
234
235 CuePoint::~CuePoint() {}
236
237 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
280 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
293 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
302 Cues::Cues()
303     : cue_entries_capacity_(0),
304       cue_entries_size_(0),
305       cue_entries_(NULL),
306       output_block_number_(true) {}
307
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
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
350 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
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
368 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
410 ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}
411
412 uint64 ContentEncAESSettings::Size() const {
413   const uint64 payload = PayloadSize();
414   const uint64 size =
415       EbmlMasterElementSize(kMkvContentEncAESSettings, payload) + payload;
416   return size;
417 }
418
419 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
440 uint64 ContentEncAESSettings::PayloadSize() const {
441   uint64 size = EbmlElementSize(kMkvAESSettingsCipherMode, cipher_mode_);
442   return size;
443 }
444
445 ///////////////////////////////////////////////////////////////
446 //
447 // ContentEncoding Class
448
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
457 ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
458
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
476 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
485 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
523 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
543 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
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
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
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
615 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
625 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
662 uint64 Track::Size() const {
663   uint64 size = PayloadSize();
664   size += EbmlMasterElementSize(kMkvTrackEntry, size);
665   return size;
666 }
667
668 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
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
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.
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
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
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
863 VideoTrack::~VideoTrack() {}
864
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
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
884 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
893 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
958 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
987 AudioTrack::AudioTrack(unsigned int* seed)
988     : Track(seed), bit_depth_(0), channels_(1), sample_rate_(0.0) {}
989
990 AudioTrack::~AudioTrack() {}
991
992 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
1005 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
1049 Tracks::Tracks() : track_entries_(NULL), track_entries_size_(0) {}
1050
1051 Tracks::~Tracks() {
1052   if (track_entries_) {
1053     for (uint32 i = 0; i < track_entries_size_; ++i) {
1054       Track* const track = track_entries_[i];
1055       delete track;
1056     }
1057     delete[] track_entries_;
1058   }
1059 }
1060
1061 bool Tracks::AddTrack(Track* track, int32 number) {
1062   if (number < 0)
1063     return false;
1064
1065   // This muxer only supports track numbers in the range [1, 126], in
1066   // order to be able (to use Matroska integer representation) to
1067   // serialize the block header (of which the track number is a part)
1068   // for a frame using exactly 4 bytes.
1069
1070   if (number > 0x7E)
1071     return false;
1072
1073   uint32 track_num = number;
1074
1075   if (track_num > 0) {
1076     // Check to make sure a track does not already have |track_num|.
1077     for (uint32 i = 0; i < track_entries_size_; ++i) {
1078       if (track_entries_[i]->number() == track_num)
1079         return false;
1080     }
1081   }
1082
1083   const uint32 count = track_entries_size_ + 1;
1084
1085   Track** const track_entries = new (std::nothrow) Track*[count];  // NOLINT
1086   if (!track_entries)
1087     return false;
1088
1089   for (uint32 i = 0; i < track_entries_size_; ++i) {
1090     track_entries[i] = track_entries_[i];
1091   }
1092
1093   delete[] track_entries_;
1094
1095   // Find the lowest availible track number > 0.
1096   if (track_num == 0) {
1097     track_num = count;
1098
1099     // Check to make sure a track does not already have |track_num|.
1100     bool exit = false;
1101     do {
1102       exit = true;
1103       for (uint32 i = 0; i < track_entries_size_; ++i) {
1104         if (track_entries[i]->number() == track_num) {
1105           track_num++;
1106           exit = false;
1107           break;
1108         }
1109       }
1110     } while (!exit);
1111   }
1112   track->set_number(track_num);
1113
1114   track_entries_ = track_entries;
1115   track_entries_[track_entries_size_] = track;
1116   track_entries_size_ = count;
1117   return true;
1118 }
1119
1120 const Track* Tracks::GetTrackByIndex(uint32 index) const {
1121   if (track_entries_ == NULL)
1122     return NULL;
1123
1124   if (index >= track_entries_size_)
1125     return NULL;
1126
1127   return track_entries_[index];
1128 }
1129
1130 Track* Tracks::GetTrackByNumber(uint64 track_number) const {
1131   const int32 count = track_entries_size();
1132   for (int32 i = 0; i < count; ++i) {
1133     if (track_entries_[i]->number() == track_number)
1134       return track_entries_[i];
1135   }
1136
1137   return NULL;
1138 }
1139
1140 bool Tracks::TrackIsAudio(uint64 track_number) const {
1141   const Track* const track = GetTrackByNumber(track_number);
1142
1143   if (track->type() == kAudio)
1144     return true;
1145
1146   return false;
1147 }
1148
1149 bool Tracks::TrackIsVideo(uint64 track_number) const {
1150   const Track* const track = GetTrackByNumber(track_number);
1151
1152   if (track->type() == kVideo)
1153     return true;
1154
1155   return false;
1156 }
1157
1158 bool Tracks::Write(IMkvWriter* writer) const {
1159   uint64 size = 0;
1160   const int32 count = track_entries_size();
1161   for (int32 i = 0; i < count; ++i) {
1162     const Track* const track = GetTrackByIndex(i);
1163
1164     if (!track)
1165       return false;
1166
1167     size += track->Size();
1168   }
1169
1170   if (!WriteEbmlMasterElement(writer, kMkvTracks, size))
1171     return false;
1172
1173   const int64 payload_position = writer->Position();
1174   if (payload_position < 0)
1175     return false;
1176
1177   for (int32 i = 0; i < count; ++i) {
1178     const Track* const track = GetTrackByIndex(i);
1179     if (!track->Write(writer))
1180       return false;
1181   }
1182
1183   const int64 stop_position = writer->Position();
1184   if (stop_position < 0 ||
1185       stop_position - payload_position != static_cast<int64>(size))
1186     return false;
1187
1188   return true;
1189 }
1190
1191 ///////////////////////////////////////////////////////////////
1192 //
1193 // Chapter Class
1194
1195 bool Chapter::set_id(const char* id) { return StrCpy(id, &id_); }
1196
1197 void Chapter::set_time(const Segment& segment, uint64 start_ns, uint64 end_ns) {
1198   const SegmentInfo* const info = segment.GetSegmentInfo();
1199   const uint64 timecode_scale = info->timecode_scale();
1200   start_timecode_ = start_ns / timecode_scale;
1201   end_timecode_ = end_ns / timecode_scale;
1202 }
1203
1204 bool Chapter::add_string(const char* title, const char* language,
1205                          const char* country) {
1206   if (!ExpandDisplaysArray())
1207     return false;
1208
1209   Display& d = displays_[displays_count_++];
1210   d.Init();
1211
1212   if (!d.set_title(title))
1213     return false;
1214
1215   if (!d.set_language(language))
1216     return false;
1217
1218   if (!d.set_country(country))
1219     return false;
1220
1221   return true;
1222 }
1223
1224 Chapter::Chapter() {
1225   // This ctor only constructs the object.  Proper initialization is
1226   // done in Init() (called in Chapters::AddChapter()).  The only
1227   // reason we bother implementing this ctor is because we had to
1228   // declare it as private (along with the dtor), in order to prevent
1229   // clients from creating Chapter instances (a privelege we grant
1230   // only to the Chapters class).  Doing no initialization here also
1231   // means that creating arrays of chapter objects is more efficient,
1232   // because we only initialize each new chapter object as it becomes
1233   // active on the array.
1234 }
1235
1236 Chapter::~Chapter() {}
1237
1238 void Chapter::Init(unsigned int* seed) {
1239   id_ = NULL;
1240   start_timecode_ = 0;
1241   end_timecode_ = 0;
1242   displays_ = NULL;
1243   displays_size_ = 0;
1244   displays_count_ = 0;
1245   uid_ = MakeUID(seed);
1246 }
1247
1248 void Chapter::ShallowCopy(Chapter* dst) const {
1249   dst->id_ = id_;
1250   dst->start_timecode_ = start_timecode_;
1251   dst->end_timecode_ = end_timecode_;
1252   dst->uid_ = uid_;
1253   dst->displays_ = displays_;
1254   dst->displays_size_ = displays_size_;
1255   dst->displays_count_ = displays_count_;
1256 }
1257
1258 void Chapter::Clear() {
1259   StrCpy(NULL, &id_);
1260
1261   while (displays_count_ > 0) {
1262     Display& d = displays_[--displays_count_];
1263     d.Clear();
1264   }
1265
1266   delete[] displays_;
1267   displays_ = NULL;
1268
1269   displays_size_ = 0;
1270 }
1271
1272 bool Chapter::ExpandDisplaysArray() {
1273   if (displays_size_ > displays_count_)
1274     return true;  // nothing to do yet
1275
1276   const int size = (displays_size_ == 0) ? 1 : 2 * displays_size_;
1277
1278   Display* const displays = new (std::nothrow) Display[size];  // NOLINT
1279   if (displays == NULL)
1280     return false;
1281
1282   for (int idx = 0; idx < displays_count_; ++idx) {
1283     displays[idx] = displays_[idx];  // shallow copy
1284   }
1285
1286   delete[] displays_;
1287
1288   displays_ = displays;
1289   displays_size_ = size;
1290
1291   return true;
1292 }
1293
1294 uint64 Chapter::WriteAtom(IMkvWriter* writer) const {
1295   uint64 payload_size = EbmlElementSize(kMkvChapterStringUID, id_) +
1296                         EbmlElementSize(kMkvChapterUID, uid_) +
1297                         EbmlElementSize(kMkvChapterTimeStart, start_timecode_) +
1298                         EbmlElementSize(kMkvChapterTimeEnd, end_timecode_);
1299
1300   for (int idx = 0; idx < displays_count_; ++idx) {
1301     const Display& d = displays_[idx];
1302     payload_size += d.WriteDisplay(NULL);
1303   }
1304
1305   const uint64 atom_size =
1306       EbmlMasterElementSize(kMkvChapterAtom, payload_size) + payload_size;
1307
1308   if (writer == NULL)
1309     return atom_size;
1310
1311   const int64 start = writer->Position();
1312
1313   if (!WriteEbmlMasterElement(writer, kMkvChapterAtom, payload_size))
1314     return 0;
1315
1316   if (!WriteEbmlElement(writer, kMkvChapterStringUID, id_))
1317     return 0;
1318
1319   if (!WriteEbmlElement(writer, kMkvChapterUID, uid_))
1320     return 0;
1321
1322   if (!WriteEbmlElement(writer, kMkvChapterTimeStart, start_timecode_))
1323     return 0;
1324
1325   if (!WriteEbmlElement(writer, kMkvChapterTimeEnd, end_timecode_))
1326     return 0;
1327
1328   for (int idx = 0; idx < displays_count_; ++idx) {
1329     const Display& d = displays_[idx];
1330
1331     if (!d.WriteDisplay(writer))
1332       return 0;
1333   }
1334
1335   const int64 stop = writer->Position();
1336
1337   if (stop >= start && uint64(stop - start) != atom_size)
1338     return 0;
1339
1340   return atom_size;
1341 }
1342
1343 void Chapter::Display::Init() {
1344   title_ = NULL;
1345   language_ = NULL;
1346   country_ = NULL;
1347 }
1348
1349 void Chapter::Display::Clear() {
1350   StrCpy(NULL, &title_);
1351   StrCpy(NULL, &language_);
1352   StrCpy(NULL, &country_);
1353 }
1354
1355 bool Chapter::Display::set_title(const char* title) {
1356   return StrCpy(title, &title_);
1357 }
1358
1359 bool Chapter::Display::set_language(const char* language) {
1360   return StrCpy(language, &language_);
1361 }
1362
1363 bool Chapter::Display::set_country(const char* country) {
1364   return StrCpy(country, &country_);
1365 }
1366
1367 uint64 Chapter::Display::WriteDisplay(IMkvWriter* writer) const {
1368   uint64 payload_size = EbmlElementSize(kMkvChapString, title_);
1369
1370   if (language_)
1371     payload_size += EbmlElementSize(kMkvChapLanguage, language_);
1372
1373   if (country_)
1374     payload_size += EbmlElementSize(kMkvChapCountry, country_);
1375
1376   const uint64 display_size =
1377       EbmlMasterElementSize(kMkvChapterDisplay, payload_size) + payload_size;
1378
1379   if (writer == NULL)
1380     return display_size;
1381
1382   const int64 start = writer->Position();
1383
1384   if (!WriteEbmlMasterElement(writer, kMkvChapterDisplay, payload_size))
1385     return 0;
1386
1387   if (!WriteEbmlElement(writer, kMkvChapString, title_))
1388     return 0;
1389
1390   if (language_) {
1391     if (!WriteEbmlElement(writer, kMkvChapLanguage, language_))
1392       return 0;
1393   }
1394
1395   if (country_) {
1396     if (!WriteEbmlElement(writer, kMkvChapCountry, country_))
1397       return 0;
1398   }
1399
1400   const int64 stop = writer->Position();
1401
1402   if (stop >= start && uint64(stop - start) != display_size)
1403     return 0;
1404
1405   return display_size;
1406 }
1407
1408 ///////////////////////////////////////////////////////////////
1409 //
1410 // Chapters Class
1411
1412 Chapters::Chapters() : chapters_size_(0), chapters_count_(0), chapters_(NULL) {}
1413
1414 Chapters::~Chapters() {
1415   while (chapters_count_ > 0) {
1416     Chapter& chapter = chapters_[--chapters_count_];
1417     chapter.Clear();
1418   }
1419
1420   delete[] chapters_;
1421   chapters_ = NULL;
1422 }
1423
1424 int Chapters::Count() const { return chapters_count_; }
1425
1426 Chapter* Chapters::AddChapter(unsigned int* seed) {
1427   if (!ExpandChaptersArray())
1428     return NULL;
1429
1430   Chapter& chapter = chapters_[chapters_count_++];
1431   chapter.Init(seed);
1432
1433   return &chapter;
1434 }
1435
1436 bool Chapters::Write(IMkvWriter* writer) const {
1437   if (writer == NULL)
1438     return false;
1439
1440   const uint64 payload_size = WriteEdition(NULL);  // return size only
1441
1442   if (!WriteEbmlMasterElement(writer, kMkvChapters, payload_size))
1443     return false;
1444
1445   const int64 start = writer->Position();
1446
1447   if (WriteEdition(writer) == 0)  // error
1448     return false;
1449
1450   const int64 stop = writer->Position();
1451
1452   if (stop >= start && uint64(stop - start) != payload_size)
1453     return false;
1454
1455   return true;
1456 }
1457
1458 bool Chapters::ExpandChaptersArray() {
1459   if (chapters_size_ > chapters_count_)
1460     return true;  // nothing to do yet
1461
1462   const int size = (chapters_size_ == 0) ? 1 : 2 * chapters_size_;
1463
1464   Chapter* const chapters = new (std::nothrow) Chapter[size];  // NOLINT
1465   if (chapters == NULL)
1466     return false;
1467
1468   for (int idx = 0; idx < chapters_count_; ++idx) {
1469     const Chapter& src = chapters_[idx];
1470     Chapter* const dst = chapters + idx;
1471     src.ShallowCopy(dst);
1472   }
1473
1474   delete[] chapters_;
1475
1476   chapters_ = chapters;
1477   chapters_size_ = size;
1478
1479   return true;
1480 }
1481
1482 uint64 Chapters::WriteEdition(IMkvWriter* writer) const {
1483   uint64 payload_size = 0;
1484
1485   for (int idx = 0; idx < chapters_count_; ++idx) {
1486     const Chapter& chapter = chapters_[idx];
1487     payload_size += chapter.WriteAtom(NULL);
1488   }
1489
1490   const uint64 edition_size =
1491       EbmlMasterElementSize(kMkvEditionEntry, payload_size) + payload_size;
1492
1493   if (writer == NULL)  // return size only
1494     return edition_size;
1495
1496   const int64 start = writer->Position();
1497
1498   if (!WriteEbmlMasterElement(writer, kMkvEditionEntry, payload_size))
1499     return 0;  // error
1500
1501   for (int idx = 0; idx < chapters_count_; ++idx) {
1502     const Chapter& chapter = chapters_[idx];
1503
1504     const uint64 chapter_size = chapter.WriteAtom(writer);
1505     if (chapter_size == 0)  // error
1506       return 0;
1507   }
1508
1509   const int64 stop = writer->Position();
1510
1511   if (stop >= start && uint64(stop - start) != edition_size)
1512     return 0;
1513
1514   return edition_size;
1515 }
1516
1517 // Tag Class
1518
1519 bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) {
1520   if (!ExpandSimpleTagsArray())
1521     return false;
1522
1523   SimpleTag& st = simple_tags_[simple_tags_count_++];
1524   st.Init();
1525
1526   if (!st.set_tag_name(tag_name))
1527     return false;
1528
1529   if (!st.set_tag_string(tag_string))
1530     return false;
1531
1532   return true;
1533 }
1534
1535 Tag::Tag() {
1536   simple_tags_ = NULL;
1537   simple_tags_size_ = 0;
1538   simple_tags_count_ = 0;
1539 }
1540
1541 Tag::~Tag() {}
1542
1543 void Tag::ShallowCopy(Tag* dst) const {
1544   dst->simple_tags_ = simple_tags_;
1545   dst->simple_tags_size_ = simple_tags_size_;
1546   dst->simple_tags_count_ = simple_tags_count_;
1547 }
1548
1549 void Tag::Clear() {
1550   while (simple_tags_count_ > 0) {
1551     SimpleTag& st = simple_tags_[--simple_tags_count_];
1552     st.Clear();
1553   }
1554
1555   delete[] simple_tags_;
1556   simple_tags_ = NULL;
1557
1558   simple_tags_size_ = 0;
1559 }
1560
1561 bool Tag::ExpandSimpleTagsArray() {
1562   if (simple_tags_size_ > simple_tags_count_)
1563     return true;  // nothing to do yet
1564
1565   const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_;
1566
1567   SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size];  // NOLINT
1568   if (simple_tags == NULL)
1569     return false;
1570
1571   for (int idx = 0; idx < simple_tags_count_; ++idx) {
1572     simple_tags[idx] = simple_tags_[idx];  // shallow copy
1573   }
1574
1575   delete[] simple_tags_;
1576
1577   simple_tags_ = simple_tags;
1578   simple_tags_size_ = size;
1579
1580   return true;
1581 }
1582
1583 uint64 Tag::Write(IMkvWriter* writer) const {
1584   uint64 payload_size = 0;
1585
1586   for (int idx = 0; idx < simple_tags_count_; ++idx) {
1587     const SimpleTag& st = simple_tags_[idx];
1588     payload_size += st.Write(NULL);
1589   }
1590
1591   const uint64 tag_size =
1592       EbmlMasterElementSize(kMkvTag, payload_size) + payload_size;
1593
1594   if (writer == NULL)
1595     return tag_size;
1596
1597   const int64 start = writer->Position();
1598
1599   if (!WriteEbmlMasterElement(writer, kMkvTag, payload_size))
1600     return 0;
1601
1602   for (int idx = 0; idx < simple_tags_count_; ++idx) {
1603     const SimpleTag& st = simple_tags_[idx];
1604
1605     if (!st.Write(writer))
1606       return 0;
1607   }
1608
1609   const int64 stop = writer->Position();
1610
1611   if (stop >= start && uint64(stop - start) != tag_size)
1612     return 0;
1613
1614   return tag_size;
1615 }
1616
1617 // Tag::SimpleTag
1618
1619 void Tag::SimpleTag::Init() {
1620   tag_name_ = NULL;
1621   tag_string_ = NULL;
1622 }
1623
1624 void Tag::SimpleTag::Clear() {
1625   StrCpy(NULL, &tag_name_);
1626   StrCpy(NULL, &tag_string_);
1627 }
1628
1629 bool Tag::SimpleTag::set_tag_name(const char* tag_name) {
1630   return StrCpy(tag_name, &tag_name_);
1631 }
1632
1633 bool Tag::SimpleTag::set_tag_string(const char* tag_string) {
1634   return StrCpy(tag_string, &tag_string_);
1635 }
1636
1637 uint64 Tag::SimpleTag::Write(IMkvWriter* writer) const {
1638   uint64 payload_size = EbmlElementSize(kMkvTagName, tag_name_);
1639
1640   payload_size += EbmlElementSize(kMkvTagString, tag_string_);
1641
1642   const uint64 simple_tag_size =
1643       EbmlMasterElementSize(kMkvSimpleTag, payload_size) + payload_size;
1644
1645   if (writer == NULL)
1646     return simple_tag_size;
1647
1648   const int64 start = writer->Position();
1649
1650   if (!WriteEbmlMasterElement(writer, kMkvSimpleTag, payload_size))
1651     return 0;
1652
1653   if (!WriteEbmlElement(writer, kMkvTagName, tag_name_))
1654     return 0;
1655
1656   if (!WriteEbmlElement(writer, kMkvTagString, tag_string_))
1657     return 0;
1658
1659   const int64 stop = writer->Position();
1660
1661   if (stop >= start && uint64(stop - start) != simple_tag_size)
1662     return 0;
1663
1664   return simple_tag_size;
1665 }
1666
1667 // Tags Class
1668
1669 Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {}
1670
1671 Tags::~Tags() {
1672   while (tags_count_ > 0) {
1673     Tag& tag = tags_[--tags_count_];
1674     tag.Clear();
1675   }
1676
1677   delete[] tags_;
1678   tags_ = NULL;
1679 }
1680
1681 int Tags::Count() const { return tags_count_; }
1682
1683 Tag* Tags::AddTag() {
1684   if (!ExpandTagsArray())
1685     return NULL;
1686
1687   Tag& tag = tags_[tags_count_++];
1688
1689   return &tag;
1690 }
1691
1692 bool Tags::Write(IMkvWriter* writer) const {
1693   if (writer == NULL)
1694     return false;
1695
1696   uint64 payload_size = 0;
1697
1698   for (int idx = 0; idx < tags_count_; ++idx) {
1699     const Tag& tag = tags_[idx];
1700     payload_size += tag.Write(NULL);
1701   }
1702
1703   if (!WriteEbmlMasterElement(writer, kMkvTags, payload_size))
1704     return false;
1705
1706   const int64 start = writer->Position();
1707
1708   for (int idx = 0; idx < tags_count_; ++idx) {
1709     const Tag& tag = tags_[idx];
1710
1711     const uint64 tag_size = tag.Write(writer);
1712     if (tag_size == 0)  // error
1713       return 0;
1714   }
1715
1716   const int64 stop = writer->Position();
1717
1718   if (stop >= start && uint64(stop - start) != payload_size)
1719     return false;
1720
1721   return true;
1722 }
1723
1724 bool Tags::ExpandTagsArray() {
1725   if (tags_size_ > tags_count_)
1726     return true;  // nothing to do yet
1727
1728   const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_;
1729
1730   Tag* const tags = new (std::nothrow) Tag[size];  // NOLINT
1731   if (tags == NULL)
1732     return false;
1733
1734   for (int idx = 0; idx < tags_count_; ++idx) {
1735     const Tag& src = tags_[idx];
1736     Tag* const dst = tags + idx;
1737     src.ShallowCopy(dst);
1738   }
1739
1740   delete[] tags_;
1741
1742   tags_ = tags;
1743   tags_size_ = size;
1744
1745   return true;
1746 }
1747
1748 ///////////////////////////////////////////////////////////////
1749 //
1750 // Cluster class
1751
1752 Cluster::Cluster(uint64 timecode, int64 cues_pos, uint64 timecode_scale)
1753     : blocks_added_(0),
1754       finalized_(false),
1755       header_written_(false),
1756       payload_size_(0),
1757       position_for_cues_(cues_pos),
1758       size_position_(-1),
1759       timecode_(timecode),
1760       timecode_scale_(timecode_scale),
1761       writer_(NULL) {}
1762
1763 Cluster::~Cluster() {}
1764
1765 bool Cluster::Init(IMkvWriter* ptr_writer) {
1766   if (!ptr_writer) {
1767     return false;
1768   }
1769   writer_ = ptr_writer;
1770   return true;
1771 }
1772
1773 bool Cluster::AddFrame(const Frame* const frame) { return DoWriteFrame(frame); }
1774
1775 bool Cluster::AddFrame(const uint8* data, uint64 length, uint64 track_number,
1776                        uint64 abs_timecode, bool is_key) {
1777   Frame frame;
1778   if (!frame.Init(data, length))
1779     return false;
1780   frame.set_track_number(track_number);
1781   frame.set_timestamp(abs_timecode);
1782   frame.set_is_key(is_key);
1783   return DoWriteFrame(&frame);
1784 }
1785
1786 bool Cluster::AddFrameWithAdditional(const uint8* data, uint64 length,
1787                                      const uint8* additional,
1788                                      uint64 additional_length, uint64 add_id,
1789                                      uint64 track_number, uint64 abs_timecode,
1790                                      bool is_key) {
1791   if (!additional || additional_length == 0) {
1792     return false;
1793   }
1794   Frame frame;
1795   if (!frame.Init(data, length) ||
1796       !frame.AddAdditionalData(additional, additional_length, add_id)) {
1797     return false;
1798   }
1799   frame.set_track_number(track_number);
1800   frame.set_timestamp(abs_timecode);
1801   frame.set_is_key(is_key);
1802   return DoWriteFrame(&frame);
1803 }
1804
1805 bool Cluster::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
1806                                          int64 discard_padding,
1807                                          uint64 track_number,
1808                                          uint64 abs_timecode, bool is_key) {
1809   Frame frame;
1810   if (!frame.Init(data, length))
1811     return false;
1812   frame.set_discard_padding(discard_padding);
1813   frame.set_track_number(track_number);
1814   frame.set_timestamp(abs_timecode);
1815   frame.set_is_key(is_key);
1816   return DoWriteFrame(&frame);
1817 }
1818
1819 bool Cluster::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
1820                           uint64 abs_timecode, uint64 duration_timecode) {
1821   Frame frame;
1822   if (!frame.Init(data, length))
1823     return false;
1824   frame.set_track_number(track_number);
1825   frame.set_timestamp(abs_timecode);
1826   frame.set_duration(duration_timecode);
1827   frame.set_is_key(true);  // All metadata blocks are keyframes.
1828   return DoWriteFrame(&frame);
1829 }
1830
1831 void Cluster::AddPayloadSize(uint64 size) { payload_size_ += size; }
1832
1833 bool Cluster::Finalize() {
1834   if (!writer_ || finalized_ || size_position_ == -1)
1835     return false;
1836
1837   if (writer_->Seekable()) {
1838     const int64 pos = writer_->Position();
1839
1840     if (writer_->Position(size_position_))
1841       return false;
1842
1843     if (WriteUIntSize(writer_, payload_size(), 8))
1844       return false;
1845
1846     if (writer_->Position(pos))
1847       return false;
1848   }
1849
1850   finalized_ = true;
1851
1852   return true;
1853 }
1854
1855 uint64 Cluster::Size() const {
1856   const uint64 element_size =
1857       EbmlMasterElementSize(kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) + payload_size_;
1858   return element_size;
1859 }
1860
1861 bool Cluster::PreWriteBlock() {
1862   if (finalized_)
1863     return false;
1864
1865   if (!header_written_) {
1866     if (!WriteClusterHeader())
1867       return false;
1868   }
1869
1870   return true;
1871 }
1872
1873 void Cluster::PostWriteBlock(uint64 element_size) {
1874   AddPayloadSize(element_size);
1875   ++blocks_added_;
1876 }
1877
1878 int64 Cluster::GetRelativeTimecode(int64 abs_timecode) const {
1879   const int64 cluster_timecode = this->Cluster::timecode();
1880   const int64 rel_timecode =
1881       static_cast<int64>(abs_timecode) - cluster_timecode;
1882
1883   if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode)
1884     return -1;
1885
1886   return rel_timecode;
1887 }
1888
1889 bool Cluster::DoWriteFrame(const Frame* const frame) {
1890   if (!frame || !frame->IsValid())
1891     return false;
1892
1893   if (!PreWriteBlock())
1894     return false;
1895
1896   const uint64 element_size = WriteFrame(writer_, frame, this);
1897   if (element_size == 0)
1898     return false;
1899
1900   PostWriteBlock(element_size);
1901   return true;
1902 }
1903
1904 bool Cluster::WriteClusterHeader() {
1905   if (finalized_)
1906     return false;
1907
1908   if (WriteID(writer_, kMkvCluster))
1909     return false;
1910
1911   // Save for later.
1912   size_position_ = writer_->Position();
1913
1914   // Write "unknown" (EBML coded -1) as cluster size value. We need to write 8
1915   // bytes because we do not know how big our cluster will be.
1916   if (SerializeInt(writer_, kEbmlUnknownValue, 8))
1917     return false;
1918
1919   if (!WriteEbmlElement(writer_, kMkvTimecode, timecode()))
1920     return false;
1921   AddPayloadSize(EbmlElementSize(kMkvTimecode, timecode()));
1922   header_written_ = true;
1923
1924   return true;
1925 }
1926
1927 ///////////////////////////////////////////////////////////////
1928 //
1929 // SeekHead Class
1930
1931 SeekHead::SeekHead() : start_pos_(0ULL) {
1932   for (int32 i = 0; i < kSeekEntryCount; ++i) {
1933     seek_entry_id_[i] = 0;
1934     seek_entry_pos_[i] = 0;
1935   }
1936 }
1937
1938 SeekHead::~SeekHead() {}
1939
1940 bool SeekHead::Finalize(IMkvWriter* writer) const {
1941   if (writer->Seekable()) {
1942     if (start_pos_ == -1)
1943       return false;
1944
1945     uint64 payload_size = 0;
1946     uint64 entry_size[kSeekEntryCount];
1947
1948     for (int32 i = 0; i < kSeekEntryCount; ++i) {
1949       if (seek_entry_id_[i] != 0) {
1950         entry_size[i] =
1951             EbmlElementSize(kMkvSeekID, static_cast<uint64>(seek_entry_id_[i]));
1952         entry_size[i] += EbmlElementSize(kMkvSeekPosition, seek_entry_pos_[i]);
1953
1954         payload_size +=
1955             EbmlMasterElementSize(kMkvSeek, entry_size[i]) + entry_size[i];
1956       }
1957     }
1958
1959     // No SeekHead elements
1960     if (payload_size == 0)
1961       return true;
1962
1963     const int64 pos = writer->Position();
1964     if (writer->Position(start_pos_))
1965       return false;
1966
1967     if (!WriteEbmlMasterElement(writer, kMkvSeekHead, payload_size))
1968       return false;
1969
1970     for (int32 i = 0; i < kSeekEntryCount; ++i) {
1971       if (seek_entry_id_[i] != 0) {
1972         if (!WriteEbmlMasterElement(writer, kMkvSeek, entry_size[i]))
1973           return false;
1974
1975         if (!WriteEbmlElement(writer, kMkvSeekID,
1976                               static_cast<uint64>(seek_entry_id_[i])))
1977           return false;
1978
1979         if (!WriteEbmlElement(writer, kMkvSeekPosition, seek_entry_pos_[i]))
1980           return false;
1981       }
1982     }
1983
1984     const uint64 total_entry_size = kSeekEntryCount * MaxEntrySize();
1985     const uint64 total_size =
1986         EbmlMasterElementSize(kMkvSeekHead, total_entry_size) +
1987         total_entry_size;
1988     const int64 size_left = total_size - (writer->Position() - start_pos_);
1989
1990     const uint64 bytes_written = WriteVoidElement(writer, size_left);
1991     if (!bytes_written)
1992       return false;
1993
1994     if (writer->Position(pos))
1995       return false;
1996   }
1997
1998   return true;
1999 }
2000
2001 bool SeekHead::Write(IMkvWriter* writer) {
2002   const uint64 entry_size = kSeekEntryCount * MaxEntrySize();
2003   const uint64 size = EbmlMasterElementSize(kMkvSeekHead, entry_size);
2004
2005   start_pos_ = writer->Position();
2006
2007   const uint64 bytes_written = WriteVoidElement(writer, size + entry_size);
2008   if (!bytes_written)
2009     return false;
2010
2011   return true;
2012 }
2013
2014 bool SeekHead::AddSeekEntry(uint32 id, uint64 pos) {
2015   for (int32 i = 0; i < kSeekEntryCount; ++i) {
2016     if (seek_entry_id_[i] == 0) {
2017       seek_entry_id_[i] = id;
2018       seek_entry_pos_[i] = pos;
2019       return true;
2020     }
2021   }
2022   return false;
2023 }
2024
2025 uint32 SeekHead::GetId(int index) const {
2026   if (index < 0 || index >= kSeekEntryCount)
2027     return UINT_MAX;
2028   return seek_entry_id_[index];
2029 }
2030
2031 uint64 SeekHead::GetPosition(int index) const {
2032   if (index < 0 || index >= kSeekEntryCount)
2033     return ULLONG_MAX;
2034   return seek_entry_pos_[index];
2035 }
2036
2037 bool SeekHead::SetSeekEntry(int index, uint32 id, uint64 position) {
2038   if (index < 0 || index >= kSeekEntryCount)
2039     return false;
2040   seek_entry_id_[index] = id;
2041   seek_entry_pos_[index] = position;
2042   return true;
2043 }
2044
2045 uint64 SeekHead::MaxEntrySize() const {
2046   const uint64 max_entry_payload_size =
2047       EbmlElementSize(kMkvSeekID, 0xffffffffULL) +
2048       EbmlElementSize(kMkvSeekPosition, 0xffffffffffffffffULL);
2049   const uint64 max_entry_size =
2050       EbmlMasterElementSize(kMkvSeek, max_entry_payload_size) +
2051       max_entry_payload_size;
2052
2053   return max_entry_size;
2054 }
2055
2056 ///////////////////////////////////////////////////////////////
2057 //
2058 // SegmentInfo Class
2059
2060 SegmentInfo::SegmentInfo()
2061     : duration_(-1.0),
2062       muxing_app_(NULL),
2063       timecode_scale_(1000000ULL),
2064       writing_app_(NULL),
2065       date_utc_(LLONG_MIN),
2066       duration_pos_(-1) {}
2067
2068 SegmentInfo::~SegmentInfo() {
2069   delete[] muxing_app_;
2070   delete[] writing_app_;
2071 }
2072
2073 bool SegmentInfo::Init() {
2074   int32 major;
2075   int32 minor;
2076   int32 build;
2077   int32 revision;
2078   GetVersion(&major, &minor, &build, &revision);
2079   char temp[256];
2080 #ifdef _MSC_VER
2081   sprintf_s(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
2082             minor, build, revision);
2083 #else
2084   snprintf(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
2085            minor, build, revision);
2086 #endif
2087
2088   const size_t app_len = strlen(temp) + 1;
2089
2090   delete[] muxing_app_;
2091
2092   muxing_app_ = new (std::nothrow) char[app_len];  // NOLINT
2093   if (!muxing_app_)
2094     return false;
2095
2096 #ifdef _MSC_VER
2097   strcpy_s(muxing_app_, app_len, temp);
2098 #else
2099   strcpy(muxing_app_, temp);
2100 #endif
2101
2102   set_writing_app(temp);
2103   if (!writing_app_)
2104     return false;
2105   return true;
2106 }
2107
2108 bool SegmentInfo::Finalize(IMkvWriter* writer) const {
2109   if (!writer)
2110     return false;
2111
2112   if (duration_ > 0.0) {
2113     if (writer->Seekable()) {
2114       if (duration_pos_ == -1)
2115         return false;
2116
2117       const int64 pos = writer->Position();
2118
2119       if (writer->Position(duration_pos_))
2120         return false;
2121
2122       if (!WriteEbmlElement(writer, kMkvDuration,
2123                             static_cast<float>(duration_)))
2124         return false;
2125
2126       if (writer->Position(pos))
2127         return false;
2128     }
2129   }
2130
2131   return true;
2132 }
2133
2134 bool SegmentInfo::Write(IMkvWriter* writer) {
2135   if (!writer || !muxing_app_ || !writing_app_)
2136     return false;
2137
2138   uint64 size = EbmlElementSize(kMkvTimecodeScale, timecode_scale_);
2139   if (duration_ > 0.0)
2140     size += EbmlElementSize(kMkvDuration, static_cast<float>(duration_));
2141   if (date_utc_ != LLONG_MIN)
2142     size += EbmlDateElementSize(kMkvDateUTC);
2143   size += EbmlElementSize(kMkvMuxingApp, muxing_app_);
2144   size += EbmlElementSize(kMkvWritingApp, writing_app_);
2145
2146   if (!WriteEbmlMasterElement(writer, kMkvInfo, size))
2147     return false;
2148
2149   const int64 payload_position = writer->Position();
2150   if (payload_position < 0)
2151     return false;
2152
2153   if (!WriteEbmlElement(writer, kMkvTimecodeScale, timecode_scale_))
2154     return false;
2155
2156   if (duration_ > 0.0) {
2157     // Save for later
2158     duration_pos_ = writer->Position();
2159
2160     if (!WriteEbmlElement(writer, kMkvDuration, static_cast<float>(duration_)))
2161       return false;
2162   }
2163
2164   if (date_utc_ != LLONG_MIN)
2165     WriteEbmlDateElement(writer, kMkvDateUTC, date_utc_);
2166
2167   if (!WriteEbmlElement(writer, kMkvMuxingApp, muxing_app_))
2168     return false;
2169   if (!WriteEbmlElement(writer, kMkvWritingApp, writing_app_))
2170     return false;
2171
2172   const int64 stop_position = writer->Position();
2173   if (stop_position < 0 ||
2174       stop_position - payload_position != static_cast<int64>(size))
2175     return false;
2176
2177   return true;
2178 }
2179
2180 void SegmentInfo::set_muxing_app(const char* app) {
2181   if (app) {
2182     const size_t length = strlen(app) + 1;
2183     char* temp_str = new (std::nothrow) char[length];  // NOLINT
2184     if (!temp_str)
2185       return;
2186
2187 #ifdef _MSC_VER
2188     strcpy_s(temp_str, length, app);
2189 #else
2190     strcpy(temp_str, app);
2191 #endif
2192
2193     delete[] muxing_app_;
2194     muxing_app_ = temp_str;
2195   }
2196 }
2197
2198 void SegmentInfo::set_writing_app(const char* app) {
2199   if (app) {
2200     const size_t length = strlen(app) + 1;
2201     char* temp_str = new (std::nothrow) char[length];  // NOLINT
2202     if (!temp_str)
2203       return;
2204
2205 #ifdef _MSC_VER
2206     strcpy_s(temp_str, length, app);
2207 #else
2208     strcpy(temp_str, app);
2209 #endif
2210
2211     delete[] writing_app_;
2212     writing_app_ = temp_str;
2213   }
2214 }
2215
2216 ///////////////////////////////////////////////////////////////
2217 //
2218 // Segment Class
2219
2220 Segment::Segment()
2221     : chunk_count_(0),
2222       chunk_name_(NULL),
2223       chunk_writer_cluster_(NULL),
2224       chunk_writer_cues_(NULL),
2225       chunk_writer_header_(NULL),
2226       chunking_(false),
2227       chunking_base_name_(NULL),
2228       cluster_list_(NULL),
2229       cluster_list_capacity_(0),
2230       cluster_list_size_(0),
2231       cues_position_(kAfterClusters),
2232       cues_track_(0),
2233       force_new_cluster_(false),
2234       frames_(NULL),
2235       frames_capacity_(0),
2236       frames_size_(0),
2237       has_video_(false),
2238       header_written_(false),
2239       last_block_duration_(0),
2240       last_timestamp_(0),
2241       max_cluster_duration_(kDefaultMaxClusterDuration),
2242       max_cluster_size_(0),
2243       mode_(kFile),
2244       new_cuepoint_(false),
2245       output_cues_(true),
2246       payload_pos_(0),
2247       size_position_(0),
2248       doc_type_version_(kDefaultDocTypeVersion),
2249       doc_type_version_written_(0),
2250       writer_cluster_(NULL),
2251       writer_cues_(NULL),
2252       writer_header_(NULL) {
2253   const time_t curr_time = time(NULL);
2254   seed_ = static_cast<unsigned int>(curr_time);
2255 #ifdef _WIN32
2256   srand(seed_);
2257 #endif
2258 }
2259
2260 Segment::~Segment() {
2261   if (cluster_list_) {
2262     for (int32 i = 0; i < cluster_list_size_; ++i) {
2263       Cluster* const cluster = cluster_list_[i];
2264       delete cluster;
2265     }
2266     delete[] cluster_list_;
2267   }
2268
2269   if (frames_) {
2270     for (int32 i = 0; i < frames_size_; ++i) {
2271       Frame* const frame = frames_[i];
2272       delete frame;
2273     }
2274     delete[] frames_;
2275   }
2276
2277   delete[] chunk_name_;
2278   delete[] chunking_base_name_;
2279
2280   if (chunk_writer_cluster_) {
2281     chunk_writer_cluster_->Close();
2282     delete chunk_writer_cluster_;
2283   }
2284   if (chunk_writer_cues_) {
2285     chunk_writer_cues_->Close();
2286     delete chunk_writer_cues_;
2287   }
2288   if (chunk_writer_header_) {
2289     chunk_writer_header_->Close();
2290     delete chunk_writer_header_;
2291   }
2292 }
2293
2294 void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index,
2295                                            uint64* cues_size) {
2296   CuePoint* const cue_point = cues_.GetCueByIndex(index);
2297   if (cue_point == NULL)
2298     return;
2299   const uint64 old_cue_point_size = cue_point->Size();
2300   const uint64 cluster_pos = cue_point->cluster_pos() + diff;
2301   cue_point->set_cluster_pos(cluster_pos);  // update the new cluster position
2302   // New size of the cue is computed as follows
2303   //    Let a = current sum of size of all CuePoints
2304   //    Let b = Increase in Cue Point's size due to this iteration
2305   //    Let c = Increase in size of Cues Element's length due to this iteration
2306   //            (This is computed as CodedSize(a + b) - CodedSize(a))
2307   //    Let d = b + c. Now d is the |diff| passed to the next recursive call.
2308   //    Let e = a + b. Now e is the |cues_size| passed to the next recursive
2309   //                   call.
2310   const uint64 cue_point_size_diff = cue_point->Size() - old_cue_point_size;
2311   const uint64 cue_size_diff =
2312       GetCodedUIntSize(*cues_size + cue_point_size_diff) -
2313       GetCodedUIntSize(*cues_size);
2314   *cues_size += cue_point_size_diff;
2315   diff = cue_size_diff + cue_point_size_diff;
2316   if (diff > 0) {
2317     for (int32 i = 0; i < cues_.cue_entries_size(); ++i) {
2318       MoveCuesBeforeClustersHelper(diff, i, cues_size);
2319     }
2320   }
2321 }
2322
2323 void Segment::MoveCuesBeforeClusters() {
2324   const uint64 current_cue_size = cues_.Size();
2325   uint64 cue_size = 0;
2326   for (int32 i = 0; i < cues_.cue_entries_size(); ++i)
2327     cue_size += cues_.GetCueByIndex(i)->Size();
2328   for (int32 i = 0; i < cues_.cue_entries_size(); ++i)
2329     MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size);
2330
2331   // Adjust the Seek Entry to reflect the change in position
2332   // of Cluster and Cues
2333   int32 cluster_index = 0;
2334   int32 cues_index = 0;
2335   for (int32 i = 0; i < SeekHead::kSeekEntryCount; ++i) {
2336     if (seek_head_.GetId(i) == kMkvCluster)
2337       cluster_index = i;
2338     if (seek_head_.GetId(i) == kMkvCues)
2339       cues_index = i;
2340   }
2341   seek_head_.SetSeekEntry(cues_index, kMkvCues,
2342                           seek_head_.GetPosition(cluster_index));
2343   seek_head_.SetSeekEntry(cluster_index, kMkvCluster,
2344                           cues_.Size() + seek_head_.GetPosition(cues_index));
2345 }
2346
2347 bool Segment::Init(IMkvWriter* ptr_writer) {
2348   if (!ptr_writer) {
2349     return false;
2350   }
2351   writer_cluster_ = ptr_writer;
2352   writer_cues_ = ptr_writer;
2353   writer_header_ = ptr_writer;
2354   return segment_info_.Init();
2355 }
2356
2357 bool Segment::CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
2358                                             IMkvWriter* writer) {
2359   if (!writer->Seekable() || chunking_)
2360     return false;
2361   const int64 cluster_offset =
2362       cluster_list_[0]->size_position() - GetUIntSize(kMkvCluster);
2363
2364   // Copy the headers.
2365   if (!ChunkedCopy(reader, writer, 0, cluster_offset))
2366     return false;
2367
2368   // Recompute cue positions and seek entries.
2369   MoveCuesBeforeClusters();
2370
2371   // Write cues and seek entries.
2372   // TODO(vigneshv): As of now, it's safe to call seek_head_.Finalize() for the
2373   // second time with a different writer object. But the name Finalize() doesn't
2374   // indicate something we want to call more than once. So consider renaming it
2375   // to write() or some such.
2376   if (!cues_.Write(writer) || !seek_head_.Finalize(writer))
2377     return false;
2378
2379   // Copy the Clusters.
2380   if (!ChunkedCopy(reader, writer, cluster_offset,
2381                    cluster_end_offset_ - cluster_offset))
2382     return false;
2383
2384   // Update the Segment size in case the Cues size has changed.
2385   const int64 pos = writer->Position();
2386   const int64 segment_size = writer->Position() - payload_pos_;
2387   if (writer->Position(size_position_) ||
2388       WriteUIntSize(writer, segment_size, 8) || writer->Position(pos))
2389     return false;
2390   return true;
2391 }
2392
2393 bool Segment::Finalize() {
2394   if (WriteFramesAll() < 0)
2395     return false;
2396
2397   if (mode_ == kFile) {
2398     if (cluster_list_size_ > 0) {
2399       // Update last cluster's size
2400       Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
2401
2402       if (!old_cluster || !old_cluster->Finalize())
2403         return false;
2404     }
2405
2406     if (chunking_ && chunk_writer_cluster_) {
2407       chunk_writer_cluster_->Close();
2408       chunk_count_++;
2409     }
2410
2411     const double duration =
2412         (static_cast<double>(last_timestamp_) + last_block_duration_) /
2413         segment_info_.timecode_scale();
2414     segment_info_.set_duration(duration);
2415     if (!segment_info_.Finalize(writer_header_))
2416       return false;
2417
2418     if (output_cues_)
2419       if (!seek_head_.AddSeekEntry(kMkvCues, MaxOffset()))
2420         return false;
2421
2422     if (chunking_) {
2423       if (!chunk_writer_cues_)
2424         return false;
2425
2426       char* name = NULL;
2427       if (!UpdateChunkName("cues", &name))
2428         return false;
2429
2430       const bool cues_open = chunk_writer_cues_->Open(name);
2431       delete[] name;
2432       if (!cues_open)
2433         return false;
2434     }
2435
2436     cluster_end_offset_ = writer_cluster_->Position();
2437
2438     // Write the seek headers and cues
2439     if (output_cues_)
2440       if (!cues_.Write(writer_cues_))
2441         return false;
2442
2443     if (!seek_head_.Finalize(writer_header_))
2444       return false;
2445
2446     if (writer_header_->Seekable()) {
2447       if (size_position_ == -1)
2448         return false;
2449
2450       const int64 segment_size = MaxOffset();
2451       if (segment_size < 1)
2452         return false;
2453
2454       const int64 pos = writer_header_->Position();
2455       UpdateDocTypeVersion();
2456       if (doc_type_version_ != doc_type_version_written_) {
2457         if (writer_header_->Position(0))
2458           return false;
2459
2460         if (!WriteEbmlHeader(writer_header_, doc_type_version_))
2461           return false;
2462         if (writer_header_->Position() != ebml_header_size_)
2463           return false;
2464
2465         doc_type_version_written_ = doc_type_version_;
2466       }
2467
2468       if (writer_header_->Position(size_position_))
2469         return false;
2470
2471       if (WriteUIntSize(writer_header_, segment_size, 8))
2472         return false;
2473
2474       if (writer_header_->Position(pos))
2475         return false;
2476     }
2477
2478     if (chunking_) {
2479       // Do not close any writers until the segment size has been written,
2480       // otherwise the size may be off.
2481       if (!chunk_writer_cues_ || !chunk_writer_header_)
2482         return false;
2483
2484       chunk_writer_cues_->Close();
2485       chunk_writer_header_->Close();
2486     }
2487   }
2488
2489   return true;
2490 }
2491
2492 Track* Segment::AddTrack(int32 number) {
2493   Track* const track = new (std::nothrow) Track(&seed_);  // NOLINT
2494
2495   if (!track)
2496     return NULL;
2497
2498   if (!tracks_.AddTrack(track, number)) {
2499     delete track;
2500     return NULL;
2501   }
2502
2503   return track;
2504 }
2505
2506 Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
2507
2508 Tag* Segment::AddTag() { return tags_.AddTag(); }
2509
2510 uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) {
2511   VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_);  // NOLINT
2512   if (!track)
2513     return 0;
2514
2515   track->set_type(Tracks::kVideo);
2516   track->set_codec_id(Tracks::kVp8CodecId);
2517   track->set_width(width);
2518   track->set_height(height);
2519
2520   tracks_.AddTrack(track, number);
2521   has_video_ = true;
2522
2523   return track->number();
2524 }
2525
2526 bool Segment::AddCuePoint(uint64 timestamp, uint64 track) {
2527   if (cluster_list_size_ < 1)
2528     return false;
2529
2530   const Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
2531   if (!cluster)
2532     return false;
2533
2534   CuePoint* const cue = new (std::nothrow) CuePoint();  // NOLINT
2535   if (!cue)
2536     return false;
2537
2538   cue->set_time(timestamp / segment_info_.timecode_scale());
2539   cue->set_block_number(cluster->blocks_added());
2540   cue->set_cluster_pos(cluster->position_for_cues());
2541   cue->set_track(track);
2542   if (!cues_.AddCue(cue))
2543     return false;
2544
2545   new_cuepoint_ = false;
2546   return true;
2547 }
2548
2549 uint64 Segment::AddAudioTrack(int32 sample_rate, int32 channels, int32 number) {
2550   AudioTrack* const track = new (std::nothrow) AudioTrack(&seed_);  // NOLINT
2551   if (!track)
2552     return 0;
2553
2554   track->set_type(Tracks::kAudio);
2555   track->set_codec_id(Tracks::kVorbisCodecId);
2556   track->set_sample_rate(sample_rate);
2557   track->set_channels(channels);
2558
2559   tracks_.AddTrack(track, number);
2560
2561   return track->number();
2562 }
2563
2564 bool Segment::AddFrame(const uint8* data, uint64 length, uint64 track_number,
2565                        uint64 timestamp, bool is_key) {
2566   if (!data)
2567     return false;
2568
2569   Frame frame;
2570   if (!frame.Init(data, length))
2571     return false;
2572   frame.set_track_number(track_number);
2573   frame.set_timestamp(timestamp);
2574   frame.set_is_key(is_key);
2575   return AddGenericFrame(&frame);
2576 }
2577
2578 bool Segment::AddFrameWithAdditional(const uint8* data, uint64 length,
2579                                      const uint8* additional,
2580                                      uint64 additional_length, uint64 add_id,
2581                                      uint64 track_number, uint64 timestamp,
2582                                      bool is_key) {
2583   if (!data || !additional)
2584     return false;
2585
2586   Frame frame;
2587   if (!frame.Init(data, length) ||
2588       !frame.AddAdditionalData(additional, additional_length, add_id)) {
2589     return false;
2590   }
2591   frame.set_track_number(track_number);
2592   frame.set_timestamp(timestamp);
2593   frame.set_is_key(is_key);
2594   return AddGenericFrame(&frame);
2595 }
2596
2597 bool Segment::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
2598                                          int64 discard_padding,
2599                                          uint64 track_number, uint64 timestamp,
2600                                          bool is_key) {
2601   if (!data)
2602     return false;
2603
2604   Frame frame;
2605   if (!frame.Init(data, length))
2606     return false;
2607   frame.set_discard_padding(discard_padding);
2608   frame.set_track_number(track_number);
2609   frame.set_timestamp(timestamp);
2610   frame.set_is_key(is_key);
2611   return AddGenericFrame(&frame);
2612 }
2613
2614 bool Segment::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
2615                           uint64 timestamp_ns, uint64 duration_ns) {
2616   if (!data)
2617     return false;
2618
2619   Frame frame;
2620   if (!frame.Init(data, length))
2621     return false;
2622   frame.set_track_number(track_number);
2623   frame.set_timestamp(timestamp_ns);
2624   frame.set_duration(duration_ns);
2625   frame.set_is_key(true);  // All metadata blocks are keyframes.
2626   return AddGenericFrame(&frame);
2627 }
2628
2629 bool Segment::AddGenericFrame(const Frame* frame) {
2630   if (!frame)
2631     return false;
2632
2633   if (!CheckHeaderInfo())
2634     return false;
2635
2636   // Check for non-monotonically increasing timestamps.
2637   if (frame->timestamp() < last_timestamp_)
2638     return false;
2639
2640   // Check if the track number is valid.
2641   if (!tracks_.GetTrackByNumber(frame->track_number()))
2642     return false;
2643
2644   if (frame->discard_padding() != 0)
2645     doc_type_version_ = 4;
2646
2647   // If the segment has a video track hold onto audio frames to make sure the
2648   // audio that is associated with the start time of a video key-frame is
2649   // muxed into the same cluster.
2650   if (has_video_ && tracks_.TrackIsAudio(frame->track_number()) &&
2651       !force_new_cluster_) {
2652     Frame* const new_frame = new (std::nothrow) Frame();
2653     if (!new_frame || !new_frame->CopyFrom(*frame))
2654       return false;
2655     return QueueFrame(new_frame);
2656   }
2657
2658   if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(),
2659                               frame->is_key())) {
2660     return false;
2661   }
2662
2663   if (cluster_list_size_ < 1)
2664     return false;
2665
2666   Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
2667   if (!cluster)
2668     return false;
2669
2670   // If the Frame is not a SimpleBlock, then set the reference_block_timestamp
2671   // if it is not set already.
2672   bool frame_created = false;
2673   if (!frame->CanBeSimpleBlock() && !frame->is_key() &&
2674       !frame->reference_block_timestamp_set()) {
2675     Frame* const new_frame = new (std::nothrow) Frame();
2676     if (!new_frame->CopyFrom(*frame))
2677       return false;
2678     new_frame->set_reference_block_timestamp(
2679         last_track_timestamp_[frame->track_number() - 1]);
2680     frame = new_frame;
2681     frame_created = true;
2682   }
2683
2684   if (!cluster->AddFrame(frame))
2685     return false;
2686
2687   if (new_cuepoint_ && cues_track_ == frame->track_number()) {
2688     if (!AddCuePoint(frame->timestamp(), cues_track_))
2689       return false;
2690   }
2691
2692   last_timestamp_ = frame->timestamp();
2693   last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
2694   last_block_duration_ = frame->duration();
2695
2696   if (frame_created)
2697     delete frame;
2698
2699   return true;
2700 }
2701
2702 void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; }
2703
2704 bool Segment::SetChunking(bool chunking, const char* filename) {
2705   if (chunk_count_ > 0)
2706     return false;
2707
2708   if (chunking) {
2709     if (!filename)
2710       return false;
2711
2712     // Check if we are being set to what is already set.
2713     if (chunking_ && !strcmp(filename, chunking_base_name_))
2714       return true;
2715
2716     const size_t name_length = strlen(filename) + 1;
2717     char* const temp = new (std::nothrow) char[name_length];  // NOLINT
2718     if (!temp)
2719       return false;
2720
2721 #ifdef _MSC_VER
2722     strcpy_s(temp, name_length, filename);
2723 #else
2724     strcpy(temp, filename);
2725 #endif
2726
2727     delete[] chunking_base_name_;
2728     chunking_base_name_ = temp;
2729
2730     if (!UpdateChunkName("chk", &chunk_name_))
2731       return false;
2732
2733     if (!chunk_writer_cluster_) {
2734       chunk_writer_cluster_ = new (std::nothrow) MkvWriter();  // NOLINT
2735       if (!chunk_writer_cluster_)
2736         return false;
2737     }
2738
2739     if (!chunk_writer_cues_) {
2740       chunk_writer_cues_ = new (std::nothrow) MkvWriter();  // NOLINT
2741       if (!chunk_writer_cues_)
2742         return false;
2743     }
2744
2745     if (!chunk_writer_header_) {
2746       chunk_writer_header_ = new (std::nothrow) MkvWriter();  // NOLINT
2747       if (!chunk_writer_header_)
2748         return false;
2749     }
2750
2751     if (!chunk_writer_cluster_->Open(chunk_name_))
2752       return false;
2753
2754     const size_t header_length = strlen(filename) + strlen(".hdr") + 1;
2755     char* const header = new (std::nothrow) char[header_length];  // NOLINT
2756     if (!header)
2757       return false;
2758
2759 #ifdef _MSC_VER
2760     strcpy_s(header, header_length - strlen(".hdr"), chunking_base_name_);
2761     strcat_s(header, header_length, ".hdr");
2762 #else
2763     strcpy(header, chunking_base_name_);
2764     strcat(header, ".hdr");
2765 #endif
2766     if (!chunk_writer_header_->Open(header)) {
2767       delete[] header;
2768       return false;
2769     }
2770
2771     writer_cluster_ = chunk_writer_cluster_;
2772     writer_cues_ = chunk_writer_cues_;
2773     writer_header_ = chunk_writer_header_;
2774
2775     delete[] header;
2776   }
2777
2778   chunking_ = chunking;
2779
2780   return true;
2781 }
2782
2783 bool Segment::CuesTrack(uint64 track_number) {
2784   const Track* const track = GetTrackByNumber(track_number);
2785   if (!track)
2786     return false;
2787
2788   cues_track_ = track_number;
2789   return true;
2790 }
2791
2792 void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; }
2793
2794 Track* Segment::GetTrackByNumber(uint64 track_number) const {
2795   return tracks_.GetTrackByNumber(track_number);
2796 }
2797
2798 bool Segment::WriteSegmentHeader() {
2799   UpdateDocTypeVersion();
2800
2801   // TODO(fgalligan): Support more than one segment.
2802   if (!WriteEbmlHeader(writer_header_, doc_type_version_))
2803     return false;
2804   doc_type_version_written_ = doc_type_version_;
2805   ebml_header_size_ = static_cast<int32>(writer_header_->Position());
2806
2807   // Write "unknown" (-1) as segment size value. If mode is kFile, Segment
2808   // will write over duration when the file is finalized.
2809   if (WriteID(writer_header_, kMkvSegment))
2810     return false;
2811
2812   // Save for later.
2813   size_position_ = writer_header_->Position();
2814
2815   // Write "unknown" (EBML coded -1) as segment size value. We need to write 8
2816   // bytes because if we are going to overwrite the segment size later we do
2817   // not know how big our segment will be.
2818   if (SerializeInt(writer_header_, kEbmlUnknownValue, 8))
2819     return false;
2820
2821   payload_pos_ = writer_header_->Position();
2822
2823   if (mode_ == kFile && writer_header_->Seekable()) {
2824     // Set the duration > 0.0 so SegmentInfo will write out the duration. When
2825     // the muxer is done writing we will set the correct duration and have
2826     // SegmentInfo upadte it.
2827     segment_info_.set_duration(1.0);
2828
2829     if (!seek_head_.Write(writer_header_))
2830       return false;
2831   }
2832
2833   if (!seek_head_.AddSeekEntry(kMkvInfo, MaxOffset()))
2834     return false;
2835   if (!segment_info_.Write(writer_header_))
2836     return false;
2837
2838   if (!seek_head_.AddSeekEntry(kMkvTracks, MaxOffset()))
2839     return false;
2840   if (!tracks_.Write(writer_header_))
2841     return false;
2842
2843   if (chapters_.Count() > 0) {
2844     if (!seek_head_.AddSeekEntry(kMkvChapters, MaxOffset()))
2845       return false;
2846     if (!chapters_.Write(writer_header_))
2847       return false;
2848   }
2849
2850   if (tags_.Count() > 0) {
2851     if (!seek_head_.AddSeekEntry(kMkvTags, MaxOffset()))
2852       return false;
2853     if (!tags_.Write(writer_header_))
2854       return false;
2855   }
2856
2857   if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) {
2858     if (!chunk_writer_header_)
2859       return false;
2860
2861     chunk_writer_header_->Close();
2862   }
2863
2864   header_written_ = true;
2865
2866   return true;
2867 }
2868
2869 // Here we are testing whether to create a new cluster, given a frame
2870 // having time frame_timestamp_ns.
2871 //
2872 int Segment::TestFrame(uint64 track_number, uint64 frame_timestamp_ns,
2873                        bool is_key) const {
2874   if (force_new_cluster_)
2875     return 1;
2876
2877   // If no clusters have been created yet, then create a new cluster
2878   // and write this frame immediately, in the new cluster.  This path
2879   // should only be followed once, the first time we attempt to write
2880   // a frame.
2881
2882   if (cluster_list_size_ <= 0)
2883     return 1;
2884
2885   // There exists at least one cluster. We must compare the frame to
2886   // the last cluster, in order to determine whether the frame is
2887   // written to the existing cluster, or that a new cluster should be
2888   // created.
2889
2890   const uint64 timecode_scale = segment_info_.timecode_scale();
2891   const uint64 frame_timecode = frame_timestamp_ns / timecode_scale;
2892
2893   const Cluster* const last_cluster = cluster_list_[cluster_list_size_ - 1];
2894   const uint64 last_cluster_timecode = last_cluster->timecode();
2895
2896   // For completeness we test for the case when the frame's timecode
2897   // is less than the cluster's timecode.  Although in principle that
2898   // is allowed, this muxer doesn't actually write clusters like that,
2899   // so this indicates a bug somewhere in our algorithm.
2900
2901   if (frame_timecode < last_cluster_timecode)  // should never happen
2902     return -1;
2903
2904   // If the frame has a timestamp significantly larger than the last
2905   // cluster (in Matroska, cluster-relative timestamps are serialized
2906   // using a 16-bit signed integer), then we cannot write this frame
2907   // to that cluster, and so we must create a new cluster.
2908
2909   const int64 delta_timecode = frame_timecode - last_cluster_timecode;
2910
2911   if (delta_timecode > kMaxBlockTimecode)
2912     return 2;
2913
2914   // We decide to create a new cluster when we have a video keyframe.
2915   // This will flush queued (audio) frames, and write the keyframe
2916   // immediately, in the newly-created cluster.
2917
2918   if (is_key && tracks_.TrackIsVideo(track_number))
2919     return 1;
2920
2921   // Create a new cluster if we have accumulated too many frames
2922   // already, where "too many" is defined as "the total time of frames
2923   // in the cluster exceeds a threshold".
2924
2925   const uint64 delta_ns = delta_timecode * timecode_scale;
2926
2927   if (max_cluster_duration_ > 0 && delta_ns >= max_cluster_duration_)
2928     return 1;
2929
2930   // This is similar to the case above, with the difference that a new
2931   // cluster is created when the size of the current cluster exceeds a
2932   // threshold.
2933
2934   const uint64 cluster_size = last_cluster->payload_size();
2935
2936   if (max_cluster_size_ > 0 && cluster_size >= max_cluster_size_)
2937     return 1;
2938
2939   // There's no need to create a new cluster, so emit this frame now.
2940
2941   return 0;
2942 }
2943
2944 bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) {
2945   const int32 new_size = cluster_list_size_ + 1;
2946
2947   if (new_size > cluster_list_capacity_) {
2948     // Add more clusters.
2949     const int32 new_capacity =
2950         (cluster_list_capacity_ <= 0) ? 1 : cluster_list_capacity_ * 2;
2951     Cluster** const clusters =
2952         new (std::nothrow) Cluster*[new_capacity];  // NOLINT
2953     if (!clusters)
2954       return false;
2955
2956     for (int32 i = 0; i < cluster_list_size_; ++i) {
2957       clusters[i] = cluster_list_[i];
2958     }
2959
2960     delete[] cluster_list_;
2961
2962     cluster_list_ = clusters;
2963     cluster_list_capacity_ = new_capacity;
2964   }
2965
2966   if (!WriteFramesLessThan(frame_timestamp_ns))
2967     return false;
2968
2969   if (mode_ == kFile) {
2970     if (cluster_list_size_ > 0) {
2971       // Update old cluster's size
2972       Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
2973
2974       if (!old_cluster || !old_cluster->Finalize())
2975         return false;
2976     }
2977
2978     if (output_cues_)
2979       new_cuepoint_ = true;
2980   }
2981
2982   if (chunking_ && cluster_list_size_ > 0) {
2983     chunk_writer_cluster_->Close();
2984     chunk_count_++;
2985
2986     if (!UpdateChunkName("chk", &chunk_name_))
2987       return false;
2988     if (!chunk_writer_cluster_->Open(chunk_name_))
2989       return false;
2990   }
2991
2992   const uint64 timecode_scale = segment_info_.timecode_scale();
2993   const uint64 frame_timecode = frame_timestamp_ns / timecode_scale;
2994
2995   uint64 cluster_timecode = frame_timecode;
2996
2997   if (frames_size_ > 0) {
2998     const Frame* const f = frames_[0];  // earliest queued frame
2999     const uint64 ns = f->timestamp();
3000     const uint64 tc = ns / timecode_scale;
3001
3002     if (tc < cluster_timecode)
3003       cluster_timecode = tc;
3004   }
3005
3006   Cluster*& cluster = cluster_list_[cluster_list_size_];
3007   const int64 offset = MaxOffset();
3008   cluster = new (std::nothrow) Cluster(cluster_timecode,  // NOLINT
3009                                        offset, segment_info_.timecode_scale());
3010   if (!cluster)
3011     return false;
3012
3013   if (!cluster->Init(writer_cluster_))
3014     return false;
3015
3016   cluster_list_size_ = new_size;
3017   return true;
3018 }
3019
3020 bool Segment::DoNewClusterProcessing(uint64 track_number,
3021                                      uint64 frame_timestamp_ns, bool is_key) {
3022   for (;;) {
3023     // Based on the characteristics of the current frame and current
3024     // cluster, decide whether to create a new cluster.
3025     const int result = TestFrame(track_number, frame_timestamp_ns, is_key);
3026     if (result < 0)  // error
3027       return false;
3028
3029     // Always set force_new_cluster_ to false after TestFrame.
3030     force_new_cluster_ = false;
3031
3032     // A non-zero result means create a new cluster.
3033     if (result > 0 && !MakeNewCluster(frame_timestamp_ns))
3034       return false;
3035
3036     // Write queued (audio) frames.
3037     const int frame_count = WriteFramesAll();
3038     if (frame_count < 0)  // error
3039       return false;
3040
3041     // Write the current frame to the current cluster (if TestFrame
3042     // returns 0) or to a newly created cluster (TestFrame returns 1).
3043     if (result <= 1)
3044       return true;
3045
3046     // TestFrame returned 2, which means there was a large time
3047     // difference between the cluster and the frame itself.  Do the
3048     // test again, comparing the frame to the new cluster.
3049   }
3050 }
3051
3052 bool Segment::CheckHeaderInfo() {
3053   if (!header_written_) {
3054     if (!WriteSegmentHeader())
3055       return false;
3056
3057     if (!seek_head_.AddSeekEntry(kMkvCluster, MaxOffset()))
3058       return false;
3059
3060     if (output_cues_ && cues_track_ == 0) {
3061       // Check for a video track
3062       for (uint32 i = 0; i < tracks_.track_entries_size(); ++i) {
3063         const Track* const track = tracks_.GetTrackByIndex(i);
3064         if (!track)
3065           return false;
3066
3067         if (tracks_.TrackIsVideo(track->number())) {
3068           cues_track_ = track->number();
3069           break;
3070         }
3071       }
3072
3073       // Set first track found
3074       if (cues_track_ == 0) {
3075         const Track* const track = tracks_.GetTrackByIndex(0);
3076         if (!track)
3077           return false;
3078
3079         cues_track_ = track->number();
3080       }
3081     }
3082   }
3083   return true;
3084 }
3085
3086 void Segment::UpdateDocTypeVersion() {
3087   for (uint32 index = 0; index < tracks_.track_entries_size(); ++index) {
3088     const Track* track = tracks_.GetTrackByIndex(index);
3089     if (track == NULL)
3090       break;
3091     if ((track->codec_delay() || track->seek_pre_roll()) &&
3092         doc_type_version_ < 4) {
3093       doc_type_version_ = 4;
3094       break;
3095     }
3096   }
3097 }
3098
3099 bool Segment::UpdateChunkName(const char* ext, char** name) const {
3100   if (!name || !ext)
3101     return false;
3102
3103   char ext_chk[64];
3104 #ifdef _MSC_VER
3105   sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
3106 #else
3107   snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
3108 #endif
3109
3110   const size_t length = strlen(chunking_base_name_) + strlen(ext_chk) + 1;
3111   char* const str = new (std::nothrow) char[length];  // NOLINT
3112   if (!str)
3113     return false;
3114
3115 #ifdef _MSC_VER
3116   strcpy_s(str, length - strlen(ext_chk), chunking_base_name_);
3117   strcat_s(str, length, ext_chk);
3118 #else
3119   strcpy(str, chunking_base_name_);
3120   strcat(str, ext_chk);
3121 #endif
3122
3123   delete[] * name;
3124   *name = str;
3125
3126   return true;
3127 }
3128
3129 int64 Segment::MaxOffset() {
3130   if (!writer_header_)
3131     return -1;
3132
3133   int64 offset = writer_header_->Position() - payload_pos_;
3134
3135   if (chunking_) {
3136     for (int32 i = 0; i < cluster_list_size_; ++i) {
3137       Cluster* const cluster = cluster_list_[i];
3138       offset += cluster->Size();
3139     }
3140
3141     if (writer_cues_)
3142       offset += writer_cues_->Position();
3143   }
3144
3145   return offset;
3146 }
3147
3148 bool Segment::QueueFrame(Frame* frame) {
3149   const int32 new_size = frames_size_ + 1;
3150
3151   if (new_size > frames_capacity_) {
3152     // Add more frames.
3153     const int32 new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2;
3154
3155     if (new_capacity < 1)
3156       return false;
3157
3158     Frame** const frames = new (std::nothrow) Frame*[new_capacity];  // NOLINT
3159     if (!frames)
3160       return false;
3161
3162     for (int32 i = 0; i < frames_size_; ++i) {
3163       frames[i] = frames_[i];
3164     }
3165
3166     delete[] frames_;
3167     frames_ = frames;
3168     frames_capacity_ = new_capacity;
3169   }
3170
3171   frames_[frames_size_++] = frame;
3172
3173   return true;
3174 }
3175
3176 int Segment::WriteFramesAll() {
3177   if (frames_ == NULL)
3178     return 0;
3179
3180   if (cluster_list_size_ < 1)
3181     return -1;
3182
3183   Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
3184
3185   if (!cluster)
3186     return -1;
3187
3188   for (int32 i = 0; i < frames_size_; ++i) {
3189     Frame*& frame = frames_[i];
3190     // TODO(jzern/vigneshv): using Segment::AddGenericFrame here would limit the
3191     // places where |doc_type_version_| needs to be updated.
3192     if (frame->discard_padding() != 0)
3193       doc_type_version_ = 4;
3194     if (!cluster->AddFrame(frame))
3195       return -1;
3196
3197     if (new_cuepoint_ && cues_track_ == frame->track_number()) {
3198       if (!AddCuePoint(frame->timestamp(), cues_track_))
3199         return -1;
3200     }
3201
3202     if (frame->timestamp() > last_timestamp_) {
3203       last_timestamp_ = frame->timestamp();
3204       last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
3205     }
3206
3207     delete frame;
3208     frame = NULL;
3209   }
3210
3211   const int result = frames_size_;
3212   frames_size_ = 0;
3213
3214   return result;
3215 }
3216
3217 bool Segment::WriteFramesLessThan(uint64 timestamp) {
3218   // Check |cluster_list_size_| to see if this is the first cluster. If it is
3219   // the first cluster the audio frames that are less than the first video
3220   // timesatmp will be written in a later step.
3221   if (frames_size_ > 0 && cluster_list_size_ > 0) {
3222     if (!frames_)
3223       return false;
3224
3225     Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
3226     if (!cluster)
3227       return false;
3228
3229     int32 shift_left = 0;
3230
3231     // TODO(fgalligan): Change this to use the durations of frames instead of
3232     // the next frame's start time if the duration is accurate.
3233     for (int32 i = 1; i < frames_size_; ++i) {
3234       const Frame* const frame_curr = frames_[i];
3235
3236       if (frame_curr->timestamp() > timestamp)
3237         break;
3238
3239       const Frame* const frame_prev = frames_[i - 1];
3240       if (frame_prev->discard_padding() != 0)
3241         doc_type_version_ = 4;
3242       if (!cluster->AddFrame(frame_prev))
3243         return false;
3244
3245       if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
3246         if (!AddCuePoint(frame_prev->timestamp(), cues_track_))
3247           return false;
3248       }
3249
3250       ++shift_left;
3251       if (frame_prev->timestamp() > last_timestamp_) {
3252         last_timestamp_ = frame_prev->timestamp();
3253         last_track_timestamp_[frame_prev->track_number() - 1] =
3254             frame_prev->timestamp();
3255       }
3256
3257       delete frame_prev;
3258     }
3259
3260     if (shift_left > 0) {
3261       if (shift_left >= frames_size_)
3262         return false;
3263
3264       const int32 new_frames_size = frames_size_ - shift_left;
3265       for (int32 i = 0; i < new_frames_size; ++i) {
3266         frames_[i] = frames_[i + shift_left];
3267       }
3268
3269       frames_size_ = new_frames_size;
3270     }
3271   }
3272
3273   return true;
3274 }
3275
3276 }  // namespace mkvmuxer