mkvmuxer.cpp 85.7 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS.  All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.

9
#include "mkvmuxer.hpp"
10 11 12

#include <climits>
#include <cstdio>
13
#include <cstdlib>
14 15 16 17
#include <cstring>
#include <ctime>
#include <new>

18 19 20 21
#include "mkvmuxerutil.hpp"
#include "mkvparser.hpp"
#include "mkvwriter.hpp"
#include "webmids.hpp"
22 23 24

#ifdef _MSC_VER
// Disable MSVC warnings that suggest making code non-portable.
25
#pragma warning(disable : 4996)
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#endif

namespace mkvmuxer {

namespace {
// Deallocate the string designated by |dst|, and then copy the |src|
// string to |dst|.  The caller owns both the |src| string and the
// |dst| copy (hence the caller is responsible for eventually
// deallocating the strings, either directly, or indirectly via
// StrCpy).  Returns true if the source string was successfully copied
// to the destination.
bool StrCpy(const char* src, char** dst_ptr) {
  if (dst_ptr == NULL)
    return false;

  char*& dst = *dst_ptr;

43
  delete[] dst;
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
  dst = NULL;

  if (src == NULL)
    return true;

  const size_t size = strlen(src) + 1;

  dst = new (std::nothrow) char[size];  // NOLINT
  if (dst == NULL)
    return false;

  strcpy(dst, src);  // NOLINT
  return true;
}
}  // namespace

///////////////////////////////////////////////////////////////
//
// IMkvWriter Class

64
IMkvWriter::IMkvWriter() {}
65

66
IMkvWriter::~IMkvWriter() {}
67

68
bool WriteEbmlHeader(IMkvWriter* writer, uint64 doc_type_version) {
69
  // Level 0
70 71 72 73 74 75 76
  uint64 size = EbmlElementSize(kMkvEBMLVersion, 1ULL);
  size += EbmlElementSize(kMkvEBMLReadVersion, 1ULL);
  size += EbmlElementSize(kMkvEBMLMaxIDLength, 4ULL);
  size += EbmlElementSize(kMkvEBMLMaxSizeLength, 8ULL);
  size += EbmlElementSize(kMkvDocType, "webm");
  size += EbmlElementSize(kMkvDocTypeVersion, doc_type_version);
  size += EbmlElementSize(kMkvDocTypeReadVersion, 2ULL);
77

78
  if (!WriteEbmlMasterElement(writer, kMkvEBML, size))
79
    return false;
80
  if (!WriteEbmlElement(writer, kMkvEBMLVersion, 1ULL))
81
    return false;
82
  if (!WriteEbmlElement(writer, kMkvEBMLReadVersion, 1ULL))
83
    return false;
84
  if (!WriteEbmlElement(writer, kMkvEBMLMaxIDLength, 4ULL))
85
    return false;
86
  if (!WriteEbmlElement(writer, kMkvEBMLMaxSizeLength, 8ULL))
87
    return false;
88
  if (!WriteEbmlElement(writer, kMkvDocType, "webm"))
89
    return false;
90
  if (!WriteEbmlElement(writer, kMkvDocTypeVersion, doc_type_version))
91
    return false;
92
  if (!WriteEbmlElement(writer, kMkvDocTypeReadVersion, 2ULL))
93 94 95 96 97
    return false;

  return true;
}

98 99 100 101
bool WriteEbmlHeader(IMkvWriter* writer) {
  return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion);
}

102
bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst,
103
                 mkvmuxer::int64 start, int64 size) {
104
  // TODO(vigneshv): Check if this is a reasonable value.
105 106 107
  const uint32 kBufSize = 2048;
  uint8* buf = new uint8[kBufSize];
  int64 offset = start;
108
  while (size > 0) {
109
    const int64 read_len = (size > kBufSize) ? kBufSize : size;
110 111
    if (source->Read(offset, static_cast<long>(read_len), buf))
      return false;
112
    dst->Write(buf, static_cast<uint32>(read_len));
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    offset += read_len;
    size -= read_len;
  }
  delete[] buf;
  return true;
}

///////////////////////////////////////////////////////////////
//
// Frame Class

