| Index: source/libvpx/third_party/libwebm/mkvmuxer.cpp
|
| diff --git a/source/libvpx/third_party/libwebm/mkvmuxer.cpp b/source/libvpx/third_party/libwebm/mkvmuxer.cpp
|
| index 45167ea4c23aa71f389ebcbd54a7ed84ff3ecbc5..9be3119a4603311635058d3d1bd32da7a41ae913 100644
|
| --- a/source/libvpx/third_party/libwebm/mkvmuxer.cpp
|
| +++ b/source/libvpx/third_party/libwebm/mkvmuxer.cpp
|
| @@ -65,14 +65,14 @@ IMkvWriter::IMkvWriter() {}
|
|
|
| IMkvWriter::~IMkvWriter() {}
|
|
|
| -bool WriteEbmlHeader(IMkvWriter* writer) {
|
| +bool WriteEbmlHeader(IMkvWriter* writer, uint64 doc_type_version) {
|
| // Level 0
|
| uint64 size = EbmlElementSize(kMkvEBMLVersion, 1ULL);
|
| size += EbmlElementSize(kMkvEBMLReadVersion, 1ULL);
|
| size += EbmlElementSize(kMkvEBMLMaxIDLength, 4ULL);
|
| size += EbmlElementSize(kMkvEBMLMaxSizeLength, 8ULL);
|
| size += EbmlElementSize(kMkvDocType, "webm");
|
| - size += EbmlElementSize(kMkvDocTypeVersion, 2ULL);
|
| + size += EbmlElementSize(kMkvDocTypeVersion, doc_type_version);
|
| size += EbmlElementSize(kMkvDocTypeReadVersion, 2ULL);
|
|
|
| if (!WriteEbmlMasterElement(writer, kMkvEBML, size))
|
| @@ -87,7 +87,7 @@ bool WriteEbmlHeader(IMkvWriter* writer) {
|
| return false;
|
| if (!WriteEbmlElement(writer, kMkvDocType, "webm"))
|
| return false;
|
| - if (!WriteEbmlElement(writer, kMkvDocTypeVersion, 2ULL))
|
| + if (!WriteEbmlElement(writer, kMkvDocTypeVersion, doc_type_version))
|
| return false;
|
| if (!WriteEbmlElement(writer, kMkvDocTypeReadVersion, 2ULL))
|
| return false;
|
| @@ -95,6 +95,10 @@ bool WriteEbmlHeader(IMkvWriter* writer) {
|
| return true;
|
| }
|
|
|
| +bool WriteEbmlHeader(IMkvWriter* writer) {
|
| + return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion);
|
| +}
|
| +
|
| bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst,
|
| mkvmuxer::int64 start, int64 size) {
|
| // TODO(vigneshv): Check if this is a reasonable value.
|
| @@ -127,13 +131,40 @@ Frame::Frame()
|
| length_(0),
|
| track_number_(0),
|
| timestamp_(0),
|
| - discard_padding_(0) {}
|
| + discard_padding_(0),
|
| + reference_block_timestamp_(0),
|
| + reference_block_timestamp_set_(false) {}
|
|
|
| Frame::~Frame() {
|
| delete[] frame_;
|
| delete[] additional_;
|
| }
|
|
|
| +bool Frame::CopyFrom(const Frame& frame) {
|
| + delete[] frame_;
|
| + frame_ = NULL;
|
| + length_ = 0;
|
| + if (frame.length() > 0 && frame.frame() != NULL &&
|
| + !Init(frame.frame(), frame.length())) {
|
| + return false;
|
| + }
|
| + add_id_ = 0;
|
| + delete[] additional_;
|
| + additional_ = NULL;
|
| + additional_length_ = 0;
|
| + if (frame.additional_length() > 0 && frame.additional() != NULL &&
|
| + !AddAdditionalData(frame.additional(), frame.additional_length(),
|
| + frame.add_id())) {
|
| + return false;
|
| + }
|
| + duration_ = frame.duration();
|
| + is_key_ = frame.is_key();
|
| + track_number_ = frame.track_number();
|
| + timestamp_ = frame.timestamp();
|
| + discard_padding_ = frame.discard_padding();
|
| + return true;
|
| +}
|
| +
|
| bool Frame::Init(const uint8* frame, uint64 length) {
|
| uint8* const data =
|
| new (std::nothrow) uint8[static_cast<size_t>(length)]; // NOLINT
|
| @@ -164,6 +195,32 @@ bool Frame::AddAdditionalData(const uint8* additional, uint64 length,
|
| return true;
|
| }
|
|
|
| +bool Frame::IsValid() const {
|
| + if (length_ == 0 || !frame_) {
|
| + return false;
|
| + }
|
| + if ((additional_length_ != 0 && !additional_) ||
|
| + (additional_ != NULL && additional_length_ == 0)) {
|
| + return false;
|
| + }
|
| + if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
|
| + return false;
|
| + }
|
| + if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool Frame::CanBeSimpleBlock() const {
|
| + return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
|
| +}
|
| +
|
| +void Frame::set_reference_block_timestamp(int64 reference_block_timestamp) {
|
| + reference_block_timestamp_ = reference_block_timestamp;
|
| + reference_block_timestamp_set_ = true;
|
| +}
|
| +
|
| ///////////////////////////////////////////////////////////////
|
| //
|
| // CuePoint Class
|
| @@ -271,7 +328,7 @@ bool Cues::AddCue(CuePoint* cue) {
|
| return false;
|
|
|
| CuePoint** const cues =
|
| - new (std::nothrow) CuePoint* [new_capacity]; // NOLINT
|
| + new (std::nothrow) CuePoint*[new_capacity]; // NOLINT
|
| if (!cues)
|
| return false;
|
|
|
| @@ -532,7 +589,7 @@ bool Track::AddContentEncoding() {
|
| const uint32 count = content_encoding_entries_size_ + 1;
|
|
|
| ContentEncoding** const content_encoding_entries =
|
| - new (std::nothrow) ContentEncoding* [count]; // NOLINT
|
| + new (std::nothrow) ContentEncoding*[count]; // NOLINT
|
| if (!content_encoding_entries)
|
| return false;
|
|
|
| @@ -612,6 +669,10 @@ bool Track::Write(IMkvWriter* writer) const {
|
| if (!writer)
|
| return false;
|
|
|
| + // mandatory elements without a default value.
|
| + if (!type_ || !codec_id_)
|
| + return false;
|
| +
|
| // |size| may be bigger than what is written out in this function because
|
| // derived classes may write out more data in the Track element.
|
| const uint64 payload_size = PayloadSize();
|
| @@ -619,10 +680,6 @@ bool Track::Write(IMkvWriter* writer) const {
|
| if (!WriteEbmlMasterElement(writer, kMkvTrackEntry, payload_size))
|
| return false;
|
|
|
| - // |type_| has to be specified before the Track can be written.
|
| - if (!type_)
|
| - return false;
|
| -
|
| uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
|
| size += EbmlElementSize(kMkvTrackUID, uid_);
|
| size += EbmlElementSize(kMkvTrackType, type_);
|
| @@ -793,6 +850,10 @@ VideoTrack::VideoTrack(unsigned int* seed)
|
| : Track(seed),
|
| display_height_(0),
|
| display_width_(0),
|
| + crop_left_(0),
|
| + crop_right_(0),
|
| + crop_top_(0),
|
| + crop_bottom_(0),
|
| frame_rate_(0.0),
|
| height_(0),
|
| stereo_mode_(0),
|
| @@ -846,27 +907,50 @@ bool VideoTrack::Write(IMkvWriter* writer) const {
|
| return false;
|
| if (!WriteEbmlElement(writer, kMkvPixelHeight, height_))
|
| return false;
|
| - if (display_width_ > 0)
|
| + if (display_width_ > 0) {
|
| if (!WriteEbmlElement(writer, kMkvDisplayWidth, display_width_))
|
| return false;
|
| - if (display_height_ > 0)
|
| + }
|
| + if (display_height_ > 0) {
|
| if (!WriteEbmlElement(writer, kMkvDisplayHeight, display_height_))
|
| return false;
|
| - if (stereo_mode_ > kMono)
|
| + }
|
| + if (crop_left_ > 0) {
|
| + if (!WriteEbmlElement(writer, kMkvPixelCropLeft, crop_left_))
|
| + return false;
|
| + }
|
| + if (crop_right_ > 0) {
|
| + if (!WriteEbmlElement(writer, kMkvPixelCropRight, crop_right_))
|
| + return false;
|
| + }
|
| + if (crop_top_ > 0) {
|
| + if (!WriteEbmlElement(writer, kMkvPixelCropTop, crop_top_))
|
| + return false;
|
| + }
|
| + if (crop_bottom_ > 0) {
|
| + if (!WriteEbmlElement(writer, kMkvPixelCropBottom, crop_bottom_))
|
| + return false;
|
| + }
|
| + if (stereo_mode_ > kMono) {
|
| if (!WriteEbmlElement(writer, kMkvStereoMode, stereo_mode_))
|
| return false;
|
| - if (alpha_mode_ > kNoAlpha)
|
| + }
|
| + if (alpha_mode_ > kNoAlpha) {
|
| if (!WriteEbmlElement(writer, kMkvAlphaMode, alpha_mode_))
|
| return false;
|
| - if (frame_rate_ > 0.0)
|
| + }
|
| + if (frame_rate_ > 0.0) {
|
| if (!WriteEbmlElement(writer, kMkvFrameRate,
|
| - static_cast<float>(frame_rate_)))
|
| + static_cast<float>(frame_rate_))) {
|
| return false;
|
| + }
|
| + }
|
|
|
| const int64 stop_position = writer->Position();
|
| if (stop_position < 0 ||
|
| - stop_position - payload_position != static_cast<int64>(size))
|
| + stop_position - payload_position != static_cast<int64>(size)) {
|
| return false;
|
| + }
|
|
|
| return true;
|
| }
|
| @@ -878,6 +962,14 @@ uint64 VideoTrack::VideoPayloadSize() const {
|
| size += EbmlElementSize(kMkvDisplayWidth, display_width_);
|
| if (display_height_ > 0)
|
| size += EbmlElementSize(kMkvDisplayHeight, display_height_);
|
| + if (crop_left_ > 0)
|
| + size += EbmlElementSize(kMkvPixelCropLeft, crop_left_);
|
| + if (crop_right_ > 0)
|
| + size += EbmlElementSize(kMkvPixelCropRight, crop_right_);
|
| + if (crop_top_ > 0)
|
| + size += EbmlElementSize(kMkvPixelCropTop, crop_top_);
|
| + if (crop_bottom_ > 0)
|
| + size += EbmlElementSize(kMkvPixelCropBottom, crop_bottom_);
|
| if (stereo_mode_ > kMono)
|
| size += EbmlElementSize(kMkvStereoMode, stereo_mode_);
|
| if (alpha_mode_ > kNoAlpha)
|
| @@ -953,6 +1045,7 @@ const char Tracks::kOpusCodecId[] = "A_OPUS";
|
| const char Tracks::kVorbisCodecId[] = "A_VORBIS";
|
| const char Tracks::kVp8CodecId[] = "V_VP8";
|
| const char Tracks::kVp9CodecId[] = "V_VP9";
|
| +const char Tracks::kVp10CodecId[] = "V_VP10";
|
|
|
| Tracks::Tracks() : track_entries_(NULL), track_entries_size_(0) {}
|
|
|
| @@ -990,7 +1083,7 @@ bool Tracks::AddTrack(Track* track, int32 number) {
|
|
|
| const uint32 count = track_entries_size_ + 1;
|
|
|
| - Track** const track_entries = new (std::nothrow) Track* [count]; // NOLINT
|
| + Track** const track_entries = new (std::nothrow) Track*[count]; // NOLINT
|
| if (!track_entries)
|
| return false;
|
|
|
| @@ -1145,6 +1238,8 @@ Chapter::~Chapter() {}
|
|
|
| void Chapter::Init(unsigned int* seed) {
|
| id_ = NULL;
|
| + start_timecode_ = 0;
|
| + end_timecode_ = 0;
|
| displays_ = NULL;
|
| displays_size_ = 0;
|
| displays_count_ = 0;
|
| @@ -1420,11 +1515,242 @@ uint64 Chapters::WriteEdition(IMkvWriter* writer) const {
|
| return edition_size;
|
| }
|
|
|
| +// Tag Class
|
| +
|
| +bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) {
|
| + if (!ExpandSimpleTagsArray())
|
| + return false;
|
| +
|
| + SimpleTag& st = simple_tags_[simple_tags_count_++];
|
| + st.Init();
|
| +
|
| + if (!st.set_tag_name(tag_name))
|
| + return false;
|
| +
|
| + if (!st.set_tag_string(tag_string))
|
| + return false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +Tag::Tag() {
|
| + simple_tags_ = NULL;
|
| + simple_tags_size_ = 0;
|
| + simple_tags_count_ = 0;
|
| +}
|
| +
|
| +Tag::~Tag() {}
|
| +
|
| +void Tag::ShallowCopy(Tag* dst) const {
|
| + dst->simple_tags_ = simple_tags_;
|
| + dst->simple_tags_size_ = simple_tags_size_;
|
| + dst->simple_tags_count_ = simple_tags_count_;
|
| +}
|
| +
|
| +void Tag::Clear() {
|
| + while (simple_tags_count_ > 0) {
|
| + SimpleTag& st = simple_tags_[--simple_tags_count_];
|
| + st.Clear();
|
| + }
|
| +
|
| + delete[] simple_tags_;
|
| + simple_tags_ = NULL;
|
| +
|
| + simple_tags_size_ = 0;
|
| +}
|
| +
|
| +bool Tag::ExpandSimpleTagsArray() {
|
| + if (simple_tags_size_ > simple_tags_count_)
|
| + return true; // nothing to do yet
|
| +
|
| + const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_;
|
| +
|
| + SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size]; // NOLINT
|
| + if (simple_tags == NULL)
|
| + return false;
|
| +
|
| + for (int idx = 0; idx < simple_tags_count_; ++idx) {
|
| + simple_tags[idx] = simple_tags_[idx]; // shallow copy
|
| + }
|
| +
|
| + delete[] simple_tags_;
|
| +
|
| + simple_tags_ = simple_tags;
|
| + simple_tags_size_ = size;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +uint64 Tag::Write(IMkvWriter* writer) const {
|
| + uint64 payload_size = 0;
|
| +
|
| + for (int idx = 0; idx < simple_tags_count_; ++idx) {
|
| + const SimpleTag& st = simple_tags_[idx];
|
| + payload_size += st.Write(NULL);
|
| + }
|
| +
|
| + const uint64 tag_size =
|
| + EbmlMasterElementSize(kMkvTag, payload_size) + payload_size;
|
| +
|
| + if (writer == NULL)
|
| + return tag_size;
|
| +
|
| + const int64 start = writer->Position();
|
| +
|
| + if (!WriteEbmlMasterElement(writer, kMkvTag, payload_size))
|
| + return 0;
|
| +
|
| + for (int idx = 0; idx < simple_tags_count_; ++idx) {
|
| + const SimpleTag& st = simple_tags_[idx];
|
| +
|
| + if (!st.Write(writer))
|
| + return 0;
|
| + }
|
| +
|
| + const int64 stop = writer->Position();
|
| +
|
| + if (stop >= start && uint64(stop - start) != tag_size)
|
| + return 0;
|
| +
|
| + return tag_size;
|
| +}
|
| +
|
| +// Tag::SimpleTag
|
| +
|
| +void Tag::SimpleTag::Init() {
|
| + tag_name_ = NULL;
|
| + tag_string_ = NULL;
|
| +}
|
| +
|
| +void Tag::SimpleTag::Clear() {
|
| + StrCpy(NULL, &tag_name_);
|
| + StrCpy(NULL, &tag_string_);
|
| +}
|
| +
|
| +bool Tag::SimpleTag::set_tag_name(const char* tag_name) {
|
| + return StrCpy(tag_name, &tag_name_);
|
| +}
|
| +
|
| +bool Tag::SimpleTag::set_tag_string(const char* tag_string) {
|
| + return StrCpy(tag_string, &tag_string_);
|
| +}
|
| +
|
| +uint64 Tag::SimpleTag::Write(IMkvWriter* writer) const {
|
| + uint64 payload_size = EbmlElementSize(kMkvTagName, tag_name_);
|
| +
|
| + payload_size += EbmlElementSize(kMkvTagString, tag_string_);
|
| +
|
| + const uint64 simple_tag_size =
|
| + EbmlMasterElementSize(kMkvSimpleTag, payload_size) + payload_size;
|
| +
|
| + if (writer == NULL)
|
| + return simple_tag_size;
|
| +
|
| + const int64 start = writer->Position();
|
| +
|
| + if (!WriteEbmlMasterElement(writer, kMkvSimpleTag, payload_size))
|
| + return 0;
|
| +
|
| + if (!WriteEbmlElement(writer, kMkvTagName, tag_name_))
|
| + return 0;
|
| +
|
| + if (!WriteEbmlElement(writer, kMkvTagString, tag_string_))
|
| + return 0;
|
| +
|
| + const int64 stop = writer->Position();
|
| +
|
| + if (stop >= start && uint64(stop - start) != simple_tag_size)
|
| + return 0;
|
| +
|
| + return simple_tag_size;
|
| +}
|
| +
|
| +// Tags Class
|
| +
|
| +Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {}
|
| +
|
| +Tags::~Tags() {
|
| + while (tags_count_ > 0) {
|
| + Tag& tag = tags_[--tags_count_];
|
| + tag.Clear();
|
| + }
|
| +
|
| + delete[] tags_;
|
| + tags_ = NULL;
|
| +}
|
| +
|
| +int Tags::Count() const { return tags_count_; }
|
| +
|
| +Tag* Tags::AddTag() {
|
| + if (!ExpandTagsArray())
|
| + return NULL;
|
| +
|
| + Tag& tag = tags_[tags_count_++];
|
| +
|
| + return &tag;
|
| +}
|
| +
|
| +bool Tags::Write(IMkvWriter* writer) const {
|
| + if (writer == NULL)
|
| + return false;
|
| +
|
| + uint64 payload_size = 0;
|
| +
|
| + for (int idx = 0; idx < tags_count_; ++idx) {
|
| + const Tag& tag = tags_[idx];
|
| + payload_size += tag.Write(NULL);
|
| + }
|
| +
|
| + if (!WriteEbmlMasterElement(writer, kMkvTags, payload_size))
|
| + return false;
|
| +
|
| + const int64 start = writer->Position();
|
| +
|
| + for (int idx = 0; idx < tags_count_; ++idx) {
|
| + const Tag& tag = tags_[idx];
|
| +
|
| + const uint64 tag_size = tag.Write(writer);
|
| + if (tag_size == 0) // error
|
| + return 0;
|
| + }
|
| +
|
| + const int64 stop = writer->Position();
|
| +
|
| + if (stop >= start && uint64(stop - start) != payload_size)
|
| + return false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool Tags::ExpandTagsArray() {
|
| + if (tags_size_ > tags_count_)
|
| + return true; // nothing to do yet
|
| +
|
| + const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_;
|
| +
|
| + Tag* const tags = new (std::nothrow) Tag[size]; // NOLINT
|
| + if (tags == NULL)
|
| + return false;
|
| +
|
| + for (int idx = 0; idx < tags_count_; ++idx) {
|
| + const Tag& src = tags_[idx];
|
| + Tag* const dst = tags + idx;
|
| + src.ShallowCopy(dst);
|
| + }
|
| +
|
| + delete[] tags_;
|
| +
|
| + tags_ = tags;
|
| + tags_size_ = size;
|
| +
|
| + return true;
|
| +}
|
| +
|
| ///////////////////////////////////////////////////////////////
|
| //
|
| // Cluster class
|
|
|
| -Cluster::Cluster(uint64 timecode, int64 cues_pos)
|
| +Cluster::Cluster(uint64 timecode, int64 cues_pos, uint64 timecode_scale)
|
| : blocks_added_(0),
|
| finalized_(false),
|
| header_written_(false),
|
| @@ -1432,6 +1758,7 @@ Cluster::Cluster(uint64 timecode, int64 cues_pos)
|
| position_for_cues_(cues_pos),
|
| size_position_(-1),
|
| timecode_(timecode),
|
| + timecode_scale_(timecode_scale),
|
| writer_(NULL) {}
|
|
|
| Cluster::~Cluster() {}
|
| @@ -1444,36 +1771,62 @@ bool Cluster::Init(IMkvWriter* ptr_writer) {
|
| return true;
|
| }
|
|
|
| -bool Cluster::AddFrame(const uint8* frame, uint64 length, uint64 track_number,
|
| +bool Cluster::AddFrame(const Frame* const frame) { return DoWriteFrame(frame); }
|
| +
|
| +bool Cluster::AddFrame(const uint8* data, uint64 length, uint64 track_number,
|
| uint64 abs_timecode, bool is_key) {
|
| - return DoWriteBlock(frame, length, track_number, abs_timecode, is_key ? 1 : 0,
|
| - &WriteSimpleBlock);
|
| + Frame frame;
|
| + if (!frame.Init(data, length))
|
| + return false;
|
| + frame.set_track_number(track_number);
|
| + frame.set_timestamp(abs_timecode);
|
| + frame.set_is_key(is_key);
|
| + return DoWriteFrame(&frame);
|
| }
|
|
|
| -bool Cluster::AddFrameWithAdditional(const uint8* frame, uint64 length,
|
| +bool Cluster::AddFrameWithAdditional(const uint8* data, uint64 length,
|
| const uint8* additional,
|
| uint64 additional_length, uint64 add_id,
|
| uint64 track_number, uint64 abs_timecode,
|
| bool is_key) {
|
| - return DoWriteBlockWithAdditional(
|
| - frame, length, additional, additional_length, add_id, track_number,
|
| - abs_timecode, is_key ? 1 : 0, &WriteBlockWithAdditional);
|
| + if (!additional || additional_length == 0) {
|
| + return false;
|
| + }
|
| + Frame frame;
|
| + if (!frame.Init(data, length) ||
|
| + !frame.AddAdditionalData(additional, additional_length, add_id)) {
|
| + return false;
|
| + }
|
| + frame.set_track_number(track_number);
|
| + frame.set_timestamp(abs_timecode);
|
| + frame.set_is_key(is_key);
|
| + return DoWriteFrame(&frame);
|
| }
|
|
|
| -bool Cluster::AddFrameWithDiscardPadding(const uint8* frame, uint64 length,
|
| +bool Cluster::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
|
| int64 discard_padding,
|
| uint64 track_number,
|
| uint64 abs_timecode, bool is_key) {
|
| - return DoWriteBlockWithDiscardPadding(
|
| - frame, length, discard_padding, track_number, abs_timecode,
|
| - is_key ? 1 : 0, &WriteBlockWithDiscardPadding);
|
| + Frame frame;
|
| + if (!frame.Init(data, length))
|
| + return false;
|
| + frame.set_discard_padding(discard_padding);
|
| + frame.set_track_number(track_number);
|
| + frame.set_timestamp(abs_timecode);
|
| + frame.set_is_key(is_key);
|
| + return DoWriteFrame(&frame);
|
| }
|
|
|
| -bool Cluster::AddMetadata(const uint8* frame, uint64 length,
|
| - uint64 track_number, uint64 abs_timecode,
|
| - uint64 duration_timecode) {
|
| - return DoWriteBlock(frame, length, track_number, abs_timecode,
|
| - duration_timecode, &WriteMetadataBlock);
|
| +bool Cluster::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
|
| + uint64 abs_timecode, uint64 duration_timecode) {
|
| + Frame frame;
|
| + if (!frame.Init(data, length))
|
| + return false;
|
| + frame.set_track_number(track_number);
|
| + frame.set_timestamp(abs_timecode);
|
| + frame.set_duration(duration_timecode);
|
| + frame.set_is_key(true); // All metadata blocks are keyframes.
|
| + return DoWriteFrame(&frame);
|
| }
|
|
|
| void Cluster::AddPayloadSize(uint64 size) { payload_size_ += size; }
|
| @@ -1506,11 +1859,7 @@ uint64 Cluster::Size() const {
|
| return element_size;
|
| }
|
|
|
| -template <typename Type>
|
| -bool Cluster::PreWriteBlock(Type* write_function) {
|
| - if (write_function == NULL)
|
| - return false;
|
| -
|
| +bool Cluster::PreWriteBlock() {
|
| if (finalized_)
|
| return false;
|
|
|
| @@ -1527,10 +1876,6 @@ void Cluster::PostWriteBlock(uint64 element_size) {
|
| ++blocks_added_;
|
| }
|
|
|
| -bool Cluster::IsValidTrackNumber(uint64 track_number) const {
|
| - return (track_number > 0 && track_number <= 0x7E);
|
| -}
|
| -
|
| int64 Cluster::GetRelativeTimecode(int64 abs_timecode) const {
|
| const int64 cluster_timecode = this->Cluster::timecode();
|
| const int64 rel_timecode =
|
| @@ -1542,79 +1887,14 @@ int64 Cluster::GetRelativeTimecode(int64 abs_timecode) const {
|
| return rel_timecode;
|
| }
|
|
|
| -bool Cluster::DoWriteBlock(const uint8* frame, uint64 length,
|
| - uint64 track_number, uint64 abs_timecode,
|
| - uint64 generic_arg, WriteBlock write_block) {
|
| - if (frame == NULL || length == 0)
|
| - return false;
|
| -
|
| - if (!IsValidTrackNumber(track_number))
|
| - return false;
|
| -
|
| - const int64 rel_timecode = GetRelativeTimecode(abs_timecode);
|
| - if (rel_timecode < 0)
|
| - return false;
|
| -
|
| - if (!PreWriteBlock(write_block))
|
| - return false;
|
| -
|
| - const uint64 element_size = (*write_block)(
|
| - writer_, frame, length, track_number, rel_timecode, generic_arg);
|
| - if (element_size == 0)
|
| - return false;
|
| -
|
| - PostWriteBlock(element_size);
|
| - return true;
|
| -}
|
| -
|
| -bool Cluster::DoWriteBlockWithAdditional(
|
| - const uint8* frame, uint64 length, const uint8* additional,
|
| - uint64 additional_length, uint64 add_id, uint64 track_number,
|
| - uint64 abs_timecode, uint64 generic_arg, WriteBlockAdditional write_block) {
|
| - if (frame == NULL || length == 0 || additional == NULL ||
|
| - additional_length == 0)
|
| - return false;
|
| -
|
| - if (!IsValidTrackNumber(track_number))
|
| - return false;
|
| -
|
| - const int64 rel_timecode = GetRelativeTimecode(abs_timecode);
|
| - if (rel_timecode < 0)
|
| - return false;
|
| -
|
| - if (!PreWriteBlock(write_block))
|
| - return false;
|
| -
|
| - const uint64 element_size =
|
| - (*write_block)(writer_, frame, length, additional, additional_length,
|
| - add_id, track_number, rel_timecode, generic_arg);
|
| - if (element_size == 0)
|
| - return false;
|
| -
|
| - PostWriteBlock(element_size);
|
| - return true;
|
| -}
|
| -
|
| -bool Cluster::DoWriteBlockWithDiscardPadding(
|
| - const uint8* frame, uint64 length, int64 discard_padding,
|
| - uint64 track_number, uint64 abs_timecode, uint64 generic_arg,
|
| - WriteBlockDiscardPadding write_block) {
|
| - if (frame == NULL || length == 0 || discard_padding <= 0)
|
| - return false;
|
| -
|
| - if (!IsValidTrackNumber(track_number))
|
| - return false;
|
| -
|
| - const int64 rel_timecode = GetRelativeTimecode(abs_timecode);
|
| - if (rel_timecode < 0)
|
| +bool Cluster::DoWriteFrame(const Frame* const frame) {
|
| + if (!frame || !frame->IsValid())
|
| return false;
|
|
|
| - if (!PreWriteBlock(write_block))
|
| + if (!PreWriteBlock())
|
| return false;
|
|
|
| - const uint64 element_size =
|
| - (*write_block)(writer_, frame, length, discard_padding, track_number,
|
| - rel_timecode, generic_arg);
|
| + const uint64 element_size = WriteFrame(writer_, frame, this);
|
| if (element_size == 0)
|
| return false;
|
|
|
| @@ -1860,7 +2140,7 @@ bool SegmentInfo::Write(IMkvWriter* writer) {
|
| if (duration_ > 0.0)
|
| size += EbmlElementSize(kMkvDuration, static_cast<float>(duration_));
|
| if (date_utc_ != LLONG_MIN)
|
| - size += EbmlDateElementSize(kMkvDateUTC, date_utc_);
|
| + size += EbmlDateElementSize(kMkvDateUTC);
|
| size += EbmlElementSize(kMkvMuxingApp, muxing_app_);
|
| size += EbmlElementSize(kMkvWritingApp, writing_app_);
|
|
|
| @@ -1966,6 +2246,8 @@ Segment::Segment()
|
| output_cues_(true),
|
| payload_pos_(0),
|
| size_position_(0),
|
| + doc_type_version_(kDefaultDocTypeVersion),
|
| + doc_type_version_written_(0),
|
| writer_cluster_(NULL),
|
| writer_cues_(NULL),
|
| writer_header_(NULL) {
|
| @@ -2012,7 +2294,6 @@ Segment::~Segment() {
|
|
|
| void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index,
|
| uint64* cues_size) {
|
| - const uint64 old_cues_size = *cues_size;
|
| CuePoint* const cue_point = cues_.GetCueByIndex(index);
|
| if (cue_point == NULL)
|
| return;
|
| @@ -2020,18 +2301,19 @@ void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index,
|
| const uint64 cluster_pos = cue_point->cluster_pos() + diff;
|
| cue_point->set_cluster_pos(cluster_pos); // update the new cluster position
|
| // New size of the cue is computed as follows
|
| - // Let a = current size of Cues Element
|
| - // Let b = Difference in Cue Point's size after this pass
|
| - // Let c = Difference in length of Cues Element's size
|
| - // (This is computed as CodedSize(a + b) - CodedSize(a)
|
| - // Let d = a + b + c. Now d is the new size of the Cues element which is
|
| - // passed on to the next recursive call.
|
| + // Let a = current sum of size of all CuePoints
|
| + // Let b = Increase in Cue Point's size due to this iteration
|
| + // Let c = Increase in size of Cues Element's length due to this iteration
|
| + // (This is computed as CodedSize(a + b) - CodedSize(a))
|
| + // Let d = b + c. Now d is the |diff| passed to the next recursive call.
|
| + // Let e = a + b. Now e is the |cues_size| passed to the next recursive
|
| + // call.
|
| const uint64 cue_point_size_diff = cue_point->Size() - old_cue_point_size;
|
| const uint64 cue_size_diff =
|
| GetCodedUIntSize(*cues_size + cue_point_size_diff) -
|
| GetCodedUIntSize(*cues_size);
|
| - *cues_size += cue_point_size_diff + cue_size_diff;
|
| - diff = *cues_size - old_cues_size;
|
| + *cues_size += cue_point_size_diff;
|
| + diff = cue_size_diff + cue_point_size_diff;
|
| if (diff > 0) {
|
| for (int32 i = 0; i < cues_.cue_entries_size(); ++i) {
|
| MoveCuesBeforeClustersHelper(diff, i, cues_size);
|
| @@ -2041,8 +2323,10 @@ void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index,
|
|
|
| void Segment::MoveCuesBeforeClusters() {
|
| const uint64 current_cue_size = cues_.Size();
|
| - uint64 cue_size = current_cue_size;
|
| - for (int32 i = 0; i < cues_.cue_entries_size(); i++)
|
| + uint64 cue_size = 0;
|
| + for (int32 i = 0; i < cues_.cue_entries_size(); ++i)
|
| + cue_size += cues_.GetCueByIndex(i)->Size();
|
| + for (int32 i = 0; i < cues_.cue_entries_size(); ++i)
|
| MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size);
|
|
|
| // Adjust the Seek Entry to reflect the change in position
|
| @@ -2164,12 +2448,24 @@ bool Segment::Finalize() {
|
| if (size_position_ == -1)
|
| return false;
|
|
|
| - const int64 pos = writer_header_->Position();
|
| const int64 segment_size = MaxOffset();
|
| -
|
| if (segment_size < 1)
|
| return false;
|
|
|
| + const int64 pos = writer_header_->Position();
|
| + UpdateDocTypeVersion();
|
| + if (doc_type_version_ != doc_type_version_written_) {
|
| + if (writer_header_->Position(0))
|
| + return false;
|
| +
|
| + if (!WriteEbmlHeader(writer_header_, doc_type_version_))
|
| + return false;
|
| + if (writer_header_->Position() != ebml_header_size_)
|
| + return false;
|
| +
|
| + doc_type_version_written_ = doc_type_version_;
|
| + }
|
| +
|
| if (writer_header_->Position(size_position_))
|
| return false;
|
|
|
| @@ -2210,6 +2506,8 @@ Track* Segment::AddTrack(int32 number) {
|
|
|
| Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
|
|
|
| +Tag* Segment::AddTag() { return tags_.AddTag(); }
|
| +
|
| uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) {
|
| VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_); // NOLINT
|
| if (!track)
|
| @@ -2264,157 +2562,104 @@ uint64 Segment::AddAudioTrack(int32 sample_rate, int32 channels, int32 number) {
|
| return track->number();
|
| }
|
|
|
| -bool Segment::AddFrame(const uint8* frame, uint64 length, uint64 track_number,
|
| +bool Segment::AddFrame(const uint8* data, uint64 length, uint64 track_number,
|
| uint64 timestamp, bool is_key) {
|
| - if (!frame)
|
| - return false;
|
| -
|
| - if (!CheckHeaderInfo())
|
| - return false;
|
| -
|
| - // Check for non-monotonically increasing timestamps.
|
| - if (timestamp < last_timestamp_)
|
| - return false;
|
| -
|
| - // If the segment has a video track hold onto audio frames to make sure the
|
| - // audio that is associated with the start time of a video key-frame is
|
| - // muxed into the same cluster.
|
| - if (has_video_ && tracks_.TrackIsAudio(track_number) && !force_new_cluster_) {
|
| - Frame* const new_frame = new (std::nothrow) Frame();
|
| - if (new_frame == NULL || !new_frame->Init(frame, length))
|
| - return false;
|
| - new_frame->set_track_number(track_number);
|
| - new_frame->set_timestamp(timestamp);
|
| - new_frame->set_is_key(is_key);
|
| -
|
| - if (!QueueFrame(new_frame))
|
| - return false;
|
| -
|
| - return true;
|
| - }
|
| -
|
| - if (!DoNewClusterProcessing(track_number, timestamp, is_key))
|
| - return false;
|
| -
|
| - if (cluster_list_size_ < 1)
|
| - return false;
|
| -
|
| - Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
|
| - if (!cluster)
|
| + if (!data)
|
| return false;
|
|
|
| - const uint64 timecode_scale = segment_info_.timecode_scale();
|
| - const uint64 abs_timecode = timestamp / timecode_scale;
|
| -
|
| - if (!cluster->AddFrame(frame, length, track_number, abs_timecode, is_key))
|
| + Frame frame;
|
| + if (!frame.Init(data, length))
|
| return false;
|
| -
|
| - if (new_cuepoint_ && cues_track_ == track_number) {
|
| - if (!AddCuePoint(timestamp, cues_track_))
|
| - return false;
|
| - }
|
| -
|
| - if (timestamp > last_timestamp_)
|
| - last_timestamp_ = timestamp;
|
| -
|
| - return true;
|
| + frame.set_track_number(track_number);
|
| + frame.set_timestamp(timestamp);
|
| + frame.set_is_key(is_key);
|
| + return AddGenericFrame(&frame);
|
| }
|
|
|
| -bool Segment::AddFrameWithAdditional(const uint8* frame, uint64 length,
|
| +bool Segment::AddFrameWithAdditional(const uint8* data, uint64 length,
|
| const uint8* additional,
|
| uint64 additional_length, uint64 add_id,
|
| uint64 track_number, uint64 timestamp,
|
| bool is_key) {
|
| - if (frame == NULL || additional == NULL)
|
| + if (!data || !additional)
|
| return false;
|
|
|
| - if (!CheckHeaderInfo())
|
| - return false;
|
| -
|
| - // Check for non-monotonically increasing timestamps.
|
| - if (timestamp < last_timestamp_)
|
| + Frame frame;
|
| + if (!frame.Init(data, length) ||
|
| + !frame.AddAdditionalData(additional, additional_length, add_id)) {
|
| return false;
|
| -
|
| - // If the segment has a video track hold onto audio frames to make sure the
|
| - // audio that is associated with the start time of a video key-frame is
|
| - // muxed into the same cluster.
|
| - if (has_video_ && tracks_.TrackIsAudio(track_number) && !force_new_cluster_) {
|
| - Frame* const new_frame = new (std::nothrow) Frame();
|
| - if (new_frame == NULL || !new_frame->Init(frame, length))
|
| - return false;
|
| - new_frame->set_track_number(track_number);
|
| - new_frame->set_timestamp(timestamp);
|
| - new_frame->set_is_key(is_key);
|
| -
|
| - if (!QueueFrame(new_frame))
|
| - return false;
|
| -
|
| - return true;
|
| }
|
| + frame.set_track_number(track_number);
|
| + frame.set_timestamp(timestamp);
|
| + frame.set_is_key(is_key);
|
| + return AddGenericFrame(&frame);
|
| +}
|
|
|
| - if (!DoNewClusterProcessing(track_number, timestamp, is_key))
|
| +bool Segment::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
|
| + int64 discard_padding,
|
| + uint64 track_number, uint64 timestamp,
|
| + bool is_key) {
|
| + if (!data)
|
| return false;
|
|
|
| - if (cluster_list_size_ < 1)
|
| + Frame frame;
|
| + if (!frame.Init(data, length))
|
| return false;
|
| + frame.set_discard_padding(discard_padding);
|
| + frame.set_track_number(track_number);
|
| + frame.set_timestamp(timestamp);
|
| + frame.set_is_key(is_key);
|
| + return AddGenericFrame(&frame);
|
| +}
|
|
|
| - Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
|
| - if (cluster == NULL)
|
| +bool Segment::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
|
| + uint64 timestamp_ns, uint64 duration_ns) {
|
| + if (!data)
|
| return false;
|
|
|
| - const uint64 timecode_scale = segment_info_.timecode_scale();
|
| - const uint64 abs_timecode = timestamp / timecode_scale;
|
| -
|
| - if (!cluster->AddFrameWithAdditional(frame, length, additional,
|
| - additional_length, add_id, track_number,
|
| - abs_timecode, is_key))
|
| + Frame frame;
|
| + if (!frame.Init(data, length))
|
| return false;
|
| -
|
| - if (new_cuepoint_ && cues_track_ == track_number) {
|
| - if (!AddCuePoint(timestamp, cues_track_))
|
| - return false;
|
| - }
|
| -
|
| - if (timestamp > last_timestamp_)
|
| - last_timestamp_ = timestamp;
|
| -
|
| - return true;
|
| + frame.set_track_number(track_number);
|
| + frame.set_timestamp(timestamp_ns);
|
| + frame.set_duration(duration_ns);
|
| + frame.set_is_key(true); // All metadata blocks are keyframes.
|
| + return AddGenericFrame(&frame);
|
| }
|
|
|
| -bool Segment::AddFrameWithDiscardPadding(const uint8* frame, uint64 length,
|
| - int64 discard_padding,
|
| - uint64 track_number, uint64 timestamp,
|
| - bool is_key) {
|
| - if (frame == NULL || discard_padding <= 0)
|
| +bool Segment::AddGenericFrame(const Frame* frame) {
|
| + if (!frame)
|
| return false;
|
|
|
| if (!CheckHeaderInfo())
|
| return false;
|
|
|
| // Check for non-monotonically increasing timestamps.
|
| - if (timestamp < last_timestamp_)
|
| + if (frame->timestamp() < last_timestamp_)
|
| return false;
|
|
|
| + // Check if the track number is valid.
|
| + if (!tracks_.GetTrackByNumber(frame->track_number()))
|
| + return false;
|
| +
|
| + if (frame->discard_padding() != 0)
|
| + doc_type_version_ = 4;
|
| +
|
| // If the segment has a video track hold onto audio frames to make sure the
|
| // audio that is associated with the start time of a video key-frame is
|
| // muxed into the same cluster.
|
| - if (has_video_ && tracks_.TrackIsAudio(track_number) && !force_new_cluster_) {
|
| + if (has_video_ && tracks_.TrackIsAudio(frame->track_number()) &&
|
| + !force_new_cluster_) {
|
| Frame* const new_frame = new (std::nothrow) Frame();
|
| - if (new_frame == NULL || !new_frame->Init(frame, length))
|
| + if (!new_frame || !new_frame->CopyFrom(*frame))
|
| return false;
|
| - new_frame->set_track_number(track_number);
|
| - new_frame->set_timestamp(timestamp);
|
| - new_frame->set_is_key(is_key);
|
| - new_frame->set_discard_padding(discard_padding);
|
| -
|
| - if (!QueueFrame(new_frame))
|
| - return false;
|
| -
|
| - return true;
|
| + return QueueFrame(new_frame);
|
| }
|
|
|
| - if (!DoNewClusterProcessing(track_number, timestamp, is_key))
|
| + if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(),
|
| + frame->is_key())) {
|
| return false;
|
| + }
|
|
|
| if (cluster_list_size_ < 1)
|
| return false;
|
| @@ -2423,84 +2668,38 @@ bool Segment::AddFrameWithDiscardPadding(const uint8* frame, uint64 length,
|
| if (!cluster)
|
| return false;
|
|
|
| - const uint64 timecode_scale = segment_info_.timecode_scale();
|
| - const uint64 abs_timecode = timestamp / timecode_scale;
|
| -
|
| - if (!cluster->AddFrameWithDiscardPadding(
|
| - frame, length, discard_padding, track_number, abs_timecode, is_key)) {
|
| - return false;
|
| - }
|
| -
|
| - if (new_cuepoint_ && cues_track_ == track_number) {
|
| - if (!AddCuePoint(timestamp, cues_track_))
|
| + // If the Frame is not a SimpleBlock, then set the reference_block_timestamp
|
| + // if it is not set already.
|
| + bool frame_created = false;
|
| + if (!frame->CanBeSimpleBlock() && !frame->is_key() &&
|
| + !frame->reference_block_timestamp_set()) {
|
| + Frame* const new_frame = new (std::nothrow) Frame();
|
| + if (!new_frame->CopyFrom(*frame))
|
| return false;
|
| + new_frame->set_reference_block_timestamp(
|
| + last_track_timestamp_[frame->track_number() - 1]);
|
| + frame = new_frame;
|
| + frame_created = true;
|
| }
|
|
|
| - if (timestamp > last_timestamp_)
|
| - last_timestamp_ = timestamp;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool Segment::AddMetadata(const uint8* frame, uint64 length,
|
| - uint64 track_number, uint64 timestamp_ns,
|
| - uint64 duration_ns) {
|
| - if (!frame)
|
| - return false;
|
| -
|
| - if (!CheckHeaderInfo())
|
| + if (!cluster->AddFrame(frame))
|
| return false;
|
|
|
| - // Check for non-monotonically increasing timestamps.
|
| - if (timestamp_ns < last_timestamp_)
|
| - return false;
|
| -
|
| - if (!DoNewClusterProcessing(track_number, timestamp_ns, true))
|
| - return false;
|
| -
|
| - if (cluster_list_size_ < 1)
|
| - return false;
|
| -
|
| - Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
|
| -
|
| - if (!cluster)
|
| - return false;
|
| -
|
| - const uint64 timecode_scale = segment_info_.timecode_scale();
|
| - const uint64 abs_timecode = timestamp_ns / timecode_scale;
|
| - const uint64 duration_timecode = duration_ns / timecode_scale;
|
| + if (new_cuepoint_ && cues_track_ == frame->track_number()) {
|
| + if (!AddCuePoint(frame->timestamp(), cues_track_))
|
| + return false;
|
| + }
|
|
|
| - if (!cluster->AddMetadata(frame, length, track_number, abs_timecode,
|
| - duration_timecode))
|
| - return false;
|
| + last_timestamp_ = frame->timestamp();
|
| + last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
|
| + last_block_duration_ = frame->duration();
|
|
|
| - if (timestamp_ns > last_timestamp_)
|
| - last_timestamp_ = timestamp_ns;
|
| + if (frame_created)
|
| + delete frame;
|
|
|
| return true;
|
| }
|
|
|
| -bool Segment::AddGenericFrame(const Frame* frame) {
|
| - last_block_duration_ = frame->duration();
|
| - if (!tracks_.TrackIsAudio(frame->track_number()) &&
|
| - !tracks_.TrackIsVideo(frame->track_number()) && frame->duration() > 0) {
|
| - return AddMetadata(frame->frame(), frame->length(), frame->track_number(),
|
| - frame->timestamp(), frame->duration());
|
| - } else if (frame->additional() && frame->additional_length() > 0) {
|
| - return AddFrameWithAdditional(
|
| - frame->frame(), frame->length(), frame->additional(),
|
| - frame->additional_length(), frame->add_id(), frame->track_number(),
|
| - frame->timestamp(), frame->is_key());
|
| - } else if (frame->discard_padding() > 0) {
|
| - return AddFrameWithDiscardPadding(
|
| - frame->frame(), frame->length(), frame->discard_padding(),
|
| - frame->track_number(), frame->timestamp(), frame->is_key());
|
| - } else {
|
| - return AddFrame(frame->frame(), frame->length(), frame->track_number(),
|
| - frame->timestamp(), frame->is_key());
|
| - }
|
| -}
|
| -
|
| void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; }
|
|
|
| bool Segment::SetChunking(bool chunking, const char* filename) {
|
| @@ -2598,9 +2797,13 @@ Track* Segment::GetTrackByNumber(uint64 track_number) const {
|
| }
|
|
|
| bool Segment::WriteSegmentHeader() {
|
| + UpdateDocTypeVersion();
|
| +
|
| // TODO(fgalligan): Support more than one segment.
|
| - if (!WriteEbmlHeader(writer_header_))
|
| + if (!WriteEbmlHeader(writer_header_, doc_type_version_))
|
| return false;
|
| + doc_type_version_written_ = doc_type_version_;
|
| + ebml_header_size_ = static_cast<int32>(writer_header_->Position());
|
|
|
| // Write "unknown" (-1) as segment size value. If mode is kFile, Segment
|
| // will write over duration when the file is finalized.
|
| @@ -2645,6 +2848,13 @@ bool Segment::WriteSegmentHeader() {
|
| return false;
|
| }
|
|
|
| + if (tags_.Count() > 0) {
|
| + if (!seek_head_.AddSeekEntry(kMkvTags, MaxOffset()))
|
| + return false;
|
| + if (!tags_.Write(writer_header_))
|
| + return false;
|
| + }
|
| +
|
| if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) {
|
| if (!chunk_writer_header_)
|
| return false;
|
| @@ -2740,7 +2950,7 @@ bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) {
|
| const int32 new_capacity =
|
| (cluster_list_capacity_ <= 0) ? 1 : cluster_list_capacity_ * 2;
|
| Cluster** const clusters =
|
| - new (std::nothrow) Cluster* [new_capacity]; // NOLINT
|
| + new (std::nothrow) Cluster*[new_capacity]; // NOLINT
|
| if (!clusters)
|
| return false;
|
|
|
| @@ -2796,7 +3006,8 @@ bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) {
|
|
|
| Cluster*& cluster = cluster_list_[cluster_list_size_];
|
| const int64 offset = MaxOffset();
|
| - cluster = new (std::nothrow) Cluster(cluster_timecode, offset); // NOLINT
|
| + cluster = new (std::nothrow) Cluster(cluster_timecode, // NOLINT
|
| + offset, segment_info_.timecode_scale());
|
| if (!cluster)
|
| return false;
|
|
|
| @@ -2873,6 +3084,19 @@ bool Segment::CheckHeaderInfo() {
|
| return true;
|
| }
|
|
|
| +void Segment::UpdateDocTypeVersion() {
|
| + for (uint32 index = 0; index < tracks_.track_entries_size(); ++index) {
|
| + const Track* track = tracks_.GetTrackByIndex(index);
|
| + if (track == NULL)
|
| + break;
|
| + if ((track->codec_delay() || track->seek_pre_roll()) &&
|
| + doc_type_version_ < 4) {
|
| + doc_type_version_ = 4;
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| bool Segment::UpdateChunkName(const char* ext, char** name) const {
|
| if (!name || !ext)
|
| return false;
|
| @@ -2932,7 +3156,7 @@ bool Segment::QueueFrame(Frame* frame) {
|
| if (new_capacity < 1)
|
| return false;
|
|
|
| - Frame** const frames = new (std::nothrow) Frame* [new_capacity]; // NOLINT
|
| + Frame** const frames = new (std::nothrow) Frame*[new_capacity]; // NOLINT
|
| if (!frames)
|
| return false;
|
|
|
| @@ -2962,34 +3186,24 @@ int Segment::WriteFramesAll() {
|
| if (!cluster)
|
| return -1;
|
|
|
| - const uint64 timecode_scale = segment_info_.timecode_scale();
|
| -
|
| for (int32 i = 0; i < frames_size_; ++i) {
|
| Frame*& frame = frames_[i];
|
| - const uint64 frame_timestamp = frame->timestamp(); // ns
|
| - const uint64 frame_timecode = frame_timestamp / timecode_scale;
|
| -
|
| - if (frame->discard_padding() > 0) {
|
| - if (!cluster->AddFrameWithDiscardPadding(
|
| - frame->frame(), frame->length(), frame->discard_padding(),
|
| - frame->track_number(), frame_timecode, frame->is_key())) {
|
| - return -1;
|
| - }
|
| - } else {
|
| - if (!cluster->AddFrame(frame->frame(), frame->length(),
|
| - frame->track_number(), frame_timecode,
|
| - frame->is_key())) {
|
| - return -1;
|
| - }
|
| - }
|
| + // TODO(jzern/vigneshv): using Segment::AddGenericFrame here would limit the
|
| + // places where |doc_type_version_| needs to be updated.
|
| + if (frame->discard_padding() != 0)
|
| + doc_type_version_ = 4;
|
| + if (!cluster->AddFrame(frame))
|
| + return -1;
|
|
|
| if (new_cuepoint_ && cues_track_ == frame->track_number()) {
|
| - if (!AddCuePoint(frame_timestamp, cues_track_))
|
| + if (!AddCuePoint(frame->timestamp(), cues_track_))
|
| return -1;
|
| }
|
|
|
| - if (frame_timestamp > last_timestamp_)
|
| - last_timestamp_ = frame_timestamp;
|
| + if (frame->timestamp() > last_timestamp_) {
|
| + last_timestamp_ = frame->timestamp();
|
| + last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
|
| + }
|
|
|
| delete frame;
|
| frame = NULL;
|
| @@ -3013,7 +3227,6 @@ bool Segment::WriteFramesLessThan(uint64 timestamp) {
|
| if (!cluster)
|
| return false;
|
|
|
| - const uint64 timecode_scale = segment_info_.timecode_scale();
|
| int32 shift_left = 0;
|
|
|
| // TODO(fgalligan): Change this to use the durations of frames instead of
|
| @@ -3025,33 +3238,22 @@ bool Segment::WriteFramesLessThan(uint64 timestamp) {
|
| break;
|
|
|
| const Frame* const frame_prev = frames_[i - 1];
|
| - const uint64 frame_timestamp = frame_prev->timestamp();
|
| - const uint64 frame_timecode = frame_timestamp / timecode_scale;
|
| - const int64 discard_padding = frame_prev->discard_padding();
|
| -
|
| - if (discard_padding > 0) {
|
| - if (!cluster->AddFrameWithDiscardPadding(
|
| - frame_prev->frame(), frame_prev->length(), discard_padding,
|
| - frame_prev->track_number(), frame_timecode,
|
| - frame_prev->is_key())) {
|
| - return false;
|
| - }
|
| - } else {
|
| - if (!cluster->AddFrame(frame_prev->frame(), frame_prev->length(),
|
| - frame_prev->track_number(), frame_timecode,
|
| - frame_prev->is_key())) {
|
| - return false;
|
| - }
|
| - }
|
| + if (frame_prev->discard_padding() != 0)
|
| + doc_type_version_ = 4;
|
| + if (!cluster->AddFrame(frame_prev))
|
| + return false;
|
|
|
| if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
|
| - if (!AddCuePoint(frame_timestamp, cues_track_))
|
| + if (!AddCuePoint(frame_prev->timestamp(), cues_track_))
|
| return false;
|
| }
|
|
|
| ++shift_left;
|
| - if (frame_timestamp > last_timestamp_)
|
| - last_timestamp_ = frame_timestamp;
|
| + if (frame_prev->timestamp() > last_timestamp_) {
|
| + last_timestamp_ = frame_prev->timestamp();
|
| + last_track_timestamp_[frame_prev->track_number() - 1] =
|
| + frame_prev->timestamp();
|
| + }
|
|
|
| delete frame_prev;
|
| }
|
|
|