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