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