Frame::Frame()
    : add_id_(0),
      additional_(NULL),
      additional_length_(0),
      duration_(0),
      frame_(NULL),
      is_key_(false),
      length_(0),
      track_number_(0),
      timestamp_(0),
134 135 136
      discard_padding_(0),
      reference_block_timestamp_(0),
      reference_block_timestamp_set_(false) {}
137 138

Frame::~Frame() {
139 140
  delete[] frame_;
  delete[] additional_;
141 142
}

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
bool Frame::CopyFrom(const Frame& frame) {
  delete[] frame_;
  frame_ = NULL;
  length_ = 0;
  if (frame.length() > 0 && frame.frame() != NULL &&
      !Init(frame.frame(), frame.length())) {
    return false;
  }
  add_id_ = 0;
  delete[] additional_;
  additional_ = NULL;
  additional_length_ = 0;
  if (frame.additional_length() > 0 && frame.additional() != NULL &&
      !AddAdditionalData(frame.additional(), frame.additional_length(),
                         frame.add_id())) {
    return false;
  }
  duration_ = frame.duration();
  is_key_ = frame.is_key();
  track_number_ = frame.track_number();
  timestamp_ = frame.timestamp();
  discard_padding_ = frame.discard_padding();
  return true;
}

168 169 170
bool Frame::Init(const uint8* frame, uint64 length) {
  uint8* const data =
      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
171 172 173
  if (!data)
    return false;

174
  delete[] frame_;
175 176 177 178 179 180 181
  frame_ = data;
  length_ = length;

  memcpy(frame_, frame, static_cast<size_t>(length_));
  return true;
}

182 183 184 185
bool Frame::AddAdditionalData(const uint8* additional, uint64 length,
                              uint64 add_id) {
  uint8* const data =
      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
186 187 188
  if (!data)
    return false;

189
  delete[] additional_;
190 191 192 193 194 195 196 197
  additional_ = data;
  additional_length_ = length;
  add_id_ = add_id;

  memcpy(additional_, additional, static_cast<size_t>(additional_length_));
  return true;
}

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
bool Frame::IsValid() const {
  if (length_ == 0 || !frame_) {
    return false;
  }
  if ((additional_length_ != 0 && !additional_) ||
      (additional_ != NULL && additional_length_ == 0)) {
    return false;
  }
  if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
    return false;
  }
  if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
    return false;
  }
  return true;
}

bool Frame::CanBeSimpleBlock() const {
  return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
}

219
void Frame::set_reference_block_timestamp(int64 reference_block_timestamp) {
220 221 222 223
  reference_block_timestamp_ = reference_block_timestamp;
  reference_block_timestamp_set_ = true;
}

224 225 226 227 228 229 230 231 232
///////////////////////////////////////////////////////////////
//
// CuePoint Class

CuePoint::CuePoint()
    : time_(0),
      track_(0),
      cluster_pos_(0),
      block_number_(1),
233
      output_block_number_(true) {}
234

235
CuePoint::~CuePoint() {}
236 237 238 239 240

bool CuePoint::Write(IMkvWriter* writer) const {
  if (!writer || track_ < 1 || cluster_pos_ < 1)
    return false;

241 242
  uint64 size = EbmlElementSize(kMkvCueClusterPosition, cluster_pos_);
  size += EbmlElementSize(kMkvCueTrack, track_);
243
  if (output_block_number_ && block_number_ > 1)
244 245 246 247 248
    size += EbmlElementSize(kMkvCueBlockNumber, block_number_);
  const uint64 track_pos_size =
      EbmlMasterElementSize(kMkvCueTrackPositions, size) + size;
  const uint64 payload_size =
      EbmlElementSize(kMkvCueTime, time_) + track_pos_size;
249

250
  if (!WriteEbmlMasterElement(writer, kMkvCuePoint, payload_size))
251 252
    return false;

253
  const int64 payload_position = writer->Position();
254 255 256
  if (payload_position < 0)
    return false;

257
  if (!WriteEbmlElement(writer, kMkvCueTime, time_))
258 259
    return false;

260
  if (!WriteEbmlMasterElement(writer, kMkvCueTrackPositions, size))
261
    return false;
262
  if (!WriteEbmlElement(writer, kMkvCueTrack, track_))
263
    return false;
264
  if (!WriteEbmlElement(writer, kMkvCueClusterPosition, cluster_pos_))
265 266
    return false;
  if (output_block_number_ && block_number_ > 1)
267
    if (!WriteEbmlElement(writer, kMkvCueBlockNumber, block_number_))
268 269
      return false;

270
  const int64 stop_position = writer->Position();
271 272 273
  if (stop_position < 0)
    return false;

274
  if (stop_position - payload_position != static_cast<int64>(payload_size))
275 276 277 278 279
    return false;

  return true;
}

