1233d2500723e5594f3e7c70896ffeeef32b9c950ywan// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
2233d2500723e5594f3e7c70896ffeeef32b9c950ywan//
3233d2500723e5594f3e7c70896ffeeef32b9c950ywan// Use of this source code is governed by a BSD-style license
4233d2500723e5594f3e7c70896ffeeef32b9c950ywan// that can be found in the LICENSE file in the root of the source
5233d2500723e5594f3e7c70896ffeeef32b9c950ywan// tree. An additional intellectual property rights grant can be found
6233d2500723e5594f3e7c70896ffeeef32b9c950ywan// in the file PATENTS.  All contributing project authors may
7233d2500723e5594f3e7c70896ffeeef32b9c950ywan// be found in the AUTHORS file in the root of the source tree.
8233d2500723e5594f3e7c70896ffeeef32b9c950ywan
9233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "mkvmuxerutil.hpp"
10233d2500723e5594f3e7c70896ffeeef32b9c950ywan
11233d2500723e5594f3e7c70896ffeeef32b9c950ywan#ifdef __ANDROID__
12233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <fcntl.h>
13233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif
14233d2500723e5594f3e7c70896ffeeef32b9c950ywan
15233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <cassert>
16233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <cmath>
17233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <cstdio>
18233d2500723e5594f3e7c70896ffeeef32b9c950ywan#ifdef _MSC_VER
19233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define _CRT_RAND_S
20233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif
21233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <cstdlib>
22233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <cstring>
23233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <ctime>
24233d2500723e5594f3e7c70896ffeeef32b9c950ywan
25233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <new>
26233d2500723e5594f3e7c70896ffeeef32b9c950ywan
27233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "mkvwriter.hpp"
28233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "webmids.hpp"
29233d2500723e5594f3e7c70896ffeeef32b9c950ywan
30233d2500723e5594f3e7c70896ffeeef32b9c950ywannamespace mkvmuxer {
31233d2500723e5594f3e7c70896ffeeef32b9c950ywan
32233d2500723e5594f3e7c70896ffeeef32b9c950ywanint32 GetCodedUIntSize(uint64 value) {
33233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (value < 0x000000000000007FULL)
34233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 1;
35233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x0000000000003FFFULL)
36233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 2;
37233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x00000000001FFFFFULL)
38233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 3;
39233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x000000000FFFFFFFULL)
40233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 4;
41233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x00000007FFFFFFFFULL)
42233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 5;
43233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x000003FFFFFFFFFFULL)
44233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 6;
45233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x0001FFFFFFFFFFFFULL)
46233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 7;
47233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return 8;
48233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
49233d2500723e5594f3e7c70896ffeeef32b9c950ywan
50233d2500723e5594f3e7c70896ffeeef32b9c950ywanint32 GetUIntSize(uint64 value) {
51233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (value < 0x0000000000000100ULL)
52233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 1;
53233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x0000000000010000ULL)
54233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 2;
55233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x0000000001000000ULL)
56233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 3;
57233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x0000000100000000ULL)
58233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 4;
59233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x0000010000000000ULL)
60233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 5;
61233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x0001000000000000ULL)
62233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 6;
63233d2500723e5594f3e7c70896ffeeef32b9c950ywan  else if (value < 0x0100000000000000ULL)
64233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 7;
65233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return 8;
66233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
67233d2500723e5594f3e7c70896ffeeef32b9c950ywan
68233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 EbmlMasterElementSize(uint64 type, uint64 value) {
69233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Size of EBML ID
70233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int32 ebml_size = GetUIntSize(type);
71233d2500723e5594f3e7c70896ffeeef32b9c950ywan
72233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Datasize
73233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ebml_size += GetCodedUIntSize(value);
74233d2500723e5594f3e7c70896ffeeef32b9c950ywan
75233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return ebml_size;
76233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
77233d2500723e5594f3e7c70896ffeeef32b9c950ywan
78233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 EbmlElementSize(uint64 type, int64 value) {
79233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return EbmlElementSize(type, static_cast<uint64>(value));
80233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
81233d2500723e5594f3e7c70896ffeeef32b9c950ywan
82233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 EbmlElementSize(uint64 type, uint64 value) {
83233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Size of EBML ID
84233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int32 ebml_size = GetUIntSize(type);
85233d2500723e5594f3e7c70896ffeeef32b9c950ywan
86233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Datasize
87233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ebml_size += GetUIntSize(value);
88233d2500723e5594f3e7c70896ffeeef32b9c950ywan
89233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Size of Datasize
90233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ebml_size++;
91233d2500723e5594f3e7c70896ffeeef32b9c950ywan
92233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return ebml_size;
93233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
94233d2500723e5594f3e7c70896ffeeef32b9c950ywan
95233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 EbmlElementSize(uint64 type, float /* value */ ) {
96233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Size of EBML ID
97233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint64 ebml_size = GetUIntSize(type);
98233d2500723e5594f3e7c70896ffeeef32b9c950ywan
99233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Datasize
100233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ebml_size += sizeof(float);
101233d2500723e5594f3e7c70896ffeeef32b9c950ywan
102233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Size of Datasize
103233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ebml_size++;
104233d2500723e5594f3e7c70896ffeeef32b9c950ywan
105233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return ebml_size;
106233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
107233d2500723e5594f3e7c70896ffeeef32b9c950ywan
108233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 EbmlElementSize(uint64 type, const char* value) {
109233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!value)
110233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
111233d2500723e5594f3e7c70896ffeeef32b9c950ywan
112233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Size of EBML ID
113233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint64 ebml_size = GetUIntSize(type);
114233d2500723e5594f3e7c70896ffeeef32b9c950ywan
115233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Datasize
116233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ebml_size += strlen(value);
117233d2500723e5594f3e7c70896ffeeef32b9c950ywan
118233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Size of Datasize
119233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ebml_size++;
120233d2500723e5594f3e7c70896ffeeef32b9c950ywan
121233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return ebml_size;
122233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
123233d2500723e5594f3e7c70896ffeeef32b9c950ywan
124233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) {
125233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!value)
126233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
127233d2500723e5594f3e7c70896ffeeef32b9c950ywan
128233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Size of EBML ID
129233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint64 ebml_size = GetUIntSize(type);
130233d2500723e5594f3e7c70896ffeeef32b9c950ywan
131233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Datasize
132233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ebml_size += size;
133233d2500723e5594f3e7c70896ffeeef32b9c950ywan
134233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Size of Datasize
135233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ebml_size += GetCodedUIntSize(size);
136233d2500723e5594f3e7c70896ffeeef32b9c950ywan
137233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return ebml_size;
138233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
139233d2500723e5594f3e7c70896ffeeef32b9c950ywan
140233d2500723e5594f3e7c70896ffeeef32b9c950ywanint32 SerializeInt(IMkvWriter* writer, int64 value, int32 size) {
141233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer || size < 1 || size > 8)
142233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return -1;
143233d2500723e5594f3e7c70896ffeeef32b9c950ywan
144233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (int32 i = 1; i <= size; ++i) {
145233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 byte_count = size - i;
146233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 bit_count = byte_count * 8;
147233d2500723e5594f3e7c70896ffeeef32b9c950ywan
148233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int64 bb = value >> bit_count;
149233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const uint8 b = static_cast<uint8>(bb);
150233d2500723e5594f3e7c70896ffeeef32b9c950ywan
151233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 status = writer->Write(&b, 1);
152233d2500723e5594f3e7c70896ffeeef32b9c950ywan
153233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (status < 0)
154233d2500723e5594f3e7c70896ffeeef32b9c950ywan      return status;
155233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
156233d2500723e5594f3e7c70896ffeeef32b9c950ywan
157233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return 0;
158233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
159233d2500723e5594f3e7c70896ffeeef32b9c950ywan
160233d2500723e5594f3e7c70896ffeeef32b9c950ywanint32 SerializeFloat(IMkvWriter* writer, float f) {
161233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer)
162233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return -1;
163233d2500723e5594f3e7c70896ffeeef32b9c950ywan
164233d2500723e5594f3e7c70896ffeeef32b9c950ywan  assert(sizeof(uint32) == sizeof(float));
165233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // This union is merely used to avoid a reinterpret_cast from float& to
166233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // uint32& which will result in violation of strict aliasing.
167233d2500723e5594f3e7c70896ffeeef32b9c950ywan  union U32 {
168233d2500723e5594f3e7c70896ffeeef32b9c950ywan    uint32 u32;
169233d2500723e5594f3e7c70896ffeeef32b9c950ywan    float f;
170233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } value;
171233d2500723e5594f3e7c70896ffeeef32b9c950ywan  value.f = f;
172233d2500723e5594f3e7c70896ffeeef32b9c950ywan
173233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (int32 i = 1; i <= 4; ++i) {
174233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 byte_count = 4 - i;
175233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 bit_count = byte_count * 8;
176233d2500723e5594f3e7c70896ffeeef32b9c950ywan
177233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const uint8 byte = static_cast<uint8>(value.u32 >> bit_count);
178233d2500723e5594f3e7c70896ffeeef32b9c950ywan
179233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 status = writer->Write(&byte, 1);
180233d2500723e5594f3e7c70896ffeeef32b9c950ywan
181233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (status < 0)
182233d2500723e5594f3e7c70896ffeeef32b9c950ywan      return status;
183233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
184233d2500723e5594f3e7c70896ffeeef32b9c950ywan
185233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return 0;
186233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
187233d2500723e5594f3e7c70896ffeeef32b9c950ywan
188233d2500723e5594f3e7c70896ffeeef32b9c950ywanint32 WriteUInt(IMkvWriter* writer, uint64 value) {
189233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer)
190233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return -1;
191233d2500723e5594f3e7c70896ffeeef32b9c950ywan
192233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int32 size = GetCodedUIntSize(value);
193233d2500723e5594f3e7c70896ffeeef32b9c950ywan
194233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return WriteUIntSize(writer, value, size);
195233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
196233d2500723e5594f3e7c70896ffeeef32b9c950ywan
197233d2500723e5594f3e7c70896ffeeef32b9c950ywanint32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) {
198233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer || size < 0 || size > 8)
199233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return -1;
200233d2500723e5594f3e7c70896ffeeef32b9c950ywan
201233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (size > 0) {
202233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const uint64 bit = 1LL << (size * 7);
203233d2500723e5594f3e7c70896ffeeef32b9c950ywan
204233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (value > (bit - 2))
205233d2500723e5594f3e7c70896ffeeef32b9c950ywan      return -1;
206233d2500723e5594f3e7c70896ffeeef32b9c950ywan
207233d2500723e5594f3e7c70896ffeeef32b9c950ywan    value |= bit;
208233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
209233d2500723e5594f3e7c70896ffeeef32b9c950ywan    size = 1;
210233d2500723e5594f3e7c70896ffeeef32b9c950ywan    int64 bit;
211233d2500723e5594f3e7c70896ffeeef32b9c950ywan
212233d2500723e5594f3e7c70896ffeeef32b9c950ywan    for (;;) {
213233d2500723e5594f3e7c70896ffeeef32b9c950ywan      bit = 1LL << (size * 7);
214233d2500723e5594f3e7c70896ffeeef32b9c950ywan      const uint64 max = bit - 2;
215233d2500723e5594f3e7c70896ffeeef32b9c950ywan
216233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (value <= max)
217233d2500723e5594f3e7c70896ffeeef32b9c950ywan        break;
218233d2500723e5594f3e7c70896ffeeef32b9c950ywan
219233d2500723e5594f3e7c70896ffeeef32b9c950ywan      ++size;
220233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
221233d2500723e5594f3e7c70896ffeeef32b9c950ywan
222233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (size > 8)
223233d2500723e5594f3e7c70896ffeeef32b9c950ywan      return false;
224233d2500723e5594f3e7c70896ffeeef32b9c950ywan
225233d2500723e5594f3e7c70896ffeeef32b9c950ywan    value |= bit;
226233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
227233d2500723e5594f3e7c70896ffeeef32b9c950ywan
228233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return SerializeInt(writer, value, size);
229233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
230233d2500723e5594f3e7c70896ffeeef32b9c950ywan
231233d2500723e5594f3e7c70896ffeeef32b9c950ywanint32 WriteID(IMkvWriter* writer, uint64 type) {
232233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer)
233233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return -1;
234233d2500723e5594f3e7c70896ffeeef32b9c950ywan
235233d2500723e5594f3e7c70896ffeeef32b9c950ywan  writer->ElementStartNotify(type, writer->Position());
236233d2500723e5594f3e7c70896ffeeef32b9c950ywan
237233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const int32 size = GetUIntSize(type);
238233d2500723e5594f3e7c70896ffeeef32b9c950ywan
239233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return SerializeInt(writer, type, size);
240233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
241233d2500723e5594f3e7c70896ffeeef32b9c950ywan
242233d2500723e5594f3e7c70896ffeeef32b9c950ywanbool WriteEbmlMasterElement(IMkvWriter* writer, uint64 type, uint64 size) {
243233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer)
244233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
245233d2500723e5594f3e7c70896ffeeef32b9c950ywan
246233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, type))
247233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
248233d2500723e5594f3e7c70896ffeeef32b9c950ywan
249233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, size))
250233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
251233d2500723e5594f3e7c70896ffeeef32b9c950ywan
252233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return true;
253233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
254233d2500723e5594f3e7c70896ffeeef32b9c950ywan
255233d2500723e5594f3e7c70896ffeeef32b9c950ywanbool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
256233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer)
257233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
258233d2500723e5594f3e7c70896ffeeef32b9c950ywan
259233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, type))
260233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
261233d2500723e5594f3e7c70896ffeeef32b9c950ywan
262233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 size = GetUIntSize(value);
263233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, size))
264233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
265233d2500723e5594f3e7c70896ffeeef32b9c950ywan
266233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, value, static_cast<int32>(size)))
267233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
268233d2500723e5594f3e7c70896ffeeef32b9c950ywan
269233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return true;
270233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
271233d2500723e5594f3e7c70896ffeeef32b9c950ywan
272233d2500723e5594f3e7c70896ffeeef32b9c950ywanbool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
273233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer)
274233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
275233d2500723e5594f3e7c70896ffeeef32b9c950ywan
276233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, type))
277233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
278233d2500723e5594f3e7c70896ffeeef32b9c950ywan
279233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, 4))
280233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
281233d2500723e5594f3e7c70896ffeeef32b9c950ywan
282233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeFloat(writer, value))
283233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
284233d2500723e5594f3e7c70896ffeeef32b9c950ywan
285233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return true;
286233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
287233d2500723e5594f3e7c70896ffeeef32b9c950ywan
288233d2500723e5594f3e7c70896ffeeef32b9c950ywanbool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value) {
289233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer || !value)
290233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
291233d2500723e5594f3e7c70896ffeeef32b9c950ywan
292233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, type))
293233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
294233d2500723e5594f3e7c70896ffeeef32b9c950ywan
295233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const int32 length = strlen(value);
296233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, length))
297233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
298233d2500723e5594f3e7c70896ffeeef32b9c950ywan
299233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (writer->Write(value, length))
300233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
301233d2500723e5594f3e7c70896ffeeef32b9c950ywan
302233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return true;
303233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
304233d2500723e5594f3e7c70896ffeeef32b9c950ywan
305233d2500723e5594f3e7c70896ffeeef32b9c950ywanbool WriteEbmlElement(IMkvWriter* writer,
306233d2500723e5594f3e7c70896ffeeef32b9c950ywan                      uint64 type,
307233d2500723e5594f3e7c70896ffeeef32b9c950ywan                      const uint8* value,
308233d2500723e5594f3e7c70896ffeeef32b9c950ywan                      uint64 size) {
309233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer || !value || size < 1)
310233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
311233d2500723e5594f3e7c70896ffeeef32b9c950ywan
312233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, type))
313233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
314233d2500723e5594f3e7c70896ffeeef32b9c950ywan
315233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, size))
316233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
317233d2500723e5594f3e7c70896ffeeef32b9c950ywan
318233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (writer->Write(value, static_cast<uint32>(size)))
319233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
320233d2500723e5594f3e7c70896ffeeef32b9c950ywan
321233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return true;
322233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
323233d2500723e5594f3e7c70896ffeeef32b9c950ywan
324233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 WriteSimpleBlock(IMkvWriter* writer,
325233d2500723e5594f3e7c70896ffeeef32b9c950ywan                        const uint8* data,
326233d2500723e5594f3e7c70896ffeeef32b9c950ywan                        uint64 length,
327233d2500723e5594f3e7c70896ffeeef32b9c950ywan                        uint64 track_number,
328233d2500723e5594f3e7c70896ffeeef32b9c950ywan                        int64 timecode,
329233d2500723e5594f3e7c70896ffeeef32b9c950ywan                        uint64 is_key) {
330233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer)
331233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
332233d2500723e5594f3e7c70896ffeeef32b9c950ywan
333233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!data || length < 1)
334233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
335233d2500723e5594f3e7c70896ffeeef32b9c950ywan
336233d2500723e5594f3e7c70896ffeeef32b9c950ywan  //  Here we only permit track number values to be no greater than
337233d2500723e5594f3e7c70896ffeeef32b9c950ywan  //  126, which the largest value we can store having a Matroska
338233d2500723e5594f3e7c70896ffeeef32b9c950ywan  //  integer representation of only 1 byte.
339233d2500723e5594f3e7c70896ffeeef32b9c950ywan
340233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (track_number < 1 || track_number > 126)
341233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
342233d2500723e5594f3e7c70896ffeeef32b9c950ywan
343233d2500723e5594f3e7c70896ffeeef32b9c950ywan  //  Technically the timestamp for a block can be less than the
344233d2500723e5594f3e7c70896ffeeef32b9c950ywan  //  timestamp for the cluster itself (remember that block timestamp
345233d2500723e5594f3e7c70896ffeeef32b9c950ywan  //  is a signed, 16-bit integer).  However, as a simplification we
346233d2500723e5594f3e7c70896ffeeef32b9c950ywan  //  only permit non-negative cluster-relative timestamps for blocks.
347233d2500723e5594f3e7c70896ffeeef32b9c950ywan
348233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (timecode < 0 || timecode > kMaxBlockTimecode)
349233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
350233d2500723e5594f3e7c70896ffeeef32b9c950ywan
351233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, kMkvSimpleBlock))
352233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
353233d2500723e5594f3e7c70896ffeeef32b9c950ywan
354233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const int32 size = static_cast<int32>(length) + 4;
355233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, size))
356233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
357233d2500723e5594f3e7c70896ffeeef32b9c950ywan
358233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, static_cast<uint64>(track_number)))
359233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
360233d2500723e5594f3e7c70896ffeeef32b9c950ywan
361233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, timecode, 2))
362233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
363233d2500723e5594f3e7c70896ffeeef32b9c950ywan
364233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint64 flags = 0;
365233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (is_key)
366233d2500723e5594f3e7c70896ffeeef32b9c950ywan    flags |= 0x80;
367233d2500723e5594f3e7c70896ffeeef32b9c950ywan
368233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, flags, 1))
369233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
370233d2500723e5594f3e7c70896ffeeef32b9c950ywan
371233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (writer->Write(data, static_cast<uint32>(length)))
372233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
373233d2500723e5594f3e7c70896ffeeef32b9c950ywan
374233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 element_size =
375233d2500723e5594f3e7c70896ffeeef32b9c950ywan    GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 + length;
376233d2500723e5594f3e7c70896ffeeef32b9c950ywan
377233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return element_size;
378233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
379233d2500723e5594f3e7c70896ffeeef32b9c950ywan
380233d2500723e5594f3e7c70896ffeeef32b9c950ywan// We must write the metadata (key)frame as a BlockGroup element,
381233d2500723e5594f3e7c70896ffeeef32b9c950ywan// because we need to specify a duration for the frame.  The
382233d2500723e5594f3e7c70896ffeeef32b9c950ywan// BlockGroup element comprises the frame itself and its duration,
383233d2500723e5594f3e7c70896ffeeef32b9c950ywan// and is laid out as follows:
384233d2500723e5594f3e7c70896ffeeef32b9c950ywan//
385233d2500723e5594f3e7c70896ffeeef32b9c950ywan//   BlockGroup tag
386233d2500723e5594f3e7c70896ffeeef32b9c950ywan//   BlockGroup size
387233d2500723e5594f3e7c70896ffeeef32b9c950ywan//     Block tag
388233d2500723e5594f3e7c70896ffeeef32b9c950ywan//     Block size
389233d2500723e5594f3e7c70896ffeeef32b9c950ywan//     (the frame is the block payload)
390233d2500723e5594f3e7c70896ffeeef32b9c950ywan//     Duration tag
391233d2500723e5594f3e7c70896ffeeef32b9c950ywan//     Duration size
392233d2500723e5594f3e7c70896ffeeef32b9c950ywan//     (duration payload)
393233d2500723e5594f3e7c70896ffeeef32b9c950ywan//
394233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 WriteMetadataBlock(IMkvWriter* writer,
395233d2500723e5594f3e7c70896ffeeef32b9c950ywan                          const uint8* data,
396233d2500723e5594f3e7c70896ffeeef32b9c950ywan                          uint64 length,
397233d2500723e5594f3e7c70896ffeeef32b9c950ywan                          uint64 track_number,
398233d2500723e5594f3e7c70896ffeeef32b9c950ywan                          int64 timecode,
399233d2500723e5594f3e7c70896ffeeef32b9c950ywan                          uint64 duration) {
400233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // We don't backtrack when writing to the stream, so we must
401233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // pre-compute the BlockGroup size, by summing the sizes of each
402233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // sub-element (the block and the duration).
403233d2500723e5594f3e7c70896ffeeef32b9c950ywan
404233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // We use a single byte for the track number of the block, which
405233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // means the block header is exactly 4 bytes.
406233d2500723e5594f3e7c70896ffeeef32b9c950ywan
407233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // TODO(matthewjheaney): use EbmlMasterElementSize and WriteEbmlMasterElement
408233d2500723e5594f3e7c70896ffeeef32b9c950ywan
409233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_payload_size = 4 + length;
410233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const int32 block_size = GetCodedUIntSize(block_payload_size);
411233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_elem_size = 1 + block_size + block_payload_size;
412233d2500723e5594f3e7c70896ffeeef32b9c950ywan
413233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const int32 duration_payload_size = GetUIntSize(duration);
414233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const int32 duration_size = GetCodedUIntSize(duration_payload_size);
415233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 duration_elem_size = 1 + duration_size + duration_payload_size;
416233d2500723e5594f3e7c70896ffeeef32b9c950ywan
417233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 blockg_payload_size = block_elem_size + duration_elem_size;
418233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const int32 blockg_size = GetCodedUIntSize(blockg_payload_size);
419233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 blockg_elem_size = 1 + blockg_size + blockg_payload_size;
420233d2500723e5594f3e7c70896ffeeef32b9c950ywan
421233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, kMkvBlockGroup))  // 1-byte ID size
422233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
423233d2500723e5594f3e7c70896ffeeef32b9c950ywan
424233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, blockg_payload_size))
425233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
426233d2500723e5594f3e7c70896ffeeef32b9c950ywan
427233d2500723e5594f3e7c70896ffeeef32b9c950ywan  //  Write Block element
428233d2500723e5594f3e7c70896ffeeef32b9c950ywan
429233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, kMkvBlock))  // 1-byte ID size
430233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
431233d2500723e5594f3e7c70896ffeeef32b9c950ywan
432233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, block_payload_size))
433233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
434233d2500723e5594f3e7c70896ffeeef32b9c950ywan
435233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Byte 1 of 4
436233d2500723e5594f3e7c70896ffeeef32b9c950ywan
437233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, track_number))
438233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
439233d2500723e5594f3e7c70896ffeeef32b9c950ywan
440233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Bytes 2 & 3 of 4
441233d2500723e5594f3e7c70896ffeeef32b9c950ywan
442233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, timecode, 2))
443233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
444233d2500723e5594f3e7c70896ffeeef32b9c950ywan
445233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Byte 4 of 4
446233d2500723e5594f3e7c70896ffeeef32b9c950ywan
447233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 flags = 0;
448233d2500723e5594f3e7c70896ffeeef32b9c950ywan
449233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, flags, 1))
450233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
451233d2500723e5594f3e7c70896ffeeef32b9c950ywan
452233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Now write the actual frame (of metadata)
453233d2500723e5594f3e7c70896ffeeef32b9c950ywan
454233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (writer->Write(data, static_cast<uint32>(length)))
455233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
456233d2500723e5594f3e7c70896ffeeef32b9c950ywan
457233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Write Duration element
458233d2500723e5594f3e7c70896ffeeef32b9c950ywan
459233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, kMkvBlockDuration))  // 1-byte ID size
460233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
461233d2500723e5594f3e7c70896ffeeef32b9c950ywan
462233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, duration_payload_size))
463233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
464233d2500723e5594f3e7c70896ffeeef32b9c950ywan
465233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, duration, duration_payload_size))
466233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
467233d2500723e5594f3e7c70896ffeeef32b9c950ywan
468233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Note that we don't write a reference time as part of the block
469233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // group; no reference time(s) indicates that this block is a
470233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // keyframe.  (Unlike the case for a SimpleBlock element, the header
471233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // bits of the Block sub-element of a BlockGroup element do not
472233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // indicate keyframe status.  The keyframe status is inferred from
473233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // the absence of reference time sub-elements.)
474233d2500723e5594f3e7c70896ffeeef32b9c950ywan
475233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return blockg_elem_size;
476233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
477233d2500723e5594f3e7c70896ffeeef32b9c950ywan
478233d2500723e5594f3e7c70896ffeeef32b9c950ywan// Writes a WebM BlockGroup with BlockAdditional data. The structure is as
479233d2500723e5594f3e7c70896ffeeef32b9c950ywan// follows:
480233d2500723e5594f3e7c70896ffeeef32b9c950ywan// Indentation shows sub-levels
481233d2500723e5594f3e7c70896ffeeef32b9c950ywan// BlockGroup
482233d2500723e5594f3e7c70896ffeeef32b9c950ywan//  Block
483233d2500723e5594f3e7c70896ffeeef32b9c950ywan//    Data
484233d2500723e5594f3e7c70896ffeeef32b9c950ywan//  BlockAdditions
485233d2500723e5594f3e7c70896ffeeef32b9c950ywan//    BlockMore
486233d2500723e5594f3e7c70896ffeeef32b9c950ywan//      BlockAddID
487233d2500723e5594f3e7c70896ffeeef32b9c950ywan//        1 (Denotes Alpha)
488233d2500723e5594f3e7c70896ffeeef32b9c950ywan//      BlockAdditional
489233d2500723e5594f3e7c70896ffeeef32b9c950ywan//        Data
490233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 WriteBlockWithAdditional(IMkvWriter* writer,
491233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                const uint8* data,
492233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                uint64 length,
493233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                const uint8* additional,
494233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                uint64 additional_length,
495233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                uint64 add_id,
496233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                uint64 track_number,
497233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                int64 timecode,
498233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                uint64 is_key) {
499233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!data || !additional || length < 1 || additional_length < 1)
500233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
501233d2500723e5594f3e7c70896ffeeef32b9c950ywan
502233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_payload_size = 4 + length;
503233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_elem_size = EbmlMasterElementSize(kMkvBlock,
504233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                                       block_payload_size) +
505233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                 block_payload_size;
506233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_additional_elem_size = EbmlElementSize(kMkvBlockAdditional,
507233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                                            additional,
508233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                                            additional_length);
509233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_addid_elem_size = EbmlElementSize(kMkvBlockAddID, add_id);
510233d2500723e5594f3e7c70896ffeeef32b9c950ywan
511233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_more_payload_size = block_addid_elem_size +
512233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                         block_additional_elem_size;
513233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_more_elem_size = EbmlMasterElementSize(
514233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                          kMkvBlockMore,
515233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                          block_more_payload_size) +
516233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                      block_more_payload_size;
517233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_additions_payload_size = block_more_elem_size;
518233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_additions_elem_size = EbmlMasterElementSize(
519233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                               kMkvBlockAdditions,
520233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                               block_additions_payload_size) +
521233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                           block_additions_payload_size;
522233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_group_payload_size = block_elem_size +
523233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                          block_additions_elem_size;
524233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_group_elem_size = EbmlMasterElementSize(
525233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                           kMkvBlockGroup,
526233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                           block_group_payload_size) +
527233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                       block_group_payload_size;
528233d2500723e5594f3e7c70896ffeeef32b9c950ywan
529233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
530233d2500723e5594f3e7c70896ffeeef32b9c950ywan                              block_group_payload_size))
531233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
532233d2500723e5594f3e7c70896ffeeef32b9c950ywan
533233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
534233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
535233d2500723e5594f3e7c70896ffeeef32b9c950ywan
536233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, track_number))
537233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
538233d2500723e5594f3e7c70896ffeeef32b9c950ywan
539233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, timecode, 2))
540233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
541233d2500723e5594f3e7c70896ffeeef32b9c950ywan
542233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint64 flags = 0;
543233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (is_key)
544233d2500723e5594f3e7c70896ffeeef32b9c950ywan    flags |= 0x80;
545233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, flags, 1))
546233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
547233d2500723e5594f3e7c70896ffeeef32b9c950ywan
548233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (writer->Write(data, static_cast<uint32>(length)))
549233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
550233d2500723e5594f3e7c70896ffeeef32b9c950ywan
551233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!WriteEbmlMasterElement(writer, kMkvBlockAdditions,
552233d2500723e5594f3e7c70896ffeeef32b9c950ywan                              block_additions_payload_size))
553233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
554233d2500723e5594f3e7c70896ffeeef32b9c950ywan
555233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!WriteEbmlMasterElement(writer, kMkvBlockMore, block_more_payload_size))
556233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
557233d2500723e5594f3e7c70896ffeeef32b9c950ywan
558233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!WriteEbmlElement(writer, kMkvBlockAddID, add_id))
559233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
560233d2500723e5594f3e7c70896ffeeef32b9c950ywan
561233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!WriteEbmlElement(writer, kMkvBlockAdditional,
562233d2500723e5594f3e7c70896ffeeef32b9c950ywan                        additional, additional_length))
563233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
564233d2500723e5594f3e7c70896ffeeef32b9c950ywan
565233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return block_group_elem_size;
566233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
567233d2500723e5594f3e7c70896ffeeef32b9c950ywan
568233d2500723e5594f3e7c70896ffeeef32b9c950ywan// Writes a WebM BlockGroup with DiscardPadding. The structure is as follows:
569233d2500723e5594f3e7c70896ffeeef32b9c950ywan// Indentation shows sub-levels
570233d2500723e5594f3e7c70896ffeeef32b9c950ywan// BlockGroup
571233d2500723e5594f3e7c70896ffeeef32b9c950ywan//  Block
572233d2500723e5594f3e7c70896ffeeef32b9c950ywan//    Data
573233d2500723e5594f3e7c70896ffeeef32b9c950ywan//  DiscardPadding
574233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 WriteBlockWithDiscardPadding(IMkvWriter* writer,
575233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                    const uint8* data,
576233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                    uint64 length,
577233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                    int64 discard_padding,
578233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                    uint64 track_number,
579233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                    int64 timecode,
580233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                    uint64 is_key) {
581233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!data || length < 1 || discard_padding <= 0)
582233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
583233d2500723e5594f3e7c70896ffeeef32b9c950ywan
584233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_payload_size = 4 + length;
585233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_elem_size = EbmlMasterElementSize(kMkvBlock,
586233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                                       block_payload_size) +
587233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                 block_payload_size;
588233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 discard_padding_elem_size = EbmlElementSize(kMkvDiscardPadding,
589233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                                           discard_padding);
590233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_group_payload_size = block_elem_size +
591233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                          discard_padding_elem_size;
592233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 block_group_elem_size = EbmlMasterElementSize(
593233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                           kMkvBlockGroup,
594233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                           block_group_payload_size) +
595233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                       block_group_payload_size;
596233d2500723e5594f3e7c70896ffeeef32b9c950ywan
597233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
598233d2500723e5594f3e7c70896ffeeef32b9c950ywan                              block_group_payload_size))
599233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
600233d2500723e5594f3e7c70896ffeeef32b9c950ywan
601233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
602233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
603233d2500723e5594f3e7c70896ffeeef32b9c950ywan
604233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, track_number))
605233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
606233d2500723e5594f3e7c70896ffeeef32b9c950ywan
607233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, timecode, 2))
608233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
609233d2500723e5594f3e7c70896ffeeef32b9c950ywan
610233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint64 flags = 0;
611233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (is_key)
612233d2500723e5594f3e7c70896ffeeef32b9c950ywan    flags |= 0x80;
613233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, flags, 1))
614233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
615233d2500723e5594f3e7c70896ffeeef32b9c950ywan
616233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (writer->Write(data, static_cast<uint32>(length)))
617233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
618233d2500723e5594f3e7c70896ffeeef32b9c950ywan
619233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, kMkvDiscardPadding))
620233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
621233d2500723e5594f3e7c70896ffeeef32b9c950ywan
622233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint64 size = GetUIntSize(discard_padding);
623233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, size))
624233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
625233d2500723e5594f3e7c70896ffeeef32b9c950ywan
626233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (SerializeInt(writer, discard_padding, static_cast<int32>(size)))
627233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
628233d2500723e5594f3e7c70896ffeeef32b9c950ywan
629233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return block_group_elem_size;
630233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
631233d2500723e5594f3e7c70896ffeeef32b9c950ywan
632233d2500723e5594f3e7c70896ffeeef32b9c950ywanuint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
633233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!writer)
634233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return false;
635233d2500723e5594f3e7c70896ffeeef32b9c950ywan
636233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Subtract one for the void ID and the coded size.
637233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint64 void_entry_size = size - 1 - GetCodedUIntSize(size-1);
638233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint64 void_size = EbmlMasterElementSize(kMkvVoid, void_entry_size) +
639233d2500723e5594f3e7c70896ffeeef32b9c950ywan                     void_entry_size;
640233d2500723e5594f3e7c70896ffeeef32b9c950ywan
641233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (void_size != size)
642233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
643233d2500723e5594f3e7c70896ffeeef32b9c950ywan
644233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const int64 payload_position = writer->Position();
645233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (payload_position < 0)
646233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
647233d2500723e5594f3e7c70896ffeeef32b9c950ywan
648233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteID(writer, kMkvVoid))
649233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
650233d2500723e5594f3e7c70896ffeeef32b9c950ywan
651233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (WriteUInt(writer, void_entry_size))
652233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
653233d2500723e5594f3e7c70896ffeeef32b9c950ywan
654233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const uint8 value = 0;
655233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (int32 i = 0; i < static_cast<int32>(void_entry_size); ++i) {
656233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (writer->Write(&value, 1))
657233d2500723e5594f3e7c70896ffeeef32b9c950ywan      return 0;
658233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
659233d2500723e5594f3e7c70896ffeeef32b9c950ywan
660233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const int64 stop_position = writer->Position();
661233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (stop_position < 0 ||
662233d2500723e5594f3e7c70896ffeeef32b9c950ywan      stop_position - payload_position != static_cast<int64>(void_size))
663233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return 0;
664233d2500723e5594f3e7c70896ffeeef32b9c950ywan
665233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return void_size;
666233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
667233d2500723e5594f3e7c70896ffeeef32b9c950ywan
668233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid GetVersion(int32* major, int32* minor, int32* build, int32* revision) {
669233d2500723e5594f3e7c70896ffeeef32b9c950ywan  *major = 0;
670233d2500723e5594f3e7c70896ffeeef32b9c950ywan  *minor = 2;
671233d2500723e5594f3e7c70896ffeeef32b9c950ywan  *build = 1;
672233d2500723e5594f3e7c70896ffeeef32b9c950ywan  *revision = 0;
673233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
674233d2500723e5594f3e7c70896ffeeef32b9c950ywan
675233d2500723e5594f3e7c70896ffeeef32b9c950ywan}  // namespace mkvmuxer
676233d2500723e5594f3e7c70896ffeeef32b9c950ywan
677233d2500723e5594f3e7c70896ffeeef32b9c950ywanmkvmuxer::uint64 mkvmuxer::MakeUID(unsigned int* seed) {
678233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint64 uid = 0;
679233d2500723e5594f3e7c70896ffeeef32b9c950ywan
680233d2500723e5594f3e7c70896ffeeef32b9c950ywan#ifdef __MINGW32__
681233d2500723e5594f3e7c70896ffeeef32b9c950ywan  srand(*seed);
682233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif
683233d2500723e5594f3e7c70896ffeeef32b9c950ywan
684233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (int i = 0; i < 7; ++i) {  // avoid problems with 8-byte values
685233d2500723e5594f3e7c70896ffeeef32b9c950ywan    uid <<= 8;
686233d2500723e5594f3e7c70896ffeeef32b9c950ywan
687233d2500723e5594f3e7c70896ffeeef32b9c950ywan    // TODO(fgalligan): Move random number generation to platform specific code.
688233d2500723e5594f3e7c70896ffeeef32b9c950ywan#ifdef _MSC_VER
689233d2500723e5594f3e7c70896ffeeef32b9c950ywan    (void)seed;
690233d2500723e5594f3e7c70896ffeeef32b9c950ywan    unsigned int random_value;
691233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const errno_t e = rand_s(&random_value);
692233d2500723e5594f3e7c70896ffeeef32b9c950ywan    (void)e;
693233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 nn  = random_value;
694233d2500723e5594f3e7c70896ffeeef32b9c950ywan#elif __ANDROID__
695233d2500723e5594f3e7c70896ffeeef32b9c950ywan    int32 temp_num = 1;
696233d2500723e5594f3e7c70896ffeeef32b9c950ywan    int fd = open("/dev/urandom", O_RDONLY);
697233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (fd != -1) {
698233d2500723e5594f3e7c70896ffeeef32b9c950ywan      read(fd, &temp_num, sizeof(int32));
699233d2500723e5594f3e7c70896ffeeef32b9c950ywan      close(fd);
700233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
701233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 nn = temp_num;
702233d2500723e5594f3e7c70896ffeeef32b9c950ywan#elif defined __MINGW32__
703233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 nn = rand();
704233d2500723e5594f3e7c70896ffeeef32b9c950ywan#else
705233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 nn = rand_r(seed);
706233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif
707233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int32 n = 0xFF & (nn >> 4);  // throw away low-order bits
708233d2500723e5594f3e7c70896ffeeef32b9c950ywan
709233d2500723e5594f3e7c70896ffeeef32b9c950ywan    uid |= n;
710233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
711233d2500723e5594f3e7c70896ffeeef32b9c950ywan
712233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return uid;
713233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
714