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
28namespace mkvmuxer {
29
30namespace {
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.
37bool 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
64IMkvWriter::IMkvWriter() {}
65
66IMkvWriter::~IMkvWriter() {}
67
68bool 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
98bool 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
120Frame::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
132Frame::~Frame() {
133  delete[] frame_;
134  delete[] additional_;
135}
136
137bool 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
151bool 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
171CuePoint::CuePoint()
172    : time_(0),
173      track_(0),
174      cluster_pos_(0),
175      block_number_(1),
176      output_block_number_(true) {}
177
178CuePoint::~CuePoint() {}
179
180bool 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
223uint64 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
236uint64 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
245Cues::Cues()
246    : cue_entries_capacity_(0),
247      cue_entries_size_(0),
248      cue_entries_(NULL),
249      output_block_number_(true) {}
250
251Cues::~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
261bool 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
293CuePoint* 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
303uint64 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
311bool 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
353ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}
354
355uint64 ContentEncAESSettings::Size() const {
356  const uint64 payload = PayloadSize();
357  const uint64 size =
358      EbmlMasterElementSize(kMkvContentEncAESSettings, payload) + payload;
359  return size;
360}
361
362bool 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
383uint64 ContentEncAESSettings::PayloadSize() const {
384  uint64 size = EbmlElementSize(kMkvAESSettingsCipherMode, cipher_mode_);
385  return size;
386}
387
388///////////////////////////////////////////////////////////////
389//
390// ContentEncoding Class
391
392ContentEncoding::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
400ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
401
402bool 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
419uint64 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
428bool 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
466uint64 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
486uint64 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
500Track::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
516Track::~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
531bool 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
558ContentEncoding* 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
568uint64 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
605uint64 Track::Size() const {
606  uint64 size = PayloadSize();
607  size += EbmlMasterElementSize(kMkvTrackEntry, size);
608  return size;
609}
610
611bool 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
722bool 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
739void 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.
756void 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
772void 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
792VideoTrack::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
802VideoTrack::~VideoTrack() {}
803
804bool 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
815bool 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
823uint64 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
832bool 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
874uint64 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
895AudioTrack::AudioTrack(unsigned int* seed)
896    : Track(seed), bit_depth_(0), channels_(1), sample_rate_(0.0) {}
897
898AudioTrack::~AudioTrack() {}
899
900uint64 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
913bool 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
952const char Tracks::kOpusCodecId[] = "A_OPUS";
953const char Tracks::kVorbisCodecId[] = "A_VORBIS";
954const char Tracks::kVp8CodecId[] = "V_VP8";
955const char Tracks::kVp9CodecId[] = "V_VP9";
956
957Tracks::Tracks() : track_entries_(NULL), track_entries_size_(0) {}
958
959Tracks::~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
969bool 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
1028const 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
1038Track* 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
1048bool 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
1057bool 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
1066bool 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
1103bool Chapter::set_id(const char* id) { return StrCpy(id, &id_); }
1104
1105void 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
1112bool 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
1132Chapter::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
1144Chapter::~Chapter() {}
1145
1146void 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
1154void 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
1164void 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
1178bool 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
1200uint64 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
1249void Chapter::Display::Init() {
1250  title_ = NULL;
1251  language_ = NULL;
1252  country_ = NULL;
1253}
1254
1255void Chapter::Display::Clear() {
1256  StrCpy(NULL, &title_);
1257  StrCpy(NULL, &language_);
1258  StrCpy(NULL, &country_);
1259}
1260
1261bool Chapter::Display::set_title(const char* title) {
1262  return StrCpy(title, &title_);
1263}
1264
1265bool Chapter::Display::set_language(const char* language) {
1266  return StrCpy(language, &language_);
1267}
1268
1269bool Chapter::Display::set_country(const char* country) {
1270  return StrCpy(country, &country_);
1271}
1272
1273uint64 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
1318Chapters::Chapters() : chapters_size_(0), chapters_count_(0), chapters_(NULL) {}
1319
1320Chapters::~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
1330int Chapters::Count() const { return chapters_count_; }
1331
1332Chapter* 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
1342bool 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
1364bool 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
1388uint64 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
1427Cluster::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
1437Cluster::~Cluster() {}
1438
1439bool Cluster::Init(IMkvWriter* ptr_writer) {
1440  if (!ptr_writer) {
1441    return false;
1442  }
1443  writer_ = ptr_writer;
1444  return true;
1445}
1446
1447bool 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
1453bool 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
1463bool 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
1472bool 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
1479void Cluster::AddPayloadSize(uint64 size) { payload_size_ += size; }
1480
1481bool 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
1503uint64 Cluster::Size() const {
1504  const uint64 element_size =
1505      EbmlMasterElementSize(kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) + payload_size_;
1506  return element_size;
1507}
1508
1509template <typename Type>
1510bool 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
1525void Cluster::PostWriteBlock(uint64 element_size) {
1526  AddPayloadSize(element_size);
1527  ++blocks_added_;
1528}
1529
1530bool Cluster::IsValidTrackNumber(uint64 track_number) const {
1531  return (track_number > 0 && track_number <= 0x7E);
1532}
1533
1534int64 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
1545bool 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
1570bool 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
1598bool 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
1625bool 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
1652SeekHead::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
1659SeekHead::~SeekHead() {}
1660
1661bool 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
1722bool 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
1735bool 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
1746uint32 SeekHead::GetId(int index) const {
1747  if (index < 0 || index >= kSeekEntryCount)
1748    return UINT_MAX;
1749  return seek_entry_id_[index];
1750}
1751
1752uint64 SeekHead::GetPosition(int index) const {
1753  if (index < 0 || index >= kSeekEntryCount)
1754    return ULLONG_MAX;
1755  return seek_entry_pos_[index];
1756}
1757
1758bool 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
1766uint64 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
1781SegmentInfo::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
1789SegmentInfo::~SegmentInfo() {
1790  delete[] muxing_app_;
1791  delete[] writing_app_;
1792}
1793
1794bool 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
1829bool 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
1855bool 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
1901void 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
1919void 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
1941Segment::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
1979Segment::~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
2013void 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
2042void 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
2064bool 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
2074bool 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
2110bool 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
2197Track* 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
2211Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
2212
2213uint64 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
2229bool 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
2252uint64 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
2267bool 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
2323bool 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
2384bool 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
2445bool 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
2483bool 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
2504void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; }
2505
2506bool 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
2585bool 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
2594void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; }
2595
2596Track* Segment::GetTrackByNumber(uint64 track_number) const {
2597  return tracks_.GetTrackByNumber(track_number);
2598}
2599
2600bool 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//
2663int 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
2735bool 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
2810bool 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
2842bool 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
2876bool 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
2906int64 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
2925bool 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
2953int 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
3004bool 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
3076