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