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