280 281 282
uint64 CuePoint::PayloadSize() const {
  uint64 size = EbmlElementSize(kMkvCueClusterPosition, cluster_pos_);
  size += EbmlElementSize(kMkvCueTrack, track_);
283
  if (output_block_number_ && block_number_ > 1)
284 285 286 287 288
    size += EbmlElementSize(kMkvCueBlockNumber, block_number_);
  const uint64 track_pos_size =
      EbmlMasterElementSize(kMkvCueTrackPositions, size) + size;
  const uint64 payload_size =
      EbmlElementSize(kMkvCueTime, time_) + track_pos_size;
289 290 291 292

  return payload_size;
}

293 294 295
uint64 CuePoint::Size() const {
  const uint64 payload_size = PayloadSize();
  return EbmlMasterElementSize(kMkvCuePoint, payload_size) + payload_size;
296 297 298 299 300 301 302 303 304 305
}

///////////////////////////////////////////////////////////////
//
// Cues Class

Cues::Cues()
    : cue_entries_capacity_(0),
      cue_entries_size_(0),
      cue_entries_(NULL),
306
      output_block_number_(true) {}
307 308 309

Cues::~Cues() {
  if (cue_entries_) {
310
    for (int32 i = 0; i < cue_entries_size_; ++i) {
311 312 313
      CuePoint* const cue = cue_entries_[i];
      delete cue;
    }
314
    delete[] cue_entries_;
315 316 317 318 319 320 321 322 323
  }
}

bool Cues::AddCue(CuePoint* cue) {
  if (!cue)
    return false;

  if ((cue_entries_size_ + 1) > cue_entries_capacity_) {
    // Add more CuePoints.
324
    const int32 new_capacity =
325 326 327 328 329 330
        (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2;

    if (new_capacity < 1)
      return false;

    CuePoint** const cues =
331
        new (std::nothrow) CuePoint*[new_capacity];  // NOLINT
332 333 334
    if (!cues)
      return false;

335
    for (int32 i = 0; i < cue_entries_size_; ++i) {
336 337 338
      cues[i] = cue_entries_[i];
    }

339
    delete[] cue_entries_;
340 341 342 343 344 345 346 347 348 349

    cue_entries_ = cues;
    cue_entries_capacity_ = new_capacity;
  }

  cue->set_output_block_number(output_block_number_);
  cue_entries_[cue_entries_size_++] = cue;
  return true;
}

350
CuePoint* Cues::GetCueByIndex(int32 index) const {
351 352 353 354 355 356 357 358 359
  if (cue_entries_ == NULL)
    return NULL;

  if (index >= cue_entries_size_)
    return NULL;

  return cue_entries_[index];
}

360 361 362
uint64 Cues::Size() {
  uint64 size = 0;
  for (int32 i = 0; i < cue_entries_size_; ++i)
363
    size += GetCueByIndex(i)->Size();
364
  size += EbmlMasterElementSize(kMkvCues, size);
365 366 367 368 369 370 371
  return size;
}

bool Cues::Write(IMkvWriter* writer) const {
  if (!writer)
    return false;

372 373
  uint64 size = 0;
  for (int32 i = 0; i < cue_entries_size_; ++i) {
374 375 376 377 378 379 380 381
    const CuePoint* const cue = GetCueByIndex(i);

    if (!cue)
      return false;

    size += cue->Size();
  }

382
  if (!WriteEbmlMasterElement(writer, kMkvCues, size))
383 384
    return false;

385
  const int64 payload_position = writer->Position();
386 387 388
  if (payload_position < 0)
    return false;

389
  for (int32 i = 0; i < cue_entries_size_; ++i) {
390 391 392 393 394 395
    const CuePoint* const cue = GetCueByIndex(i);

    if (!cue->Write(writer))
      return false;
  }

396
  const int64 stop_position = writer->Position();
397 398 399
  if (stop_position < 0)
    return false;

400
  if (stop_position - payload_position != static_cast<int64>(size))
401 402 403 404 405 406 407 408 409 410 411
    return false;

  return true;
}

///////////////////////////////////////////////////////////////
//
// ContentEncAESSettings Class

ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}

