Home | History | Annotate | Download | only in mkvmuxer
      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/mkvmuxer.h"
     10 
     11 #include <stdint.h>
     12 
     13 #include <cfloat>
     14 #include <climits>
     15 #include <cstdio>
     16 #include <cstdlib>
     17 #include <cstring>
     18 #include <ctime>
     19 #include <memory>
     20 #include <new>
     21 #include <string>
     22 #include <vector>
     23 
     24 #include "common/webmids.h"
     25 #include "mkvmuxer/mkvmuxerutil.h"
     26 #include "mkvmuxer/mkvwriter.h"
     27 #include "mkvparser/mkvparser.h"
     28 
     29 namespace mkvmuxer {
     30 
     31 const float PrimaryChromaticity::kChromaticityMin = 0.0f;
     32 const float PrimaryChromaticity::kChromaticityMax = 1.0f;
     33 const float MasteringMetadata::kMinLuminance = 0.0f;
     34 const float MasteringMetadata::kMinLuminanceMax = 999.99f;
     35 const float MasteringMetadata::kMaxLuminanceMax = 9999.99f;
     36 const float MasteringMetadata::kValueNotPresent = FLT_MAX;
     37 const uint64_t Colour::kValueNotPresent = UINT64_MAX;
     38 
     39 namespace {
     40 
     41 const char kDocTypeWebm[] = "webm";
     42 const char kDocTypeMatroska[] = "matroska";
     43 
     44 // Deallocate the string designated by |dst|, and then copy the |src|
     45 // string to |dst|.  The caller owns both the |src| string and the
     46 // |dst| copy (hence the caller is responsible for eventually
     47 // deallocating the strings, either directly, or indirectly via
     48 // StrCpy).  Returns true if the source string was successfully copied
     49 // to the destination.
     50 bool StrCpy(const char* src, char** dst_ptr) {
     51   if (dst_ptr == NULL)
     52     return false;
     53 
     54   char*& dst = *dst_ptr;
     55 
     56   delete[] dst;
     57   dst = NULL;
     58 
     59   if (src == NULL)
     60     return true;
     61 
     62   const size_t size = strlen(src) + 1;
     63 
     64   dst = new (std::nothrow) char[size];  // NOLINT
     65   if (dst == NULL)
     66     return false;
     67 
     68   strcpy(dst, src);  // NOLINT
     69   return true;
     70 }
     71 
     72 typedef std::unique_ptr<PrimaryChromaticity> PrimaryChromaticityPtr;
     73 bool CopyChromaticity(const PrimaryChromaticity* src,
     74                       PrimaryChromaticityPtr* dst) {
     75   if (!dst)
     76     return false;
     77 
     78   dst->reset(new (std::nothrow) PrimaryChromaticity(src->x(), src->y()));
     79   if (!dst->get())
     80     return false;
     81 
     82   return true;
     83 }
     84 
     85 }  // namespace
     86 
     87 ///////////////////////////////////////////////////////////////
     88 //
     89 // IMkvWriter Class
     90 
     91 IMkvWriter::IMkvWriter() {}
     92 
     93 IMkvWriter::~IMkvWriter() {}
     94 
     95 bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version,
     96                      const char* const doc_type) {
     97   // Level 0
     98   uint64_t size =
     99       EbmlElementSize(libwebm::kMkvEBMLVersion, static_cast<uint64>(1));
    100   size += EbmlElementSize(libwebm::kMkvEBMLReadVersion, static_cast<uint64>(1));
    101   size += EbmlElementSize(libwebm::kMkvEBMLMaxIDLength, static_cast<uint64>(4));
    102   size +=
    103       EbmlElementSize(libwebm::kMkvEBMLMaxSizeLength, static_cast<uint64>(8));
    104   size += EbmlElementSize(libwebm::kMkvDocType, doc_type);
    105   size += EbmlElementSize(libwebm::kMkvDocTypeVersion,
    106                           static_cast<uint64>(doc_type_version));
    107   size +=
    108       EbmlElementSize(libwebm::kMkvDocTypeReadVersion, static_cast<uint64>(2));
    109 
    110   if (!WriteEbmlMasterElement(writer, libwebm::kMkvEBML, size))
    111     return false;
    112   if (!WriteEbmlElement(writer, libwebm::kMkvEBMLVersion,
    113                         static_cast<uint64>(1))) {
    114     return false;
    115   }
    116   if (!WriteEbmlElement(writer, libwebm::kMkvEBMLReadVersion,
    117                         static_cast<uint64>(1))) {
    118     return false;
    119   }
    120   if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxIDLength,
    121                         static_cast<uint64>(4))) {
    122     return false;
    123   }
    124   if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxSizeLength,
    125                         static_cast<uint64>(8))) {
    126     return false;
    127   }
    128   if (!WriteEbmlElement(writer, libwebm::kMkvDocType, doc_type))
    129     return false;
    130   if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeVersion,
    131                         static_cast<uint64>(doc_type_version))) {
    132     return false;
    133   }
    134   if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeReadVersion,
    135                         static_cast<uint64>(2))) {
    136     return false;
    137   }
    138 
    139   return true;
    140 }
    141 
    142 bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version) {
    143   return WriteEbmlHeader(writer, doc_type_version, kDocTypeWebm);
    144 }
    145 
    146 bool WriteEbmlHeader(IMkvWriter* writer) {
    147   return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion);
    148 }
    149 
    150 bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst,
    151                  int64_t start, int64_t size) {
    152   // TODO(vigneshv): Check if this is a reasonable value.
    153   const uint32_t kBufSize = 2048;
    154   uint8_t* buf = new uint8_t[kBufSize];
    155   int64_t offset = start;
    156   while (size > 0) {
    157     const int64_t read_len = (size > kBufSize) ? kBufSize : size;
    158     if (source->Read(offset, static_cast<long>(read_len), buf))
    159       return false;
    160     dst->Write(buf, static_cast<uint32_t>(read_len));
    161     offset += read_len;
    162     size -= read_len;
    163   }
    164   delete[] buf;
    165   return true;
    166 }
    167 
    168 ///////////////////////////////////////////////////////////////
    169 //
    170 // Frame Class
    171 
    172 Frame::Frame()
    173     : add_id_(0),
    174       additional_(NULL),
    175       additional_length_(0),
    176       duration_(0),
    177       duration_set_(false),
    178       frame_(NULL),
    179       is_key_(false),
    180       length_(0),
    181       track_number_(0),
    182       timestamp_(0),
    183       discard_padding_(0),
    184       reference_block_timestamp_(0),
    185       reference_block_timestamp_set_(false) {}
    186 
    187 Frame::~Frame() {
    188   delete[] frame_;
    189   delete[] additional_;
    190 }
    191 
    192 bool Frame::CopyFrom(const Frame& frame) {
    193   delete[] frame_;
    194   frame_ = NULL;
    195   length_ = 0;
    196   if (frame.length() > 0 && frame.frame() != NULL &&
    197       !Init(frame.frame(), frame.length())) {
    198     return false;
    199   }
    200   add_id_ = 0;
    201   delete[] additional_;
    202   additional_ = NULL;
    203   additional_length_ = 0;
    204   if (frame.additional_length() > 0 && frame.additional() != NULL &&
    205       !AddAdditionalData(frame.additional(), frame.additional_length(),
    206                          frame.add_id())) {
    207     return false;
    208   }
    209   duration_ = frame.duration();
    210   duration_set_ = frame.duration_set();
    211   is_key_ = frame.is_key();
    212   track_number_ = frame.track_number();
    213   timestamp_ = frame.timestamp();
    214   discard_padding_ = frame.discard_padding();
    215   reference_block_timestamp_ = frame.reference_block_timestamp();
    216   reference_block_timestamp_set_ = frame.reference_block_timestamp_set();
    217   return true;
    218 }
    219 
    220 bool Frame::Init(const uint8_t* frame, uint64_t length) {
    221   uint8_t* const data =
    222       new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
    223   if (!data)
    224     return false;
    225 
    226   delete[] frame_;
    227   frame_ = data;
    228   length_ = length;
    229 
    230   memcpy(frame_, frame, static_cast<size_t>(length_));
    231   return true;
    232 }
    233 
    234 bool Frame::AddAdditionalData(const uint8_t* additional, uint64_t length,
    235                               uint64_t add_id) {
    236   uint8_t* const data =
    237       new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
    238   if (!data)
    239     return false;
    240 
    241   delete[] additional_;
    242   additional_ = data;
    243   additional_length_ = length;
    244   add_id_ = add_id;
    245 
    246   memcpy(additional_, additional, static_cast<size_t>(additional_length_));
    247   return true;
    248 }
    249 
    250 bool Frame::IsValid() const {
    251   if (length_ == 0 || !frame_) {
    252     return false;
    253   }
    254   if ((additional_length_ != 0 && !additional_) ||
    255       (additional_ != NULL && additional_length_ == 0)) {
    256     return false;
    257   }
    258   if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
    259     return false;
    260   }
    261   if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
    262     return false;
    263   }
    264   return true;
    265 }
    266 
    267 bool Frame::CanBeSimpleBlock() const {
    268   return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
    269 }
    270 
    271 void Frame::set_duration(uint64_t duration) {
    272   duration_ = duration;
    273   duration_set_ = true;
    274 }
    275 
    276 void Frame::set_reference_block_timestamp(int64_t reference_block_timestamp) {
    277   reference_block_timestamp_ = reference_block_timestamp;
    278   reference_block_timestamp_set_ = true;
    279 }
    280 
    281 ///////////////////////////////////////////////////////////////
    282 //
    283 // CuePoint Class
    284 
    285 CuePoint::CuePoint()
    286     : time_(0),
    287       track_(0),
    288       cluster_pos_(0),
    289       block_number_(1),
    290       output_block_number_(true) {}
    291 
    292 CuePoint::~CuePoint() {}
    293 
    294 bool CuePoint::Write(IMkvWriter* writer) const {
    295   if (!writer || track_ < 1 || cluster_pos_ < 1)
    296     return false;
    297 
    298   uint64_t size = EbmlElementSize(libwebm::kMkvCueClusterPosition,
    299                                   static_cast<uint64>(cluster_pos_));
    300   size += EbmlElementSize(libwebm::kMkvCueTrack, static_cast<uint64>(track_));
    301   if (output_block_number_ && block_number_ > 1)
    302     size += EbmlElementSize(libwebm::kMkvCueBlockNumber,
    303                             static_cast<uint64>(block_number_));
    304   const uint64_t track_pos_size =
    305       EbmlMasterElementSize(libwebm::kMkvCueTrackPositions, size) + size;
    306   const uint64_t payload_size =
    307       EbmlElementSize(libwebm::kMkvCueTime, static_cast<uint64>(time_)) +
    308       track_pos_size;
    309 
    310   if (!WriteEbmlMasterElement(writer, libwebm::kMkvCuePoint, payload_size))
    311     return false;
    312 
    313   const int64_t payload_position = writer->Position();
    314   if (payload_position < 0)
    315     return false;
    316 
    317   if (!WriteEbmlElement(writer, libwebm::kMkvCueTime,
    318                         static_cast<uint64>(time_))) {
    319     return false;
    320   }
    321 
    322   if (!WriteEbmlMasterElement(writer, libwebm::kMkvCueTrackPositions, size))
    323     return false;
    324   if (!WriteEbmlElement(writer, libwebm::kMkvCueTrack,
    325                         static_cast<uint64>(track_))) {
    326     return false;
    327   }
    328   if (!WriteEbmlElement(writer, libwebm::kMkvCueClusterPosition,
    329                         static_cast<uint64>(cluster_pos_))) {
    330     return false;
    331   }
    332   if (output_block_number_ && block_number_ > 1) {
    333     if (!WriteEbmlElement(writer, libwebm::kMkvCueBlockNumber,
    334                           static_cast<uint64>(block_number_))) {
    335       return false;
    336     }
    337   }
    338 
    339   const int64_t stop_position = writer->Position();
    340   if (stop_position < 0)
    341     return false;
    342 
    343   if (stop_position - payload_position != static_cast<int64_t>(payload_size))
    344     return false;
    345 
    346   return true;
    347 }
    348 
    349 uint64_t CuePoint::PayloadSize() const {
    350   uint64_t size = EbmlElementSize(libwebm::kMkvCueClusterPosition,
    351                                   static_cast<uint64>(cluster_pos_));
    352   size += EbmlElementSize(libwebm::kMkvCueTrack, static_cast<uint64>(track_));
    353   if (output_block_number_ && block_number_ > 1)
    354     size += EbmlElementSize(libwebm::kMkvCueBlockNumber,
    355                             static_cast<uint64>(block_number_));
    356   const uint64_t track_pos_size =
    357       EbmlMasterElementSize(libwebm::kMkvCueTrackPositions, size) + size;
    358   const uint64_t payload_size =
    359       EbmlElementSize(libwebm::kMkvCueTime, static_cast<uint64>(time_)) +
    360       track_pos_size;
    361 
    362   return payload_size;
    363 }
    364 
    365 uint64_t CuePoint::Size() const {
    366   const uint64_t payload_size = PayloadSize();
    367   return EbmlMasterElementSize(libwebm::kMkvCuePoint, payload_size) +
    368          payload_size;
    369 }
    370 
    371 ///////////////////////////////////////////////////////////////
    372 //
    373 // Cues Class
    374 
    375 Cues::Cues()
    376     : cue_entries_capacity_(0),
    377       cue_entries_size_(0),
    378       cue_entries_(NULL),
    379       output_block_number_(true) {}
    380 
    381 Cues::~Cues() {
    382   if (cue_entries_) {
    383     for (int32_t i = 0; i < cue_entries_size_; ++i) {
    384       CuePoint* const cue = cue_entries_[i];
    385       delete cue;
    386     }
    387     delete[] cue_entries_;
    388   }
    389 }
    390 
    391 bool Cues::AddCue(CuePoint* cue) {
    392   if (!cue)
    393     return false;
    394 
    395   if ((cue_entries_size_ + 1) > cue_entries_capacity_) {
    396     // Add more CuePoints.
    397     const int32_t new_capacity =
    398         (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2;
    399 
    400     if (new_capacity < 1)
    401       return false;
    402 
    403     CuePoint** const cues =
    404         new (std::nothrow) CuePoint*[new_capacity];  // NOLINT
    405     if (!cues)
    406       return false;
    407 
    408     for (int32_t i = 0; i < cue_entries_size_; ++i) {
    409       cues[i] = cue_entries_[i];
    410     }
    411 
    412     delete[] cue_entries_;
    413 
    414     cue_entries_ = cues;
    415     cue_entries_capacity_ = new_capacity;
    416   }
    417 
    418   cue->set_output_block_number(output_block_number_);
    419   cue_entries_[cue_entries_size_++] = cue;
    420   return true;
    421 }
    422 
    423 CuePoint* Cues::GetCueByIndex(int32_t index) const {
    424   if (cue_entries_ == NULL)
    425     return NULL;
    426 
    427   if (index >= cue_entries_size_)
    428     return NULL;
    429 
    430   return cue_entries_[index];
    431 }
    432 
    433 uint64_t Cues::Size() {
    434   uint64_t size = 0;
    435   for (int32_t i = 0; i < cue_entries_size_; ++i)
    436     size += GetCueByIndex(i)->Size();
    437   size += EbmlMasterElementSize(libwebm::kMkvCues, size);
    438   return size;
    439 }
    440 
    441 bool Cues::Write(IMkvWriter* writer) const {
    442   if (!writer)
    443     return false;
    444 
    445   uint64_t size = 0;
    446   for (int32_t i = 0; i < cue_entries_size_; ++i) {
    447     const CuePoint* const cue = GetCueByIndex(i);
    448 
    449     if (!cue)
    450       return false;
    451 
    452     size += cue->Size();
    453   }
    454 
    455   if (!WriteEbmlMasterElement(writer, libwebm::kMkvCues, size))
    456     return false;
    457 
    458   const int64_t payload_position = writer->Position();
    459   if (payload_position < 0)
    460     return false;
    461 
    462   for (int32_t i = 0; i < cue_entries_size_; ++i) {
    463     const CuePoint* const cue = GetCueByIndex(i);
    464 
    465     if (!cue->Write(writer))
    466       return false;
    467   }
    468 
    469   const int64_t stop_position = writer->Position();
    470   if (stop_position < 0)
    471     return false;
    472 
    473   if (stop_position - payload_position != static_cast<int64_t>(size))
    474     return false;
    475 
    476   return true;
    477 }
    478 
    479 ///////////////////////////////////////////////////////////////
    480 //
    481 // ContentEncAESSettings Class
    482 
    483 ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}
    484 
    485 uint64_t ContentEncAESSettings::Size() const {
    486   const uint64_t payload = PayloadSize();
    487   const uint64_t size =
    488       EbmlMasterElementSize(libwebm::kMkvContentEncAESSettings, payload) +
    489       payload;
    490   return size;
    491 }
    492 
    493 bool ContentEncAESSettings::Write(IMkvWriter* writer) const {
    494   const uint64_t payload = PayloadSize();
    495 
    496   if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncAESSettings,
    497                               payload))
    498     return false;
    499 
    500   const int64_t payload_position = writer->Position();
    501   if (payload_position < 0)
    502     return false;
    503 
    504   if (!WriteEbmlElement(writer, libwebm::kMkvAESSettingsCipherMode,
    505                         static_cast<uint64>(cipher_mode_))) {
    506     return false;
    507   }
    508 
    509   const int64_t stop_position = writer->Position();
    510   if (stop_position < 0 ||
    511       stop_position - payload_position != static_cast<int64_t>(payload))
    512     return false;
    513 
    514   return true;
    515 }
    516 
    517 uint64_t ContentEncAESSettings::PayloadSize() const {
    518   uint64_t size = EbmlElementSize(libwebm::kMkvAESSettingsCipherMode,
    519                                   static_cast<uint64>(cipher_mode_));
    520   return size;
    521 }
    522 
    523 ///////////////////////////////////////////////////////////////
    524 //
    525 // ContentEncoding Class
    526 
    527 ContentEncoding::ContentEncoding()
    528     : enc_algo_(5),
    529       enc_key_id_(NULL),
    530       encoding_order_(0),
    531       encoding_scope_(1),
    532       encoding_type_(1),
    533       enc_key_id_length_(0) {}
    534 
    535 ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
    536 
    537 bool ContentEncoding::SetEncryptionID(const uint8_t* id, uint64_t length) {
    538   if (!id || length < 1)
    539     return false;
    540 
    541   delete[] enc_key_id_;
    542 
    543   enc_key_id_ =
    544       new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
    545   if (!enc_key_id_)
    546     return false;
    547 
    548   memcpy(enc_key_id_, id, static_cast<size_t>(length));
    549   enc_key_id_length_ = length;
    550 
    551   return true;
    552 }
    553 
    554 uint64_t ContentEncoding::Size() const {
    555   const uint64_t encryption_size = EncryptionSize();
    556   const uint64_t encoding_size = EncodingSize(0, encryption_size);
    557   const uint64_t encodings_size =
    558       EbmlMasterElementSize(libwebm::kMkvContentEncoding, encoding_size) +
    559       encoding_size;
    560 
    561   return encodings_size;
    562 }
    563 
    564 bool ContentEncoding::Write(IMkvWriter* writer) const {
    565   const uint64_t encryption_size = EncryptionSize();
    566   const uint64_t encoding_size = EncodingSize(0, encryption_size);
    567   const uint64_t size =
    568       EbmlMasterElementSize(libwebm::kMkvContentEncoding, encoding_size) +
    569       encoding_size;
    570 
    571   const int64_t payload_position = writer->Position();
    572   if (payload_position < 0)
    573     return false;
    574 
    575   if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncoding,
    576                               encoding_size))
    577     return false;
    578   if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingOrder,
    579                         static_cast<uint64>(encoding_order_)))
    580     return false;
    581   if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingScope,
    582                         static_cast<uint64>(encoding_scope_)))
    583     return false;
    584   if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingType,
    585                         static_cast<uint64>(encoding_type_)))
    586     return false;
    587 
    588   if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncryption,
    589                               encryption_size))
    590     return false;
    591   if (!WriteEbmlElement(writer, libwebm::kMkvContentEncAlgo,
    592                         static_cast<uint64>(enc_algo_))) {
    593     return false;
    594   }
    595   if (!WriteEbmlElement(writer, libwebm::kMkvContentEncKeyID, enc_key_id_,
    596                         enc_key_id_length_))
    597     return false;
    598 
    599   if (!enc_aes_settings_.Write(writer))
    600     return false;
    601 
    602   const int64_t stop_position = writer->Position();
    603   if (stop_position < 0 ||
    604       stop_position - payload_position != static_cast<int64_t>(size))
    605     return false;
    606 
    607   return true;
    608 }
    609 
    610 uint64_t ContentEncoding::EncodingSize(uint64_t compresion_size,
    611                                        uint64_t encryption_size) const {
    612   // TODO(fgalligan): Add support for compression settings.
    613   if (compresion_size != 0)
    614     return 0;
    615 
    616   uint64_t encoding_size = 0;
    617 
    618   if (encryption_size > 0) {
    619     encoding_size +=
    620         EbmlMasterElementSize(libwebm::kMkvContentEncryption, encryption_size) +
    621         encryption_size;
    622   }
    623   encoding_size += EbmlElementSize(libwebm::kMkvContentEncodingType,
    624                                    static_cast<uint64>(encoding_type_));
    625   encoding_size += EbmlElementSize(libwebm::kMkvContentEncodingScope,
    626                                    static_cast<uint64>(encoding_scope_));
    627   encoding_size += EbmlElementSize(libwebm::kMkvContentEncodingOrder,
    628                                    static_cast<uint64>(encoding_order_));
    629 
    630   return encoding_size;
    631 }
    632 
    633 uint64_t ContentEncoding::EncryptionSize() const {
    634   const uint64_t aes_size = enc_aes_settings_.Size();
    635 
    636   uint64_t encryption_size = EbmlElementSize(libwebm::kMkvContentEncKeyID,
    637                                              enc_key_id_, enc_key_id_length_);
    638   encryption_size += EbmlElementSize(libwebm::kMkvContentEncAlgo,
    639                                      static_cast<uint64>(enc_algo_));
    640 
    641   return encryption_size + aes_size;
    642 }
    643 
    644 ///////////////////////////////////////////////////////////////
    645 //
    646 // Track Class
    647 
    648 Track::Track(unsigned int* seed)
    649     : codec_id_(NULL),
    650       codec_private_(NULL),
    651       language_(NULL),
    652       max_block_additional_id_(0),
    653       name_(NULL),
    654       number_(0),
    655       type_(0),
    656       uid_(MakeUID(seed)),
    657       codec_delay_(0),
    658       seek_pre_roll_(0),
    659       default_duration_(0),
    660       codec_private_length_(0),
    661       content_encoding_entries_(NULL),
    662       content_encoding_entries_size_(0) {}
    663 
    664 Track::~Track() {
    665   delete[] codec_id_;
    666   delete[] codec_private_;
    667   delete[] language_;
    668   delete[] name_;
    669 
    670   if (content_encoding_entries_) {
    671     for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
    672       ContentEncoding* const encoding = content_encoding_entries_[i];
    673       delete encoding;
    674     }
    675     delete[] content_encoding_entries_;
    676   }
    677 }
    678 
    679 bool Track::AddContentEncoding() {
    680   const uint32_t count = content_encoding_entries_size_ + 1;
    681 
    682   ContentEncoding** const content_encoding_entries =
    683       new (std::nothrow) ContentEncoding*[count];  // NOLINT
    684   if (!content_encoding_entries)
    685     return false;
    686 
    687   ContentEncoding* const content_encoding =
    688       new (std::nothrow) ContentEncoding();  // NOLINT
    689   if (!content_encoding) {
    690     delete[] content_encoding_entries;
    691     return false;
    692   }
    693 
    694   for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
    695     content_encoding_entries[i] = content_encoding_entries_[i];
    696   }
    697 
    698   delete[] content_encoding_entries_;
    699 
    700   content_encoding_entries_ = content_encoding_entries;
    701   content_encoding_entries_[content_encoding_entries_size_] = content_encoding;
    702   content_encoding_entries_size_ = count;
    703   return true;
    704 }
    705 
    706 ContentEncoding* Track::GetContentEncodingByIndex(uint32_t index) const {
    707   if (content_encoding_entries_ == NULL)
    708     return NULL;
    709 
    710   if (index >= content_encoding_entries_size_)
    711     return NULL;
    712 
    713   return content_encoding_entries_[index];
    714 }
    715 
    716 uint64_t Track::PayloadSize() const {
    717   uint64_t size =
    718       EbmlElementSize(libwebm::kMkvTrackNumber, static_cast<uint64>(number_));
    719   size += EbmlElementSize(libwebm::kMkvTrackUID, static_cast<uint64>(uid_));
    720   size += EbmlElementSize(libwebm::kMkvTrackType, static_cast<uint64>(type_));
    721   if (codec_id_)
    722     size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_);
    723   if (codec_private_)
    724     size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_,
    725                             codec_private_length_);
    726   if (language_)
    727     size += EbmlElementSize(libwebm::kMkvLanguage, language_);
    728   if (name_)
    729     size += EbmlElementSize(libwebm::kMkvName, name_);
    730   if (max_block_additional_id_) {
    731     size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID,
    732                             static_cast<uint64>(max_block_additional_id_));
    733   }
    734   if (codec_delay_) {
    735     size += EbmlElementSize(libwebm::kMkvCodecDelay,
    736                             static_cast<uint64>(codec_delay_));
    737   }
    738   if (seek_pre_roll_) {
    739     size += EbmlElementSize(libwebm::kMkvSeekPreRoll,
    740                             static_cast<uint64>(seek_pre_roll_));
    741   }
    742   if (default_duration_) {
    743     size += EbmlElementSize(libwebm::kMkvDefaultDuration,
    744                             static_cast<uint64>(default_duration_));
    745   }
    746 
    747   if (content_encoding_entries_size_ > 0) {
    748     uint64_t content_encodings_size = 0;
    749     for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
    750       ContentEncoding* const encoding = content_encoding_entries_[i];
    751       content_encodings_size += encoding->Size();
    752     }
    753 
    754     size += EbmlMasterElementSize(libwebm::kMkvContentEncodings,
    755                                   content_encodings_size) +
    756             content_encodings_size;
    757   }
    758 
    759   return size;
    760 }
    761 
    762 uint64_t Track::Size() const {
    763   uint64_t size = PayloadSize();
    764   size += EbmlMasterElementSize(libwebm::kMkvTrackEntry, size);
    765   return size;
    766 }
    767 
    768 bool Track::Write(IMkvWriter* writer) const {
    769   if (!writer)
    770     return false;
    771 
    772   // mandatory elements without a default value.
    773   if (!type_ || !codec_id_)
    774     return false;
    775 
    776   // AV1 tracks require a CodecPrivate. See
    777   // https://github.com/Matroska-Org/matroska-specification/blob/av1-mappin/codec/av1.md
    778   // TODO(tomfinegan): Update the above link to the AV1 Matroska mappings to
    779   // point to a stable version once it is finalized, or our own WebM mappings
    780   // page on webmproject.org should we decide to release them.
    781   if (!strcmp(codec_id_, Tracks::kAv1CodecId) && !codec_private_)
    782     return false;
    783 
    784   // |size| may be bigger than what is written out in this function because
    785   // derived classes may write out more data in the Track element.
    786   const uint64_t payload_size = PayloadSize();
    787 
    788   if (!WriteEbmlMasterElement(writer, libwebm::kMkvTrackEntry, payload_size))
    789     return false;
    790 
    791   uint64_t size =
    792       EbmlElementSize(libwebm::kMkvTrackNumber, static_cast<uint64>(number_));
    793   size += EbmlElementSize(libwebm::kMkvTrackUID, static_cast<uint64>(uid_));
    794   size += EbmlElementSize(libwebm::kMkvTrackType, static_cast<uint64>(type_));
    795   if (codec_id_)
    796     size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_);
    797   if (codec_private_)
    798     size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_,
    799                             static_cast<uint64>(codec_private_length_));
    800   if (language_)
    801     size += EbmlElementSize(libwebm::kMkvLanguage, language_);
    802   if (name_)
    803     size += EbmlElementSize(libwebm::kMkvName, name_);
    804   if (max_block_additional_id_)
    805     size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID,
    806                             static_cast<uint64>(max_block_additional_id_));
    807   if (codec_delay_)
    808     size += EbmlElementSize(libwebm::kMkvCodecDelay,
    809                             static_cast<uint64>(codec_delay_));
    810   if (seek_pre_roll_)
    811     size += EbmlElementSize(libwebm::kMkvSeekPreRoll,
    812                             static_cast<uint64>(seek_pre_roll_));
    813   if (default_duration_)
    814     size += EbmlElementSize(libwebm::kMkvDefaultDuration,
    815                             static_cast<uint64>(default_duration_));
    816 
    817   const int64_t payload_position = writer->Position();
    818   if (payload_position < 0)
    819     return false;
    820 
    821   if (!WriteEbmlElement(writer, libwebm::kMkvTrackNumber,
    822                         static_cast<uint64>(number_)))
    823     return false;
    824   if (!WriteEbmlElement(writer, libwebm::kMkvTrackUID,
    825                         static_cast<uint64>(uid_)))
    826     return false;
    827   if (!WriteEbmlElement(writer, libwebm::kMkvTrackType,
    828                         static_cast<uint64>(type_)))
    829     return false;
    830   if (max_block_additional_id_) {
    831     if (!WriteEbmlElement(writer, libwebm::kMkvMaxBlockAdditionID,
    832                           static_cast<uint64>(max_block_additional_id_))) {
    833       return false;
    834     }
    835   }
    836   if (codec_delay_) {
    837     if (!WriteEbmlElement(writer, libwebm::kMkvCodecDelay,
    838                           static_cast<uint64>(codec_delay_)))
    839       return false;
    840   }
    841   if (seek_pre_roll_) {
    842     if (!WriteEbmlElement(writer, libwebm::kMkvSeekPreRoll,
    843                           static_cast<uint64>(seek_pre_roll_)))
    844       return false;
    845   }
    846   if (default_duration_) {
    847     if (!WriteEbmlElement(writer, libwebm::kMkvDefaultDuration,
    848                           static_cast<uint64>(default_duration_)))
    849       return false;
    850   }
    851   if (codec_id_) {
    852     if (!WriteEbmlElement(writer, libwebm::kMkvCodecID, codec_id_))
    853       return false;
    854   }
    855   if (codec_private_) {
    856     if (!WriteEbmlElement(writer, libwebm::kMkvCodecPrivate, codec_private_,
    857                           static_cast<uint64>(codec_private_length_)))
    858       return false;
    859   }
    860   if (language_) {
    861     if (!WriteEbmlElement(writer, libwebm::kMkvLanguage, language_))
    862       return false;
    863   }
    864   if (name_) {
    865     if (!WriteEbmlElement(writer, libwebm::kMkvName, name_))
    866       return false;
    867   }
    868 
    869   int64_t stop_position = writer->Position();
    870   if (stop_position < 0 ||
    871       stop_position - payload_position != static_cast<int64_t>(size))
    872     return false;
    873 
    874   if (content_encoding_entries_size_ > 0) {
    875     uint64_t content_encodings_size = 0;
    876     for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
    877       ContentEncoding* const encoding = content_encoding_entries_[i];
    878       content_encodings_size += encoding->Size();
    879     }
    880 
    881     if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncodings,
    882                                 content_encodings_size))
    883       return false;
    884 
    885     for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
    886       ContentEncoding* const encoding = content_encoding_entries_[i];
    887       if (!encoding->Write(writer))
    888         return false;
    889     }
    890   }
    891 
    892   stop_position = writer->Position();
    893   if (stop_position < 0)
    894     return false;
    895   return true;
    896 }
    897 
    898 bool Track::SetCodecPrivate(const uint8_t* codec_private, uint64_t length) {
    899   if (!codec_private || length < 1)
    900     return false;
    901 
    902   delete[] codec_private_;
    903 
    904   codec_private_ =
    905       new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
    906   if (!codec_private_)
    907     return false;
    908 
    909   memcpy(codec_private_, codec_private, static_cast<size_t>(length));
    910   codec_private_length_ = length;
    911 
    912   return true;
    913 }
    914 
    915 void Track::set_codec_id(const char* codec_id) {
    916   if (codec_id) {
    917     delete[] codec_id_;
    918 
    919     const size_t length = strlen(codec_id) + 1;
    920     codec_id_ = new (std::nothrow) char[length];  // NOLINT
    921     if (codec_id_) {
    922 #ifdef _MSC_VER
    923       strcpy_s(codec_id_, length, codec_id);
    924 #else
    925       strcpy(codec_id_, codec_id);
    926 #endif
    927     }
    928   }
    929 }
    930 
    931 // TODO(fgalligan): Vet the language parameter.
    932 void Track::set_language(const char* language) {
    933   if (language) {
    934     delete[] language_;
    935 
    936     const size_t length = strlen(language) + 1;
    937     language_ = new (std::nothrow) char[length];  // NOLINT
    938     if (language_) {
    939 #ifdef _MSC_VER
    940       strcpy_s(language_, length, language);
    941 #else
    942       strcpy(language_, language);
    943 #endif
    944     }
    945   }
    946 }
    947 
    948 void Track::set_name(const char* name) {
    949   if (name) {
    950     delete[] name_;
    951 
    952     const size_t length = strlen(name) + 1;
    953     name_ = new (std::nothrow) char[length];  // NOLINT
    954     if (name_) {
    955 #ifdef _MSC_VER
    956       strcpy_s(name_, length, name);
    957 #else
    958       strcpy(name_, name);
    959 #endif
    960     }
    961   }
    962 }
    963 
    964 ///////////////////////////////////////////////////////////////
    965 //
    966 // Colour and its child elements
    967 
    968 uint64_t PrimaryChromaticity::PrimaryChromaticitySize(
    969     libwebm::MkvId x_id, libwebm::MkvId y_id) const {
    970   return EbmlElementSize(x_id, x_) + EbmlElementSize(y_id, y_);
    971 }
    972 
    973 bool PrimaryChromaticity::Write(IMkvWriter* writer, libwebm::MkvId x_id,
    974                                 libwebm::MkvId y_id) const {
    975   if (!Valid()) {
    976     return false;
    977   }
    978   return WriteEbmlElement(writer, x_id, x_) &&
    979          WriteEbmlElement(writer, y_id, y_);
    980 }
    981 
    982 bool PrimaryChromaticity::Valid() const {
    983   return (x_ >= kChromaticityMin && x_ <= kChromaticityMax &&
    984           y_ >= kChromaticityMin && y_ <= kChromaticityMax);
    985 }
    986 
    987 uint64_t MasteringMetadata::MasteringMetadataSize() const {
    988   uint64_t size = PayloadSize();
    989 
    990   if (size > 0)
    991     size += EbmlMasterElementSize(libwebm::kMkvMasteringMetadata, size);
    992 
    993   return size;
    994 }
    995 
    996 bool MasteringMetadata::Valid() const {
    997   if (luminance_min_ != kValueNotPresent) {
    998     if (luminance_min_ < kMinLuminance || luminance_min_ > kMinLuminanceMax ||
    999         luminance_min_ > luminance_max_) {
   1000       return false;
   1001     }
   1002   }
   1003   if (luminance_max_ != kValueNotPresent) {
   1004     if (luminance_max_ < kMinLuminance || luminance_max_ > kMaxLuminanceMax ||
   1005         luminance_max_ < luminance_min_) {
   1006       return false;
   1007     }
   1008   }
   1009   if (r_ && !r_->Valid())
   1010     return false;
   1011   if (g_ && !g_->Valid())
   1012     return false;
   1013   if (b_ && !b_->Valid())
   1014     return false;
   1015   if (white_point_ && !white_point_->Valid())
   1016     return false;
   1017 
   1018   return true;
   1019 }
   1020 
   1021 bool MasteringMetadata::Write(IMkvWriter* writer) const {
   1022   const uint64_t size = PayloadSize();
   1023 
   1024   // Don't write an empty element.
   1025   if (size == 0)
   1026     return true;
   1027 
   1028   if (!WriteEbmlMasterElement(writer, libwebm::kMkvMasteringMetadata, size))
   1029     return false;
   1030   if (luminance_max_ != kValueNotPresent &&
   1031       !WriteEbmlElement(writer, libwebm::kMkvLuminanceMax, luminance_max_)) {
   1032     return false;
   1033   }
   1034   if (luminance_min_ != kValueNotPresent &&
   1035       !WriteEbmlElement(writer, libwebm::kMkvLuminanceMin, luminance_min_)) {
   1036     return false;
   1037   }
   1038   if (r_ && !r_->Write(writer, libwebm::kMkvPrimaryRChromaticityX,
   1039                        libwebm::kMkvPrimaryRChromaticityY)) {
   1040     return false;
   1041   }
   1042   if (g_ && !g_->Write(writer, libwebm::kMkvPrimaryGChromaticityX,
   1043                        libwebm::kMkvPrimaryGChromaticityY)) {
   1044     return false;
   1045   }
   1046   if (b_ && !b_->Write(writer, libwebm::kMkvPrimaryBChromaticityX,
   1047                        libwebm::kMkvPrimaryBChromaticityY)) {
   1048     return false;
   1049   }
   1050   if (white_point_ &&
   1051       !white_point_->Write(writer, libwebm::kMkvWhitePointChromaticityX,
   1052                            libwebm::kMkvWhitePointChromaticityY)) {
   1053     return false;
   1054   }
   1055 
   1056   return true;
   1057 }
   1058 
   1059 bool MasteringMetadata::SetChromaticity(
   1060     const PrimaryChromaticity* r, const PrimaryChromaticity* g,
   1061     const PrimaryChromaticity* b, const PrimaryChromaticity* white_point) {
   1062   PrimaryChromaticityPtr r_ptr(nullptr);
   1063   if (r) {
   1064     if (!CopyChromaticity(r, &r_ptr))
   1065       return false;
   1066   }
   1067   PrimaryChromaticityPtr g_ptr(nullptr);
   1068   if (g) {
   1069     if (!CopyChromaticity(g, &g_ptr))
   1070       return false;
   1071   }
   1072   PrimaryChromaticityPtr b_ptr(nullptr);
   1073   if (b) {
   1074     if (!CopyChromaticity(b, &b_ptr))
   1075       return false;
   1076   }
   1077   PrimaryChromaticityPtr wp_ptr(nullptr);
   1078   if (white_point) {
   1079     if (!CopyChromaticity(white_point, &wp_ptr))
   1080       return false;
   1081   }
   1082 
   1083   r_ = r_ptr.release();
   1084   g_ = g_ptr.release();
   1085   b_ = b_ptr.release();
   1086   white_point_ = wp_ptr.release();
   1087   return true;
   1088 }
   1089 
   1090 uint64_t MasteringMetadata::PayloadSize() const {
   1091   uint64_t size = 0;
   1092 
   1093   if (luminance_max_ != kValueNotPresent)
   1094     size += EbmlElementSize(libwebm::kMkvLuminanceMax, luminance_max_);
   1095   if (luminance_min_ != kValueNotPresent)
   1096     size += EbmlElementSize(libwebm::kMkvLuminanceMin, luminance_min_);
   1097 
   1098   if (r_) {
   1099     size += r_->PrimaryChromaticitySize(libwebm::kMkvPrimaryRChromaticityX,
   1100                                         libwebm::kMkvPrimaryRChromaticityY);
   1101   }
   1102   if (g_) {
   1103     size += g_->PrimaryChromaticitySize(libwebm::kMkvPrimaryGChromaticityX,
   1104                                         libwebm::kMkvPrimaryGChromaticityY);
   1105   }
   1106   if (b_) {
   1107     size += b_->PrimaryChromaticitySize(libwebm::kMkvPrimaryBChromaticityX,
   1108                                         libwebm::kMkvPrimaryBChromaticityY);
   1109   }
   1110   if (white_point_) {
   1111     size += white_point_->PrimaryChromaticitySize(
   1112         libwebm::kMkvWhitePointChromaticityX,
   1113         libwebm::kMkvWhitePointChromaticityY);
   1114   }
   1115 
   1116   return size;
   1117 }
   1118 
   1119 uint64_t Colour::ColourSize() const {
   1120   uint64_t size = PayloadSize();
   1121 
   1122   if (size > 0)
   1123     size += EbmlMasterElementSize(libwebm::kMkvColour, size);
   1124 
   1125   return size;
   1126 }
   1127 
   1128 bool Colour::Valid() const {
   1129   if (mastering_metadata_ && !mastering_metadata_->Valid())
   1130     return false;
   1131   if (matrix_coefficients_ != kValueNotPresent &&
   1132       !IsMatrixCoefficientsValueValid(matrix_coefficients_)) {
   1133     return false;
   1134   }
   1135   if (chroma_siting_horz_ != kValueNotPresent &&
   1136       !IsChromaSitingHorzValueValid(chroma_siting_horz_)) {
   1137     return false;
   1138   }
   1139   if (chroma_siting_vert_ != kValueNotPresent &&
   1140       !IsChromaSitingVertValueValid(chroma_siting_vert_)) {
   1141     return false;
   1142   }
   1143   if (range_ != kValueNotPresent && !IsColourRangeValueValid(range_))
   1144     return false;
   1145   if (transfer_characteristics_ != kValueNotPresent &&
   1146       !IsTransferCharacteristicsValueValid(transfer_characteristics_)) {
   1147     return false;
   1148   }
   1149   if (primaries_ != kValueNotPresent && !IsPrimariesValueValid(primaries_))
   1150     return false;
   1151 
   1152   return true;
   1153 }
   1154 
   1155 bool Colour::Write(IMkvWriter* writer) const {
   1156   const uint64_t size = PayloadSize();
   1157 
   1158   // Don't write an empty element.
   1159   if (size == 0)
   1160     return true;
   1161 
   1162   // Don't write an invalid element.
   1163   if (!Valid())
   1164     return false;
   1165 
   1166   if (!WriteEbmlMasterElement(writer, libwebm::kMkvColour, size))
   1167     return false;
   1168 
   1169   if (matrix_coefficients_ != kValueNotPresent &&
   1170       !WriteEbmlElement(writer, libwebm::kMkvMatrixCoefficients,
   1171                         static_cast<uint64>(matrix_coefficients_))) {
   1172     return false;
   1173   }
   1174   if (bits_per_channel_ != kValueNotPresent &&
   1175       !WriteEbmlElement(writer, libwebm::kMkvBitsPerChannel,
   1176                         static_cast<uint64>(bits_per_channel_))) {
   1177     return false;
   1178   }
   1179   if (chroma_subsampling_horz_ != kValueNotPresent &&
   1180       !WriteEbmlElement(writer, libwebm::kMkvChromaSubsamplingHorz,
   1181                         static_cast<uint64>(chroma_subsampling_horz_))) {
   1182     return false;
   1183   }
   1184   if (chroma_subsampling_vert_ != kValueNotPresent &&
   1185       !WriteEbmlElement(writer, libwebm::kMkvChromaSubsamplingVert,
   1186                         static_cast<uint64>(chroma_subsampling_vert_))) {
   1187     return false;
   1188   }
   1189 
   1190   if (cb_subsampling_horz_ != kValueNotPresent &&
   1191       !WriteEbmlElement(writer, libwebm::kMkvCbSubsamplingHorz,
   1192                         static_cast<uint64>(cb_subsampling_horz_))) {
   1193     return false;
   1194   }
   1195   if (cb_subsampling_vert_ != kValueNotPresent &&
   1196       !WriteEbmlElement(writer, libwebm::kMkvCbSubsamplingVert,
   1197                         static_cast<uint64>(cb_subsampling_vert_))) {
   1198     return false;
   1199   }
   1200   if (chroma_siting_horz_ != kValueNotPresent &&
   1201       !WriteEbmlElement(writer, libwebm::kMkvChromaSitingHorz,
   1202                         static_cast<uint64>(chroma_siting_horz_))) {
   1203     return false;
   1204   }
   1205   if (chroma_siting_vert_ != kValueNotPresent &&
   1206       !WriteEbmlElement(writer, libwebm::kMkvChromaSitingVert,
   1207                         static_cast<uint64>(chroma_siting_vert_))) {
   1208     return false;
   1209   }
   1210   if (range_ != kValueNotPresent &&
   1211       !WriteEbmlElement(writer, libwebm::kMkvRange,
   1212                         static_cast<uint64>(range_))) {
   1213     return false;
   1214   }
   1215   if (transfer_characteristics_ != kValueNotPresent &&
   1216       !WriteEbmlElement(writer, libwebm::kMkvTransferCharacteristics,
   1217                         static_cast<uint64>(transfer_characteristics_))) {
   1218     return false;
   1219   }
   1220   if (primaries_ != kValueNotPresent &&
   1221       !WriteEbmlElement(writer, libwebm::kMkvPrimaries,
   1222                         static_cast<uint64>(primaries_))) {
   1223     return false;
   1224   }
   1225   if (max_cll_ != kValueNotPresent &&
   1226       !WriteEbmlElement(writer, libwebm::kMkvMaxCLL,
   1227                         static_cast<uint64>(max_cll_))) {
   1228     return false;
   1229   }
   1230   if (max_fall_ != kValueNotPresent &&
   1231       !WriteEbmlElement(writer, libwebm::kMkvMaxFALL,
   1232                         static_cast<uint64>(max_fall_))) {
   1233     return false;
   1234   }
   1235 
   1236   if (mastering_metadata_ && !mastering_metadata_->Write(writer))
   1237     return false;
   1238 
   1239   return true;
   1240 }
   1241 
   1242 bool Colour::SetMasteringMetadata(const MasteringMetadata& mastering_metadata) {
   1243   std::unique_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
   1244   if (!mm_ptr.get())
   1245     return false;
   1246 
   1247   mm_ptr->set_luminance_max(mastering_metadata.luminance_max());
   1248   mm_ptr->set_luminance_min(mastering_metadata.luminance_min());
   1249 
   1250   if (!mm_ptr->SetChromaticity(mastering_metadata.r(), mastering_metadata.g(),
   1251                                mastering_metadata.b(),
   1252                                mastering_metadata.white_point())) {
   1253     return false;
   1254   }
   1255 
   1256   delete mastering_metadata_;
   1257   mastering_metadata_ = mm_ptr.release();
   1258   return true;
   1259 }
   1260 
   1261 uint64_t Colour::PayloadSize() const {
   1262   uint64_t size = 0;
   1263 
   1264   if (matrix_coefficients_ != kValueNotPresent) {
   1265     size += EbmlElementSize(libwebm::kMkvMatrixCoefficients,
   1266                             static_cast<uint64>(matrix_coefficients_));
   1267   }
   1268   if (bits_per_channel_ != kValueNotPresent) {
   1269     size += EbmlElementSize(libwebm::kMkvBitsPerChannel,
   1270                             static_cast<uint64>(bits_per_channel_));
   1271   }
   1272   if (chroma_subsampling_horz_ != kValueNotPresent) {
   1273     size += EbmlElementSize(libwebm::kMkvChromaSubsamplingHorz,
   1274                             static_cast<uint64>(chroma_subsampling_horz_));
   1275   }
   1276   if (chroma_subsampling_vert_ != kValueNotPresent) {
   1277     size += EbmlElementSize(libwebm::kMkvChromaSubsamplingVert,
   1278                             static_cast<uint64>(chroma_subsampling_vert_));
   1279   }
   1280   if (cb_subsampling_horz_ != kValueNotPresent) {
   1281     size += EbmlElementSize(libwebm::kMkvCbSubsamplingHorz,
   1282                             static_cast<uint64>(cb_subsampling_horz_));
   1283   }
   1284   if (cb_subsampling_vert_ != kValueNotPresent) {
   1285     size += EbmlElementSize(libwebm::kMkvCbSubsamplingVert,
   1286                             static_cast<uint64>(cb_subsampling_vert_));
   1287   }
   1288   if (chroma_siting_horz_ != kValueNotPresent) {
   1289     size += EbmlElementSize(libwebm::kMkvChromaSitingHorz,
   1290                             static_cast<uint64>(chroma_siting_horz_));
   1291   }
   1292   if (chroma_siting_vert_ != kValueNotPresent) {
   1293     size += EbmlElementSize(libwebm::kMkvChromaSitingVert,
   1294                             static_cast<uint64>(chroma_siting_vert_));
   1295   }
   1296   if (range_ != kValueNotPresent) {
   1297     size += EbmlElementSize(libwebm::kMkvRange, static_cast<uint64>(range_));
   1298   }
   1299   if (transfer_characteristics_ != kValueNotPresent) {
   1300     size += EbmlElementSize(libwebm::kMkvTransferCharacteristics,
   1301                             static_cast<uint64>(transfer_characteristics_));
   1302   }
   1303   if (primaries_ != kValueNotPresent) {
   1304     size += EbmlElementSize(libwebm::kMkvPrimaries,
   1305                             static_cast<uint64>(primaries_));
   1306   }
   1307   if (max_cll_ != kValueNotPresent) {
   1308     size += EbmlElementSize(libwebm::kMkvMaxCLL, static_cast<uint64>(max_cll_));
   1309   }
   1310   if (max_fall_ != kValueNotPresent) {
   1311     size +=
   1312         EbmlElementSize(libwebm::kMkvMaxFALL, static_cast<uint64>(max_fall_));
   1313   }
   1314 
   1315   if (mastering_metadata_)
   1316     size += mastering_metadata_->MasteringMetadataSize();
   1317 
   1318   return size;
   1319 }
   1320 
   1321 ///////////////////////////////////////////////////////////////
   1322 //
   1323 // Projection element
   1324 
   1325 uint64_t Projection::ProjectionSize() const {
   1326   uint64_t size = PayloadSize();
   1327 
   1328   if (size > 0)
   1329     size += EbmlMasterElementSize(libwebm::kMkvProjection, size);
   1330 
   1331   return size;
   1332 }
   1333 
   1334 bool Projection::Write(IMkvWriter* writer) const {
   1335   const uint64_t size = PayloadSize();
   1336 
   1337   // Don't write an empty element.
   1338   if (size == 0)
   1339     return true;
   1340 
   1341   if (!WriteEbmlMasterElement(writer, libwebm::kMkvProjection, size))
   1342     return false;
   1343 
   1344   if (!WriteEbmlElement(writer, libwebm::kMkvProjectionType,
   1345                         static_cast<uint64>(type_))) {
   1346     return false;
   1347   }
   1348 
   1349   if (private_data_length_ > 0 && private_data_ != NULL &&
   1350       !WriteEbmlElement(writer, libwebm::kMkvProjectionPrivate, private_data_,
   1351                         private_data_length_)) {
   1352     return false;
   1353   }
   1354 
   1355   if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPoseYaw, pose_yaw_))
   1356     return false;
   1357 
   1358   if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPosePitch,
   1359                         pose_pitch_)) {
   1360     return false;
   1361   }
   1362 
   1363   if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPoseRoll, pose_roll_)) {
   1364     return false;
   1365   }
   1366 
   1367   return true;
   1368 }
   1369 
   1370 bool Projection::SetProjectionPrivate(const uint8_t* data,
   1371                                       uint64_t data_length) {
   1372   if (data == NULL || data_length == 0) {
   1373     return false;
   1374   }
   1375 
   1376   if (data_length != static_cast<size_t>(data_length)) {
   1377     return false;
   1378   }
   1379 
   1380   uint8_t* new_private_data =
   1381       new (std::nothrow) uint8_t[static_cast<size_t>(data_length)];
   1382   if (new_private_data == NULL) {
   1383     return false;
   1384   }
   1385 
   1386   delete[] private_data_;
   1387   private_data_ = new_private_data;
   1388   private_data_length_ = data_length;
   1389   memcpy(private_data_, data, static_cast<size_t>(data_length));
   1390 
   1391   return true;
   1392 }
   1393 
   1394 uint64_t Projection::PayloadSize() const {
   1395   uint64_t size =
   1396       EbmlElementSize(libwebm::kMkvProjection, static_cast<uint64>(type_));
   1397 
   1398   if (private_data_length_ > 0 && private_data_ != NULL) {
   1399     size += EbmlElementSize(libwebm::kMkvProjectionPrivate, private_data_,
   1400                             private_data_length_);
   1401   }
   1402 
   1403   size += EbmlElementSize(libwebm::kMkvProjectionPoseYaw, pose_yaw_);
   1404   size += EbmlElementSize(libwebm::kMkvProjectionPosePitch, pose_pitch_);
   1405   size += EbmlElementSize(libwebm::kMkvProjectionPoseRoll, pose_roll_);
   1406 
   1407   return size;
   1408 }
   1409 
   1410 ///////////////////////////////////////////////////////////////
   1411 //
   1412 // VideoTrack Class
   1413 
   1414 VideoTrack::VideoTrack(unsigned int* seed)
   1415     : Track(seed),
   1416       display_height_(0),
   1417       display_width_(0),
   1418       pixel_height_(0),
   1419       pixel_width_(0),
   1420       crop_left_(0),
   1421       crop_right_(0),
   1422       crop_top_(0),
   1423       crop_bottom_(0),
   1424       frame_rate_(0.0),
   1425       height_(0),
   1426       stereo_mode_(0),
   1427       alpha_mode_(0),
   1428       width_(0),
   1429       colour_space_(NULL),
   1430       colour_(NULL),
   1431       projection_(NULL) {}
   1432 
   1433 VideoTrack::~VideoTrack() {
   1434   delete colour_;
   1435   delete projection_;
   1436 }
   1437 
   1438 bool VideoTrack::SetStereoMode(uint64_t stereo_mode) {
   1439   if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
   1440       stereo_mode != kTopBottomRightIsFirst &&
   1441       stereo_mode != kTopBottomLeftIsFirst &&
   1442       stereo_mode != kSideBySideRightIsFirst)
   1443     return false;
   1444 
   1445   stereo_mode_ = stereo_mode;
   1446   return true;
   1447 }
   1448 
   1449 bool VideoTrack::SetAlphaMode(uint64_t alpha_mode) {
   1450   if (alpha_mode != kNoAlpha && alpha_mode != kAlpha)
   1451     return false;
   1452 
   1453   alpha_mode_ = alpha_mode;
   1454   return true;
   1455 }
   1456 
   1457 uint64_t VideoTrack::PayloadSize() const {
   1458   const uint64_t parent_size = Track::PayloadSize();
   1459 
   1460   uint64_t size = VideoPayloadSize();
   1461   size += EbmlMasterElementSize(libwebm::kMkvVideo, size);
   1462 
   1463   return parent_size + size;
   1464 }
   1465 
   1466 bool VideoTrack::Write(IMkvWriter* writer) const {
   1467   if (!Track::Write(writer))
   1468     return false;
   1469 
   1470   const uint64_t size = VideoPayloadSize();
   1471 
   1472   if (!WriteEbmlMasterElement(writer, libwebm::kMkvVideo, size))
   1473     return false;
   1474 
   1475   const int64_t payload_position = writer->Position();
   1476   if (payload_position < 0)
   1477     return false;
   1478 
   1479   if (!WriteEbmlElement(
   1480           writer, libwebm::kMkvPixelWidth,
   1481           static_cast<uint64>((pixel_width_ > 0) ? pixel_width_ : width_)))
   1482     return false;
   1483   if (!WriteEbmlElement(
   1484           writer, libwebm::kMkvPixelHeight,
   1485           static_cast<uint64>((pixel_height_ > 0) ? pixel_height_ : height_)))
   1486     return false;
   1487   if (display_width_ > 0) {
   1488     if (!WriteEbmlElement(writer, libwebm::kMkvDisplayWidth,
   1489                           static_cast<uint64>(display_width_)))
   1490       return false;
   1491   }
   1492   if (display_height_ > 0) {
   1493     if (!WriteEbmlElement(writer, libwebm::kMkvDisplayHeight,
   1494                           static_cast<uint64>(display_height_)))
   1495       return false;
   1496   }
   1497   if (crop_left_ > 0) {
   1498     if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropLeft,
   1499                           static_cast<uint64>(crop_left_)))
   1500       return false;
   1501   }
   1502   if (crop_right_ > 0) {
   1503     if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropRight,
   1504                           static_cast<uint64>(crop_right_)))
   1505       return false;
   1506   }
   1507   if (crop_top_ > 0) {
   1508     if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropTop,
   1509                           static_cast<uint64>(crop_top_)))
   1510       return false;
   1511   }
   1512   if (crop_bottom_ > 0) {
   1513     if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropBottom,
   1514                           static_cast<uint64>(crop_bottom_)))
   1515       return false;
   1516   }
   1517   if (stereo_mode_ > kMono) {
   1518     if (!WriteEbmlElement(writer, libwebm::kMkvStereoMode,
   1519                           static_cast<uint64>(stereo_mode_)))
   1520       return false;
   1521   }
   1522   if (alpha_mode_ > kNoAlpha) {
   1523     if (!WriteEbmlElement(writer, libwebm::kMkvAlphaMode,
   1524                           static_cast<uint64>(alpha_mode_)))
   1525       return false;
   1526   }
   1527   if (colour_space_) {
   1528     if (!WriteEbmlElement(writer, libwebm::kMkvColourSpace, colour_space_))
   1529       return false;
   1530   }
   1531   if (frame_rate_ > 0.0) {
   1532     if (!WriteEbmlElement(writer, libwebm::kMkvFrameRate,
   1533                           static_cast<float>(frame_rate_))) {
   1534       return false;
   1535     }
   1536   }
   1537   if (colour_) {
   1538     if (!colour_->Write(writer))
   1539       return false;
   1540   }
   1541   if (projection_) {
   1542     if (!projection_->Write(writer))
   1543       return false;
   1544   }
   1545 
   1546   const int64_t stop_position = writer->Position();
   1547   if (stop_position < 0 ||
   1548       stop_position - payload_position != static_cast<int64_t>(size)) {
   1549     return false;
   1550   }
   1551 
   1552   return true;
   1553 }
   1554 
   1555 void VideoTrack::set_colour_space(const char* colour_space) {
   1556   if (colour_space) {
   1557     delete[] colour_space_;
   1558 
   1559     const size_t length = strlen(colour_space) + 1;
   1560     colour_space_ = new (std::nothrow) char[length];  // NOLINT
   1561     if (colour_space_) {
   1562 #ifdef _MSC_VER
   1563       strcpy_s(colour_space_, length, colour_space);
   1564 #else
   1565       strcpy(colour_space_, colour_space);
   1566 #endif
   1567     }
   1568   }
   1569 }
   1570 
   1571 bool VideoTrack::SetColour(const Colour& colour) {
   1572   std::unique_ptr<Colour> colour_ptr(new Colour());
   1573   if (!colour_ptr.get())
   1574     return false;
   1575 
   1576   if (colour.mastering_metadata()) {
   1577     if (!colour_ptr->SetMasteringMetadata(*colour.mastering_metadata()))
   1578       return false;
   1579   }
   1580 
   1581   colour_ptr->set_matrix_coefficients(colour.matrix_coefficients());
   1582   colour_ptr->set_bits_per_channel(colour.bits_per_channel());
   1583   colour_ptr->set_chroma_subsampling_horz(colour.chroma_subsampling_horz());
   1584   colour_ptr->set_chroma_subsampling_vert(colour.chroma_subsampling_vert());
   1585   colour_ptr->set_cb_subsampling_horz(colour.cb_subsampling_horz());
   1586   colour_ptr->set_cb_subsampling_vert(colour.cb_subsampling_vert());
   1587   colour_ptr->set_chroma_siting_horz(colour.chroma_siting_horz());
   1588   colour_ptr->set_chroma_siting_vert(colour.chroma_siting_vert());
   1589   colour_ptr->set_range(colour.range());
   1590   colour_ptr->set_transfer_characteristics(colour.transfer_characteristics());
   1591   colour_ptr->set_primaries(colour.primaries());
   1592   colour_ptr->set_max_cll(colour.max_cll());
   1593   colour_ptr->set_max_fall(colour.max_fall());
   1594   delete colour_;
   1595   colour_ = colour_ptr.release();
   1596   return true;
   1597 }
   1598 
   1599 bool VideoTrack::SetProjection(const Projection& projection) {
   1600   std::unique_ptr<Projection> projection_ptr(new Projection());
   1601   if (!projection_ptr.get())
   1602     return false;
   1603 
   1604   if (projection.private_data()) {
   1605     if (!projection_ptr->SetProjectionPrivate(
   1606             projection.private_data(), projection.private_data_length())) {
   1607       return false;
   1608     }
   1609   }
   1610 
   1611   projection_ptr->set_type(projection.type());
   1612   projection_ptr->set_pose_yaw(projection.pose_yaw());
   1613   projection_ptr->set_pose_pitch(projection.pose_pitch());
   1614   projection_ptr->set_pose_roll(projection.pose_roll());
   1615   delete projection_;
   1616   projection_ = projection_ptr.release();
   1617   return true;
   1618 }
   1619 
   1620 uint64_t VideoTrack::VideoPayloadSize() const {
   1621   uint64_t size = EbmlElementSize(
   1622       libwebm::kMkvPixelWidth,
   1623       static_cast<uint64>((pixel_width_ > 0) ? pixel_width_ : width_));
   1624   size += EbmlElementSize(
   1625       libwebm::kMkvPixelHeight,
   1626       static_cast<uint64>((pixel_height_ > 0) ? pixel_height_ : height_));
   1627   if (display_width_ > 0)
   1628     size += EbmlElementSize(libwebm::kMkvDisplayWidth,
   1629                             static_cast<uint64>(display_width_));
   1630   if (display_height_ > 0)
   1631     size += EbmlElementSize(libwebm::kMkvDisplayHeight,
   1632                             static_cast<uint64>(display_height_));
   1633   if (crop_left_ > 0)
   1634     size += EbmlElementSize(libwebm::kMkvPixelCropLeft,
   1635                             static_cast<uint64>(crop_left_));
   1636   if (crop_right_ > 0)
   1637     size += EbmlElementSize(libwebm::kMkvPixelCropRight,
   1638                             static_cast<uint64>(crop_right_));
   1639   if (crop_top_ > 0)
   1640     size += EbmlElementSize(libwebm::kMkvPixelCropTop,
   1641                             static_cast<uint64>(crop_top_));
   1642   if (crop_bottom_ > 0)
   1643     size += EbmlElementSize(libwebm::kMkvPixelCropBottom,
   1644                             static_cast<uint64>(crop_bottom_));
   1645   if (stereo_mode_ > kMono)
   1646     size += EbmlElementSize(libwebm::kMkvStereoMode,
   1647                             static_cast<uint64>(stereo_mode_));
   1648   if (alpha_mode_ > kNoAlpha)
   1649     size += EbmlElementSize(libwebm::kMkvAlphaMode,
   1650                             static_cast<uint64>(alpha_mode_));
   1651   if (frame_rate_ > 0.0)
   1652     size += EbmlElementSize(libwebm::kMkvFrameRate,
   1653                             static_cast<float>(frame_rate_));
   1654   if (colour_space_)
   1655     size += EbmlElementSize(libwebm::kMkvColourSpace, colour_space_);
   1656   if (colour_)
   1657     size += colour_->ColourSize();
   1658   if (projection_)
   1659     size += projection_->ProjectionSize();
   1660 
   1661   return size;
   1662 }
   1663 
   1664 ///////////////////////////////////////////////////////////////
   1665 //
   1666 // AudioTrack Class
   1667 
   1668 AudioTrack::AudioTrack(unsigned int* seed)
   1669     : Track(seed), bit_depth_(0), channels_(1), sample_rate_(0.0) {}
   1670 
   1671 AudioTrack::~AudioTrack() {}
   1672 
   1673 uint64_t AudioTrack::PayloadSize() const {
   1674   const uint64_t parent_size = Track::PayloadSize();
   1675 
   1676   uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency,
   1677                                   static_cast<float>(sample_rate_));
   1678   size +=
   1679       EbmlElementSize(libwebm::kMkvChannels, static_cast<uint64>(channels_));
   1680   if (bit_depth_ > 0)
   1681     size +=
   1682         EbmlElementSize(libwebm::kMkvBitDepth, static_cast<uint64>(bit_depth_));
   1683   size += EbmlMasterElementSize(libwebm::kMkvAudio, size);
   1684 
   1685   return parent_size + size;
   1686 }
   1687 
   1688 bool AudioTrack::Write(IMkvWriter* writer) const {
   1689   if (!Track::Write(writer))
   1690     return false;
   1691 
   1692   // Calculate AudioSettings size.
   1693   uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency,
   1694                                   static_cast<float>(sample_rate_));
   1695   size +=
   1696       EbmlElementSize(libwebm::kMkvChannels, static_cast<uint64>(channels_));
   1697   if (bit_depth_ > 0)
   1698     size +=
   1699         EbmlElementSize(libwebm::kMkvBitDepth, static_cast<uint64>(bit_depth_));
   1700 
   1701   if (!WriteEbmlMasterElement(writer, libwebm::kMkvAudio, size))
   1702     return false;
   1703 
   1704   const int64_t payload_position = writer->Position();
   1705   if (payload_position < 0)
   1706     return false;
   1707 
   1708   if (!WriteEbmlElement(writer, libwebm::kMkvSamplingFrequency,
   1709                         static_cast<float>(sample_rate_)))
   1710     return false;
   1711   if (!WriteEbmlElement(writer, libwebm::kMkvChannels,
   1712                         static_cast<uint64>(channels_)))
   1713     return false;
   1714   if (bit_depth_ > 0)
   1715     if (!WriteEbmlElement(writer, libwebm::kMkvBitDepth,
   1716                           static_cast<uint64>(bit_depth_)))
   1717       return false;
   1718 
   1719   const int64_t stop_position = writer->Position();
   1720   if (stop_position < 0 ||
   1721       stop_position - payload_position != static_cast<int64_t>(size))
   1722     return false;
   1723 
   1724   return true;
   1725 }
   1726 
   1727 ///////////////////////////////////////////////////////////////
   1728 //
   1729 // Tracks Class
   1730 
   1731 const char Tracks::kOpusCodecId[] = "A_OPUS";
   1732 const char Tracks::kVorbisCodecId[] = "A_VORBIS";
   1733 const char Tracks::kAv1CodecId[] = "V_AV1";
   1734 const char Tracks::kVp8CodecId[] = "V_VP8";
   1735 const char Tracks::kVp9CodecId[] = "V_VP9";
   1736 const char Tracks::kWebVttCaptionsId[] = "D_WEBVTT/CAPTIONS";
   1737 const char Tracks::kWebVttDescriptionsId[] = "D_WEBVTT/DESCRIPTIONS";
   1738 const char Tracks::kWebVttMetadataId[] = "D_WEBVTT/METADATA";
   1739 const char Tracks::kWebVttSubtitlesId[] = "D_WEBVTT/SUBTITLES";
   1740 
   1741 Tracks::Tracks()
   1742     : track_entries_(NULL), track_entries_size_(0), wrote_tracks_(false) {}
   1743 
   1744 Tracks::~Tracks() {
   1745   if (track_entries_) {
   1746     for (uint32_t i = 0; i < track_entries_size_; ++i) {
   1747       Track* const track = track_entries_[i];
   1748       delete track;
   1749     }
   1750     delete[] track_entries_;
   1751   }
   1752 }
   1753 
   1754 bool Tracks::AddTrack(Track* track, int32_t number) {
   1755   if (number < 0 || wrote_tracks_)
   1756     return false;
   1757 
   1758   // This muxer only supports track numbers in the range [1, 126], in
   1759   // order to be able (to use Matroska integer representation) to
   1760   // serialize the block header (of which the track number is a part)
   1761   // for a frame using exactly 4 bytes.
   1762 
   1763   if (number > 0x7E)
   1764     return false;
   1765 
   1766   uint32_t track_num = number;
   1767 
   1768   if (track_num > 0) {
   1769     // Check to make sure a track does not already have |track_num|.
   1770     for (uint32_t i = 0; i < track_entries_size_; ++i) {
   1771       if (track_entries_[i]->number() == track_num)
   1772         return false;
   1773     }
   1774   }
   1775 
   1776   const uint32_t count = track_entries_size_ + 1;
   1777 
   1778   Track** const track_entries = new (std::nothrow) Track*[count];  // NOLINT
   1779   if (!track_entries)
   1780     return false;
   1781 
   1782   for (uint32_t i = 0; i < track_entries_size_; ++i) {
   1783     track_entries[i] = track_entries_[i];
   1784   }
   1785 
   1786   delete[] track_entries_;
   1787 
   1788   // Find the lowest availible track number > 0.
   1789   if (track_num == 0) {
   1790     track_num = count;
   1791 
   1792     // Check to make sure a track does not already have |track_num|.
   1793     bool exit = false;
   1794     do {
   1795       exit = true;
   1796       for (uint32_t i = 0; i < track_entries_size_; ++i) {
   1797         if (track_entries[i]->number() == track_num) {
   1798           track_num++;
   1799           exit = false;
   1800           break;
   1801         }
   1802       }
   1803     } while (!exit);
   1804   }
   1805   track->set_number(track_num);
   1806 
   1807   track_entries_ = track_entries;
   1808   track_entries_[track_entries_size_] = track;
   1809   track_entries_size_ = count;
   1810   return true;
   1811 }
   1812 
   1813 const Track* Tracks::GetTrackByIndex(uint32_t index) const {
   1814   if (track_entries_ == NULL)
   1815     return NULL;
   1816 
   1817   if (index >= track_entries_size_)
   1818     return NULL;
   1819 
   1820   return track_entries_[index];
   1821 }
   1822 
   1823 Track* Tracks::GetTrackByNumber(uint64_t track_number) const {
   1824   const int32_t count = track_entries_size();
   1825   for (int32_t i = 0; i < count; ++i) {
   1826     if (track_entries_[i]->number() == track_number)
   1827       return track_entries_[i];
   1828   }
   1829 
   1830   return NULL;
   1831 }
   1832 
   1833 bool Tracks::TrackIsAudio(uint64_t track_number) const {
   1834   const Track* const track = GetTrackByNumber(track_number);
   1835 
   1836   if (track->type() == kAudio)
   1837     return true;
   1838 
   1839   return false;
   1840 }
   1841 
   1842 bool Tracks::TrackIsVideo(uint64_t track_number) const {
   1843   const Track* const track = GetTrackByNumber(track_number);
   1844 
   1845   if (track->type() == kVideo)
   1846     return true;
   1847 
   1848   return false;
   1849 }
   1850 
   1851 bool Tracks::Write(IMkvWriter* writer) const {
   1852   uint64_t size = 0;
   1853   const int32_t count = track_entries_size();
   1854   for (int32_t i = 0; i < count; ++i) {
   1855     const Track* const track = GetTrackByIndex(i);
   1856 
   1857     if (!track)
   1858       return false;
   1859 
   1860     size += track->Size();
   1861   }
   1862 
   1863   if (!WriteEbmlMasterElement(writer, libwebm::kMkvTracks, size))
   1864     return false;
   1865 
   1866   const int64_t payload_position = writer->Position();
   1867   if (payload_position < 0)
   1868     return false;
   1869 
   1870   for (int32_t i = 0; i < count; ++i) {
   1871     const Track* const track = GetTrackByIndex(i);
   1872     if (!track->Write(writer))
   1873       return false;
   1874   }
   1875 
   1876   const int64_t stop_position = writer->Position();
   1877   if (stop_position < 0 ||
   1878       stop_position - payload_position != static_cast<int64_t>(size))
   1879     return false;
   1880 
   1881   wrote_tracks_ = true;
   1882   return true;
   1883 }
   1884 
   1885 ///////////////////////////////////////////////////////////////
   1886 //
   1887 // Chapter Class
   1888 
   1889 bool Chapter::set_id(const char* id) { return StrCpy(id, &id_); }
   1890 
   1891 void Chapter::set_time(const Segment& segment, uint64_t start_ns,
   1892                        uint64_t end_ns) {
   1893   const SegmentInfo* const info = segment.GetSegmentInfo();
   1894   const uint64_t timecode_scale = info->timecode_scale();
   1895   start_timecode_ = start_ns / timecode_scale;
   1896   end_timecode_ = end_ns / timecode_scale;
   1897 }
   1898 
   1899 bool Chapter::add_string(const char* title, const char* language,
   1900                          const char* country) {
   1901   if (!ExpandDisplaysArray())
   1902     return false;
   1903 
   1904   Display& d = displays_[displays_count_++];
   1905   d.Init();
   1906 
   1907   if (!d.set_title(title))
   1908     return false;
   1909 
   1910   if (!d.set_language(language))
   1911     return false;
   1912 
   1913   if (!d.set_country(country))
   1914     return false;
   1915 
   1916   return true;
   1917 }
   1918 
   1919 Chapter::Chapter() {
   1920   // This ctor only constructs the object.  Proper initialization is
   1921   // done in Init() (called in Chapters::AddChapter()).  The only
   1922   // reason we bother implementing this ctor is because we had to
   1923   // declare it as private (along with the dtor), in order to prevent
   1924   // clients from creating Chapter instances (a privelege we grant
   1925   // only to the Chapters class).  Doing no initialization here also
   1926   // means that creating arrays of chapter objects is more efficient,
   1927   // because we only initialize each new chapter object as it becomes
   1928   // active on the array.
   1929 }
   1930 
   1931 Chapter::~Chapter() {}
   1932 
   1933 void Chapter::Init(unsigned int* seed) {
   1934   id_ = NULL;
   1935   start_timecode_ = 0;
   1936   end_timecode_ = 0;
   1937   displays_ = NULL;
   1938   displays_size_ = 0;
   1939   displays_count_ = 0;
   1940   uid_ = MakeUID(seed);
   1941 }
   1942 
   1943 void Chapter::ShallowCopy(Chapter* dst) const {
   1944   dst->id_ = id_;
   1945   dst->start_timecode_ = start_timecode_;
   1946   dst->end_timecode_ = end_timecode_;
   1947   dst->uid_ = uid_;
   1948   dst->displays_ = displays_;
   1949   dst->displays_size_ = displays_size_;
   1950   dst->displays_count_ = displays_count_;
   1951 }
   1952 
   1953 void Chapter::Clear() {
   1954   StrCpy(NULL, &id_);
   1955 
   1956   while (displays_count_ > 0) {
   1957     Display& d = displays_[--displays_count_];
   1958     d.Clear();
   1959   }
   1960 
   1961   delete[] displays_;
   1962   displays_ = NULL;
   1963 
   1964   displays_size_ = 0;
   1965 }
   1966 
   1967 bool Chapter::ExpandDisplaysArray() {
   1968   if (displays_size_ > displays_count_)
   1969     return true;  // nothing to do yet
   1970 
   1971   const int size = (displays_size_ == 0) ? 1 : 2 * displays_size_;
   1972 
   1973   Display* const displays = new (std::nothrow) Display[size];  // NOLINT
   1974   if (displays == NULL)
   1975     return false;
   1976 
   1977   for (int idx = 0; idx < displays_count_; ++idx) {
   1978     displays[idx] = displays_[idx];  // shallow copy
   1979   }
   1980 
   1981   delete[] displays_;
   1982 
   1983   displays_ = displays;
   1984   displays_size_ = size;
   1985 
   1986   return true;
   1987 }
   1988 
   1989 uint64_t Chapter::WriteAtom(IMkvWriter* writer) const {
   1990   uint64_t payload_size =
   1991       EbmlElementSize(libwebm::kMkvChapterStringUID, id_) +
   1992       EbmlElementSize(libwebm::kMkvChapterUID, static_cast<uint64>(uid_)) +
   1993       EbmlElementSize(libwebm::kMkvChapterTimeStart,
   1994                       static_cast<uint64>(start_timecode_)) +
   1995       EbmlElementSize(libwebm::kMkvChapterTimeEnd,
   1996                       static_cast<uint64>(end_timecode_));
   1997 
   1998   for (int idx = 0; idx < displays_count_; ++idx) {
   1999     const Display& d = displays_[idx];
   2000     payload_size += d.WriteDisplay(NULL);
   2001   }
   2002 
   2003   const uint64_t atom_size =
   2004       EbmlMasterElementSize(libwebm::kMkvChapterAtom, payload_size) +
   2005       payload_size;
   2006 
   2007   if (writer == NULL)
   2008     return atom_size;
   2009 
   2010   const int64_t start = writer->Position();
   2011 
   2012   if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapterAtom, payload_size))
   2013     return 0;
   2014 
   2015   if (!WriteEbmlElement(writer, libwebm::kMkvChapterStringUID, id_))
   2016     return 0;
   2017 
   2018   if (!WriteEbmlElement(writer, libwebm::kMkvChapterUID,
   2019                         static_cast<uint64>(uid_)))
   2020     return 0;
   2021 
   2022   if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeStart,
   2023                         static_cast<uint64>(start_timecode_)))
   2024     return 0;
   2025 
   2026   if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeEnd,
   2027                         static_cast<uint64>(end_timecode_)))
   2028     return 0;
   2029 
   2030   for (int idx = 0; idx < displays_count_; ++idx) {
   2031     const Display& d = displays_[idx];
   2032 
   2033     if (!d.WriteDisplay(writer))
   2034       return 0;
   2035   }
   2036 
   2037   const int64_t stop = writer->Position();
   2038 
   2039   if (stop >= start && uint64_t(stop - start) != atom_size)
   2040     return 0;
   2041 
   2042   return atom_size;
   2043 }
   2044 
   2045 void Chapter::Display::Init() {
   2046   title_ = NULL;
   2047   language_ = NULL;
   2048   country_ = NULL;
   2049 }
   2050 
   2051 void Chapter::Display::Clear() {
   2052   StrCpy(NULL, &title_);
   2053   StrCpy(NULL, &language_);
   2054   StrCpy(NULL, &country_);
   2055 }
   2056 
   2057 bool Chapter::Display::set_title(const char* title) {
   2058   return StrCpy(title, &title_);
   2059 }
   2060 
   2061 bool Chapter::Display::set_language(const char* language) {
   2062   return StrCpy(language, &language_);
   2063 }
   2064 
   2065 bool Chapter::Display::set_country(const char* country) {
   2066   return StrCpy(country, &country_);
   2067 }
   2068 
   2069 uint64_t Chapter::Display::WriteDisplay(IMkvWriter* writer) const {
   2070   uint64_t payload_size = EbmlElementSize(libwebm::kMkvChapString, title_);
   2071 
   2072   if (language_)
   2073     payload_size += EbmlElementSize(libwebm::kMkvChapLanguage, language_);
   2074 
   2075   if (country_)
   2076     payload_size += EbmlElementSize(libwebm::kMkvChapCountry, country_);
   2077 
   2078   const uint64_t display_size =
   2079       EbmlMasterElementSize(libwebm::kMkvChapterDisplay, payload_size) +
   2080       payload_size;
   2081 
   2082   if (writer == NULL)
   2083     return display_size;
   2084 
   2085   const int64_t start = writer->Position();
   2086 
   2087   if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapterDisplay,
   2088                               payload_size))
   2089     return 0;
   2090 
   2091   if (!WriteEbmlElement(writer, libwebm::kMkvChapString, title_))
   2092     return 0;
   2093 
   2094   if (language_) {
   2095     if (!WriteEbmlElement(writer, libwebm::kMkvChapLanguage, language_))
   2096       return 0;
   2097   }
   2098 
   2099   if (country_) {
   2100     if (!WriteEbmlElement(writer, libwebm::kMkvChapCountry, country_))
   2101       return 0;
   2102   }
   2103 
   2104   const int64_t stop = writer->Position();
   2105 
   2106   if (stop >= start && uint64_t(stop - start) != display_size)
   2107     return 0;
   2108 
   2109   return display_size;
   2110 }
   2111 
   2112 ///////////////////////////////////////////////////////////////
   2113 //
   2114 // Chapters Class
   2115 
   2116 Chapters::Chapters() : chapters_size_(0), chapters_count_(0), chapters_(NULL) {}
   2117 
   2118 Chapters::~Chapters() {
   2119   while (chapters_count_ > 0) {
   2120     Chapter& chapter = chapters_[--chapters_count_];
   2121     chapter.Clear();
   2122   }
   2123 
   2124   delete[] chapters_;
   2125   chapters_ = NULL;
   2126 }
   2127 
   2128 int Chapters::Count() const { return chapters_count_; }
   2129 
   2130 Chapter* Chapters::AddChapter(unsigned int* seed) {
   2131   if (!ExpandChaptersArray())
   2132     return NULL;
   2133 
   2134   Chapter& chapter = chapters_[chapters_count_++];
   2135   chapter.Init(seed);
   2136 
   2137   return &chapter;
   2138 }
   2139 
   2140 bool Chapters::Write(IMkvWriter* writer) const {
   2141   if (writer == NULL)
   2142     return false;
   2143 
   2144   const uint64_t payload_size = WriteEdition(NULL);  // return size only
   2145 
   2146   if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapters, payload_size))
   2147     return false;
   2148 
   2149   const int64_t start = writer->Position();
   2150 
   2151   if (WriteEdition(writer) == 0)  // error
   2152     return false;
   2153 
   2154   const int64_t stop = writer->Position();
   2155 
   2156   if (stop >= start && uint64_t(stop - start) != payload_size)
   2157     return false;
   2158 
   2159   return true;
   2160 }
   2161 
   2162 bool Chapters::ExpandChaptersArray() {
   2163   if (chapters_size_ > chapters_count_)
   2164     return true;  // nothing to do yet
   2165 
   2166   const int size = (chapters_size_ == 0) ? 1 : 2 * chapters_size_;
   2167 
   2168   Chapter* const chapters = new (std::nothrow) Chapter[size];  // NOLINT
   2169   if (chapters == NULL)
   2170     return false;
   2171 
   2172   for (int idx = 0; idx < chapters_count_; ++idx) {
   2173     const Chapter& src = chapters_[idx];
   2174     Chapter* const dst = chapters + idx;
   2175     src.ShallowCopy(dst);
   2176   }
   2177 
   2178   delete[] chapters_;
   2179 
   2180   chapters_ = chapters;
   2181   chapters_size_ = size;
   2182 
   2183   return true;
   2184 }
   2185 
   2186 uint64_t Chapters::WriteEdition(IMkvWriter* writer) const {
   2187   uint64_t payload_size = 0;
   2188 
   2189   for (int idx = 0; idx < chapters_count_; ++idx) {
   2190     const Chapter& chapter = chapters_[idx];
   2191     payload_size += chapter.WriteAtom(NULL);
   2192   }
   2193 
   2194   const uint64_t edition_size =
   2195       EbmlMasterElementSize(libwebm::kMkvEditionEntry, payload_size) +
   2196       payload_size;
   2197 
   2198   if (writer == NULL)  // return size only
   2199     return edition_size;
   2200 
   2201   const int64_t start = writer->Position();
   2202 
   2203   if (!WriteEbmlMasterElement(writer, libwebm::kMkvEditionEntry, payload_size))
   2204     return 0;  // error
   2205 
   2206   for (int idx = 0; idx < chapters_count_; ++idx) {
   2207     const Chapter& chapter = chapters_[idx];
   2208 
   2209     const uint64_t chapter_size = chapter.WriteAtom(writer);
   2210     if (chapter_size == 0)  // error
   2211       return 0;
   2212   }
   2213 
   2214   const int64_t stop = writer->Position();
   2215 
   2216   if (stop >= start && uint64_t(stop - start) != edition_size)
   2217     return 0;
   2218 
   2219   return edition_size;
   2220 }
   2221 
   2222 // Tag Class
   2223 
   2224 bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) {
   2225   if (!ExpandSimpleTagsArray())
   2226     return false;
   2227 
   2228   SimpleTag& st = simple_tags_[simple_tags_count_++];
   2229   st.Init();
   2230 
   2231   if (!st.set_tag_name(tag_name))
   2232     return false;
   2233 
   2234   if (!st.set_tag_string(tag_string))
   2235     return false;
   2236 
   2237   return true;
   2238 }
   2239 
   2240 Tag::Tag() {
   2241   simple_tags_ = NULL;
   2242   simple_tags_size_ = 0;
   2243   simple_tags_count_ = 0;
   2244 }
   2245 
   2246 Tag::~Tag() {}
   2247 
   2248 void Tag::ShallowCopy(Tag* dst) const {
   2249   dst->simple_tags_ = simple_tags_;
   2250   dst->simple_tags_size_ = simple_tags_size_;
   2251   dst->simple_tags_count_ = simple_tags_count_;
   2252 }
   2253 
   2254 void Tag::Clear() {
   2255   while (simple_tags_count_ > 0) {
   2256     SimpleTag& st = simple_tags_[--simple_tags_count_];
   2257     st.Clear();
   2258   }
   2259 
   2260   delete[] simple_tags_;
   2261   simple_tags_ = NULL;
   2262 
   2263   simple_tags_size_ = 0;
   2264 }
   2265 
   2266 bool Tag::ExpandSimpleTagsArray() {
   2267   if (simple_tags_size_ > simple_tags_count_)
   2268     return true;  // nothing to do yet
   2269 
   2270   const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_;
   2271 
   2272   SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size];  // NOLINT
   2273   if (simple_tags == NULL)
   2274     return false;
   2275 
   2276   for (int idx = 0; idx < simple_tags_count_; ++idx) {
   2277     simple_tags[idx] = simple_tags_[idx];  // shallow copy
   2278   }
   2279 
   2280   delete[] simple_tags_;
   2281 
   2282   simple_tags_ = simple_tags;
   2283   simple_tags_size_ = size;
   2284 
   2285   return true;
   2286 }
   2287 
   2288 uint64_t Tag::Write(IMkvWriter* writer) const {
   2289   uint64_t payload_size = 0;
   2290 
   2291   for (int idx = 0; idx < simple_tags_count_; ++idx) {
   2292     const SimpleTag& st = simple_tags_[idx];
   2293     payload_size += st.Write(NULL);
   2294   }
   2295 
   2296   const uint64_t tag_size =
   2297       EbmlMasterElementSize(libwebm::kMkvTag, payload_size) + payload_size;
   2298 
   2299   if (writer == NULL)
   2300     return tag_size;
   2301 
   2302   const int64_t start = writer->Position();
   2303 
   2304   if (!WriteEbmlMasterElement(writer, libwebm::kMkvTag, payload_size))
   2305     return 0;
   2306 
   2307   for (int idx = 0; idx < simple_tags_count_; ++idx) {
   2308     const SimpleTag& st = simple_tags_[idx];
   2309 
   2310     if (!st.Write(writer))
   2311       return 0;
   2312   }
   2313 
   2314   const int64_t stop = writer->Position();
   2315 
   2316   if (stop >= start && uint64_t(stop - start) != tag_size)
   2317     return 0;
   2318 
   2319   return tag_size;
   2320 }
   2321 
   2322 // Tag::SimpleTag
   2323 
   2324 void Tag::SimpleTag::Init() {
   2325   tag_name_ = NULL;
   2326   tag_string_ = NULL;
   2327 }
   2328 
   2329 void Tag::SimpleTag::Clear() {
   2330   StrCpy(NULL, &tag_name_);
   2331   StrCpy(NULL, &tag_string_);
   2332 }
   2333 
   2334 bool Tag::SimpleTag::set_tag_name(const char* tag_name) {
   2335   return StrCpy(tag_name, &tag_name_);
   2336 }
   2337 
   2338 bool Tag::SimpleTag::set_tag_string(const char* tag_string) {
   2339   return StrCpy(tag_string, &tag_string_);
   2340 }
   2341 
   2342 uint64_t Tag::SimpleTag::Write(IMkvWriter* writer) const {
   2343   uint64_t payload_size = EbmlElementSize(libwebm::kMkvTagName, tag_name_);
   2344 
   2345   payload_size += EbmlElementSize(libwebm::kMkvTagString, tag_string_);
   2346 
   2347   const uint64_t simple_tag_size =
   2348       EbmlMasterElementSize(libwebm::kMkvSimpleTag, payload_size) +
   2349       payload_size;
   2350 
   2351   if (writer == NULL)
   2352     return simple_tag_size;
   2353 
   2354   const int64_t start = writer->Position();
   2355 
   2356   if (!WriteEbmlMasterElement(writer, libwebm::kMkvSimpleTag, payload_size))
   2357     return 0;
   2358 
   2359   if (!WriteEbmlElement(writer, libwebm::kMkvTagName, tag_name_))
   2360     return 0;
   2361 
   2362   if (!WriteEbmlElement(writer, libwebm::kMkvTagString, tag_string_))
   2363     return 0;
   2364 
   2365   const int64_t stop = writer->Position();
   2366 
   2367   if (stop >= start && uint64_t(stop - start) != simple_tag_size)
   2368     return 0;
   2369 
   2370   return simple_tag_size;
   2371 }
   2372 
   2373 // Tags Class
   2374 
   2375 Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {}
   2376 
   2377 Tags::~Tags() {
   2378   while (tags_count_ > 0) {
   2379     Tag& tag = tags_[--tags_count_];
   2380     tag.Clear();
   2381   }
   2382 
   2383   delete[] tags_;
   2384   tags_ = NULL;
   2385 }
   2386 
   2387 int Tags::Count() const { return tags_count_; }
   2388 
   2389 Tag* Tags::AddTag() {
   2390   if (!ExpandTagsArray())
   2391     return NULL;
   2392 
   2393   Tag& tag = tags_[tags_count_++];
   2394 
   2395   return &tag;
   2396 }
   2397 
   2398 bool Tags::Write(IMkvWriter* writer) const {
   2399   if (writer == NULL)
   2400     return false;
   2401 
   2402   uint64_t payload_size = 0;
   2403 
   2404   for (int idx = 0; idx < tags_count_; ++idx) {
   2405     const Tag& tag = tags_[idx];
   2406     payload_size += tag.Write(NULL);
   2407   }
   2408 
   2409   if (!WriteEbmlMasterElement(writer, libwebm::kMkvTags, payload_size))
   2410     return false;
   2411 
   2412   const int64_t start = writer->Position();
   2413 
   2414   for (int idx = 0; idx < tags_count_; ++idx) {
   2415     const Tag& tag = tags_[idx];
   2416 
   2417     const uint64_t tag_size = tag.Write(writer);
   2418     if (tag_size == 0)  // error
   2419       return 0;
   2420   }
   2421 
   2422   const int64_t stop = writer->Position();
   2423 
   2424   if (stop >= start && uint64_t(stop - start) != payload_size)
   2425     return false;
   2426 
   2427   return true;
   2428 }
   2429 
   2430 bool Tags::ExpandTagsArray() {
   2431   if (tags_size_ > tags_count_)
   2432     return true;  // nothing to do yet
   2433 
   2434   const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_;
   2435 
   2436   Tag* const tags = new (std::nothrow) Tag[size];  // NOLINT
   2437   if (tags == NULL)
   2438     return false;
   2439 
   2440   for (int idx = 0; idx < tags_count_; ++idx) {
   2441     const Tag& src = tags_[idx];
   2442     Tag* const dst = tags + idx;
   2443     src.ShallowCopy(dst);
   2444   }
   2445 
   2446   delete[] tags_;
   2447 
   2448   tags_ = tags;
   2449   tags_size_ = size;
   2450 
   2451   return true;
   2452 }
   2453 
   2454 ///////////////////////////////////////////////////////////////
   2455 //
   2456 // Cluster class
   2457 
   2458 Cluster::Cluster(uint64_t timecode, int64_t cues_pos, uint64_t timecode_scale,
   2459                  bool write_last_frame_with_duration, bool fixed_size_timecode)
   2460     : blocks_added_(0),
   2461       finalized_(false),
   2462       fixed_size_timecode_(fixed_size_timecode),
   2463       header_written_(false),
   2464       payload_size_(0),
   2465       position_for_cues_(cues_pos),
   2466       size_position_(-1),
   2467       timecode_(timecode),
   2468       timecode_scale_(timecode_scale),
   2469       write_last_frame_with_duration_(write_last_frame_with_duration),
   2470       writer_(NULL) {}
   2471 
   2472 Cluster::~Cluster() {
   2473   // Delete any stored frames that are left behind. This will happen if the
   2474   // Cluster was not Finalized for whatever reason.
   2475   while (!stored_frames_.empty()) {
   2476     while (!stored_frames_.begin()->second.empty()) {
   2477       delete stored_frames_.begin()->second.front();
   2478       stored_frames_.begin()->second.pop_front();
   2479     }
   2480     stored_frames_.erase(stored_frames_.begin()->first);
   2481   }
   2482 }
   2483 
   2484 bool Cluster::Init(IMkvWriter* ptr_writer) {
   2485   if (!ptr_writer) {
   2486     return false;
   2487   }
   2488   writer_ = ptr_writer;
   2489   return true;
   2490 }
   2491 
   2492 bool Cluster::AddFrame(const Frame* const frame) {
   2493   return QueueOrWriteFrame(frame);
   2494 }
   2495 
   2496 bool Cluster::AddFrame(const uint8_t* data, uint64_t length,
   2497                        uint64_t track_number, uint64_t abs_timecode,
   2498                        bool is_key) {
   2499   Frame frame;
   2500   if (!frame.Init(data, length))
   2501     return false;
   2502   frame.set_track_number(track_number);
   2503   frame.set_timestamp(abs_timecode);
   2504   frame.set_is_key(is_key);
   2505   return QueueOrWriteFrame(&frame);
   2506 }
   2507 
   2508 bool Cluster::AddFrameWithAdditional(const uint8_t* data, uint64_t length,
   2509                                      const uint8_t* additional,
   2510                                      uint64_t additional_length,
   2511                                      uint64_t add_id, uint64_t track_number,
   2512                                      uint64_t abs_timecode, bool is_key) {
   2513   if (!additional || additional_length == 0) {
   2514     return false;
   2515   }
   2516   Frame frame;
   2517   if (!frame.Init(data, length) ||
   2518       !frame.AddAdditionalData(additional, additional_length, add_id)) {
   2519     return false;
   2520   }
   2521   frame.set_track_number(track_number);
   2522   frame.set_timestamp(abs_timecode);
   2523   frame.set_is_key(is_key);
   2524   return QueueOrWriteFrame(&frame);
   2525 }
   2526 
   2527 bool Cluster::AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
   2528                                          int64_t discard_padding,
   2529                                          uint64_t track_number,
   2530                                          uint64_t abs_timecode, bool is_key) {
   2531   Frame frame;
   2532   if (!frame.Init(data, length))
   2533     return false;
   2534   frame.set_discard_padding(discard_padding);
   2535   frame.set_track_number(track_number);
   2536   frame.set_timestamp(abs_timecode);
   2537   frame.set_is_key(is_key);
   2538   return QueueOrWriteFrame(&frame);
   2539 }
   2540 
   2541 bool Cluster::AddMetadata(const uint8_t* data, uint64_t length,
   2542                           uint64_t track_number, uint64_t abs_timecode,
   2543                           uint64_t duration_timecode) {
   2544   Frame frame;
   2545   if (!frame.Init(data, length))
   2546     return false;
   2547   frame.set_track_number(track_number);
   2548   frame.set_timestamp(abs_timecode);
   2549   frame.set_duration(duration_timecode);
   2550   frame.set_is_key(true);  // All metadata blocks are keyframes.
   2551   return QueueOrWriteFrame(&frame);
   2552 }
   2553 
   2554 void Cluster::AddPayloadSize(uint64_t size) { payload_size_ += size; }
   2555 
   2556 bool Cluster::Finalize() {
   2557   return !write_last_frame_with_duration_ && Finalize(false, 0);
   2558 }
   2559 
   2560 bool Cluster::Finalize(bool set_last_frame_duration, uint64_t duration) {
   2561   if (!writer_ || finalized_)
   2562     return false;
   2563 
   2564   if (write_last_frame_with_duration_) {
   2565     // Write out held back Frames. This essentially performs a k-way merge
   2566     // across all tracks in the increasing order of timestamps.
   2567     while (!stored_frames_.empty()) {
   2568       Frame* frame = stored_frames_.begin()->second.front();
   2569 
   2570       // Get the next frame to write (frame with least timestamp across all
   2571       // tracks).
   2572       for (FrameMapIterator frames_iterator = ++stored_frames_.begin();
   2573            frames_iterator != stored_frames_.end(); ++frames_iterator) {
   2574         if (frames_iterator->second.front()->timestamp() < frame->timestamp()) {
   2575           frame = frames_iterator->second.front();
   2576         }
   2577       }
   2578 
   2579       // Set the duration if it's the last frame for the track.
   2580       if (set_last_frame_duration &&
   2581           stored_frames_[frame->track_number()].size() == 1 &&
   2582           !frame->duration_set()) {
   2583         frame->set_duration(duration - frame->timestamp());
   2584         if (!frame->is_key() && !frame->reference_block_timestamp_set()) {
   2585           frame->set_reference_block_timestamp(
   2586               last_block_timestamp_[frame->track_number()]);
   2587         }
   2588       }
   2589 
   2590       // Write the frame and remove it from |stored_frames_|.
   2591       const bool wrote_frame = DoWriteFrame(frame);
   2592       stored_frames_[frame->track_number()].pop_front();
   2593       if (stored_frames_[frame->track_number()].empty()) {
   2594         stored_frames_.erase(frame->track_number());
   2595       }
   2596       delete frame;
   2597       if (!wrote_frame)
   2598         return false;
   2599     }
   2600   }
   2601 
   2602   if (size_position_ == -1)
   2603     return false;
   2604 
   2605   if (writer_->Seekable()) {
   2606     const int64_t pos = writer_->Position();
   2607 
   2608     if (writer_->Position(size_position_))
   2609       return false;
   2610 
   2611     if (WriteUIntSize(writer_, payload_size(), 8))
   2612       return false;
   2613 
   2614     if (writer_->Position(pos))
   2615       return false;
   2616   }
   2617 
   2618   finalized_ = true;
   2619 
   2620   return true;
   2621 }
   2622 
   2623 uint64_t Cluster::Size() const {
   2624   const uint64_t element_size =
   2625       EbmlMasterElementSize(libwebm::kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) +
   2626       payload_size_;
   2627   return element_size;
   2628 }
   2629 
   2630 bool Cluster::PreWriteBlock() {
   2631   if (finalized_)
   2632     return false;
   2633 
   2634   if (!header_written_) {
   2635     if (!WriteClusterHeader())
   2636       return false;
   2637   }
   2638 
   2639   return true;
   2640 }
   2641 
   2642 void Cluster::PostWriteBlock(uint64_t element_size) {
   2643   AddPayloadSize(element_size);
   2644   ++blocks_added_;
   2645 }
   2646 
   2647 int64_t Cluster::GetRelativeTimecode(int64_t abs_timecode) const {
   2648   const int64_t cluster_timecode = this->Cluster::timecode();
   2649   const int64_t rel_timecode =
   2650       static_cast<int64_t>(abs_timecode) - cluster_timecode;
   2651 
   2652   if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode)
   2653     return -1;
   2654 
   2655   return rel_timecode;
   2656 }
   2657 
   2658 bool Cluster::DoWriteFrame(const Frame* const frame) {
   2659   if (!frame || !frame->IsValid())
   2660     return false;
   2661 
   2662   if (!PreWriteBlock())
   2663     return false;
   2664 
   2665   const uint64_t element_size = WriteFrame(writer_, frame, this);
   2666   if (element_size == 0)
   2667     return false;
   2668 
   2669   PostWriteBlock(element_size);
   2670   last_block_timestamp_[frame->track_number()] = frame->timestamp();
   2671   return true;
   2672 }
   2673 
   2674 bool Cluster::QueueOrWriteFrame(const Frame* const frame) {
   2675   if (!frame || !frame->IsValid())
   2676     return false;
   2677 
   2678   // If |write_last_frame_with_duration_| is not set, then write the frame right
   2679   // away.
   2680   if (!write_last_frame_with_duration_) {
   2681     return DoWriteFrame(frame);
   2682   }
   2683 
   2684   // Queue the current frame.
   2685   uint64_t track_number = frame->track_number();
   2686   Frame* const frame_to_store = new Frame();
   2687   frame_to_store->CopyFrom(*frame);
   2688   stored_frames_[track_number].push_back(frame_to_store);
   2689 
   2690   // Iterate through all queued frames in the current track except the last one
   2691   // and write it if it is okay to do so (i.e.) no other track has an held back
   2692   // frame with timestamp <= the timestamp of the frame in question.
   2693   std::vector<std::list<Frame*>::iterator> frames_to_erase;
   2694   for (std::list<Frame*>::iterator
   2695            current_track_iterator = stored_frames_[track_number].begin(),
   2696            end = --stored_frames_[track_number].end();
   2697        current_track_iterator != end; ++current_track_iterator) {
   2698     const Frame* const frame_to_write = *current_track_iterator;
   2699     bool okay_to_write = true;
   2700     for (FrameMapIterator track_iterator = stored_frames_.begin();
   2701          track_iterator != stored_frames_.end(); ++track_iterator) {
   2702       if (track_iterator->first == track_number) {
   2703         continue;
   2704       }
   2705       if (track_iterator->second.front()->timestamp() <
   2706           frame_to_write->timestamp()) {
   2707         okay_to_write = false;
   2708         break;
   2709       }
   2710     }
   2711     if (okay_to_write) {
   2712       const bool wrote_frame = DoWriteFrame(frame_to_write);
   2713       delete frame_to_write;
   2714       if (!wrote_frame)
   2715         return false;
   2716       frames_to_erase.push_back(current_track_iterator);
   2717     } else {
   2718       break;
   2719     }
   2720   }
   2721   for (std::vector<std::list<Frame*>::iterator>::iterator iterator =
   2722            frames_to_erase.begin();
   2723        iterator != frames_to_erase.end(); ++iterator) {
   2724     stored_frames_[track_number].erase(*iterator);
   2725   }
   2726   return true;
   2727 }
   2728 
   2729 bool Cluster::WriteClusterHeader() {
   2730   if (finalized_)
   2731     return false;
   2732 
   2733   if (WriteID(writer_, libwebm::kMkvCluster))
   2734     return false;
   2735 
   2736   // Save for later.
   2737   size_position_ = writer_->Position();
   2738 
   2739   // Write "unknown" (EBML coded -1) as cluster size value. We need to write 8
   2740   // bytes because we do not know how big our cluster will be.
   2741   if (SerializeInt(writer_, kEbmlUnknownValue, 8))
   2742     return false;
   2743 
   2744   if (!WriteEbmlElement(writer_, libwebm::kMkvTimecode, timecode(),
   2745                         fixed_size_timecode_ ? 8 : 0)) {
   2746     return false;
   2747   }
   2748   AddPayloadSize(EbmlElementSize(libwebm::kMkvTimecode, timecode(),
   2749                                  fixed_size_timecode_ ? 8 : 0));
   2750   header_written_ = true;
   2751 
   2752   return true;
   2753 }
   2754 
   2755 ///////////////////////////////////////////////////////////////
   2756 //
   2757 // SeekHead Class
   2758 
   2759 SeekHead::SeekHead() : start_pos_(0ULL) {
   2760   for (int32_t i = 0; i < kSeekEntryCount; ++i) {
   2761     seek_entry_id_[i] = 0;
   2762     seek_entry_pos_[i] = 0;
   2763   }
   2764 }
   2765 
   2766 SeekHead::~SeekHead() {}
   2767 
   2768 bool SeekHead::Finalize(IMkvWriter* writer) const {
   2769   if (writer->Seekable()) {
   2770     if (start_pos_ == -1)
   2771       return false;
   2772 
   2773     uint64_t payload_size = 0;
   2774     uint64_t entry_size[kSeekEntryCount];
   2775 
   2776     for (int32_t i = 0; i < kSeekEntryCount; ++i) {
   2777       if (seek_entry_id_[i] != 0) {
   2778         entry_size[i] = EbmlElementSize(libwebm::kMkvSeekID,
   2779                                         static_cast<uint64>(seek_entry_id_[i]));
   2780         entry_size[i] += EbmlElementSize(
   2781             libwebm::kMkvSeekPosition, static_cast<uint64>(seek_entry_pos_[i]));
   2782 
   2783         payload_size +=
   2784             EbmlMasterElementSize(libwebm::kMkvSeek, entry_size[i]) +
   2785             entry_size[i];
   2786       }
   2787     }
   2788 
   2789     // No SeekHead elements
   2790     if (payload_size == 0)
   2791       return true;
   2792 
   2793     const int64_t pos = writer->Position();
   2794     if (writer->Position(start_pos_))
   2795       return false;
   2796 
   2797     if (!WriteEbmlMasterElement(writer, libwebm::kMkvSeekHead, payload_size))
   2798       return false;
   2799 
   2800     for (int32_t i = 0; i < kSeekEntryCount; ++i) {
   2801       if (seek_entry_id_[i] != 0) {
   2802         if (!WriteEbmlMasterElement(writer, libwebm::kMkvSeek, entry_size[i]))
   2803           return false;
   2804 
   2805         if (!WriteEbmlElement(writer, libwebm::kMkvSeekID,
   2806                               static_cast<uint64>(seek_entry_id_[i])))
   2807           return false;
   2808 
   2809         if (!WriteEbmlElement(writer, libwebm::kMkvSeekPosition,
   2810                               static_cast<uint64>(seek_entry_pos_[i])))
   2811           return false;
   2812       }
   2813     }
   2814 
   2815     const uint64_t total_entry_size = kSeekEntryCount * MaxEntrySize();
   2816     const uint64_t total_size =
   2817         EbmlMasterElementSize(libwebm::kMkvSeekHead, total_entry_size) +
   2818         total_entry_size;
   2819     const int64_t size_left = total_size - (writer->Position() - start_pos_);
   2820 
   2821     const uint64_t bytes_written = WriteVoidElement(writer, size_left);
   2822     if (!bytes_written)
   2823       return false;
   2824 
   2825     if (writer->Position(pos))
   2826       return false;
   2827   }
   2828 
   2829   return true;
   2830 }
   2831 
   2832 bool SeekHead::Write(IMkvWriter* writer) {
   2833   const uint64_t entry_size = kSeekEntryCount * MaxEntrySize();
   2834   const uint64_t size =
   2835       EbmlMasterElementSize(libwebm::kMkvSeekHead, entry_size);
   2836 
   2837   start_pos_ = writer->Position();
   2838 
   2839   const uint64_t bytes_written = WriteVoidElement(writer, size + entry_size);
   2840   if (!bytes_written)
   2841     return false;
   2842 
   2843   return true;
   2844 }
   2845 
   2846 bool SeekHead::AddSeekEntry(uint32_t id, uint64_t pos) {
   2847   for (int32_t i = 0; i < kSeekEntryCount; ++i) {
   2848     if (seek_entry_id_[i] == 0) {
   2849       seek_entry_id_[i] = id;
   2850       seek_entry_pos_[i] = pos;
   2851       return true;
   2852     }
   2853   }
   2854   return false;
   2855 }
   2856 
   2857 uint32_t SeekHead::GetId(int index) const {
   2858   if (index < 0 || index >= kSeekEntryCount)
   2859     return UINT_MAX;
   2860   return seek_entry_id_[index];
   2861 }
   2862 
   2863 uint64_t SeekHead::GetPosition(int index) const {
   2864   if (index < 0 || index >= kSeekEntryCount)
   2865     return ULLONG_MAX;
   2866   return seek_entry_pos_[index];
   2867 }
   2868 
   2869 bool SeekHead::SetSeekEntry(int index, uint32_t id, uint64_t position) {
   2870   if (index < 0 || index >= kSeekEntryCount)
   2871     return false;
   2872   seek_entry_id_[index] = id;
   2873   seek_entry_pos_[index] = position;
   2874   return true;
   2875 }
   2876 
   2877 uint64_t SeekHead::MaxEntrySize() const {
   2878   const uint64_t max_entry_payload_size =
   2879       EbmlElementSize(libwebm::kMkvSeekID,
   2880                       static_cast<uint64>(UINT64_C(0xffffffff))) +
   2881       EbmlElementSize(libwebm::kMkvSeekPosition,
   2882                       static_cast<uint64>(UINT64_C(0xffffffffffffffff)));
   2883   const uint64_t max_entry_size =
   2884       EbmlMasterElementSize(libwebm::kMkvSeek, max_entry_payload_size) +
   2885       max_entry_payload_size;
   2886 
   2887   return max_entry_size;
   2888 }
   2889 
   2890 ///////////////////////////////////////////////////////////////
   2891 //
   2892 // SegmentInfo Class
   2893 
   2894 SegmentInfo::SegmentInfo()
   2895     : duration_(-1.0),
   2896       muxing_app_(NULL),
   2897       timecode_scale_(1000000ULL),
   2898       writing_app_(NULL),
   2899       date_utc_(LLONG_MIN),
   2900       duration_pos_(-1) {}
   2901 
   2902 SegmentInfo::~SegmentInfo() {
   2903   delete[] muxing_app_;
   2904   delete[] writing_app_;
   2905 }
   2906 
   2907 bool SegmentInfo::Init() {
   2908   int32_t major;
   2909   int32_t minor;
   2910   int32_t build;
   2911   int32_t revision;
   2912   GetVersion(&major, &minor, &build, &revision);
   2913   char temp[256];
   2914 #ifdef _MSC_VER
   2915   sprintf_s(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
   2916             minor, build, revision);
   2917 #else
   2918   snprintf(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
   2919            minor, build, revision);
   2920 #endif
   2921 
   2922   const size_t app_len = strlen(temp) + 1;
   2923 
   2924   delete[] muxing_app_;
   2925 
   2926   muxing_app_ = new (std::nothrow) char[app_len];  // NOLINT
   2927   if (!muxing_app_)
   2928     return false;
   2929 
   2930 #ifdef _MSC_VER
   2931   strcpy_s(muxing_app_, app_len, temp);
   2932 #else
   2933   strcpy(muxing_app_, temp);
   2934 #endif
   2935 
   2936   set_writing_app(temp);
   2937   if (!writing_app_)
   2938     return false;
   2939   return true;
   2940 }
   2941 
   2942 bool SegmentInfo::Finalize(IMkvWriter* writer) const {
   2943   if (!writer)
   2944     return false;
   2945 
   2946   if (duration_ > 0.0) {
   2947     if (writer->Seekable()) {
   2948       if (duration_pos_ == -1)
   2949         return false;
   2950 
   2951       const int64_t pos = writer->Position();
   2952 
   2953       if (writer->Position(duration_pos_))
   2954         return false;
   2955 
   2956       if (!WriteEbmlElement(writer, libwebm::kMkvDuration,
   2957                             static_cast<float>(duration_)))
   2958         return false;
   2959 
   2960       if (writer->Position(pos))
   2961         return false;
   2962     }
   2963   }
   2964 
   2965   return true;
   2966 }
   2967 
   2968 bool SegmentInfo::Write(IMkvWriter* writer) {
   2969   if (!writer || !muxing_app_ || !writing_app_)
   2970     return false;
   2971 
   2972   uint64_t size = EbmlElementSize(libwebm::kMkvTimecodeScale,
   2973                                   static_cast<uint64>(timecode_scale_));
   2974   if (duration_ > 0.0)
   2975     size +=
   2976         EbmlElementSize(libwebm::kMkvDuration, static_cast<float>(duration_));
   2977   if (date_utc_ != LLONG_MIN)
   2978     size += EbmlDateElementSize(libwebm::kMkvDateUTC);
   2979   size += EbmlElementSize(libwebm::kMkvMuxingApp, muxing_app_);
   2980   size += EbmlElementSize(libwebm::kMkvWritingApp, writing_app_);
   2981 
   2982   if (!WriteEbmlMasterElement(writer, libwebm::kMkvInfo, size))
   2983     return false;
   2984 
   2985   const int64_t payload_position = writer->Position();
   2986   if (payload_position < 0)
   2987     return false;
   2988 
   2989   if (!WriteEbmlElement(writer, libwebm::kMkvTimecodeScale,
   2990                         static_cast<uint64>(timecode_scale_)))
   2991     return false;
   2992 
   2993   if (duration_ > 0.0) {
   2994     // Save for later
   2995     duration_pos_ = writer->Position();
   2996 
   2997     if (!WriteEbmlElement(writer, libwebm::kMkvDuration,
   2998                           static_cast<float>(duration_)))
   2999       return false;
   3000   }
   3001 
   3002   if (date_utc_ != LLONG_MIN)
   3003     WriteEbmlDateElement(writer, libwebm::kMkvDateUTC, date_utc_);
   3004 
   3005   if (!WriteEbmlElement(writer, libwebm::kMkvMuxingApp, muxing_app_))
   3006     return false;
   3007   if (!WriteEbmlElement(writer, libwebm::kMkvWritingApp, writing_app_))
   3008     return false;
   3009 
   3010   const int64_t stop_position = writer->Position();
   3011   if (stop_position < 0 ||
   3012       stop_position - payload_position != static_cast<int64_t>(size))
   3013     return false;
   3014 
   3015   return true;
   3016 }
   3017 
   3018 void SegmentInfo::set_muxing_app(const char* app) {
   3019   if (app) {
   3020     const size_t length = strlen(app) + 1;
   3021     char* temp_str = new (std::nothrow) char[length];  // NOLINT
   3022     if (!temp_str)
   3023       return;
   3024 
   3025 #ifdef _MSC_VER
   3026     strcpy_s(temp_str, length, app);
   3027 #else
   3028     strcpy(temp_str, app);
   3029 #endif
   3030 
   3031     delete[] muxing_app_;
   3032     muxing_app_ = temp_str;
   3033   }
   3034 }
   3035 
   3036 void SegmentInfo::set_writing_app(const char* app) {
   3037   if (app) {
   3038     const size_t length = strlen(app) + 1;
   3039     char* temp_str = new (std::nothrow) char[length];  // NOLINT
   3040     if (!temp_str)
   3041       return;
   3042 
   3043 #ifdef _MSC_VER
   3044     strcpy_s(temp_str, length, app);
   3045 #else
   3046     strcpy(temp_str, app);
   3047 #endif
   3048 
   3049     delete[] writing_app_;
   3050     writing_app_ = temp_str;
   3051   }
   3052 }
   3053 
   3054 ///////////////////////////////////////////////////////////////
   3055 //
   3056 // Segment Class
   3057 
   3058 Segment::Segment()
   3059     : chunk_count_(0),
   3060       chunk_name_(NULL),
   3061       chunk_writer_cluster_(NULL),
   3062       chunk_writer_cues_(NULL),
   3063       chunk_writer_header_(NULL),
   3064       chunking_(false),
   3065       chunking_base_name_(NULL),
   3066       cluster_list_(NULL),
   3067       cluster_list_capacity_(0),
   3068       cluster_list_size_(0),
   3069       cues_position_(kAfterClusters),
   3070       cues_track_(0),
   3071       force_new_cluster_(false),
   3072       frames_(NULL),
   3073       frames_capacity_(0),
   3074       frames_size_(0),
   3075       has_video_(false),
   3076       header_written_(false),
   3077       last_block_duration_(0),
   3078       last_timestamp_(0),
   3079       max_cluster_duration_(kDefaultMaxClusterDuration),
   3080       max_cluster_size_(0),
   3081       mode_(kFile),
   3082       new_cuepoint_(false),
   3083       output_cues_(true),
   3084       accurate_cluster_duration_(false),
   3085       fixed_size_cluster_timecode_(false),
   3086       estimate_file_duration_(false),
   3087       payload_pos_(0),
   3088       size_position_(0),
   3089       doc_type_version_(kDefaultDocTypeVersion),
   3090       doc_type_version_written_(0),
   3091       duration_(0.0),
   3092       writer_cluster_(NULL),
   3093       writer_cues_(NULL),
   3094       writer_header_(NULL) {
   3095   const time_t curr_time = time(NULL);
   3096   seed_ = static_cast<unsigned int>(curr_time);
   3097 #ifdef _WIN32
   3098   srand(seed_);
   3099 #endif
   3100 }
   3101 
   3102 Segment::~Segment() {
   3103   if (cluster_list_) {
   3104     for (int32_t i = 0; i < cluster_list_size_; ++i) {
   3105       Cluster* const cluster = cluster_list_[i];
   3106       delete cluster;
   3107     }
   3108     delete[] cluster_list_;
   3109   }
   3110 
   3111   if (frames_) {
   3112     for (int32_t i = 0; i < frames_size_; ++i) {
   3113       Frame* const frame = frames_[i];
   3114       delete frame;
   3115     }
   3116     delete[] frames_;
   3117   }
   3118 
   3119   delete[] chunk_name_;
   3120   delete[] chunking_base_name_;
   3121 
   3122   if (chunk_writer_cluster_) {
   3123     chunk_writer_cluster_->Close();
   3124     delete chunk_writer_cluster_;
   3125   }
   3126   if (chunk_writer_cues_) {
   3127     chunk_writer_cues_->Close();
   3128     delete chunk_writer_cues_;
   3129   }
   3130   if (chunk_writer_header_) {
   3131     chunk_writer_header_->Close();
   3132     delete chunk_writer_header_;
   3133   }
   3134 }
   3135 
   3136 void Segment::MoveCuesBeforeClustersHelper(uint64_t diff, int32_t index,
   3137                                            uint64_t* cues_size) {
   3138   CuePoint* const cue_point = cues_.GetCueByIndex(index);
   3139   if (cue_point == NULL)
   3140     return;
   3141   const uint64_t old_cue_point_size = cue_point->Size();
   3142   const uint64_t cluster_pos = cue_point->cluster_pos() + diff;
   3143   cue_point->set_cluster_pos(cluster_pos);  // update the new cluster position
   3144   // New size of the cue is computed as follows
   3145   //    Let a = current sum of size of all CuePoints
   3146   //    Let b = Increase in Cue Point's size due to this iteration
   3147   //    Let c = Increase in size of Cues Element's length due to this iteration
   3148   //            (This is computed as CodedSize(a + b) - CodedSize(a))
   3149   //    Let d = b + c. Now d is the |diff| passed to the next recursive call.
   3150   //    Let e = a + b. Now e is the |cues_size| passed to the next recursive
   3151   //                   call.
   3152   const uint64_t cue_point_size_diff = cue_point->Size() - old_cue_point_size;
   3153   const uint64_t cue_size_diff =
   3154       GetCodedUIntSize(*cues_size + cue_point_size_diff) -
   3155       GetCodedUIntSize(*cues_size);
   3156   *cues_size += cue_point_size_diff;
   3157   diff = cue_size_diff + cue_point_size_diff;
   3158   if (diff > 0) {
   3159     for (int32_t i = 0; i < cues_.cue_entries_size(); ++i) {
   3160       MoveCuesBeforeClustersHelper(diff, i, cues_size);
   3161     }
   3162   }
   3163 }
   3164 
   3165 void Segment::MoveCuesBeforeClusters() {
   3166   const uint64_t current_cue_size = cues_.Size();
   3167   uint64_t cue_size = 0;
   3168   for (int32_t i = 0; i < cues_.cue_entries_size(); ++i)
   3169     cue_size += cues_.GetCueByIndex(i)->Size();
   3170   for (int32_t i = 0; i < cues_.cue_entries_size(); ++i)
   3171     MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size);
   3172 
   3173   // Adjust the Seek Entry to reflect the change in position
   3174   // of Cluster and Cues
   3175   int32_t cluster_index = 0;
   3176   int32_t cues_index = 0;
   3177   for (int32_t i = 0; i < SeekHead::kSeekEntryCount; ++i) {
   3178     if (seek_head_.GetId(i) == libwebm::kMkvCluster)
   3179       cluster_index = i;
   3180     if (seek_head_.GetId(i) == libwebm::kMkvCues)
   3181       cues_index = i;
   3182   }
   3183   seek_head_.SetSeekEntry(cues_index, libwebm::kMkvCues,
   3184                           seek_head_.GetPosition(cluster_index));
   3185   seek_head_.SetSeekEntry(cluster_index, libwebm::kMkvCluster,
   3186                           cues_.Size() + seek_head_.GetPosition(cues_index));
   3187 }
   3188 
   3189 bool Segment::Init(IMkvWriter* ptr_writer) {
   3190   if (!ptr_writer) {
   3191     return false;
   3192   }
   3193   writer_cluster_ = ptr_writer;
   3194   writer_cues_ = ptr_writer;
   3195   writer_header_ = ptr_writer;
   3196   memset(&track_frames_written_, 0,
   3197          sizeof(track_frames_written_[0]) * kMaxTrackNumber);
   3198   memset(&last_track_timestamp_, 0,
   3199          sizeof(last_track_timestamp_[0]) * kMaxTrackNumber);
   3200   return segment_info_.Init();
   3201 }
   3202 
   3203 bool Segment::CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
   3204                                             IMkvWriter* writer) {
   3205   if (!writer->Seekable() || chunking_)
   3206     return false;
   3207   const int64_t cluster_offset =
   3208       cluster_list_[0]->size_position() - GetUIntSize(libwebm::kMkvCluster);
   3209 
   3210   // Copy the headers.
   3211   if (!ChunkedCopy(reader, writer, 0, cluster_offset))
   3212     return false;
   3213 
   3214   // Recompute cue positions and seek entries.
   3215   MoveCuesBeforeClusters();
   3216 
   3217   // Write cues and seek entries.
   3218   // TODO(vigneshv): As of now, it's safe to call seek_head_.Finalize() for the
   3219   // second time with a different writer object. But the name Finalize() doesn't
   3220   // indicate something we want to call more than once. So consider renaming it
   3221   // to write() or some such.
   3222   if (!cues_.Write(writer) || !seek_head_.Finalize(writer))
   3223     return false;
   3224 
   3225   // Copy the Clusters.
   3226   if (!ChunkedCopy(reader, writer, cluster_offset,
   3227                    cluster_end_offset_ - cluster_offset))
   3228     return false;
   3229 
   3230   // Update the Segment size in case the Cues size has changed.
   3231   const int64_t pos = writer->Position();
   3232   const int64_t segment_size = writer->Position() - payload_pos_;
   3233   if (writer->Position(size_position_) ||
   3234       WriteUIntSize(writer, segment_size, 8) || writer->Position(pos))
   3235     return false;
   3236   return true;
   3237 }
   3238 
   3239 bool Segment::Finalize() {
   3240   if (WriteFramesAll() < 0)
   3241     return false;
   3242 
   3243   // In kLive mode, call Cluster::Finalize only if |accurate_cluster_duration_|
   3244   // is set. In all other modes, always call Cluster::Finalize.
   3245   if ((mode_ == kLive ? accurate_cluster_duration_ : true) &&
   3246       cluster_list_size_ > 0) {
   3247     // Update last cluster's size
   3248     Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
   3249 
   3250     // For the last frame of the last Cluster, we don't write it as a BlockGroup
   3251     // with Duration unless the frame itself has duration set explicitly.
   3252     if (!old_cluster || !old_cluster->Finalize(false, 0))
   3253       return false;
   3254   }
   3255 
   3256   if (mode_ == kFile) {
   3257     if (chunking_ && chunk_writer_cluster_) {
   3258       chunk_writer_cluster_->Close();
   3259       chunk_count_++;
   3260     }
   3261 
   3262     double duration =
   3263         (static_cast<double>(last_timestamp_) + last_block_duration_) /
   3264         segment_info_.timecode_scale();
   3265     if (duration_ > 0.0) {
   3266       duration = duration_;
   3267     } else {
   3268       if (last_block_duration_ == 0 && estimate_file_duration_) {
   3269         const int num_tracks = static_cast<int>(tracks_.track_entries_size());
   3270         for (int i = 0; i < num_tracks; ++i) {
   3271           if (track_frames_written_[i] < 2)
   3272             continue;
   3273 
   3274           // Estimate the duration for the last block of a Track.
   3275           const double nano_per_frame =
   3276               static_cast<double>(last_track_timestamp_[i]) /
   3277               (track_frames_written_[i] - 1);
   3278           const double track_duration =
   3279               (last_track_timestamp_[i] + nano_per_frame) /
   3280               segment_info_.timecode_scale();
   3281           if (track_duration > duration)
   3282             duration = track_duration;
   3283         }
   3284       }
   3285     }
   3286     segment_info_.set_duration(duration);
   3287     if (!segment_info_.Finalize(writer_header_))
   3288       return false;
   3289 
   3290     if (output_cues_)
   3291       if (!seek_head_.AddSeekEntry(libwebm::kMkvCues, MaxOffset()))
   3292         return false;
   3293 
   3294     if (chunking_) {
   3295       if (!chunk_writer_cues_)
   3296         return false;
   3297 
   3298       char* name = NULL;
   3299       if (!UpdateChunkName("cues", &name))
   3300         return false;
   3301 
   3302       const bool cues_open = chunk_writer_cues_->Open(name);
   3303       delete[] name;
   3304       if (!cues_open)
   3305         return false;
   3306     }
   3307 
   3308     cluster_end_offset_ = writer_cluster_->Position();
   3309 
   3310     // Write the seek headers and cues
   3311     if (output_cues_)
   3312       if (!cues_.Write(writer_cues_))
   3313         return false;
   3314 
   3315     if (!seek_head_.Finalize(writer_header_))
   3316       return false;
   3317 
   3318     if (writer_header_->Seekable()) {
   3319       if (size_position_ == -1)
   3320         return false;
   3321 
   3322       const int64_t segment_size = MaxOffset();
   3323       if (segment_size < 1)
   3324         return false;
   3325 
   3326       const int64_t pos = writer_header_->Position();
   3327       UpdateDocTypeVersion();
   3328       if (doc_type_version_ != doc_type_version_written_) {
   3329         if (writer_header_->Position(0))
   3330           return false;
   3331 
   3332         const char* const doc_type =
   3333             DocTypeIsWebm() ? kDocTypeWebm : kDocTypeMatroska;
   3334         if (!WriteEbmlHeader(writer_header_, doc_type_version_, doc_type))
   3335           return false;
   3336         if (writer_header_->Position() != ebml_header_size_)
   3337           return false;
   3338 
   3339         doc_type_version_written_ = doc_type_version_;
   3340       }
   3341 
   3342       if (writer_header_->Position(size_position_))
   3343         return false;
   3344 
   3345       if (WriteUIntSize(writer_header_, segment_size, 8))
   3346         return false;
   3347 
   3348       if (writer_header_->Position(pos))
   3349         return false;
   3350     }
   3351 
   3352     if (chunking_) {
   3353       // Do not close any writers until the segment size has been written,
   3354       // otherwise the size may be off.
   3355       if (!chunk_writer_cues_ || !chunk_writer_header_)
   3356         return false;
   3357 
   3358       chunk_writer_cues_->Close();
   3359       chunk_writer_header_->Close();
   3360     }
   3361   }
   3362 
   3363   return true;
   3364 }
   3365 
   3366 Track* Segment::AddTrack(int32_t number) {
   3367   Track* const track = new (std::nothrow) Track(&seed_);  // NOLINT
   3368 
   3369   if (!track)
   3370     return NULL;
   3371 
   3372   if (!tracks_.AddTrack(track, number)) {
   3373     delete track;
   3374     return NULL;
   3375   }
   3376 
   3377   return track;
   3378 }
   3379 
   3380 Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
   3381 
   3382 Tag* Segment::AddTag() { return tags_.AddTag(); }
   3383 
   3384 uint64_t Segment::AddVideoTrack(int32_t width, int32_t height, int32_t number) {
   3385   VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_);  // NOLINT
   3386   if (!track)
   3387     return 0;
   3388 
   3389   track->set_type(Tracks::kVideo);
   3390   track->set_codec_id(Tracks::kVp8CodecId);
   3391   track->set_width(width);
   3392   track->set_height(height);
   3393 
   3394   if (!tracks_.AddTrack(track, number)) {
   3395     delete track;
   3396     return 0;
   3397   }
   3398   has_video_ = true;
   3399 
   3400   return track->number();
   3401 }
   3402 
   3403 bool Segment::AddCuePoint(uint64_t timestamp, uint64_t track) {
   3404   if (cluster_list_size_ < 1)
   3405     return false;
   3406 
   3407   const Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
   3408   if (!cluster)
   3409     return false;
   3410 
   3411   CuePoint* const cue = new (std::nothrow) CuePoint();  // NOLINT
   3412   if (!cue)
   3413     return false;
   3414 
   3415   cue->set_time(timestamp / segment_info_.timecode_scale());
   3416   cue->set_block_number(cluster->blocks_added());
   3417   cue->set_cluster_pos(cluster->position_for_cues());
   3418   cue->set_track(track);
   3419   if (!cues_.AddCue(cue)) {
   3420     delete cue;
   3421     return false;
   3422   }
   3423 
   3424   new_cuepoint_ = false;
   3425   return true;
   3426 }
   3427 
   3428 uint64_t Segment::AddAudioTrack(int32_t sample_rate, int32_t channels,
   3429                                 int32_t number) {
   3430   AudioTrack* const track = new (std::nothrow) AudioTrack(&seed_);  // NOLINT
   3431   if (!track)
   3432     return 0;
   3433 
   3434   track->set_type(Tracks::kAudio);
   3435   track->set_codec_id(Tracks::kVorbisCodecId);
   3436   track->set_sample_rate(sample_rate);
   3437   track->set_channels(channels);
   3438 
   3439   if (!tracks_.AddTrack(track, number)) {
   3440     delete track;
   3441     return 0;
   3442   }
   3443 
   3444   return track->number();
   3445 }
   3446 
   3447 bool Segment::AddFrame(const uint8_t* data, uint64_t length,
   3448                        uint64_t track_number, uint64_t timestamp, bool is_key) {
   3449   if (!data)
   3450     return false;
   3451 
   3452   Frame frame;
   3453   if (!frame.Init(data, length))
   3454     return false;
   3455   frame.set_track_number(track_number);
   3456   frame.set_timestamp(timestamp);
   3457   frame.set_is_key(is_key);
   3458   return AddGenericFrame(&frame);
   3459 }
   3460 
   3461 bool Segment::AddFrameWithAdditional(const uint8_t* data, uint64_t length,
   3462                                      const uint8_t* additional,
   3463                                      uint64_t additional_length,
   3464                                      uint64_t add_id, uint64_t track_number,
   3465                                      uint64_t timestamp, bool is_key) {
   3466   if (!data || !additional)
   3467     return false;
   3468 
   3469   Frame frame;
   3470   if (!frame.Init(data, length) ||
   3471       !frame.AddAdditionalData(additional, additional_length, add_id)) {
   3472     return false;
   3473   }
   3474   frame.set_track_number(track_number);
   3475   frame.set_timestamp(timestamp);
   3476   frame.set_is_key(is_key);
   3477   return AddGenericFrame(&frame);
   3478 }
   3479 
   3480 bool Segment::AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
   3481                                          int64_t discard_padding,
   3482                                          uint64_t track_number,
   3483                                          uint64_t timestamp, bool is_key) {
   3484   if (!data)
   3485     return false;
   3486 
   3487   Frame frame;
   3488   if (!frame.Init(data, length))
   3489     return false;
   3490   frame.set_discard_padding(discard_padding);
   3491   frame.set_track_number(track_number);
   3492   frame.set_timestamp(timestamp);
   3493   frame.set_is_key(is_key);
   3494   return AddGenericFrame(&frame);
   3495 }
   3496 
   3497 bool Segment::AddMetadata(const uint8_t* data, uint64_t length,
   3498                           uint64_t track_number, uint64_t timestamp_ns,
   3499                           uint64_t duration_ns) {
   3500   if (!data)
   3501     return false;
   3502 
   3503   Frame frame;
   3504   if (!frame.Init(data, length))
   3505     return false;
   3506   frame.set_track_number(track_number);
   3507   frame.set_timestamp(timestamp_ns);
   3508   frame.set_duration(duration_ns);
   3509   frame.set_is_key(true);  // All metadata blocks are keyframes.
   3510   return AddGenericFrame(&frame);
   3511 }
   3512 
   3513 bool Segment::AddGenericFrame(const Frame* frame) {
   3514   if (!frame)
   3515     return false;
   3516 
   3517   if (!CheckHeaderInfo())
   3518     return false;
   3519 
   3520   // Check for non-monotonically increasing timestamps.
   3521   if (frame->timestamp() < last_timestamp_)
   3522     return false;
   3523 
   3524   // Check if the track number is valid.
   3525   if (!tracks_.GetTrackByNumber(frame->track_number()))
   3526     return false;
   3527 
   3528   if (frame->discard_padding() != 0)
   3529     doc_type_version_ = 4;
   3530 
   3531   if (cluster_list_size_ > 0) {
   3532     const uint64_t timecode_scale = segment_info_.timecode_scale();
   3533     const uint64_t frame_timecode = frame->timestamp() / timecode_scale;
   3534 
   3535     const Cluster* const last_cluster = cluster_list_[cluster_list_size_ - 1];
   3536     const uint64_t last_cluster_timecode = last_cluster->timecode();
   3537 
   3538     const uint64_t rel_timecode = frame_timecode - last_cluster_timecode;
   3539     if (rel_timecode > kMaxBlockTimecode) {
   3540       force_new_cluster_ = true;
   3541     }
   3542   }
   3543 
   3544   // If the segment has a video track hold onto audio frames to make sure the
   3545   // audio that is associated with the start time of a video key-frame is
   3546   // muxed into the same cluster.
   3547   if (has_video_ && tracks_.TrackIsAudio(frame->track_number()) &&
   3548       !force_new_cluster_) {
   3549     Frame* const new_frame = new (std::nothrow) Frame();
   3550     if (!new_frame || !new_frame->CopyFrom(*frame)) {
   3551       delete new_frame;
   3552       return false;
   3553     }
   3554     if (!QueueFrame(new_frame)) {
   3555       delete new_frame;
   3556       return false;
   3557     }
   3558     track_frames_written_[frame->track_number() - 1]++;
   3559     return true;
   3560   }
   3561 
   3562   if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(),
   3563                               frame->is_key())) {
   3564     return false;
   3565   }
   3566 
   3567   if (cluster_list_size_ < 1)
   3568     return false;
   3569 
   3570   Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
   3571   if (!cluster)
   3572     return false;
   3573 
   3574   // If the Frame is not a SimpleBlock, then set the reference_block_timestamp
   3575   // if it is not set already.
   3576   bool frame_created = false;
   3577   if (!frame->CanBeSimpleBlock() && !frame->is_key() &&
   3578       !frame->reference_block_timestamp_set()) {
   3579     Frame* const new_frame = new (std::nothrow) Frame();
   3580     if (!new_frame || !new_frame->CopyFrom(*frame)) {
   3581       delete new_frame;
   3582       return false;
   3583     }
   3584     new_frame->set_reference_block_timestamp(
   3585         last_track_timestamp_[frame->track_number() - 1]);
   3586     frame = new_frame;
   3587     frame_created = true;
   3588   }
   3589 
   3590   if (!cluster->AddFrame(frame))
   3591     return false;
   3592 
   3593   if (new_cuepoint_ && cues_track_ == frame->track_number()) {
   3594     if (!AddCuePoint(frame->timestamp(), cues_track_))
   3595       return false;
   3596   }
   3597 
   3598   last_timestamp_ = frame->timestamp();
   3599   last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
   3600   last_block_duration_ = frame->duration();
   3601   track_frames_written_[frame->track_number() - 1]++;
   3602 
   3603   if (frame_created)
   3604     delete frame;
   3605   return true;
   3606 }
   3607 
   3608 void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; }
   3609 
   3610 void Segment::AccurateClusterDuration(bool accurate_cluster_duration) {
   3611   accurate_cluster_duration_ = accurate_cluster_duration;
   3612 }
   3613 
   3614 void Segment::UseFixedSizeClusterTimecode(bool fixed_size_cluster_timecode) {
   3615   fixed_size_cluster_timecode_ = fixed_size_cluster_timecode;
   3616 }
   3617 
   3618 bool Segment::SetChunking(bool chunking, const char* filename) {
   3619   if (chunk_count_ > 0)
   3620     return false;
   3621 
   3622   if (chunking) {
   3623     if (!filename)
   3624       return false;
   3625 
   3626     // Check if we are being set to what is already set.
   3627     if (chunking_ && !strcmp(filename, chunking_base_name_))
   3628       return true;
   3629 
   3630     const size_t name_length = strlen(filename) + 1;
   3631     char* const temp = new (std::nothrow) char[name_length];  // NOLINT
   3632     if (!temp)
   3633       return false;
   3634 
   3635 #ifdef _MSC_VER
   3636     strcpy_s(temp, name_length, filename);
   3637 #else
   3638     strcpy(temp, filename);
   3639 #endif
   3640 
   3641     delete[] chunking_base_name_;
   3642     chunking_base_name_ = temp;
   3643 
   3644     if (!UpdateChunkName("chk", &chunk_name_))
   3645       return false;
   3646 
   3647     if (!chunk_writer_cluster_) {
   3648       chunk_writer_cluster_ = new (std::nothrow) MkvWriter();  // NOLINT
   3649       if (!chunk_writer_cluster_)
   3650         return false;
   3651     }
   3652 
   3653     if (!chunk_writer_cues_) {
   3654       chunk_writer_cues_ = new (std::nothrow) MkvWriter();  // NOLINT
   3655       if (!chunk_writer_cues_)
   3656         return false;
   3657     }
   3658 
   3659     if (!chunk_writer_header_) {
   3660       chunk_writer_header_ = new (std::nothrow) MkvWriter();  // NOLINT
   3661       if (!chunk_writer_header_)
   3662         return false;
   3663     }
   3664 
   3665     if (!chunk_writer_cluster_->Open(chunk_name_))
   3666       return false;
   3667 
   3668     const size_t header_length = strlen(filename) + strlen(".hdr") + 1;
   3669     char* const header = new (std::nothrow) char[header_length];  // NOLINT
   3670     if (!header)
   3671       return false;
   3672 
   3673 #ifdef _MSC_VER
   3674     strcpy_s(header, header_length - strlen(".hdr"), chunking_base_name_);
   3675     strcat_s(header, header_length, ".hdr");
   3676 #else
   3677     strcpy(header, chunking_base_name_);
   3678     strcat(header, ".hdr");
   3679 #endif
   3680     if (!chunk_writer_header_->Open(header)) {
   3681       delete[] header;
   3682       return false;
   3683     }
   3684 
   3685     writer_cluster_ = chunk_writer_cluster_;
   3686     writer_cues_ = chunk_writer_cues_;
   3687     writer_header_ = chunk_writer_header_;
   3688 
   3689     delete[] header;
   3690   }
   3691 
   3692   chunking_ = chunking;
   3693 
   3694   return true;
   3695 }
   3696 
   3697 bool Segment::CuesTrack(uint64_t track_number) {
   3698   const Track* const track = GetTrackByNumber(track_number);
   3699   if (!track)
   3700     return false;
   3701 
   3702   cues_track_ = track_number;
   3703   return true;
   3704 }
   3705 
   3706 void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; }
   3707 
   3708 Track* Segment::GetTrackByNumber(uint64_t track_number) const {
   3709   return tracks_.GetTrackByNumber(track_number);
   3710 }
   3711 
   3712 bool Segment::WriteSegmentHeader() {
   3713   UpdateDocTypeVersion();
   3714 
   3715   const char* const doc_type =
   3716       DocTypeIsWebm() ? kDocTypeWebm : kDocTypeMatroska;
   3717   if (!WriteEbmlHeader(writer_header_, doc_type_version_, doc_type))
   3718     return false;
   3719   doc_type_version_written_ = doc_type_version_;
   3720   ebml_header_size_ = static_cast<int32_t>(writer_header_->Position());
   3721 
   3722   // Write "unknown" (-1) as segment size value. If mode is kFile, Segment
   3723   // will write over duration when the file is finalized.
   3724   if (WriteID(writer_header_, libwebm::kMkvSegment))
   3725     return false;
   3726 
   3727   // Save for later.
   3728   size_position_ = writer_header_->Position();
   3729 
   3730   // Write "unknown" (EBML coded -1) as segment size value. We need to write 8
   3731   // bytes because if we are going to overwrite the segment size later we do
   3732   // not know how big our segment will be.
   3733   if (SerializeInt(writer_header_, kEbmlUnknownValue, 8))
   3734     return false;
   3735 
   3736   payload_pos_ = writer_header_->Position();
   3737 
   3738   if (mode_ == kFile && writer_header_->Seekable()) {
   3739     // Set the duration > 0.0 so SegmentInfo will write out the duration. When
   3740     // the muxer is done writing we will set the correct duration and have
   3741     // SegmentInfo upadte it.
   3742     segment_info_.set_duration(1.0);
   3743 
   3744     if (!seek_head_.Write(writer_header_))
   3745       return false;
   3746   }
   3747 
   3748   if (!seek_head_.AddSeekEntry(libwebm::kMkvInfo, MaxOffset()))
   3749     return false;
   3750   if (!segment_info_.Write(writer_header_))
   3751     return false;
   3752 
   3753   if (!seek_head_.AddSeekEntry(libwebm::kMkvTracks, MaxOffset()))
   3754     return false;
   3755   if (!tracks_.Write(writer_header_))
   3756     return false;
   3757 
   3758   if (chapters_.Count() > 0) {
   3759     if (!seek_head_.AddSeekEntry(libwebm::kMkvChapters, MaxOffset()))
   3760       return false;
   3761     if (!chapters_.Write(writer_header_))
   3762       return false;
   3763   }
   3764 
   3765   if (tags_.Count() > 0) {
   3766     if (!seek_head_.AddSeekEntry(libwebm::kMkvTags, MaxOffset()))
   3767       return false;
   3768     if (!tags_.Write(writer_header_))
   3769       return false;
   3770   }
   3771 
   3772   if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) {
   3773     if (!chunk_writer_header_)
   3774       return false;
   3775 
   3776     chunk_writer_header_->Close();
   3777   }
   3778 
   3779   header_written_ = true;
   3780 
   3781   return true;
   3782 }
   3783 
   3784 // Here we are testing whether to create a new cluster, given a frame
   3785 // having time frame_timestamp_ns.
   3786 //
   3787 int Segment::TestFrame(uint64_t track_number, uint64_t frame_timestamp_ns,
   3788                        bool is_key) const {
   3789   if (force_new_cluster_)
   3790     return 1;
   3791 
   3792   // If no clusters have been created yet, then create a new cluster
   3793   // and write this frame immediately, in the new cluster.  This path
   3794   // should only be followed once, the first time we attempt to write
   3795   // a frame.
   3796 
   3797   if (cluster_list_size_ <= 0)
   3798     return 1;
   3799 
   3800   // There exists at least one cluster. We must compare the frame to
   3801   // the last cluster, in order to determine whether the frame is
   3802   // written to the existing cluster, or that a new cluster should be
   3803   // created.
   3804 
   3805   const uint64_t timecode_scale = segment_info_.timecode_scale();
   3806   const uint64_t frame_timecode = frame_timestamp_ns / timecode_scale;
   3807 
   3808   const Cluster* const last_cluster = cluster_list_[cluster_list_size_ - 1];
   3809   const uint64_t last_cluster_timecode = last_cluster->timecode();
   3810 
   3811   // For completeness we test for the case when the frame's timecode
   3812   // is less than the cluster's timecode.  Although in principle that
   3813   // is allowed, this muxer doesn't actually write clusters like that,
   3814   // so this indicates a bug somewhere in our algorithm.
   3815 
   3816   if (frame_timecode < last_cluster_timecode)  // should never happen
   3817     return -1;
   3818 
   3819   // If the frame has a timestamp significantly larger than the last
   3820   // cluster (in Matroska, cluster-relative timestamps are serialized
   3821   // using a 16-bit signed integer), then we cannot write this frame
   3822   // to that cluster, and so we must create a new cluster.
   3823 
   3824   const int64_t delta_timecode = frame_timecode - last_cluster_timecode;
   3825 
   3826   if (delta_timecode > kMaxBlockTimecode)
   3827     return 2;
   3828 
   3829   // We decide to create a new cluster when we have a video keyframe.
   3830   // This will flush queued (audio) frames, and write the keyframe
   3831   // immediately, in the newly-created cluster.
   3832 
   3833   if (is_key && tracks_.TrackIsVideo(track_number))
   3834     return 1;
   3835 
   3836   // Create a new cluster if we have accumulated too many frames
   3837   // already, where "too many" is defined as "the total time of frames
   3838   // in the cluster exceeds a threshold".
   3839 
   3840   const uint64_t delta_ns = delta_timecode * timecode_scale;
   3841 
   3842   if (max_cluster_duration_ > 0 && delta_ns >= max_cluster_duration_)
   3843     return 1;
   3844 
   3845   // This is similar to the case above, with the difference that a new
   3846   // cluster is created when the size of the current cluster exceeds a
   3847   // threshold.
   3848 
   3849   const uint64_t cluster_size = last_cluster->payload_size();
   3850 
   3851   if (max_cluster_size_ > 0 && cluster_size >= max_cluster_size_)
   3852     return 1;
   3853 
   3854   // There's no need to create a new cluster, so emit this frame now.
   3855 
   3856   return 0;
   3857 }
   3858 
   3859 bool Segment::MakeNewCluster(uint64_t frame_timestamp_ns) {
   3860   const int32_t new_size = cluster_list_size_ + 1;
   3861 
   3862   if (new_size > cluster_list_capacity_) {
   3863     // Add more clusters.
   3864     const int32_t new_capacity =
   3865         (cluster_list_capacity_ <= 0) ? 1 : cluster_list_capacity_ * 2;
   3866     Cluster** const clusters =
   3867         new (std::nothrow) Cluster*[new_capacity];  // NOLINT
   3868     if (!clusters)
   3869       return false;
   3870 
   3871     for (int32_t i = 0; i < cluster_list_size_; ++i) {
   3872       clusters[i] = cluster_list_[i];
   3873     }
   3874 
   3875     delete[] cluster_list_;
   3876 
   3877     cluster_list_ = clusters;
   3878     cluster_list_capacity_ = new_capacity;
   3879   }
   3880 
   3881   if (!WriteFramesLessThan(frame_timestamp_ns))
   3882     return false;
   3883 
   3884   if (cluster_list_size_ > 0) {
   3885     // Update old cluster's size
   3886     Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
   3887 
   3888     if (!old_cluster || !old_cluster->Finalize(true, frame_timestamp_ns))
   3889       return false;
   3890   }
   3891 
   3892   if (output_cues_)
   3893     new_cuepoint_ = true;
   3894 
   3895   if (chunking_ && cluster_list_size_ > 0) {
   3896     chunk_writer_cluster_->Close();
   3897     chunk_count_++;
   3898 
   3899     if (!UpdateChunkName("chk", &chunk_name_))
   3900       return false;
   3901     if (!chunk_writer_cluster_->Open(chunk_name_))
   3902       return false;
   3903   }
   3904 
   3905   const uint64_t timecode_scale = segment_info_.timecode_scale();
   3906   const uint64_t frame_timecode = frame_timestamp_ns / timecode_scale;
   3907 
   3908   uint64_t cluster_timecode = frame_timecode;
   3909 
   3910   if (frames_size_ > 0) {
   3911     const Frame* const f = frames_[0];  // earliest queued frame
   3912     const uint64_t ns = f->timestamp();
   3913     const uint64_t tc = ns / timecode_scale;
   3914 
   3915     if (tc < cluster_timecode)
   3916       cluster_timecode = tc;
   3917   }
   3918 
   3919   Cluster*& cluster = cluster_list_[cluster_list_size_];
   3920   const int64_t offset = MaxOffset();
   3921   cluster = new (std::nothrow)
   3922       Cluster(cluster_timecode, offset, segment_info_.timecode_scale(),
   3923               accurate_cluster_duration_, fixed_size_cluster_timecode_);
   3924   if (!cluster)
   3925     return false;
   3926 
   3927   if (!cluster->Init(writer_cluster_))
   3928     return false;
   3929 
   3930   cluster_list_size_ = new_size;
   3931   return true;
   3932 }
   3933 
   3934 bool Segment::DoNewClusterProcessing(uint64_t track_number,
   3935                                      uint64_t frame_timestamp_ns, bool is_key) {
   3936   for (;;) {
   3937     // Based on the characteristics of the current frame and current
   3938     // cluster, decide whether to create a new cluster.
   3939     const int result = TestFrame(track_number, frame_timestamp_ns, is_key);
   3940     if (result < 0)  // error
   3941       return false;
   3942 
   3943     // Always set force_new_cluster_ to false after TestFrame.
   3944     force_new_cluster_ = false;
   3945 
   3946     // A non-zero result means create a new cluster.
   3947     if (result > 0 && !MakeNewCluster(frame_timestamp_ns))
   3948       return false;
   3949 
   3950     // Write queued (audio) frames.
   3951     const int frame_count = WriteFramesAll();
   3952     if (frame_count < 0)  // error
   3953       return false;
   3954 
   3955     // Write the current frame to the current cluster (if TestFrame
   3956     // returns 0) or to a newly created cluster (TestFrame returns 1).
   3957     if (result <= 1)
   3958       return true;
   3959 
   3960     // TestFrame returned 2, which means there was a large time
   3961     // difference between the cluster and the frame itself.  Do the
   3962     // test again, comparing the frame to the new cluster.
   3963   }
   3964 }
   3965 
   3966 bool Segment::CheckHeaderInfo() {
   3967   if (!header_written_) {
   3968     if (!WriteSegmentHeader())
   3969       return false;
   3970 
   3971     if (!seek_head_.AddSeekEntry(libwebm::kMkvCluster, MaxOffset()))
   3972       return false;
   3973 
   3974     if (output_cues_ && cues_track_ == 0) {
   3975       // Check for a video track
   3976       for (uint32_t i = 0; i < tracks_.track_entries_size(); ++i) {
   3977         const Track* const track = tracks_.GetTrackByIndex(i);
   3978         if (!track)
   3979           return false;
   3980 
   3981         if (tracks_.TrackIsVideo(track->number())) {
   3982           cues_track_ = track->number();
   3983           break;
   3984         }
   3985       }
   3986 
   3987       // Set first track found
   3988       if (cues_track_ == 0) {
   3989         const Track* const track = tracks_.GetTrackByIndex(0);
   3990         if (!track)
   3991           return false;
   3992 
   3993         cues_track_ = track->number();
   3994       }
   3995     }
   3996   }
   3997   return true;
   3998 }
   3999 
   4000 void Segment::UpdateDocTypeVersion() {
   4001   for (uint32_t index = 0; index < tracks_.track_entries_size(); ++index) {
   4002     const Track* track = tracks_.GetTrackByIndex(index);
   4003     if (track == NULL)
   4004       break;
   4005     if ((track->codec_delay() || track->seek_pre_roll()) &&
   4006         doc_type_version_ < 4) {
   4007       doc_type_version_ = 4;
   4008       break;
   4009     }
   4010   }
   4011 }
   4012 
   4013 bool Segment::UpdateChunkName(const char* ext, char** name) const {
   4014   if (!name || !ext)
   4015     return false;
   4016 
   4017   char ext_chk[64];
   4018 #ifdef _MSC_VER
   4019   sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
   4020 #else
   4021   snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
   4022 #endif
   4023 
   4024   const size_t length = strlen(chunking_base_name_) + strlen(ext_chk) + 1;
   4025   char* const str = new (std::nothrow) char[length];  // NOLINT
   4026   if (!str)
   4027     return false;
   4028 
   4029 #ifdef _MSC_VER
   4030   strcpy_s(str, length - strlen(ext_chk), chunking_base_name_);
   4031   strcat_s(str, length, ext_chk);
   4032 #else
   4033   strcpy(str, chunking_base_name_);
   4034   strcat(str, ext_chk);
   4035 #endif
   4036 
   4037   delete[] * name;
   4038   *name = str;
   4039 
   4040   return true;
   4041 }
   4042 
   4043 int64_t Segment::MaxOffset() {
   4044   if (!writer_header_)
   4045     return -1;
   4046 
   4047   int64_t offset = writer_header_->Position() - payload_pos_;
   4048 
   4049   if (chunking_) {
   4050     for (int32_t i = 0; i < cluster_list_size_; ++i) {
   4051       Cluster* const cluster = cluster_list_[i];
   4052       offset += cluster->Size();
   4053     }
   4054 
   4055     if (writer_cues_)
   4056       offset += writer_cues_->Position();
   4057   }
   4058 
   4059   return offset;
   4060 }
   4061 
   4062 bool Segment::QueueFrame(Frame* frame) {
   4063   const int32_t new_size = frames_size_ + 1;
   4064 
   4065   if (new_size > frames_capacity_) {
   4066     // Add more frames.
   4067     const int32_t new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2;
   4068 
   4069     if (new_capacity < 1)
   4070       return false;
   4071 
   4072     Frame** const frames = new (std::nothrow) Frame*[new_capacity];  // NOLINT
   4073     if (!frames)
   4074       return false;
   4075 
   4076     for (int32_t i = 0; i < frames_size_; ++i) {
   4077       frames[i] = frames_[i];
   4078     }
   4079 
   4080     delete[] frames_;
   4081     frames_ = frames;
   4082     frames_capacity_ = new_capacity;
   4083   }
   4084 
   4085   frames_[frames_size_++] = frame;
   4086 
   4087   return true;
   4088 }
   4089 
   4090 int Segment::WriteFramesAll() {
   4091   if (frames_ == NULL)
   4092     return 0;
   4093 
   4094   if (cluster_list_size_ < 1)
   4095     return -1;
   4096 
   4097   Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
   4098 
   4099   if (!cluster)
   4100     return -1;
   4101 
   4102   for (int32_t i = 0; i < frames_size_; ++i) {
   4103     Frame*& frame = frames_[i];
   4104     // TODO(jzern/vigneshv): using Segment::AddGenericFrame here would limit the
   4105     // places where |doc_type_version_| needs to be updated.
   4106     if (frame->discard_padding() != 0)
   4107       doc_type_version_ = 4;
   4108     if (!cluster->AddFrame(frame))
   4109       return -1;
   4110 
   4111     if (new_cuepoint_ && cues_track_ == frame->track_number()) {
   4112       if (!AddCuePoint(frame->timestamp(), cues_track_))
   4113         return -1;
   4114     }
   4115 
   4116     if (frame->timestamp() > last_timestamp_) {
   4117       last_timestamp_ = frame->timestamp();
   4118       last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
   4119     }
   4120 
   4121     delete frame;
   4122     frame = NULL;
   4123   }
   4124 
   4125   const int result = frames_size_;
   4126   frames_size_ = 0;
   4127 
   4128   return result;
   4129 }
   4130 
   4131 bool Segment::WriteFramesLessThan(uint64_t timestamp) {
   4132   // Check |cluster_list_size_| to see if this is the first cluster. If it is
   4133   // the first cluster the audio frames that are less than the first video
   4134   // timesatmp will be written in a later step.
   4135   if (frames_size_ > 0 && cluster_list_size_ > 0) {
   4136     if (!frames_)
   4137       return false;
   4138 
   4139     Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
   4140     if (!cluster)
   4141       return false;
   4142 
   4143     int32_t shift_left = 0;
   4144 
   4145     // TODO(fgalligan): Change this to use the durations of frames instead of
   4146     // the next frame's start time if the duration is accurate.
   4147     for (int32_t i = 1; i < frames_size_; ++i) {
   4148       const Frame* const frame_curr = frames_[i];
   4149 
   4150       if (frame_curr->timestamp() > timestamp)
   4151         break;
   4152 
   4153       const Frame* const frame_prev = frames_[i - 1];
   4154       if (frame_prev->discard_padding() != 0)
   4155         doc_type_version_ = 4;
   4156       if (!cluster->AddFrame(frame_prev))
   4157         return false;
   4158 
   4159       if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
   4160         if (!AddCuePoint(frame_prev->timestamp(), cues_track_))
   4161           return false;
   4162       }
   4163 
   4164       ++shift_left;
   4165       if (frame_prev->timestamp() > last_timestamp_) {
   4166         last_timestamp_ = frame_prev->timestamp();
   4167         last_track_timestamp_[frame_prev->track_number() - 1] =
   4168             frame_prev->timestamp();
   4169       }
   4170 
   4171       delete frame_prev;
   4172     }
   4173 
   4174     if (shift_left > 0) {
   4175       if (shift_left >= frames_size_)
   4176         return false;
   4177 
   4178       const int32_t new_frames_size = frames_size_ - shift_left;
   4179       for (int32_t i = 0; i < new_frames_size; ++i) {
   4180         frames_[i] = frames_[i + shift_left];
   4181       }
   4182 
   4183       frames_size_ = new_frames_size;
   4184     }
   4185   }
   4186 
   4187   return true;
   4188 }
   4189 
   4190 bool Segment::DocTypeIsWebm() const {
   4191   const int kNumCodecIds = 9;
   4192 
   4193   // TODO(vigneshv): Tweak .clang-format.
   4194   const char* kWebmCodecIds[kNumCodecIds] = {
   4195       Tracks::kOpusCodecId,          Tracks::kVorbisCodecId,
   4196       Tracks::kAv1CodecId,           Tracks::kVp8CodecId,
   4197       Tracks::kVp9CodecId,           Tracks::kWebVttCaptionsId,
   4198       Tracks::kWebVttDescriptionsId, Tracks::kWebVttMetadataId,
   4199       Tracks::kWebVttSubtitlesId};
   4200 
   4201   const int num_tracks = static_cast<int>(tracks_.track_entries_size());
   4202   for (int track_index = 0; track_index < num_tracks; ++track_index) {
   4203     const Track* const track = tracks_.GetTrackByIndex(track_index);
   4204     const std::string codec_id = track->codec_id();
   4205 
   4206     bool id_is_webm = false;
   4207     for (int id_index = 0; id_index < kNumCodecIds; ++id_index) {
   4208       if (codec_id == kWebmCodecIds[id_index]) {
   4209         id_is_webm = true;
   4210         break;
   4211       }
   4212     }
   4213 
   4214     if (!id_is_webm)
   4215       return false;
   4216   }
   4217 
   4218   return true;
   4219 }
   4220 
   4221 }  // namespace mkvmuxer
   4222