1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved.
2 //
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.
8
9 #include "mkvmuxerutil.hpp"
10
11 #ifdef __ANDROID__
12 #include <fcntl.h>
13 #endif
14
15 #include <cassert>
16 #include <cmath>
17 #include <cstdio>
18 #ifdef _MSC_VER
19 #define _CRT_RAND_S
20 #endif
21 #include <cstdlib>
22 #include <cstring>
23 #include <ctime>
24
25 #include <new>
26
27 #include "mkvwriter.hpp"
28 #include "webmids.hpp"
29
30 namespace mkvmuxer {
31
GetCodedUIntSize(uint64 value)32 int32 GetCodedUIntSize(uint64 value) {
33 if (value < 0x000000000000007FULL)
34 return 1;
35 else if (value < 0x0000000000003FFFULL)
36 return 2;
37 else if (value < 0x00000000001FFFFFULL)
38 return 3;
39 else if (value < 0x000000000FFFFFFFULL)
40 return 4;
41 else if (value < 0x00000007FFFFFFFFULL)
42 return 5;
43 else if (value < 0x000003FFFFFFFFFFULL)
44 return 6;
45 else if (value < 0x0001FFFFFFFFFFFFULL)
46 return 7;
47 return 8;
48 }
49
GetUIntSize(uint64 value)50 int32 GetUIntSize(uint64 value) {
51 if (value < 0x0000000000000100ULL)
52 return 1;
53 else if (value < 0x0000000000010000ULL)
54 return 2;
55 else if (value < 0x0000000001000000ULL)
56 return 3;
57 else if (value < 0x0000000100000000ULL)
58 return 4;
59 else if (value < 0x0000010000000000ULL)
60 return 5;
61 else if (value < 0x0001000000000000ULL)
62 return 6;
63 else if (value < 0x0100000000000000ULL)
64 return 7;
65 return 8;
66 }
67
EbmlMasterElementSize(uint64 type,uint64 value)68 uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
69 // Size of EBML ID
70 int32 ebml_size = GetUIntSize(type);
71
72 // Datasize
73 ebml_size += GetCodedUIntSize(value);
74
75 return ebml_size;
76 }
77
EbmlElementSize(uint64 type,int64 value)78 uint64 EbmlElementSize(uint64 type, int64 value) {
79 return EbmlElementSize(type, static_cast<uint64>(value));
80 }
81
EbmlElementSize(uint64 type,uint64 value)82 uint64 EbmlElementSize(uint64 type, uint64 value) {
83 // Size of EBML ID
84 int32 ebml_size = GetUIntSize(type);
85
86 // Datasize
87 ebml_size += GetUIntSize(value);
88
89 // Size of Datasize
90 ebml_size++;
91
92 return ebml_size;
93 }
94
EbmlElementSize(uint64 type,float)95 uint64 EbmlElementSize(uint64 type, float /* value */ ) {
96 // Size of EBML ID
97 uint64 ebml_size = GetUIntSize(type);
98
99 // Datasize
100 ebml_size += sizeof(float);
101
102 // Size of Datasize
103 ebml_size++;
104
105 return ebml_size;
106 }
107
EbmlElementSize(uint64 type,const char * value)108 uint64 EbmlElementSize(uint64 type, const char* value) {
109 if (!value)
110 return 0;
111
112 // Size of EBML ID
113 uint64 ebml_size = GetUIntSize(type);
114
115 // Datasize
116 ebml_size += strlen(value);
117
118 // Size of Datasize
119 ebml_size++;
120
121 return ebml_size;
122 }
123
EbmlElementSize(uint64 type,const uint8 * value,uint64 size)124 uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) {
125 if (!value)
126 return 0;
127
128 // Size of EBML ID
129 uint64 ebml_size = GetUIntSize(type);
130
131 // Datasize
132 ebml_size += size;
133
134 // Size of Datasize
135 ebml_size += GetCodedUIntSize(size);
136
137 return ebml_size;
138 }
139
SerializeInt(IMkvWriter * writer,int64 value,int32 size)140 int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size) {
141 if (!writer || size < 1 || size > 8)
142 return -1;
143
144 for (int32 i = 1; i <= size; ++i) {
145 const int32 byte_count = size - i;
146 const int32 bit_count = byte_count * 8;
147
148 const int64 bb = value >> bit_count;
149 const uint8 b = static_cast<uint8>(bb);
150
151 const int32 status = writer->Write(&b, 1);
152
153 if (status < 0)
154 return status;
155 }
156
157 return 0;
158 }
159
SerializeFloat(IMkvWriter * writer,float f)160 int32 SerializeFloat(IMkvWriter* writer, float f) {
161 if (!writer)
162 return -1;
163
164 assert(sizeof(uint32) == sizeof(float));
165 // This union is merely used to avoid a reinterpret_cast from float& to
166 // uint32& which will result in violation of strict aliasing.
167 union U32 {
168 uint32 u32;
169 float f;
170 } value;
171 value.f = f;
172
173 for (int32 i = 1; i <= 4; ++i) {
174 const int32 byte_count = 4 - i;
175 const int32 bit_count = byte_count * 8;
176
177 const uint8 byte = static_cast<uint8>(value.u32 >> bit_count);
178
179 const int32 status = writer->Write(&byte, 1);
180
181 if (status < 0)
182 return status;
183 }
184
185 return 0;
186 }
187
WriteUInt(IMkvWriter * writer,uint64 value)188 int32 WriteUInt(IMkvWriter* writer, uint64 value) {
189 if (!writer)
190 return -1;
191
192 int32 size = GetCodedUIntSize(value);
193
194 return WriteUIntSize(writer, value, size);
195 }
196
WriteUIntSize(IMkvWriter * writer,uint64 value,int32 size)197 int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) {
198 if (!writer || size < 0 || size > 8)
199 return -1;
200
201 if (size > 0) {
202 const uint64 bit = 1LL << (size * 7);
203
204 if (value > (bit - 2))
205 return -1;
206
207 value |= bit;
208 } else {
209 size = 1;
210 int64 bit;
211
212 for (;;) {
213 bit = 1LL << (size * 7);
214 const uint64 max = bit - 2;
215
216 if (value <= max)
217 break;
218
219 ++size;
220 }
221
222 if (size > 8)
223 return false;
224
225 value |= bit;
226 }
227
228 return SerializeInt(writer, value, size);
229 }
230
WriteID(IMkvWriter * writer,uint64 type)231 int32 WriteID(IMkvWriter* writer, uint64 type) {
232 if (!writer)
233 return -1;
234
235 writer->ElementStartNotify(type, writer->Position());
236
237 const int32 size = GetUIntSize(type);
238
239 return SerializeInt(writer, type, size);
240 }
241
WriteEbmlMasterElement(IMkvWriter * writer,uint64 type,uint64 size)242 bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 type, uint64 size) {
243 if (!writer)
244 return false;
245
246 if (WriteID(writer, type))
247 return false;
248
249 if (WriteUInt(writer, size))
250 return false;
251
252 return true;
253 }
254
WriteEbmlElement(IMkvWriter * writer,uint64 type,uint64 value)255 bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
256 if (!writer)
257 return false;
258
259 if (WriteID(writer, type))
260 return false;
261
262 const uint64 size = GetUIntSize(value);
263 if (WriteUInt(writer, size))
264 return false;
265
266 if (SerializeInt(writer, value, static_cast<int32>(size)))
267 return false;
268
269 return true;
270 }
271
WriteEbmlElement(IMkvWriter * writer,uint64 type,float value)272 bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
273 if (!writer)
274 return false;
275
276 if (WriteID(writer, type))
277 return false;
278
279 if (WriteUInt(writer, 4))
280 return false;
281
282 if (SerializeFloat(writer, value))
283 return false;
284
285 return true;
286 }
287
WriteEbmlElement(IMkvWriter * writer,uint64 type,const char * value)288 bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value) {
289 if (!writer || !value)
290 return false;
291
292 if (WriteID(writer, type))
293 return false;
294
295 const int32 length = strlen(value);
296 if (WriteUInt(writer, length))
297 return false;
298
299 if (writer->Write(value, length))
300 return false;
301
302 return true;
303 }
304
WriteEbmlElement(IMkvWriter * writer,uint64 type,const uint8 * value,uint64 size)305 bool WriteEbmlElement(IMkvWriter* writer,
306 uint64 type,
307 const uint8* value,
308 uint64 size) {
309 if (!writer || !value || size < 1)
310 return false;
311
312 if (WriteID(writer, type))
313 return false;
314
315 if (WriteUInt(writer, size))
316 return false;
317
318 if (writer->Write(value, static_cast<uint32>(size)))
319 return false;
320
321 return true;
322 }
323
WriteSimpleBlock(IMkvWriter * writer,const uint8 * data,uint64 length,uint64 track_number,int64 timecode,uint64 is_key)324 uint64 WriteSimpleBlock(IMkvWriter* writer,
325 const uint8* data,
326 uint64 length,
327 uint64 track_number,
328 int64 timecode,
329 uint64 is_key) {
330 if (!writer)
331 return false;
332
333 if (!data || length < 1)
334 return false;
335
336 // Here we only permit track number values to be no greater than
337 // 126, which the largest value we can store having a Matroska
338 // integer representation of only 1 byte.
339
340 if (track_number < 1 || track_number > 126)
341 return false;
342
343 // Technically the timestamp for a block can be less than the
344 // timestamp for the cluster itself (remember that block timestamp
345 // is a signed, 16-bit integer). However, as a simplification we
346 // only permit non-negative cluster-relative timestamps for blocks.
347
348 if (timecode < 0 || timecode > kMaxBlockTimecode)
349 return false;
350
351 if (WriteID(writer, kMkvSimpleBlock))
352 return 0;
353
354 const int32 size = static_cast<int32>(length) + 4;
355 if (WriteUInt(writer, size))
356 return 0;
357
358 if (WriteUInt(writer, static_cast<uint64>(track_number)))
359 return 0;
360
361 if (SerializeInt(writer, timecode, 2))
362 return 0;
363
364 uint64 flags = 0;
365 if (is_key)
366 flags |= 0x80;
367
368 if (SerializeInt(writer, flags, 1))
369 return 0;
370
371 if (writer->Write(data, static_cast<uint32>(length)))
372 return 0;
373
374 const uint64 element_size =
375 GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 + length;
376
377 return element_size;
378 }
379
380 // We must write the metadata (key)frame as a BlockGroup element,
381 // because we need to specify a duration for the frame. The
382 // BlockGroup element comprises the frame itself and its duration,
383 // and is laid out as follows:
384 //
385 // BlockGroup tag
386 // BlockGroup size
387 // Block tag
388 // Block size
389 // (the frame is the block payload)
390 // Duration tag
391 // Duration size
392 // (duration payload)
393 //
WriteMetadataBlock(IMkvWriter * writer,const uint8 * data,uint64 length,uint64 track_number,int64 timecode,uint64 duration)394 uint64 WriteMetadataBlock(IMkvWriter* writer,
395 const uint8* data,
396 uint64 length,
397 uint64 track_number,
398 int64 timecode,
399 uint64 duration) {
400 // We don't backtrack when writing to the stream, so we must
401 // pre-compute the BlockGroup size, by summing the sizes of each
402 // sub-element (the block and the duration).
403
404 // We use a single byte for the track number of the block, which
405 // means the block header is exactly 4 bytes.
406
407 // TODO(matthewjheaney): use EbmlMasterElementSize and WriteEbmlMasterElement
408
409 const uint64 block_payload_size = 4 + length;
410 const int32 block_size = GetCodedUIntSize(block_payload_size);
411 const uint64 block_elem_size = 1 + block_size + block_payload_size;
412
413 const int32 duration_payload_size = GetUIntSize(duration);
414 const int32 duration_size = GetCodedUIntSize(duration_payload_size);
415 const uint64 duration_elem_size = 1 + duration_size + duration_payload_size;
416
417 const uint64 blockg_payload_size = block_elem_size + duration_elem_size;
418 const int32 blockg_size = GetCodedUIntSize(blockg_payload_size);
419 const uint64 blockg_elem_size = 1 + blockg_size + blockg_payload_size;
420
421 if (WriteID(writer, kMkvBlockGroup)) // 1-byte ID size
422 return 0;
423
424 if (WriteUInt(writer, blockg_payload_size))
425 return 0;
426
427 // Write Block element
428
429 if (WriteID(writer, kMkvBlock)) // 1-byte ID size
430 return 0;
431
432 if (WriteUInt(writer, block_payload_size))
433 return 0;
434
435 // Byte 1 of 4
436
437 if (WriteUInt(writer, track_number))
438 return 0;
439
440 // Bytes 2 & 3 of 4
441
442 if (SerializeInt(writer, timecode, 2))
443 return 0;
444
445 // Byte 4 of 4
446
447 const uint64 flags = 0;
448
449 if (SerializeInt(writer, flags, 1))
450 return 0;
451
452 // Now write the actual frame (of metadata)
453
454 if (writer->Write(data, static_cast<uint32>(length)))
455 return 0;
456
457 // Write Duration element
458
459 if (WriteID(writer, kMkvBlockDuration)) // 1-byte ID size
460 return 0;
461
462 if (WriteUInt(writer, duration_payload_size))
463 return 0;
464
465 if (SerializeInt(writer, duration, duration_payload_size))
466 return 0;
467
468 // Note that we don't write a reference time as part of the block
469 // group; no reference time(s) indicates that this block is a
470 // keyframe. (Unlike the case for a SimpleBlock element, the header
471 // bits of the Block sub-element of a BlockGroup element do not
472 // indicate keyframe status. The keyframe status is inferred from
473 // the absence of reference time sub-elements.)
474
475 return blockg_elem_size;
476 }
477
478 // Writes a WebM BlockGroup with BlockAdditional data. The structure is as
479 // follows:
480 // Indentation shows sub-levels
481 // BlockGroup
482 // Block
483 // Data
484 // BlockAdditions
485 // BlockMore
486 // BlockAddID
487 // 1 (Denotes Alpha)
488 // BlockAdditional
489 // Data
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)490 uint64 WriteBlockWithAdditional(IMkvWriter* writer,
491 const uint8* data,
492 uint64 length,
493 const uint8* additional,
494 uint64 additional_length,
495 uint64 add_id,
496 uint64 track_number,
497 int64 timecode,
498 uint64 is_key) {
499 if (!data || !additional || length < 1 || additional_length < 1)
500 return 0;
501
502 const uint64 block_payload_size = 4 + length;
503 const uint64 block_elem_size = EbmlMasterElementSize(kMkvBlock,
504 block_payload_size) +
505 block_payload_size;
506 const uint64 block_additional_elem_size = EbmlElementSize(kMkvBlockAdditional,
507 additional,
508 additional_length);
509 const uint64 block_addid_elem_size = EbmlElementSize(kMkvBlockAddID, add_id);
510
511 const uint64 block_more_payload_size = block_addid_elem_size +
512 block_additional_elem_size;
513 const uint64 block_more_elem_size = EbmlMasterElementSize(
514 kMkvBlockMore,
515 block_more_payload_size) +
516 block_more_payload_size;
517 const uint64 block_additions_payload_size = block_more_elem_size;
518 const uint64 block_additions_elem_size = EbmlMasterElementSize(
519 kMkvBlockAdditions,
520 block_additions_payload_size) +
521 block_additions_payload_size;
522 const uint64 block_group_payload_size = block_elem_size +
523 block_additions_elem_size;
524 const uint64 block_group_elem_size = EbmlMasterElementSize(
525 kMkvBlockGroup,
526 block_group_payload_size) +
527 block_group_payload_size;
528
529 if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
530 block_group_payload_size))
531 return 0;
532
533 if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
534 return 0;
535
536 if (WriteUInt(writer, track_number))
537 return 0;
538
539 if (SerializeInt(writer, timecode, 2))
540 return 0;
541
542 uint64 flags = 0;
543 if (is_key)
544 flags |= 0x80;
545 if (SerializeInt(writer, flags, 1))
546 return 0;
547
548 if (writer->Write(data, static_cast<uint32>(length)))
549 return 0;
550
551 if (!WriteEbmlMasterElement(writer, kMkvBlockAdditions,
552 block_additions_payload_size))
553 return 0;
554
555 if (!WriteEbmlMasterElement(writer, kMkvBlockMore, block_more_payload_size))
556 return 0;
557
558 if (!WriteEbmlElement(writer, kMkvBlockAddID, add_id))
559 return 0;
560
561 if (!WriteEbmlElement(writer, kMkvBlockAdditional,
562 additional, additional_length))
563 return 0;
564
565 return block_group_elem_size;
566 }
567
568 // Writes a WebM BlockGroup with DiscardPadding. The structure is as follows:
569 // Indentation shows sub-levels
570 // BlockGroup
571 // Block
572 // Data
573 // DiscardPadding
WriteBlockWithDiscardPadding(IMkvWriter * writer,const uint8 * data,uint64 length,int64 discard_padding,uint64 track_number,int64 timecode,uint64 is_key)574 uint64 WriteBlockWithDiscardPadding(IMkvWriter* writer,
575 const uint8* data,
576 uint64 length,
577 int64 discard_padding,
578 uint64 track_number,
579 int64 timecode,
580 uint64 is_key) {
581 if (!data || length < 1 || discard_padding <= 0)
582 return 0;
583
584 const uint64 block_payload_size = 4 + length;
585 const uint64 block_elem_size = EbmlMasterElementSize(kMkvBlock,
586 block_payload_size) +
587 block_payload_size;
588 const uint64 discard_padding_elem_size = EbmlElementSize(kMkvDiscardPadding,
589 discard_padding);
590 const uint64 block_group_payload_size = block_elem_size +
591 discard_padding_elem_size;
592 const uint64 block_group_elem_size = EbmlMasterElementSize(
593 kMkvBlockGroup,
594 block_group_payload_size) +
595 block_group_payload_size;
596
597 if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
598 block_group_payload_size))
599 return 0;
600
601 if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
602 return 0;
603
604 if (WriteUInt(writer, track_number))
605 return 0;
606
607 if (SerializeInt(writer, timecode, 2))
608 return 0;
609
610 uint64 flags = 0;
611 if (is_key)
612 flags |= 0x80;
613 if (SerializeInt(writer, flags, 1))
614 return 0;
615
616 if (writer->Write(data, static_cast<uint32>(length)))
617 return 0;
618
619 if (WriteID(writer, kMkvDiscardPadding))
620 return 0;
621
622 const uint64 size = GetUIntSize(discard_padding);
623 if (WriteUInt(writer, size))
624 return false;
625
626 if (SerializeInt(writer, discard_padding, static_cast<int32>(size)))
627 return false;
628
629 return block_group_elem_size;
630 }
631
WriteVoidElement(IMkvWriter * writer,uint64 size)632 uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
633 if (!writer)
634 return false;
635
636 // Subtract one for the void ID and the coded size.
637 uint64 void_entry_size = size - 1 - GetCodedUIntSize(size-1);
638 uint64 void_size = EbmlMasterElementSize(kMkvVoid, void_entry_size) +
639 void_entry_size;
640
641 if (void_size != size)
642 return 0;
643
644 const int64 payload_position = writer->Position();
645 if (payload_position < 0)
646 return 0;
647
648 if (WriteID(writer, kMkvVoid))
649 return 0;
650
651 if (WriteUInt(writer, void_entry_size))
652 return 0;
653
654 const uint8 value = 0;
655 for (int32 i = 0; i < static_cast<int32>(void_entry_size); ++i) {
656 if (writer->Write(&value, 1))
657 return 0;
658 }
659
660 const int64 stop_position = writer->Position();
661 if (stop_position < 0 ||
662 stop_position - payload_position != static_cast<int64>(void_size))
663 return 0;
664
665 return void_size;
666 }
667
GetVersion(int32 * major,int32 * minor,int32 * build,int32 * revision)668 void GetVersion(int32* major, int32* minor, int32* build, int32* revision) {
669 *major = 0;
670 *minor = 2;
671 *build = 1;
672 *revision = 0;
673 }
674
675 } // namespace mkvmuxer
676
MakeUID(unsigned int * seed)677 mkvmuxer::uint64 mkvmuxer::MakeUID(unsigned int* seed) {
678 uint64 uid = 0;
679
680 #ifdef __MINGW32__
681 srand(*seed);
682 #endif
683
684 for (int i = 0; i < 7; ++i) { // avoid problems with 8-byte values
685 uid <<= 8;
686
687 // TODO(fgalligan): Move random number generation to platform specific code.
688 #ifdef _MSC_VER
689 (void)seed;
690 unsigned int random_value;
691 const errno_t e = rand_s(&random_value);
692 (void)e;
693 const int32 nn = random_value;
694 #elif __ANDROID__
695 int32 temp_num = 1;
696 int fd = open("/dev/urandom", O_RDONLY);
697 if (fd != -1) {
698 read(fd, &temp_num, sizeof(int32));
699 close(fd);
700 }
701 const int32 nn = temp_num;
702 #elif defined __MINGW32__
703 const int32 nn = rand();
704 #else
705 const int32 nn = rand_r(seed);
706 #endif
707 const int32 n = 0xFF & (nn >> 4); // throw away low-order bits
708
709 uid |= n;
710 }
711
712 return uid;
713 }
714