412 413 414 415
uint64 ContentEncAESSettings::Size() const {
  const uint64 payload = PayloadSize();
  const uint64 size =
      EbmlMasterElementSize(kMkvContentEncAESSettings, payload) + payload;
416 417 418 419
  return size;
}

bool ContentEncAESSettings::Write(IMkvWriter* writer) const {
420
  const uint64 payload = PayloadSize();
421

422
  if (!WriteEbmlMasterElement(writer, kMkvContentEncAESSettings, payload))
423 424
    return false;

425
  const int64 payload_position = writer->Position();
426 427 428
  if (payload_position < 0)
    return false;

429
  if (!WriteEbmlElement(writer, kMkvAESSettingsCipherMode, cipher_mode_))
430 431
    return false;

432
  const int64 stop_position = writer->Position();
433
  if (stop_position < 0 ||
434
      stop_position - payload_position != static_cast<int64>(payload))
435 436 437 438 439
    return false;

  return true;
}

440 441
uint64 ContentEncAESSettings::PayloadSize() const {
  uint64 size = EbmlElementSize(kMkvAESSettingsCipherMode, cipher_mode_);
442 443 444 445 446 447 448 449 450 451 452 453 454
  return size;
}

///////////////////////////////////////////////////////////////
//
// ContentEncoding Class

ContentEncoding::ContentEncoding()
    : enc_algo_(5),
      enc_key_id_(NULL),
      encoding_order_(0),
      encoding_scope_(1),
      encoding_type_(1),
455
      enc_key_id_length_(0) {}
456

457
ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
458

459
bool ContentEncoding::SetEncryptionID(const uint8* id, uint64 length) {
460 461 462
  if (!id || length < 1)
    return false;

463
  delete[] enc_key_id_;
464 465

  enc_key_id_ =
466
      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
467 468 469 470 471 472 473 474 475
  if (!enc_key_id_)
    return false;

  memcpy(enc_key_id_, id, static_cast<size_t>(length));
  enc_key_id_length_ = length;

  return true;
}

476 477 478 479 480
uint64 ContentEncoding::Size() const {
  const uint64 encryption_size = EncryptionSize();
  const uint64 encoding_size = EncodingSize(0, encryption_size);
  const uint64 encodings_size =
      EbmlMasterElementSize(kMkvContentEncoding, encoding_size) + encoding_size;
481 482 483 484 485

  return encodings_size;
}

bool ContentEncoding::Write(IMkvWriter* writer) const {
486 487 488 489
  const uint64 encryption_size = EncryptionSize();
  const uint64 encoding_size = EncodingSize(0, encryption_size);
  const uint64 size =
      EbmlMasterElementSize(kMkvContentEncoding, encoding_size) + encoding_size;
490

491
  const int64 payload_position = writer->Position();
492 493 494
  if (payload_position < 0)
    return false;

495
  if (!WriteEbmlMasterElement(writer, kMkvContentEncoding, encoding_size))
496
    return false;
497
  if (!WriteEbmlElement(writer, kMkvContentEncodingOrder, encoding_order_))
498
    return false;
499
  if (!WriteEbmlElement(writer, kMkvContentEncodingScope, encoding_scope_))
500
    return false;
501
  if (!WriteEbmlElement(writer, kMkvContentEncodingType, encoding_type_))
502 503
    return false;

504
  if (!WriteEbmlMasterElement(writer, kMkvContentEncryption, encryption_size))
505
    return false;
506
  if (!WriteEbmlElement(writer, kMkvContentEncAlgo, enc_algo_))
507
    return false;
508
  if (!WriteEbmlElement(writer, kMkvContentEncKeyID, enc_key_id_,
509 510 511 512 513 514
                        enc_key_id_length_))
    return false;

  if (!enc_aes_settings_.Write(writer))
    return false;

515
  const int64 stop_position = writer->Position();
516
  if (stop_position < 0 ||
517
      stop_position - payload_position != static_cast<int64>(size))
518 519 520 521 522
    return false;

  return true;
}

