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