1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved.
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
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
9 #include "mkvmuxer/mkvmuxerutil.h"
23 #include "common/webmids.h"
24 #include "mkvmuxer/mkvmuxer.h"
25 #include "mkvmuxer/mkvwriter.h"
31 // Date elements are always 8 octets in size.
32 const int kDateElementSize = 8;
34 uint64_t WriteBlock(IMkvWriter* writer, const Frame* const frame,
35 int64_t timecode, uint64_t timecode_scale) {
36 uint64_t block_additional_elem_size = 0;
37 uint64_t block_addid_elem_size = 0;
38 uint64_t block_more_payload_size = 0;
39 uint64_t block_more_elem_size = 0;
40 uint64_t block_additions_payload_size = 0;
41 uint64_t block_additions_elem_size = 0;
42 if (frame->additional()) {
43 block_additional_elem_size =
44 EbmlElementSize(libwebm::kMkvBlockAdditional, frame->additional(),
45 frame->additional_length());
46 block_addid_elem_size =
47 EbmlElementSize(libwebm::kMkvBlockAddID, frame->add_id());
49 block_more_payload_size =
50 block_addid_elem_size + block_additional_elem_size;
51 block_more_elem_size =
52 EbmlMasterElementSize(libwebm::kMkvBlockMore, block_more_payload_size) +
53 block_more_payload_size;
54 block_additions_payload_size = block_more_elem_size;
55 block_additions_elem_size =
56 EbmlMasterElementSize(libwebm::kMkvBlockAdditions,
57 block_additions_payload_size) +
58 block_additions_payload_size;
61 uint64_t discard_padding_elem_size = 0;
62 if (frame->discard_padding() != 0) {
63 discard_padding_elem_size =
64 EbmlElementSize(libwebm::kMkvDiscardPadding, frame->discard_padding());
67 const uint64_t reference_block_timestamp =
68 frame->reference_block_timestamp() / timecode_scale;
69 uint64_t reference_block_elem_size = 0;
70 if (!frame->is_key()) {
71 reference_block_elem_size =
72 EbmlElementSize(libwebm::kMkvReferenceBlock, reference_block_timestamp);
75 const uint64_t duration = frame->duration() / timecode_scale;
76 uint64_t block_duration_elem_size = 0;
78 block_duration_elem_size =
79 EbmlElementSize(libwebm::kMkvBlockDuration, duration);
81 const uint64_t block_payload_size = 4 + frame->length();
82 const uint64_t block_elem_size =
83 EbmlMasterElementSize(libwebm::kMkvBlock, block_payload_size) +
86 const uint64_t block_group_payload_size =
87 block_elem_size + block_additions_elem_size + block_duration_elem_size +
88 discard_padding_elem_size + reference_block_elem_size;
90 if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockGroup,
91 block_group_payload_size)) {
95 if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlock, block_payload_size))
98 if (WriteUInt(writer, frame->track_number()))
101 if (SerializeInt(writer, timecode, 2))
104 // For a Block, flags is always 0.
105 if (SerializeInt(writer, 0, 1))
108 if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length())))
111 if (frame->additional()) {
112 if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockAdditions,
113 block_additions_payload_size)) {
117 if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockMore,
118 block_more_payload_size))
121 if (!WriteEbmlElement(writer, libwebm::kMkvBlockAddID, frame->add_id()))
124 if (!WriteEbmlElement(writer, libwebm::kMkvBlockAdditional,
125 frame->additional(), frame->additional_length())) {
130 if (frame->discard_padding() != 0 &&
131 !WriteEbmlElement(writer, libwebm::kMkvDiscardPadding,
132 frame->discard_padding())) {
136 if (!frame->is_key() &&
137 !WriteEbmlElement(writer, libwebm::kMkvReferenceBlock,
138 reference_block_timestamp)) {
143 !WriteEbmlElement(writer, libwebm::kMkvBlockDuration, duration)) {
146 return EbmlMasterElementSize(libwebm::kMkvBlockGroup,
147 block_group_payload_size) +
148 block_group_payload_size;
151 uint64_t WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
153 if (WriteID(writer, libwebm::kMkvSimpleBlock))
156 const int32_t size = static_cast<int32_t>(frame->length()) + 4;
157 if (WriteUInt(writer, size))
160 if (WriteUInt(writer, static_cast<uint64_t>(frame->track_number())))
163 if (SerializeInt(writer, timecode, 2))
170 if (SerializeInt(writer, flags, 1))
173 if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length())))
176 return GetUIntSize(libwebm::kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 +
182 int32_t GetCodedUIntSize(uint64_t value) {
183 if (value < 0x000000000000007FULL)
185 else if (value < 0x0000000000003FFFULL)
187 else if (value < 0x00000000001FFFFFULL)
189 else if (value < 0x000000000FFFFFFFULL)
191 else if (value < 0x00000007FFFFFFFFULL)
193 else if (value < 0x000003FFFFFFFFFFULL)
195 else if (value < 0x0001FFFFFFFFFFFFULL)
200 int32_t GetUIntSize(uint64_t value) {
201 if (value < 0x0000000000000100ULL)
203 else if (value < 0x0000000000010000ULL)
205 else if (value < 0x0000000001000000ULL)
207 else if (value < 0x0000000100000000ULL)
209 else if (value < 0x0000010000000000ULL)
211 else if (value < 0x0001000000000000ULL)
213 else if (value < 0x0100000000000000ULL)
218 int32_t GetIntSize(int64_t value) {
219 // Doubling the requested value ensures positive values with their high bit
220 // set are written with 0-padding to avoid flipping the signedness.
221 const uint64_t v = (value < 0) ? value ^ -1LL : value;
222 return GetUIntSize(2 * v);
225 uint64_t EbmlMasterElementSize(uint64_t type, uint64_t value) {
227 int32_t ebml_size = GetUIntSize(type);
230 ebml_size += GetCodedUIntSize(value);
235 uint64_t EbmlElementSize(uint64_t type, int64_t value) {
237 int32_t ebml_size = GetUIntSize(type);
240 ebml_size += GetIntSize(value);
248 uint64_t EbmlElementSize(uint64_t type, uint64_t value) {
250 int32_t ebml_size = GetUIntSize(type);
253 ebml_size += GetUIntSize(value);
261 uint64_t EbmlElementSize(uint64_t type, float /* value */) {
263 uint64_t ebml_size = GetUIntSize(type);
266 ebml_size += sizeof(float);
274 uint64_t EbmlElementSize(uint64_t type, const char* value) {
279 uint64_t ebml_size = GetUIntSize(type);
282 ebml_size += strlen(value);
290 uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size) {
295 uint64_t ebml_size = GetUIntSize(type);
301 ebml_size += GetCodedUIntSize(size);
306 uint64_t EbmlDateElementSize(uint64_t type) {
308 uint64_t ebml_size = GetUIntSize(type);
311 ebml_size += kDateElementSize;
319 int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size) {
320 if (!writer || size < 1 || size > 8)
323 for (int32_t i = 1; i <= size; ++i) {
324 const int32_t byte_count = size - i;
325 const int32_t bit_count = byte_count * 8;
327 const int64_t bb = value >> bit_count;
328 const uint8_t b = static_cast<uint8_t>(bb);
330 const int32_t status = writer->Write(&b, 1);
339 int32_t SerializeFloat(IMkvWriter* writer, float f) {
343 assert(sizeof(uint32_t) == sizeof(float));
344 // This union is merely used to avoid a reinterpret_cast from float& to
345 // uint32& which will result in violation of strict aliasing.
352 for (int32_t i = 1; i <= 4; ++i) {
353 const int32_t byte_count = 4 - i;
354 const int32_t bit_count = byte_count * 8;
356 const uint8_t byte = static_cast<uint8_t>(value.u32 >> bit_count);
358 const int32_t status = writer->Write(&byte, 1);
367 int32_t WriteUInt(IMkvWriter* writer, uint64_t value) {
371 int32_t size = GetCodedUIntSize(value);
373 return WriteUIntSize(writer, value, size);
376 int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size) {
377 if (!writer || size < 0 || size > 8)
381 const uint64_t bit = 1LL << (size * 7);
383 if (value > (bit - 2))
392 bit = 1LL << (size * 7);
393 const uint64_t max = bit - 2;
407 return SerializeInt(writer, value, size);
410 int32_t WriteID(IMkvWriter* writer, uint64_t type) {
414 writer->ElementStartNotify(type, writer->Position());
416 const int32_t size = GetUIntSize(type);
418 return SerializeInt(writer, type, size);
421 bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t type, uint64_t size) {
425 if (WriteID(writer, type))
428 if (WriteUInt(writer, size))
434 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value) {
438 if (WriteID(writer, type))
441 const uint64_t size = GetUIntSize(value);
442 if (WriteUInt(writer, size))
445 if (SerializeInt(writer, value, static_cast<int32_t>(size)))
451 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, int64_t value) {
455 if (WriteID(writer, type))
458 const uint64_t size = GetIntSize(value);
459 if (WriteUInt(writer, size))
462 if (SerializeInt(writer, value, static_cast<int32_t>(size)))
468 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value) {
472 if (WriteID(writer, type))
475 if (WriteUInt(writer, 4))
478 if (SerializeFloat(writer, value))
484 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const char* value) {
485 if (!writer || !value)
488 if (WriteID(writer, type))
491 const uint64_t length = strlen(value);
492 if (WriteUInt(writer, length))
495 if (writer->Write(value, static_cast<const uint32_t>(length)))
501 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value,
503 if (!writer || !value || size < 1)
506 if (WriteID(writer, type))
509 if (WriteUInt(writer, size))
512 if (writer->Write(value, static_cast<uint32_t>(size)))
518 bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value) {
522 if (WriteID(writer, type))
525 if (WriteUInt(writer, kDateElementSize))
528 if (SerializeInt(writer, value, kDateElementSize))
534 uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame,
536 if (!writer || !frame || !frame->IsValid() || !cluster ||
537 !cluster->timecode_scale())
540 // Technically the timecode for a block can be less than the
541 // timecode for the cluster itself (remember that block timecode
542 // is a signed, 16-bit integer). However, as a simplification we
543 // only permit non-negative cluster-relative timecodes for blocks.
544 const int64_t relative_timecode = cluster->GetRelativeTimecode(
545 frame->timestamp() / cluster->timecode_scale());
546 if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
549 return frame->CanBeSimpleBlock() ?
550 WriteSimpleBlock(writer, frame, relative_timecode) :
551 WriteBlock(writer, frame, relative_timecode,
552 cluster->timecode_scale());
555 uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size) {
559 // Subtract one for the void ID and the coded size.
560 uint64_t void_entry_size = size - 1 - GetCodedUIntSize(size - 1);
562 EbmlMasterElementSize(libwebm::kMkvVoid, void_entry_size) +
565 if (void_size != size)
568 const int64_t payload_position = writer->Position();
569 if (payload_position < 0)
572 if (WriteID(writer, libwebm::kMkvVoid))
575 if (WriteUInt(writer, void_entry_size))
578 const uint8_t value = 0;
579 for (int32_t i = 0; i < static_cast<int32_t>(void_entry_size); ++i) {
580 if (writer->Write(&value, 1))
584 const int64_t stop_position = writer->Position();
585 if (stop_position < 0 ||
586 stop_position - payload_position != static_cast<int64_t>(void_size))
592 void GetVersion(int32_t* major, int32_t* minor, int32_t* build,
600 uint64_t MakeUID(unsigned int* seed) {
607 for (int i = 0; i < 7; ++i) { // avoid problems with 8-byte values
610 // TODO(fgalligan): Move random number generation to platform specific code.
613 const int32_t nn = rand();
615 int32_t temp_num = 1;
616 int fd = open("/dev/urandom", O_RDONLY);
618 read(fd, &temp_num, sizeof(temp_num));
621 const int32_t nn = temp_num;
622 #elif defined __MINGW32__
623 const int32_t nn = rand();
625 const int32_t nn = rand_r(seed);
627 const int32_t n = 0xFF & (nn >> 4); // throw away low-order bits
635 } // namespace mkvmuxer