523 524
uint64 ContentEncoding::EncodingSize(uint64 compresion_size,
                                     uint64 encryption_size) const {
525 526 527 528
  // TODO(fgalligan): Add support for compression settings.
  if (compresion_size != 0)
    return 0;

529
  uint64 encoding_size = 0;
530 531

  if (encryption_size > 0) {
532
    encoding_size +=
533
        EbmlMasterElementSize(kMkvContentEncryption, encryption_size) +
534
        encryption_size;
535
  }
536 537 538
  encoding_size += EbmlElementSize(kMkvContentEncodingType, encoding_type_);
  encoding_size += EbmlElementSize(kMkvContentEncodingScope, encoding_scope_);
  encoding_size += EbmlElementSize(kMkvContentEncodingOrder, encoding_order_);
539 540 541 542

  return encoding_size;
}

543 544
uint64 ContentEncoding::EncryptionSize() const {
  const uint64 aes_size = enc_aes_settings_.Size();
545

546 547 548
  uint64 encryption_size =
      EbmlElementSize(kMkvContentEncKeyID, enc_key_id_, enc_key_id_length_);
  encryption_size += EbmlElementSize(kMkvContentEncAlgo, enc_algo_);
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567

  return encryption_size + aes_size;
}

///////////////////////////////////////////////////////////////
//
// Track Class

Track::Track(unsigned int* seed)
    : codec_id_(NULL),
      codec_private_(NULL),
      language_(NULL),
      max_block_additional_id_(0),
      name_(NULL),
      number_(0),
      type_(0),
      uid_(MakeUID(seed)),
      codec_delay_(0),
      seek_pre_roll_(0),
568
      default_duration_(0),
569 570
      codec_private_length_(0),
      content_encoding_entries_(NULL),
571
      content_encoding_entries_size_(0) {}
572 573

Track::~Track() {
574 575 576 577
  delete[] codec_id_;
  delete[] codec_private_;
  delete[] language_;
  delete[] name_;
578 579

  if (content_encoding_entries_) {
580
    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
581 582 583
      ContentEncoding* const encoding = content_encoding_entries_[i];
      delete encoding;
    }
584
    delete[] content_encoding_entries_;
585 586 587 588
  }
}

bool Track::AddContentEncoding() {
589
  const uint32 count = content_encoding_entries_size_ + 1;
590 591

  ContentEncoding** const content_encoding_entries =
592
      new (std::nothrow) ContentEncoding*[count];  // NOLINT
593 594 595 596 597 598
  if (!content_encoding_entries)
    return false;

  ContentEncoding* const content_encoding =
      new (std::nothrow) ContentEncoding();  // NOLINT
  if (!content_encoding) {
599
    delete[] content_encoding_entries;
600 601 602
    return false;
  }

603
  for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
604 605 606
    content_encoding_entries[i] = content_encoding_entries_[i];
  }

607
  delete[] content_encoding_entries_;
608 609 610 611 612 613 614

  content_encoding_entries_ = content_encoding_entries;
  content_encoding_entries_[content_encoding_entries_size_] = content_encoding;
  content_encoding_entries_size_ = count;
  return true;
}

615
ContentEncoding* Track::GetContentEncodingByIndex(uint32 index) const {
616 617 618 619 620 621 622 623 624
  if (content_encoding_entries_ == NULL)
    return NULL;

  if (index >= content_encoding_entries_size_)
    return NULL;

  return content_encoding_entries_[index];
}

625 626 627 628
uint64 Track::PayloadSize() const {
  uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
  size += EbmlElementSize(kMkvTrackUID, uid_);
  size += EbmlElementSize(kMkvTrackType, type_);
629
  if (codec_id_)
630
    size += EbmlElementSize(kMkvCodecID, codec_id_);
631
  if (codec_private_)
632
    size += EbmlElementSize(kMkvCodecPrivate, codec_private_,
633 634
                            codec_private_length_);
  if (language_)
635
    size += EbmlElementSize(kMkvLanguage, language_);
636
  if (name_)
637
    size += EbmlElementSize(kMkvName, name_);
638
  if (max_block_additional_id_)
639
    size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
640
  if (codec_delay_)
641
    size += EbmlElementSize(kMkvCodecDelay, codec_delay_);
642
  if (seek_pre_roll_)
643
    size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_);
