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