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 static_cast<uint64_t>(GetUIntSize(libwebm::kMkvSimpleBlock) +
177 GetCodedUIntSize(size) + 4 + frame->length());
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);
232 return static_cast<uint64_t>(ebml_size);
235 uint64_t EbmlElementSize(uint64_t type, int64_t value) {
237 int32_t ebml_size = GetUIntSize(type);
240 ebml_size += GetIntSize(value);
245 return static_cast<uint64_t>(ebml_size);
248 uint64_t EbmlElementSize(uint64_t type, uint64_t value) {
249 return EbmlElementSize(type, value, 0);
252 uint64_t EbmlElementSize(uint64_t type, uint64_t value, uint64_t fixed_size) {
254 uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
258 (fixed_size > 0) ? fixed_size : static_cast<uint64_t>(GetUIntSize(value));
266 uint64_t EbmlElementSize(uint64_t type, float /* value */) {
268 uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
271 ebml_size += sizeof(float);
279 uint64_t EbmlElementSize(uint64_t type, const char* value) {
284 uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
287 ebml_size += strlen(value);
295 uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size) {
300 uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
306 ebml_size += GetCodedUIntSize(size);
311 uint64_t EbmlDateElementSize(uint64_t type) {
313 uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
316 ebml_size += kDateElementSize;
324 int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size) {
325 if (!writer || size < 1 || size > 8)
328 for (int32_t i = 1; i <= size; ++i) {
329 const int32_t byte_count = size - i;
330 const int32_t bit_count = byte_count * 8;
332 const int64_t bb = value >> bit_count;
333 const uint8_t b = static_cast<uint8_t>(bb);
335 const int32_t status = writer->Write(&b, 1);
344 int32_t SerializeFloat(IMkvWriter* writer, float f) {
348 assert(sizeof(uint32_t) == sizeof(float));
349 // This union is merely used to avoid a reinterpret_cast from float& to
350 // uint32& which will result in violation of strict aliasing.
357 for (int32_t i = 1; i <= 4; ++i) {
358 const int32_t byte_count = 4 - i;
359 const int32_t bit_count = byte_count * 8;
361 const uint8_t byte = static_cast<uint8_t>(value.u32 >> bit_count);
363 const int32_t status = writer->Write(&byte, 1);
372 int32_t WriteUInt(IMkvWriter* writer, uint64_t value) {
376 int32_t size = GetCodedUIntSize(value);
378 return WriteUIntSize(writer, value, size);
381 int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size) {
382 if (!writer || size < 0 || size > 8)
386 const uint64_t bit = 1LL << (size * 7);
388 if (value > (bit - 2))
397 bit = 1LL << (size * 7);
398 const uint64_t max = bit - 2;
412 return SerializeInt(writer, value, size);
415 int32_t WriteID(IMkvWriter* writer, uint64_t type) {
419 writer->ElementStartNotify(type, writer->Position());
421 const int32_t size = GetUIntSize(type);
423 return SerializeInt(writer, type, size);
426 bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t type, uint64_t size) {
430 if (WriteID(writer, type))
433 if (WriteUInt(writer, size))
439 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value) {
440 return WriteEbmlElement(writer, type, value, 0);
443 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value,
444 uint64_t fixed_size) {
448 if (WriteID(writer, type))
451 uint64_t size = static_cast<uint64_t>(GetUIntSize(value));
452 if (fixed_size > 0) {
453 if (size > fixed_size)
457 if (WriteUInt(writer, size))
460 if (SerializeInt(writer, value, static_cast<int32_t>(size)))
466 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, int64_t value) {
470 if (WriteID(writer, type))
473 const uint64_t size = GetIntSize(value);
474 if (WriteUInt(writer, size))
477 if (SerializeInt(writer, value, static_cast<int32_t>(size)))
483 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value) {
487 if (WriteID(writer, type))
490 if (WriteUInt(writer, 4))
493 if (SerializeFloat(writer, value))
499 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const char* value) {
500 if (!writer || !value)
503 if (WriteID(writer, type))
506 const uint64_t length = strlen(value);
507 if (WriteUInt(writer, length))
510 if (writer->Write(value, static_cast<const uint32_t>(length)))
516 bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value,
518 if (!writer || !value || size < 1)
521 if (WriteID(writer, type))
524 if (WriteUInt(writer, size))
527 if (writer->Write(value, static_cast<uint32_t>(size)))
533 bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value) {
537 if (WriteID(writer, type))
540 if (WriteUInt(writer, kDateElementSize))
543 if (SerializeInt(writer, value, kDateElementSize))
549 uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame,
551 if (!writer || !frame || !frame->IsValid() || !cluster ||
552 !cluster->timecode_scale())
555 // Technically the timecode for a block can be less than the
556 // timecode for the cluster itself (remember that block timecode
557 // is a signed, 16-bit integer). However, as a simplification we
558 // only permit non-negative cluster-relative timecodes for blocks.
559 const int64_t relative_timecode = cluster->GetRelativeTimecode(
560 frame->timestamp() / cluster->timecode_scale());
561 if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
564 return frame->CanBeSimpleBlock() ?
565 WriteSimpleBlock(writer, frame, relative_timecode) :
566 WriteBlock(writer, frame, relative_timecode,
567 cluster->timecode_scale());
570 uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size) {
574 // Subtract one for the void ID and the coded size.
575 uint64_t void_entry_size = size - 1 - GetCodedUIntSize(size - 1);
577 EbmlMasterElementSize(libwebm::kMkvVoid, void_entry_size) +
580 if (void_size != size)
583 const int64_t payload_position = writer->Position();
584 if (payload_position < 0)
587 if (WriteID(writer, libwebm::kMkvVoid))
590 if (WriteUInt(writer, void_entry_size))
593 const uint8_t value = 0;
594 for (int32_t i = 0; i < static_cast<int32_t>(void_entry_size); ++i) {
595 if (writer->Write(&value, 1))
599 const int64_t stop_position = writer->Position();
600 if (stop_position < 0 ||
601 stop_position - payload_position != static_cast<int64_t>(void_size))
607 void GetVersion(int32_t* major, int32_t* minor, int32_t* build,
615 uint64_t MakeUID(unsigned int* seed) {
622 for (int i = 0; i < 7; ++i) { // avoid problems with 8-byte values
625 // TODO(fgalligan): Move random number generation to platform specific code.
628 const int32_t nn = rand();
630 int32_t temp_num = 1;
631 int fd = open("/dev/urandom", O_RDONLY);
633 read(fd, &temp_num, sizeof(temp_num));
636 const int32_t nn = temp_num;
637 #elif defined __MINGW32__
638 const int32_t nn = rand();
640 const int32_t nn = rand_r(seed);
642 const int32_t n = 0xFF & (nn >> 4); // throw away low-order bits
650 } // namespace mkvmuxer