644
  if (default_duration_)
645
    size += EbmlElementSize(kMkvDefaultDuration, default_duration_);
646 647

  if (content_encoding_entries_size_ > 0) {
648 649
    uint64 content_encodings_size = 0;
    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
650 651 652 653
      ContentEncoding* const encoding = content_encoding_entries_[i];
      content_encodings_size += encoding->Size();
    }

654 655 656
    size +=
        EbmlMasterElementSize(kMkvContentEncodings, content_encodings_size) +
        content_encodings_size;
657 658 659 660 661
  }

  return size;
}

662 663 664
uint64 Track::Size() const {
  uint64 size = PayloadSize();
  size += EbmlMasterElementSize(kMkvTrackEntry, size);
665 666 667 668 669 670 671
  return size;
}

bool Track::Write(IMkvWriter* writer) const {
  if (!writer)
    return false;

672 673 674 675
  // mandatory elements without a default value.
  if (!type_ || !codec_id_)
    return false;

676 677
  // |size| may be bigger than what is written out in this function because
  // derived classes may write out more data in the Track element.
678
  const uint64 payload_size = PayloadSize();
679

680
  if (!WriteEbmlMasterElement(writer, kMkvTrackEntry, payload_size))
681 682
    return false;

683 684 685
  uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
  size += EbmlElementSize(kMkvTrackUID, uid_);
  size += EbmlElementSize(kMkvTrackType, type_);
686
  if (codec_id_)
687
    size += EbmlElementSize(kMkvCodecID, codec_id_);
688
  if (codec_private_)
689
    size += EbmlElementSize(kMkvCodecPrivate, codec_private_,
690 691
                            codec_private_length_);
  if (language_)
692
    size += EbmlElementSize(kMkvLanguage, language_);
693
  if (name_)
694
    size += EbmlElementSize(kMkvName, name_);
695
  if (max_block_additional_id_)
696
    size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
697
  if (codec_delay_)
698
    size += EbmlElementSize(kMkvCodecDelay, codec_delay_);
699
  if (seek_pre_roll_)
700
    size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_);
701
  if (default_duration_)
702
    size += EbmlElementSize(kMkvDefaultDuration, default_duration_);
703

704
  const int64 payload_position = writer->Position();
705 706 707
  if (payload_position < 0)
    return false;

708
  if (!WriteEbmlElement(writer, kMkvTrackNumber, number_))
709
    return false;
710
  if (!WriteEbmlElement(writer, kMkvTrackUID, uid_))
711
    return false;
712
  if (!WriteEbmlElement(writer, kMkvTrackType, type_))
713 714
    return false;
  if (max_block_additional_id_) {
715
    if (!WriteEbmlElement(writer, kMkvMaxBlockAdditionID,
716 717 718 719 720
                          max_block_additional_id_)) {
      return false;
    }
  }
  if (codec_delay_) {
721
    if (!WriteEbmlElement(writer, kMkvCodecDelay, codec_delay_))
722 723 724
      return false;
  }
  if (seek_pre_roll_) {
725
    if (!WriteEbmlElement(writer, kMkvSeekPreRoll, seek_pre_roll_))
726 727
      return false;
  }
728
  if (default_duration_) {
729
    if (!WriteEbmlElement(writer, kMkvDefaultDuration, default_duration_))
730 731
      return false;
  }
732
  if (codec_id_) {
733
    if (!WriteEbmlElement(writer, kMkvCodecID, codec_id_))
734 735 736
      return false;
  }
  if (codec_private_) {
737
    if (!WriteEbmlElement(writer, kMkvCodecPrivate, codec_private_,
738 739 740 741
                          codec_private_length_))
      return false;
  }
  if (language_) {
742
    if (!WriteEbmlElement(writer, kMkvLanguage, language_))
743 744 745
      return false;
  }
  if (name_) {
746
    if (!WriteEbmlElement(writer, kMkvName, name_))
747 748 749
      return false;
  }

