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