| Index: source/libvpx/third_party/libwebm/mkvmuxerutil.cpp
|
| diff --git a/source/libvpx/third_party/libwebm/mkvmuxerutil.cpp b/source/libvpx/third_party/libwebm/mkvmuxerutil.cpp
|
| index 3fb9bc9dc776ca49c8495fcf47db35e6bdbba168..27ab15d51f1ed4b51e822fc07f9484ea0c32ce69 100644
|
| --- a/source/libvpx/third_party/libwebm/mkvmuxerutil.cpp
|
| +++ b/source/libvpx/third_party/libwebm/mkvmuxerutil.cpp
|
| @@ -15,18 +15,19 @@
|
| #include <cassert>
|
| #include <cmath>
|
| #include <cstdio>
|
| -#ifdef _MSC_VER
|
| -#define _CRT_RAND_S
|
| -#endif
|
| #include <cstdlib>
|
| #include <cstring>
|
| #include <ctime>
|
| -
|
| #include <new>
|
|
|
| #include "mkvwriter.hpp"
|
| #include "webmids.hpp"
|
|
|
| +#ifdef _MSC_VER
|
| +// Disable MSVC warnings that suggest making code non-portable.
|
| +#pragma warning(disable : 4996)
|
| +#endif
|
| +
|
| namespace mkvmuxer {
|
|
|
| namespace {
|
| @@ -34,6 +35,144 @@ namespace {
|
| // Date elements are always 8 octets in size.
|
| const int kDateElementSize = 8;
|
|
|
| +uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
|
| + uint64 timecode_scale) {
|
| + uint64 block_additional_elem_size = 0;
|
| + uint64 block_addid_elem_size = 0;
|
| + uint64 block_more_payload_size = 0;
|
| + uint64 block_more_elem_size = 0;
|
| + uint64 block_additions_payload_size = 0;
|
| + uint64 block_additions_elem_size = 0;
|
| + if (frame->additional()) {
|
| + block_additional_elem_size = EbmlElementSize(
|
| + kMkvBlockAdditional, frame->additional(), frame->additional_length());
|
| + block_addid_elem_size = EbmlElementSize(kMkvBlockAddID, frame->add_id());
|
| +
|
| + block_more_payload_size =
|
| + block_addid_elem_size + block_additional_elem_size;
|
| + block_more_elem_size =
|
| + EbmlMasterElementSize(kMkvBlockMore, block_more_payload_size) +
|
| + block_more_payload_size;
|
| + block_additions_payload_size = block_more_elem_size;
|
| + block_additions_elem_size =
|
| + EbmlMasterElementSize(kMkvBlockAdditions,
|
| + block_additions_payload_size) +
|
| + block_additions_payload_size;
|
| + }
|
| +
|
| + uint64 discard_padding_elem_size = 0;
|
| + if (frame->discard_padding() != 0) {
|
| + discard_padding_elem_size =
|
| + EbmlElementSize(kMkvDiscardPadding, frame->discard_padding());
|
| + }
|
| +
|
| + const uint64 reference_block_timestamp =
|
| + frame->reference_block_timestamp() / timecode_scale;
|
| + uint64 reference_block_elem_size = 0;
|
| + if (!frame->is_key()) {
|
| + reference_block_elem_size =
|
| + EbmlElementSize(kMkvReferenceBlock, reference_block_timestamp);
|
| + }
|
| +
|
| + const uint64 duration = frame->duration() / timecode_scale;
|
| + uint64 block_duration_elem_size = 0;
|
| + if (duration > 0)
|
| + block_duration_elem_size = EbmlElementSize(kMkvBlockDuration, duration);
|
| +
|
| + const uint64 block_payload_size = 4 + frame->length();
|
| + const uint64 block_elem_size =
|
| + EbmlMasterElementSize(kMkvBlock, block_payload_size) + block_payload_size;
|
| +
|
| + const uint64 block_group_payload_size =
|
| + block_elem_size + block_additions_elem_size + block_duration_elem_size +
|
| + discard_padding_elem_size + reference_block_elem_size;
|
| +
|
| + if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
|
| + block_group_payload_size)) {
|
| + return 0;
|
| + }
|
| +
|
| + if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
|
| + return 0;
|
| +
|
| + if (WriteUInt(writer, frame->track_number()))
|
| + return 0;
|
| +
|
| + if (SerializeInt(writer, timecode, 2))
|
| + return 0;
|
| +
|
| + // For a Block, flags is always 0.
|
| + if (SerializeInt(writer, 0, 1))
|
| + return 0;
|
| +
|
| + if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
|
| + return 0;
|
| +
|
| + if (frame->additional()) {
|
| + if (!WriteEbmlMasterElement(writer, kMkvBlockAdditions,
|
| + block_additions_payload_size)) {
|
| + return 0;
|
| + }
|
| +
|
| + if (!WriteEbmlMasterElement(writer, kMkvBlockMore, block_more_payload_size))
|
| + return 0;
|
| +
|
| + if (!WriteEbmlElement(writer, kMkvBlockAddID, frame->add_id()))
|
| + return 0;
|
| +
|
| + if (!WriteEbmlElement(writer, kMkvBlockAdditional, frame->additional(),
|
| + frame->additional_length())) {
|
| + return 0;
|
| + }
|
| + }
|
| +
|
| + if (frame->discard_padding() != 0 &&
|
| + !WriteEbmlElement(writer, kMkvDiscardPadding, frame->discard_padding())) {
|
| + return false;
|
| + }
|
| +
|
| + if (!frame->is_key() &&
|
| + !WriteEbmlElement(writer, kMkvReferenceBlock,
|
| + reference_block_timestamp)) {
|
| + return false;
|
| + }
|
| +
|
| + if (duration > 0 && !WriteEbmlElement(writer, kMkvBlockDuration, duration)) {
|
| + return false;
|
| + }
|
| + return EbmlMasterElementSize(kMkvBlockGroup, block_group_payload_size) +
|
| + block_group_payload_size;
|
| +}
|
| +
|
| +uint64 WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
|
| + int64 timecode) {
|
| + if (WriteID(writer, kMkvSimpleBlock))
|
| + return 0;
|
| +
|
| + const int32 size = static_cast<int32>(frame->length()) + 4;
|
| + if (WriteUInt(writer, size))
|
| + return 0;
|
| +
|
| + if (WriteUInt(writer, static_cast<uint64>(frame->track_number())))
|
| + return 0;
|
| +
|
| + if (SerializeInt(writer, timecode, 2))
|
| + return 0;
|
| +
|
| + uint64 flags = 0;
|
| + if (frame->is_key())
|
| + flags |= 0x80;
|
| +
|
| + if (SerializeInt(writer, flags, 1))
|
| + return 0;
|
| +
|
| + if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
|
| + return 0;
|
| +
|
| + return GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 +
|
| + frame->length();
|
| +}
|
| +
|
| } // namespace
|
|
|
| int32 GetCodedUIntSize(uint64 value) {
|
| @@ -72,6 +211,13 @@ int32 GetUIntSize(uint64 value) {
|
| return 8;
|
| }
|
|
|
| +int32 GetIntSize(int64 value) {
|
| + // Doubling the requested value ensures positive values with their high bit
|
| + // set are written with 0-padding to avoid flipping the signedness.
|
| + const uint64 v = (value < 0) ? value ^ -1LL : value;
|
| + return GetUIntSize(2 * v);
|
| +}
|
| +
|
| uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
|
| // Size of EBML ID
|
| int32 ebml_size = GetUIntSize(type);
|
| @@ -83,7 +229,16 @@ uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
|
| }
|
|
|
| uint64 EbmlElementSize(uint64 type, int64 value) {
|
| - return EbmlElementSize(type, static_cast<uint64>(value));
|
| + // Size of EBML ID
|
| + int32 ebml_size = GetUIntSize(type);
|
| +
|
| + // Datasize
|
| + ebml_size += GetIntSize(value);
|
| +
|
| + // Size of Datasize
|
| + ebml_size++;
|
| +
|
| + return ebml_size;
|
| }
|
|
|
| uint64 EbmlElementSize(uint64 type, uint64 value) {
|
| @@ -144,7 +299,7 @@ uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) {
|
| return ebml_size;
|
| }
|
|
|
| -uint64 EbmlDateElementSize(uint64 type, int64 value) {
|
| +uint64 EbmlDateElementSize(uint64 type) {
|
| // Size of EBML ID
|
| uint64 ebml_size = GetUIntSize(type);
|
|
|
| @@ -289,6 +444,23 @@ bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
|
| return true;
|
| }
|
|
|
| +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value) {
|
| + if (!writer)
|
| + return false;
|
| +
|
| + if (WriteID(writer, type))
|
| + return 0;
|
| +
|
| + const uint64 size = GetIntSize(value);
|
| + if (WriteUInt(writer, size))
|
| + return false;
|
| +
|
| + if (SerializeInt(writer, value, static_cast<int32>(size)))
|
| + return false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
|
| if (!writer)
|
| return false;
|
| @@ -355,289 +527,25 @@ bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value) {
|
| return true;
|
| }
|
|
|
| -uint64 WriteSimpleBlock(IMkvWriter* writer, const uint8* data, uint64 length,
|
| - uint64 track_number, int64 timecode, uint64 is_key) {
|
| - if (!writer)
|
| - return false;
|
| -
|
| - if (!data || length < 1)
|
| - return false;
|
| -
|
| - // Here we only permit track number values to be no greater than
|
| - // 126, which the largest value we can store having a Matroska
|
| - // integer representation of only 1 byte.
|
| -
|
| - if (track_number < 1 || track_number > 126)
|
| - return false;
|
| -
|
| - // Technically the timestamp for a block can be less than the
|
| - // timestamp for the cluster itself (remember that block timestamp
|
| - // is a signed, 16-bit integer). However, as a simplification we
|
| - // only permit non-negative cluster-relative timestamps for blocks.
|
| -
|
| - if (timecode < 0 || timecode > kMaxBlockTimecode)
|
| - return false;
|
| -
|
| - if (WriteID(writer, kMkvSimpleBlock))
|
| - return 0;
|
| -
|
| - const int32 size = static_cast<int32>(length) + 4;
|
| - if (WriteUInt(writer, size))
|
| - return 0;
|
| -
|
| - if (WriteUInt(writer, static_cast<uint64>(track_number)))
|
| - return 0;
|
| -
|
| - if (SerializeInt(writer, timecode, 2))
|
| - return 0;
|
| -
|
| - uint64 flags = 0;
|
| - if (is_key)
|
| - flags |= 0x80;
|
| -
|
| - if (SerializeInt(writer, flags, 1))
|
| - return 0;
|
| -
|
| - if (writer->Write(data, static_cast<uint32>(length)))
|
| - return 0;
|
| -
|
| - const uint64 element_size =
|
| - GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 + length;
|
| -
|
| - return element_size;
|
| -}
|
| -
|
| -// We must write the metadata (key)frame as a BlockGroup element,
|
| -// because we need to specify a duration for the frame. The
|
| -// BlockGroup element comprises the frame itself and its duration,
|
| -// and is laid out as follows:
|
| -//
|
| -// BlockGroup tag
|
| -// BlockGroup size
|
| -// Block tag
|
| -// Block size
|
| -// (the frame is the block payload)
|
| -// Duration tag
|
| -// Duration size
|
| -// (duration payload)
|
| -//
|
| -uint64 WriteMetadataBlock(IMkvWriter* writer, const uint8* data, uint64 length,
|
| - uint64 track_number, int64 timecode,
|
| - uint64 duration) {
|
| - // We don't backtrack when writing to the stream, so we must
|
| - // pre-compute the BlockGroup size, by summing the sizes of each
|
| - // sub-element (the block and the duration).
|
| -
|
| - // We use a single byte for the track number of the block, which
|
| - // means the block header is exactly 4 bytes.
|
| -
|
| - // TODO(matthewjheaney): use EbmlMasterElementSize and WriteEbmlMasterElement
|
| -
|
| - const uint64 block_payload_size = 4 + length;
|
| - const int32 block_size = GetCodedUIntSize(block_payload_size);
|
| - const uint64 block_elem_size = 1 + block_size + block_payload_size;
|
| -
|
| - const int32 duration_payload_size = GetUIntSize(duration);
|
| - const int32 duration_size = GetCodedUIntSize(duration_payload_size);
|
| - const uint64 duration_elem_size = 1 + duration_size + duration_payload_size;
|
| -
|
| - const uint64 blockg_payload_size = block_elem_size + duration_elem_size;
|
| - const int32 blockg_size = GetCodedUIntSize(blockg_payload_size);
|
| - const uint64 blockg_elem_size = 1 + blockg_size + blockg_payload_size;
|
| -
|
| - if (WriteID(writer, kMkvBlockGroup)) // 1-byte ID size
|
| - return 0;
|
| -
|
| - if (WriteUInt(writer, blockg_payload_size))
|
| - return 0;
|
| -
|
| - // Write Block element
|
| -
|
| - if (WriteID(writer, kMkvBlock)) // 1-byte ID size
|
| - return 0;
|
| -
|
| - if (WriteUInt(writer, block_payload_size))
|
| - return 0;
|
| -
|
| - // Byte 1 of 4
|
| -
|
| - if (WriteUInt(writer, track_number))
|
| - return 0;
|
| -
|
| - // Bytes 2 & 3 of 4
|
| -
|
| - if (SerializeInt(writer, timecode, 2))
|
| - return 0;
|
| -
|
| - // Byte 4 of 4
|
| -
|
| - const uint64 flags = 0;
|
| -
|
| - if (SerializeInt(writer, flags, 1))
|
| - return 0;
|
| -
|
| - // Now write the actual frame (of metadata)
|
| -
|
| - if (writer->Write(data, static_cast<uint32>(length)))
|
| - return 0;
|
| -
|
| - // Write Duration element
|
| -
|
| - if (WriteID(writer, kMkvBlockDuration)) // 1-byte ID size
|
| - return 0;
|
| -
|
| - if (WriteUInt(writer, duration_payload_size))
|
| - return 0;
|
| -
|
| - if (SerializeInt(writer, duration, duration_payload_size))
|
| - return 0;
|
| -
|
| - // Note that we don't write a reference time as part of the block
|
| - // group; no reference time(s) indicates that this block is a
|
| - // keyframe. (Unlike the case for a SimpleBlock element, the header
|
| - // bits of the Block sub-element of a BlockGroup element do not
|
| - // indicate keyframe status. The keyframe status is inferred from
|
| - // the absence of reference time sub-elements.)
|
| -
|
| - return blockg_elem_size;
|
| -}
|
| -
|
| -// Writes a WebM BlockGroup with BlockAdditional data. The structure is as
|
| -// follows:
|
| -// Indentation shows sub-levels
|
| -// BlockGroup
|
| -// Block
|
| -// Data
|
| -// BlockAdditions
|
| -// BlockMore
|
| -// BlockAddID
|
| -// 1 (Denotes Alpha)
|
| -// BlockAdditional
|
| -// Data
|
| -uint64 WriteBlockWithAdditional(IMkvWriter* writer, const uint8* data,
|
| - uint64 length, const uint8* additional,
|
| - uint64 additional_length, uint64 add_id,
|
| - uint64 track_number, int64 timecode,
|
| - uint64 is_key) {
|
| - if (!data || !additional || length < 1 || additional_length < 1)
|
| +uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
|
| + Cluster* cluster) {
|
| + if (!writer || !frame || !frame->IsValid() || !cluster ||
|
| + !cluster->timecode_scale())
|
| return 0;
|
|
|
| - const uint64 block_payload_size = 4 + length;
|
| - const uint64 block_elem_size =
|
| - EbmlMasterElementSize(kMkvBlock, block_payload_size) + block_payload_size;
|
| - const uint64 block_additional_elem_size =
|
| - EbmlElementSize(kMkvBlockAdditional, additional, additional_length);
|
| - const uint64 block_addid_elem_size = EbmlElementSize(kMkvBlockAddID, add_id);
|
| -
|
| - const uint64 block_more_payload_size =
|
| - block_addid_elem_size + block_additional_elem_size;
|
| - const uint64 block_more_elem_size =
|
| - EbmlMasterElementSize(kMkvBlockMore, block_more_payload_size) +
|
| - block_more_payload_size;
|
| - const uint64 block_additions_payload_size = block_more_elem_size;
|
| - const uint64 block_additions_elem_size =
|
| - EbmlMasterElementSize(kMkvBlockAdditions, block_additions_payload_size) +
|
| - block_additions_payload_size;
|
| - const uint64 block_group_payload_size =
|
| - block_elem_size + block_additions_elem_size;
|
| - const uint64 block_group_elem_size =
|
| - EbmlMasterElementSize(kMkvBlockGroup, block_group_payload_size) +
|
| - block_group_payload_size;
|
| -
|
| - if (!WriteEbmlMasterElement(writer, kMkvBlockGroup, block_group_payload_size))
|
| - return 0;
|
| -
|
| - if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
|
| - return 0;
|
| -
|
| - if (WriteUInt(writer, track_number))
|
| - return 0;
|
| -
|
| - if (SerializeInt(writer, timecode, 2))
|
| - return 0;
|
| -
|
| - uint64 flags = 0;
|
| - if (is_key)
|
| - flags |= 0x80;
|
| - if (SerializeInt(writer, flags, 1))
|
| - return 0;
|
| -
|
| - if (writer->Write(data, static_cast<uint32>(length)))
|
| - return 0;
|
| -
|
| - if (!WriteEbmlMasterElement(writer, kMkvBlockAdditions,
|
| - block_additions_payload_size))
|
| - return 0;
|
| -
|
| - if (!WriteEbmlMasterElement(writer, kMkvBlockMore, block_more_payload_size))
|
| - return 0;
|
| -
|
| - if (!WriteEbmlElement(writer, kMkvBlockAddID, add_id))
|
| - return 0;
|
| -
|
| - if (!WriteEbmlElement(writer, kMkvBlockAdditional, additional,
|
| - additional_length))
|
| - return 0;
|
| -
|
| - return block_group_elem_size;
|
| -}
|
| -
|
| -// Writes a WebM BlockGroup with DiscardPadding. The structure is as follows:
|
| -// Indentation shows sub-levels
|
| -// BlockGroup
|
| -// Block
|
| -// Data
|
| -// DiscardPadding
|
| -uint64 WriteBlockWithDiscardPadding(IMkvWriter* writer, const uint8* data,
|
| - uint64 length, int64 discard_padding,
|
| - uint64 track_number, int64 timecode,
|
| - uint64 is_key) {
|
| - if (!data || length < 1 || discard_padding <= 0)
|
| - return 0;
|
| -
|
| - const uint64 block_payload_size = 4 + length;
|
| - const uint64 block_elem_size =
|
| - EbmlMasterElementSize(kMkvBlock, block_payload_size) + block_payload_size;
|
| - const uint64 discard_padding_elem_size =
|
| - EbmlElementSize(kMkvDiscardPadding, discard_padding);
|
| - const uint64 block_group_payload_size =
|
| - block_elem_size + discard_padding_elem_size;
|
| - const uint64 block_group_elem_size =
|
| - EbmlMasterElementSize(kMkvBlockGroup, block_group_payload_size) +
|
| - block_group_payload_size;
|
| -
|
| - if (!WriteEbmlMasterElement(writer, kMkvBlockGroup, block_group_payload_size))
|
| - return 0;
|
| -
|
| - if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
|
| - return 0;
|
| -
|
| - if (WriteUInt(writer, track_number))
|
| - return 0;
|
| -
|
| - if (SerializeInt(writer, timecode, 2))
|
| - return 0;
|
| -
|
| - uint64 flags = 0;
|
| - if (is_key)
|
| - flags |= 0x80;
|
| - if (SerializeInt(writer, flags, 1))
|
| - return 0;
|
| -
|
| - if (writer->Write(data, static_cast<uint32>(length)))
|
| - return 0;
|
| -
|
| - if (WriteID(writer, kMkvDiscardPadding))
|
| + // Technically the timecode for a block can be less than the
|
| + // timecode for the cluster itself (remember that block timecode
|
| + // is a signed, 16-bit integer). However, as a simplification we
|
| + // only permit non-negative cluster-relative timecodes for blocks.
|
| + const int64 relative_timecode = cluster->GetRelativeTimecode(
|
| + frame->timestamp() / cluster->timecode_scale());
|
| + if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
|
| return 0;
|
|
|
| - const uint64 size = GetUIntSize(discard_padding);
|
| - if (WriteUInt(writer, size))
|
| - return false;
|
| -
|
| - if (SerializeInt(writer, discard_padding, static_cast<int32>(size)))
|
| - return false;
|
| -
|
| - return block_group_elem_size;
|
| + return frame->CanBeSimpleBlock() ?
|
| + WriteSimpleBlock(writer, frame, relative_timecode) :
|
| + WriteBlock(writer, frame, relative_timecode,
|
| + cluster->timecode_scale());
|
| }
|
|
|
| uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
|
| @@ -698,10 +606,7 @@ mkvmuxer::uint64 mkvmuxer::MakeUID(unsigned int* seed) {
|
| // TODO(fgalligan): Move random number generation to platform specific code.
|
| #ifdef _MSC_VER
|
| (void)seed;
|
| - unsigned int random_value;
|
| - const errno_t e = rand_s(&random_value);
|
| - (void)e;
|
| - const int32 nn = random_value;
|
| + const int32 nn = rand();
|
| #elif __ANDROID__
|
| int32 temp_num = 1;
|
| int fd = open("/dev/urandom", O_RDONLY);
|
|
|