750
  int64 stop_position = writer->Position();
751
  if (stop_position < 0 ||
752
      stop_position - payload_position != static_cast<int64>(size))
753 754 755
    return false;

  if (content_encoding_entries_size_ > 0) {
756 757
    uint64 content_encodings_size = 0;
    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
758 759 760 761
      ContentEncoding* const encoding = content_encoding_entries_[i];
      content_encodings_size += encoding->Size();
    }

762
    if (!WriteEbmlMasterElement(writer, kMkvContentEncodings,
763 764 765
                                content_encodings_size))
      return false;

766
    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
767 768 769 770 771 772 773 774 775 776 777 778
      ContentEncoding* const encoding = content_encoding_entries_[i];
      if (!encoding->Write(writer))
        return false;
    }
  }

  stop_position = writer->Position();
  if (stop_position < 0)
    return false;
  return true;
}

779
bool Track::SetCodecPrivate(const uint8* codec_private, uint64 length) {
780 781 782
  if (!codec_private || length < 1)
    return false;

783
  delete[] codec_private_;
784 785

  codec_private_ =
786
      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
787 788 789 790 791 792 793 794 795 796 797
  if (!codec_private_)
    return false;

  memcpy(codec_private_, codec_private, static_cast<size_t>(length));
  codec_private_length_ = length;

  return true;
}

void Track::set_codec_id(const char* codec_id) {
  if (codec_id) {
798
    delete[] codec_id_;
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814

    const size_t length = strlen(codec_id) + 1;
    codec_id_ = new (std::nothrow) char[length];  // NOLINT
    if (codec_id_) {
#ifdef _MSC_VER
      strcpy_s(codec_id_, length, codec_id);
#else
      strcpy(codec_id_, codec_id);
#endif
    }
  }
}

// TODO(fgalligan): Vet the language parameter.
void Track::set_language(const char* language) {
  if (language) {
815
    delete[] language_;
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830

    const size_t length = strlen(language) + 1;
    language_ = new (std::nothrow) char[length];  // NOLINT
    if (language_) {
#ifdef _MSC_VER
      strcpy_s(language_, length, language);
#else
      strcpy(language_, language);
#endif
    }
  }
}

void Track::set_name(const char* name) {
  if (name) {
831
    delete[] name_;
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852

    const size_t length = strlen(name) + 1;
    name_ = new (std::nothrow) char[length];  // NOLINT
    if (name_) {
#ifdef _MSC_VER
      strcpy_s(name_, length, name);
#else
      strcpy(name_, name);
#endif
    }
  }
}

///////////////////////////////////////////////////////////////
//
// VideoTrack Class

VideoTrack::VideoTrack(unsigned int* seed)
    : Track(seed),
      display_height_(0),
      display_width_(0),
853 854 855 856
      crop_left_(0),
      crop_right_(0),
      crop_top_(0),
      crop_bottom_(0),
857 858 859 860
      frame_rate_(0.0),
      height_(0),
      stereo_mode_(0),
      alpha_mode_(0),
861
      width_(0) {}
862

863
VideoTrack::~VideoTrack() {}
864

865
bool VideoTrack::SetStereoMode(uint64 stereo_mode) {
866
  if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
867 868 869 870 871 872 873 874 875
      stereo_mode != kTopBottomRightIsFirst &&
      stereo_mode != kTopBottomLeftIsFirst &&
      stereo_mode != kSideBySideRightIsFirst)
    return false;

  stereo_mode_ = stereo_mode;
  return true;
}

876
bool VideoTrack::SetAlphaMode(uint64 alpha_mode) {
877
  if (alpha_mode != kNoAlpha && alpha_mode != kAlpha)
878 879 880 881 882 883
    return false;

  alpha_mode_ = alpha_mode;
  return true;
}

884 885
uint64 VideoTrack::PayloadSize() const {
  const uint64 parent_size = Track::PayloadSize();
886

887 888
  uint64 size = VideoPayloadSize();
  size += EbmlMasterElementSize(kMkvVideo, size);
889 890 891 892 893 894 895 896

  return parent_size + size;
}

