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
30namespace mkvmuxer {
31
32int32 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
50int32 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
68uint64 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
78uint64 EbmlElementSize(uint64 type, int64 value) {
79  return EbmlElementSize(type, static_cast<uint64>(value));
80}
81
82uint64 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
95uint64 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
108uint64 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
124uint64 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
140int32 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
160int32 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
188int32 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
197int32 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
231int32 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
242bool 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
255bool 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
272bool 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
288bool 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
305bool 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
324uint64 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//
394uint64 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
490uint64 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
574uint64 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
632uint64 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
668void 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
677mkvmuxer::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