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