bool VideoTrack::Write(IMkvWriter* writer) const {
  if (!Track::Write(writer))
    return false;

897
  const uint64 size = VideoPayloadSize();
898

899
  if (!WriteEbmlMasterElement(writer, kMkvVideo, size))
900 901
    return false;

902
  const int64 payload_position = writer->Position();
903 904 905
  if (payload_position < 0)
    return false;

906
  if (!WriteEbmlElement(writer, kMkvPixelWidth, width_))
907
    return false;
908
  if (!WriteEbmlElement(writer, kMkvPixelHeight, height_))
909
    return false;
910
  if (display_width_ > 0) {
911
    if (!WriteEbmlElement(writer, kMkvDisplayWidth, display_width_))
912
      return false;
913 914
  }
  if (display_height_ > 0) {
915
    if (!WriteEbmlElement(writer, kMkvDisplayHeight, display_height_))
916
      return false;
917 918
  }
  if (crop_left_ > 0) {
919
    if (!WriteEbmlElement(writer, kMkvPixelCropLeft, crop_left_))
920 921 922
      return false;
  }
  if (crop_right_ > 0) {
923
    if (!WriteEbmlElement(writer, kMkvPixelCropRight, crop_right_))
924 925 926
      return false;
  }
  if (crop_top_ > 0) {
927
    if (!WriteEbmlElement(writer, kMkvPixelCropTop, crop_top_))
928 929 930
      return false;
  }
  if (crop_bottom_ > 0) {
931
    if (!WriteEbmlElement(writer, kMkvPixelCropBottom, crop_bottom_))
932 933 934
      return false;
  }
  if (stereo_mode_ > kMono) {
935
    if (!WriteEbmlElement(writer, kMkvStereoMode, stereo_mode_))
936
      return false;
937 938
  }
  if (alpha_mode_ > kNoAlpha) {
939
    if (!WriteEbmlElement(writer, kMkvAlphaMode, alpha_mode_))
940
      return false;
941 942
  }
  if (frame_rate_ > 0.0) {
943
    if (!WriteEbmlElement(writer, kMkvFrameRate,
944
                          static_cast<float>(frame_rate_))) {
945
      return false;
946 947
    }
  }
948

949
  const int64 stop_position = writer->Position();
950
  if (stop_position < 0 ||
951
      stop_position - payload_position != static_cast<int64>(size)) {
952
    return false;
953
  }
954 955 956 957

  return true;
}

958 959 960
uint64 VideoTrack::VideoPayloadSize() const {
  uint64 size = EbmlElementSize(kMkvPixelWidth, width_);
  size += EbmlElementSize(kMkvPixelHeight, height_);
961
  if (display_width_ > 0)
962
    size += EbmlElementSize(kMkvDisplayWidth, display_width_);
963
  if (display_height_ > 0)
964
    size += EbmlElementSize(kMkvDisplayHeight, display_height_);
965
  if (crop_left_ > 0)
966
    size += EbmlElementSize(kMkvPixelCropLeft, crop_left_);
967
  if (crop_right_ > 0)
968
    size += EbmlElementSize(kMkvPixelCropRight, crop_right_);
969
  if (crop_top_ > 0)
970
    size += EbmlElementSize(kMkvPixelCropTop, crop_top_);
971
  if (crop_bottom_ > 0)
972
    size += EbmlElementSize(kMkvPixelCropBottom, crop_bottom_);
973
  if (stereo_mode_ > kMono)
974
    size += EbmlElementSize(kMkvStereoMode, stereo_mode_);
975
  if (alpha_mode_ > kNoAlpha)
976
    size += EbmlElementSize(kMkvAlphaMode, alpha_mode_);
977
  if (frame_rate_ > 0.0)
978
    size += EbmlElementSize(kMkvFrameRate, static_cast<float>(frame_rate_));
979 980 981 982 983 984 985 986 987

  return size;
}

///////////////////////////////////////////////////////////////
//
// AudioTrack Class

AudioTrack::AudioTrack(unsigned int* seed)
988
    : Track(seed), bit_depth_(0), channels_(1), sample_rate_(0.0) {}
989

990
AudioTrack::~AudioTrack() {}
991