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 |