| OLD | NEW |
| 1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved. | 1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved. |
| 2 // | 2 // |
| 3 // Use of this source code is governed by a BSD-style license | 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 | 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 | 5 // tree. An additional intellectual property rights grant can be found |
| 6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
| 7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
| 8 | 8 |
| 9 #include "mkvmuxer.hpp" | 9 #include "mkvmuxer.hpp" |
| 10 | 10 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 } // namespace | 58 } // namespace |
| 59 | 59 |
| 60 /////////////////////////////////////////////////////////////// | 60 /////////////////////////////////////////////////////////////// |
| 61 // | 61 // |
| 62 // IMkvWriter Class | 62 // IMkvWriter Class |
| 63 | 63 |
| 64 IMkvWriter::IMkvWriter() {} | 64 IMkvWriter::IMkvWriter() {} |
| 65 | 65 |
| 66 IMkvWriter::~IMkvWriter() {} | 66 IMkvWriter::~IMkvWriter() {} |
| 67 | 67 |
| 68 bool WriteEbmlHeader(IMkvWriter* writer) { | 68 bool WriteEbmlHeader(IMkvWriter* writer, uint64 doc_type_version) { |
| 69 // Level 0 | 69 // Level 0 |
| 70 uint64 size = EbmlElementSize(kMkvEBMLVersion, 1ULL); | 70 uint64 size = EbmlElementSize(kMkvEBMLVersion, 1ULL); |
| 71 size += EbmlElementSize(kMkvEBMLReadVersion, 1ULL); | 71 size += EbmlElementSize(kMkvEBMLReadVersion, 1ULL); |
| 72 size += EbmlElementSize(kMkvEBMLMaxIDLength, 4ULL); | 72 size += EbmlElementSize(kMkvEBMLMaxIDLength, 4ULL); |
| 73 size += EbmlElementSize(kMkvEBMLMaxSizeLength, 8ULL); | 73 size += EbmlElementSize(kMkvEBMLMaxSizeLength, 8ULL); |
| 74 size += EbmlElementSize(kMkvDocType, "webm"); | 74 size += EbmlElementSize(kMkvDocType, "webm"); |
| 75 size += EbmlElementSize(kMkvDocTypeVersion, 2ULL); | 75 size += EbmlElementSize(kMkvDocTypeVersion, doc_type_version); |
| 76 size += EbmlElementSize(kMkvDocTypeReadVersion, 2ULL); | 76 size += EbmlElementSize(kMkvDocTypeReadVersion, 2ULL); |
| 77 | 77 |
| 78 if (!WriteEbmlMasterElement(writer, kMkvEBML, size)) | 78 if (!WriteEbmlMasterElement(writer, kMkvEBML, size)) |
| 79 return false; | 79 return false; |
| 80 if (!WriteEbmlElement(writer, kMkvEBMLVersion, 1ULL)) | 80 if (!WriteEbmlElement(writer, kMkvEBMLVersion, 1ULL)) |
| 81 return false; | 81 return false; |
| 82 if (!WriteEbmlElement(writer, kMkvEBMLReadVersion, 1ULL)) | 82 if (!WriteEbmlElement(writer, kMkvEBMLReadVersion, 1ULL)) |
| 83 return false; | 83 return false; |
| 84 if (!WriteEbmlElement(writer, kMkvEBMLMaxIDLength, 4ULL)) | 84 if (!WriteEbmlElement(writer, kMkvEBMLMaxIDLength, 4ULL)) |
| 85 return false; | 85 return false; |
| 86 if (!WriteEbmlElement(writer, kMkvEBMLMaxSizeLength, 8ULL)) | 86 if (!WriteEbmlElement(writer, kMkvEBMLMaxSizeLength, 8ULL)) |
| 87 return false; | 87 return false; |
| 88 if (!WriteEbmlElement(writer, kMkvDocType, "webm")) | 88 if (!WriteEbmlElement(writer, kMkvDocType, "webm")) |
| 89 return false; | 89 return false; |
| 90 if (!WriteEbmlElement(writer, kMkvDocTypeVersion, 2ULL)) | 90 if (!WriteEbmlElement(writer, kMkvDocTypeVersion, doc_type_version)) |
| 91 return false; | 91 return false; |
| 92 if (!WriteEbmlElement(writer, kMkvDocTypeReadVersion, 2ULL)) | 92 if (!WriteEbmlElement(writer, kMkvDocTypeReadVersion, 2ULL)) |
| 93 return false; | 93 return false; |
| 94 | 94 |
| 95 return true; | 95 return true; |
| 96 } | 96 } |
| 97 | 97 |
| 98 bool WriteEbmlHeader(IMkvWriter* writer) { |
| 99 return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion); |
| 100 } |
| 101 |
| 98 bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst, | 102 bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst, |
| 99 mkvmuxer::int64 start, int64 size) { | 103 mkvmuxer::int64 start, int64 size) { |
| 100 // TODO(vigneshv): Check if this is a reasonable value. | 104 // TODO(vigneshv): Check if this is a reasonable value. |
| 101 const uint32 kBufSize = 2048; | 105 const uint32 kBufSize = 2048; |
| 102 uint8* buf = new uint8[kBufSize]; | 106 uint8* buf = new uint8[kBufSize]; |
| 103 int64 offset = start; | 107 int64 offset = start; |
| 104 while (size > 0) { | 108 while (size > 0) { |
| 105 const int64 read_len = (size > kBufSize) ? kBufSize : size; | 109 const int64 read_len = (size > kBufSize) ? kBufSize : size; |
| 106 if (source->Read(offset, static_cast<long>(read_len), buf)) | 110 if (source->Read(offset, static_cast<long>(read_len), buf)) |
| 107 return false; | 111 return false; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 120 Frame::Frame() | 124 Frame::Frame() |
| 121 : add_id_(0), | 125 : add_id_(0), |
| 122 additional_(NULL), | 126 additional_(NULL), |
| 123 additional_length_(0), | 127 additional_length_(0), |
| 124 duration_(0), | 128 duration_(0), |
| 125 frame_(NULL), | 129 frame_(NULL), |
| 126 is_key_(false), | 130 is_key_(false), |
| 127 length_(0), | 131 length_(0), |
| 128 track_number_(0), | 132 track_number_(0), |
| 129 timestamp_(0), | 133 timestamp_(0), |
| 130 discard_padding_(0) {} | 134 discard_padding_(0), |
| 135 reference_block_timestamp_(0), |
| 136 reference_block_timestamp_set_(false) {} |
| 131 | 137 |
| 132 Frame::~Frame() { | 138 Frame::~Frame() { |
| 133 delete[] frame_; | 139 delete[] frame_; |
| 134 delete[] additional_; | 140 delete[] additional_; |
| 135 } | 141 } |
| 136 | 142 |
| 143 bool Frame::CopyFrom(const Frame& frame) { |
| 144 delete[] frame_; |
| 145 frame_ = NULL; |
| 146 length_ = 0; |
| 147 if (frame.length() > 0 && frame.frame() != NULL && |
| 148 !Init(frame.frame(), frame.length())) { |
| 149 return false; |
| 150 } |
| 151 add_id_ = 0; |
| 152 delete[] additional_; |
| 153 additional_ = NULL; |
| 154 additional_length_ = 0; |
| 155 if (frame.additional_length() > 0 && frame.additional() != NULL && |
| 156 !AddAdditionalData(frame.additional(), frame.additional_length(), |
| 157 frame.add_id())) { |
| 158 return false; |
| 159 } |
| 160 duration_ = frame.duration(); |
| 161 is_key_ = frame.is_key(); |
| 162 track_number_ = frame.track_number(); |
| 163 timestamp_ = frame.timestamp(); |
| 164 discard_padding_ = frame.discard_padding(); |
| 165 return true; |
| 166 } |
| 167 |
| 137 bool Frame::Init(const uint8* frame, uint64 length) { | 168 bool Frame::Init(const uint8* frame, uint64 length) { |
| 138 uint8* const data = | 169 uint8* const data = |
| 139 new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT | 170 new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT |
| 140 if (!data) | 171 if (!data) |
| 141 return false; | 172 return false; |
| 142 | 173 |
| 143 delete[] frame_; | 174 delete[] frame_; |
| 144 frame_ = data; | 175 frame_ = data; |
| 145 length_ = length; | 176 length_ = length; |
| 146 | 177 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 157 | 188 |
| 158 delete[] additional_; | 189 delete[] additional_; |
| 159 additional_ = data; | 190 additional_ = data; |
| 160 additional_length_ = length; | 191 additional_length_ = length; |
| 161 add_id_ = add_id; | 192 add_id_ = add_id; |
| 162 | 193 |
| 163 memcpy(additional_, additional, static_cast<size_t>(additional_length_)); | 194 memcpy(additional_, additional, static_cast<size_t>(additional_length_)); |
| 164 return true; | 195 return true; |
| 165 } | 196 } |
| 166 | 197 |
| 198 bool Frame::IsValid() const { |
| 199 if (length_ == 0 || !frame_) { |
| 200 return false; |
| 201 } |
| 202 if ((additional_length_ != 0 && !additional_) || |
| 203 (additional_ != NULL && additional_length_ == 0)) { |
| 204 return false; |
| 205 } |
| 206 if (track_number_ == 0 || track_number_ > kMaxTrackNumber) { |
| 207 return false; |
| 208 } |
| 209 if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) { |
| 210 return false; |
| 211 } |
| 212 return true; |
| 213 } |
| 214 |
| 215 bool Frame::CanBeSimpleBlock() const { |
| 216 return additional_ == NULL && discard_padding_ == 0 && duration_ == 0; |
| 217 } |
| 218 |
| 219 void Frame::set_reference_block_timestamp(int64 reference_block_timestamp) { |
| 220 reference_block_timestamp_ = reference_block_timestamp; |
| 221 reference_block_timestamp_set_ = true; |
| 222 } |
| 223 |
| 167 /////////////////////////////////////////////////////////////// | 224 /////////////////////////////////////////////////////////////// |
| 168 // | 225 // |
| 169 // CuePoint Class | 226 // CuePoint Class |
| 170 | 227 |
| 171 CuePoint::CuePoint() | 228 CuePoint::CuePoint() |
| 172 : time_(0), | 229 : time_(0), |
| 173 track_(0), | 230 track_(0), |
| 174 cluster_pos_(0), | 231 cluster_pos_(0), |
| 175 block_number_(1), | 232 block_number_(1), |
| 176 output_block_number_(true) {} | 233 output_block_number_(true) {} |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 | 321 |
| 265 if ((cue_entries_size_ + 1) > cue_entries_capacity_) { | 322 if ((cue_entries_size_ + 1) > cue_entries_capacity_) { |
| 266 // Add more CuePoints. | 323 // Add more CuePoints. |
| 267 const int32 new_capacity = | 324 const int32 new_capacity = |
| 268 (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2; | 325 (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2; |
| 269 | 326 |
| 270 if (new_capacity < 1) | 327 if (new_capacity < 1) |
| 271 return false; | 328 return false; |
| 272 | 329 |
| 273 CuePoint** const cues = | 330 CuePoint** const cues = |
| 274 new (std::nothrow) CuePoint* [new_capacity]; // NOLINT | 331 new (std::nothrow) CuePoint*[new_capacity]; // NOLINT |
| 275 if (!cues) | 332 if (!cues) |
| 276 return false; | 333 return false; |
| 277 | 334 |
| 278 for (int32 i = 0; i < cue_entries_size_; ++i) { | 335 for (int32 i = 0; i < cue_entries_size_; ++i) { |
| 279 cues[i] = cue_entries_[i]; | 336 cues[i] = cue_entries_[i]; |
| 280 } | 337 } |
| 281 | 338 |
| 282 delete[] cue_entries_; | 339 delete[] cue_entries_; |
| 283 | 340 |
| 284 cue_entries_ = cues; | 341 cue_entries_ = cues; |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 delete encoding; | 582 delete encoding; |
| 526 } | 583 } |
| 527 delete[] content_encoding_entries_; | 584 delete[] content_encoding_entries_; |
| 528 } | 585 } |
| 529 } | 586 } |
| 530 | 587 |
| 531 bool Track::AddContentEncoding() { | 588 bool Track::AddContentEncoding() { |
| 532 const uint32 count = content_encoding_entries_size_ + 1; | 589 const uint32 count = content_encoding_entries_size_ + 1; |
| 533 | 590 |
| 534 ContentEncoding** const content_encoding_entries = | 591 ContentEncoding** const content_encoding_entries = |
| 535 new (std::nothrow) ContentEncoding* [count]; // NOLINT | 592 new (std::nothrow) ContentEncoding*[count]; // NOLINT |
| 536 if (!content_encoding_entries) | 593 if (!content_encoding_entries) |
| 537 return false; | 594 return false; |
| 538 | 595 |
| 539 ContentEncoding* const content_encoding = | 596 ContentEncoding* const content_encoding = |
| 540 new (std::nothrow) ContentEncoding(); // NOLINT | 597 new (std::nothrow) ContentEncoding(); // NOLINT |
| 541 if (!content_encoding) { | 598 if (!content_encoding) { |
| 542 delete[] content_encoding_entries; | 599 delete[] content_encoding_entries; |
| 543 return false; | 600 return false; |
| 544 } | 601 } |
| 545 | 602 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 uint64 Track::Size() const { | 662 uint64 Track::Size() const { |
| 606 uint64 size = PayloadSize(); | 663 uint64 size = PayloadSize(); |
| 607 size += EbmlMasterElementSize(kMkvTrackEntry, size); | 664 size += EbmlMasterElementSize(kMkvTrackEntry, size); |
| 608 return size; | 665 return size; |
| 609 } | 666 } |
| 610 | 667 |
| 611 bool Track::Write(IMkvWriter* writer) const { | 668 bool Track::Write(IMkvWriter* writer) const { |
| 612 if (!writer) | 669 if (!writer) |
| 613 return false; | 670 return false; |
| 614 | 671 |
| 672 // mandatory elements without a default value. |
| 673 if (!type_ || !codec_id_) |
| 674 return false; |
| 675 |
| 615 // |size| may be bigger than what is written out in this function because | 676 // |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. | 677 // derived classes may write out more data in the Track element. |
| 617 const uint64 payload_size = PayloadSize(); | 678 const uint64 payload_size = PayloadSize(); |
| 618 | 679 |
| 619 if (!WriteEbmlMasterElement(writer, kMkvTrackEntry, payload_size)) | 680 if (!WriteEbmlMasterElement(writer, kMkvTrackEntry, payload_size)) |
| 620 return false; | 681 return false; |
| 621 | 682 |
| 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_); | 683 uint64 size = EbmlElementSize(kMkvTrackNumber, number_); |
| 627 size += EbmlElementSize(kMkvTrackUID, uid_); | 684 size += EbmlElementSize(kMkvTrackUID, uid_); |
| 628 size += EbmlElementSize(kMkvTrackType, type_); | 685 size += EbmlElementSize(kMkvTrackType, type_); |
| 629 if (codec_id_) | 686 if (codec_id_) |
| 630 size += EbmlElementSize(kMkvCodecID, codec_id_); | 687 size += EbmlElementSize(kMkvCodecID, codec_id_); |
| 631 if (codec_private_) | 688 if (codec_private_) |
| 632 size += EbmlElementSize(kMkvCodecPrivate, codec_private_, | 689 size += EbmlElementSize(kMkvCodecPrivate, codec_private_, |
| 633 codec_private_length_); | 690 codec_private_length_); |
| 634 if (language_) | 691 if (language_) |
| 635 size += EbmlElementSize(kMkvLanguage, language_); | 692 size += EbmlElementSize(kMkvLanguage, language_); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 786 } | 843 } |
| 787 | 844 |
| 788 /////////////////////////////////////////////////////////////// | 845 /////////////////////////////////////////////////////////////// |
| 789 // | 846 // |
| 790 // VideoTrack Class | 847 // VideoTrack Class |
| 791 | 848 |
| 792 VideoTrack::VideoTrack(unsigned int* seed) | 849 VideoTrack::VideoTrack(unsigned int* seed) |
| 793 : Track(seed), | 850 : Track(seed), |
| 794 display_height_(0), | 851 display_height_(0), |
| 795 display_width_(0), | 852 display_width_(0), |
| 853 crop_left_(0), |
| 854 crop_right_(0), |
| 855 crop_top_(0), |
| 856 crop_bottom_(0), |
| 796 frame_rate_(0.0), | 857 frame_rate_(0.0), |
| 797 height_(0), | 858 height_(0), |
| 798 stereo_mode_(0), | 859 stereo_mode_(0), |
| 799 alpha_mode_(0), | 860 alpha_mode_(0), |
| 800 width_(0) {} | 861 width_(0) {} |
| 801 | 862 |
| 802 VideoTrack::~VideoTrack() {} | 863 VideoTrack::~VideoTrack() {} |
| 803 | 864 |
| 804 bool VideoTrack::SetStereoMode(uint64 stereo_mode) { | 865 bool VideoTrack::SetStereoMode(uint64 stereo_mode) { |
| 805 if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst && | 866 if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst && |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 839 return false; | 900 return false; |
| 840 | 901 |
| 841 const int64 payload_position = writer->Position(); | 902 const int64 payload_position = writer->Position(); |
| 842 if (payload_position < 0) | 903 if (payload_position < 0) |
| 843 return false; | 904 return false; |
| 844 | 905 |
| 845 if (!WriteEbmlElement(writer, kMkvPixelWidth, width_)) | 906 if (!WriteEbmlElement(writer, kMkvPixelWidth, width_)) |
| 846 return false; | 907 return false; |
| 847 if (!WriteEbmlElement(writer, kMkvPixelHeight, height_)) | 908 if (!WriteEbmlElement(writer, kMkvPixelHeight, height_)) |
| 848 return false; | 909 return false; |
| 849 if (display_width_ > 0) | 910 if (display_width_ > 0) { |
| 850 if (!WriteEbmlElement(writer, kMkvDisplayWidth, display_width_)) | 911 if (!WriteEbmlElement(writer, kMkvDisplayWidth, display_width_)) |
| 851 return false; | 912 return false; |
| 852 if (display_height_ > 0) | 913 } |
| 914 if (display_height_ > 0) { |
| 853 if (!WriteEbmlElement(writer, kMkvDisplayHeight, display_height_)) | 915 if (!WriteEbmlElement(writer, kMkvDisplayHeight, display_height_)) |
| 854 return false; | 916 return false; |
| 855 if (stereo_mode_ > kMono) | 917 } |
| 918 if (crop_left_ > 0) { |
| 919 if (!WriteEbmlElement(writer, kMkvPixelCropLeft, crop_left_)) |
| 920 return false; |
| 921 } |
| 922 if (crop_right_ > 0) { |
| 923 if (!WriteEbmlElement(writer, kMkvPixelCropRight, crop_right_)) |
| 924 return false; |
| 925 } |
| 926 if (crop_top_ > 0) { |
| 927 if (!WriteEbmlElement(writer, kMkvPixelCropTop, crop_top_)) |
| 928 return false; |
| 929 } |
| 930 if (crop_bottom_ > 0) { |
| 931 if (!WriteEbmlElement(writer, kMkvPixelCropBottom, crop_bottom_)) |
| 932 return false; |
| 933 } |
| 934 if (stereo_mode_ > kMono) { |
| 856 if (!WriteEbmlElement(writer, kMkvStereoMode, stereo_mode_)) | 935 if (!WriteEbmlElement(writer, kMkvStereoMode, stereo_mode_)) |
| 857 return false; | 936 return false; |
| 858 if (alpha_mode_ > kNoAlpha) | 937 } |
| 938 if (alpha_mode_ > kNoAlpha) { |
| 859 if (!WriteEbmlElement(writer, kMkvAlphaMode, alpha_mode_)) | 939 if (!WriteEbmlElement(writer, kMkvAlphaMode, alpha_mode_)) |
| 860 return false; | 940 return false; |
| 861 if (frame_rate_ > 0.0) | 941 } |
| 942 if (frame_rate_ > 0.0) { |
| 862 if (!WriteEbmlElement(writer, kMkvFrameRate, | 943 if (!WriteEbmlElement(writer, kMkvFrameRate, |
| 863 static_cast<float>(frame_rate_))) | 944 static_cast<float>(frame_rate_))) { |
| 864 return false; | 945 return false; |
| 946 } |
| 947 } |
| 865 | 948 |
| 866 const int64 stop_position = writer->Position(); | 949 const int64 stop_position = writer->Position(); |
| 867 if (stop_position < 0 || | 950 if (stop_position < 0 || |
| 868 stop_position - payload_position != static_cast<int64>(size)) | 951 stop_position - payload_position != static_cast<int64>(size)) { |
| 869 return false; | 952 return false; |
| 953 } |
| 870 | 954 |
| 871 return true; | 955 return true; |
| 872 } | 956 } |
| 873 | 957 |
| 874 uint64 VideoTrack::VideoPayloadSize() const { | 958 uint64 VideoTrack::VideoPayloadSize() const { |
| 875 uint64 size = EbmlElementSize(kMkvPixelWidth, width_); | 959 uint64 size = EbmlElementSize(kMkvPixelWidth, width_); |
| 876 size += EbmlElementSize(kMkvPixelHeight, height_); | 960 size += EbmlElementSize(kMkvPixelHeight, height_); |
| 877 if (display_width_ > 0) | 961 if (display_width_ > 0) |
| 878 size += EbmlElementSize(kMkvDisplayWidth, display_width_); | 962 size += EbmlElementSize(kMkvDisplayWidth, display_width_); |
| 879 if (display_height_ > 0) | 963 if (display_height_ > 0) |
| 880 size += EbmlElementSize(kMkvDisplayHeight, display_height_); | 964 size += EbmlElementSize(kMkvDisplayHeight, display_height_); |
| 965 if (crop_left_ > 0) |
| 966 size += EbmlElementSize(kMkvPixelCropLeft, crop_left_); |
| 967 if (crop_right_ > 0) |
| 968 size += EbmlElementSize(kMkvPixelCropRight, crop_right_); |
| 969 if (crop_top_ > 0) |
| 970 size += EbmlElementSize(kMkvPixelCropTop, crop_top_); |
| 971 if (crop_bottom_ > 0) |
| 972 size += EbmlElementSize(kMkvPixelCropBottom, crop_bottom_); |
| 881 if (stereo_mode_ > kMono) | 973 if (stereo_mode_ > kMono) |
| 882 size += EbmlElementSize(kMkvStereoMode, stereo_mode_); | 974 size += EbmlElementSize(kMkvStereoMode, stereo_mode_); |
| 883 if (alpha_mode_ > kNoAlpha) | 975 if (alpha_mode_ > kNoAlpha) |
| 884 size += EbmlElementSize(kMkvAlphaMode, alpha_mode_); | 976 size += EbmlElementSize(kMkvAlphaMode, alpha_mode_); |
| 885 if (frame_rate_ > 0.0) | 977 if (frame_rate_ > 0.0) |
| 886 size += EbmlElementSize(kMkvFrameRate, static_cast<float>(frame_rate_)); | 978 size += EbmlElementSize(kMkvFrameRate, static_cast<float>(frame_rate_)); |
| 887 | 979 |
| 888 return size; | 980 return size; |
| 889 } | 981 } |
| 890 | 982 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 946 } | 1038 } |
| 947 | 1039 |
| 948 /////////////////////////////////////////////////////////////// | 1040 /////////////////////////////////////////////////////////////// |
| 949 // | 1041 // |
| 950 // Tracks Class | 1042 // Tracks Class |
| 951 | 1043 |
| 952 const char Tracks::kOpusCodecId[] = "A_OPUS"; | 1044 const char Tracks::kOpusCodecId[] = "A_OPUS"; |
| 953 const char Tracks::kVorbisCodecId[] = "A_VORBIS"; | 1045 const char Tracks::kVorbisCodecId[] = "A_VORBIS"; |
| 954 const char Tracks::kVp8CodecId[] = "V_VP8"; | 1046 const char Tracks::kVp8CodecId[] = "V_VP8"; |
| 955 const char Tracks::kVp9CodecId[] = "V_VP9"; | 1047 const char Tracks::kVp9CodecId[] = "V_VP9"; |
| 1048 const char Tracks::kVp10CodecId[] = "V_VP10"; |
| 956 | 1049 |
| 957 Tracks::Tracks() : track_entries_(NULL), track_entries_size_(0) {} | 1050 Tracks::Tracks() : track_entries_(NULL), track_entries_size_(0) {} |
| 958 | 1051 |
| 959 Tracks::~Tracks() { | 1052 Tracks::~Tracks() { |
| 960 if (track_entries_) { | 1053 if (track_entries_) { |
| 961 for (uint32 i = 0; i < track_entries_size_; ++i) { | 1054 for (uint32 i = 0; i < track_entries_size_; ++i) { |
| 962 Track* const track = track_entries_[i]; | 1055 Track* const track = track_entries_[i]; |
| 963 delete track; | 1056 delete track; |
| 964 } | 1057 } |
| 965 delete[] track_entries_; | 1058 delete[] track_entries_; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 983 if (track_num > 0) { | 1076 if (track_num > 0) { |
| 984 // Check to make sure a track does not already have |track_num|. | 1077 // Check to make sure a track does not already have |track_num|. |
| 985 for (uint32 i = 0; i < track_entries_size_; ++i) { | 1078 for (uint32 i = 0; i < track_entries_size_; ++i) { |
| 986 if (track_entries_[i]->number() == track_num) | 1079 if (track_entries_[i]->number() == track_num) |
| 987 return false; | 1080 return false; |
| 988 } | 1081 } |
| 989 } | 1082 } |
| 990 | 1083 |
| 991 const uint32 count = track_entries_size_ + 1; | 1084 const uint32 count = track_entries_size_ + 1; |
| 992 | 1085 |
| 993 Track** const track_entries = new (std::nothrow) Track* [count]; // NOLINT | 1086 Track** const track_entries = new (std::nothrow) Track*[count]; // NOLINT |
| 994 if (!track_entries) | 1087 if (!track_entries) |
| 995 return false; | 1088 return false; |
| 996 | 1089 |
| 997 for (uint32 i = 0; i < track_entries_size_; ++i) { | 1090 for (uint32 i = 0; i < track_entries_size_; ++i) { |
| 998 track_entries[i] = track_entries_[i]; | 1091 track_entries[i] = track_entries_[i]; |
| 999 } | 1092 } |
| 1000 | 1093 |
| 1001 delete[] track_entries_; | 1094 delete[] track_entries_; |
| 1002 | 1095 |
| 1003 // Find the lowest availible track number > 0. | 1096 // Find the lowest availible track number > 0. |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1138 // only to the Chapters class). Doing no initialization here also | 1231 // only to the Chapters class). Doing no initialization here also |
| 1139 // means that creating arrays of chapter objects is more efficient, | 1232 // means that creating arrays of chapter objects is more efficient, |
| 1140 // because we only initialize each new chapter object as it becomes | 1233 // because we only initialize each new chapter object as it becomes |
| 1141 // active on the array. | 1234 // active on the array. |
| 1142 } | 1235 } |
| 1143 | 1236 |
| 1144 Chapter::~Chapter() {} | 1237 Chapter::~Chapter() {} |
| 1145 | 1238 |
| 1146 void Chapter::Init(unsigned int* seed) { | 1239 void Chapter::Init(unsigned int* seed) { |
| 1147 id_ = NULL; | 1240 id_ = NULL; |
| 1241 start_timecode_ = 0; |
| 1242 end_timecode_ = 0; |
| 1148 displays_ = NULL; | 1243 displays_ = NULL; |
| 1149 displays_size_ = 0; | 1244 displays_size_ = 0; |
| 1150 displays_count_ = 0; | 1245 displays_count_ = 0; |
| 1151 uid_ = MakeUID(seed); | 1246 uid_ = MakeUID(seed); |
| 1152 } | 1247 } |
| 1153 | 1248 |
| 1154 void Chapter::ShallowCopy(Chapter* dst) const { | 1249 void Chapter::ShallowCopy(Chapter* dst) const { |
| 1155 dst->id_ = id_; | 1250 dst->id_ = id_; |
| 1156 dst->start_timecode_ = start_timecode_; | 1251 dst->start_timecode_ = start_timecode_; |
| 1157 dst->end_timecode_ = end_timecode_; | 1252 dst->end_timecode_ = end_timecode_; |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1413 } | 1508 } |
| 1414 | 1509 |
| 1415 const int64 stop = writer->Position(); | 1510 const int64 stop = writer->Position(); |
| 1416 | 1511 |
| 1417 if (stop >= start && uint64(stop - start) != edition_size) | 1512 if (stop >= start && uint64(stop - start) != edition_size) |
| 1418 return 0; | 1513 return 0; |
| 1419 | 1514 |
| 1420 return edition_size; | 1515 return edition_size; |
| 1421 } | 1516 } |
| 1422 | 1517 |
| 1518 // Tag Class |
| 1519 |
| 1520 bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) { |
| 1521 if (!ExpandSimpleTagsArray()) |
| 1522 return false; |
| 1523 |
| 1524 SimpleTag& st = simple_tags_[simple_tags_count_++]; |
| 1525 st.Init(); |
| 1526 |
| 1527 if (!st.set_tag_name(tag_name)) |
| 1528 return false; |
| 1529 |
| 1530 if (!st.set_tag_string(tag_string)) |
| 1531 return false; |
| 1532 |
| 1533 return true; |
| 1534 } |
| 1535 |
| 1536 Tag::Tag() { |
| 1537 simple_tags_ = NULL; |
| 1538 simple_tags_size_ = 0; |
| 1539 simple_tags_count_ = 0; |
| 1540 } |
| 1541 |
| 1542 Tag::~Tag() {} |
| 1543 |
| 1544 void Tag::ShallowCopy(Tag* dst) const { |
| 1545 dst->simple_tags_ = simple_tags_; |
| 1546 dst->simple_tags_size_ = simple_tags_size_; |
| 1547 dst->simple_tags_count_ = simple_tags_count_; |
| 1548 } |
| 1549 |
| 1550 void Tag::Clear() { |
| 1551 while (simple_tags_count_ > 0) { |
| 1552 SimpleTag& st = simple_tags_[--simple_tags_count_]; |
| 1553 st.Clear(); |
| 1554 } |
| 1555 |
| 1556 delete[] simple_tags_; |
| 1557 simple_tags_ = NULL; |
| 1558 |
| 1559 simple_tags_size_ = 0; |
| 1560 } |
| 1561 |
| 1562 bool Tag::ExpandSimpleTagsArray() { |
| 1563 if (simple_tags_size_ > simple_tags_count_) |
| 1564 return true; // nothing to do yet |
| 1565 |
| 1566 const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_; |
| 1567 |
| 1568 SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size]; // NOLINT |
| 1569 if (simple_tags == NULL) |
| 1570 return false; |
| 1571 |
| 1572 for (int idx = 0; idx < simple_tags_count_; ++idx) { |
| 1573 simple_tags[idx] = simple_tags_[idx]; // shallow copy |
| 1574 } |
| 1575 |
| 1576 delete[] simple_tags_; |
| 1577 |
| 1578 simple_tags_ = simple_tags; |
| 1579 simple_tags_size_ = size; |
| 1580 |
| 1581 return true; |
| 1582 } |
| 1583 |
| 1584 uint64 Tag::Write(IMkvWriter* writer) const { |
| 1585 uint64 payload_size = 0; |
| 1586 |
| 1587 for (int idx = 0; idx < simple_tags_count_; ++idx) { |
| 1588 const SimpleTag& st = simple_tags_[idx]; |
| 1589 payload_size += st.Write(NULL); |
| 1590 } |
| 1591 |
| 1592 const uint64 tag_size = |
| 1593 EbmlMasterElementSize(kMkvTag, payload_size) + payload_size; |
| 1594 |
| 1595 if (writer == NULL) |
| 1596 return tag_size; |
| 1597 |
| 1598 const int64 start = writer->Position(); |
| 1599 |
| 1600 if (!WriteEbmlMasterElement(writer, kMkvTag, payload_size)) |
| 1601 return 0; |
| 1602 |
| 1603 for (int idx = 0; idx < simple_tags_count_; ++idx) { |
| 1604 const SimpleTag& st = simple_tags_[idx]; |
| 1605 |
| 1606 if (!st.Write(writer)) |
| 1607 return 0; |
| 1608 } |
| 1609 |
| 1610 const int64 stop = writer->Position(); |
| 1611 |
| 1612 if (stop >= start && uint64(stop - start) != tag_size) |
| 1613 return 0; |
| 1614 |
| 1615 return tag_size; |
| 1616 } |
| 1617 |
| 1618 // Tag::SimpleTag |
| 1619 |
| 1620 void Tag::SimpleTag::Init() { |
| 1621 tag_name_ = NULL; |
| 1622 tag_string_ = NULL; |
| 1623 } |
| 1624 |
| 1625 void Tag::SimpleTag::Clear() { |
| 1626 StrCpy(NULL, &tag_name_); |
| 1627 StrCpy(NULL, &tag_string_); |
| 1628 } |
| 1629 |
| 1630 bool Tag::SimpleTag::set_tag_name(const char* tag_name) { |
| 1631 return StrCpy(tag_name, &tag_name_); |
| 1632 } |
| 1633 |
| 1634 bool Tag::SimpleTag::set_tag_string(const char* tag_string) { |
| 1635 return StrCpy(tag_string, &tag_string_); |
| 1636 } |
| 1637 |
| 1638 uint64 Tag::SimpleTag::Write(IMkvWriter* writer) const { |
| 1639 uint64 payload_size = EbmlElementSize(kMkvTagName, tag_name_); |
| 1640 |
| 1641 payload_size += EbmlElementSize(kMkvTagString, tag_string_); |
| 1642 |
| 1643 const uint64 simple_tag_size = |
| 1644 EbmlMasterElementSize(kMkvSimpleTag, payload_size) + payload_size; |
| 1645 |
| 1646 if (writer == NULL) |
| 1647 return simple_tag_size; |
| 1648 |
| 1649 const int64 start = writer->Position(); |
| 1650 |
| 1651 if (!WriteEbmlMasterElement(writer, kMkvSimpleTag, payload_size)) |
| 1652 return 0; |
| 1653 |
| 1654 if (!WriteEbmlElement(writer, kMkvTagName, tag_name_)) |
| 1655 return 0; |
| 1656 |
| 1657 if (!WriteEbmlElement(writer, kMkvTagString, tag_string_)) |
| 1658 return 0; |
| 1659 |
| 1660 const int64 stop = writer->Position(); |
| 1661 |
| 1662 if (stop >= start && uint64(stop - start) != simple_tag_size) |
| 1663 return 0; |
| 1664 |
| 1665 return simple_tag_size; |
| 1666 } |
| 1667 |
| 1668 // Tags Class |
| 1669 |
| 1670 Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {} |
| 1671 |
| 1672 Tags::~Tags() { |
| 1673 while (tags_count_ > 0) { |
| 1674 Tag& tag = tags_[--tags_count_]; |
| 1675 tag.Clear(); |
| 1676 } |
| 1677 |
| 1678 delete[] tags_; |
| 1679 tags_ = NULL; |
| 1680 } |
| 1681 |
| 1682 int Tags::Count() const { return tags_count_; } |
| 1683 |
| 1684 Tag* Tags::AddTag() { |
| 1685 if (!ExpandTagsArray()) |
| 1686 return NULL; |
| 1687 |
| 1688 Tag& tag = tags_[tags_count_++]; |
| 1689 |
| 1690 return &tag; |
| 1691 } |
| 1692 |
| 1693 bool Tags::Write(IMkvWriter* writer) const { |
| 1694 if (writer == NULL) |
| 1695 return false; |
| 1696 |
| 1697 uint64 payload_size = 0; |
| 1698 |
| 1699 for (int idx = 0; idx < tags_count_; ++idx) { |
| 1700 const Tag& tag = tags_[idx]; |
| 1701 payload_size += tag.Write(NULL); |
| 1702 } |
| 1703 |
| 1704 if (!WriteEbmlMasterElement(writer, kMkvTags, payload_size)) |
| 1705 return false; |
| 1706 |
| 1707 const int64 start = writer->Position(); |
| 1708 |
| 1709 for (int idx = 0; idx < tags_count_; ++idx) { |
| 1710 const Tag& tag = tags_[idx]; |
| 1711 |
| 1712 const uint64 tag_size = tag.Write(writer); |
| 1713 if (tag_size == 0) // error |
| 1714 return 0; |
| 1715 } |
| 1716 |
| 1717 const int64 stop = writer->Position(); |
| 1718 |
| 1719 if (stop >= start && uint64(stop - start) != payload_size) |
| 1720 return false; |
| 1721 |
| 1722 return true; |
| 1723 } |
| 1724 |
| 1725 bool Tags::ExpandTagsArray() { |
| 1726 if (tags_size_ > tags_count_) |
| 1727 return true; // nothing to do yet |
| 1728 |
| 1729 const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_; |
| 1730 |
| 1731 Tag* const tags = new (std::nothrow) Tag[size]; // NOLINT |
| 1732 if (tags == NULL) |
| 1733 return false; |
| 1734 |
| 1735 for (int idx = 0; idx < tags_count_; ++idx) { |
| 1736 const Tag& src = tags_[idx]; |
| 1737 Tag* const dst = tags + idx; |
| 1738 src.ShallowCopy(dst); |
| 1739 } |
| 1740 |
| 1741 delete[] tags_; |
| 1742 |
| 1743 tags_ = tags; |
| 1744 tags_size_ = size; |
| 1745 |
| 1746 return true; |
| 1747 } |
| 1748 |
| 1423 /////////////////////////////////////////////////////////////// | 1749 /////////////////////////////////////////////////////////////// |
| 1424 // | 1750 // |
| 1425 // Cluster class | 1751 // Cluster class |
| 1426 | 1752 |
| 1427 Cluster::Cluster(uint64 timecode, int64 cues_pos) | 1753 Cluster::Cluster(uint64 timecode, int64 cues_pos, uint64 timecode_scale) |
| 1428 : blocks_added_(0), | 1754 : blocks_added_(0), |
| 1429 finalized_(false), | 1755 finalized_(false), |
| 1430 header_written_(false), | 1756 header_written_(false), |
| 1431 payload_size_(0), | 1757 payload_size_(0), |
| 1432 position_for_cues_(cues_pos), | 1758 position_for_cues_(cues_pos), |
| 1433 size_position_(-1), | 1759 size_position_(-1), |
| 1434 timecode_(timecode), | 1760 timecode_(timecode), |
| 1761 timecode_scale_(timecode_scale), |
| 1435 writer_(NULL) {} | 1762 writer_(NULL) {} |
| 1436 | 1763 |
| 1437 Cluster::~Cluster() {} | 1764 Cluster::~Cluster() {} |
| 1438 | 1765 |
| 1439 bool Cluster::Init(IMkvWriter* ptr_writer) { | 1766 bool Cluster::Init(IMkvWriter* ptr_writer) { |
| 1440 if (!ptr_writer) { | 1767 if (!ptr_writer) { |
| 1441 return false; | 1768 return false; |
| 1442 } | 1769 } |
| 1443 writer_ = ptr_writer; | 1770 writer_ = ptr_writer; |
| 1444 return true; | 1771 return true; |
| 1445 } | 1772 } |
| 1446 | 1773 |
| 1447 bool Cluster::AddFrame(const uint8* frame, uint64 length, uint64 track_number, | 1774 bool Cluster::AddFrame(const Frame* const frame) { return DoWriteFrame(frame); } |
| 1775 |
| 1776 bool Cluster::AddFrame(const uint8* data, uint64 length, uint64 track_number, |
| 1448 uint64 abs_timecode, bool is_key) { | 1777 uint64 abs_timecode, bool is_key) { |
| 1449 return DoWriteBlock(frame, length, track_number, abs_timecode, is_key ? 1 : 0, | 1778 Frame frame; |
| 1450 &WriteSimpleBlock); | 1779 if (!frame.Init(data, length)) |
| 1780 return false; |
| 1781 frame.set_track_number(track_number); |
| 1782 frame.set_timestamp(abs_timecode); |
| 1783 frame.set_is_key(is_key); |
| 1784 return DoWriteFrame(&frame); |
| 1451 } | 1785 } |
| 1452 | 1786 |
| 1453 bool Cluster::AddFrameWithAdditional(const uint8* frame, uint64 length, | 1787 bool Cluster::AddFrameWithAdditional(const uint8* data, uint64 length, |
| 1454 const uint8* additional, | 1788 const uint8* additional, |
| 1455 uint64 additional_length, uint64 add_id, | 1789 uint64 additional_length, uint64 add_id, |
| 1456 uint64 track_number, uint64 abs_timecode, | 1790 uint64 track_number, uint64 abs_timecode, |
| 1457 bool is_key) { | 1791 bool is_key) { |
| 1458 return DoWriteBlockWithAdditional( | 1792 if (!additional || additional_length == 0) { |
| 1459 frame, length, additional, additional_length, add_id, track_number, | 1793 return false; |
| 1460 abs_timecode, is_key ? 1 : 0, &WriteBlockWithAdditional); | 1794 } |
| 1795 Frame frame; |
| 1796 if (!frame.Init(data, length) || |
| 1797 !frame.AddAdditionalData(additional, additional_length, add_id)) { |
| 1798 return false; |
| 1799 } |
| 1800 frame.set_track_number(track_number); |
| 1801 frame.set_timestamp(abs_timecode); |
| 1802 frame.set_is_key(is_key); |
| 1803 return DoWriteFrame(&frame); |
| 1461 } | 1804 } |
| 1462 | 1805 |
| 1463 bool Cluster::AddFrameWithDiscardPadding(const uint8* frame, uint64 length, | 1806 bool Cluster::AddFrameWithDiscardPadding(const uint8* data, uint64 length, |
| 1464 int64 discard_padding, | 1807 int64 discard_padding, |
| 1465 uint64 track_number, | 1808 uint64 track_number, |
| 1466 uint64 abs_timecode, bool is_key) { | 1809 uint64 abs_timecode, bool is_key) { |
| 1467 return DoWriteBlockWithDiscardPadding( | 1810 Frame frame; |
| 1468 frame, length, discard_padding, track_number, abs_timecode, | 1811 if (!frame.Init(data, length)) |
| 1469 is_key ? 1 : 0, &WriteBlockWithDiscardPadding); | 1812 return false; |
| 1813 frame.set_discard_padding(discard_padding); |
| 1814 frame.set_track_number(track_number); |
| 1815 frame.set_timestamp(abs_timecode); |
| 1816 frame.set_is_key(is_key); |
| 1817 return DoWriteFrame(&frame); |
| 1470 } | 1818 } |
| 1471 | 1819 |
| 1472 bool Cluster::AddMetadata(const uint8* frame, uint64 length, | 1820 bool Cluster::AddMetadata(const uint8* data, uint64 length, uint64 track_number, |
| 1473 uint64 track_number, uint64 abs_timecode, | 1821 uint64 abs_timecode, uint64 duration_timecode) { |
| 1474 uint64 duration_timecode) { | 1822 Frame frame; |
| 1475 return DoWriteBlock(frame, length, track_number, abs_timecode, | 1823 if (!frame.Init(data, length)) |
| 1476 duration_timecode, &WriteMetadataBlock); | 1824 return false; |
| 1825 frame.set_track_number(track_number); |
| 1826 frame.set_timestamp(abs_timecode); |
| 1827 frame.set_duration(duration_timecode); |
| 1828 frame.set_is_key(true); // All metadata blocks are keyframes. |
| 1829 return DoWriteFrame(&frame); |
| 1477 } | 1830 } |
| 1478 | 1831 |
| 1479 void Cluster::AddPayloadSize(uint64 size) { payload_size_ += size; } | 1832 void Cluster::AddPayloadSize(uint64 size) { payload_size_ += size; } |
| 1480 | 1833 |
| 1481 bool Cluster::Finalize() { | 1834 bool Cluster::Finalize() { |
| 1482 if (!writer_ || finalized_ || size_position_ == -1) | 1835 if (!writer_ || finalized_ || size_position_ == -1) |
| 1483 return false; | 1836 return false; |
| 1484 | 1837 |
| 1485 if (writer_->Seekable()) { | 1838 if (writer_->Seekable()) { |
| 1486 const int64 pos = writer_->Position(); | 1839 const int64 pos = writer_->Position(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1499 | 1852 |
| 1500 return true; | 1853 return true; |
| 1501 } | 1854 } |
| 1502 | 1855 |
| 1503 uint64 Cluster::Size() const { | 1856 uint64 Cluster::Size() const { |
| 1504 const uint64 element_size = | 1857 const uint64 element_size = |
| 1505 EbmlMasterElementSize(kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) + payload_size_; | 1858 EbmlMasterElementSize(kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) + payload_size_; |
| 1506 return element_size; | 1859 return element_size; |
| 1507 } | 1860 } |
| 1508 | 1861 |
| 1509 template <typename Type> | 1862 bool Cluster::PreWriteBlock() { |
| 1510 bool Cluster::PreWriteBlock(Type* write_function) { | |
| 1511 if (write_function == NULL) | |
| 1512 return false; | |
| 1513 | |
| 1514 if (finalized_) | 1863 if (finalized_) |
| 1515 return false; | 1864 return false; |
| 1516 | 1865 |
| 1517 if (!header_written_) { | 1866 if (!header_written_) { |
| 1518 if (!WriteClusterHeader()) | 1867 if (!WriteClusterHeader()) |
| 1519 return false; | 1868 return false; |
| 1520 } | 1869 } |
| 1521 | 1870 |
| 1522 return true; | 1871 return true; |
| 1523 } | 1872 } |
| 1524 | 1873 |
| 1525 void Cluster::PostWriteBlock(uint64 element_size) { | 1874 void Cluster::PostWriteBlock(uint64 element_size) { |
| 1526 AddPayloadSize(element_size); | 1875 AddPayloadSize(element_size); |
| 1527 ++blocks_added_; | 1876 ++blocks_added_; |
| 1528 } | 1877 } |
| 1529 | 1878 |
| 1530 bool Cluster::IsValidTrackNumber(uint64 track_number) const { | |
| 1531 return (track_number > 0 && track_number <= 0x7E); | |
| 1532 } | |
| 1533 | |
| 1534 int64 Cluster::GetRelativeTimecode(int64 abs_timecode) const { | 1879 int64 Cluster::GetRelativeTimecode(int64 abs_timecode) const { |
| 1535 const int64 cluster_timecode = this->Cluster::timecode(); | 1880 const int64 cluster_timecode = this->Cluster::timecode(); |
| 1536 const int64 rel_timecode = | 1881 const int64 rel_timecode = |
| 1537 static_cast<int64>(abs_timecode) - cluster_timecode; | 1882 static_cast<int64>(abs_timecode) - cluster_timecode; |
| 1538 | 1883 |
| 1539 if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode) | 1884 if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode) |
| 1540 return -1; | 1885 return -1; |
| 1541 | 1886 |
| 1542 return rel_timecode; | 1887 return rel_timecode; |
| 1543 } | 1888 } |
| 1544 | 1889 |
| 1545 bool Cluster::DoWriteBlock(const uint8* frame, uint64 length, | 1890 bool Cluster::DoWriteFrame(const Frame* const frame) { |
| 1546 uint64 track_number, uint64 abs_timecode, | 1891 if (!frame || !frame->IsValid()) |
| 1547 uint64 generic_arg, WriteBlock write_block) { | |
| 1548 if (frame == NULL || length == 0) | |
| 1549 return false; | 1892 return false; |
| 1550 | 1893 |
| 1551 if (!IsValidTrackNumber(track_number)) | 1894 if (!PreWriteBlock()) |
| 1552 return false; | 1895 return false; |
| 1553 | 1896 |
| 1554 const int64 rel_timecode = GetRelativeTimecode(abs_timecode); | 1897 const uint64 element_size = WriteFrame(writer_, frame, this); |
| 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) | 1898 if (element_size == 0) |
| 1564 return false; | 1899 return false; |
| 1565 | 1900 |
| 1566 PostWriteBlock(element_size); | |
| 1567 return true; | |
| 1568 } | |
| 1569 | |
| 1570 bool 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 | |
| 1598 bool 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); | 1901 PostWriteBlock(element_size); |
| 1622 return true; | 1902 return true; |
| 1623 } | 1903 } |
| 1624 | 1904 |
| 1625 bool Cluster::WriteClusterHeader() { | 1905 bool Cluster::WriteClusterHeader() { |
| 1626 if (finalized_) | 1906 if (finalized_) |
| 1627 return false; | 1907 return false; |
| 1628 | 1908 |
| 1629 if (WriteID(writer_, kMkvCluster)) | 1909 if (WriteID(writer_, kMkvCluster)) |
| 1630 return false; | 1910 return false; |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1853 } | 2133 } |
| 1854 | 2134 |
| 1855 bool SegmentInfo::Write(IMkvWriter* writer) { | 2135 bool SegmentInfo::Write(IMkvWriter* writer) { |
| 1856 if (!writer || !muxing_app_ || !writing_app_) | 2136 if (!writer || !muxing_app_ || !writing_app_) |
| 1857 return false; | 2137 return false; |
| 1858 | 2138 |
| 1859 uint64 size = EbmlElementSize(kMkvTimecodeScale, timecode_scale_); | 2139 uint64 size = EbmlElementSize(kMkvTimecodeScale, timecode_scale_); |
| 1860 if (duration_ > 0.0) | 2140 if (duration_ > 0.0) |
| 1861 size += EbmlElementSize(kMkvDuration, static_cast<float>(duration_)); | 2141 size += EbmlElementSize(kMkvDuration, static_cast<float>(duration_)); |
| 1862 if (date_utc_ != LLONG_MIN) | 2142 if (date_utc_ != LLONG_MIN) |
| 1863 size += EbmlDateElementSize(kMkvDateUTC, date_utc_); | 2143 size += EbmlDateElementSize(kMkvDateUTC); |
| 1864 size += EbmlElementSize(kMkvMuxingApp, muxing_app_); | 2144 size += EbmlElementSize(kMkvMuxingApp, muxing_app_); |
| 1865 size += EbmlElementSize(kMkvWritingApp, writing_app_); | 2145 size += EbmlElementSize(kMkvWritingApp, writing_app_); |
| 1866 | 2146 |
| 1867 if (!WriteEbmlMasterElement(writer, kMkvInfo, size)) | 2147 if (!WriteEbmlMasterElement(writer, kMkvInfo, size)) |
| 1868 return false; | 2148 return false; |
| 1869 | 2149 |
| 1870 const int64 payload_position = writer->Position(); | 2150 const int64 payload_position = writer->Position(); |
| 1871 if (payload_position < 0) | 2151 if (payload_position < 0) |
| 1872 return false; | 2152 return false; |
| 1873 | 2153 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1959 header_written_(false), | 2239 header_written_(false), |
| 1960 last_block_duration_(0), | 2240 last_block_duration_(0), |
| 1961 last_timestamp_(0), | 2241 last_timestamp_(0), |
| 1962 max_cluster_duration_(kDefaultMaxClusterDuration), | 2242 max_cluster_duration_(kDefaultMaxClusterDuration), |
| 1963 max_cluster_size_(0), | 2243 max_cluster_size_(0), |
| 1964 mode_(kFile), | 2244 mode_(kFile), |
| 1965 new_cuepoint_(false), | 2245 new_cuepoint_(false), |
| 1966 output_cues_(true), | 2246 output_cues_(true), |
| 1967 payload_pos_(0), | 2247 payload_pos_(0), |
| 1968 size_position_(0), | 2248 size_position_(0), |
| 2249 doc_type_version_(kDefaultDocTypeVersion), |
| 2250 doc_type_version_written_(0), |
| 1969 writer_cluster_(NULL), | 2251 writer_cluster_(NULL), |
| 1970 writer_cues_(NULL), | 2252 writer_cues_(NULL), |
| 1971 writer_header_(NULL) { | 2253 writer_header_(NULL) { |
| 1972 const time_t curr_time = time(NULL); | 2254 const time_t curr_time = time(NULL); |
| 1973 seed_ = static_cast<unsigned int>(curr_time); | 2255 seed_ = static_cast<unsigned int>(curr_time); |
| 1974 #ifdef _WIN32 | 2256 #ifdef _WIN32 |
| 1975 srand(seed_); | 2257 srand(seed_); |
| 1976 #endif | 2258 #endif |
| 1977 } | 2259 } |
| 1978 | 2260 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2005 delete chunk_writer_cues_; | 2287 delete chunk_writer_cues_; |
| 2006 } | 2288 } |
| 2007 if (chunk_writer_header_) { | 2289 if (chunk_writer_header_) { |
| 2008 chunk_writer_header_->Close(); | 2290 chunk_writer_header_->Close(); |
| 2009 delete chunk_writer_header_; | 2291 delete chunk_writer_header_; |
| 2010 } | 2292 } |
| 2011 } | 2293 } |
| 2012 | 2294 |
| 2013 void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index, | 2295 void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index, |
| 2014 uint64* cues_size) { | 2296 uint64* cues_size) { |
| 2015 const uint64 old_cues_size = *cues_size; | |
| 2016 CuePoint* const cue_point = cues_.GetCueByIndex(index); | 2297 CuePoint* const cue_point = cues_.GetCueByIndex(index); |
| 2017 if (cue_point == NULL) | 2298 if (cue_point == NULL) |
| 2018 return; | 2299 return; |
| 2019 const uint64 old_cue_point_size = cue_point->Size(); | 2300 const uint64 old_cue_point_size = cue_point->Size(); |
| 2020 const uint64 cluster_pos = cue_point->cluster_pos() + diff; | 2301 const uint64 cluster_pos = cue_point->cluster_pos() + diff; |
| 2021 cue_point->set_cluster_pos(cluster_pos); // update the new cluster position | 2302 cue_point->set_cluster_pos(cluster_pos); // update the new cluster position |
| 2022 // New size of the cue is computed as follows | 2303 // New size of the cue is computed as follows |
| 2023 // Let a = current size of Cues Element | 2304 // Let a = current sum of size of all CuePoints |
| 2024 // Let b = Difference in Cue Point's size after this pass | 2305 // Let b = Increase in Cue Point's size due to this iteration |
| 2025 // Let c = Difference in length of Cues Element's size | 2306 // Let c = Increase in size of Cues Element's length due to this iteration |
| 2026 // (This is computed as CodedSize(a + b) - CodedSize(a) | 2307 // (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 | 2308 // Let d = b + c. Now d is the |diff| passed to the next recursive call. |
| 2028 // passed on to the next recursive call. | 2309 // Let e = a + b. Now e is the |cues_size| passed to the next recursive |
| 2310 // call. |
| 2029 const uint64 cue_point_size_diff = cue_point->Size() - old_cue_point_size; | 2311 const uint64 cue_point_size_diff = cue_point->Size() - old_cue_point_size; |
| 2030 const uint64 cue_size_diff = | 2312 const uint64 cue_size_diff = |
| 2031 GetCodedUIntSize(*cues_size + cue_point_size_diff) - | 2313 GetCodedUIntSize(*cues_size + cue_point_size_diff) - |
| 2032 GetCodedUIntSize(*cues_size); | 2314 GetCodedUIntSize(*cues_size); |
| 2033 *cues_size += cue_point_size_diff + cue_size_diff; | 2315 *cues_size += cue_point_size_diff; |
| 2034 diff = *cues_size - old_cues_size; | 2316 diff = cue_size_diff + cue_point_size_diff; |
| 2035 if (diff > 0) { | 2317 if (diff > 0) { |
| 2036 for (int32 i = 0; i < cues_.cue_entries_size(); ++i) { | 2318 for (int32 i = 0; i < cues_.cue_entries_size(); ++i) { |
| 2037 MoveCuesBeforeClustersHelper(diff, i, cues_size); | 2319 MoveCuesBeforeClustersHelper(diff, i, cues_size); |
| 2038 } | 2320 } |
| 2039 } | 2321 } |
| 2040 } | 2322 } |
| 2041 | 2323 |
| 2042 void Segment::MoveCuesBeforeClusters() { | 2324 void Segment::MoveCuesBeforeClusters() { |
| 2043 const uint64 current_cue_size = cues_.Size(); | 2325 const uint64 current_cue_size = cues_.Size(); |
| 2044 uint64 cue_size = current_cue_size; | 2326 uint64 cue_size = 0; |
| 2045 for (int32 i = 0; i < cues_.cue_entries_size(); i++) | 2327 for (int32 i = 0; i < cues_.cue_entries_size(); ++i) |
| 2328 cue_size += cues_.GetCueByIndex(i)->Size(); |
| 2329 for (int32 i = 0; i < cues_.cue_entries_size(); ++i) |
| 2046 MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size); | 2330 MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size); |
| 2047 | 2331 |
| 2048 // Adjust the Seek Entry to reflect the change in position | 2332 // Adjust the Seek Entry to reflect the change in position |
| 2049 // of Cluster and Cues | 2333 // of Cluster and Cues |
| 2050 int32 cluster_index = 0; | 2334 int32 cluster_index = 0; |
| 2051 int32 cues_index = 0; | 2335 int32 cues_index = 0; |
| 2052 for (int32 i = 0; i < SeekHead::kSeekEntryCount; ++i) { | 2336 for (int32 i = 0; i < SeekHead::kSeekEntryCount; ++i) { |
| 2053 if (seek_head_.GetId(i) == kMkvCluster) | 2337 if (seek_head_.GetId(i) == kMkvCluster) |
| 2054 cluster_index = i; | 2338 cluster_index = i; |
| 2055 if (seek_head_.GetId(i) == kMkvCues) | 2339 if (seek_head_.GetId(i) == kMkvCues) |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2157 if (!cues_.Write(writer_cues_)) | 2441 if (!cues_.Write(writer_cues_)) |
| 2158 return false; | 2442 return false; |
| 2159 | 2443 |
| 2160 if (!seek_head_.Finalize(writer_header_)) | 2444 if (!seek_head_.Finalize(writer_header_)) |
| 2161 return false; | 2445 return false; |
| 2162 | 2446 |
| 2163 if (writer_header_->Seekable()) { | 2447 if (writer_header_->Seekable()) { |
| 2164 if (size_position_ == -1) | 2448 if (size_position_ == -1) |
| 2165 return false; | 2449 return false; |
| 2166 | 2450 |
| 2167 const int64 pos = writer_header_->Position(); | |
| 2168 const int64 segment_size = MaxOffset(); | 2451 const int64 segment_size = MaxOffset(); |
| 2169 | |
| 2170 if (segment_size < 1) | 2452 if (segment_size < 1) |
| 2171 return false; | 2453 return false; |
| 2172 | 2454 |
| 2455 const int64 pos = writer_header_->Position(); |
| 2456 UpdateDocTypeVersion(); |
| 2457 if (doc_type_version_ != doc_type_version_written_) { |
| 2458 if (writer_header_->Position(0)) |
| 2459 return false; |
| 2460 |
| 2461 if (!WriteEbmlHeader(writer_header_, doc_type_version_)) |
| 2462 return false; |
| 2463 if (writer_header_->Position() != ebml_header_size_) |
| 2464 return false; |
| 2465 |
| 2466 doc_type_version_written_ = doc_type_version_; |
| 2467 } |
| 2468 |
| 2173 if (writer_header_->Position(size_position_)) | 2469 if (writer_header_->Position(size_position_)) |
| 2174 return false; | 2470 return false; |
| 2175 | 2471 |
| 2176 if (WriteUIntSize(writer_header_, segment_size, 8)) | 2472 if (WriteUIntSize(writer_header_, segment_size, 8)) |
| 2177 return false; | 2473 return false; |
| 2178 | 2474 |
| 2179 if (writer_header_->Position(pos)) | 2475 if (writer_header_->Position(pos)) |
| 2180 return false; | 2476 return false; |
| 2181 } | 2477 } |
| 2182 | 2478 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2203 if (!tracks_.AddTrack(track, number)) { | 2499 if (!tracks_.AddTrack(track, number)) { |
| 2204 delete track; | 2500 delete track; |
| 2205 return NULL; | 2501 return NULL; |
| 2206 } | 2502 } |
| 2207 | 2503 |
| 2208 return track; | 2504 return track; |
| 2209 } | 2505 } |
| 2210 | 2506 |
| 2211 Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); } | 2507 Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); } |
| 2212 | 2508 |
| 2509 Tag* Segment::AddTag() { return tags_.AddTag(); } |
| 2510 |
| 2213 uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) { | 2511 uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) { |
| 2214 VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_); // NOLINT | 2512 VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_); // NOLINT |
| 2215 if (!track) | 2513 if (!track) |
| 2216 return 0; | 2514 return 0; |
| 2217 | 2515 |
| 2218 track->set_type(Tracks::kVideo); | 2516 track->set_type(Tracks::kVideo); |
| 2219 track->set_codec_id(Tracks::kVp8CodecId); | 2517 track->set_codec_id(Tracks::kVp8CodecId); |
| 2220 track->set_width(width); | 2518 track->set_width(width); |
| 2221 track->set_height(height); | 2519 track->set_height(height); |
| 2222 | 2520 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2257 track->set_type(Tracks::kAudio); | 2555 track->set_type(Tracks::kAudio); |
| 2258 track->set_codec_id(Tracks::kVorbisCodecId); | 2556 track->set_codec_id(Tracks::kVorbisCodecId); |
| 2259 track->set_sample_rate(sample_rate); | 2557 track->set_sample_rate(sample_rate); |
| 2260 track->set_channels(channels); | 2558 track->set_channels(channels); |
| 2261 | 2559 |
| 2262 tracks_.AddTrack(track, number); | 2560 tracks_.AddTrack(track, number); |
| 2263 | 2561 |
| 2264 return track->number(); | 2562 return track->number(); |
| 2265 } | 2563 } |
| 2266 | 2564 |
| 2267 bool Segment::AddFrame(const uint8* frame, uint64 length, uint64 track_number, | 2565 bool Segment::AddFrame(const uint8* data, uint64 length, uint64 track_number, |
| 2268 uint64 timestamp, bool is_key) { | 2566 uint64 timestamp, bool is_key) { |
| 2567 if (!data) |
| 2568 return false; |
| 2569 |
| 2570 Frame frame; |
| 2571 if (!frame.Init(data, length)) |
| 2572 return false; |
| 2573 frame.set_track_number(track_number); |
| 2574 frame.set_timestamp(timestamp); |
| 2575 frame.set_is_key(is_key); |
| 2576 return AddGenericFrame(&frame); |
| 2577 } |
| 2578 |
| 2579 bool Segment::AddFrameWithAdditional(const uint8* data, uint64 length, |
| 2580 const uint8* additional, |
| 2581 uint64 additional_length, uint64 add_id, |
| 2582 uint64 track_number, uint64 timestamp, |
| 2583 bool is_key) { |
| 2584 if (!data || !additional) |
| 2585 return false; |
| 2586 |
| 2587 Frame frame; |
| 2588 if (!frame.Init(data, length) || |
| 2589 !frame.AddAdditionalData(additional, additional_length, add_id)) { |
| 2590 return false; |
| 2591 } |
| 2592 frame.set_track_number(track_number); |
| 2593 frame.set_timestamp(timestamp); |
| 2594 frame.set_is_key(is_key); |
| 2595 return AddGenericFrame(&frame); |
| 2596 } |
| 2597 |
| 2598 bool Segment::AddFrameWithDiscardPadding(const uint8* data, uint64 length, |
| 2599 int64 discard_padding, |
| 2600 uint64 track_number, uint64 timestamp, |
| 2601 bool is_key) { |
| 2602 if (!data) |
| 2603 return false; |
| 2604 |
| 2605 Frame frame; |
| 2606 if (!frame.Init(data, length)) |
| 2607 return false; |
| 2608 frame.set_discard_padding(discard_padding); |
| 2609 frame.set_track_number(track_number); |
| 2610 frame.set_timestamp(timestamp); |
| 2611 frame.set_is_key(is_key); |
| 2612 return AddGenericFrame(&frame); |
| 2613 } |
| 2614 |
| 2615 bool Segment::AddMetadata(const uint8* data, uint64 length, uint64 track_number, |
| 2616 uint64 timestamp_ns, uint64 duration_ns) { |
| 2617 if (!data) |
| 2618 return false; |
| 2619 |
| 2620 Frame frame; |
| 2621 if (!frame.Init(data, length)) |
| 2622 return false; |
| 2623 frame.set_track_number(track_number); |
| 2624 frame.set_timestamp(timestamp_ns); |
| 2625 frame.set_duration(duration_ns); |
| 2626 frame.set_is_key(true); // All metadata blocks are keyframes. |
| 2627 return AddGenericFrame(&frame); |
| 2628 } |
| 2629 |
| 2630 bool Segment::AddGenericFrame(const Frame* frame) { |
| 2269 if (!frame) | 2631 if (!frame) |
| 2270 return false; | 2632 return false; |
| 2271 | 2633 |
| 2272 if (!CheckHeaderInfo()) | 2634 if (!CheckHeaderInfo()) |
| 2273 return false; | 2635 return false; |
| 2274 | 2636 |
| 2275 // Check for non-monotonically increasing timestamps. | 2637 // Check for non-monotonically increasing timestamps. |
| 2276 if (timestamp < last_timestamp_) | 2638 if (frame->timestamp() < last_timestamp_) |
| 2277 return false; | 2639 return false; |
| 2278 | 2640 |
| 2641 // Check if the track number is valid. |
| 2642 if (!tracks_.GetTrackByNumber(frame->track_number())) |
| 2643 return false; |
| 2644 |
| 2645 if (frame->discard_padding() != 0) |
| 2646 doc_type_version_ = 4; |
| 2647 |
| 2279 // If the segment has a video track hold onto audio frames to make sure the | 2648 // 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 | 2649 // audio that is associated with the start time of a video key-frame is |
| 2281 // muxed into the same cluster. | 2650 // muxed into the same cluster. |
| 2282 if (has_video_ && tracks_.TrackIsAudio(track_number) && !force_new_cluster_) { | 2651 if (has_video_ && tracks_.TrackIsAudio(frame->track_number()) && |
| 2652 !force_new_cluster_) { |
| 2283 Frame* const new_frame = new (std::nothrow) Frame(); | 2653 Frame* const new_frame = new (std::nothrow) Frame(); |
| 2284 if (new_frame == NULL || !new_frame->Init(frame, length)) | 2654 if (!new_frame || !new_frame->CopyFrom(*frame)) |
| 2285 return false; | 2655 return false; |
| 2286 new_frame->set_track_number(track_number); | 2656 return QueueFrame(new_frame); |
| 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 } | 2657 } |
| 2295 | 2658 |
| 2296 if (!DoNewClusterProcessing(track_number, timestamp, is_key)) | 2659 if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(), |
| 2660 frame->is_key())) { |
| 2297 return false; | 2661 return false; |
| 2662 } |
| 2298 | 2663 |
| 2299 if (cluster_list_size_ < 1) | 2664 if (cluster_list_size_ < 1) |
| 2300 return false; | 2665 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 | |
| 2323 bool 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 | |
| 2384 bool 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 | 2666 |
| 2422 Cluster* const cluster = cluster_list_[cluster_list_size_ - 1]; | 2667 Cluster* const cluster = cluster_list_[cluster_list_size_ - 1]; |
| 2423 if (!cluster) | 2668 if (!cluster) |
| 2424 return false; | 2669 return false; |
| 2425 | 2670 |
| 2426 const uint64 timecode_scale = segment_info_.timecode_scale(); | 2671 // If the Frame is not a SimpleBlock, then set the reference_block_timestamp |
| 2427 const uint64 abs_timecode = timestamp / timecode_scale; | 2672 // if it is not set already. |
| 2428 | 2673 bool frame_created = false; |
| 2429 if (!cluster->AddFrameWithDiscardPadding( | 2674 if (!frame->CanBeSimpleBlock() && !frame->is_key() && |
| 2430 frame, length, discard_padding, track_number, abs_timecode, is_key)) { | 2675 !frame->reference_block_timestamp_set()) { |
| 2431 return false; | 2676 Frame* const new_frame = new (std::nothrow) Frame(); |
| 2677 if (!new_frame->CopyFrom(*frame)) |
| 2678 return false; |
| 2679 new_frame->set_reference_block_timestamp( |
| 2680 last_track_timestamp_[frame->track_number() - 1]); |
| 2681 frame = new_frame; |
| 2682 frame_created = true; |
| 2432 } | 2683 } |
| 2433 | 2684 |
| 2434 if (new_cuepoint_ && cues_track_ == track_number) { | 2685 if (!cluster->AddFrame(frame)) |
| 2435 if (!AddCuePoint(timestamp, cues_track_)) | 2686 return false; |
| 2687 |
| 2688 if (new_cuepoint_ && cues_track_ == frame->track_number()) { |
| 2689 if (!AddCuePoint(frame->timestamp(), cues_track_)) |
| 2436 return false; | 2690 return false; |
| 2437 } | 2691 } |
| 2438 | 2692 |
| 2439 if (timestamp > last_timestamp_) | 2693 last_timestamp_ = frame->timestamp(); |
| 2440 last_timestamp_ = timestamp; | 2694 last_track_timestamp_[frame->track_number() - 1] = frame->timestamp(); |
| 2695 last_block_duration_ = frame->duration(); |
| 2696 |
| 2697 if (frame_created) |
| 2698 delete frame; |
| 2441 | 2699 |
| 2442 return true; | 2700 return true; |
| 2443 } | 2701 } |
| 2444 | 2702 |
| 2445 bool 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 | |
| 2483 bool 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 | |
| 2504 void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; } | 2703 void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; } |
| 2505 | 2704 |
| 2506 bool Segment::SetChunking(bool chunking, const char* filename) { | 2705 bool Segment::SetChunking(bool chunking, const char* filename) { |
| 2507 if (chunk_count_ > 0) | 2706 if (chunk_count_ > 0) |
| 2508 return false; | 2707 return false; |
| 2509 | 2708 |
| 2510 if (chunking) { | 2709 if (chunking) { |
| 2511 if (!filename) | 2710 if (!filename) |
| 2512 return false; | 2711 return false; |
| 2513 | 2712 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2591 return true; | 2790 return true; |
| 2592 } | 2791 } |
| 2593 | 2792 |
| 2594 void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; } | 2793 void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; } |
| 2595 | 2794 |
| 2596 Track* Segment::GetTrackByNumber(uint64 track_number) const { | 2795 Track* Segment::GetTrackByNumber(uint64 track_number) const { |
| 2597 return tracks_.GetTrackByNumber(track_number); | 2796 return tracks_.GetTrackByNumber(track_number); |
| 2598 } | 2797 } |
| 2599 | 2798 |
| 2600 bool Segment::WriteSegmentHeader() { | 2799 bool Segment::WriteSegmentHeader() { |
| 2800 UpdateDocTypeVersion(); |
| 2801 |
| 2601 // TODO(fgalligan): Support more than one segment. | 2802 // TODO(fgalligan): Support more than one segment. |
| 2602 if (!WriteEbmlHeader(writer_header_)) | 2803 if (!WriteEbmlHeader(writer_header_, doc_type_version_)) |
| 2603 return false; | 2804 return false; |
| 2805 doc_type_version_written_ = doc_type_version_; |
| 2806 ebml_header_size_ = static_cast<int32>(writer_header_->Position()); |
| 2604 | 2807 |
| 2605 // Write "unknown" (-1) as segment size value. If mode is kFile, Segment | 2808 // Write "unknown" (-1) as segment size value. If mode is kFile, Segment |
| 2606 // will write over duration when the file is finalized. | 2809 // will write over duration when the file is finalized. |
| 2607 if (WriteID(writer_header_, kMkvSegment)) | 2810 if (WriteID(writer_header_, kMkvSegment)) |
| 2608 return false; | 2811 return false; |
| 2609 | 2812 |
| 2610 // Save for later. | 2813 // Save for later. |
| 2611 size_position_ = writer_header_->Position(); | 2814 size_position_ = writer_header_->Position(); |
| 2612 | 2815 |
| 2613 // Write "unknown" (EBML coded -1) as segment size value. We need to write 8 | 2816 // Write "unknown" (EBML coded -1) as segment size value. We need to write 8 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2638 if (!tracks_.Write(writer_header_)) | 2841 if (!tracks_.Write(writer_header_)) |
| 2639 return false; | 2842 return false; |
| 2640 | 2843 |
| 2641 if (chapters_.Count() > 0) { | 2844 if (chapters_.Count() > 0) { |
| 2642 if (!seek_head_.AddSeekEntry(kMkvChapters, MaxOffset())) | 2845 if (!seek_head_.AddSeekEntry(kMkvChapters, MaxOffset())) |
| 2643 return false; | 2846 return false; |
| 2644 if (!chapters_.Write(writer_header_)) | 2847 if (!chapters_.Write(writer_header_)) |
| 2645 return false; | 2848 return false; |
| 2646 } | 2849 } |
| 2647 | 2850 |
| 2851 if (tags_.Count() > 0) { |
| 2852 if (!seek_head_.AddSeekEntry(kMkvTags, MaxOffset())) |
| 2853 return false; |
| 2854 if (!tags_.Write(writer_header_)) |
| 2855 return false; |
| 2856 } |
| 2857 |
| 2648 if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) { | 2858 if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) { |
| 2649 if (!chunk_writer_header_) | 2859 if (!chunk_writer_header_) |
| 2650 return false; | 2860 return false; |
| 2651 | 2861 |
| 2652 chunk_writer_header_->Close(); | 2862 chunk_writer_header_->Close(); |
| 2653 } | 2863 } |
| 2654 | 2864 |
| 2655 header_written_ = true; | 2865 header_written_ = true; |
| 2656 | 2866 |
| 2657 return true; | 2867 return true; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2733 } | 2943 } |
| 2734 | 2944 |
| 2735 bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) { | 2945 bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) { |
| 2736 const int32 new_size = cluster_list_size_ + 1; | 2946 const int32 new_size = cluster_list_size_ + 1; |
| 2737 | 2947 |
| 2738 if (new_size > cluster_list_capacity_) { | 2948 if (new_size > cluster_list_capacity_) { |
| 2739 // Add more clusters. | 2949 // Add more clusters. |
| 2740 const int32 new_capacity = | 2950 const int32 new_capacity = |
| 2741 (cluster_list_capacity_ <= 0) ? 1 : cluster_list_capacity_ * 2; | 2951 (cluster_list_capacity_ <= 0) ? 1 : cluster_list_capacity_ * 2; |
| 2742 Cluster** const clusters = | 2952 Cluster** const clusters = |
| 2743 new (std::nothrow) Cluster* [new_capacity]; // NOLINT | 2953 new (std::nothrow) Cluster*[new_capacity]; // NOLINT |
| 2744 if (!clusters) | 2954 if (!clusters) |
| 2745 return false; | 2955 return false; |
| 2746 | 2956 |
| 2747 for (int32 i = 0; i < cluster_list_size_; ++i) { | 2957 for (int32 i = 0; i < cluster_list_size_; ++i) { |
| 2748 clusters[i] = cluster_list_[i]; | 2958 clusters[i] = cluster_list_[i]; |
| 2749 } | 2959 } |
| 2750 | 2960 |
| 2751 delete[] cluster_list_; | 2961 delete[] cluster_list_; |
| 2752 | 2962 |
| 2753 cluster_list_ = clusters; | 2963 cluster_list_ = clusters; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2789 const Frame* const f = frames_[0]; // earliest queued frame | 2999 const Frame* const f = frames_[0]; // earliest queued frame |
| 2790 const uint64 ns = f->timestamp(); | 3000 const uint64 ns = f->timestamp(); |
| 2791 const uint64 tc = ns / timecode_scale; | 3001 const uint64 tc = ns / timecode_scale; |
| 2792 | 3002 |
| 2793 if (tc < cluster_timecode) | 3003 if (tc < cluster_timecode) |
| 2794 cluster_timecode = tc; | 3004 cluster_timecode = tc; |
| 2795 } | 3005 } |
| 2796 | 3006 |
| 2797 Cluster*& cluster = cluster_list_[cluster_list_size_]; | 3007 Cluster*& cluster = cluster_list_[cluster_list_size_]; |
| 2798 const int64 offset = MaxOffset(); | 3008 const int64 offset = MaxOffset(); |
| 2799 cluster = new (std::nothrow) Cluster(cluster_timecode, offset); // NOLINT | 3009 cluster = new (std::nothrow) Cluster(cluster_timecode, // NOLINT |
| 3010 offset, segment_info_.timecode_scale()); |
| 2800 if (!cluster) | 3011 if (!cluster) |
| 2801 return false; | 3012 return false; |
| 2802 | 3013 |
| 2803 if (!cluster->Init(writer_cluster_)) | 3014 if (!cluster->Init(writer_cluster_)) |
| 2804 return false; | 3015 return false; |
| 2805 | 3016 |
| 2806 cluster_list_size_ = new_size; | 3017 cluster_list_size_ = new_size; |
| 2807 return true; | 3018 return true; |
| 2808 } | 3019 } |
| 2809 | 3020 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2866 if (!track) | 3077 if (!track) |
| 2867 return false; | 3078 return false; |
| 2868 | 3079 |
| 2869 cues_track_ = track->number(); | 3080 cues_track_ = track->number(); |
| 2870 } | 3081 } |
| 2871 } | 3082 } |
| 2872 } | 3083 } |
| 2873 return true; | 3084 return true; |
| 2874 } | 3085 } |
| 2875 | 3086 |
| 3087 void Segment::UpdateDocTypeVersion() { |
| 3088 for (uint32 index = 0; index < tracks_.track_entries_size(); ++index) { |
| 3089 const Track* track = tracks_.GetTrackByIndex(index); |
| 3090 if (track == NULL) |
| 3091 break; |
| 3092 if ((track->codec_delay() || track->seek_pre_roll()) && |
| 3093 doc_type_version_ < 4) { |
| 3094 doc_type_version_ = 4; |
| 3095 break; |
| 3096 } |
| 3097 } |
| 3098 } |
| 3099 |
| 2876 bool Segment::UpdateChunkName(const char* ext, char** name) const { | 3100 bool Segment::UpdateChunkName(const char* ext, char** name) const { |
| 2877 if (!name || !ext) | 3101 if (!name || !ext) |
| 2878 return false; | 3102 return false; |
| 2879 | 3103 |
| 2880 char ext_chk[64]; | 3104 char ext_chk[64]; |
| 2881 #ifdef _MSC_VER | 3105 #ifdef _MSC_VER |
| 2882 sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext); | 3106 sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext); |
| 2883 #else | 3107 #else |
| 2884 snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext); | 3108 snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext); |
| 2885 #endif | 3109 #endif |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2925 bool Segment::QueueFrame(Frame* frame) { | 3149 bool Segment::QueueFrame(Frame* frame) { |
| 2926 const int32 new_size = frames_size_ + 1; | 3150 const int32 new_size = frames_size_ + 1; |
| 2927 | 3151 |
| 2928 if (new_size > frames_capacity_) { | 3152 if (new_size > frames_capacity_) { |
| 2929 // Add more frames. | 3153 // Add more frames. |
| 2930 const int32 new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2; | 3154 const int32 new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2; |
| 2931 | 3155 |
| 2932 if (new_capacity < 1) | 3156 if (new_capacity < 1) |
| 2933 return false; | 3157 return false; |
| 2934 | 3158 |
| 2935 Frame** const frames = new (std::nothrow) Frame* [new_capacity]; // NOLINT | 3159 Frame** const frames = new (std::nothrow) Frame*[new_capacity]; // NOLINT |
| 2936 if (!frames) | 3160 if (!frames) |
| 2937 return false; | 3161 return false; |
| 2938 | 3162 |
| 2939 for (int32 i = 0; i < frames_size_; ++i) { | 3163 for (int32 i = 0; i < frames_size_; ++i) { |
| 2940 frames[i] = frames_[i]; | 3164 frames[i] = frames_[i]; |
| 2941 } | 3165 } |
| 2942 | 3166 |
| 2943 delete[] frames_; | 3167 delete[] frames_; |
| 2944 frames_ = frames; | 3168 frames_ = frames; |
| 2945 frames_capacity_ = new_capacity; | 3169 frames_capacity_ = new_capacity; |
| 2946 } | 3170 } |
| 2947 | 3171 |
| 2948 frames_[frames_size_++] = frame; | 3172 frames_[frames_size_++] = frame; |
| 2949 | 3173 |
| 2950 return true; | 3174 return true; |
| 2951 } | 3175 } |
| 2952 | 3176 |
| 2953 int Segment::WriteFramesAll() { | 3177 int Segment::WriteFramesAll() { |
| 2954 if (frames_ == NULL) | 3178 if (frames_ == NULL) |
| 2955 return 0; | 3179 return 0; |
| 2956 | 3180 |
| 2957 if (cluster_list_size_ < 1) | 3181 if (cluster_list_size_ < 1) |
| 2958 return -1; | 3182 return -1; |
| 2959 | 3183 |
| 2960 Cluster* const cluster = cluster_list_[cluster_list_size_ - 1]; | 3184 Cluster* const cluster = cluster_list_[cluster_list_size_ - 1]; |
| 2961 | 3185 |
| 2962 if (!cluster) | 3186 if (!cluster) |
| 2963 return -1; | 3187 return -1; |
| 2964 | 3188 |
| 2965 const uint64 timecode_scale = segment_info_.timecode_scale(); | |
| 2966 | |
| 2967 for (int32 i = 0; i < frames_size_; ++i) { | 3189 for (int32 i = 0; i < frames_size_; ++i) { |
| 2968 Frame*& frame = frames_[i]; | 3190 Frame*& frame = frames_[i]; |
| 2969 const uint64 frame_timestamp = frame->timestamp(); // ns | 3191 // TODO(jzern/vigneshv): using Segment::AddGenericFrame here would limit the |
| 2970 const uint64 frame_timecode = frame_timestamp / timecode_scale; | 3192 // places where |doc_type_version_| needs to be updated. |
| 2971 | 3193 if (frame->discard_padding() != 0) |
| 2972 if (frame->discard_padding() > 0) { | 3194 doc_type_version_ = 4; |
| 2973 if (!cluster->AddFrameWithDiscardPadding( | 3195 if (!cluster->AddFrame(frame)) |
| 2974 frame->frame(), frame->length(), frame->discard_padding(), | 3196 return -1; |
| 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 | 3197 |
| 2986 if (new_cuepoint_ && cues_track_ == frame->track_number()) { | 3198 if (new_cuepoint_ && cues_track_ == frame->track_number()) { |
| 2987 if (!AddCuePoint(frame_timestamp, cues_track_)) | 3199 if (!AddCuePoint(frame->timestamp(), cues_track_)) |
| 2988 return -1; | 3200 return -1; |
| 2989 } | 3201 } |
| 2990 | 3202 |
| 2991 if (frame_timestamp > last_timestamp_) | 3203 if (frame->timestamp() > last_timestamp_) { |
| 2992 last_timestamp_ = frame_timestamp; | 3204 last_timestamp_ = frame->timestamp(); |
| 3205 last_track_timestamp_[frame->track_number() - 1] = frame->timestamp(); |
| 3206 } |
| 2993 | 3207 |
| 2994 delete frame; | 3208 delete frame; |
| 2995 frame = NULL; | 3209 frame = NULL; |
| 2996 } | 3210 } |
| 2997 | 3211 |
| 2998 const int result = frames_size_; | 3212 const int result = frames_size_; |
| 2999 frames_size_ = 0; | 3213 frames_size_ = 0; |
| 3000 | 3214 |
| 3001 return result; | 3215 return result; |
| 3002 } | 3216 } |
| 3003 | 3217 |
| 3004 bool Segment::WriteFramesLessThan(uint64 timestamp) { | 3218 bool Segment::WriteFramesLessThan(uint64 timestamp) { |
| 3005 // Check |cluster_list_size_| to see if this is the first cluster. If it is | 3219 // 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 | 3220 // the first cluster the audio frames that are less than the first video |
| 3007 // timesatmp will be written in a later step. | 3221 // timesatmp will be written in a later step. |
| 3008 if (frames_size_ > 0 && cluster_list_size_ > 0) { | 3222 if (frames_size_ > 0 && cluster_list_size_ > 0) { |
| 3009 if (!frames_) | 3223 if (!frames_) |
| 3010 return false; | 3224 return false; |
| 3011 | 3225 |
| 3012 Cluster* const cluster = cluster_list_[cluster_list_size_ - 1]; | 3226 Cluster* const cluster = cluster_list_[cluster_list_size_ - 1]; |
| 3013 if (!cluster) | 3227 if (!cluster) |
| 3014 return false; | 3228 return false; |
| 3015 | 3229 |
| 3016 const uint64 timecode_scale = segment_info_.timecode_scale(); | |
| 3017 int32 shift_left = 0; | 3230 int32 shift_left = 0; |
| 3018 | 3231 |
| 3019 // TODO(fgalligan): Change this to use the durations of frames instead of | 3232 // TODO(fgalligan): Change this to use the durations of frames instead of |
| 3020 // the next frame's start time if the duration is accurate. | 3233 // the next frame's start time if the duration is accurate. |
| 3021 for (int32 i = 1; i < frames_size_; ++i) { | 3234 for (int32 i = 1; i < frames_size_; ++i) { |
| 3022 const Frame* const frame_curr = frames_[i]; | 3235 const Frame* const frame_curr = frames_[i]; |
| 3023 | 3236 |
| 3024 if (frame_curr->timestamp() > timestamp) | 3237 if (frame_curr->timestamp() > timestamp) |
| 3025 break; | 3238 break; |
| 3026 | 3239 |
| 3027 const Frame* const frame_prev = frames_[i - 1]; | 3240 const Frame* const frame_prev = frames_[i - 1]; |
| 3028 const uint64 frame_timestamp = frame_prev->timestamp(); | 3241 if (frame_prev->discard_padding() != 0) |
| 3029 const uint64 frame_timecode = frame_timestamp / timecode_scale; | 3242 doc_type_version_ = 4; |
| 3030 const int64 discard_padding = frame_prev->discard_padding(); | 3243 if (!cluster->AddFrame(frame_prev)) |
| 3031 | 3244 return false; |
| 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 | 3245 |
| 3047 if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) { | 3246 if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) { |
| 3048 if (!AddCuePoint(frame_timestamp, cues_track_)) | 3247 if (!AddCuePoint(frame_prev->timestamp(), cues_track_)) |
| 3049 return false; | 3248 return false; |
| 3050 } | 3249 } |
| 3051 | 3250 |
| 3052 ++shift_left; | 3251 ++shift_left; |
| 3053 if (frame_timestamp > last_timestamp_) | 3252 if (frame_prev->timestamp() > last_timestamp_) { |
| 3054 last_timestamp_ = frame_timestamp; | 3253 last_timestamp_ = frame_prev->timestamp(); |
| 3254 last_track_timestamp_[frame_prev->track_number() - 1] = |
| 3255 frame_prev->timestamp(); |
| 3256 } |
| 3055 | 3257 |
| 3056 delete frame_prev; | 3258 delete frame_prev; |
| 3057 } | 3259 } |
| 3058 | 3260 |
| 3059 if (shift_left > 0) { | 3261 if (shift_left > 0) { |
| 3060 if (shift_left >= frames_size_) | 3262 if (shift_left >= frames_size_) |
| 3061 return false; | 3263 return false; |
| 3062 | 3264 |
| 3063 const int32 new_frames_size = frames_size_ - shift_left; | 3265 const int32 new_frames_size = frames_size_ - shift_left; |
| 3064 for (int32 i = 0; i < new_frames_size; ++i) { | 3266 for (int32 i = 0; i < new_frames_size; ++i) { |
| 3065 frames_[i] = frames_[i + shift_left]; | 3267 frames_[i] = frames_[i + shift_left]; |
| 3066 } | 3268 } |
| 3067 | 3269 |
| 3068 frames_size_ = new_frames_size; | 3270 frames_size_ = new_frames_size; |
| 3069 } | 3271 } |
| 3070 } | 3272 } |
| 3071 | 3273 |
| 3072 return true; | 3274 return true; |
| 3073 } | 3275 } |
| 3074 | 3276 |
| 3075 } // namespace mkvmuxer | 3277 } // namespace mkvmuxer |
| OLD | NEW |