diff --git a/mkvmuxer.cpp b/mkvmuxer.cpp index 8ae0dda..6d06977 100644 --- a/mkvmuxer.cpp +++ b/mkvmuxer.cpp @@ -523,6 +523,7 @@ Track::Track(unsigned int* seed) uid_(MakeUID(seed)), codec_delay_(0), seek_pre_roll_(0), + default_duration_(0), codec_private_length_(0), content_encoding_entries_(NULL), content_encoding_entries_size_(0) { @@ -600,6 +601,8 @@ uint64 Track::PayloadSize() const { size += EbmlElementSize(kMkvCodecDelay, codec_delay_); if (seek_pre_roll_) size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_); + if (default_duration_) + size += EbmlElementSize(kMkvDefaultDuration, default_duration_); if (content_encoding_entries_size_ > 0) { uint64 content_encodings_size = 0; @@ -652,7 +655,8 @@ bool Track::Write(IMkvWriter* writer) const { size += EbmlElementSize(kMkvCodecDelay, codec_delay_); if (seek_pre_roll_) size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_); - + if (default_duration_) + size += EbmlElementSize(kMkvDefaultDuration, default_duration_); const int64 payload_position = writer->Position(); if (payload_position < 0) @@ -679,6 +683,10 @@ bool Track::Write(IMkvWriter* writer) const { if (!WriteEbmlElement(writer, kMkvSeekPreRoll, seek_pre_roll_)) return false; } + if (default_duration_) { + if (!WriteEbmlElement(writer, kMkvDefaultDuration, default_duration_)) + return false; + } if (codec_id_) { if (!WriteEbmlElement(writer, kMkvCodecID, codec_id_)) return false; @@ -1888,6 +1896,7 @@ SegmentInfo::SegmentInfo() muxing_app_(NULL), timecode_scale_(1000000ULL), writing_app_(NULL), + date_utc_(LLONG_MIN), duration_pos_(-1) { } @@ -1975,6 +1984,8 @@ bool SegmentInfo::Write(IMkvWriter* writer) { uint64 size = EbmlElementSize(kMkvTimecodeScale, timecode_scale_); if (duration_ > 0.0) size += EbmlElementSize(kMkvDuration, static_cast(duration_)); + if (date_utc_ != LLONG_MIN) + size += EbmlDateElementSize(kMkvDateUTC, date_utc_); size += EbmlElementSize(kMkvMuxingApp, muxing_app_); size += EbmlElementSize(kMkvWritingApp, writing_app_); @@ -1996,6 +2007,9 @@ bool SegmentInfo::Write(IMkvWriter* writer) { return false; } + if (date_utc_ != LLONG_MIN) + WriteEbmlDateElement(writer, kMkvDateUTC, date_utc_); + if (!WriteEbmlElement(writer, kMkvMuxingApp, muxing_app_)) return false; if (!WriteEbmlElement(writer, kMkvWritingApp, writing_app_)) @@ -2977,12 +2991,12 @@ bool Segment::DoNewClusterProcessing(uint64 track_number, if (result < 0) // error return false; - // Always set force_new_cluster_ to false after TestFrame. - force_new_cluster_ = false; + // Always set force_new_cluster_ to false after TestFrame. + force_new_cluster_ = false; - // A non-zero result means create a new cluster. - if (result > 0 && !MakeNewCluster(frame_timestamp_ns)) - return false; + // A non-zero result means create a new cluster. + if (result > 0 && !MakeNewCluster(frame_timestamp_ns)) + return false; // Write queued (audio) frames. const int frame_count = WriteFramesAll(); diff --git a/mkvmuxer.hpp b/mkvmuxer.hpp index 63a315e..cadc031 100644 --- a/mkvmuxer.hpp +++ b/mkvmuxer.hpp @@ -353,6 +353,10 @@ class Track { seek_pre_roll_ = seek_pre_roll; } uint64 seek_pre_roll() const { return seek_pre_roll_; } + void set_default_duration(uint64 default_duration) { + default_duration_ = default_duration; + } + uint64 default_duration() const { return default_duration_; } uint64 codec_private_length() const { return codec_private_length_; } uint32 content_encoding_entries_size() const { @@ -360,7 +364,7 @@ class Track { } private: - // Track element names + // Track element names. char* codec_id_; uint8* codec_private_; char* language_; @@ -371,6 +375,7 @@ class Track { uint64 uid_; uint64 codec_delay_; uint64 seek_pre_roll_; + uint64 default_duration_; // Size of the CodecPrivate data in bytes. uint64 codec_private_length_; @@ -993,6 +998,8 @@ class SegmentInfo { uint64 timecode_scale() const { return timecode_scale_; } void set_writing_app(const char* app); const char* writing_app() const { return writing_app_; } + void set_date_utc(int64 date_utc) { date_utc_ = date_utc; } + int64 date_utc() const { return date_utc_; } private: // Segment Information element names. @@ -1004,6 +1011,8 @@ class SegmentInfo { uint64 timecode_scale_; // Initially set to libwebm-%d.%d.%d.%d, major, minor, build, revision. char* writing_app_; + // LLONG_MIN when DateUTC is not set. + int64 date_utc_; // The file position of the duration element. int64 duration_pos_; diff --git a/mkvmuxerutil.cpp b/mkvmuxerutil.cpp index 18060e9..2424da5 100644 --- a/mkvmuxerutil.cpp +++ b/mkvmuxerutil.cpp @@ -29,6 +29,13 @@ namespace mkvmuxer { +namespace { + +// Date elements are always 8 octets in size. +const int kDateElementSize = 8; + +} // namespace + int32 GetCodedUIntSize(uint64 value) { if (value < 0x000000000000007FULL) return 1; @@ -137,6 +144,19 @@ uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) { return ebml_size; } +uint64 EbmlDateElementSize(uint64 type, int64 value) { + // Size of EBML ID + uint64 ebml_size = GetUIntSize(type); + + // Datasize + ebml_size += kDateElementSize; + + // Size of Datasize + ebml_size++; + + return ebml_size; +} + int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size) { if (!writer || size < 1 || size > 8) return -1; @@ -321,6 +341,22 @@ bool WriteEbmlElement(IMkvWriter* writer, return true; } +bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value) { + if (!writer) + return false; + + if (WriteID(writer, type)) + return false; + + if (WriteUInt(writer, kDateElementSize)) + return false; + + if (SerializeInt(writer, value, kDateElementSize)) + return false; + + return true; +} + uint64 WriteSimpleBlock(IMkvWriter* writer, const uint8* data, uint64 length, diff --git a/mkvmuxerutil.hpp b/mkvmuxerutil.hpp index d196ad3..31532c4 100644 --- a/mkvmuxerutil.hpp +++ b/mkvmuxerutil.hpp @@ -30,6 +30,7 @@ uint64 EbmlElementSize(uint64 type, uint64 value); uint64 EbmlElementSize(uint64 type, float value); uint64 EbmlElementSize(uint64 type, const char* value); uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size); +uint64 EbmlDateElementSize(uint64 type, int64 value); // Creates an EBML coded number from |value| and writes it out. The size of // the coded number is determined by the value of |value|. |value| must not @@ -56,6 +57,7 @@ bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value, uint64 size); +bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value); // Output an Mkv Simple Block. // Inputs: