1*77c1e3ccSAndroid Build Coastguard Worker // Copyright (c) 2012 The WebM project authors. All Rights Reserved.
2*77c1e3ccSAndroid Build Coastguard Worker //
3*77c1e3ccSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license
4*77c1e3ccSAndroid Build Coastguard Worker // that can be found in the LICENSE file in the root of the source
5*77c1e3ccSAndroid Build Coastguard Worker // tree. An additional intellectual property rights grant can be found
6*77c1e3ccSAndroid Build Coastguard Worker // in the file PATENTS. All contributing project authors may
7*77c1e3ccSAndroid Build Coastguard Worker // be found in the AUTHORS file in the root of the source tree.
8*77c1e3ccSAndroid Build Coastguard Worker #include "mkvparser/mkvparser.h"
9*77c1e3ccSAndroid Build Coastguard Worker
10*77c1e3ccSAndroid Build Coastguard Worker #if defined(_MSC_VER) && _MSC_VER < 1800
11*77c1e3ccSAndroid Build Coastguard Worker #include <float.h> // _isnan() / _finite()
12*77c1e3ccSAndroid Build Coastguard Worker #define MSC_COMPAT
13*77c1e3ccSAndroid Build Coastguard Worker #endif
14*77c1e3ccSAndroid Build Coastguard Worker
15*77c1e3ccSAndroid Build Coastguard Worker #include <cassert>
16*77c1e3ccSAndroid Build Coastguard Worker #include <cfloat>
17*77c1e3ccSAndroid Build Coastguard Worker #include <climits>
18*77c1e3ccSAndroid Build Coastguard Worker #include <cmath>
19*77c1e3ccSAndroid Build Coastguard Worker #include <cstdint>
20*77c1e3ccSAndroid Build Coastguard Worker #include <cstring>
21*77c1e3ccSAndroid Build Coastguard Worker #include <memory>
22*77c1e3ccSAndroid Build Coastguard Worker #include <new>
23*77c1e3ccSAndroid Build Coastguard Worker
24*77c1e3ccSAndroid Build Coastguard Worker #include "common/webmids.h"
25*77c1e3ccSAndroid Build Coastguard Worker
26*77c1e3ccSAndroid Build Coastguard Worker namespace mkvparser {
27*77c1e3ccSAndroid Build Coastguard Worker const long long kStringElementSizeLimit = 20 * 1000 * 1000;
28*77c1e3ccSAndroid Build Coastguard Worker const float MasteringMetadata::kValueNotPresent = FLT_MAX;
29*77c1e3ccSAndroid Build Coastguard Worker const long long Colour::kValueNotPresent = LLONG_MAX;
30*77c1e3ccSAndroid Build Coastguard Worker const float Projection::kValueNotPresent = FLT_MAX;
31*77c1e3ccSAndroid Build Coastguard Worker
32*77c1e3ccSAndroid Build Coastguard Worker #ifdef MSC_COMPAT
isnan(double val)33*77c1e3ccSAndroid Build Coastguard Worker inline bool isnan(double val) { return !!_isnan(val); }
isinf(double val)34*77c1e3ccSAndroid Build Coastguard Worker inline bool isinf(double val) { return !_finite(val); }
35*77c1e3ccSAndroid Build Coastguard Worker #else
isnan(double val)36*77c1e3ccSAndroid Build Coastguard Worker inline bool isnan(double val) { return std::isnan(val); }
isinf(double val)37*77c1e3ccSAndroid Build Coastguard Worker inline bool isinf(double val) { return std::isinf(val); }
38*77c1e3ccSAndroid Build Coastguard Worker #endif // MSC_COMPAT
39*77c1e3ccSAndroid Build Coastguard Worker
40*77c1e3ccSAndroid Build Coastguard Worker template <typename Type>
SafeArrayAlloc(unsigned long long num_elements,unsigned long long element_size)41*77c1e3ccSAndroid Build Coastguard Worker Type* SafeArrayAlloc(unsigned long long num_elements,
42*77c1e3ccSAndroid Build Coastguard Worker unsigned long long element_size) {
43*77c1e3ccSAndroid Build Coastguard Worker if (num_elements == 0 || element_size == 0)
44*77c1e3ccSAndroid Build Coastguard Worker return NULL;
45*77c1e3ccSAndroid Build Coastguard Worker
46*77c1e3ccSAndroid Build Coastguard Worker const size_t kMaxAllocSize = 0x80000000; // 2GiB
47*77c1e3ccSAndroid Build Coastguard Worker const unsigned long long num_bytes = num_elements * element_size;
48*77c1e3ccSAndroid Build Coastguard Worker if (element_size > (kMaxAllocSize / num_elements))
49*77c1e3ccSAndroid Build Coastguard Worker return NULL;
50*77c1e3ccSAndroid Build Coastguard Worker if (num_bytes != static_cast<size_t>(num_bytes))
51*77c1e3ccSAndroid Build Coastguard Worker return NULL;
52*77c1e3ccSAndroid Build Coastguard Worker
53*77c1e3ccSAndroid Build Coastguard Worker return new (std::nothrow) Type[static_cast<size_t>(num_bytes)];
54*77c1e3ccSAndroid Build Coastguard Worker }
55*77c1e3ccSAndroid Build Coastguard Worker
GetVersion(int & major,int & minor,int & build,int & revision)56*77c1e3ccSAndroid Build Coastguard Worker void GetVersion(int& major, int& minor, int& build, int& revision) {
57*77c1e3ccSAndroid Build Coastguard Worker major = 1;
58*77c1e3ccSAndroid Build Coastguard Worker minor = 1;
59*77c1e3ccSAndroid Build Coastguard Worker build = 3;
60*77c1e3ccSAndroid Build Coastguard Worker revision = 0;
61*77c1e3ccSAndroid Build Coastguard Worker }
62*77c1e3ccSAndroid Build Coastguard Worker
ReadUInt(IMkvReader * pReader,long long pos,long & len)63*77c1e3ccSAndroid Build Coastguard Worker long long ReadUInt(IMkvReader* pReader, long long pos, long& len) {
64*77c1e3ccSAndroid Build Coastguard Worker if (!pReader || pos < 0)
65*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
66*77c1e3ccSAndroid Build Coastguard Worker
67*77c1e3ccSAndroid Build Coastguard Worker len = 1;
68*77c1e3ccSAndroid Build Coastguard Worker unsigned char b;
69*77c1e3ccSAndroid Build Coastguard Worker int status = pReader->Read(pos, 1, &b);
70*77c1e3ccSAndroid Build Coastguard Worker
71*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error or underflow
72*77c1e3ccSAndroid Build Coastguard Worker return status;
73*77c1e3ccSAndroid Build Coastguard Worker
74*77c1e3ccSAndroid Build Coastguard Worker if (status > 0) // interpreted as "underflow"
75*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
76*77c1e3ccSAndroid Build Coastguard Worker
77*77c1e3ccSAndroid Build Coastguard Worker if (b == 0) // we can't handle u-int values larger than 8 bytes
78*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
79*77c1e3ccSAndroid Build Coastguard Worker
80*77c1e3ccSAndroid Build Coastguard Worker unsigned char m = 0x80;
81*77c1e3ccSAndroid Build Coastguard Worker
82*77c1e3ccSAndroid Build Coastguard Worker while (!(b & m)) {
83*77c1e3ccSAndroid Build Coastguard Worker m >>= 1;
84*77c1e3ccSAndroid Build Coastguard Worker ++len;
85*77c1e3ccSAndroid Build Coastguard Worker }
86*77c1e3ccSAndroid Build Coastguard Worker
87*77c1e3ccSAndroid Build Coastguard Worker long long result = b & (~m);
88*77c1e3ccSAndroid Build Coastguard Worker ++pos;
89*77c1e3ccSAndroid Build Coastguard Worker
90*77c1e3ccSAndroid Build Coastguard Worker for (int i = 1; i < len; ++i) {
91*77c1e3ccSAndroid Build Coastguard Worker status = pReader->Read(pos, 1, &b);
92*77c1e3ccSAndroid Build Coastguard Worker
93*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) {
94*77c1e3ccSAndroid Build Coastguard Worker len = 1;
95*77c1e3ccSAndroid Build Coastguard Worker return status;
96*77c1e3ccSAndroid Build Coastguard Worker }
97*77c1e3ccSAndroid Build Coastguard Worker
98*77c1e3ccSAndroid Build Coastguard Worker if (status > 0) {
99*77c1e3ccSAndroid Build Coastguard Worker len = 1;
100*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
101*77c1e3ccSAndroid Build Coastguard Worker }
102*77c1e3ccSAndroid Build Coastguard Worker
103*77c1e3ccSAndroid Build Coastguard Worker result <<= 8;
104*77c1e3ccSAndroid Build Coastguard Worker result |= b;
105*77c1e3ccSAndroid Build Coastguard Worker
106*77c1e3ccSAndroid Build Coastguard Worker ++pos;
107*77c1e3ccSAndroid Build Coastguard Worker }
108*77c1e3ccSAndroid Build Coastguard Worker
109*77c1e3ccSAndroid Build Coastguard Worker return result;
110*77c1e3ccSAndroid Build Coastguard Worker }
111*77c1e3ccSAndroid Build Coastguard Worker
112*77c1e3ccSAndroid Build Coastguard Worker // Reads an EBML ID and returns it.
113*77c1e3ccSAndroid Build Coastguard Worker // An ID must at least 1 byte long, cannot exceed 4, and its value must be
114*77c1e3ccSAndroid Build Coastguard Worker // greater than 0.
115*77c1e3ccSAndroid Build Coastguard Worker // See known EBML values and EBMLMaxIDLength:
116*77c1e3ccSAndroid Build Coastguard Worker // http://www.matroska.org/technical/specs/index.html
117*77c1e3ccSAndroid Build Coastguard Worker // Returns the ID, or a value less than 0 to report an error while reading the
118*77c1e3ccSAndroid Build Coastguard Worker // ID.
ReadID(IMkvReader * pReader,long long pos,long & len)119*77c1e3ccSAndroid Build Coastguard Worker long long ReadID(IMkvReader* pReader, long long pos, long& len) {
120*77c1e3ccSAndroid Build Coastguard Worker if (pReader == NULL || pos < 0)
121*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
122*77c1e3ccSAndroid Build Coastguard Worker
123*77c1e3ccSAndroid Build Coastguard Worker // Read the first byte. The length in bytes of the ID is determined by
124*77c1e3ccSAndroid Build Coastguard Worker // finding the first set bit in the first byte of the ID.
125*77c1e3ccSAndroid Build Coastguard Worker unsigned char temp_byte = 0;
126*77c1e3ccSAndroid Build Coastguard Worker int read_status = pReader->Read(pos, 1, &temp_byte);
127*77c1e3ccSAndroid Build Coastguard Worker
128*77c1e3ccSAndroid Build Coastguard Worker if (read_status < 0)
129*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
130*77c1e3ccSAndroid Build Coastguard Worker else if (read_status > 0) // No data to read.
131*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
132*77c1e3ccSAndroid Build Coastguard Worker
133*77c1e3ccSAndroid Build Coastguard Worker if (temp_byte == 0) // ID length > 8 bytes; invalid file.
134*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
135*77c1e3ccSAndroid Build Coastguard Worker
136*77c1e3ccSAndroid Build Coastguard Worker int bit_pos = 0;
137*77c1e3ccSAndroid Build Coastguard Worker const int kMaxIdLengthInBytes = 4;
138*77c1e3ccSAndroid Build Coastguard Worker const int kCheckByte = 0x80;
139*77c1e3ccSAndroid Build Coastguard Worker
140*77c1e3ccSAndroid Build Coastguard Worker // Find the first bit that's set.
141*77c1e3ccSAndroid Build Coastguard Worker bool found_bit = false;
142*77c1e3ccSAndroid Build Coastguard Worker for (; bit_pos < kMaxIdLengthInBytes; ++bit_pos) {
143*77c1e3ccSAndroid Build Coastguard Worker if ((kCheckByte >> bit_pos) & temp_byte) {
144*77c1e3ccSAndroid Build Coastguard Worker found_bit = true;
145*77c1e3ccSAndroid Build Coastguard Worker break;
146*77c1e3ccSAndroid Build Coastguard Worker }
147*77c1e3ccSAndroid Build Coastguard Worker }
148*77c1e3ccSAndroid Build Coastguard Worker
149*77c1e3ccSAndroid Build Coastguard Worker if (!found_bit) {
150*77c1e3ccSAndroid Build Coastguard Worker // The value is too large to be a valid ID.
151*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
152*77c1e3ccSAndroid Build Coastguard Worker }
153*77c1e3ccSAndroid Build Coastguard Worker
154*77c1e3ccSAndroid Build Coastguard Worker // Read the remaining bytes of the ID (if any).
155*77c1e3ccSAndroid Build Coastguard Worker const int id_length = bit_pos + 1;
156*77c1e3ccSAndroid Build Coastguard Worker long long ebml_id = temp_byte;
157*77c1e3ccSAndroid Build Coastguard Worker for (int i = 1; i < id_length; ++i) {
158*77c1e3ccSAndroid Build Coastguard Worker ebml_id <<= 8;
159*77c1e3ccSAndroid Build Coastguard Worker read_status = pReader->Read(pos + i, 1, &temp_byte);
160*77c1e3ccSAndroid Build Coastguard Worker
161*77c1e3ccSAndroid Build Coastguard Worker if (read_status < 0)
162*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
163*77c1e3ccSAndroid Build Coastguard Worker else if (read_status > 0)
164*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
165*77c1e3ccSAndroid Build Coastguard Worker
166*77c1e3ccSAndroid Build Coastguard Worker ebml_id |= temp_byte;
167*77c1e3ccSAndroid Build Coastguard Worker }
168*77c1e3ccSAndroid Build Coastguard Worker
169*77c1e3ccSAndroid Build Coastguard Worker len = id_length;
170*77c1e3ccSAndroid Build Coastguard Worker return ebml_id;
171*77c1e3ccSAndroid Build Coastguard Worker }
172*77c1e3ccSAndroid Build Coastguard Worker
GetUIntLength(IMkvReader * pReader,long long pos,long & len)173*77c1e3ccSAndroid Build Coastguard Worker long long GetUIntLength(IMkvReader* pReader, long long pos, long& len) {
174*77c1e3ccSAndroid Build Coastguard Worker if (!pReader || pos < 0)
175*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
176*77c1e3ccSAndroid Build Coastguard Worker
177*77c1e3ccSAndroid Build Coastguard Worker long long total, available;
178*77c1e3ccSAndroid Build Coastguard Worker
179*77c1e3ccSAndroid Build Coastguard Worker int status = pReader->Length(&total, &available);
180*77c1e3ccSAndroid Build Coastguard Worker if (status < 0 || (total >= 0 && available > total))
181*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
182*77c1e3ccSAndroid Build Coastguard Worker
183*77c1e3ccSAndroid Build Coastguard Worker len = 1;
184*77c1e3ccSAndroid Build Coastguard Worker
185*77c1e3ccSAndroid Build Coastguard Worker if (pos >= available)
186*77c1e3ccSAndroid Build Coastguard Worker return pos; // too few bytes available
187*77c1e3ccSAndroid Build Coastguard Worker
188*77c1e3ccSAndroid Build Coastguard Worker unsigned char b;
189*77c1e3ccSAndroid Build Coastguard Worker
190*77c1e3ccSAndroid Build Coastguard Worker status = pReader->Read(pos, 1, &b);
191*77c1e3ccSAndroid Build Coastguard Worker
192*77c1e3ccSAndroid Build Coastguard Worker if (status != 0)
193*77c1e3ccSAndroid Build Coastguard Worker return status;
194*77c1e3ccSAndroid Build Coastguard Worker
195*77c1e3ccSAndroid Build Coastguard Worker if (b == 0) // we can't handle u-int values larger than 8 bytes
196*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
197*77c1e3ccSAndroid Build Coastguard Worker
198*77c1e3ccSAndroid Build Coastguard Worker unsigned char m = 0x80;
199*77c1e3ccSAndroid Build Coastguard Worker
200*77c1e3ccSAndroid Build Coastguard Worker while (!(b & m)) {
201*77c1e3ccSAndroid Build Coastguard Worker m >>= 1;
202*77c1e3ccSAndroid Build Coastguard Worker ++len;
203*77c1e3ccSAndroid Build Coastguard Worker }
204*77c1e3ccSAndroid Build Coastguard Worker
205*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
206*77c1e3ccSAndroid Build Coastguard Worker }
207*77c1e3ccSAndroid Build Coastguard Worker
208*77c1e3ccSAndroid Build Coastguard Worker // TODO(vigneshv): This function assumes that unsigned values never have their
209*77c1e3ccSAndroid Build Coastguard Worker // high bit set.
UnserializeUInt(IMkvReader * pReader,long long pos,long long size)210*77c1e3ccSAndroid Build Coastguard Worker long long UnserializeUInt(IMkvReader* pReader, long long pos, long long size) {
211*77c1e3ccSAndroid Build Coastguard Worker if (!pReader || pos < 0 || (size <= 0) || (size > 8))
212*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
213*77c1e3ccSAndroid Build Coastguard Worker
214*77c1e3ccSAndroid Build Coastguard Worker long long result = 0;
215*77c1e3ccSAndroid Build Coastguard Worker
216*77c1e3ccSAndroid Build Coastguard Worker for (long long i = 0; i < size; ++i) {
217*77c1e3ccSAndroid Build Coastguard Worker unsigned char b;
218*77c1e3ccSAndroid Build Coastguard Worker
219*77c1e3ccSAndroid Build Coastguard Worker const long status = pReader->Read(pos, 1, &b);
220*77c1e3ccSAndroid Build Coastguard Worker
221*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
222*77c1e3ccSAndroid Build Coastguard Worker return status;
223*77c1e3ccSAndroid Build Coastguard Worker
224*77c1e3ccSAndroid Build Coastguard Worker result <<= 8;
225*77c1e3ccSAndroid Build Coastguard Worker result |= b;
226*77c1e3ccSAndroid Build Coastguard Worker
227*77c1e3ccSAndroid Build Coastguard Worker ++pos;
228*77c1e3ccSAndroid Build Coastguard Worker }
229*77c1e3ccSAndroid Build Coastguard Worker
230*77c1e3ccSAndroid Build Coastguard Worker return result;
231*77c1e3ccSAndroid Build Coastguard Worker }
232*77c1e3ccSAndroid Build Coastguard Worker
UnserializeFloat(IMkvReader * pReader,long long pos,long long size_,double & result)233*77c1e3ccSAndroid Build Coastguard Worker long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_,
234*77c1e3ccSAndroid Build Coastguard Worker double& result) {
235*77c1e3ccSAndroid Build Coastguard Worker if (!pReader || pos < 0 || ((size_ != 4) && (size_ != 8)))
236*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
237*77c1e3ccSAndroid Build Coastguard Worker
238*77c1e3ccSAndroid Build Coastguard Worker const long size = static_cast<long>(size_);
239*77c1e3ccSAndroid Build Coastguard Worker
240*77c1e3ccSAndroid Build Coastguard Worker unsigned char buf[8];
241*77c1e3ccSAndroid Build Coastguard Worker
242*77c1e3ccSAndroid Build Coastguard Worker const int status = pReader->Read(pos, size, buf);
243*77c1e3ccSAndroid Build Coastguard Worker
244*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
245*77c1e3ccSAndroid Build Coastguard Worker return status;
246*77c1e3ccSAndroid Build Coastguard Worker
247*77c1e3ccSAndroid Build Coastguard Worker if (size == 4) {
248*77c1e3ccSAndroid Build Coastguard Worker union {
249*77c1e3ccSAndroid Build Coastguard Worker float f;
250*77c1e3ccSAndroid Build Coastguard Worker uint32_t ff;
251*77c1e3ccSAndroid Build Coastguard Worker static_assert(sizeof(float) == sizeof(uint32_t), "");
252*77c1e3ccSAndroid Build Coastguard Worker };
253*77c1e3ccSAndroid Build Coastguard Worker
254*77c1e3ccSAndroid Build Coastguard Worker ff = 0;
255*77c1e3ccSAndroid Build Coastguard Worker
256*77c1e3ccSAndroid Build Coastguard Worker for (int i = 0;;) {
257*77c1e3ccSAndroid Build Coastguard Worker ff |= buf[i];
258*77c1e3ccSAndroid Build Coastguard Worker
259*77c1e3ccSAndroid Build Coastguard Worker if (++i >= 4)
260*77c1e3ccSAndroid Build Coastguard Worker break;
261*77c1e3ccSAndroid Build Coastguard Worker
262*77c1e3ccSAndroid Build Coastguard Worker ff <<= 8;
263*77c1e3ccSAndroid Build Coastguard Worker }
264*77c1e3ccSAndroid Build Coastguard Worker
265*77c1e3ccSAndroid Build Coastguard Worker result = f;
266*77c1e3ccSAndroid Build Coastguard Worker } else {
267*77c1e3ccSAndroid Build Coastguard Worker union {
268*77c1e3ccSAndroid Build Coastguard Worker double d;
269*77c1e3ccSAndroid Build Coastguard Worker uint64_t dd;
270*77c1e3ccSAndroid Build Coastguard Worker static_assert(sizeof(double) == sizeof(uint64_t), "");
271*77c1e3ccSAndroid Build Coastguard Worker };
272*77c1e3ccSAndroid Build Coastguard Worker
273*77c1e3ccSAndroid Build Coastguard Worker dd = 0;
274*77c1e3ccSAndroid Build Coastguard Worker
275*77c1e3ccSAndroid Build Coastguard Worker for (int i = 0;;) {
276*77c1e3ccSAndroid Build Coastguard Worker dd |= buf[i];
277*77c1e3ccSAndroid Build Coastguard Worker
278*77c1e3ccSAndroid Build Coastguard Worker if (++i >= 8)
279*77c1e3ccSAndroid Build Coastguard Worker break;
280*77c1e3ccSAndroid Build Coastguard Worker
281*77c1e3ccSAndroid Build Coastguard Worker dd <<= 8;
282*77c1e3ccSAndroid Build Coastguard Worker }
283*77c1e3ccSAndroid Build Coastguard Worker
284*77c1e3ccSAndroid Build Coastguard Worker result = d;
285*77c1e3ccSAndroid Build Coastguard Worker }
286*77c1e3ccSAndroid Build Coastguard Worker
287*77c1e3ccSAndroid Build Coastguard Worker if (mkvparser::isinf(result) || mkvparser::isnan(result))
288*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
289*77c1e3ccSAndroid Build Coastguard Worker
290*77c1e3ccSAndroid Build Coastguard Worker return 0;
291*77c1e3ccSAndroid Build Coastguard Worker }
292*77c1e3ccSAndroid Build Coastguard Worker
UnserializeInt(IMkvReader * pReader,long long pos,long long size,long long & result_ref)293*77c1e3ccSAndroid Build Coastguard Worker long UnserializeInt(IMkvReader* pReader, long long pos, long long size,
294*77c1e3ccSAndroid Build Coastguard Worker long long& result_ref) {
295*77c1e3ccSAndroid Build Coastguard Worker if (!pReader || pos < 0 || size < 1 || size > 8)
296*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
297*77c1e3ccSAndroid Build Coastguard Worker
298*77c1e3ccSAndroid Build Coastguard Worker signed char first_byte = 0;
299*77c1e3ccSAndroid Build Coastguard Worker const long status = pReader->Read(pos, 1, (unsigned char*)&first_byte);
300*77c1e3ccSAndroid Build Coastguard Worker
301*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
302*77c1e3ccSAndroid Build Coastguard Worker return status;
303*77c1e3ccSAndroid Build Coastguard Worker
304*77c1e3ccSAndroid Build Coastguard Worker unsigned long long result = static_cast<unsigned long long>(first_byte);
305*77c1e3ccSAndroid Build Coastguard Worker ++pos;
306*77c1e3ccSAndroid Build Coastguard Worker
307*77c1e3ccSAndroid Build Coastguard Worker for (long i = 1; i < size; ++i) {
308*77c1e3ccSAndroid Build Coastguard Worker unsigned char b;
309*77c1e3ccSAndroid Build Coastguard Worker
310*77c1e3ccSAndroid Build Coastguard Worker const long status = pReader->Read(pos, 1, &b);
311*77c1e3ccSAndroid Build Coastguard Worker
312*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
313*77c1e3ccSAndroid Build Coastguard Worker return status;
314*77c1e3ccSAndroid Build Coastguard Worker
315*77c1e3ccSAndroid Build Coastguard Worker result <<= 8;
316*77c1e3ccSAndroid Build Coastguard Worker result |= b;
317*77c1e3ccSAndroid Build Coastguard Worker
318*77c1e3ccSAndroid Build Coastguard Worker ++pos;
319*77c1e3ccSAndroid Build Coastguard Worker }
320*77c1e3ccSAndroid Build Coastguard Worker
321*77c1e3ccSAndroid Build Coastguard Worker result_ref = static_cast<long long>(result);
322*77c1e3ccSAndroid Build Coastguard Worker return 0;
323*77c1e3ccSAndroid Build Coastguard Worker }
324*77c1e3ccSAndroid Build Coastguard Worker
UnserializeString(IMkvReader * pReader,long long pos,long long size,char * & str)325*77c1e3ccSAndroid Build Coastguard Worker long UnserializeString(IMkvReader* pReader, long long pos, long long size,
326*77c1e3ccSAndroid Build Coastguard Worker char*& str) {
327*77c1e3ccSAndroid Build Coastguard Worker delete[] str;
328*77c1e3ccSAndroid Build Coastguard Worker str = NULL;
329*77c1e3ccSAndroid Build Coastguard Worker
330*77c1e3ccSAndroid Build Coastguard Worker if (size >= LONG_MAX || size < 0 || size > kStringElementSizeLimit)
331*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
332*77c1e3ccSAndroid Build Coastguard Worker
333*77c1e3ccSAndroid Build Coastguard Worker // +1 for '\0' terminator
334*77c1e3ccSAndroid Build Coastguard Worker const long required_size = static_cast<long>(size) + 1;
335*77c1e3ccSAndroid Build Coastguard Worker
336*77c1e3ccSAndroid Build Coastguard Worker str = SafeArrayAlloc<char>(1, required_size);
337*77c1e3ccSAndroid Build Coastguard Worker if (str == NULL)
338*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
339*77c1e3ccSAndroid Build Coastguard Worker
340*77c1e3ccSAndroid Build Coastguard Worker unsigned char* const buf = reinterpret_cast<unsigned char*>(str);
341*77c1e3ccSAndroid Build Coastguard Worker
342*77c1e3ccSAndroid Build Coastguard Worker const long status = pReader->Read(pos, static_cast<long>(size), buf);
343*77c1e3ccSAndroid Build Coastguard Worker
344*77c1e3ccSAndroid Build Coastguard Worker if (status) {
345*77c1e3ccSAndroid Build Coastguard Worker delete[] str;
346*77c1e3ccSAndroid Build Coastguard Worker str = NULL;
347*77c1e3ccSAndroid Build Coastguard Worker
348*77c1e3ccSAndroid Build Coastguard Worker return status;
349*77c1e3ccSAndroid Build Coastguard Worker }
350*77c1e3ccSAndroid Build Coastguard Worker
351*77c1e3ccSAndroid Build Coastguard Worker str[required_size - 1] = '\0';
352*77c1e3ccSAndroid Build Coastguard Worker return 0;
353*77c1e3ccSAndroid Build Coastguard Worker }
354*77c1e3ccSAndroid Build Coastguard Worker
ParseElementHeader(IMkvReader * pReader,long long & pos,long long stop,long long & id,long long & size)355*77c1e3ccSAndroid Build Coastguard Worker long ParseElementHeader(IMkvReader* pReader, long long& pos, long long stop,
356*77c1e3ccSAndroid Build Coastguard Worker long long& id, long long& size) {
357*77c1e3ccSAndroid Build Coastguard Worker if (stop >= 0 && pos >= stop)
358*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
359*77c1e3ccSAndroid Build Coastguard Worker
360*77c1e3ccSAndroid Build Coastguard Worker long len;
361*77c1e3ccSAndroid Build Coastguard Worker
362*77c1e3ccSAndroid Build Coastguard Worker id = ReadID(pReader, pos, len);
363*77c1e3ccSAndroid Build Coastguard Worker
364*77c1e3ccSAndroid Build Coastguard Worker if (id < 0)
365*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
366*77c1e3ccSAndroid Build Coastguard Worker
367*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume id
368*77c1e3ccSAndroid Build Coastguard Worker
369*77c1e3ccSAndroid Build Coastguard Worker if (stop >= 0 && pos >= stop)
370*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
371*77c1e3ccSAndroid Build Coastguard Worker
372*77c1e3ccSAndroid Build Coastguard Worker size = ReadUInt(pReader, pos, len);
373*77c1e3ccSAndroid Build Coastguard Worker
374*77c1e3ccSAndroid Build Coastguard Worker if (size < 0 || len < 1 || len > 8) {
375*77c1e3ccSAndroid Build Coastguard Worker // Invalid: Negative payload size, negative or 0 length integer, or integer
376*77c1e3ccSAndroid Build Coastguard Worker // larger than 64 bits (libwebm cannot handle them).
377*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
378*77c1e3ccSAndroid Build Coastguard Worker }
379*77c1e3ccSAndroid Build Coastguard Worker
380*77c1e3ccSAndroid Build Coastguard Worker // Avoid rolling over pos when very close to LLONG_MAX.
381*77c1e3ccSAndroid Build Coastguard Worker const unsigned long long rollover_check =
382*77c1e3ccSAndroid Build Coastguard Worker static_cast<unsigned long long>(pos) + len;
383*77c1e3ccSAndroid Build Coastguard Worker if (rollover_check > LLONG_MAX)
384*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
385*77c1e3ccSAndroid Build Coastguard Worker
386*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size
387*77c1e3ccSAndroid Build Coastguard Worker
388*77c1e3ccSAndroid Build Coastguard Worker // pos now designates payload
389*77c1e3ccSAndroid Build Coastguard Worker
390*77c1e3ccSAndroid Build Coastguard Worker if (stop >= 0 && pos > stop)
391*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
392*77c1e3ccSAndroid Build Coastguard Worker
393*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
394*77c1e3ccSAndroid Build Coastguard Worker }
395*77c1e3ccSAndroid Build Coastguard Worker
Match(IMkvReader * pReader,long long & pos,unsigned long expected_id,long long & val)396*77c1e3ccSAndroid Build Coastguard Worker bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
397*77c1e3ccSAndroid Build Coastguard Worker long long& val) {
398*77c1e3ccSAndroid Build Coastguard Worker if (!pReader || pos < 0)
399*77c1e3ccSAndroid Build Coastguard Worker return false;
400*77c1e3ccSAndroid Build Coastguard Worker
401*77c1e3ccSAndroid Build Coastguard Worker long long total = 0;
402*77c1e3ccSAndroid Build Coastguard Worker long long available = 0;
403*77c1e3ccSAndroid Build Coastguard Worker
404*77c1e3ccSAndroid Build Coastguard Worker const long status = pReader->Length(&total, &available);
405*77c1e3ccSAndroid Build Coastguard Worker if (status < 0 || (total >= 0 && available > total))
406*77c1e3ccSAndroid Build Coastguard Worker return false;
407*77c1e3ccSAndroid Build Coastguard Worker
408*77c1e3ccSAndroid Build Coastguard Worker long len = 0;
409*77c1e3ccSAndroid Build Coastguard Worker
410*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
411*77c1e3ccSAndroid Build Coastguard Worker if (id < 0 || (available - pos) > len)
412*77c1e3ccSAndroid Build Coastguard Worker return false;
413*77c1e3ccSAndroid Build Coastguard Worker
414*77c1e3ccSAndroid Build Coastguard Worker if (static_cast<unsigned long>(id) != expected_id)
415*77c1e3ccSAndroid Build Coastguard Worker return false;
416*77c1e3ccSAndroid Build Coastguard Worker
417*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume id
418*77c1e3ccSAndroid Build Coastguard Worker
419*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
420*77c1e3ccSAndroid Build Coastguard Worker if (size < 0 || size > 8 || len < 1 || len > 8 || (available - pos) > len)
421*77c1e3ccSAndroid Build Coastguard Worker return false;
422*77c1e3ccSAndroid Build Coastguard Worker
423*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of payload
424*77c1e3ccSAndroid Build Coastguard Worker
425*77c1e3ccSAndroid Build Coastguard Worker val = UnserializeUInt(pReader, pos, size);
426*77c1e3ccSAndroid Build Coastguard Worker if (val < 0)
427*77c1e3ccSAndroid Build Coastguard Worker return false;
428*77c1e3ccSAndroid Build Coastguard Worker
429*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume size of payload
430*77c1e3ccSAndroid Build Coastguard Worker
431*77c1e3ccSAndroid Build Coastguard Worker return true;
432*77c1e3ccSAndroid Build Coastguard Worker }
433*77c1e3ccSAndroid Build Coastguard Worker
Match(IMkvReader * pReader,long long & pos,unsigned long expected_id,unsigned char * & buf,size_t & buflen)434*77c1e3ccSAndroid Build Coastguard Worker bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
435*77c1e3ccSAndroid Build Coastguard Worker unsigned char*& buf, size_t& buflen) {
436*77c1e3ccSAndroid Build Coastguard Worker if (!pReader || pos < 0)
437*77c1e3ccSAndroid Build Coastguard Worker return false;
438*77c1e3ccSAndroid Build Coastguard Worker
439*77c1e3ccSAndroid Build Coastguard Worker long long total = 0;
440*77c1e3ccSAndroid Build Coastguard Worker long long available = 0;
441*77c1e3ccSAndroid Build Coastguard Worker
442*77c1e3ccSAndroid Build Coastguard Worker long status = pReader->Length(&total, &available);
443*77c1e3ccSAndroid Build Coastguard Worker if (status < 0 || (total >= 0 && available > total))
444*77c1e3ccSAndroid Build Coastguard Worker return false;
445*77c1e3ccSAndroid Build Coastguard Worker
446*77c1e3ccSAndroid Build Coastguard Worker long len = 0;
447*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
448*77c1e3ccSAndroid Build Coastguard Worker if (id < 0 || (available - pos) > len)
449*77c1e3ccSAndroid Build Coastguard Worker return false;
450*77c1e3ccSAndroid Build Coastguard Worker
451*77c1e3ccSAndroid Build Coastguard Worker if (static_cast<unsigned long>(id) != expected_id)
452*77c1e3ccSAndroid Build Coastguard Worker return false;
453*77c1e3ccSAndroid Build Coastguard Worker
454*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume id
455*77c1e3ccSAndroid Build Coastguard Worker
456*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
457*77c1e3ccSAndroid Build Coastguard Worker if (size < 0 || len <= 0 || len > 8 || (available - pos) > len)
458*77c1e3ccSAndroid Build Coastguard Worker return false;
459*77c1e3ccSAndroid Build Coastguard Worker
460*77c1e3ccSAndroid Build Coastguard Worker unsigned long long rollover_check =
461*77c1e3ccSAndroid Build Coastguard Worker static_cast<unsigned long long>(pos) + len;
462*77c1e3ccSAndroid Build Coastguard Worker if (rollover_check > LLONG_MAX)
463*77c1e3ccSAndroid Build Coastguard Worker return false;
464*77c1e3ccSAndroid Build Coastguard Worker
465*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of payload
466*77c1e3ccSAndroid Build Coastguard Worker
467*77c1e3ccSAndroid Build Coastguard Worker rollover_check = static_cast<unsigned long long>(pos) + size;
468*77c1e3ccSAndroid Build Coastguard Worker if (rollover_check > LLONG_MAX)
469*77c1e3ccSAndroid Build Coastguard Worker return false;
470*77c1e3ccSAndroid Build Coastguard Worker
471*77c1e3ccSAndroid Build Coastguard Worker if ((pos + size) > available)
472*77c1e3ccSAndroid Build Coastguard Worker return false;
473*77c1e3ccSAndroid Build Coastguard Worker
474*77c1e3ccSAndroid Build Coastguard Worker if (size >= LONG_MAX)
475*77c1e3ccSAndroid Build Coastguard Worker return false;
476*77c1e3ccSAndroid Build Coastguard Worker
477*77c1e3ccSAndroid Build Coastguard Worker const long buflen_ = static_cast<long>(size);
478*77c1e3ccSAndroid Build Coastguard Worker
479*77c1e3ccSAndroid Build Coastguard Worker buf = SafeArrayAlloc<unsigned char>(1, buflen_);
480*77c1e3ccSAndroid Build Coastguard Worker if (!buf)
481*77c1e3ccSAndroid Build Coastguard Worker return false;
482*77c1e3ccSAndroid Build Coastguard Worker
483*77c1e3ccSAndroid Build Coastguard Worker status = pReader->Read(pos, buflen_, buf);
484*77c1e3ccSAndroid Build Coastguard Worker if (status != 0)
485*77c1e3ccSAndroid Build Coastguard Worker return false;
486*77c1e3ccSAndroid Build Coastguard Worker
487*77c1e3ccSAndroid Build Coastguard Worker buflen = buflen_;
488*77c1e3ccSAndroid Build Coastguard Worker
489*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume size of payload
490*77c1e3ccSAndroid Build Coastguard Worker return true;
491*77c1e3ccSAndroid Build Coastguard Worker }
492*77c1e3ccSAndroid Build Coastguard Worker
EBMLHeader()493*77c1e3ccSAndroid Build Coastguard Worker EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); }
494*77c1e3ccSAndroid Build Coastguard Worker
~EBMLHeader()495*77c1e3ccSAndroid Build Coastguard Worker EBMLHeader::~EBMLHeader() { delete[] m_docType; }
496*77c1e3ccSAndroid Build Coastguard Worker
Init()497*77c1e3ccSAndroid Build Coastguard Worker void EBMLHeader::Init() {
498*77c1e3ccSAndroid Build Coastguard Worker m_version = 1;
499*77c1e3ccSAndroid Build Coastguard Worker m_readVersion = 1;
500*77c1e3ccSAndroid Build Coastguard Worker m_maxIdLength = 4;
501*77c1e3ccSAndroid Build Coastguard Worker m_maxSizeLength = 8;
502*77c1e3ccSAndroid Build Coastguard Worker
503*77c1e3ccSAndroid Build Coastguard Worker if (m_docType) {
504*77c1e3ccSAndroid Build Coastguard Worker delete[] m_docType;
505*77c1e3ccSAndroid Build Coastguard Worker m_docType = NULL;
506*77c1e3ccSAndroid Build Coastguard Worker }
507*77c1e3ccSAndroid Build Coastguard Worker
508*77c1e3ccSAndroid Build Coastguard Worker m_docTypeVersion = 1;
509*77c1e3ccSAndroid Build Coastguard Worker m_docTypeReadVersion = 1;
510*77c1e3ccSAndroid Build Coastguard Worker }
511*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * pReader,long long & pos)512*77c1e3ccSAndroid Build Coastguard Worker long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
513*77c1e3ccSAndroid Build Coastguard Worker if (!pReader)
514*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
515*77c1e3ccSAndroid Build Coastguard Worker
516*77c1e3ccSAndroid Build Coastguard Worker long long total, available;
517*77c1e3ccSAndroid Build Coastguard Worker
518*77c1e3ccSAndroid Build Coastguard Worker long status = pReader->Length(&total, &available);
519*77c1e3ccSAndroid Build Coastguard Worker
520*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
521*77c1e3ccSAndroid Build Coastguard Worker return status;
522*77c1e3ccSAndroid Build Coastguard Worker
523*77c1e3ccSAndroid Build Coastguard Worker pos = 0;
524*77c1e3ccSAndroid Build Coastguard Worker
525*77c1e3ccSAndroid Build Coastguard Worker // Scan until we find what looks like the first byte of the EBML header.
526*77c1e3ccSAndroid Build Coastguard Worker const long long kMaxScanBytes = (available >= 1024) ? 1024 : available;
527*77c1e3ccSAndroid Build Coastguard Worker const unsigned char kEbmlByte0 = 0x1A;
528*77c1e3ccSAndroid Build Coastguard Worker unsigned char scan_byte = 0;
529*77c1e3ccSAndroid Build Coastguard Worker
530*77c1e3ccSAndroid Build Coastguard Worker while (pos < kMaxScanBytes) {
531*77c1e3ccSAndroid Build Coastguard Worker status = pReader->Read(pos, 1, &scan_byte);
532*77c1e3ccSAndroid Build Coastguard Worker
533*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
534*77c1e3ccSAndroid Build Coastguard Worker return status;
535*77c1e3ccSAndroid Build Coastguard Worker else if (status > 0)
536*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
537*77c1e3ccSAndroid Build Coastguard Worker
538*77c1e3ccSAndroid Build Coastguard Worker if (scan_byte == kEbmlByte0)
539*77c1e3ccSAndroid Build Coastguard Worker break;
540*77c1e3ccSAndroid Build Coastguard Worker
541*77c1e3ccSAndroid Build Coastguard Worker ++pos;
542*77c1e3ccSAndroid Build Coastguard Worker }
543*77c1e3ccSAndroid Build Coastguard Worker
544*77c1e3ccSAndroid Build Coastguard Worker long len = 0;
545*77c1e3ccSAndroid Build Coastguard Worker const long long ebml_id = ReadID(pReader, pos, len);
546*77c1e3ccSAndroid Build Coastguard Worker
547*77c1e3ccSAndroid Build Coastguard Worker if (ebml_id == E_BUFFER_NOT_FULL)
548*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
549*77c1e3ccSAndroid Build Coastguard Worker
550*77c1e3ccSAndroid Build Coastguard Worker if (len != 4 || ebml_id != libwebm::kMkvEBML)
551*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
552*77c1e3ccSAndroid Build Coastguard Worker
553*77c1e3ccSAndroid Build Coastguard Worker // Move read pos forward to the EBML header size field.
554*77c1e3ccSAndroid Build Coastguard Worker pos += 4;
555*77c1e3ccSAndroid Build Coastguard Worker
556*77c1e3ccSAndroid Build Coastguard Worker // Read length of size field.
557*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(pReader, pos, len);
558*77c1e3ccSAndroid Build Coastguard Worker
559*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
560*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
561*77c1e3ccSAndroid Build Coastguard Worker else if (result > 0) // need more data
562*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
563*77c1e3ccSAndroid Build Coastguard Worker
564*77c1e3ccSAndroid Build Coastguard Worker if (len < 1 || len > 8)
565*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
566*77c1e3ccSAndroid Build Coastguard Worker
567*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && ((total - pos) < len))
568*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
569*77c1e3ccSAndroid Build Coastguard Worker
570*77c1e3ccSAndroid Build Coastguard Worker if ((available - pos) < len)
571*77c1e3ccSAndroid Build Coastguard Worker return pos + len; // try again later
572*77c1e3ccSAndroid Build Coastguard Worker
573*77c1e3ccSAndroid Build Coastguard Worker // Read the EBML header size.
574*77c1e3ccSAndroid Build Coastguard Worker result = ReadUInt(pReader, pos, len);
575*77c1e3ccSAndroid Build Coastguard Worker
576*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
577*77c1e3ccSAndroid Build Coastguard Worker return result;
578*77c1e3ccSAndroid Build Coastguard Worker
579*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size field
580*77c1e3ccSAndroid Build Coastguard Worker
581*77c1e3ccSAndroid Build Coastguard Worker // pos now designates start of payload
582*77c1e3ccSAndroid Build Coastguard Worker
583*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && ((total - pos) < result))
584*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
585*77c1e3ccSAndroid Build Coastguard Worker
586*77c1e3ccSAndroid Build Coastguard Worker if ((available - pos) < result)
587*77c1e3ccSAndroid Build Coastguard Worker return pos + result;
588*77c1e3ccSAndroid Build Coastguard Worker
589*77c1e3ccSAndroid Build Coastguard Worker const long long end = pos + result;
590*77c1e3ccSAndroid Build Coastguard Worker
591*77c1e3ccSAndroid Build Coastguard Worker Init();
592*77c1e3ccSAndroid Build Coastguard Worker
593*77c1e3ccSAndroid Build Coastguard Worker while (pos < end) {
594*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
595*77c1e3ccSAndroid Build Coastguard Worker
596*77c1e3ccSAndroid Build Coastguard Worker status = ParseElementHeader(pReader, pos, end, id, size);
597*77c1e3ccSAndroid Build Coastguard Worker
598*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
599*77c1e3ccSAndroid Build Coastguard Worker return status;
600*77c1e3ccSAndroid Build Coastguard Worker
601*77c1e3ccSAndroid Build Coastguard Worker if (size == 0)
602*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
603*77c1e3ccSAndroid Build Coastguard Worker
604*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvEBMLVersion) {
605*77c1e3ccSAndroid Build Coastguard Worker m_version = UnserializeUInt(pReader, pos, size);
606*77c1e3ccSAndroid Build Coastguard Worker
607*77c1e3ccSAndroid Build Coastguard Worker if (m_version <= 0)
608*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
609*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvEBMLReadVersion) {
610*77c1e3ccSAndroid Build Coastguard Worker m_readVersion = UnserializeUInt(pReader, pos, size);
611*77c1e3ccSAndroid Build Coastguard Worker
612*77c1e3ccSAndroid Build Coastguard Worker if (m_readVersion <= 0)
613*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
614*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvEBMLMaxIDLength) {
615*77c1e3ccSAndroid Build Coastguard Worker m_maxIdLength = UnserializeUInt(pReader, pos, size);
616*77c1e3ccSAndroid Build Coastguard Worker
617*77c1e3ccSAndroid Build Coastguard Worker if (m_maxIdLength <= 0)
618*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
619*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvEBMLMaxSizeLength) {
620*77c1e3ccSAndroid Build Coastguard Worker m_maxSizeLength = UnserializeUInt(pReader, pos, size);
621*77c1e3ccSAndroid Build Coastguard Worker
622*77c1e3ccSAndroid Build Coastguard Worker if (m_maxSizeLength <= 0)
623*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
624*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvDocType) {
625*77c1e3ccSAndroid Build Coastguard Worker if (m_docType)
626*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
627*77c1e3ccSAndroid Build Coastguard Worker
628*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeString(pReader, pos, size, m_docType);
629*77c1e3ccSAndroid Build Coastguard Worker
630*77c1e3ccSAndroid Build Coastguard Worker if (status) // error
631*77c1e3ccSAndroid Build Coastguard Worker return status;
632*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvDocTypeVersion) {
633*77c1e3ccSAndroid Build Coastguard Worker m_docTypeVersion = UnserializeUInt(pReader, pos, size);
634*77c1e3ccSAndroid Build Coastguard Worker
635*77c1e3ccSAndroid Build Coastguard Worker if (m_docTypeVersion <= 0)
636*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
637*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvDocTypeReadVersion) {
638*77c1e3ccSAndroid Build Coastguard Worker m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
639*77c1e3ccSAndroid Build Coastguard Worker
640*77c1e3ccSAndroid Build Coastguard Worker if (m_docTypeReadVersion <= 0)
641*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
642*77c1e3ccSAndroid Build Coastguard Worker }
643*77c1e3ccSAndroid Build Coastguard Worker
644*77c1e3ccSAndroid Build Coastguard Worker pos += size;
645*77c1e3ccSAndroid Build Coastguard Worker }
646*77c1e3ccSAndroid Build Coastguard Worker
647*77c1e3ccSAndroid Build Coastguard Worker if (pos != end)
648*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
649*77c1e3ccSAndroid Build Coastguard Worker
650*77c1e3ccSAndroid Build Coastguard Worker // Make sure DocType, DocTypeReadVersion, and DocTypeVersion are valid.
651*77c1e3ccSAndroid Build Coastguard Worker if (m_docType == NULL || m_docTypeReadVersion <= 0 || m_docTypeVersion <= 0)
652*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
653*77c1e3ccSAndroid Build Coastguard Worker
654*77c1e3ccSAndroid Build Coastguard Worker // Make sure EBMLMaxIDLength and EBMLMaxSizeLength are valid.
655*77c1e3ccSAndroid Build Coastguard Worker if (m_maxIdLength <= 0 || m_maxIdLength > 4 || m_maxSizeLength <= 0 ||
656*77c1e3ccSAndroid Build Coastguard Worker m_maxSizeLength > 8)
657*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
658*77c1e3ccSAndroid Build Coastguard Worker
659*77c1e3ccSAndroid Build Coastguard Worker return 0;
660*77c1e3ccSAndroid Build Coastguard Worker }
661*77c1e3ccSAndroid Build Coastguard Worker
Segment(IMkvReader * pReader,long long elem_start,long long start,long long size)662*77c1e3ccSAndroid Build Coastguard Worker Segment::Segment(IMkvReader* pReader, long long elem_start,
663*77c1e3ccSAndroid Build Coastguard Worker // long long elem_size,
664*77c1e3ccSAndroid Build Coastguard Worker long long start, long long size)
665*77c1e3ccSAndroid Build Coastguard Worker : m_pReader(pReader),
666*77c1e3ccSAndroid Build Coastguard Worker m_element_start(elem_start),
667*77c1e3ccSAndroid Build Coastguard Worker // m_element_size(elem_size),
668*77c1e3ccSAndroid Build Coastguard Worker m_start(start),
669*77c1e3ccSAndroid Build Coastguard Worker m_size(size),
670*77c1e3ccSAndroid Build Coastguard Worker m_pos(start),
671*77c1e3ccSAndroid Build Coastguard Worker m_pUnknownSize(0),
672*77c1e3ccSAndroid Build Coastguard Worker m_pSeekHead(NULL),
673*77c1e3ccSAndroid Build Coastguard Worker m_pInfo(NULL),
674*77c1e3ccSAndroid Build Coastguard Worker m_pTracks(NULL),
675*77c1e3ccSAndroid Build Coastguard Worker m_pCues(NULL),
676*77c1e3ccSAndroid Build Coastguard Worker m_pChapters(NULL),
677*77c1e3ccSAndroid Build Coastguard Worker m_pTags(NULL),
678*77c1e3ccSAndroid Build Coastguard Worker m_clusters(NULL),
679*77c1e3ccSAndroid Build Coastguard Worker m_clusterCount(0),
680*77c1e3ccSAndroid Build Coastguard Worker m_clusterPreloadCount(0),
681*77c1e3ccSAndroid Build Coastguard Worker m_clusterSize(0) {}
682*77c1e3ccSAndroid Build Coastguard Worker
~Segment()683*77c1e3ccSAndroid Build Coastguard Worker Segment::~Segment() {
684*77c1e3ccSAndroid Build Coastguard Worker const long count = m_clusterCount + m_clusterPreloadCount;
685*77c1e3ccSAndroid Build Coastguard Worker
686*77c1e3ccSAndroid Build Coastguard Worker Cluster** i = m_clusters;
687*77c1e3ccSAndroid Build Coastguard Worker Cluster** j = m_clusters + count;
688*77c1e3ccSAndroid Build Coastguard Worker
689*77c1e3ccSAndroid Build Coastguard Worker while (i != j) {
690*77c1e3ccSAndroid Build Coastguard Worker Cluster* const p = *i++;
691*77c1e3ccSAndroid Build Coastguard Worker delete p;
692*77c1e3ccSAndroid Build Coastguard Worker }
693*77c1e3ccSAndroid Build Coastguard Worker
694*77c1e3ccSAndroid Build Coastguard Worker delete[] m_clusters;
695*77c1e3ccSAndroid Build Coastguard Worker
696*77c1e3ccSAndroid Build Coastguard Worker delete m_pTracks;
697*77c1e3ccSAndroid Build Coastguard Worker delete m_pInfo;
698*77c1e3ccSAndroid Build Coastguard Worker delete m_pCues;
699*77c1e3ccSAndroid Build Coastguard Worker delete m_pChapters;
700*77c1e3ccSAndroid Build Coastguard Worker delete m_pTags;
701*77c1e3ccSAndroid Build Coastguard Worker delete m_pSeekHead;
702*77c1e3ccSAndroid Build Coastguard Worker }
703*77c1e3ccSAndroid Build Coastguard Worker
CreateInstance(IMkvReader * pReader,long long pos,Segment * & pSegment)704*77c1e3ccSAndroid Build Coastguard Worker long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
705*77c1e3ccSAndroid Build Coastguard Worker Segment*& pSegment) {
706*77c1e3ccSAndroid Build Coastguard Worker if (pReader == NULL || pos < 0)
707*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
708*77c1e3ccSAndroid Build Coastguard Worker
709*77c1e3ccSAndroid Build Coastguard Worker pSegment = NULL;
710*77c1e3ccSAndroid Build Coastguard Worker
711*77c1e3ccSAndroid Build Coastguard Worker long long total, available;
712*77c1e3ccSAndroid Build Coastguard Worker
713*77c1e3ccSAndroid Build Coastguard Worker const long status = pReader->Length(&total, &available);
714*77c1e3ccSAndroid Build Coastguard Worker
715*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
716*77c1e3ccSAndroid Build Coastguard Worker return status;
717*77c1e3ccSAndroid Build Coastguard Worker
718*77c1e3ccSAndroid Build Coastguard Worker if (available < 0)
719*77c1e3ccSAndroid Build Coastguard Worker return -1;
720*77c1e3ccSAndroid Build Coastguard Worker
721*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (available > total))
722*77c1e3ccSAndroid Build Coastguard Worker return -1;
723*77c1e3ccSAndroid Build Coastguard Worker
724*77c1e3ccSAndroid Build Coastguard Worker // I would assume that in practice this loop would execute
725*77c1e3ccSAndroid Build Coastguard Worker // exactly once, but we allow for other elements (e.g. Void)
726*77c1e3ccSAndroid Build Coastguard Worker // to immediately follow the EBML header. This is fine for
727*77c1e3ccSAndroid Build Coastguard Worker // the source filter case (since the entire file is available),
728*77c1e3ccSAndroid Build Coastguard Worker // but in the splitter case over a network we should probably
729*77c1e3ccSAndroid Build Coastguard Worker // just give up early. We could for example decide only to
730*77c1e3ccSAndroid Build Coastguard Worker // execute this loop a maximum of, say, 10 times.
731*77c1e3ccSAndroid Build Coastguard Worker // TODO:
732*77c1e3ccSAndroid Build Coastguard Worker // There is an implied "give up early" by only parsing up
733*77c1e3ccSAndroid Build Coastguard Worker // to the available limit. We do do that, but only if the
734*77c1e3ccSAndroid Build Coastguard Worker // total file size is unknown. We could decide to always
735*77c1e3ccSAndroid Build Coastguard Worker // use what's available as our limit (irrespective of whether
736*77c1e3ccSAndroid Build Coastguard Worker // we happen to know the total file length). This would have
737*77c1e3ccSAndroid Build Coastguard Worker // as its sense "parse this much of the file before giving up",
738*77c1e3ccSAndroid Build Coastguard Worker // which a slightly different sense from "try to parse up to
739*77c1e3ccSAndroid Build Coastguard Worker // 10 EMBL elements before giving up".
740*77c1e3ccSAndroid Build Coastguard Worker
741*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
742*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (pos >= total))
743*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
744*77c1e3ccSAndroid Build Coastguard Worker
745*77c1e3ccSAndroid Build Coastguard Worker // Read ID
746*77c1e3ccSAndroid Build Coastguard Worker long len;
747*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(pReader, pos, len);
748*77c1e3ccSAndroid Build Coastguard Worker
749*77c1e3ccSAndroid Build Coastguard Worker if (result) // error, or too few available bytes
750*77c1e3ccSAndroid Build Coastguard Worker return result;
751*77c1e3ccSAndroid Build Coastguard Worker
752*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && ((pos + len) > total))
753*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
754*77c1e3ccSAndroid Build Coastguard Worker
755*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > available)
756*77c1e3ccSAndroid Build Coastguard Worker return pos + len;
757*77c1e3ccSAndroid Build Coastguard Worker
758*77c1e3ccSAndroid Build Coastguard Worker const long long idpos = pos;
759*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
760*77c1e3ccSAndroid Build Coastguard Worker
761*77c1e3ccSAndroid Build Coastguard Worker if (id < 0)
762*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
763*77c1e3ccSAndroid Build Coastguard Worker
764*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
765*77c1e3ccSAndroid Build Coastguard Worker
766*77c1e3ccSAndroid Build Coastguard Worker // Read Size
767*77c1e3ccSAndroid Build Coastguard Worker
768*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(pReader, pos, len);
769*77c1e3ccSAndroid Build Coastguard Worker
770*77c1e3ccSAndroid Build Coastguard Worker if (result) // error, or too few available bytes
771*77c1e3ccSAndroid Build Coastguard Worker return result;
772*77c1e3ccSAndroid Build Coastguard Worker
773*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && ((pos + len) > total))
774*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
775*77c1e3ccSAndroid Build Coastguard Worker
776*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > available)
777*77c1e3ccSAndroid Build Coastguard Worker return pos + len;
778*77c1e3ccSAndroid Build Coastguard Worker
779*77c1e3ccSAndroid Build Coastguard Worker long long size = ReadUInt(pReader, pos, len);
780*77c1e3ccSAndroid Build Coastguard Worker
781*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
782*77c1e3ccSAndroid Build Coastguard Worker return size;
783*77c1e3ccSAndroid Build Coastguard Worker
784*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of element
785*77c1e3ccSAndroid Build Coastguard Worker
786*77c1e3ccSAndroid Build Coastguard Worker // Pos now points to start of payload
787*77c1e3ccSAndroid Build Coastguard Worker
788*77c1e3ccSAndroid Build Coastguard Worker // Handle "unknown size" for live streaming of webm files.
789*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
790*77c1e3ccSAndroid Build Coastguard Worker
791*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvSegment) {
792*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size)
793*77c1e3ccSAndroid Build Coastguard Worker size = -1;
794*77c1e3ccSAndroid Build Coastguard Worker
795*77c1e3ccSAndroid Build Coastguard Worker else if (total < 0)
796*77c1e3ccSAndroid Build Coastguard Worker size = -1;
797*77c1e3ccSAndroid Build Coastguard Worker
798*77c1e3ccSAndroid Build Coastguard Worker else if ((pos + size) > total)
799*77c1e3ccSAndroid Build Coastguard Worker size = -1;
800*77c1e3ccSAndroid Build Coastguard Worker
801*77c1e3ccSAndroid Build Coastguard Worker pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size);
802*77c1e3ccSAndroid Build Coastguard Worker if (pSegment == NULL)
803*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
804*77c1e3ccSAndroid Build Coastguard Worker
805*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
806*77c1e3ccSAndroid Build Coastguard Worker }
807*77c1e3ccSAndroid Build Coastguard Worker
808*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size)
809*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
810*77c1e3ccSAndroid Build Coastguard Worker
811*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && ((pos + size) > total))
812*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
813*77c1e3ccSAndroid Build Coastguard Worker
814*77c1e3ccSAndroid Build Coastguard Worker if ((pos + size) > available)
815*77c1e3ccSAndroid Build Coastguard Worker return pos + size;
816*77c1e3ccSAndroid Build Coastguard Worker
817*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
818*77c1e3ccSAndroid Build Coastguard Worker }
819*77c1e3ccSAndroid Build Coastguard Worker }
820*77c1e3ccSAndroid Build Coastguard Worker
ParseHeaders()821*77c1e3ccSAndroid Build Coastguard Worker long long Segment::ParseHeaders() {
822*77c1e3ccSAndroid Build Coastguard Worker // Outermost (level 0) segment object has been constructed,
823*77c1e3ccSAndroid Build Coastguard Worker // and pos designates start of payload. We need to find the
824*77c1e3ccSAndroid Build Coastguard Worker // inner (level 1) elements.
825*77c1e3ccSAndroid Build Coastguard Worker long long total, available;
826*77c1e3ccSAndroid Build Coastguard Worker
827*77c1e3ccSAndroid Build Coastguard Worker const int status = m_pReader->Length(&total, &available);
828*77c1e3ccSAndroid Build Coastguard Worker
829*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
830*77c1e3ccSAndroid Build Coastguard Worker return status;
831*77c1e3ccSAndroid Build Coastguard Worker
832*77c1e3ccSAndroid Build Coastguard Worker if (total > 0 && available > total)
833*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
834*77c1e3ccSAndroid Build Coastguard Worker
835*77c1e3ccSAndroid Build Coastguard Worker const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
836*77c1e3ccSAndroid Build Coastguard Worker
837*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0 && total >= 0 && segment_stop > total) ||
838*77c1e3ccSAndroid Build Coastguard Worker (segment_stop >= 0 && m_pos > segment_stop)) {
839*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
840*77c1e3ccSAndroid Build Coastguard Worker }
841*77c1e3ccSAndroid Build Coastguard Worker
842*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
843*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (m_pos >= total))
844*77c1e3ccSAndroid Build Coastguard Worker break;
845*77c1e3ccSAndroid Build Coastguard Worker
846*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && (m_pos >= segment_stop))
847*77c1e3ccSAndroid Build Coastguard Worker break;
848*77c1e3ccSAndroid Build Coastguard Worker
849*77c1e3ccSAndroid Build Coastguard Worker long long pos = m_pos;
850*77c1e3ccSAndroid Build Coastguard Worker const long long element_start = pos;
851*77c1e3ccSAndroid Build Coastguard Worker
852*77c1e3ccSAndroid Build Coastguard Worker // Avoid rolling over pos when very close to LLONG_MAX.
853*77c1e3ccSAndroid Build Coastguard Worker unsigned long long rollover_check = pos + 1ULL;
854*77c1e3ccSAndroid Build Coastguard Worker if (rollover_check > LLONG_MAX)
855*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
856*77c1e3ccSAndroid Build Coastguard Worker
857*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > available)
858*77c1e3ccSAndroid Build Coastguard Worker return (pos + 1);
859*77c1e3ccSAndroid Build Coastguard Worker
860*77c1e3ccSAndroid Build Coastguard Worker long len;
861*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(m_pReader, pos, len);
862*77c1e3ccSAndroid Build Coastguard Worker
863*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
864*77c1e3ccSAndroid Build Coastguard Worker return result;
865*77c1e3ccSAndroid Build Coastguard Worker
866*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) {
867*77c1e3ccSAndroid Build Coastguard Worker // MkvReader doesn't have enough data to satisfy this read attempt.
868*77c1e3ccSAndroid Build Coastguard Worker return (pos + 1);
869*77c1e3ccSAndroid Build Coastguard Worker }
870*77c1e3ccSAndroid Build Coastguard Worker
871*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
872*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
873*77c1e3ccSAndroid Build Coastguard Worker
874*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > available)
875*77c1e3ccSAndroid Build Coastguard Worker return pos + len;
876*77c1e3ccSAndroid Build Coastguard Worker
877*77c1e3ccSAndroid Build Coastguard Worker const long long idpos = pos;
878*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(m_pReader, idpos, len);
879*77c1e3ccSAndroid Build Coastguard Worker
880*77c1e3ccSAndroid Build Coastguard Worker if (id < 0)
881*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
882*77c1e3ccSAndroid Build Coastguard Worker
883*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCluster)
884*77c1e3ccSAndroid Build Coastguard Worker break;
885*77c1e3ccSAndroid Build Coastguard Worker
886*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
887*77c1e3ccSAndroid Build Coastguard Worker
888*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > available)
889*77c1e3ccSAndroid Build Coastguard Worker return (pos + 1);
890*77c1e3ccSAndroid Build Coastguard Worker
891*77c1e3ccSAndroid Build Coastguard Worker // Read Size
892*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(m_pReader, pos, len);
893*77c1e3ccSAndroid Build Coastguard Worker
894*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
895*77c1e3ccSAndroid Build Coastguard Worker return result;
896*77c1e3ccSAndroid Build Coastguard Worker
897*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) {
898*77c1e3ccSAndroid Build Coastguard Worker // MkvReader doesn't have enough data to satisfy this read attempt.
899*77c1e3ccSAndroid Build Coastguard Worker return (pos + 1);
900*77c1e3ccSAndroid Build Coastguard Worker }
901*77c1e3ccSAndroid Build Coastguard Worker
902*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
903*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
904*77c1e3ccSAndroid Build Coastguard Worker
905*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > available)
906*77c1e3ccSAndroid Build Coastguard Worker return pos + len;
907*77c1e3ccSAndroid Build Coastguard Worker
908*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(m_pReader, pos, len);
909*77c1e3ccSAndroid Build Coastguard Worker
910*77c1e3ccSAndroid Build Coastguard Worker if (size < 0 || len < 1 || len > 8) {
911*77c1e3ccSAndroid Build Coastguard Worker // TODO(tomfinegan): ReadUInt should return an error when len is < 1 or
912*77c1e3ccSAndroid Build Coastguard Worker // len > 8 is true instead of checking this _everywhere_.
913*77c1e3ccSAndroid Build Coastguard Worker return size;
914*77c1e3ccSAndroid Build Coastguard Worker }
915*77c1e3ccSAndroid Build Coastguard Worker
916*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of element
917*77c1e3ccSAndroid Build Coastguard Worker
918*77c1e3ccSAndroid Build Coastguard Worker // Avoid rolling over pos when very close to LLONG_MAX.
919*77c1e3ccSAndroid Build Coastguard Worker rollover_check = static_cast<unsigned long long>(pos) + size;
920*77c1e3ccSAndroid Build Coastguard Worker if (rollover_check > LLONG_MAX)
921*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
922*77c1e3ccSAndroid Build Coastguard Worker
923*77c1e3ccSAndroid Build Coastguard Worker const long long element_size = size + pos - element_start;
924*77c1e3ccSAndroid Build Coastguard Worker
925*77c1e3ccSAndroid Build Coastguard Worker // Pos now points to start of payload
926*77c1e3ccSAndroid Build Coastguard Worker
927*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + size) > segment_stop))
928*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
929*77c1e3ccSAndroid Build Coastguard Worker
930*77c1e3ccSAndroid Build Coastguard Worker // We read EBML elements either in total or nothing at all.
931*77c1e3ccSAndroid Build Coastguard Worker
932*77c1e3ccSAndroid Build Coastguard Worker if ((pos + size) > available)
933*77c1e3ccSAndroid Build Coastguard Worker return pos + size;
934*77c1e3ccSAndroid Build Coastguard Worker
935*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvInfo) {
936*77c1e3ccSAndroid Build Coastguard Worker if (m_pInfo)
937*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
938*77c1e3ccSAndroid Build Coastguard Worker
939*77c1e3ccSAndroid Build Coastguard Worker m_pInfo = new (std::nothrow)
940*77c1e3ccSAndroid Build Coastguard Worker SegmentInfo(this, pos, size, element_start, element_size);
941*77c1e3ccSAndroid Build Coastguard Worker
942*77c1e3ccSAndroid Build Coastguard Worker if (m_pInfo == NULL)
943*77c1e3ccSAndroid Build Coastguard Worker return -1;
944*77c1e3ccSAndroid Build Coastguard Worker
945*77c1e3ccSAndroid Build Coastguard Worker const long status = m_pInfo->Parse();
946*77c1e3ccSAndroid Build Coastguard Worker
947*77c1e3ccSAndroid Build Coastguard Worker if (status)
948*77c1e3ccSAndroid Build Coastguard Worker return status;
949*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvTracks) {
950*77c1e3ccSAndroid Build Coastguard Worker if (m_pTracks)
951*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
952*77c1e3ccSAndroid Build Coastguard Worker
953*77c1e3ccSAndroid Build Coastguard Worker m_pTracks = new (std::nothrow)
954*77c1e3ccSAndroid Build Coastguard Worker Tracks(this, pos, size, element_start, element_size);
955*77c1e3ccSAndroid Build Coastguard Worker
956*77c1e3ccSAndroid Build Coastguard Worker if (m_pTracks == NULL)
957*77c1e3ccSAndroid Build Coastguard Worker return -1;
958*77c1e3ccSAndroid Build Coastguard Worker
959*77c1e3ccSAndroid Build Coastguard Worker const long status = m_pTracks->Parse();
960*77c1e3ccSAndroid Build Coastguard Worker
961*77c1e3ccSAndroid Build Coastguard Worker if (status)
962*77c1e3ccSAndroid Build Coastguard Worker return status;
963*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvCues) {
964*77c1e3ccSAndroid Build Coastguard Worker if (m_pCues == NULL) {
965*77c1e3ccSAndroid Build Coastguard Worker m_pCues = new (std::nothrow)
966*77c1e3ccSAndroid Build Coastguard Worker Cues(this, pos, size, element_start, element_size);
967*77c1e3ccSAndroid Build Coastguard Worker
968*77c1e3ccSAndroid Build Coastguard Worker if (m_pCues == NULL)
969*77c1e3ccSAndroid Build Coastguard Worker return -1;
970*77c1e3ccSAndroid Build Coastguard Worker }
971*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvSeekHead) {
972*77c1e3ccSAndroid Build Coastguard Worker if (m_pSeekHead == NULL) {
973*77c1e3ccSAndroid Build Coastguard Worker m_pSeekHead = new (std::nothrow)
974*77c1e3ccSAndroid Build Coastguard Worker SeekHead(this, pos, size, element_start, element_size);
975*77c1e3ccSAndroid Build Coastguard Worker
976*77c1e3ccSAndroid Build Coastguard Worker if (m_pSeekHead == NULL)
977*77c1e3ccSAndroid Build Coastguard Worker return -1;
978*77c1e3ccSAndroid Build Coastguard Worker
979*77c1e3ccSAndroid Build Coastguard Worker const long status = m_pSeekHead->Parse();
980*77c1e3ccSAndroid Build Coastguard Worker
981*77c1e3ccSAndroid Build Coastguard Worker if (status)
982*77c1e3ccSAndroid Build Coastguard Worker return status;
983*77c1e3ccSAndroid Build Coastguard Worker }
984*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvChapters) {
985*77c1e3ccSAndroid Build Coastguard Worker if (m_pChapters == NULL) {
986*77c1e3ccSAndroid Build Coastguard Worker m_pChapters = new (std::nothrow)
987*77c1e3ccSAndroid Build Coastguard Worker Chapters(this, pos, size, element_start, element_size);
988*77c1e3ccSAndroid Build Coastguard Worker
989*77c1e3ccSAndroid Build Coastguard Worker if (m_pChapters == NULL)
990*77c1e3ccSAndroid Build Coastguard Worker return -1;
991*77c1e3ccSAndroid Build Coastguard Worker
992*77c1e3ccSAndroid Build Coastguard Worker const long status = m_pChapters->Parse();
993*77c1e3ccSAndroid Build Coastguard Worker
994*77c1e3ccSAndroid Build Coastguard Worker if (status)
995*77c1e3ccSAndroid Build Coastguard Worker return status;
996*77c1e3ccSAndroid Build Coastguard Worker }
997*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvTags) {
998*77c1e3ccSAndroid Build Coastguard Worker if (m_pTags == NULL) {
999*77c1e3ccSAndroid Build Coastguard Worker m_pTags = new (std::nothrow)
1000*77c1e3ccSAndroid Build Coastguard Worker Tags(this, pos, size, element_start, element_size);
1001*77c1e3ccSAndroid Build Coastguard Worker
1002*77c1e3ccSAndroid Build Coastguard Worker if (m_pTags == NULL)
1003*77c1e3ccSAndroid Build Coastguard Worker return -1;
1004*77c1e3ccSAndroid Build Coastguard Worker
1005*77c1e3ccSAndroid Build Coastguard Worker const long status = m_pTags->Parse();
1006*77c1e3ccSAndroid Build Coastguard Worker
1007*77c1e3ccSAndroid Build Coastguard Worker if (status)
1008*77c1e3ccSAndroid Build Coastguard Worker return status;
1009*77c1e3ccSAndroid Build Coastguard Worker }
1010*77c1e3ccSAndroid Build Coastguard Worker }
1011*77c1e3ccSAndroid Build Coastguard Worker
1012*77c1e3ccSAndroid Build Coastguard Worker m_pos = pos + size; // consume payload
1013*77c1e3ccSAndroid Build Coastguard Worker }
1014*77c1e3ccSAndroid Build Coastguard Worker
1015*77c1e3ccSAndroid Build Coastguard Worker if (segment_stop >= 0 && m_pos > segment_stop)
1016*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1017*77c1e3ccSAndroid Build Coastguard Worker
1018*77c1e3ccSAndroid Build Coastguard Worker if (m_pInfo == NULL) // TODO: liberalize this behavior
1019*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1020*77c1e3ccSAndroid Build Coastguard Worker
1021*77c1e3ccSAndroid Build Coastguard Worker if (m_pTracks == NULL)
1022*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1023*77c1e3ccSAndroid Build Coastguard Worker
1024*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
1025*77c1e3ccSAndroid Build Coastguard Worker }
1026*77c1e3ccSAndroid Build Coastguard Worker
LoadCluster(long long & pos,long & len)1027*77c1e3ccSAndroid Build Coastguard Worker long Segment::LoadCluster(long long& pos, long& len) {
1028*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
1029*77c1e3ccSAndroid Build Coastguard Worker const long result = DoLoadCluster(pos, len);
1030*77c1e3ccSAndroid Build Coastguard Worker
1031*77c1e3ccSAndroid Build Coastguard Worker if (result <= 1)
1032*77c1e3ccSAndroid Build Coastguard Worker return result;
1033*77c1e3ccSAndroid Build Coastguard Worker }
1034*77c1e3ccSAndroid Build Coastguard Worker }
1035*77c1e3ccSAndroid Build Coastguard Worker
DoLoadCluster(long long & pos,long & len)1036*77c1e3ccSAndroid Build Coastguard Worker long Segment::DoLoadCluster(long long& pos, long& len) {
1037*77c1e3ccSAndroid Build Coastguard Worker if (m_pos < 0)
1038*77c1e3ccSAndroid Build Coastguard Worker return DoLoadClusterUnknownSize(pos, len);
1039*77c1e3ccSAndroid Build Coastguard Worker
1040*77c1e3ccSAndroid Build Coastguard Worker long long total, avail;
1041*77c1e3ccSAndroid Build Coastguard Worker
1042*77c1e3ccSAndroid Build Coastguard Worker long status = m_pReader->Length(&total, &avail);
1043*77c1e3ccSAndroid Build Coastguard Worker
1044*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
1045*77c1e3ccSAndroid Build Coastguard Worker return status;
1046*77c1e3ccSAndroid Build Coastguard Worker
1047*77c1e3ccSAndroid Build Coastguard Worker if (total >= 0 && avail > total)
1048*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1049*77c1e3ccSAndroid Build Coastguard Worker
1050*77c1e3ccSAndroid Build Coastguard Worker const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1051*77c1e3ccSAndroid Build Coastguard Worker
1052*77c1e3ccSAndroid Build Coastguard Worker long long cluster_off = -1; // offset relative to start of segment
1053*77c1e3ccSAndroid Build Coastguard Worker long long cluster_size = -1; // size of cluster payload
1054*77c1e3ccSAndroid Build Coastguard Worker
1055*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
1056*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (m_pos >= total))
1057*77c1e3ccSAndroid Build Coastguard Worker return 1; // no more clusters
1058*77c1e3ccSAndroid Build Coastguard Worker
1059*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && (m_pos >= segment_stop))
1060*77c1e3ccSAndroid Build Coastguard Worker return 1; // no more clusters
1061*77c1e3ccSAndroid Build Coastguard Worker
1062*77c1e3ccSAndroid Build Coastguard Worker pos = m_pos;
1063*77c1e3ccSAndroid Build Coastguard Worker
1064*77c1e3ccSAndroid Build Coastguard Worker // Read ID
1065*77c1e3ccSAndroid Build Coastguard Worker
1066*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
1067*77c1e3ccSAndroid Build Coastguard Worker len = 1;
1068*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1069*77c1e3ccSAndroid Build Coastguard Worker }
1070*77c1e3ccSAndroid Build Coastguard Worker
1071*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(m_pReader, pos, len);
1072*77c1e3ccSAndroid Build Coastguard Worker
1073*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
1074*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
1075*77c1e3ccSAndroid Build Coastguard Worker
1076*77c1e3ccSAndroid Build Coastguard Worker if (result > 0)
1077*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1078*77c1e3ccSAndroid Build Coastguard Worker
1079*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1080*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1081*77c1e3ccSAndroid Build Coastguard Worker
1082*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
1083*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1084*77c1e3ccSAndroid Build Coastguard Worker
1085*77c1e3ccSAndroid Build Coastguard Worker const long long idpos = pos;
1086*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(m_pReader, idpos, len);
1087*77c1e3ccSAndroid Build Coastguard Worker
1088*77c1e3ccSAndroid Build Coastguard Worker if (id < 0)
1089*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1090*77c1e3ccSAndroid Build Coastguard Worker
1091*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
1092*77c1e3ccSAndroid Build Coastguard Worker
1093*77c1e3ccSAndroid Build Coastguard Worker // Read Size
1094*77c1e3ccSAndroid Build Coastguard Worker
1095*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
1096*77c1e3ccSAndroid Build Coastguard Worker len = 1;
1097*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1098*77c1e3ccSAndroid Build Coastguard Worker }
1099*77c1e3ccSAndroid Build Coastguard Worker
1100*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(m_pReader, pos, len);
1101*77c1e3ccSAndroid Build Coastguard Worker
1102*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
1103*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
1104*77c1e3ccSAndroid Build Coastguard Worker
1105*77c1e3ccSAndroid Build Coastguard Worker if (result > 0)
1106*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1107*77c1e3ccSAndroid Build Coastguard Worker
1108*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1109*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1110*77c1e3ccSAndroid Build Coastguard Worker
1111*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
1112*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1113*77c1e3ccSAndroid Build Coastguard Worker
1114*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(m_pReader, pos, len);
1115*77c1e3ccSAndroid Build Coastguard Worker
1116*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
1117*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(size);
1118*77c1e3ccSAndroid Build Coastguard Worker
1119*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of element
1120*77c1e3ccSAndroid Build Coastguard Worker
1121*77c1e3ccSAndroid Build Coastguard Worker // pos now points to start of payload
1122*77c1e3ccSAndroid Build Coastguard Worker
1123*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) {
1124*77c1e3ccSAndroid Build Coastguard Worker // Missing element payload: move on.
1125*77c1e3ccSAndroid Build Coastguard Worker m_pos = pos;
1126*77c1e3ccSAndroid Build Coastguard Worker continue;
1127*77c1e3ccSAndroid Build Coastguard Worker }
1128*77c1e3ccSAndroid Build Coastguard Worker
1129*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
1130*77c1e3ccSAndroid Build Coastguard Worker
1131*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && (size != unknown_size) &&
1132*77c1e3ccSAndroid Build Coastguard Worker ((pos + size) > segment_stop)) {
1133*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1134*77c1e3ccSAndroid Build Coastguard Worker }
1135*77c1e3ccSAndroid Build Coastguard Worker
1136*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCues) {
1137*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size) {
1138*77c1e3ccSAndroid Build Coastguard Worker // Cues element of unknown size: Not supported.
1139*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1140*77c1e3ccSAndroid Build Coastguard Worker }
1141*77c1e3ccSAndroid Build Coastguard Worker
1142*77c1e3ccSAndroid Build Coastguard Worker if (m_pCues == NULL) {
1143*77c1e3ccSAndroid Build Coastguard Worker const long long element_size = (pos - idpos) + size;
1144*77c1e3ccSAndroid Build Coastguard Worker
1145*77c1e3ccSAndroid Build Coastguard Worker m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size);
1146*77c1e3ccSAndroid Build Coastguard Worker if (m_pCues == NULL)
1147*77c1e3ccSAndroid Build Coastguard Worker return -1;
1148*77c1e3ccSAndroid Build Coastguard Worker }
1149*77c1e3ccSAndroid Build Coastguard Worker
1150*77c1e3ccSAndroid Build Coastguard Worker m_pos = pos + size; // consume payload
1151*77c1e3ccSAndroid Build Coastguard Worker continue;
1152*77c1e3ccSAndroid Build Coastguard Worker }
1153*77c1e3ccSAndroid Build Coastguard Worker
1154*77c1e3ccSAndroid Build Coastguard Worker if (id != libwebm::kMkvCluster) {
1155*77c1e3ccSAndroid Build Coastguard Worker // Besides the Segment, Libwebm allows only cluster elements of unknown
1156*77c1e3ccSAndroid Build Coastguard Worker // size. Fail the parse upon encountering a non-cluster element reporting
1157*77c1e3ccSAndroid Build Coastguard Worker // unknown size.
1158*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size)
1159*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1160*77c1e3ccSAndroid Build Coastguard Worker
1161*77c1e3ccSAndroid Build Coastguard Worker m_pos = pos + size; // consume payload
1162*77c1e3ccSAndroid Build Coastguard Worker continue;
1163*77c1e3ccSAndroid Build Coastguard Worker }
1164*77c1e3ccSAndroid Build Coastguard Worker
1165*77c1e3ccSAndroid Build Coastguard Worker // We have a cluster.
1166*77c1e3ccSAndroid Build Coastguard Worker
1167*77c1e3ccSAndroid Build Coastguard Worker cluster_off = idpos - m_start; // relative pos
1168*77c1e3ccSAndroid Build Coastguard Worker
1169*77c1e3ccSAndroid Build Coastguard Worker if (size != unknown_size)
1170*77c1e3ccSAndroid Build Coastguard Worker cluster_size = size;
1171*77c1e3ccSAndroid Build Coastguard Worker
1172*77c1e3ccSAndroid Build Coastguard Worker break;
1173*77c1e3ccSAndroid Build Coastguard Worker }
1174*77c1e3ccSAndroid Build Coastguard Worker
1175*77c1e3ccSAndroid Build Coastguard Worker if (cluster_off < 0) {
1176*77c1e3ccSAndroid Build Coastguard Worker // No cluster, die.
1177*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1178*77c1e3ccSAndroid Build Coastguard Worker }
1179*77c1e3ccSAndroid Build Coastguard Worker
1180*77c1e3ccSAndroid Build Coastguard Worker long long pos_;
1181*77c1e3ccSAndroid Build Coastguard Worker long len_;
1182*77c1e3ccSAndroid Build Coastguard Worker
1183*77c1e3ccSAndroid Build Coastguard Worker status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_);
1184*77c1e3ccSAndroid Build Coastguard Worker
1185*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) { // error, or underflow
1186*77c1e3ccSAndroid Build Coastguard Worker pos = pos_;
1187*77c1e3ccSAndroid Build Coastguard Worker len = len_;
1188*77c1e3ccSAndroid Build Coastguard Worker
1189*77c1e3ccSAndroid Build Coastguard Worker return status;
1190*77c1e3ccSAndroid Build Coastguard Worker }
1191*77c1e3ccSAndroid Build Coastguard Worker
1192*77c1e3ccSAndroid Build Coastguard Worker // status == 0 means "no block entries found"
1193*77c1e3ccSAndroid Build Coastguard Worker // status > 0 means "found at least one block entry"
1194*77c1e3ccSAndroid Build Coastguard Worker
1195*77c1e3ccSAndroid Build Coastguard Worker // TODO:
1196*77c1e3ccSAndroid Build Coastguard Worker // The issue here is that the segment increments its own
1197*77c1e3ccSAndroid Build Coastguard Worker // pos ptr past the most recent cluster parsed, and then
1198*77c1e3ccSAndroid Build Coastguard Worker // starts from there to parse the next cluster. If we
1199*77c1e3ccSAndroid Build Coastguard Worker // don't know the size of the current cluster, then we
1200*77c1e3ccSAndroid Build Coastguard Worker // must either parse its payload (as we do below), looking
1201*77c1e3ccSAndroid Build Coastguard Worker // for the cluster (or cues) ID to terminate the parse.
1202*77c1e3ccSAndroid Build Coastguard Worker // This isn't really what we want: rather, we really need
1203*77c1e3ccSAndroid Build Coastguard Worker // a way to create the curr cluster object immediately.
1204*77c1e3ccSAndroid Build Coastguard Worker // The pity is that cluster::parse can determine its own
1205*77c1e3ccSAndroid Build Coastguard Worker // boundary, and we largely duplicate that same logic here.
1206*77c1e3ccSAndroid Build Coastguard Worker //
1207*77c1e3ccSAndroid Build Coastguard Worker // Maybe we need to get rid of our look-ahead preloading
1208*77c1e3ccSAndroid Build Coastguard Worker // in source::parse???
1209*77c1e3ccSAndroid Build Coastguard Worker //
1210*77c1e3ccSAndroid Build Coastguard Worker // As we're parsing the blocks in the curr cluster
1211*77c1e3ccSAndroid Build Coastguard Worker //(in cluster::parse), we should have some way to signal
1212*77c1e3ccSAndroid Build Coastguard Worker // to the segment that we have determined the boundary,
1213*77c1e3ccSAndroid Build Coastguard Worker // so it can adjust its own segment::m_pos member.
1214*77c1e3ccSAndroid Build Coastguard Worker //
1215*77c1e3ccSAndroid Build Coastguard Worker // The problem is that we're asserting in asyncreadinit,
1216*77c1e3ccSAndroid Build Coastguard Worker // because we adjust the pos down to the curr seek pos,
1217*77c1e3ccSAndroid Build Coastguard Worker // and the resulting adjusted len is > 2GB. I'm suspicious
1218*77c1e3ccSAndroid Build Coastguard Worker // that this is even correct, but even if it is, we can't
1219*77c1e3ccSAndroid Build Coastguard Worker // be loading that much data in the cache anyway.
1220*77c1e3ccSAndroid Build Coastguard Worker
1221*77c1e3ccSAndroid Build Coastguard Worker const long idx = m_clusterCount;
1222*77c1e3ccSAndroid Build Coastguard Worker
1223*77c1e3ccSAndroid Build Coastguard Worker if (m_clusterPreloadCount > 0) {
1224*77c1e3ccSAndroid Build Coastguard Worker if (idx >= m_clusterSize)
1225*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1226*77c1e3ccSAndroid Build Coastguard Worker
1227*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = m_clusters[idx];
1228*77c1e3ccSAndroid Build Coastguard Worker if (pCluster == NULL || pCluster->m_index >= 0)
1229*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1230*77c1e3ccSAndroid Build Coastguard Worker
1231*77c1e3ccSAndroid Build Coastguard Worker const long long off = pCluster->GetPosition();
1232*77c1e3ccSAndroid Build Coastguard Worker if (off < 0)
1233*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1234*77c1e3ccSAndroid Build Coastguard Worker
1235*77c1e3ccSAndroid Build Coastguard Worker if (off == cluster_off) { // preloaded already
1236*77c1e3ccSAndroid Build Coastguard Worker if (status == 0) // no entries found
1237*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1238*77c1e3ccSAndroid Build Coastguard Worker
1239*77c1e3ccSAndroid Build Coastguard Worker if (cluster_size >= 0)
1240*77c1e3ccSAndroid Build Coastguard Worker pos += cluster_size;
1241*77c1e3ccSAndroid Build Coastguard Worker else {
1242*77c1e3ccSAndroid Build Coastguard Worker const long long element_size = pCluster->GetElementSize();
1243*77c1e3ccSAndroid Build Coastguard Worker
1244*77c1e3ccSAndroid Build Coastguard Worker if (element_size <= 0)
1245*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID; // TODO: handle this case
1246*77c1e3ccSAndroid Build Coastguard Worker
1247*77c1e3ccSAndroid Build Coastguard Worker pos = pCluster->m_element_start + element_size;
1248*77c1e3ccSAndroid Build Coastguard Worker }
1249*77c1e3ccSAndroid Build Coastguard Worker
1250*77c1e3ccSAndroid Build Coastguard Worker pCluster->m_index = idx; // move from preloaded to loaded
1251*77c1e3ccSAndroid Build Coastguard Worker ++m_clusterCount;
1252*77c1e3ccSAndroid Build Coastguard Worker --m_clusterPreloadCount;
1253*77c1e3ccSAndroid Build Coastguard Worker
1254*77c1e3ccSAndroid Build Coastguard Worker m_pos = pos; // consume payload
1255*77c1e3ccSAndroid Build Coastguard Worker if (segment_stop >= 0 && m_pos > segment_stop)
1256*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1257*77c1e3ccSAndroid Build Coastguard Worker
1258*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
1259*77c1e3ccSAndroid Build Coastguard Worker }
1260*77c1e3ccSAndroid Build Coastguard Worker }
1261*77c1e3ccSAndroid Build Coastguard Worker
1262*77c1e3ccSAndroid Build Coastguard Worker if (status == 0) { // no entries found
1263*77c1e3ccSAndroid Build Coastguard Worker if (cluster_size >= 0)
1264*77c1e3ccSAndroid Build Coastguard Worker pos += cluster_size;
1265*77c1e3ccSAndroid Build Coastguard Worker
1266*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (pos >= total)) {
1267*77c1e3ccSAndroid Build Coastguard Worker m_pos = total;
1268*77c1e3ccSAndroid Build Coastguard Worker return 1; // no more clusters
1269*77c1e3ccSAndroid Build Coastguard Worker }
1270*77c1e3ccSAndroid Build Coastguard Worker
1271*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && (pos >= segment_stop)) {
1272*77c1e3ccSAndroid Build Coastguard Worker m_pos = segment_stop;
1273*77c1e3ccSAndroid Build Coastguard Worker return 1; // no more clusters
1274*77c1e3ccSAndroid Build Coastguard Worker }
1275*77c1e3ccSAndroid Build Coastguard Worker
1276*77c1e3ccSAndroid Build Coastguard Worker m_pos = pos;
1277*77c1e3ccSAndroid Build Coastguard Worker return 2; // try again
1278*77c1e3ccSAndroid Build Coastguard Worker }
1279*77c1e3ccSAndroid Build Coastguard Worker
1280*77c1e3ccSAndroid Build Coastguard Worker // status > 0 means we have an entry
1281*77c1e3ccSAndroid Build Coastguard Worker
1282*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = Cluster::Create(this, idx, cluster_off);
1283*77c1e3ccSAndroid Build Coastguard Worker if (pCluster == NULL)
1284*77c1e3ccSAndroid Build Coastguard Worker return -1;
1285*77c1e3ccSAndroid Build Coastguard Worker
1286*77c1e3ccSAndroid Build Coastguard Worker if (!AppendCluster(pCluster)) {
1287*77c1e3ccSAndroid Build Coastguard Worker delete pCluster;
1288*77c1e3ccSAndroid Build Coastguard Worker return -1;
1289*77c1e3ccSAndroid Build Coastguard Worker }
1290*77c1e3ccSAndroid Build Coastguard Worker
1291*77c1e3ccSAndroid Build Coastguard Worker if (cluster_size >= 0) {
1292*77c1e3ccSAndroid Build Coastguard Worker pos += cluster_size;
1293*77c1e3ccSAndroid Build Coastguard Worker
1294*77c1e3ccSAndroid Build Coastguard Worker m_pos = pos;
1295*77c1e3ccSAndroid Build Coastguard Worker
1296*77c1e3ccSAndroid Build Coastguard Worker if (segment_stop > 0 && m_pos > segment_stop)
1297*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1298*77c1e3ccSAndroid Build Coastguard Worker
1299*77c1e3ccSAndroid Build Coastguard Worker return 0;
1300*77c1e3ccSAndroid Build Coastguard Worker }
1301*77c1e3ccSAndroid Build Coastguard Worker
1302*77c1e3ccSAndroid Build Coastguard Worker m_pUnknownSize = pCluster;
1303*77c1e3ccSAndroid Build Coastguard Worker m_pos = -pos;
1304*77c1e3ccSAndroid Build Coastguard Worker
1305*77c1e3ccSAndroid Build Coastguard Worker return 0; // partial success, since we have a new cluster
1306*77c1e3ccSAndroid Build Coastguard Worker
1307*77c1e3ccSAndroid Build Coastguard Worker // status == 0 means "no block entries found"
1308*77c1e3ccSAndroid Build Coastguard Worker // pos designates start of payload
1309*77c1e3ccSAndroid Build Coastguard Worker // m_pos has NOT been adjusted yet (in case we need to come back here)
1310*77c1e3ccSAndroid Build Coastguard Worker }
1311*77c1e3ccSAndroid Build Coastguard Worker
DoLoadClusterUnknownSize(long long & pos,long & len)1312*77c1e3ccSAndroid Build Coastguard Worker long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
1313*77c1e3ccSAndroid Build Coastguard Worker if (m_pos >= 0 || m_pUnknownSize == NULL)
1314*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
1315*77c1e3ccSAndroid Build Coastguard Worker
1316*77c1e3ccSAndroid Build Coastguard Worker const long status = m_pUnknownSize->Parse(pos, len);
1317*77c1e3ccSAndroid Build Coastguard Worker
1318*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error or underflow
1319*77c1e3ccSAndroid Build Coastguard Worker return status;
1320*77c1e3ccSAndroid Build Coastguard Worker
1321*77c1e3ccSAndroid Build Coastguard Worker if (status == 0) // parsed a block
1322*77c1e3ccSAndroid Build Coastguard Worker return 2; // continue parsing
1323*77c1e3ccSAndroid Build Coastguard Worker
1324*77c1e3ccSAndroid Build Coastguard Worker const long long start = m_pUnknownSize->m_element_start;
1325*77c1e3ccSAndroid Build Coastguard Worker const long long size = m_pUnknownSize->GetElementSize();
1326*77c1e3ccSAndroid Build Coastguard Worker
1327*77c1e3ccSAndroid Build Coastguard Worker if (size < 0)
1328*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1329*77c1e3ccSAndroid Build Coastguard Worker
1330*77c1e3ccSAndroid Build Coastguard Worker pos = start + size;
1331*77c1e3ccSAndroid Build Coastguard Worker m_pos = pos;
1332*77c1e3ccSAndroid Build Coastguard Worker
1333*77c1e3ccSAndroid Build Coastguard Worker m_pUnknownSize = 0;
1334*77c1e3ccSAndroid Build Coastguard Worker
1335*77c1e3ccSAndroid Build Coastguard Worker return 2; // continue parsing
1336*77c1e3ccSAndroid Build Coastguard Worker }
1337*77c1e3ccSAndroid Build Coastguard Worker
AppendCluster(Cluster * pCluster)1338*77c1e3ccSAndroid Build Coastguard Worker bool Segment::AppendCluster(Cluster* pCluster) {
1339*77c1e3ccSAndroid Build Coastguard Worker if (pCluster == NULL || pCluster->m_index < 0)
1340*77c1e3ccSAndroid Build Coastguard Worker return false;
1341*77c1e3ccSAndroid Build Coastguard Worker
1342*77c1e3ccSAndroid Build Coastguard Worker const long count = m_clusterCount + m_clusterPreloadCount;
1343*77c1e3ccSAndroid Build Coastguard Worker
1344*77c1e3ccSAndroid Build Coastguard Worker long& size = m_clusterSize;
1345*77c1e3ccSAndroid Build Coastguard Worker const long idx = pCluster->m_index;
1346*77c1e3ccSAndroid Build Coastguard Worker
1347*77c1e3ccSAndroid Build Coastguard Worker if (size < count || idx != m_clusterCount)
1348*77c1e3ccSAndroid Build Coastguard Worker return false;
1349*77c1e3ccSAndroid Build Coastguard Worker
1350*77c1e3ccSAndroid Build Coastguard Worker if (count >= size) {
1351*77c1e3ccSAndroid Build Coastguard Worker const long n = (size <= 0) ? 2048 : 2 * size;
1352*77c1e3ccSAndroid Build Coastguard Worker
1353*77c1e3ccSAndroid Build Coastguard Worker Cluster** const qq = new (std::nothrow) Cluster*[n];
1354*77c1e3ccSAndroid Build Coastguard Worker if (qq == NULL)
1355*77c1e3ccSAndroid Build Coastguard Worker return false;
1356*77c1e3ccSAndroid Build Coastguard Worker
1357*77c1e3ccSAndroid Build Coastguard Worker Cluster** q = qq;
1358*77c1e3ccSAndroid Build Coastguard Worker Cluster** p = m_clusters;
1359*77c1e3ccSAndroid Build Coastguard Worker Cluster** const pp = p + count;
1360*77c1e3ccSAndroid Build Coastguard Worker
1361*77c1e3ccSAndroid Build Coastguard Worker while (p != pp)
1362*77c1e3ccSAndroid Build Coastguard Worker *q++ = *p++;
1363*77c1e3ccSAndroid Build Coastguard Worker
1364*77c1e3ccSAndroid Build Coastguard Worker delete[] m_clusters;
1365*77c1e3ccSAndroid Build Coastguard Worker
1366*77c1e3ccSAndroid Build Coastguard Worker m_clusters = qq;
1367*77c1e3ccSAndroid Build Coastguard Worker size = n;
1368*77c1e3ccSAndroid Build Coastguard Worker }
1369*77c1e3ccSAndroid Build Coastguard Worker
1370*77c1e3ccSAndroid Build Coastguard Worker if (m_clusterPreloadCount > 0) {
1371*77c1e3ccSAndroid Build Coastguard Worker Cluster** const p = m_clusters + m_clusterCount;
1372*77c1e3ccSAndroid Build Coastguard Worker if (*p == NULL || (*p)->m_index >= 0)
1373*77c1e3ccSAndroid Build Coastguard Worker return false;
1374*77c1e3ccSAndroid Build Coastguard Worker
1375*77c1e3ccSAndroid Build Coastguard Worker Cluster** q = p + m_clusterPreloadCount;
1376*77c1e3ccSAndroid Build Coastguard Worker if (q >= (m_clusters + size))
1377*77c1e3ccSAndroid Build Coastguard Worker return false;
1378*77c1e3ccSAndroid Build Coastguard Worker
1379*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
1380*77c1e3ccSAndroid Build Coastguard Worker Cluster** const qq = q - 1;
1381*77c1e3ccSAndroid Build Coastguard Worker if ((*qq)->m_index >= 0)
1382*77c1e3ccSAndroid Build Coastguard Worker return false;
1383*77c1e3ccSAndroid Build Coastguard Worker
1384*77c1e3ccSAndroid Build Coastguard Worker *q = *qq;
1385*77c1e3ccSAndroid Build Coastguard Worker q = qq;
1386*77c1e3ccSAndroid Build Coastguard Worker
1387*77c1e3ccSAndroid Build Coastguard Worker if (q == p)
1388*77c1e3ccSAndroid Build Coastguard Worker break;
1389*77c1e3ccSAndroid Build Coastguard Worker }
1390*77c1e3ccSAndroid Build Coastguard Worker }
1391*77c1e3ccSAndroid Build Coastguard Worker
1392*77c1e3ccSAndroid Build Coastguard Worker m_clusters[idx] = pCluster;
1393*77c1e3ccSAndroid Build Coastguard Worker ++m_clusterCount;
1394*77c1e3ccSAndroid Build Coastguard Worker return true;
1395*77c1e3ccSAndroid Build Coastguard Worker }
1396*77c1e3ccSAndroid Build Coastguard Worker
PreloadCluster(Cluster * pCluster,ptrdiff_t idx)1397*77c1e3ccSAndroid Build Coastguard Worker bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
1398*77c1e3ccSAndroid Build Coastguard Worker if (pCluster == NULL || pCluster->m_index >= 0 || idx < m_clusterCount)
1399*77c1e3ccSAndroid Build Coastguard Worker return false;
1400*77c1e3ccSAndroid Build Coastguard Worker
1401*77c1e3ccSAndroid Build Coastguard Worker const long count = m_clusterCount + m_clusterPreloadCount;
1402*77c1e3ccSAndroid Build Coastguard Worker
1403*77c1e3ccSAndroid Build Coastguard Worker long& size = m_clusterSize;
1404*77c1e3ccSAndroid Build Coastguard Worker if (size < count)
1405*77c1e3ccSAndroid Build Coastguard Worker return false;
1406*77c1e3ccSAndroid Build Coastguard Worker
1407*77c1e3ccSAndroid Build Coastguard Worker if (count >= size) {
1408*77c1e3ccSAndroid Build Coastguard Worker const long n = (size <= 0) ? 2048 : 2 * size;
1409*77c1e3ccSAndroid Build Coastguard Worker
1410*77c1e3ccSAndroid Build Coastguard Worker Cluster** const qq = new (std::nothrow) Cluster*[n];
1411*77c1e3ccSAndroid Build Coastguard Worker if (qq == NULL)
1412*77c1e3ccSAndroid Build Coastguard Worker return false;
1413*77c1e3ccSAndroid Build Coastguard Worker Cluster** q = qq;
1414*77c1e3ccSAndroid Build Coastguard Worker
1415*77c1e3ccSAndroid Build Coastguard Worker Cluster** p = m_clusters;
1416*77c1e3ccSAndroid Build Coastguard Worker Cluster** const pp = p + count;
1417*77c1e3ccSAndroid Build Coastguard Worker
1418*77c1e3ccSAndroid Build Coastguard Worker while (p != pp)
1419*77c1e3ccSAndroid Build Coastguard Worker *q++ = *p++;
1420*77c1e3ccSAndroid Build Coastguard Worker
1421*77c1e3ccSAndroid Build Coastguard Worker delete[] m_clusters;
1422*77c1e3ccSAndroid Build Coastguard Worker
1423*77c1e3ccSAndroid Build Coastguard Worker m_clusters = qq;
1424*77c1e3ccSAndroid Build Coastguard Worker size = n;
1425*77c1e3ccSAndroid Build Coastguard Worker }
1426*77c1e3ccSAndroid Build Coastguard Worker
1427*77c1e3ccSAndroid Build Coastguard Worker if (m_clusters == NULL)
1428*77c1e3ccSAndroid Build Coastguard Worker return false;
1429*77c1e3ccSAndroid Build Coastguard Worker
1430*77c1e3ccSAndroid Build Coastguard Worker Cluster** const p = m_clusters + idx;
1431*77c1e3ccSAndroid Build Coastguard Worker
1432*77c1e3ccSAndroid Build Coastguard Worker Cluster** q = m_clusters + count;
1433*77c1e3ccSAndroid Build Coastguard Worker if (q < p || q >= (m_clusters + size))
1434*77c1e3ccSAndroid Build Coastguard Worker return false;
1435*77c1e3ccSAndroid Build Coastguard Worker
1436*77c1e3ccSAndroid Build Coastguard Worker while (q > p) {
1437*77c1e3ccSAndroid Build Coastguard Worker Cluster** const qq = q - 1;
1438*77c1e3ccSAndroid Build Coastguard Worker
1439*77c1e3ccSAndroid Build Coastguard Worker if ((*qq)->m_index >= 0)
1440*77c1e3ccSAndroid Build Coastguard Worker return false;
1441*77c1e3ccSAndroid Build Coastguard Worker
1442*77c1e3ccSAndroid Build Coastguard Worker *q = *qq;
1443*77c1e3ccSAndroid Build Coastguard Worker q = qq;
1444*77c1e3ccSAndroid Build Coastguard Worker }
1445*77c1e3ccSAndroid Build Coastguard Worker
1446*77c1e3ccSAndroid Build Coastguard Worker m_clusters[idx] = pCluster;
1447*77c1e3ccSAndroid Build Coastguard Worker ++m_clusterPreloadCount;
1448*77c1e3ccSAndroid Build Coastguard Worker return true;
1449*77c1e3ccSAndroid Build Coastguard Worker }
1450*77c1e3ccSAndroid Build Coastguard Worker
Load()1451*77c1e3ccSAndroid Build Coastguard Worker long Segment::Load() {
1452*77c1e3ccSAndroid Build Coastguard Worker if (m_clusters != NULL || m_clusterSize != 0 || m_clusterCount != 0)
1453*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
1454*77c1e3ccSAndroid Build Coastguard Worker
1455*77c1e3ccSAndroid Build Coastguard Worker // Outermost (level 0) segment object has been constructed,
1456*77c1e3ccSAndroid Build Coastguard Worker // and pos designates start of payload. We need to find the
1457*77c1e3ccSAndroid Build Coastguard Worker // inner (level 1) elements.
1458*77c1e3ccSAndroid Build Coastguard Worker
1459*77c1e3ccSAndroid Build Coastguard Worker const long long header_status = ParseHeaders();
1460*77c1e3ccSAndroid Build Coastguard Worker
1461*77c1e3ccSAndroid Build Coastguard Worker if (header_status < 0) // error
1462*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(header_status);
1463*77c1e3ccSAndroid Build Coastguard Worker
1464*77c1e3ccSAndroid Build Coastguard Worker if (header_status > 0) // underflow
1465*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1466*77c1e3ccSAndroid Build Coastguard Worker
1467*77c1e3ccSAndroid Build Coastguard Worker if (m_pInfo == NULL || m_pTracks == NULL)
1468*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1469*77c1e3ccSAndroid Build Coastguard Worker
1470*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
1471*77c1e3ccSAndroid Build Coastguard Worker const long status = LoadCluster();
1472*77c1e3ccSAndroid Build Coastguard Worker
1473*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
1474*77c1e3ccSAndroid Build Coastguard Worker return status;
1475*77c1e3ccSAndroid Build Coastguard Worker
1476*77c1e3ccSAndroid Build Coastguard Worker if (status >= 1) // no more clusters
1477*77c1e3ccSAndroid Build Coastguard Worker return 0;
1478*77c1e3ccSAndroid Build Coastguard Worker }
1479*77c1e3ccSAndroid Build Coastguard Worker }
1480*77c1e3ccSAndroid Build Coastguard Worker
Entry()1481*77c1e3ccSAndroid Build Coastguard Worker SeekHead::Entry::Entry() : id(0), pos(0), element_start(0), element_size(0) {}
1482*77c1e3ccSAndroid Build Coastguard Worker
SeekHead(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)1483*77c1e3ccSAndroid Build Coastguard Worker SeekHead::SeekHead(Segment* pSegment, long long start, long long size_,
1484*77c1e3ccSAndroid Build Coastguard Worker long long element_start, long long element_size)
1485*77c1e3ccSAndroid Build Coastguard Worker : m_pSegment(pSegment),
1486*77c1e3ccSAndroid Build Coastguard Worker m_start(start),
1487*77c1e3ccSAndroid Build Coastguard Worker m_size(size_),
1488*77c1e3ccSAndroid Build Coastguard Worker m_element_start(element_start),
1489*77c1e3ccSAndroid Build Coastguard Worker m_element_size(element_size),
1490*77c1e3ccSAndroid Build Coastguard Worker m_entries(0),
1491*77c1e3ccSAndroid Build Coastguard Worker m_entry_count(0),
1492*77c1e3ccSAndroid Build Coastguard Worker m_void_elements(0),
1493*77c1e3ccSAndroid Build Coastguard Worker m_void_element_count(0) {}
1494*77c1e3ccSAndroid Build Coastguard Worker
~SeekHead()1495*77c1e3ccSAndroid Build Coastguard Worker SeekHead::~SeekHead() {
1496*77c1e3ccSAndroid Build Coastguard Worker delete[] m_entries;
1497*77c1e3ccSAndroid Build Coastguard Worker delete[] m_void_elements;
1498*77c1e3ccSAndroid Build Coastguard Worker }
1499*77c1e3ccSAndroid Build Coastguard Worker
Parse()1500*77c1e3ccSAndroid Build Coastguard Worker long SeekHead::Parse() {
1501*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
1502*77c1e3ccSAndroid Build Coastguard Worker
1503*77c1e3ccSAndroid Build Coastguard Worker long long pos = m_start;
1504*77c1e3ccSAndroid Build Coastguard Worker const long long stop = m_start + m_size;
1505*77c1e3ccSAndroid Build Coastguard Worker
1506*77c1e3ccSAndroid Build Coastguard Worker // first count the seek head entries
1507*77c1e3ccSAndroid Build Coastguard Worker
1508*77c1e3ccSAndroid Build Coastguard Worker long long entry_count = 0;
1509*77c1e3ccSAndroid Build Coastguard Worker long long void_element_count = 0;
1510*77c1e3ccSAndroid Build Coastguard Worker
1511*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
1512*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
1513*77c1e3ccSAndroid Build Coastguard Worker
1514*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, stop, id, size);
1515*77c1e3ccSAndroid Build Coastguard Worker
1516*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
1517*77c1e3ccSAndroid Build Coastguard Worker return status;
1518*77c1e3ccSAndroid Build Coastguard Worker
1519*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvSeek) {
1520*77c1e3ccSAndroid Build Coastguard Worker ++entry_count;
1521*77c1e3ccSAndroid Build Coastguard Worker if (entry_count > INT_MAX)
1522*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
1523*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvVoid) {
1524*77c1e3ccSAndroid Build Coastguard Worker ++void_element_count;
1525*77c1e3ccSAndroid Build Coastguard Worker if (void_element_count > INT_MAX)
1526*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
1527*77c1e3ccSAndroid Build Coastguard Worker }
1528*77c1e3ccSAndroid Build Coastguard Worker
1529*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
1530*77c1e3ccSAndroid Build Coastguard Worker
1531*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
1532*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1533*77c1e3ccSAndroid Build Coastguard Worker }
1534*77c1e3ccSAndroid Build Coastguard Worker
1535*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
1536*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1537*77c1e3ccSAndroid Build Coastguard Worker
1538*77c1e3ccSAndroid Build Coastguard Worker if (entry_count > 0) {
1539*77c1e3ccSAndroid Build Coastguard Worker m_entries = new (std::nothrow) Entry[static_cast<size_t>(entry_count)];
1540*77c1e3ccSAndroid Build Coastguard Worker
1541*77c1e3ccSAndroid Build Coastguard Worker if (m_entries == NULL)
1542*77c1e3ccSAndroid Build Coastguard Worker return -1;
1543*77c1e3ccSAndroid Build Coastguard Worker }
1544*77c1e3ccSAndroid Build Coastguard Worker
1545*77c1e3ccSAndroid Build Coastguard Worker if (void_element_count > 0) {
1546*77c1e3ccSAndroid Build Coastguard Worker m_void_elements =
1547*77c1e3ccSAndroid Build Coastguard Worker new (std::nothrow) VoidElement[static_cast<size_t>(void_element_count)];
1548*77c1e3ccSAndroid Build Coastguard Worker
1549*77c1e3ccSAndroid Build Coastguard Worker if (m_void_elements == NULL)
1550*77c1e3ccSAndroid Build Coastguard Worker return -1;
1551*77c1e3ccSAndroid Build Coastguard Worker }
1552*77c1e3ccSAndroid Build Coastguard Worker
1553*77c1e3ccSAndroid Build Coastguard Worker // now parse the entries and void elements
1554*77c1e3ccSAndroid Build Coastguard Worker
1555*77c1e3ccSAndroid Build Coastguard Worker Entry* pEntry = m_entries;
1556*77c1e3ccSAndroid Build Coastguard Worker VoidElement* pVoidElement = m_void_elements;
1557*77c1e3ccSAndroid Build Coastguard Worker
1558*77c1e3ccSAndroid Build Coastguard Worker pos = m_start;
1559*77c1e3ccSAndroid Build Coastguard Worker
1560*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
1561*77c1e3ccSAndroid Build Coastguard Worker const long long idpos = pos;
1562*77c1e3ccSAndroid Build Coastguard Worker
1563*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
1564*77c1e3ccSAndroid Build Coastguard Worker
1565*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, stop, id, size);
1566*77c1e3ccSAndroid Build Coastguard Worker
1567*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
1568*77c1e3ccSAndroid Build Coastguard Worker return status;
1569*77c1e3ccSAndroid Build Coastguard Worker
1570*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvSeek && entry_count > 0) {
1571*77c1e3ccSAndroid Build Coastguard Worker if (ParseEntry(pReader, pos, size, pEntry)) {
1572*77c1e3ccSAndroid Build Coastguard Worker Entry& e = *pEntry++;
1573*77c1e3ccSAndroid Build Coastguard Worker
1574*77c1e3ccSAndroid Build Coastguard Worker e.element_start = idpos;
1575*77c1e3ccSAndroid Build Coastguard Worker e.element_size = (pos + size) - idpos;
1576*77c1e3ccSAndroid Build Coastguard Worker }
1577*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvVoid && void_element_count > 0) {
1578*77c1e3ccSAndroid Build Coastguard Worker VoidElement& e = *pVoidElement++;
1579*77c1e3ccSAndroid Build Coastguard Worker
1580*77c1e3ccSAndroid Build Coastguard Worker e.element_start = idpos;
1581*77c1e3ccSAndroid Build Coastguard Worker e.element_size = (pos + size) - idpos;
1582*77c1e3ccSAndroid Build Coastguard Worker }
1583*77c1e3ccSAndroid Build Coastguard Worker
1584*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
1585*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
1586*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1587*77c1e3ccSAndroid Build Coastguard Worker }
1588*77c1e3ccSAndroid Build Coastguard Worker
1589*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
1590*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1591*77c1e3ccSAndroid Build Coastguard Worker
1592*77c1e3ccSAndroid Build Coastguard Worker ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
1593*77c1e3ccSAndroid Build Coastguard Worker assert(count_ >= 0);
1594*77c1e3ccSAndroid Build Coastguard Worker assert(static_cast<long long>(count_) <= entry_count);
1595*77c1e3ccSAndroid Build Coastguard Worker
1596*77c1e3ccSAndroid Build Coastguard Worker m_entry_count = static_cast<int>(count_);
1597*77c1e3ccSAndroid Build Coastguard Worker
1598*77c1e3ccSAndroid Build Coastguard Worker count_ = ptrdiff_t(pVoidElement - m_void_elements);
1599*77c1e3ccSAndroid Build Coastguard Worker assert(count_ >= 0);
1600*77c1e3ccSAndroid Build Coastguard Worker assert(static_cast<long long>(count_) <= void_element_count);
1601*77c1e3ccSAndroid Build Coastguard Worker
1602*77c1e3ccSAndroid Build Coastguard Worker m_void_element_count = static_cast<int>(count_);
1603*77c1e3ccSAndroid Build Coastguard Worker
1604*77c1e3ccSAndroid Build Coastguard Worker return 0;
1605*77c1e3ccSAndroid Build Coastguard Worker }
1606*77c1e3ccSAndroid Build Coastguard Worker
GetCount() const1607*77c1e3ccSAndroid Build Coastguard Worker int SeekHead::GetCount() const { return m_entry_count; }
1608*77c1e3ccSAndroid Build Coastguard Worker
GetEntry(int idx) const1609*77c1e3ccSAndroid Build Coastguard Worker const SeekHead::Entry* SeekHead::GetEntry(int idx) const {
1610*77c1e3ccSAndroid Build Coastguard Worker if (idx < 0)
1611*77c1e3ccSAndroid Build Coastguard Worker return 0;
1612*77c1e3ccSAndroid Build Coastguard Worker
1613*77c1e3ccSAndroid Build Coastguard Worker if (idx >= m_entry_count)
1614*77c1e3ccSAndroid Build Coastguard Worker return 0;
1615*77c1e3ccSAndroid Build Coastguard Worker
1616*77c1e3ccSAndroid Build Coastguard Worker return m_entries + idx;
1617*77c1e3ccSAndroid Build Coastguard Worker }
1618*77c1e3ccSAndroid Build Coastguard Worker
GetVoidElementCount() const1619*77c1e3ccSAndroid Build Coastguard Worker int SeekHead::GetVoidElementCount() const { return m_void_element_count; }
1620*77c1e3ccSAndroid Build Coastguard Worker
GetVoidElement(int idx) const1621*77c1e3ccSAndroid Build Coastguard Worker const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const {
1622*77c1e3ccSAndroid Build Coastguard Worker if (idx < 0)
1623*77c1e3ccSAndroid Build Coastguard Worker return 0;
1624*77c1e3ccSAndroid Build Coastguard Worker
1625*77c1e3ccSAndroid Build Coastguard Worker if (idx >= m_void_element_count)
1626*77c1e3ccSAndroid Build Coastguard Worker return 0;
1627*77c1e3ccSAndroid Build Coastguard Worker
1628*77c1e3ccSAndroid Build Coastguard Worker return m_void_elements + idx;
1629*77c1e3ccSAndroid Build Coastguard Worker }
1630*77c1e3ccSAndroid Build Coastguard Worker
ParseCues(long long off,long long & pos,long & len)1631*77c1e3ccSAndroid Build Coastguard Worker long Segment::ParseCues(long long off, long long& pos, long& len) {
1632*77c1e3ccSAndroid Build Coastguard Worker if (m_pCues)
1633*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
1634*77c1e3ccSAndroid Build Coastguard Worker
1635*77c1e3ccSAndroid Build Coastguard Worker if (off < 0)
1636*77c1e3ccSAndroid Build Coastguard Worker return -1;
1637*77c1e3ccSAndroid Build Coastguard Worker
1638*77c1e3ccSAndroid Build Coastguard Worker long long total, avail;
1639*77c1e3ccSAndroid Build Coastguard Worker
1640*77c1e3ccSAndroid Build Coastguard Worker const int status = m_pReader->Length(&total, &avail);
1641*77c1e3ccSAndroid Build Coastguard Worker
1642*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
1643*77c1e3ccSAndroid Build Coastguard Worker return status;
1644*77c1e3ccSAndroid Build Coastguard Worker
1645*77c1e3ccSAndroid Build Coastguard Worker assert((total < 0) || (avail <= total));
1646*77c1e3ccSAndroid Build Coastguard Worker
1647*77c1e3ccSAndroid Build Coastguard Worker pos = m_start + off;
1648*77c1e3ccSAndroid Build Coastguard Worker
1649*77c1e3ccSAndroid Build Coastguard Worker if ((total < 0) || (pos >= total))
1650*77c1e3ccSAndroid Build Coastguard Worker return 1; // don't bother parsing cues
1651*77c1e3ccSAndroid Build Coastguard Worker
1652*77c1e3ccSAndroid Build Coastguard Worker const long long element_start = pos;
1653*77c1e3ccSAndroid Build Coastguard Worker const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1654*77c1e3ccSAndroid Build Coastguard Worker
1655*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
1656*77c1e3ccSAndroid Build Coastguard Worker len = 1;
1657*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1658*77c1e3ccSAndroid Build Coastguard Worker }
1659*77c1e3ccSAndroid Build Coastguard Worker
1660*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(m_pReader, pos, len);
1661*77c1e3ccSAndroid Build Coastguard Worker
1662*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
1663*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
1664*77c1e3ccSAndroid Build Coastguard Worker
1665*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // underflow (weird)
1666*77c1e3ccSAndroid Build Coastguard Worker {
1667*77c1e3ccSAndroid Build Coastguard Worker len = 1;
1668*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1669*77c1e3ccSAndroid Build Coastguard Worker }
1670*77c1e3ccSAndroid Build Coastguard Worker
1671*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1672*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1673*77c1e3ccSAndroid Build Coastguard Worker
1674*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
1675*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1676*77c1e3ccSAndroid Build Coastguard Worker
1677*77c1e3ccSAndroid Build Coastguard Worker const long long idpos = pos;
1678*77c1e3ccSAndroid Build Coastguard Worker
1679*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(m_pReader, idpos, len);
1680*77c1e3ccSAndroid Build Coastguard Worker
1681*77c1e3ccSAndroid Build Coastguard Worker if (id != libwebm::kMkvCues)
1682*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1683*77c1e3ccSAndroid Build Coastguard Worker
1684*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
1685*77c1e3ccSAndroid Build Coastguard Worker assert((segment_stop < 0) || (pos <= segment_stop));
1686*77c1e3ccSAndroid Build Coastguard Worker
1687*77c1e3ccSAndroid Build Coastguard Worker // Read Size
1688*77c1e3ccSAndroid Build Coastguard Worker
1689*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
1690*77c1e3ccSAndroid Build Coastguard Worker len = 1;
1691*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1692*77c1e3ccSAndroid Build Coastguard Worker }
1693*77c1e3ccSAndroid Build Coastguard Worker
1694*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(m_pReader, pos, len);
1695*77c1e3ccSAndroid Build Coastguard Worker
1696*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
1697*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
1698*77c1e3ccSAndroid Build Coastguard Worker
1699*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // underflow (weird)
1700*77c1e3ccSAndroid Build Coastguard Worker {
1701*77c1e3ccSAndroid Build Coastguard Worker len = 1;
1702*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1703*77c1e3ccSAndroid Build Coastguard Worker }
1704*77c1e3ccSAndroid Build Coastguard Worker
1705*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1706*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1707*77c1e3ccSAndroid Build Coastguard Worker
1708*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
1709*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1710*77c1e3ccSAndroid Build Coastguard Worker
1711*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(m_pReader, pos, len);
1712*77c1e3ccSAndroid Build Coastguard Worker
1713*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
1714*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(size);
1715*77c1e3ccSAndroid Build Coastguard Worker
1716*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // weird, although technically not illegal
1717*77c1e3ccSAndroid Build Coastguard Worker return 1; // done
1718*77c1e3ccSAndroid Build Coastguard Worker
1719*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of element
1720*77c1e3ccSAndroid Build Coastguard Worker assert((segment_stop < 0) || (pos <= segment_stop));
1721*77c1e3ccSAndroid Build Coastguard Worker
1722*77c1e3ccSAndroid Build Coastguard Worker // Pos now points to start of payload
1723*77c1e3ccSAndroid Build Coastguard Worker
1724*77c1e3ccSAndroid Build Coastguard Worker const long long element_stop = pos + size;
1725*77c1e3ccSAndroid Build Coastguard Worker
1726*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && (element_stop > segment_stop))
1727*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
1728*77c1e3ccSAndroid Build Coastguard Worker
1729*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (element_stop > total))
1730*77c1e3ccSAndroid Build Coastguard Worker return 1; // don't bother parsing anymore
1731*77c1e3ccSAndroid Build Coastguard Worker
1732*77c1e3ccSAndroid Build Coastguard Worker len = static_cast<long>(size);
1733*77c1e3ccSAndroid Build Coastguard Worker
1734*77c1e3ccSAndroid Build Coastguard Worker if (element_stop > avail)
1735*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
1736*77c1e3ccSAndroid Build Coastguard Worker
1737*77c1e3ccSAndroid Build Coastguard Worker const long long element_size = element_stop - element_start;
1738*77c1e3ccSAndroid Build Coastguard Worker
1739*77c1e3ccSAndroid Build Coastguard Worker m_pCues =
1740*77c1e3ccSAndroid Build Coastguard Worker new (std::nothrow) Cues(this, pos, size, element_start, element_size);
1741*77c1e3ccSAndroid Build Coastguard Worker if (m_pCues == NULL)
1742*77c1e3ccSAndroid Build Coastguard Worker return -1;
1743*77c1e3ccSAndroid Build Coastguard Worker
1744*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
1745*77c1e3ccSAndroid Build Coastguard Worker }
1746*77c1e3ccSAndroid Build Coastguard Worker
ParseEntry(IMkvReader * pReader,long long start,long long size_,Entry * pEntry)1747*77c1e3ccSAndroid Build Coastguard Worker bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
1748*77c1e3ccSAndroid Build Coastguard Worker Entry* pEntry) {
1749*77c1e3ccSAndroid Build Coastguard Worker if (size_ <= 0)
1750*77c1e3ccSAndroid Build Coastguard Worker return false;
1751*77c1e3ccSAndroid Build Coastguard Worker
1752*77c1e3ccSAndroid Build Coastguard Worker long long pos = start;
1753*77c1e3ccSAndroid Build Coastguard Worker const long long stop = start + size_;
1754*77c1e3ccSAndroid Build Coastguard Worker
1755*77c1e3ccSAndroid Build Coastguard Worker long len;
1756*77c1e3ccSAndroid Build Coastguard Worker
1757*77c1e3ccSAndroid Build Coastguard Worker // parse the container for the level-1 element ID
1758*77c1e3ccSAndroid Build Coastguard Worker
1759*77c1e3ccSAndroid Build Coastguard Worker const long long seekIdId = ReadID(pReader, pos, len);
1760*77c1e3ccSAndroid Build Coastguard Worker if (seekIdId < 0)
1761*77c1e3ccSAndroid Build Coastguard Worker return false;
1762*77c1e3ccSAndroid Build Coastguard Worker
1763*77c1e3ccSAndroid Build Coastguard Worker if (seekIdId != libwebm::kMkvSeekID)
1764*77c1e3ccSAndroid Build Coastguard Worker return false;
1765*77c1e3ccSAndroid Build Coastguard Worker
1766*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > stop)
1767*77c1e3ccSAndroid Build Coastguard Worker return false;
1768*77c1e3ccSAndroid Build Coastguard Worker
1769*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume SeekID id
1770*77c1e3ccSAndroid Build Coastguard Worker
1771*77c1e3ccSAndroid Build Coastguard Worker const long long seekIdSize = ReadUInt(pReader, pos, len);
1772*77c1e3ccSAndroid Build Coastguard Worker
1773*77c1e3ccSAndroid Build Coastguard Worker if (seekIdSize <= 0)
1774*77c1e3ccSAndroid Build Coastguard Worker return false;
1775*77c1e3ccSAndroid Build Coastguard Worker
1776*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > stop)
1777*77c1e3ccSAndroid Build Coastguard Worker return false;
1778*77c1e3ccSAndroid Build Coastguard Worker
1779*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size of field
1780*77c1e3ccSAndroid Build Coastguard Worker
1781*77c1e3ccSAndroid Build Coastguard Worker if ((pos + seekIdSize) > stop)
1782*77c1e3ccSAndroid Build Coastguard Worker return false;
1783*77c1e3ccSAndroid Build Coastguard Worker
1784*77c1e3ccSAndroid Build Coastguard Worker pEntry->id = ReadID(pReader, pos, len); // payload
1785*77c1e3ccSAndroid Build Coastguard Worker
1786*77c1e3ccSAndroid Build Coastguard Worker if (pEntry->id <= 0)
1787*77c1e3ccSAndroid Build Coastguard Worker return false;
1788*77c1e3ccSAndroid Build Coastguard Worker
1789*77c1e3ccSAndroid Build Coastguard Worker if (len != seekIdSize)
1790*77c1e3ccSAndroid Build Coastguard Worker return false;
1791*77c1e3ccSAndroid Build Coastguard Worker
1792*77c1e3ccSAndroid Build Coastguard Worker pos += seekIdSize; // consume SeekID payload
1793*77c1e3ccSAndroid Build Coastguard Worker
1794*77c1e3ccSAndroid Build Coastguard Worker const long long seekPosId = ReadID(pReader, pos, len);
1795*77c1e3ccSAndroid Build Coastguard Worker
1796*77c1e3ccSAndroid Build Coastguard Worker if (seekPosId != libwebm::kMkvSeekPosition)
1797*77c1e3ccSAndroid Build Coastguard Worker return false;
1798*77c1e3ccSAndroid Build Coastguard Worker
1799*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > stop)
1800*77c1e3ccSAndroid Build Coastguard Worker return false;
1801*77c1e3ccSAndroid Build Coastguard Worker
1802*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume id
1803*77c1e3ccSAndroid Build Coastguard Worker
1804*77c1e3ccSAndroid Build Coastguard Worker const long long seekPosSize = ReadUInt(pReader, pos, len);
1805*77c1e3ccSAndroid Build Coastguard Worker
1806*77c1e3ccSAndroid Build Coastguard Worker if (seekPosSize <= 0)
1807*77c1e3ccSAndroid Build Coastguard Worker return false;
1808*77c1e3ccSAndroid Build Coastguard Worker
1809*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > stop)
1810*77c1e3ccSAndroid Build Coastguard Worker return false;
1811*77c1e3ccSAndroid Build Coastguard Worker
1812*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size
1813*77c1e3ccSAndroid Build Coastguard Worker
1814*77c1e3ccSAndroid Build Coastguard Worker if ((pos + seekPosSize) > stop)
1815*77c1e3ccSAndroid Build Coastguard Worker return false;
1816*77c1e3ccSAndroid Build Coastguard Worker
1817*77c1e3ccSAndroid Build Coastguard Worker pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize);
1818*77c1e3ccSAndroid Build Coastguard Worker
1819*77c1e3ccSAndroid Build Coastguard Worker if (pEntry->pos < 0)
1820*77c1e3ccSAndroid Build Coastguard Worker return false;
1821*77c1e3ccSAndroid Build Coastguard Worker
1822*77c1e3ccSAndroid Build Coastguard Worker pos += seekPosSize; // consume payload
1823*77c1e3ccSAndroid Build Coastguard Worker
1824*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
1825*77c1e3ccSAndroid Build Coastguard Worker return false;
1826*77c1e3ccSAndroid Build Coastguard Worker
1827*77c1e3ccSAndroid Build Coastguard Worker return true;
1828*77c1e3ccSAndroid Build Coastguard Worker }
1829*77c1e3ccSAndroid Build Coastguard Worker
Cues(Segment * pSegment,long long start_,long long size_,long long element_start,long long element_size)1830*77c1e3ccSAndroid Build Coastguard Worker Cues::Cues(Segment* pSegment, long long start_, long long size_,
1831*77c1e3ccSAndroid Build Coastguard Worker long long element_start, long long element_size)
1832*77c1e3ccSAndroid Build Coastguard Worker : m_pSegment(pSegment),
1833*77c1e3ccSAndroid Build Coastguard Worker m_start(start_),
1834*77c1e3ccSAndroid Build Coastguard Worker m_size(size_),
1835*77c1e3ccSAndroid Build Coastguard Worker m_element_start(element_start),
1836*77c1e3ccSAndroid Build Coastguard Worker m_element_size(element_size),
1837*77c1e3ccSAndroid Build Coastguard Worker m_cue_points(NULL),
1838*77c1e3ccSAndroid Build Coastguard Worker m_count(0),
1839*77c1e3ccSAndroid Build Coastguard Worker m_preload_count(0),
1840*77c1e3ccSAndroid Build Coastguard Worker m_pos(start_) {}
1841*77c1e3ccSAndroid Build Coastguard Worker
~Cues()1842*77c1e3ccSAndroid Build Coastguard Worker Cues::~Cues() {
1843*77c1e3ccSAndroid Build Coastguard Worker const long n = m_count + m_preload_count;
1844*77c1e3ccSAndroid Build Coastguard Worker
1845*77c1e3ccSAndroid Build Coastguard Worker CuePoint** p = m_cue_points;
1846*77c1e3ccSAndroid Build Coastguard Worker CuePoint** const q = p + n;
1847*77c1e3ccSAndroid Build Coastguard Worker
1848*77c1e3ccSAndroid Build Coastguard Worker while (p != q) {
1849*77c1e3ccSAndroid Build Coastguard Worker CuePoint* const pCP = *p++;
1850*77c1e3ccSAndroid Build Coastguard Worker assert(pCP);
1851*77c1e3ccSAndroid Build Coastguard Worker
1852*77c1e3ccSAndroid Build Coastguard Worker delete pCP;
1853*77c1e3ccSAndroid Build Coastguard Worker }
1854*77c1e3ccSAndroid Build Coastguard Worker
1855*77c1e3ccSAndroid Build Coastguard Worker delete[] m_cue_points;
1856*77c1e3ccSAndroid Build Coastguard Worker }
1857*77c1e3ccSAndroid Build Coastguard Worker
GetCount() const1858*77c1e3ccSAndroid Build Coastguard Worker long Cues::GetCount() const {
1859*77c1e3ccSAndroid Build Coastguard Worker if (m_cue_points == NULL)
1860*77c1e3ccSAndroid Build Coastguard Worker return -1;
1861*77c1e3ccSAndroid Build Coastguard Worker
1862*77c1e3ccSAndroid Build Coastguard Worker return m_count; // TODO: really ignore preload count?
1863*77c1e3ccSAndroid Build Coastguard Worker }
1864*77c1e3ccSAndroid Build Coastguard Worker
DoneParsing() const1865*77c1e3ccSAndroid Build Coastguard Worker bool Cues::DoneParsing() const {
1866*77c1e3ccSAndroid Build Coastguard Worker const long long stop = m_start + m_size;
1867*77c1e3ccSAndroid Build Coastguard Worker return (m_pos >= stop);
1868*77c1e3ccSAndroid Build Coastguard Worker }
1869*77c1e3ccSAndroid Build Coastguard Worker
Init() const1870*77c1e3ccSAndroid Build Coastguard Worker bool Cues::Init() const {
1871*77c1e3ccSAndroid Build Coastguard Worker if (m_cue_points)
1872*77c1e3ccSAndroid Build Coastguard Worker return true;
1873*77c1e3ccSAndroid Build Coastguard Worker
1874*77c1e3ccSAndroid Build Coastguard Worker if (m_count != 0 || m_preload_count != 0)
1875*77c1e3ccSAndroid Build Coastguard Worker return false;
1876*77c1e3ccSAndroid Build Coastguard Worker
1877*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
1878*77c1e3ccSAndroid Build Coastguard Worker
1879*77c1e3ccSAndroid Build Coastguard Worker const long long stop = m_start + m_size;
1880*77c1e3ccSAndroid Build Coastguard Worker long long pos = m_start;
1881*77c1e3ccSAndroid Build Coastguard Worker
1882*77c1e3ccSAndroid Build Coastguard Worker long cue_points_size = 0;
1883*77c1e3ccSAndroid Build Coastguard Worker
1884*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
1885*77c1e3ccSAndroid Build Coastguard Worker const long long idpos = pos;
1886*77c1e3ccSAndroid Build Coastguard Worker
1887*77c1e3ccSAndroid Build Coastguard Worker long len;
1888*77c1e3ccSAndroid Build Coastguard Worker
1889*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
1890*77c1e3ccSAndroid Build Coastguard Worker if (id < 0 || (pos + len) > stop) {
1891*77c1e3ccSAndroid Build Coastguard Worker return false;
1892*77c1e3ccSAndroid Build Coastguard Worker }
1893*77c1e3ccSAndroid Build Coastguard Worker
1894*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
1895*77c1e3ccSAndroid Build Coastguard Worker
1896*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
1897*77c1e3ccSAndroid Build Coastguard Worker if (size < 0 || (pos + len > stop)) {
1898*77c1e3ccSAndroid Build Coastguard Worker return false;
1899*77c1e3ccSAndroid Build Coastguard Worker }
1900*77c1e3ccSAndroid Build Coastguard Worker
1901*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume Size field
1902*77c1e3ccSAndroid Build Coastguard Worker if (pos + size > stop) {
1903*77c1e3ccSAndroid Build Coastguard Worker return false;
1904*77c1e3ccSAndroid Build Coastguard Worker }
1905*77c1e3ccSAndroid Build Coastguard Worker
1906*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCuePoint) {
1907*77c1e3ccSAndroid Build Coastguard Worker if (!PreloadCuePoint(cue_points_size, idpos))
1908*77c1e3ccSAndroid Build Coastguard Worker return false;
1909*77c1e3ccSAndroid Build Coastguard Worker }
1910*77c1e3ccSAndroid Build Coastguard Worker
1911*77c1e3ccSAndroid Build Coastguard Worker pos += size; // skip payload
1912*77c1e3ccSAndroid Build Coastguard Worker }
1913*77c1e3ccSAndroid Build Coastguard Worker return true;
1914*77c1e3ccSAndroid Build Coastguard Worker }
1915*77c1e3ccSAndroid Build Coastguard Worker
PreloadCuePoint(long & cue_points_size,long long pos) const1916*77c1e3ccSAndroid Build Coastguard Worker bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
1917*77c1e3ccSAndroid Build Coastguard Worker if (m_count != 0)
1918*77c1e3ccSAndroid Build Coastguard Worker return false;
1919*77c1e3ccSAndroid Build Coastguard Worker
1920*77c1e3ccSAndroid Build Coastguard Worker if (m_preload_count >= cue_points_size) {
1921*77c1e3ccSAndroid Build Coastguard Worker const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;
1922*77c1e3ccSAndroid Build Coastguard Worker
1923*77c1e3ccSAndroid Build Coastguard Worker CuePoint** const qq = new (std::nothrow) CuePoint*[n];
1924*77c1e3ccSAndroid Build Coastguard Worker if (qq == NULL)
1925*77c1e3ccSAndroid Build Coastguard Worker return false;
1926*77c1e3ccSAndroid Build Coastguard Worker
1927*77c1e3ccSAndroid Build Coastguard Worker CuePoint** q = qq; // beginning of target
1928*77c1e3ccSAndroid Build Coastguard Worker
1929*77c1e3ccSAndroid Build Coastguard Worker CuePoint** p = m_cue_points; // beginning of source
1930*77c1e3ccSAndroid Build Coastguard Worker CuePoint** const pp = p + m_preload_count; // end of source
1931*77c1e3ccSAndroid Build Coastguard Worker
1932*77c1e3ccSAndroid Build Coastguard Worker while (p != pp)
1933*77c1e3ccSAndroid Build Coastguard Worker *q++ = *p++;
1934*77c1e3ccSAndroid Build Coastguard Worker
1935*77c1e3ccSAndroid Build Coastguard Worker delete[] m_cue_points;
1936*77c1e3ccSAndroid Build Coastguard Worker
1937*77c1e3ccSAndroid Build Coastguard Worker m_cue_points = qq;
1938*77c1e3ccSAndroid Build Coastguard Worker cue_points_size = n;
1939*77c1e3ccSAndroid Build Coastguard Worker }
1940*77c1e3ccSAndroid Build Coastguard Worker
1941*77c1e3ccSAndroid Build Coastguard Worker CuePoint* const pCP = new (std::nothrow) CuePoint(m_preload_count, pos);
1942*77c1e3ccSAndroid Build Coastguard Worker if (pCP == NULL)
1943*77c1e3ccSAndroid Build Coastguard Worker return false;
1944*77c1e3ccSAndroid Build Coastguard Worker
1945*77c1e3ccSAndroid Build Coastguard Worker m_cue_points[m_preload_count++] = pCP;
1946*77c1e3ccSAndroid Build Coastguard Worker return true;
1947*77c1e3ccSAndroid Build Coastguard Worker }
1948*77c1e3ccSAndroid Build Coastguard Worker
LoadCuePoint() const1949*77c1e3ccSAndroid Build Coastguard Worker bool Cues::LoadCuePoint() const {
1950*77c1e3ccSAndroid Build Coastguard Worker const long long stop = m_start + m_size;
1951*77c1e3ccSAndroid Build Coastguard Worker
1952*77c1e3ccSAndroid Build Coastguard Worker if (m_pos >= stop)
1953*77c1e3ccSAndroid Build Coastguard Worker return false; // nothing else to do
1954*77c1e3ccSAndroid Build Coastguard Worker
1955*77c1e3ccSAndroid Build Coastguard Worker if (!Init()) {
1956*77c1e3ccSAndroid Build Coastguard Worker m_pos = stop;
1957*77c1e3ccSAndroid Build Coastguard Worker return false;
1958*77c1e3ccSAndroid Build Coastguard Worker }
1959*77c1e3ccSAndroid Build Coastguard Worker
1960*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
1961*77c1e3ccSAndroid Build Coastguard Worker
1962*77c1e3ccSAndroid Build Coastguard Worker while (m_pos < stop) {
1963*77c1e3ccSAndroid Build Coastguard Worker const long long idpos = m_pos;
1964*77c1e3ccSAndroid Build Coastguard Worker
1965*77c1e3ccSAndroid Build Coastguard Worker long len;
1966*77c1e3ccSAndroid Build Coastguard Worker
1967*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, m_pos, len);
1968*77c1e3ccSAndroid Build Coastguard Worker if (id < 0 || (m_pos + len) > stop)
1969*77c1e3ccSAndroid Build Coastguard Worker return false;
1970*77c1e3ccSAndroid Build Coastguard Worker
1971*77c1e3ccSAndroid Build Coastguard Worker m_pos += len; // consume ID
1972*77c1e3ccSAndroid Build Coastguard Worker
1973*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, m_pos, len);
1974*77c1e3ccSAndroid Build Coastguard Worker if (size < 0 || (m_pos + len) > stop)
1975*77c1e3ccSAndroid Build Coastguard Worker return false;
1976*77c1e3ccSAndroid Build Coastguard Worker
1977*77c1e3ccSAndroid Build Coastguard Worker m_pos += len; // consume Size field
1978*77c1e3ccSAndroid Build Coastguard Worker if ((m_pos + size) > stop)
1979*77c1e3ccSAndroid Build Coastguard Worker return false;
1980*77c1e3ccSAndroid Build Coastguard Worker
1981*77c1e3ccSAndroid Build Coastguard Worker if (id != libwebm::kMkvCuePoint) {
1982*77c1e3ccSAndroid Build Coastguard Worker m_pos += size; // consume payload
1983*77c1e3ccSAndroid Build Coastguard Worker if (m_pos > stop)
1984*77c1e3ccSAndroid Build Coastguard Worker return false;
1985*77c1e3ccSAndroid Build Coastguard Worker
1986*77c1e3ccSAndroid Build Coastguard Worker continue;
1987*77c1e3ccSAndroid Build Coastguard Worker }
1988*77c1e3ccSAndroid Build Coastguard Worker
1989*77c1e3ccSAndroid Build Coastguard Worker if (m_preload_count < 1)
1990*77c1e3ccSAndroid Build Coastguard Worker return false;
1991*77c1e3ccSAndroid Build Coastguard Worker
1992*77c1e3ccSAndroid Build Coastguard Worker CuePoint* const pCP = m_cue_points[m_count];
1993*77c1e3ccSAndroid Build Coastguard Worker if (!pCP || (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)))
1994*77c1e3ccSAndroid Build Coastguard Worker return false;
1995*77c1e3ccSAndroid Build Coastguard Worker
1996*77c1e3ccSAndroid Build Coastguard Worker if (!pCP->Load(pReader)) {
1997*77c1e3ccSAndroid Build Coastguard Worker m_pos = stop;
1998*77c1e3ccSAndroid Build Coastguard Worker return false;
1999*77c1e3ccSAndroid Build Coastguard Worker }
2000*77c1e3ccSAndroid Build Coastguard Worker ++m_count;
2001*77c1e3ccSAndroid Build Coastguard Worker --m_preload_count;
2002*77c1e3ccSAndroid Build Coastguard Worker
2003*77c1e3ccSAndroid Build Coastguard Worker m_pos += size; // consume payload
2004*77c1e3ccSAndroid Build Coastguard Worker if (m_pos > stop)
2005*77c1e3ccSAndroid Build Coastguard Worker return false;
2006*77c1e3ccSAndroid Build Coastguard Worker
2007*77c1e3ccSAndroid Build Coastguard Worker return true; // yes, we loaded a cue point
2008*77c1e3ccSAndroid Build Coastguard Worker }
2009*77c1e3ccSAndroid Build Coastguard Worker
2010*77c1e3ccSAndroid Build Coastguard Worker return false; // no, we did not load a cue point
2011*77c1e3ccSAndroid Build Coastguard Worker }
2012*77c1e3ccSAndroid Build Coastguard Worker
Find(long long time_ns,const Track * pTrack,const CuePoint * & pCP,const CuePoint::TrackPosition * & pTP) const2013*77c1e3ccSAndroid Build Coastguard Worker bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
2014*77c1e3ccSAndroid Build Coastguard Worker const CuePoint::TrackPosition*& pTP) const {
2015*77c1e3ccSAndroid Build Coastguard Worker if (time_ns < 0 || pTrack == NULL || m_cue_points == NULL || m_count == 0)
2016*77c1e3ccSAndroid Build Coastguard Worker return false;
2017*77c1e3ccSAndroid Build Coastguard Worker
2018*77c1e3ccSAndroid Build Coastguard Worker CuePoint** const ii = m_cue_points;
2019*77c1e3ccSAndroid Build Coastguard Worker CuePoint** i = ii;
2020*77c1e3ccSAndroid Build Coastguard Worker
2021*77c1e3ccSAndroid Build Coastguard Worker CuePoint** const jj = ii + m_count;
2022*77c1e3ccSAndroid Build Coastguard Worker CuePoint** j = jj;
2023*77c1e3ccSAndroid Build Coastguard Worker
2024*77c1e3ccSAndroid Build Coastguard Worker pCP = *i;
2025*77c1e3ccSAndroid Build Coastguard Worker if (pCP == NULL)
2026*77c1e3ccSAndroid Build Coastguard Worker return false;
2027*77c1e3ccSAndroid Build Coastguard Worker
2028*77c1e3ccSAndroid Build Coastguard Worker if (time_ns <= pCP->GetTime(m_pSegment)) {
2029*77c1e3ccSAndroid Build Coastguard Worker pTP = pCP->Find(pTrack);
2030*77c1e3ccSAndroid Build Coastguard Worker return (pTP != NULL);
2031*77c1e3ccSAndroid Build Coastguard Worker }
2032*77c1e3ccSAndroid Build Coastguard Worker
2033*77c1e3ccSAndroid Build Coastguard Worker while (i < j) {
2034*77c1e3ccSAndroid Build Coastguard Worker // INVARIANT:
2035*77c1e3ccSAndroid Build Coastguard Worker //[ii, i) <= time_ns
2036*77c1e3ccSAndroid Build Coastguard Worker //[i, j) ?
2037*77c1e3ccSAndroid Build Coastguard Worker //[j, jj) > time_ns
2038*77c1e3ccSAndroid Build Coastguard Worker
2039*77c1e3ccSAndroid Build Coastguard Worker CuePoint** const k = i + (j - i) / 2;
2040*77c1e3ccSAndroid Build Coastguard Worker if (k >= jj)
2041*77c1e3ccSAndroid Build Coastguard Worker return false;
2042*77c1e3ccSAndroid Build Coastguard Worker
2043*77c1e3ccSAndroid Build Coastguard Worker CuePoint* const pCP = *k;
2044*77c1e3ccSAndroid Build Coastguard Worker if (pCP == NULL)
2045*77c1e3ccSAndroid Build Coastguard Worker return false;
2046*77c1e3ccSAndroid Build Coastguard Worker
2047*77c1e3ccSAndroid Build Coastguard Worker const long long t = pCP->GetTime(m_pSegment);
2048*77c1e3ccSAndroid Build Coastguard Worker
2049*77c1e3ccSAndroid Build Coastguard Worker if (t <= time_ns)
2050*77c1e3ccSAndroid Build Coastguard Worker i = k + 1;
2051*77c1e3ccSAndroid Build Coastguard Worker else
2052*77c1e3ccSAndroid Build Coastguard Worker j = k;
2053*77c1e3ccSAndroid Build Coastguard Worker
2054*77c1e3ccSAndroid Build Coastguard Worker if (i > j)
2055*77c1e3ccSAndroid Build Coastguard Worker return false;
2056*77c1e3ccSAndroid Build Coastguard Worker }
2057*77c1e3ccSAndroid Build Coastguard Worker
2058*77c1e3ccSAndroid Build Coastguard Worker if (i != j || i > jj || i <= ii)
2059*77c1e3ccSAndroid Build Coastguard Worker return false;
2060*77c1e3ccSAndroid Build Coastguard Worker
2061*77c1e3ccSAndroid Build Coastguard Worker pCP = *--i;
2062*77c1e3ccSAndroid Build Coastguard Worker
2063*77c1e3ccSAndroid Build Coastguard Worker if (pCP == NULL || pCP->GetTime(m_pSegment) > time_ns)
2064*77c1e3ccSAndroid Build Coastguard Worker return false;
2065*77c1e3ccSAndroid Build Coastguard Worker
2066*77c1e3ccSAndroid Build Coastguard Worker // TODO: here and elsewhere, it's probably not correct to search
2067*77c1e3ccSAndroid Build Coastguard Worker // for the cue point with this time, and then search for a matching
2068*77c1e3ccSAndroid Build Coastguard Worker // track. In principle, the matching track could be on some earlier
2069*77c1e3ccSAndroid Build Coastguard Worker // cue point, and with our current algorithm, we'd miss it. To make
2070*77c1e3ccSAndroid Build Coastguard Worker // this bullet-proof, we'd need to create a secondary structure,
2071*77c1e3ccSAndroid Build Coastguard Worker // with a list of cue points that apply to a track, and then search
2072*77c1e3ccSAndroid Build Coastguard Worker // that track-based structure for a matching cue point.
2073*77c1e3ccSAndroid Build Coastguard Worker
2074*77c1e3ccSAndroid Build Coastguard Worker pTP = pCP->Find(pTrack);
2075*77c1e3ccSAndroid Build Coastguard Worker return (pTP != NULL);
2076*77c1e3ccSAndroid Build Coastguard Worker }
2077*77c1e3ccSAndroid Build Coastguard Worker
GetFirst() const2078*77c1e3ccSAndroid Build Coastguard Worker const CuePoint* Cues::GetFirst() const {
2079*77c1e3ccSAndroid Build Coastguard Worker if (m_cue_points == NULL || m_count == 0)
2080*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2081*77c1e3ccSAndroid Build Coastguard Worker
2082*77c1e3ccSAndroid Build Coastguard Worker CuePoint* const* const pp = m_cue_points;
2083*77c1e3ccSAndroid Build Coastguard Worker if (pp == NULL)
2084*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2085*77c1e3ccSAndroid Build Coastguard Worker
2086*77c1e3ccSAndroid Build Coastguard Worker CuePoint* const pCP = pp[0];
2087*77c1e3ccSAndroid Build Coastguard Worker if (pCP == NULL || pCP->GetTimeCode() < 0)
2088*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2089*77c1e3ccSAndroid Build Coastguard Worker
2090*77c1e3ccSAndroid Build Coastguard Worker return pCP;
2091*77c1e3ccSAndroid Build Coastguard Worker }
2092*77c1e3ccSAndroid Build Coastguard Worker
GetLast() const2093*77c1e3ccSAndroid Build Coastguard Worker const CuePoint* Cues::GetLast() const {
2094*77c1e3ccSAndroid Build Coastguard Worker if (m_cue_points == NULL || m_count <= 0)
2095*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2096*77c1e3ccSAndroid Build Coastguard Worker
2097*77c1e3ccSAndroid Build Coastguard Worker const long index = m_count - 1;
2098*77c1e3ccSAndroid Build Coastguard Worker
2099*77c1e3ccSAndroid Build Coastguard Worker CuePoint* const* const pp = m_cue_points;
2100*77c1e3ccSAndroid Build Coastguard Worker if (pp == NULL)
2101*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2102*77c1e3ccSAndroid Build Coastguard Worker
2103*77c1e3ccSAndroid Build Coastguard Worker CuePoint* const pCP = pp[index];
2104*77c1e3ccSAndroid Build Coastguard Worker if (pCP == NULL || pCP->GetTimeCode() < 0)
2105*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2106*77c1e3ccSAndroid Build Coastguard Worker
2107*77c1e3ccSAndroid Build Coastguard Worker return pCP;
2108*77c1e3ccSAndroid Build Coastguard Worker }
2109*77c1e3ccSAndroid Build Coastguard Worker
GetNext(const CuePoint * pCurr) const2110*77c1e3ccSAndroid Build Coastguard Worker const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
2111*77c1e3ccSAndroid Build Coastguard Worker if (pCurr == NULL || pCurr->GetTimeCode() < 0 || m_cue_points == NULL ||
2112*77c1e3ccSAndroid Build Coastguard Worker m_count < 1) {
2113*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2114*77c1e3ccSAndroid Build Coastguard Worker }
2115*77c1e3ccSAndroid Build Coastguard Worker
2116*77c1e3ccSAndroid Build Coastguard Worker long index = pCurr->m_index;
2117*77c1e3ccSAndroid Build Coastguard Worker if (index >= m_count)
2118*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2119*77c1e3ccSAndroid Build Coastguard Worker
2120*77c1e3ccSAndroid Build Coastguard Worker CuePoint* const* const pp = m_cue_points;
2121*77c1e3ccSAndroid Build Coastguard Worker if (pp == NULL || pp[index] != pCurr)
2122*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2123*77c1e3ccSAndroid Build Coastguard Worker
2124*77c1e3ccSAndroid Build Coastguard Worker ++index;
2125*77c1e3ccSAndroid Build Coastguard Worker
2126*77c1e3ccSAndroid Build Coastguard Worker if (index >= m_count)
2127*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2128*77c1e3ccSAndroid Build Coastguard Worker
2129*77c1e3ccSAndroid Build Coastguard Worker CuePoint* const pNext = pp[index];
2130*77c1e3ccSAndroid Build Coastguard Worker
2131*77c1e3ccSAndroid Build Coastguard Worker if (pNext == NULL || pNext->GetTimeCode() < 0)
2132*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2133*77c1e3ccSAndroid Build Coastguard Worker
2134*77c1e3ccSAndroid Build Coastguard Worker return pNext;
2135*77c1e3ccSAndroid Build Coastguard Worker }
2136*77c1e3ccSAndroid Build Coastguard Worker
GetBlock(const CuePoint * pCP,const CuePoint::TrackPosition * pTP) const2137*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* Cues::GetBlock(const CuePoint* pCP,
2138*77c1e3ccSAndroid Build Coastguard Worker const CuePoint::TrackPosition* pTP) const {
2139*77c1e3ccSAndroid Build Coastguard Worker if (pCP == NULL || pTP == NULL)
2140*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2141*77c1e3ccSAndroid Build Coastguard Worker
2142*77c1e3ccSAndroid Build Coastguard Worker return m_pSegment->GetBlock(*pCP, *pTP);
2143*77c1e3ccSAndroid Build Coastguard Worker }
2144*77c1e3ccSAndroid Build Coastguard Worker
GetBlock(const CuePoint & cp,const CuePoint::TrackPosition & tp)2145*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* Segment::GetBlock(const CuePoint& cp,
2146*77c1e3ccSAndroid Build Coastguard Worker const CuePoint::TrackPosition& tp) {
2147*77c1e3ccSAndroid Build Coastguard Worker Cluster** const ii = m_clusters;
2148*77c1e3ccSAndroid Build Coastguard Worker Cluster** i = ii;
2149*77c1e3ccSAndroid Build Coastguard Worker
2150*77c1e3ccSAndroid Build Coastguard Worker const long count = m_clusterCount + m_clusterPreloadCount;
2151*77c1e3ccSAndroid Build Coastguard Worker
2152*77c1e3ccSAndroid Build Coastguard Worker Cluster** const jj = ii + count;
2153*77c1e3ccSAndroid Build Coastguard Worker Cluster** j = jj;
2154*77c1e3ccSAndroid Build Coastguard Worker
2155*77c1e3ccSAndroid Build Coastguard Worker while (i < j) {
2156*77c1e3ccSAndroid Build Coastguard Worker // INVARIANT:
2157*77c1e3ccSAndroid Build Coastguard Worker //[ii, i) < pTP->m_pos
2158*77c1e3ccSAndroid Build Coastguard Worker //[i, j) ?
2159*77c1e3ccSAndroid Build Coastguard Worker //[j, jj) > pTP->m_pos
2160*77c1e3ccSAndroid Build Coastguard Worker
2161*77c1e3ccSAndroid Build Coastguard Worker Cluster** const k = i + (j - i) / 2;
2162*77c1e3ccSAndroid Build Coastguard Worker assert(k < jj);
2163*77c1e3ccSAndroid Build Coastguard Worker
2164*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = *k;
2165*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
2166*77c1e3ccSAndroid Build Coastguard Worker
2167*77c1e3ccSAndroid Build Coastguard Worker // const long long pos_ = pCluster->m_pos;
2168*77c1e3ccSAndroid Build Coastguard Worker // assert(pos_);
2169*77c1e3ccSAndroid Build Coastguard Worker // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2170*77c1e3ccSAndroid Build Coastguard Worker
2171*77c1e3ccSAndroid Build Coastguard Worker const long long pos = pCluster->GetPosition();
2172*77c1e3ccSAndroid Build Coastguard Worker assert(pos >= 0);
2173*77c1e3ccSAndroid Build Coastguard Worker
2174*77c1e3ccSAndroid Build Coastguard Worker if (pos < tp.m_pos)
2175*77c1e3ccSAndroid Build Coastguard Worker i = k + 1;
2176*77c1e3ccSAndroid Build Coastguard Worker else if (pos > tp.m_pos)
2177*77c1e3ccSAndroid Build Coastguard Worker j = k;
2178*77c1e3ccSAndroid Build Coastguard Worker else
2179*77c1e3ccSAndroid Build Coastguard Worker return pCluster->GetEntry(cp, tp);
2180*77c1e3ccSAndroid Build Coastguard Worker }
2181*77c1e3ccSAndroid Build Coastguard Worker
2182*77c1e3ccSAndroid Build Coastguard Worker assert(i == j);
2183*77c1e3ccSAndroid Build Coastguard Worker // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2184*77c1e3ccSAndroid Build Coastguard Worker
2185*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1);
2186*77c1e3ccSAndroid Build Coastguard Worker if (pCluster == NULL)
2187*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2188*77c1e3ccSAndroid Build Coastguard Worker
2189*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t idx = i - m_clusters;
2190*77c1e3ccSAndroid Build Coastguard Worker
2191*77c1e3ccSAndroid Build Coastguard Worker if (!PreloadCluster(pCluster, idx)) {
2192*77c1e3ccSAndroid Build Coastguard Worker delete pCluster;
2193*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2194*77c1e3ccSAndroid Build Coastguard Worker }
2195*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters);
2196*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusterPreloadCount > 0);
2197*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters[idx] == pCluster);
2198*77c1e3ccSAndroid Build Coastguard Worker
2199*77c1e3ccSAndroid Build Coastguard Worker return pCluster->GetEntry(cp, tp);
2200*77c1e3ccSAndroid Build Coastguard Worker }
2201*77c1e3ccSAndroid Build Coastguard Worker
FindOrPreloadCluster(long long requested_pos)2202*77c1e3ccSAndroid Build Coastguard Worker const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) {
2203*77c1e3ccSAndroid Build Coastguard Worker if (requested_pos < 0)
2204*77c1e3ccSAndroid Build Coastguard Worker return 0;
2205*77c1e3ccSAndroid Build Coastguard Worker
2206*77c1e3ccSAndroid Build Coastguard Worker Cluster** const ii = m_clusters;
2207*77c1e3ccSAndroid Build Coastguard Worker Cluster** i = ii;
2208*77c1e3ccSAndroid Build Coastguard Worker
2209*77c1e3ccSAndroid Build Coastguard Worker const long count = m_clusterCount + m_clusterPreloadCount;
2210*77c1e3ccSAndroid Build Coastguard Worker
2211*77c1e3ccSAndroid Build Coastguard Worker Cluster** const jj = ii + count;
2212*77c1e3ccSAndroid Build Coastguard Worker Cluster** j = jj;
2213*77c1e3ccSAndroid Build Coastguard Worker
2214*77c1e3ccSAndroid Build Coastguard Worker while (i < j) {
2215*77c1e3ccSAndroid Build Coastguard Worker // INVARIANT:
2216*77c1e3ccSAndroid Build Coastguard Worker //[ii, i) < pTP->m_pos
2217*77c1e3ccSAndroid Build Coastguard Worker //[i, j) ?
2218*77c1e3ccSAndroid Build Coastguard Worker //[j, jj) > pTP->m_pos
2219*77c1e3ccSAndroid Build Coastguard Worker
2220*77c1e3ccSAndroid Build Coastguard Worker Cluster** const k = i + (j - i) / 2;
2221*77c1e3ccSAndroid Build Coastguard Worker assert(k < jj);
2222*77c1e3ccSAndroid Build Coastguard Worker
2223*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = *k;
2224*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
2225*77c1e3ccSAndroid Build Coastguard Worker
2226*77c1e3ccSAndroid Build Coastguard Worker // const long long pos_ = pCluster->m_pos;
2227*77c1e3ccSAndroid Build Coastguard Worker // assert(pos_);
2228*77c1e3ccSAndroid Build Coastguard Worker // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2229*77c1e3ccSAndroid Build Coastguard Worker
2230*77c1e3ccSAndroid Build Coastguard Worker const long long pos = pCluster->GetPosition();
2231*77c1e3ccSAndroid Build Coastguard Worker assert(pos >= 0);
2232*77c1e3ccSAndroid Build Coastguard Worker
2233*77c1e3ccSAndroid Build Coastguard Worker if (pos < requested_pos)
2234*77c1e3ccSAndroid Build Coastguard Worker i = k + 1;
2235*77c1e3ccSAndroid Build Coastguard Worker else if (pos > requested_pos)
2236*77c1e3ccSAndroid Build Coastguard Worker j = k;
2237*77c1e3ccSAndroid Build Coastguard Worker else
2238*77c1e3ccSAndroid Build Coastguard Worker return pCluster;
2239*77c1e3ccSAndroid Build Coastguard Worker }
2240*77c1e3ccSAndroid Build Coastguard Worker
2241*77c1e3ccSAndroid Build Coastguard Worker assert(i == j);
2242*77c1e3ccSAndroid Build Coastguard Worker // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2243*77c1e3ccSAndroid Build Coastguard Worker
2244*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = Cluster::Create(this, -1, requested_pos);
2245*77c1e3ccSAndroid Build Coastguard Worker if (pCluster == NULL)
2246*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2247*77c1e3ccSAndroid Build Coastguard Worker
2248*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t idx = i - m_clusters;
2249*77c1e3ccSAndroid Build Coastguard Worker
2250*77c1e3ccSAndroid Build Coastguard Worker if (!PreloadCluster(pCluster, idx)) {
2251*77c1e3ccSAndroid Build Coastguard Worker delete pCluster;
2252*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2253*77c1e3ccSAndroid Build Coastguard Worker }
2254*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters);
2255*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusterPreloadCount > 0);
2256*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters[idx] == pCluster);
2257*77c1e3ccSAndroid Build Coastguard Worker
2258*77c1e3ccSAndroid Build Coastguard Worker return pCluster;
2259*77c1e3ccSAndroid Build Coastguard Worker }
2260*77c1e3ccSAndroid Build Coastguard Worker
CuePoint(long idx,long long pos)2261*77c1e3ccSAndroid Build Coastguard Worker CuePoint::CuePoint(long idx, long long pos)
2262*77c1e3ccSAndroid Build Coastguard Worker : m_element_start(0),
2263*77c1e3ccSAndroid Build Coastguard Worker m_element_size(0),
2264*77c1e3ccSAndroid Build Coastguard Worker m_index(idx),
2265*77c1e3ccSAndroid Build Coastguard Worker m_timecode(-1 * pos),
2266*77c1e3ccSAndroid Build Coastguard Worker m_track_positions(NULL),
2267*77c1e3ccSAndroid Build Coastguard Worker m_track_positions_count(0) {
2268*77c1e3ccSAndroid Build Coastguard Worker assert(pos > 0);
2269*77c1e3ccSAndroid Build Coastguard Worker }
2270*77c1e3ccSAndroid Build Coastguard Worker
~CuePoint()2271*77c1e3ccSAndroid Build Coastguard Worker CuePoint::~CuePoint() { delete[] m_track_positions; }
2272*77c1e3ccSAndroid Build Coastguard Worker
Load(IMkvReader * pReader)2273*77c1e3ccSAndroid Build Coastguard Worker bool CuePoint::Load(IMkvReader* pReader) {
2274*77c1e3ccSAndroid Build Coastguard Worker // odbgstream os;
2275*77c1e3ccSAndroid Build Coastguard Worker // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;
2276*77c1e3ccSAndroid Build Coastguard Worker
2277*77c1e3ccSAndroid Build Coastguard Worker if (m_timecode >= 0) // already loaded
2278*77c1e3ccSAndroid Build Coastguard Worker return true;
2279*77c1e3ccSAndroid Build Coastguard Worker
2280*77c1e3ccSAndroid Build Coastguard Worker assert(m_track_positions == NULL);
2281*77c1e3ccSAndroid Build Coastguard Worker assert(m_track_positions_count == 0);
2282*77c1e3ccSAndroid Build Coastguard Worker
2283*77c1e3ccSAndroid Build Coastguard Worker long long pos_ = -m_timecode;
2284*77c1e3ccSAndroid Build Coastguard Worker const long long element_start = pos_;
2285*77c1e3ccSAndroid Build Coastguard Worker
2286*77c1e3ccSAndroid Build Coastguard Worker long long stop;
2287*77c1e3ccSAndroid Build Coastguard Worker
2288*77c1e3ccSAndroid Build Coastguard Worker {
2289*77c1e3ccSAndroid Build Coastguard Worker long len;
2290*77c1e3ccSAndroid Build Coastguard Worker
2291*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos_, len);
2292*77c1e3ccSAndroid Build Coastguard Worker if (id != libwebm::kMkvCuePoint)
2293*77c1e3ccSAndroid Build Coastguard Worker return false;
2294*77c1e3ccSAndroid Build Coastguard Worker
2295*77c1e3ccSAndroid Build Coastguard Worker pos_ += len; // consume ID
2296*77c1e3ccSAndroid Build Coastguard Worker
2297*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos_, len);
2298*77c1e3ccSAndroid Build Coastguard Worker assert(size >= 0);
2299*77c1e3ccSAndroid Build Coastguard Worker
2300*77c1e3ccSAndroid Build Coastguard Worker pos_ += len; // consume Size field
2301*77c1e3ccSAndroid Build Coastguard Worker // pos_ now points to start of payload
2302*77c1e3ccSAndroid Build Coastguard Worker
2303*77c1e3ccSAndroid Build Coastguard Worker stop = pos_ + size;
2304*77c1e3ccSAndroid Build Coastguard Worker }
2305*77c1e3ccSAndroid Build Coastguard Worker
2306*77c1e3ccSAndroid Build Coastguard Worker const long long element_size = stop - element_start;
2307*77c1e3ccSAndroid Build Coastguard Worker
2308*77c1e3ccSAndroid Build Coastguard Worker long long pos = pos_;
2309*77c1e3ccSAndroid Build Coastguard Worker
2310*77c1e3ccSAndroid Build Coastguard Worker // First count number of track positions
2311*77c1e3ccSAndroid Build Coastguard Worker unsigned long long track_positions_count = 0;
2312*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
2313*77c1e3ccSAndroid Build Coastguard Worker long len;
2314*77c1e3ccSAndroid Build Coastguard Worker
2315*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
2316*77c1e3ccSAndroid Build Coastguard Worker if ((id < 0) || (pos + len > stop)) {
2317*77c1e3ccSAndroid Build Coastguard Worker return false;
2318*77c1e3ccSAndroid Build Coastguard Worker }
2319*77c1e3ccSAndroid Build Coastguard Worker
2320*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
2321*77c1e3ccSAndroid Build Coastguard Worker
2322*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
2323*77c1e3ccSAndroid Build Coastguard Worker if ((size < 0) || (pos + len > stop)) {
2324*77c1e3ccSAndroid Build Coastguard Worker return false;
2325*77c1e3ccSAndroid Build Coastguard Worker }
2326*77c1e3ccSAndroid Build Coastguard Worker
2327*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume Size field
2328*77c1e3ccSAndroid Build Coastguard Worker if ((pos + size) > stop) {
2329*77c1e3ccSAndroid Build Coastguard Worker return false;
2330*77c1e3ccSAndroid Build Coastguard Worker }
2331*77c1e3ccSAndroid Build Coastguard Worker
2332*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCueTime)
2333*77c1e3ccSAndroid Build Coastguard Worker m_timecode = UnserializeUInt(pReader, pos, size);
2334*77c1e3ccSAndroid Build Coastguard Worker
2335*77c1e3ccSAndroid Build Coastguard Worker else if (id == libwebm::kMkvCueTrackPositions) {
2336*77c1e3ccSAndroid Build Coastguard Worker ++track_positions_count;
2337*77c1e3ccSAndroid Build Coastguard Worker if (track_positions_count > UINT_MAX)
2338*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
2339*77c1e3ccSAndroid Build Coastguard Worker }
2340*77c1e3ccSAndroid Build Coastguard Worker
2341*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
2342*77c1e3ccSAndroid Build Coastguard Worker }
2343*77c1e3ccSAndroid Build Coastguard Worker
2344*77c1e3ccSAndroid Build Coastguard Worker m_track_positions_count = static_cast<size_t>(track_positions_count);
2345*77c1e3ccSAndroid Build Coastguard Worker
2346*77c1e3ccSAndroid Build Coastguard Worker if (m_timecode < 0 || m_track_positions_count <= 0) {
2347*77c1e3ccSAndroid Build Coastguard Worker return false;
2348*77c1e3ccSAndroid Build Coastguard Worker }
2349*77c1e3ccSAndroid Build Coastguard Worker
2350*77c1e3ccSAndroid Build Coastguard Worker // os << "CuePoint::Load(cont'd): idpos=" << idpos
2351*77c1e3ccSAndroid Build Coastguard Worker // << " timecode=" << m_timecode
2352*77c1e3ccSAndroid Build Coastguard Worker // << endl;
2353*77c1e3ccSAndroid Build Coastguard Worker
2354*77c1e3ccSAndroid Build Coastguard Worker m_track_positions = new (std::nothrow) TrackPosition[m_track_positions_count];
2355*77c1e3ccSAndroid Build Coastguard Worker if (m_track_positions == NULL)
2356*77c1e3ccSAndroid Build Coastguard Worker return false;
2357*77c1e3ccSAndroid Build Coastguard Worker
2358*77c1e3ccSAndroid Build Coastguard Worker // Now parse track positions
2359*77c1e3ccSAndroid Build Coastguard Worker
2360*77c1e3ccSAndroid Build Coastguard Worker TrackPosition* p = m_track_positions;
2361*77c1e3ccSAndroid Build Coastguard Worker pos = pos_;
2362*77c1e3ccSAndroid Build Coastguard Worker
2363*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
2364*77c1e3ccSAndroid Build Coastguard Worker long len;
2365*77c1e3ccSAndroid Build Coastguard Worker
2366*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
2367*77c1e3ccSAndroid Build Coastguard Worker if (id < 0 || (pos + len) > stop)
2368*77c1e3ccSAndroid Build Coastguard Worker return false;
2369*77c1e3ccSAndroid Build Coastguard Worker
2370*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
2371*77c1e3ccSAndroid Build Coastguard Worker
2372*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
2373*77c1e3ccSAndroid Build Coastguard Worker assert(size >= 0);
2374*77c1e3ccSAndroid Build Coastguard Worker assert((pos + len) <= stop);
2375*77c1e3ccSAndroid Build Coastguard Worker
2376*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume Size field
2377*77c1e3ccSAndroid Build Coastguard Worker assert((pos + size) <= stop);
2378*77c1e3ccSAndroid Build Coastguard Worker
2379*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCueTrackPositions) {
2380*77c1e3ccSAndroid Build Coastguard Worker TrackPosition& tp = *p++;
2381*77c1e3ccSAndroid Build Coastguard Worker if (!tp.Parse(pReader, pos, size)) {
2382*77c1e3ccSAndroid Build Coastguard Worker return false;
2383*77c1e3ccSAndroid Build Coastguard Worker }
2384*77c1e3ccSAndroid Build Coastguard Worker }
2385*77c1e3ccSAndroid Build Coastguard Worker
2386*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
2387*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
2388*77c1e3ccSAndroid Build Coastguard Worker return false;
2389*77c1e3ccSAndroid Build Coastguard Worker }
2390*77c1e3ccSAndroid Build Coastguard Worker
2391*77c1e3ccSAndroid Build Coastguard Worker assert(size_t(p - m_track_positions) == m_track_positions_count);
2392*77c1e3ccSAndroid Build Coastguard Worker
2393*77c1e3ccSAndroid Build Coastguard Worker m_element_start = element_start;
2394*77c1e3ccSAndroid Build Coastguard Worker m_element_size = element_size;
2395*77c1e3ccSAndroid Build Coastguard Worker
2396*77c1e3ccSAndroid Build Coastguard Worker return true;
2397*77c1e3ccSAndroid Build Coastguard Worker }
2398*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * pReader,long long start_,long long size_)2399*77c1e3ccSAndroid Build Coastguard Worker bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
2400*77c1e3ccSAndroid Build Coastguard Worker long long size_) {
2401*77c1e3ccSAndroid Build Coastguard Worker const long long stop = start_ + size_;
2402*77c1e3ccSAndroid Build Coastguard Worker long long pos = start_;
2403*77c1e3ccSAndroid Build Coastguard Worker
2404*77c1e3ccSAndroid Build Coastguard Worker m_track = -1;
2405*77c1e3ccSAndroid Build Coastguard Worker m_pos = -1;
2406*77c1e3ccSAndroid Build Coastguard Worker m_block = 1; // default
2407*77c1e3ccSAndroid Build Coastguard Worker
2408*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
2409*77c1e3ccSAndroid Build Coastguard Worker long len;
2410*77c1e3ccSAndroid Build Coastguard Worker
2411*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
2412*77c1e3ccSAndroid Build Coastguard Worker if ((id < 0) || ((pos + len) > stop)) {
2413*77c1e3ccSAndroid Build Coastguard Worker return false;
2414*77c1e3ccSAndroid Build Coastguard Worker }
2415*77c1e3ccSAndroid Build Coastguard Worker
2416*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
2417*77c1e3ccSAndroid Build Coastguard Worker
2418*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
2419*77c1e3ccSAndroid Build Coastguard Worker if ((size < 0) || ((pos + len) > stop)) {
2420*77c1e3ccSAndroid Build Coastguard Worker return false;
2421*77c1e3ccSAndroid Build Coastguard Worker }
2422*77c1e3ccSAndroid Build Coastguard Worker
2423*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume Size field
2424*77c1e3ccSAndroid Build Coastguard Worker if ((pos + size) > stop) {
2425*77c1e3ccSAndroid Build Coastguard Worker return false;
2426*77c1e3ccSAndroid Build Coastguard Worker }
2427*77c1e3ccSAndroid Build Coastguard Worker
2428*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCueTrack)
2429*77c1e3ccSAndroid Build Coastguard Worker m_track = UnserializeUInt(pReader, pos, size);
2430*77c1e3ccSAndroid Build Coastguard Worker else if (id == libwebm::kMkvCueClusterPosition)
2431*77c1e3ccSAndroid Build Coastguard Worker m_pos = UnserializeUInt(pReader, pos, size);
2432*77c1e3ccSAndroid Build Coastguard Worker else if (id == libwebm::kMkvCueBlockNumber)
2433*77c1e3ccSAndroid Build Coastguard Worker m_block = UnserializeUInt(pReader, pos, size);
2434*77c1e3ccSAndroid Build Coastguard Worker
2435*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
2436*77c1e3ccSAndroid Build Coastguard Worker }
2437*77c1e3ccSAndroid Build Coastguard Worker
2438*77c1e3ccSAndroid Build Coastguard Worker if ((m_pos < 0) || (m_track <= 0) || (m_block < 0) || (m_block > LONG_MAX)) {
2439*77c1e3ccSAndroid Build Coastguard Worker return false;
2440*77c1e3ccSAndroid Build Coastguard Worker }
2441*77c1e3ccSAndroid Build Coastguard Worker
2442*77c1e3ccSAndroid Build Coastguard Worker return true;
2443*77c1e3ccSAndroid Build Coastguard Worker }
2444*77c1e3ccSAndroid Build Coastguard Worker
Find(const Track * pTrack) const2445*77c1e3ccSAndroid Build Coastguard Worker const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const {
2446*77c1e3ccSAndroid Build Coastguard Worker if (pTrack == NULL) {
2447*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2448*77c1e3ccSAndroid Build Coastguard Worker }
2449*77c1e3ccSAndroid Build Coastguard Worker
2450*77c1e3ccSAndroid Build Coastguard Worker const long long n = pTrack->GetNumber();
2451*77c1e3ccSAndroid Build Coastguard Worker
2452*77c1e3ccSAndroid Build Coastguard Worker const TrackPosition* i = m_track_positions;
2453*77c1e3ccSAndroid Build Coastguard Worker const TrackPosition* const j = i + m_track_positions_count;
2454*77c1e3ccSAndroid Build Coastguard Worker
2455*77c1e3ccSAndroid Build Coastguard Worker while (i != j) {
2456*77c1e3ccSAndroid Build Coastguard Worker const TrackPosition& p = *i++;
2457*77c1e3ccSAndroid Build Coastguard Worker
2458*77c1e3ccSAndroid Build Coastguard Worker if (p.m_track == n)
2459*77c1e3ccSAndroid Build Coastguard Worker return &p;
2460*77c1e3ccSAndroid Build Coastguard Worker }
2461*77c1e3ccSAndroid Build Coastguard Worker
2462*77c1e3ccSAndroid Build Coastguard Worker return NULL; // no matching track number found
2463*77c1e3ccSAndroid Build Coastguard Worker }
2464*77c1e3ccSAndroid Build Coastguard Worker
GetTimeCode() const2465*77c1e3ccSAndroid Build Coastguard Worker long long CuePoint::GetTimeCode() const { return m_timecode; }
2466*77c1e3ccSAndroid Build Coastguard Worker
GetTime(const Segment * pSegment) const2467*77c1e3ccSAndroid Build Coastguard Worker long long CuePoint::GetTime(const Segment* pSegment) const {
2468*77c1e3ccSAndroid Build Coastguard Worker assert(pSegment);
2469*77c1e3ccSAndroid Build Coastguard Worker assert(m_timecode >= 0);
2470*77c1e3ccSAndroid Build Coastguard Worker
2471*77c1e3ccSAndroid Build Coastguard Worker const SegmentInfo* const pInfo = pSegment->GetInfo();
2472*77c1e3ccSAndroid Build Coastguard Worker assert(pInfo);
2473*77c1e3ccSAndroid Build Coastguard Worker
2474*77c1e3ccSAndroid Build Coastguard Worker const long long scale = pInfo->GetTimeCodeScale();
2475*77c1e3ccSAndroid Build Coastguard Worker assert(scale >= 1);
2476*77c1e3ccSAndroid Build Coastguard Worker
2477*77c1e3ccSAndroid Build Coastguard Worker const long long time = scale * m_timecode;
2478*77c1e3ccSAndroid Build Coastguard Worker
2479*77c1e3ccSAndroid Build Coastguard Worker return time;
2480*77c1e3ccSAndroid Build Coastguard Worker }
2481*77c1e3ccSAndroid Build Coastguard Worker
DoneParsing() const2482*77c1e3ccSAndroid Build Coastguard Worker bool Segment::DoneParsing() const {
2483*77c1e3ccSAndroid Build Coastguard Worker if (m_size < 0) {
2484*77c1e3ccSAndroid Build Coastguard Worker long long total, avail;
2485*77c1e3ccSAndroid Build Coastguard Worker
2486*77c1e3ccSAndroid Build Coastguard Worker const int status = m_pReader->Length(&total, &avail);
2487*77c1e3ccSAndroid Build Coastguard Worker
2488*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
2489*77c1e3ccSAndroid Build Coastguard Worker return true; // must assume done
2490*77c1e3ccSAndroid Build Coastguard Worker
2491*77c1e3ccSAndroid Build Coastguard Worker if (total < 0)
2492*77c1e3ccSAndroid Build Coastguard Worker return false; // assume live stream
2493*77c1e3ccSAndroid Build Coastguard Worker
2494*77c1e3ccSAndroid Build Coastguard Worker return (m_pos >= total);
2495*77c1e3ccSAndroid Build Coastguard Worker }
2496*77c1e3ccSAndroid Build Coastguard Worker
2497*77c1e3ccSAndroid Build Coastguard Worker const long long stop = m_start + m_size;
2498*77c1e3ccSAndroid Build Coastguard Worker
2499*77c1e3ccSAndroid Build Coastguard Worker return (m_pos >= stop);
2500*77c1e3ccSAndroid Build Coastguard Worker }
2501*77c1e3ccSAndroid Build Coastguard Worker
GetFirst() const2502*77c1e3ccSAndroid Build Coastguard Worker const Cluster* Segment::GetFirst() const {
2503*77c1e3ccSAndroid Build Coastguard Worker if ((m_clusters == NULL) || (m_clusterCount <= 0))
2504*77c1e3ccSAndroid Build Coastguard Worker return &m_eos;
2505*77c1e3ccSAndroid Build Coastguard Worker
2506*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = m_clusters[0];
2507*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
2508*77c1e3ccSAndroid Build Coastguard Worker
2509*77c1e3ccSAndroid Build Coastguard Worker return pCluster;
2510*77c1e3ccSAndroid Build Coastguard Worker }
2511*77c1e3ccSAndroid Build Coastguard Worker
GetLast() const2512*77c1e3ccSAndroid Build Coastguard Worker const Cluster* Segment::GetLast() const {
2513*77c1e3ccSAndroid Build Coastguard Worker if ((m_clusters == NULL) || (m_clusterCount <= 0))
2514*77c1e3ccSAndroid Build Coastguard Worker return &m_eos;
2515*77c1e3ccSAndroid Build Coastguard Worker
2516*77c1e3ccSAndroid Build Coastguard Worker const long idx = m_clusterCount - 1;
2517*77c1e3ccSAndroid Build Coastguard Worker
2518*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = m_clusters[idx];
2519*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
2520*77c1e3ccSAndroid Build Coastguard Worker
2521*77c1e3ccSAndroid Build Coastguard Worker return pCluster;
2522*77c1e3ccSAndroid Build Coastguard Worker }
2523*77c1e3ccSAndroid Build Coastguard Worker
GetCount() const2524*77c1e3ccSAndroid Build Coastguard Worker unsigned long Segment::GetCount() const { return m_clusterCount; }
2525*77c1e3ccSAndroid Build Coastguard Worker
GetNext(const Cluster * pCurr)2526*77c1e3ccSAndroid Build Coastguard Worker const Cluster* Segment::GetNext(const Cluster* pCurr) {
2527*77c1e3ccSAndroid Build Coastguard Worker assert(pCurr);
2528*77c1e3ccSAndroid Build Coastguard Worker assert(pCurr != &m_eos);
2529*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters);
2530*77c1e3ccSAndroid Build Coastguard Worker
2531*77c1e3ccSAndroid Build Coastguard Worker long idx = pCurr->m_index;
2532*77c1e3ccSAndroid Build Coastguard Worker
2533*77c1e3ccSAndroid Build Coastguard Worker if (idx >= 0) {
2534*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusterCount > 0);
2535*77c1e3ccSAndroid Build Coastguard Worker assert(idx < m_clusterCount);
2536*77c1e3ccSAndroid Build Coastguard Worker assert(pCurr == m_clusters[idx]);
2537*77c1e3ccSAndroid Build Coastguard Worker
2538*77c1e3ccSAndroid Build Coastguard Worker ++idx;
2539*77c1e3ccSAndroid Build Coastguard Worker
2540*77c1e3ccSAndroid Build Coastguard Worker if (idx >= m_clusterCount)
2541*77c1e3ccSAndroid Build Coastguard Worker return &m_eos; // caller will LoadCluster as desired
2542*77c1e3ccSAndroid Build Coastguard Worker
2543*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pNext = m_clusters[idx];
2544*77c1e3ccSAndroid Build Coastguard Worker assert(pNext);
2545*77c1e3ccSAndroid Build Coastguard Worker assert(pNext->m_index >= 0);
2546*77c1e3ccSAndroid Build Coastguard Worker assert(pNext->m_index == idx);
2547*77c1e3ccSAndroid Build Coastguard Worker
2548*77c1e3ccSAndroid Build Coastguard Worker return pNext;
2549*77c1e3ccSAndroid Build Coastguard Worker }
2550*77c1e3ccSAndroid Build Coastguard Worker
2551*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusterPreloadCount > 0);
2552*77c1e3ccSAndroid Build Coastguard Worker
2553*77c1e3ccSAndroid Build Coastguard Worker long long pos = pCurr->m_element_start;
2554*77c1e3ccSAndroid Build Coastguard Worker
2555*77c1e3ccSAndroid Build Coastguard Worker assert(m_size >= 0); // TODO
2556*77c1e3ccSAndroid Build Coastguard Worker const long long stop = m_start + m_size; // end of segment
2557*77c1e3ccSAndroid Build Coastguard Worker
2558*77c1e3ccSAndroid Build Coastguard Worker {
2559*77c1e3ccSAndroid Build Coastguard Worker long len;
2560*77c1e3ccSAndroid Build Coastguard Worker
2561*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(m_pReader, pos, len);
2562*77c1e3ccSAndroid Build Coastguard Worker assert(result == 0);
2563*77c1e3ccSAndroid Build Coastguard Worker assert((pos + len) <= stop); // TODO
2564*77c1e3ccSAndroid Build Coastguard Worker if (result != 0)
2565*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2566*77c1e3ccSAndroid Build Coastguard Worker
2567*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(m_pReader, pos, len);
2568*77c1e3ccSAndroid Build Coastguard Worker if (id != libwebm::kMkvCluster)
2569*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2570*77c1e3ccSAndroid Build Coastguard Worker
2571*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
2572*77c1e3ccSAndroid Build Coastguard Worker
2573*77c1e3ccSAndroid Build Coastguard Worker // Read Size
2574*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(m_pReader, pos, len);
2575*77c1e3ccSAndroid Build Coastguard Worker assert(result == 0); // TODO
2576*77c1e3ccSAndroid Build Coastguard Worker assert((pos + len) <= stop); // TODO
2577*77c1e3ccSAndroid Build Coastguard Worker
2578*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(m_pReader, pos, len);
2579*77c1e3ccSAndroid Build Coastguard Worker assert(size > 0); // TODO
2580*77c1e3ccSAndroid Build Coastguard Worker // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
2581*77c1e3ccSAndroid Build Coastguard Worker
2582*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of element
2583*77c1e3ccSAndroid Build Coastguard Worker assert((pos + size) <= stop); // TODO
2584*77c1e3ccSAndroid Build Coastguard Worker
2585*77c1e3ccSAndroid Build Coastguard Worker // Pos now points to start of payload
2586*77c1e3ccSAndroid Build Coastguard Worker
2587*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
2588*77c1e3ccSAndroid Build Coastguard Worker }
2589*77c1e3ccSAndroid Build Coastguard Worker
2590*77c1e3ccSAndroid Build Coastguard Worker long long off_next = 0;
2591*77c1e3ccSAndroid Build Coastguard Worker
2592*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
2593*77c1e3ccSAndroid Build Coastguard Worker long len;
2594*77c1e3ccSAndroid Build Coastguard Worker
2595*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(m_pReader, pos, len);
2596*77c1e3ccSAndroid Build Coastguard Worker assert(result == 0);
2597*77c1e3ccSAndroid Build Coastguard Worker assert((pos + len) <= stop); // TODO
2598*77c1e3ccSAndroid Build Coastguard Worker if (result != 0)
2599*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2600*77c1e3ccSAndroid Build Coastguard Worker
2601*77c1e3ccSAndroid Build Coastguard Worker const long long idpos = pos; // pos of next (potential) cluster
2602*77c1e3ccSAndroid Build Coastguard Worker
2603*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(m_pReader, idpos, len);
2604*77c1e3ccSAndroid Build Coastguard Worker if (id < 0)
2605*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2606*77c1e3ccSAndroid Build Coastguard Worker
2607*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
2608*77c1e3ccSAndroid Build Coastguard Worker
2609*77c1e3ccSAndroid Build Coastguard Worker // Read Size
2610*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(m_pReader, pos, len);
2611*77c1e3ccSAndroid Build Coastguard Worker assert(result == 0); // TODO
2612*77c1e3ccSAndroid Build Coastguard Worker assert((pos + len) <= stop); // TODO
2613*77c1e3ccSAndroid Build Coastguard Worker
2614*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(m_pReader, pos, len);
2615*77c1e3ccSAndroid Build Coastguard Worker assert(size >= 0); // TODO
2616*77c1e3ccSAndroid Build Coastguard Worker
2617*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of element
2618*77c1e3ccSAndroid Build Coastguard Worker assert((pos + size) <= stop); // TODO
2619*77c1e3ccSAndroid Build Coastguard Worker
2620*77c1e3ccSAndroid Build Coastguard Worker // Pos now points to start of payload
2621*77c1e3ccSAndroid Build Coastguard Worker
2622*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // weird
2623*77c1e3ccSAndroid Build Coastguard Worker continue;
2624*77c1e3ccSAndroid Build Coastguard Worker
2625*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCluster) {
2626*77c1e3ccSAndroid Build Coastguard Worker const long long off_next_ = idpos - m_start;
2627*77c1e3ccSAndroid Build Coastguard Worker
2628*77c1e3ccSAndroid Build Coastguard Worker long long pos_;
2629*77c1e3ccSAndroid Build Coastguard Worker long len_;
2630*77c1e3ccSAndroid Build Coastguard Worker
2631*77c1e3ccSAndroid Build Coastguard Worker const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_);
2632*77c1e3ccSAndroid Build Coastguard Worker
2633*77c1e3ccSAndroid Build Coastguard Worker assert(status >= 0);
2634*77c1e3ccSAndroid Build Coastguard Worker
2635*77c1e3ccSAndroid Build Coastguard Worker if (status > 0) {
2636*77c1e3ccSAndroid Build Coastguard Worker off_next = off_next_;
2637*77c1e3ccSAndroid Build Coastguard Worker break;
2638*77c1e3ccSAndroid Build Coastguard Worker }
2639*77c1e3ccSAndroid Build Coastguard Worker }
2640*77c1e3ccSAndroid Build Coastguard Worker
2641*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
2642*77c1e3ccSAndroid Build Coastguard Worker }
2643*77c1e3ccSAndroid Build Coastguard Worker
2644*77c1e3ccSAndroid Build Coastguard Worker if (off_next <= 0)
2645*77c1e3ccSAndroid Build Coastguard Worker return 0;
2646*77c1e3ccSAndroid Build Coastguard Worker
2647*77c1e3ccSAndroid Build Coastguard Worker Cluster** const ii = m_clusters + m_clusterCount;
2648*77c1e3ccSAndroid Build Coastguard Worker Cluster** i = ii;
2649*77c1e3ccSAndroid Build Coastguard Worker
2650*77c1e3ccSAndroid Build Coastguard Worker Cluster** const jj = ii + m_clusterPreloadCount;
2651*77c1e3ccSAndroid Build Coastguard Worker Cluster** j = jj;
2652*77c1e3ccSAndroid Build Coastguard Worker
2653*77c1e3ccSAndroid Build Coastguard Worker while (i < j) {
2654*77c1e3ccSAndroid Build Coastguard Worker // INVARIANT:
2655*77c1e3ccSAndroid Build Coastguard Worker //[0, i) < pos_next
2656*77c1e3ccSAndroid Build Coastguard Worker //[i, j) ?
2657*77c1e3ccSAndroid Build Coastguard Worker //[j, jj) > pos_next
2658*77c1e3ccSAndroid Build Coastguard Worker
2659*77c1e3ccSAndroid Build Coastguard Worker Cluster** const k = i + (j - i) / 2;
2660*77c1e3ccSAndroid Build Coastguard Worker assert(k < jj);
2661*77c1e3ccSAndroid Build Coastguard Worker
2662*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pNext = *k;
2663*77c1e3ccSAndroid Build Coastguard Worker assert(pNext);
2664*77c1e3ccSAndroid Build Coastguard Worker assert(pNext->m_index < 0);
2665*77c1e3ccSAndroid Build Coastguard Worker
2666*77c1e3ccSAndroid Build Coastguard Worker // const long long pos_ = pNext->m_pos;
2667*77c1e3ccSAndroid Build Coastguard Worker // assert(pos_);
2668*77c1e3ccSAndroid Build Coastguard Worker // pos = pos_ * ((pos_ < 0) ? -1 : 1);
2669*77c1e3ccSAndroid Build Coastguard Worker
2670*77c1e3ccSAndroid Build Coastguard Worker pos = pNext->GetPosition();
2671*77c1e3ccSAndroid Build Coastguard Worker
2672*77c1e3ccSAndroid Build Coastguard Worker if (pos < off_next)
2673*77c1e3ccSAndroid Build Coastguard Worker i = k + 1;
2674*77c1e3ccSAndroid Build Coastguard Worker else if (pos > off_next)
2675*77c1e3ccSAndroid Build Coastguard Worker j = k;
2676*77c1e3ccSAndroid Build Coastguard Worker else
2677*77c1e3ccSAndroid Build Coastguard Worker return pNext;
2678*77c1e3ccSAndroid Build Coastguard Worker }
2679*77c1e3ccSAndroid Build Coastguard Worker
2680*77c1e3ccSAndroid Build Coastguard Worker assert(i == j);
2681*77c1e3ccSAndroid Build Coastguard Worker
2682*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pNext = Cluster::Create(this, -1, off_next);
2683*77c1e3ccSAndroid Build Coastguard Worker if (pNext == NULL)
2684*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2685*77c1e3ccSAndroid Build Coastguard Worker
2686*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t idx_next = i - m_clusters; // insertion position
2687*77c1e3ccSAndroid Build Coastguard Worker
2688*77c1e3ccSAndroid Build Coastguard Worker if (!PreloadCluster(pNext, idx_next)) {
2689*77c1e3ccSAndroid Build Coastguard Worker delete pNext;
2690*77c1e3ccSAndroid Build Coastguard Worker return NULL;
2691*77c1e3ccSAndroid Build Coastguard Worker }
2692*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters);
2693*77c1e3ccSAndroid Build Coastguard Worker assert(idx_next < m_clusterSize);
2694*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters[idx_next] == pNext);
2695*77c1e3ccSAndroid Build Coastguard Worker
2696*77c1e3ccSAndroid Build Coastguard Worker return pNext;
2697*77c1e3ccSAndroid Build Coastguard Worker }
2698*77c1e3ccSAndroid Build Coastguard Worker
ParseNext(const Cluster * pCurr,const Cluster * & pResult,long long & pos,long & len)2699*77c1e3ccSAndroid Build Coastguard Worker long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
2700*77c1e3ccSAndroid Build Coastguard Worker long long& pos, long& len) {
2701*77c1e3ccSAndroid Build Coastguard Worker assert(pCurr);
2702*77c1e3ccSAndroid Build Coastguard Worker assert(!pCurr->EOS());
2703*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters);
2704*77c1e3ccSAndroid Build Coastguard Worker
2705*77c1e3ccSAndroid Build Coastguard Worker pResult = 0;
2706*77c1e3ccSAndroid Build Coastguard Worker
2707*77c1e3ccSAndroid Build Coastguard Worker if (pCurr->m_index >= 0) { // loaded (not merely preloaded)
2708*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters[pCurr->m_index] == pCurr);
2709*77c1e3ccSAndroid Build Coastguard Worker
2710*77c1e3ccSAndroid Build Coastguard Worker const long next_idx = pCurr->m_index + 1;
2711*77c1e3ccSAndroid Build Coastguard Worker
2712*77c1e3ccSAndroid Build Coastguard Worker if (next_idx < m_clusterCount) {
2713*77c1e3ccSAndroid Build Coastguard Worker pResult = m_clusters[next_idx];
2714*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
2715*77c1e3ccSAndroid Build Coastguard Worker }
2716*77c1e3ccSAndroid Build Coastguard Worker
2717*77c1e3ccSAndroid Build Coastguard Worker // curr cluster is last among loaded
2718*77c1e3ccSAndroid Build Coastguard Worker
2719*77c1e3ccSAndroid Build Coastguard Worker const long result = LoadCluster(pos, len);
2720*77c1e3ccSAndroid Build Coastguard Worker
2721*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error or underflow
2722*77c1e3ccSAndroid Build Coastguard Worker return result;
2723*77c1e3ccSAndroid Build Coastguard Worker
2724*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // no more clusters
2725*77c1e3ccSAndroid Build Coastguard Worker {
2726*77c1e3ccSAndroid Build Coastguard Worker // pResult = &m_eos;
2727*77c1e3ccSAndroid Build Coastguard Worker return 1;
2728*77c1e3ccSAndroid Build Coastguard Worker }
2729*77c1e3ccSAndroid Build Coastguard Worker
2730*77c1e3ccSAndroid Build Coastguard Worker pResult = GetLast();
2731*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
2732*77c1e3ccSAndroid Build Coastguard Worker }
2733*77c1e3ccSAndroid Build Coastguard Worker
2734*77c1e3ccSAndroid Build Coastguard Worker assert(m_pos > 0);
2735*77c1e3ccSAndroid Build Coastguard Worker
2736*77c1e3ccSAndroid Build Coastguard Worker long long total, avail;
2737*77c1e3ccSAndroid Build Coastguard Worker
2738*77c1e3ccSAndroid Build Coastguard Worker long status = m_pReader->Length(&total, &avail);
2739*77c1e3ccSAndroid Build Coastguard Worker
2740*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
2741*77c1e3ccSAndroid Build Coastguard Worker return status;
2742*77c1e3ccSAndroid Build Coastguard Worker
2743*77c1e3ccSAndroid Build Coastguard Worker assert((total < 0) || (avail <= total));
2744*77c1e3ccSAndroid Build Coastguard Worker
2745*77c1e3ccSAndroid Build Coastguard Worker const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
2746*77c1e3ccSAndroid Build Coastguard Worker
2747*77c1e3ccSAndroid Build Coastguard Worker // interrogate curr cluster
2748*77c1e3ccSAndroid Build Coastguard Worker
2749*77c1e3ccSAndroid Build Coastguard Worker pos = pCurr->m_element_start;
2750*77c1e3ccSAndroid Build Coastguard Worker
2751*77c1e3ccSAndroid Build Coastguard Worker if (pCurr->m_element_size >= 0)
2752*77c1e3ccSAndroid Build Coastguard Worker pos += pCurr->m_element_size;
2753*77c1e3ccSAndroid Build Coastguard Worker else {
2754*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
2755*77c1e3ccSAndroid Build Coastguard Worker len = 1;
2756*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2757*77c1e3ccSAndroid Build Coastguard Worker }
2758*77c1e3ccSAndroid Build Coastguard Worker
2759*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(m_pReader, pos, len);
2760*77c1e3ccSAndroid Build Coastguard Worker
2761*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
2762*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
2763*77c1e3ccSAndroid Build Coastguard Worker
2764*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
2765*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2766*77c1e3ccSAndroid Build Coastguard Worker
2767*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2768*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2769*77c1e3ccSAndroid Build Coastguard Worker
2770*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
2771*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2772*77c1e3ccSAndroid Build Coastguard Worker
2773*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadUInt(m_pReader, pos, len);
2774*77c1e3ccSAndroid Build Coastguard Worker
2775*77c1e3ccSAndroid Build Coastguard Worker if (id != libwebm::kMkvCluster)
2776*77c1e3ccSAndroid Build Coastguard Worker return -1;
2777*77c1e3ccSAndroid Build Coastguard Worker
2778*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
2779*77c1e3ccSAndroid Build Coastguard Worker
2780*77c1e3ccSAndroid Build Coastguard Worker // Read Size
2781*77c1e3ccSAndroid Build Coastguard Worker
2782*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
2783*77c1e3ccSAndroid Build Coastguard Worker len = 1;
2784*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2785*77c1e3ccSAndroid Build Coastguard Worker }
2786*77c1e3ccSAndroid Build Coastguard Worker
2787*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(m_pReader, pos, len);
2788*77c1e3ccSAndroid Build Coastguard Worker
2789*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
2790*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
2791*77c1e3ccSAndroid Build Coastguard Worker
2792*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
2793*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2794*77c1e3ccSAndroid Build Coastguard Worker
2795*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2796*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2797*77c1e3ccSAndroid Build Coastguard Worker
2798*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
2799*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2800*77c1e3ccSAndroid Build Coastguard Worker
2801*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(m_pReader, pos, len);
2802*77c1e3ccSAndroid Build Coastguard Worker
2803*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
2804*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(size);
2805*77c1e3ccSAndroid Build Coastguard Worker
2806*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size field
2807*77c1e3ccSAndroid Build Coastguard Worker
2808*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
2809*77c1e3ccSAndroid Build Coastguard Worker
2810*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size) // TODO: should never happen
2811*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID; // TODO: resolve this
2812*77c1e3ccSAndroid Build Coastguard Worker
2813*77c1e3ccSAndroid Build Coastguard Worker // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
2814*77c1e3ccSAndroid Build Coastguard Worker
2815*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + size) > segment_stop))
2816*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2817*77c1e3ccSAndroid Build Coastguard Worker
2818*77c1e3ccSAndroid Build Coastguard Worker // Pos now points to start of payload
2819*77c1e3ccSAndroid Build Coastguard Worker
2820*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload (that is, the current cluster)
2821*77c1e3ccSAndroid Build Coastguard Worker if (segment_stop >= 0 && pos > segment_stop)
2822*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2823*77c1e3ccSAndroid Build Coastguard Worker
2824*77c1e3ccSAndroid Build Coastguard Worker // By consuming the payload, we are assuming that the curr
2825*77c1e3ccSAndroid Build Coastguard Worker // cluster isn't interesting. That is, we don't bother checking
2826*77c1e3ccSAndroid Build Coastguard Worker // whether the payload of the curr cluster is less than what
2827*77c1e3ccSAndroid Build Coastguard Worker // happens to be available (obtained via IMkvReader::Length).
2828*77c1e3ccSAndroid Build Coastguard Worker // Presumably the caller has already dispensed with the current
2829*77c1e3ccSAndroid Build Coastguard Worker // cluster, and really does want the next cluster.
2830*77c1e3ccSAndroid Build Coastguard Worker }
2831*77c1e3ccSAndroid Build Coastguard Worker
2832*77c1e3ccSAndroid Build Coastguard Worker // pos now points to just beyond the last fully-loaded cluster
2833*77c1e3ccSAndroid Build Coastguard Worker
2834*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
2835*77c1e3ccSAndroid Build Coastguard Worker const long status = DoParseNext(pResult, pos, len);
2836*77c1e3ccSAndroid Build Coastguard Worker
2837*77c1e3ccSAndroid Build Coastguard Worker if (status <= 1)
2838*77c1e3ccSAndroid Build Coastguard Worker return status;
2839*77c1e3ccSAndroid Build Coastguard Worker }
2840*77c1e3ccSAndroid Build Coastguard Worker }
2841*77c1e3ccSAndroid Build Coastguard Worker
DoParseNext(const Cluster * & pResult,long long & pos,long & len)2842*77c1e3ccSAndroid Build Coastguard Worker long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
2843*77c1e3ccSAndroid Build Coastguard Worker long long total, avail;
2844*77c1e3ccSAndroid Build Coastguard Worker
2845*77c1e3ccSAndroid Build Coastguard Worker long status = m_pReader->Length(&total, &avail);
2846*77c1e3ccSAndroid Build Coastguard Worker
2847*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
2848*77c1e3ccSAndroid Build Coastguard Worker return status;
2849*77c1e3ccSAndroid Build Coastguard Worker
2850*77c1e3ccSAndroid Build Coastguard Worker assert((total < 0) || (avail <= total));
2851*77c1e3ccSAndroid Build Coastguard Worker
2852*77c1e3ccSAndroid Build Coastguard Worker const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
2853*77c1e3ccSAndroid Build Coastguard Worker
2854*77c1e3ccSAndroid Build Coastguard Worker // Parse next cluster. This is strictly a parsing activity.
2855*77c1e3ccSAndroid Build Coastguard Worker // Creation of a new cluster object happens later, after the
2856*77c1e3ccSAndroid Build Coastguard Worker // parsing is done.
2857*77c1e3ccSAndroid Build Coastguard Worker
2858*77c1e3ccSAndroid Build Coastguard Worker long long off_next = 0;
2859*77c1e3ccSAndroid Build Coastguard Worker long long cluster_size = -1;
2860*77c1e3ccSAndroid Build Coastguard Worker
2861*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
2862*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (pos >= total))
2863*77c1e3ccSAndroid Build Coastguard Worker return 1; // EOF
2864*77c1e3ccSAndroid Build Coastguard Worker
2865*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && (pos >= segment_stop))
2866*77c1e3ccSAndroid Build Coastguard Worker return 1; // EOF
2867*77c1e3ccSAndroid Build Coastguard Worker
2868*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
2869*77c1e3ccSAndroid Build Coastguard Worker len = 1;
2870*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2871*77c1e3ccSAndroid Build Coastguard Worker }
2872*77c1e3ccSAndroid Build Coastguard Worker
2873*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(m_pReader, pos, len);
2874*77c1e3ccSAndroid Build Coastguard Worker
2875*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
2876*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
2877*77c1e3ccSAndroid Build Coastguard Worker
2878*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
2879*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2880*77c1e3ccSAndroid Build Coastguard Worker
2881*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2882*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2883*77c1e3ccSAndroid Build Coastguard Worker
2884*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
2885*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2886*77c1e3ccSAndroid Build Coastguard Worker
2887*77c1e3ccSAndroid Build Coastguard Worker const long long idpos = pos; // absolute
2888*77c1e3ccSAndroid Build Coastguard Worker const long long idoff = pos - m_start; // relative
2889*77c1e3ccSAndroid Build Coastguard Worker
2890*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(m_pReader, idpos, len); // absolute
2891*77c1e3ccSAndroid Build Coastguard Worker
2892*77c1e3ccSAndroid Build Coastguard Worker if (id < 0) // error
2893*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(id);
2894*77c1e3ccSAndroid Build Coastguard Worker
2895*77c1e3ccSAndroid Build Coastguard Worker if (id == 0) // weird
2896*77c1e3ccSAndroid Build Coastguard Worker return -1; // generic error
2897*77c1e3ccSAndroid Build Coastguard Worker
2898*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
2899*77c1e3ccSAndroid Build Coastguard Worker
2900*77c1e3ccSAndroid Build Coastguard Worker // Read Size
2901*77c1e3ccSAndroid Build Coastguard Worker
2902*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
2903*77c1e3ccSAndroid Build Coastguard Worker len = 1;
2904*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2905*77c1e3ccSAndroid Build Coastguard Worker }
2906*77c1e3ccSAndroid Build Coastguard Worker
2907*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(m_pReader, pos, len);
2908*77c1e3ccSAndroid Build Coastguard Worker
2909*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
2910*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
2911*77c1e3ccSAndroid Build Coastguard Worker
2912*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
2913*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2914*77c1e3ccSAndroid Build Coastguard Worker
2915*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2916*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2917*77c1e3ccSAndroid Build Coastguard Worker
2918*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
2919*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
2920*77c1e3ccSAndroid Build Coastguard Worker
2921*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(m_pReader, pos, len);
2922*77c1e3ccSAndroid Build Coastguard Worker
2923*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
2924*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(size);
2925*77c1e3ccSAndroid Build Coastguard Worker
2926*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of element
2927*77c1e3ccSAndroid Build Coastguard Worker
2928*77c1e3ccSAndroid Build Coastguard Worker // Pos now points to start of payload
2929*77c1e3ccSAndroid Build Coastguard Worker
2930*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // weird
2931*77c1e3ccSAndroid Build Coastguard Worker continue;
2932*77c1e3ccSAndroid Build Coastguard Worker
2933*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
2934*77c1e3ccSAndroid Build Coastguard Worker
2935*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && (size != unknown_size) &&
2936*77c1e3ccSAndroid Build Coastguard Worker ((pos + size) > segment_stop)) {
2937*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2938*77c1e3ccSAndroid Build Coastguard Worker }
2939*77c1e3ccSAndroid Build Coastguard Worker
2940*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCues) {
2941*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size)
2942*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2943*77c1e3ccSAndroid Build Coastguard Worker
2944*77c1e3ccSAndroid Build Coastguard Worker const long long element_stop = pos + size;
2945*77c1e3ccSAndroid Build Coastguard Worker
2946*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && (element_stop > segment_stop))
2947*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2948*77c1e3ccSAndroid Build Coastguard Worker
2949*77c1e3ccSAndroid Build Coastguard Worker const long long element_start = idpos;
2950*77c1e3ccSAndroid Build Coastguard Worker const long long element_size = element_stop - element_start;
2951*77c1e3ccSAndroid Build Coastguard Worker
2952*77c1e3ccSAndroid Build Coastguard Worker if (m_pCues == NULL) {
2953*77c1e3ccSAndroid Build Coastguard Worker m_pCues = new (std::nothrow)
2954*77c1e3ccSAndroid Build Coastguard Worker Cues(this, pos, size, element_start, element_size);
2955*77c1e3ccSAndroid Build Coastguard Worker if (m_pCues == NULL)
2956*77c1e3ccSAndroid Build Coastguard Worker return false;
2957*77c1e3ccSAndroid Build Coastguard Worker }
2958*77c1e3ccSAndroid Build Coastguard Worker
2959*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
2960*77c1e3ccSAndroid Build Coastguard Worker if (segment_stop >= 0 && pos > segment_stop)
2961*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2962*77c1e3ccSAndroid Build Coastguard Worker
2963*77c1e3ccSAndroid Build Coastguard Worker continue;
2964*77c1e3ccSAndroid Build Coastguard Worker }
2965*77c1e3ccSAndroid Build Coastguard Worker
2966*77c1e3ccSAndroid Build Coastguard Worker if (id != libwebm::kMkvCluster) { // not a Cluster ID
2967*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size)
2968*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2969*77c1e3ccSAndroid Build Coastguard Worker
2970*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
2971*77c1e3ccSAndroid Build Coastguard Worker if (segment_stop >= 0 && pos > segment_stop)
2972*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
2973*77c1e3ccSAndroid Build Coastguard Worker
2974*77c1e3ccSAndroid Build Coastguard Worker continue;
2975*77c1e3ccSAndroid Build Coastguard Worker }
2976*77c1e3ccSAndroid Build Coastguard Worker
2977*77c1e3ccSAndroid Build Coastguard Worker // We have a cluster.
2978*77c1e3ccSAndroid Build Coastguard Worker off_next = idoff;
2979*77c1e3ccSAndroid Build Coastguard Worker
2980*77c1e3ccSAndroid Build Coastguard Worker if (size != unknown_size)
2981*77c1e3ccSAndroid Build Coastguard Worker cluster_size = size;
2982*77c1e3ccSAndroid Build Coastguard Worker
2983*77c1e3ccSAndroid Build Coastguard Worker break;
2984*77c1e3ccSAndroid Build Coastguard Worker }
2985*77c1e3ccSAndroid Build Coastguard Worker
2986*77c1e3ccSAndroid Build Coastguard Worker assert(off_next > 0); // have cluster
2987*77c1e3ccSAndroid Build Coastguard Worker
2988*77c1e3ccSAndroid Build Coastguard Worker // We have parsed the next cluster.
2989*77c1e3ccSAndroid Build Coastguard Worker // We have not created a cluster object yet. What we need
2990*77c1e3ccSAndroid Build Coastguard Worker // to do now is determine whether it has already be preloaded
2991*77c1e3ccSAndroid Build Coastguard Worker //(in which case, an object for this cluster has already been
2992*77c1e3ccSAndroid Build Coastguard Worker // created), and if not, create a new cluster object.
2993*77c1e3ccSAndroid Build Coastguard Worker
2994*77c1e3ccSAndroid Build Coastguard Worker Cluster** const ii = m_clusters + m_clusterCount;
2995*77c1e3ccSAndroid Build Coastguard Worker Cluster** i = ii;
2996*77c1e3ccSAndroid Build Coastguard Worker
2997*77c1e3ccSAndroid Build Coastguard Worker Cluster** const jj = ii + m_clusterPreloadCount;
2998*77c1e3ccSAndroid Build Coastguard Worker Cluster** j = jj;
2999*77c1e3ccSAndroid Build Coastguard Worker
3000*77c1e3ccSAndroid Build Coastguard Worker while (i < j) {
3001*77c1e3ccSAndroid Build Coastguard Worker // INVARIANT:
3002*77c1e3ccSAndroid Build Coastguard Worker //[0, i) < pos_next
3003*77c1e3ccSAndroid Build Coastguard Worker //[i, j) ?
3004*77c1e3ccSAndroid Build Coastguard Worker //[j, jj) > pos_next
3005*77c1e3ccSAndroid Build Coastguard Worker
3006*77c1e3ccSAndroid Build Coastguard Worker Cluster** const k = i + (j - i) / 2;
3007*77c1e3ccSAndroid Build Coastguard Worker assert(k < jj);
3008*77c1e3ccSAndroid Build Coastguard Worker
3009*77c1e3ccSAndroid Build Coastguard Worker const Cluster* const pNext = *k;
3010*77c1e3ccSAndroid Build Coastguard Worker assert(pNext);
3011*77c1e3ccSAndroid Build Coastguard Worker assert(pNext->m_index < 0);
3012*77c1e3ccSAndroid Build Coastguard Worker
3013*77c1e3ccSAndroid Build Coastguard Worker pos = pNext->GetPosition();
3014*77c1e3ccSAndroid Build Coastguard Worker assert(pos >= 0);
3015*77c1e3ccSAndroid Build Coastguard Worker
3016*77c1e3ccSAndroid Build Coastguard Worker if (pos < off_next)
3017*77c1e3ccSAndroid Build Coastguard Worker i = k + 1;
3018*77c1e3ccSAndroid Build Coastguard Worker else if (pos > off_next)
3019*77c1e3ccSAndroid Build Coastguard Worker j = k;
3020*77c1e3ccSAndroid Build Coastguard Worker else {
3021*77c1e3ccSAndroid Build Coastguard Worker pResult = pNext;
3022*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
3023*77c1e3ccSAndroid Build Coastguard Worker }
3024*77c1e3ccSAndroid Build Coastguard Worker }
3025*77c1e3ccSAndroid Build Coastguard Worker
3026*77c1e3ccSAndroid Build Coastguard Worker assert(i == j);
3027*77c1e3ccSAndroid Build Coastguard Worker
3028*77c1e3ccSAndroid Build Coastguard Worker long long pos_;
3029*77c1e3ccSAndroid Build Coastguard Worker long len_;
3030*77c1e3ccSAndroid Build Coastguard Worker
3031*77c1e3ccSAndroid Build Coastguard Worker status = Cluster::HasBlockEntries(this, off_next, pos_, len_);
3032*77c1e3ccSAndroid Build Coastguard Worker
3033*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) { // error or underflow
3034*77c1e3ccSAndroid Build Coastguard Worker pos = pos_;
3035*77c1e3ccSAndroid Build Coastguard Worker len = len_;
3036*77c1e3ccSAndroid Build Coastguard Worker
3037*77c1e3ccSAndroid Build Coastguard Worker return status;
3038*77c1e3ccSAndroid Build Coastguard Worker }
3039*77c1e3ccSAndroid Build Coastguard Worker
3040*77c1e3ccSAndroid Build Coastguard Worker if (status > 0) { // means "found at least one block entry"
3041*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pNext = Cluster::Create(this,
3042*77c1e3ccSAndroid Build Coastguard Worker -1, // preloaded
3043*77c1e3ccSAndroid Build Coastguard Worker off_next);
3044*77c1e3ccSAndroid Build Coastguard Worker if (pNext == NULL)
3045*77c1e3ccSAndroid Build Coastguard Worker return -1;
3046*77c1e3ccSAndroid Build Coastguard Worker
3047*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t idx_next = i - m_clusters; // insertion position
3048*77c1e3ccSAndroid Build Coastguard Worker
3049*77c1e3ccSAndroid Build Coastguard Worker if (!PreloadCluster(pNext, idx_next)) {
3050*77c1e3ccSAndroid Build Coastguard Worker delete pNext;
3051*77c1e3ccSAndroid Build Coastguard Worker return -1;
3052*77c1e3ccSAndroid Build Coastguard Worker }
3053*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters);
3054*77c1e3ccSAndroid Build Coastguard Worker assert(idx_next < m_clusterSize);
3055*77c1e3ccSAndroid Build Coastguard Worker assert(m_clusters[idx_next] == pNext);
3056*77c1e3ccSAndroid Build Coastguard Worker
3057*77c1e3ccSAndroid Build Coastguard Worker pResult = pNext;
3058*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
3059*77c1e3ccSAndroid Build Coastguard Worker }
3060*77c1e3ccSAndroid Build Coastguard Worker
3061*77c1e3ccSAndroid Build Coastguard Worker // status == 0 means "no block entries found"
3062*77c1e3ccSAndroid Build Coastguard Worker
3063*77c1e3ccSAndroid Build Coastguard Worker if (cluster_size < 0) { // unknown size
3064*77c1e3ccSAndroid Build Coastguard Worker const long long payload_pos = pos; // absolute pos of cluster payload
3065*77c1e3ccSAndroid Build Coastguard Worker
3066*77c1e3ccSAndroid Build Coastguard Worker for (;;) { // determine cluster size
3067*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (pos >= total))
3068*77c1e3ccSAndroid Build Coastguard Worker break;
3069*77c1e3ccSAndroid Build Coastguard Worker
3070*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && (pos >= segment_stop))
3071*77c1e3ccSAndroid Build Coastguard Worker break; // no more clusters
3072*77c1e3ccSAndroid Build Coastguard Worker
3073*77c1e3ccSAndroid Build Coastguard Worker // Read ID
3074*77c1e3ccSAndroid Build Coastguard Worker
3075*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
3076*77c1e3ccSAndroid Build Coastguard Worker len = 1;
3077*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
3078*77c1e3ccSAndroid Build Coastguard Worker }
3079*77c1e3ccSAndroid Build Coastguard Worker
3080*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(m_pReader, pos, len);
3081*77c1e3ccSAndroid Build Coastguard Worker
3082*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
3083*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
3084*77c1e3ccSAndroid Build Coastguard Worker
3085*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
3086*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
3087*77c1e3ccSAndroid Build Coastguard Worker
3088*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3089*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3090*77c1e3ccSAndroid Build Coastguard Worker
3091*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
3092*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
3093*77c1e3ccSAndroid Build Coastguard Worker
3094*77c1e3ccSAndroid Build Coastguard Worker const long long idpos = pos;
3095*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(m_pReader, idpos, len);
3096*77c1e3ccSAndroid Build Coastguard Worker
3097*77c1e3ccSAndroid Build Coastguard Worker if (id < 0) // error (or underflow)
3098*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(id);
3099*77c1e3ccSAndroid Build Coastguard Worker
3100*77c1e3ccSAndroid Build Coastguard Worker // This is the distinguished set of ID's we use to determine
3101*77c1e3ccSAndroid Build Coastguard Worker // that we have exhausted the sub-element's inside the cluster
3102*77c1e3ccSAndroid Build Coastguard Worker // whose ID we parsed earlier.
3103*77c1e3ccSAndroid Build Coastguard Worker
3104*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCluster || id == libwebm::kMkvCues)
3105*77c1e3ccSAndroid Build Coastguard Worker break;
3106*77c1e3ccSAndroid Build Coastguard Worker
3107*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID (of sub-element)
3108*77c1e3ccSAndroid Build Coastguard Worker
3109*77c1e3ccSAndroid Build Coastguard Worker // Read Size
3110*77c1e3ccSAndroid Build Coastguard Worker
3111*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
3112*77c1e3ccSAndroid Build Coastguard Worker len = 1;
3113*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
3114*77c1e3ccSAndroid Build Coastguard Worker }
3115*77c1e3ccSAndroid Build Coastguard Worker
3116*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(m_pReader, pos, len);
3117*77c1e3ccSAndroid Build Coastguard Worker
3118*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
3119*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
3120*77c1e3ccSAndroid Build Coastguard Worker
3121*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
3122*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
3123*77c1e3ccSAndroid Build Coastguard Worker
3124*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3125*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3126*77c1e3ccSAndroid Build Coastguard Worker
3127*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
3128*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
3129*77c1e3ccSAndroid Build Coastguard Worker
3130*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(m_pReader, pos, len);
3131*77c1e3ccSAndroid Build Coastguard Worker
3132*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
3133*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(size);
3134*77c1e3ccSAndroid Build Coastguard Worker
3135*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size field of element
3136*77c1e3ccSAndroid Build Coastguard Worker
3137*77c1e3ccSAndroid Build Coastguard Worker // pos now points to start of sub-element's payload
3138*77c1e3ccSAndroid Build Coastguard Worker
3139*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // weird
3140*77c1e3ccSAndroid Build Coastguard Worker continue;
3141*77c1e3ccSAndroid Build Coastguard Worker
3142*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
3143*77c1e3ccSAndroid Build Coastguard Worker
3144*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size)
3145*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID; // not allowed for sub-elements
3146*77c1e3ccSAndroid Build Coastguard Worker
3147*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + size) > segment_stop)) // weird
3148*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3149*77c1e3ccSAndroid Build Coastguard Worker
3150*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload of sub-element
3151*77c1e3ccSAndroid Build Coastguard Worker if (segment_stop >= 0 && pos > segment_stop)
3152*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3153*77c1e3ccSAndroid Build Coastguard Worker } // determine cluster size
3154*77c1e3ccSAndroid Build Coastguard Worker
3155*77c1e3ccSAndroid Build Coastguard Worker cluster_size = pos - payload_pos;
3156*77c1e3ccSAndroid Build Coastguard Worker assert(cluster_size >= 0); // TODO: handle cluster_size = 0
3157*77c1e3ccSAndroid Build Coastguard Worker
3158*77c1e3ccSAndroid Build Coastguard Worker pos = payload_pos; // reset and re-parse original cluster
3159*77c1e3ccSAndroid Build Coastguard Worker }
3160*77c1e3ccSAndroid Build Coastguard Worker
3161*77c1e3ccSAndroid Build Coastguard Worker pos += cluster_size; // consume payload
3162*77c1e3ccSAndroid Build Coastguard Worker if (segment_stop >= 0 && pos > segment_stop)
3163*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3164*77c1e3ccSAndroid Build Coastguard Worker
3165*77c1e3ccSAndroid Build Coastguard Worker return 2; // try to find a cluster that follows next
3166*77c1e3ccSAndroid Build Coastguard Worker }
3167*77c1e3ccSAndroid Build Coastguard Worker
FindCluster(long long time_ns) const3168*77c1e3ccSAndroid Build Coastguard Worker const Cluster* Segment::FindCluster(long long time_ns) const {
3169*77c1e3ccSAndroid Build Coastguard Worker if ((m_clusters == NULL) || (m_clusterCount <= 0))
3170*77c1e3ccSAndroid Build Coastguard Worker return &m_eos;
3171*77c1e3ccSAndroid Build Coastguard Worker
3172*77c1e3ccSAndroid Build Coastguard Worker {
3173*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = m_clusters[0];
3174*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
3175*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->m_index == 0);
3176*77c1e3ccSAndroid Build Coastguard Worker
3177*77c1e3ccSAndroid Build Coastguard Worker if (time_ns <= pCluster->GetTime())
3178*77c1e3ccSAndroid Build Coastguard Worker return pCluster;
3179*77c1e3ccSAndroid Build Coastguard Worker }
3180*77c1e3ccSAndroid Build Coastguard Worker
3181*77c1e3ccSAndroid Build Coastguard Worker // Binary search of cluster array
3182*77c1e3ccSAndroid Build Coastguard Worker
3183*77c1e3ccSAndroid Build Coastguard Worker long i = 0;
3184*77c1e3ccSAndroid Build Coastguard Worker long j = m_clusterCount;
3185*77c1e3ccSAndroid Build Coastguard Worker
3186*77c1e3ccSAndroid Build Coastguard Worker while (i < j) {
3187*77c1e3ccSAndroid Build Coastguard Worker // INVARIANT:
3188*77c1e3ccSAndroid Build Coastguard Worker //[0, i) <= time_ns
3189*77c1e3ccSAndroid Build Coastguard Worker //[i, j) ?
3190*77c1e3ccSAndroid Build Coastguard Worker //[j, m_clusterCount) > time_ns
3191*77c1e3ccSAndroid Build Coastguard Worker
3192*77c1e3ccSAndroid Build Coastguard Worker const long k = i + (j - i) / 2;
3193*77c1e3ccSAndroid Build Coastguard Worker assert(k < m_clusterCount);
3194*77c1e3ccSAndroid Build Coastguard Worker
3195*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = m_clusters[k];
3196*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
3197*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->m_index == k);
3198*77c1e3ccSAndroid Build Coastguard Worker
3199*77c1e3ccSAndroid Build Coastguard Worker const long long t = pCluster->GetTime();
3200*77c1e3ccSAndroid Build Coastguard Worker
3201*77c1e3ccSAndroid Build Coastguard Worker if (t <= time_ns)
3202*77c1e3ccSAndroid Build Coastguard Worker i = k + 1;
3203*77c1e3ccSAndroid Build Coastguard Worker else
3204*77c1e3ccSAndroid Build Coastguard Worker j = k;
3205*77c1e3ccSAndroid Build Coastguard Worker
3206*77c1e3ccSAndroid Build Coastguard Worker assert(i <= j);
3207*77c1e3ccSAndroid Build Coastguard Worker }
3208*77c1e3ccSAndroid Build Coastguard Worker
3209*77c1e3ccSAndroid Build Coastguard Worker assert(i == j);
3210*77c1e3ccSAndroid Build Coastguard Worker assert(i > 0);
3211*77c1e3ccSAndroid Build Coastguard Worker assert(i <= m_clusterCount);
3212*77c1e3ccSAndroid Build Coastguard Worker
3213*77c1e3ccSAndroid Build Coastguard Worker const long k = i - 1;
3214*77c1e3ccSAndroid Build Coastguard Worker
3215*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster = m_clusters[k];
3216*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
3217*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->m_index == k);
3218*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetTime() <= time_ns);
3219*77c1e3ccSAndroid Build Coastguard Worker
3220*77c1e3ccSAndroid Build Coastguard Worker return pCluster;
3221*77c1e3ccSAndroid Build Coastguard Worker }
3222*77c1e3ccSAndroid Build Coastguard Worker
GetTracks() const3223*77c1e3ccSAndroid Build Coastguard Worker const Tracks* Segment::GetTracks() const { return m_pTracks; }
GetInfo() const3224*77c1e3ccSAndroid Build Coastguard Worker const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
GetCues() const3225*77c1e3ccSAndroid Build Coastguard Worker const Cues* Segment::GetCues() const { return m_pCues; }
GetChapters() const3226*77c1e3ccSAndroid Build Coastguard Worker const Chapters* Segment::GetChapters() const { return m_pChapters; }
GetTags() const3227*77c1e3ccSAndroid Build Coastguard Worker const Tags* Segment::GetTags() const { return m_pTags; }
GetSeekHead() const3228*77c1e3ccSAndroid Build Coastguard Worker const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
3229*77c1e3ccSAndroid Build Coastguard Worker
GetDuration() const3230*77c1e3ccSAndroid Build Coastguard Worker long long Segment::GetDuration() const {
3231*77c1e3ccSAndroid Build Coastguard Worker assert(m_pInfo);
3232*77c1e3ccSAndroid Build Coastguard Worker return m_pInfo->GetDuration();
3233*77c1e3ccSAndroid Build Coastguard Worker }
3234*77c1e3ccSAndroid Build Coastguard Worker
Chapters(Segment * pSegment,long long payload_start,long long payload_size,long long element_start,long long element_size)3235*77c1e3ccSAndroid Build Coastguard Worker Chapters::Chapters(Segment* pSegment, long long payload_start,
3236*77c1e3ccSAndroid Build Coastguard Worker long long payload_size, long long element_start,
3237*77c1e3ccSAndroid Build Coastguard Worker long long element_size)
3238*77c1e3ccSAndroid Build Coastguard Worker : m_pSegment(pSegment),
3239*77c1e3ccSAndroid Build Coastguard Worker m_start(payload_start),
3240*77c1e3ccSAndroid Build Coastguard Worker m_size(payload_size),
3241*77c1e3ccSAndroid Build Coastguard Worker m_element_start(element_start),
3242*77c1e3ccSAndroid Build Coastguard Worker m_element_size(element_size),
3243*77c1e3ccSAndroid Build Coastguard Worker m_editions(NULL),
3244*77c1e3ccSAndroid Build Coastguard Worker m_editions_size(0),
3245*77c1e3ccSAndroid Build Coastguard Worker m_editions_count(0) {}
3246*77c1e3ccSAndroid Build Coastguard Worker
~Chapters()3247*77c1e3ccSAndroid Build Coastguard Worker Chapters::~Chapters() {
3248*77c1e3ccSAndroid Build Coastguard Worker while (m_editions_count > 0) {
3249*77c1e3ccSAndroid Build Coastguard Worker Edition& e = m_editions[--m_editions_count];
3250*77c1e3ccSAndroid Build Coastguard Worker e.Clear();
3251*77c1e3ccSAndroid Build Coastguard Worker }
3252*77c1e3ccSAndroid Build Coastguard Worker delete[] m_editions;
3253*77c1e3ccSAndroid Build Coastguard Worker }
3254*77c1e3ccSAndroid Build Coastguard Worker
Parse()3255*77c1e3ccSAndroid Build Coastguard Worker long Chapters::Parse() {
3256*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
3257*77c1e3ccSAndroid Build Coastguard Worker
3258*77c1e3ccSAndroid Build Coastguard Worker long long pos = m_start; // payload start
3259*77c1e3ccSAndroid Build Coastguard Worker const long long stop = pos + m_size; // payload stop
3260*77c1e3ccSAndroid Build Coastguard Worker
3261*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
3262*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
3263*77c1e3ccSAndroid Build Coastguard Worker
3264*77c1e3ccSAndroid Build Coastguard Worker long status = ParseElementHeader(pReader, pos, stop, id, size);
3265*77c1e3ccSAndroid Build Coastguard Worker
3266*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
3267*77c1e3ccSAndroid Build Coastguard Worker return status;
3268*77c1e3ccSAndroid Build Coastguard Worker
3269*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // weird
3270*77c1e3ccSAndroid Build Coastguard Worker continue;
3271*77c1e3ccSAndroid Build Coastguard Worker
3272*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvEditionEntry) {
3273*77c1e3ccSAndroid Build Coastguard Worker status = ParseEdition(pos, size);
3274*77c1e3ccSAndroid Build Coastguard Worker
3275*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
3276*77c1e3ccSAndroid Build Coastguard Worker return status;
3277*77c1e3ccSAndroid Build Coastguard Worker }
3278*77c1e3ccSAndroid Build Coastguard Worker
3279*77c1e3ccSAndroid Build Coastguard Worker pos += size;
3280*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
3281*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3282*77c1e3ccSAndroid Build Coastguard Worker }
3283*77c1e3ccSAndroid Build Coastguard Worker
3284*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
3285*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3286*77c1e3ccSAndroid Build Coastguard Worker return 0;
3287*77c1e3ccSAndroid Build Coastguard Worker }
3288*77c1e3ccSAndroid Build Coastguard Worker
GetEditionCount() const3289*77c1e3ccSAndroid Build Coastguard Worker int Chapters::GetEditionCount() const { return m_editions_count; }
3290*77c1e3ccSAndroid Build Coastguard Worker
GetEdition(int idx) const3291*77c1e3ccSAndroid Build Coastguard Worker const Chapters::Edition* Chapters::GetEdition(int idx) const {
3292*77c1e3ccSAndroid Build Coastguard Worker if (idx < 0)
3293*77c1e3ccSAndroid Build Coastguard Worker return NULL;
3294*77c1e3ccSAndroid Build Coastguard Worker
3295*77c1e3ccSAndroid Build Coastguard Worker if (idx >= m_editions_count)
3296*77c1e3ccSAndroid Build Coastguard Worker return NULL;
3297*77c1e3ccSAndroid Build Coastguard Worker
3298*77c1e3ccSAndroid Build Coastguard Worker return m_editions + idx;
3299*77c1e3ccSAndroid Build Coastguard Worker }
3300*77c1e3ccSAndroid Build Coastguard Worker
ExpandEditionsArray()3301*77c1e3ccSAndroid Build Coastguard Worker bool Chapters::ExpandEditionsArray() {
3302*77c1e3ccSAndroid Build Coastguard Worker if (m_editions_size > m_editions_count)
3303*77c1e3ccSAndroid Build Coastguard Worker return true; // nothing else to do
3304*77c1e3ccSAndroid Build Coastguard Worker
3305*77c1e3ccSAndroid Build Coastguard Worker const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size;
3306*77c1e3ccSAndroid Build Coastguard Worker
3307*77c1e3ccSAndroid Build Coastguard Worker Edition* const editions = new (std::nothrow) Edition[size];
3308*77c1e3ccSAndroid Build Coastguard Worker
3309*77c1e3ccSAndroid Build Coastguard Worker if (editions == NULL)
3310*77c1e3ccSAndroid Build Coastguard Worker return false;
3311*77c1e3ccSAndroid Build Coastguard Worker
3312*77c1e3ccSAndroid Build Coastguard Worker for (int idx = 0; idx < m_editions_count; ++idx) {
3313*77c1e3ccSAndroid Build Coastguard Worker m_editions[idx].ShallowCopy(editions[idx]);
3314*77c1e3ccSAndroid Build Coastguard Worker }
3315*77c1e3ccSAndroid Build Coastguard Worker
3316*77c1e3ccSAndroid Build Coastguard Worker delete[] m_editions;
3317*77c1e3ccSAndroid Build Coastguard Worker m_editions = editions;
3318*77c1e3ccSAndroid Build Coastguard Worker
3319*77c1e3ccSAndroid Build Coastguard Worker m_editions_size = size;
3320*77c1e3ccSAndroid Build Coastguard Worker return true;
3321*77c1e3ccSAndroid Build Coastguard Worker }
3322*77c1e3ccSAndroid Build Coastguard Worker
ParseEdition(long long pos,long long size)3323*77c1e3ccSAndroid Build Coastguard Worker long Chapters::ParseEdition(long long pos, long long size) {
3324*77c1e3ccSAndroid Build Coastguard Worker if (!ExpandEditionsArray())
3325*77c1e3ccSAndroid Build Coastguard Worker return -1;
3326*77c1e3ccSAndroid Build Coastguard Worker
3327*77c1e3ccSAndroid Build Coastguard Worker Edition& e = m_editions[m_editions_count++];
3328*77c1e3ccSAndroid Build Coastguard Worker e.Init();
3329*77c1e3ccSAndroid Build Coastguard Worker
3330*77c1e3ccSAndroid Build Coastguard Worker return e.Parse(m_pSegment->m_pReader, pos, size);
3331*77c1e3ccSAndroid Build Coastguard Worker }
3332*77c1e3ccSAndroid Build Coastguard Worker
Edition()3333*77c1e3ccSAndroid Build Coastguard Worker Chapters::Edition::Edition() {}
3334*77c1e3ccSAndroid Build Coastguard Worker
~Edition()3335*77c1e3ccSAndroid Build Coastguard Worker Chapters::Edition::~Edition() {}
3336*77c1e3ccSAndroid Build Coastguard Worker
GetAtomCount() const3337*77c1e3ccSAndroid Build Coastguard Worker int Chapters::Edition::GetAtomCount() const { return m_atoms_count; }
3338*77c1e3ccSAndroid Build Coastguard Worker
GetAtom(int index) const3339*77c1e3ccSAndroid Build Coastguard Worker const Chapters::Atom* Chapters::Edition::GetAtom(int index) const {
3340*77c1e3ccSAndroid Build Coastguard Worker if (index < 0)
3341*77c1e3ccSAndroid Build Coastguard Worker return NULL;
3342*77c1e3ccSAndroid Build Coastguard Worker
3343*77c1e3ccSAndroid Build Coastguard Worker if (index >= m_atoms_count)
3344*77c1e3ccSAndroid Build Coastguard Worker return NULL;
3345*77c1e3ccSAndroid Build Coastguard Worker
3346*77c1e3ccSAndroid Build Coastguard Worker return m_atoms + index;
3347*77c1e3ccSAndroid Build Coastguard Worker }
3348*77c1e3ccSAndroid Build Coastguard Worker
Init()3349*77c1e3ccSAndroid Build Coastguard Worker void Chapters::Edition::Init() {
3350*77c1e3ccSAndroid Build Coastguard Worker m_atoms = NULL;
3351*77c1e3ccSAndroid Build Coastguard Worker m_atoms_size = 0;
3352*77c1e3ccSAndroid Build Coastguard Worker m_atoms_count = 0;
3353*77c1e3ccSAndroid Build Coastguard Worker }
3354*77c1e3ccSAndroid Build Coastguard Worker
ShallowCopy(Edition & rhs) const3355*77c1e3ccSAndroid Build Coastguard Worker void Chapters::Edition::ShallowCopy(Edition& rhs) const {
3356*77c1e3ccSAndroid Build Coastguard Worker rhs.m_atoms = m_atoms;
3357*77c1e3ccSAndroid Build Coastguard Worker rhs.m_atoms_size = m_atoms_size;
3358*77c1e3ccSAndroid Build Coastguard Worker rhs.m_atoms_count = m_atoms_count;
3359*77c1e3ccSAndroid Build Coastguard Worker }
3360*77c1e3ccSAndroid Build Coastguard Worker
Clear()3361*77c1e3ccSAndroid Build Coastguard Worker void Chapters::Edition::Clear() {
3362*77c1e3ccSAndroid Build Coastguard Worker while (m_atoms_count > 0) {
3363*77c1e3ccSAndroid Build Coastguard Worker Atom& a = m_atoms[--m_atoms_count];
3364*77c1e3ccSAndroid Build Coastguard Worker a.Clear();
3365*77c1e3ccSAndroid Build Coastguard Worker }
3366*77c1e3ccSAndroid Build Coastguard Worker
3367*77c1e3ccSAndroid Build Coastguard Worker delete[] m_atoms;
3368*77c1e3ccSAndroid Build Coastguard Worker m_atoms = NULL;
3369*77c1e3ccSAndroid Build Coastguard Worker
3370*77c1e3ccSAndroid Build Coastguard Worker m_atoms_size = 0;
3371*77c1e3ccSAndroid Build Coastguard Worker }
3372*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * pReader,long long pos,long long size)3373*77c1e3ccSAndroid Build Coastguard Worker long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
3374*77c1e3ccSAndroid Build Coastguard Worker long long size) {
3375*77c1e3ccSAndroid Build Coastguard Worker const long long stop = pos + size;
3376*77c1e3ccSAndroid Build Coastguard Worker
3377*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
3378*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
3379*77c1e3ccSAndroid Build Coastguard Worker
3380*77c1e3ccSAndroid Build Coastguard Worker long status = ParseElementHeader(pReader, pos, stop, id, size);
3381*77c1e3ccSAndroid Build Coastguard Worker
3382*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
3383*77c1e3ccSAndroid Build Coastguard Worker return status;
3384*77c1e3ccSAndroid Build Coastguard Worker
3385*77c1e3ccSAndroid Build Coastguard Worker if (size == 0)
3386*77c1e3ccSAndroid Build Coastguard Worker continue;
3387*77c1e3ccSAndroid Build Coastguard Worker
3388*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvChapterAtom) {
3389*77c1e3ccSAndroid Build Coastguard Worker status = ParseAtom(pReader, pos, size);
3390*77c1e3ccSAndroid Build Coastguard Worker
3391*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
3392*77c1e3ccSAndroid Build Coastguard Worker return status;
3393*77c1e3ccSAndroid Build Coastguard Worker }
3394*77c1e3ccSAndroid Build Coastguard Worker
3395*77c1e3ccSAndroid Build Coastguard Worker pos += size;
3396*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
3397*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3398*77c1e3ccSAndroid Build Coastguard Worker }
3399*77c1e3ccSAndroid Build Coastguard Worker
3400*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
3401*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3402*77c1e3ccSAndroid Build Coastguard Worker return 0;
3403*77c1e3ccSAndroid Build Coastguard Worker }
3404*77c1e3ccSAndroid Build Coastguard Worker
ParseAtom(IMkvReader * pReader,long long pos,long long size)3405*77c1e3ccSAndroid Build Coastguard Worker long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos,
3406*77c1e3ccSAndroid Build Coastguard Worker long long size) {
3407*77c1e3ccSAndroid Build Coastguard Worker if (!ExpandAtomsArray())
3408*77c1e3ccSAndroid Build Coastguard Worker return -1;
3409*77c1e3ccSAndroid Build Coastguard Worker
3410*77c1e3ccSAndroid Build Coastguard Worker Atom& a = m_atoms[m_atoms_count++];
3411*77c1e3ccSAndroid Build Coastguard Worker a.Init();
3412*77c1e3ccSAndroid Build Coastguard Worker
3413*77c1e3ccSAndroid Build Coastguard Worker return a.Parse(pReader, pos, size);
3414*77c1e3ccSAndroid Build Coastguard Worker }
3415*77c1e3ccSAndroid Build Coastguard Worker
ExpandAtomsArray()3416*77c1e3ccSAndroid Build Coastguard Worker bool Chapters::Edition::ExpandAtomsArray() {
3417*77c1e3ccSAndroid Build Coastguard Worker if (m_atoms_size > m_atoms_count)
3418*77c1e3ccSAndroid Build Coastguard Worker return true; // nothing else to do
3419*77c1e3ccSAndroid Build Coastguard Worker
3420*77c1e3ccSAndroid Build Coastguard Worker const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size;
3421*77c1e3ccSAndroid Build Coastguard Worker
3422*77c1e3ccSAndroid Build Coastguard Worker Atom* const atoms = new (std::nothrow) Atom[size];
3423*77c1e3ccSAndroid Build Coastguard Worker
3424*77c1e3ccSAndroid Build Coastguard Worker if (atoms == NULL)
3425*77c1e3ccSAndroid Build Coastguard Worker return false;
3426*77c1e3ccSAndroid Build Coastguard Worker
3427*77c1e3ccSAndroid Build Coastguard Worker for (int idx = 0; idx < m_atoms_count; ++idx) {
3428*77c1e3ccSAndroid Build Coastguard Worker m_atoms[idx].ShallowCopy(atoms[idx]);
3429*77c1e3ccSAndroid Build Coastguard Worker }
3430*77c1e3ccSAndroid Build Coastguard Worker
3431*77c1e3ccSAndroid Build Coastguard Worker delete[] m_atoms;
3432*77c1e3ccSAndroid Build Coastguard Worker m_atoms = atoms;
3433*77c1e3ccSAndroid Build Coastguard Worker
3434*77c1e3ccSAndroid Build Coastguard Worker m_atoms_size = size;
3435*77c1e3ccSAndroid Build Coastguard Worker return true;
3436*77c1e3ccSAndroid Build Coastguard Worker }
3437*77c1e3ccSAndroid Build Coastguard Worker
Atom()3438*77c1e3ccSAndroid Build Coastguard Worker Chapters::Atom::Atom() {}
3439*77c1e3ccSAndroid Build Coastguard Worker
~Atom()3440*77c1e3ccSAndroid Build Coastguard Worker Chapters::Atom::~Atom() {}
3441*77c1e3ccSAndroid Build Coastguard Worker
GetUID() const3442*77c1e3ccSAndroid Build Coastguard Worker unsigned long long Chapters::Atom::GetUID() const { return m_uid; }
3443*77c1e3ccSAndroid Build Coastguard Worker
GetStringUID() const3444*77c1e3ccSAndroid Build Coastguard Worker const char* Chapters::Atom::GetStringUID() const { return m_string_uid; }
3445*77c1e3ccSAndroid Build Coastguard Worker
GetStartTimecode() const3446*77c1e3ccSAndroid Build Coastguard Worker long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; }
3447*77c1e3ccSAndroid Build Coastguard Worker
GetStopTimecode() const3448*77c1e3ccSAndroid Build Coastguard Worker long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; }
3449*77c1e3ccSAndroid Build Coastguard Worker
GetStartTime(const Chapters * pChapters) const3450*77c1e3ccSAndroid Build Coastguard Worker long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const {
3451*77c1e3ccSAndroid Build Coastguard Worker return GetTime(pChapters, m_start_timecode);
3452*77c1e3ccSAndroid Build Coastguard Worker }
3453*77c1e3ccSAndroid Build Coastguard Worker
GetStopTime(const Chapters * pChapters) const3454*77c1e3ccSAndroid Build Coastguard Worker long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const {
3455*77c1e3ccSAndroid Build Coastguard Worker return GetTime(pChapters, m_stop_timecode);
3456*77c1e3ccSAndroid Build Coastguard Worker }
3457*77c1e3ccSAndroid Build Coastguard Worker
GetDisplayCount() const3458*77c1e3ccSAndroid Build Coastguard Worker int Chapters::Atom::GetDisplayCount() const { return m_displays_count; }
3459*77c1e3ccSAndroid Build Coastguard Worker
GetDisplay(int index) const3460*77c1e3ccSAndroid Build Coastguard Worker const Chapters::Display* Chapters::Atom::GetDisplay(int index) const {
3461*77c1e3ccSAndroid Build Coastguard Worker if (index < 0)
3462*77c1e3ccSAndroid Build Coastguard Worker return NULL;
3463*77c1e3ccSAndroid Build Coastguard Worker
3464*77c1e3ccSAndroid Build Coastguard Worker if (index >= m_displays_count)
3465*77c1e3ccSAndroid Build Coastguard Worker return NULL;
3466*77c1e3ccSAndroid Build Coastguard Worker
3467*77c1e3ccSAndroid Build Coastguard Worker return m_displays + index;
3468*77c1e3ccSAndroid Build Coastguard Worker }
3469*77c1e3ccSAndroid Build Coastguard Worker
Init()3470*77c1e3ccSAndroid Build Coastguard Worker void Chapters::Atom::Init() {
3471*77c1e3ccSAndroid Build Coastguard Worker m_string_uid = NULL;
3472*77c1e3ccSAndroid Build Coastguard Worker m_uid = 0;
3473*77c1e3ccSAndroid Build Coastguard Worker m_start_timecode = -1;
3474*77c1e3ccSAndroid Build Coastguard Worker m_stop_timecode = -1;
3475*77c1e3ccSAndroid Build Coastguard Worker
3476*77c1e3ccSAndroid Build Coastguard Worker m_displays = NULL;
3477*77c1e3ccSAndroid Build Coastguard Worker m_displays_size = 0;
3478*77c1e3ccSAndroid Build Coastguard Worker m_displays_count = 0;
3479*77c1e3ccSAndroid Build Coastguard Worker }
3480*77c1e3ccSAndroid Build Coastguard Worker
ShallowCopy(Atom & rhs) const3481*77c1e3ccSAndroid Build Coastguard Worker void Chapters::Atom::ShallowCopy(Atom& rhs) const {
3482*77c1e3ccSAndroid Build Coastguard Worker rhs.m_string_uid = m_string_uid;
3483*77c1e3ccSAndroid Build Coastguard Worker rhs.m_uid = m_uid;
3484*77c1e3ccSAndroid Build Coastguard Worker rhs.m_start_timecode = m_start_timecode;
3485*77c1e3ccSAndroid Build Coastguard Worker rhs.m_stop_timecode = m_stop_timecode;
3486*77c1e3ccSAndroid Build Coastguard Worker
3487*77c1e3ccSAndroid Build Coastguard Worker rhs.m_displays = m_displays;
3488*77c1e3ccSAndroid Build Coastguard Worker rhs.m_displays_size = m_displays_size;
3489*77c1e3ccSAndroid Build Coastguard Worker rhs.m_displays_count = m_displays_count;
3490*77c1e3ccSAndroid Build Coastguard Worker }
3491*77c1e3ccSAndroid Build Coastguard Worker
Clear()3492*77c1e3ccSAndroid Build Coastguard Worker void Chapters::Atom::Clear() {
3493*77c1e3ccSAndroid Build Coastguard Worker delete[] m_string_uid;
3494*77c1e3ccSAndroid Build Coastguard Worker m_string_uid = NULL;
3495*77c1e3ccSAndroid Build Coastguard Worker
3496*77c1e3ccSAndroid Build Coastguard Worker while (m_displays_count > 0) {
3497*77c1e3ccSAndroid Build Coastguard Worker Display& d = m_displays[--m_displays_count];
3498*77c1e3ccSAndroid Build Coastguard Worker d.Clear();
3499*77c1e3ccSAndroid Build Coastguard Worker }
3500*77c1e3ccSAndroid Build Coastguard Worker
3501*77c1e3ccSAndroid Build Coastguard Worker delete[] m_displays;
3502*77c1e3ccSAndroid Build Coastguard Worker m_displays = NULL;
3503*77c1e3ccSAndroid Build Coastguard Worker
3504*77c1e3ccSAndroid Build Coastguard Worker m_displays_size = 0;
3505*77c1e3ccSAndroid Build Coastguard Worker }
3506*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * pReader,long long pos,long long size)3507*77c1e3ccSAndroid Build Coastguard Worker long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
3508*77c1e3ccSAndroid Build Coastguard Worker const long long stop = pos + size;
3509*77c1e3ccSAndroid Build Coastguard Worker
3510*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
3511*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
3512*77c1e3ccSAndroid Build Coastguard Worker
3513*77c1e3ccSAndroid Build Coastguard Worker long status = ParseElementHeader(pReader, pos, stop, id, size);
3514*77c1e3ccSAndroid Build Coastguard Worker
3515*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
3516*77c1e3ccSAndroid Build Coastguard Worker return status;
3517*77c1e3ccSAndroid Build Coastguard Worker
3518*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // 0 length payload, skip.
3519*77c1e3ccSAndroid Build Coastguard Worker continue;
3520*77c1e3ccSAndroid Build Coastguard Worker
3521*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvChapterDisplay) {
3522*77c1e3ccSAndroid Build Coastguard Worker status = ParseDisplay(pReader, pos, size);
3523*77c1e3ccSAndroid Build Coastguard Worker
3524*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
3525*77c1e3ccSAndroid Build Coastguard Worker return status;
3526*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvChapterStringUID) {
3527*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeString(pReader, pos, size, m_string_uid);
3528*77c1e3ccSAndroid Build Coastguard Worker
3529*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
3530*77c1e3ccSAndroid Build Coastguard Worker return status;
3531*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvChapterUID) {
3532*77c1e3ccSAndroid Build Coastguard Worker long long val;
3533*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeInt(pReader, pos, size, val);
3534*77c1e3ccSAndroid Build Coastguard Worker
3535*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
3536*77c1e3ccSAndroid Build Coastguard Worker return status;
3537*77c1e3ccSAndroid Build Coastguard Worker
3538*77c1e3ccSAndroid Build Coastguard Worker m_uid = static_cast<unsigned long long>(val);
3539*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvChapterTimeStart) {
3540*77c1e3ccSAndroid Build Coastguard Worker const long long val = UnserializeUInt(pReader, pos, size);
3541*77c1e3ccSAndroid Build Coastguard Worker
3542*77c1e3ccSAndroid Build Coastguard Worker if (val < 0) // error
3543*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(val);
3544*77c1e3ccSAndroid Build Coastguard Worker
3545*77c1e3ccSAndroid Build Coastguard Worker m_start_timecode = val;
3546*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvChapterTimeEnd) {
3547*77c1e3ccSAndroid Build Coastguard Worker const long long val = UnserializeUInt(pReader, pos, size);
3548*77c1e3ccSAndroid Build Coastguard Worker
3549*77c1e3ccSAndroid Build Coastguard Worker if (val < 0) // error
3550*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(val);
3551*77c1e3ccSAndroid Build Coastguard Worker
3552*77c1e3ccSAndroid Build Coastguard Worker m_stop_timecode = val;
3553*77c1e3ccSAndroid Build Coastguard Worker }
3554*77c1e3ccSAndroid Build Coastguard Worker
3555*77c1e3ccSAndroid Build Coastguard Worker pos += size;
3556*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
3557*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3558*77c1e3ccSAndroid Build Coastguard Worker }
3559*77c1e3ccSAndroid Build Coastguard Worker
3560*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
3561*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3562*77c1e3ccSAndroid Build Coastguard Worker return 0;
3563*77c1e3ccSAndroid Build Coastguard Worker }
3564*77c1e3ccSAndroid Build Coastguard Worker
GetTime(const Chapters * pChapters,long long timecode)3565*77c1e3ccSAndroid Build Coastguard Worker long long Chapters::Atom::GetTime(const Chapters* pChapters,
3566*77c1e3ccSAndroid Build Coastguard Worker long long timecode) {
3567*77c1e3ccSAndroid Build Coastguard Worker if (pChapters == NULL)
3568*77c1e3ccSAndroid Build Coastguard Worker return -1;
3569*77c1e3ccSAndroid Build Coastguard Worker
3570*77c1e3ccSAndroid Build Coastguard Worker Segment* const pSegment = pChapters->m_pSegment;
3571*77c1e3ccSAndroid Build Coastguard Worker
3572*77c1e3ccSAndroid Build Coastguard Worker if (pSegment == NULL) // weird
3573*77c1e3ccSAndroid Build Coastguard Worker return -1;
3574*77c1e3ccSAndroid Build Coastguard Worker
3575*77c1e3ccSAndroid Build Coastguard Worker const SegmentInfo* const pInfo = pSegment->GetInfo();
3576*77c1e3ccSAndroid Build Coastguard Worker
3577*77c1e3ccSAndroid Build Coastguard Worker if (pInfo == NULL)
3578*77c1e3ccSAndroid Build Coastguard Worker return -1;
3579*77c1e3ccSAndroid Build Coastguard Worker
3580*77c1e3ccSAndroid Build Coastguard Worker const long long timecode_scale = pInfo->GetTimeCodeScale();
3581*77c1e3ccSAndroid Build Coastguard Worker
3582*77c1e3ccSAndroid Build Coastguard Worker if (timecode_scale < 1) // weird
3583*77c1e3ccSAndroid Build Coastguard Worker return -1;
3584*77c1e3ccSAndroid Build Coastguard Worker
3585*77c1e3ccSAndroid Build Coastguard Worker if (timecode < 0)
3586*77c1e3ccSAndroid Build Coastguard Worker return -1;
3587*77c1e3ccSAndroid Build Coastguard Worker
3588*77c1e3ccSAndroid Build Coastguard Worker const long long result = timecode_scale * timecode;
3589*77c1e3ccSAndroid Build Coastguard Worker
3590*77c1e3ccSAndroid Build Coastguard Worker return result;
3591*77c1e3ccSAndroid Build Coastguard Worker }
3592*77c1e3ccSAndroid Build Coastguard Worker
ParseDisplay(IMkvReader * pReader,long long pos,long long size)3593*77c1e3ccSAndroid Build Coastguard Worker long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos,
3594*77c1e3ccSAndroid Build Coastguard Worker long long size) {
3595*77c1e3ccSAndroid Build Coastguard Worker if (!ExpandDisplaysArray())
3596*77c1e3ccSAndroid Build Coastguard Worker return -1;
3597*77c1e3ccSAndroid Build Coastguard Worker
3598*77c1e3ccSAndroid Build Coastguard Worker Display& d = m_displays[m_displays_count++];
3599*77c1e3ccSAndroid Build Coastguard Worker d.Init();
3600*77c1e3ccSAndroid Build Coastguard Worker
3601*77c1e3ccSAndroid Build Coastguard Worker return d.Parse(pReader, pos, size);
3602*77c1e3ccSAndroid Build Coastguard Worker }
3603*77c1e3ccSAndroid Build Coastguard Worker
ExpandDisplaysArray()3604*77c1e3ccSAndroid Build Coastguard Worker bool Chapters::Atom::ExpandDisplaysArray() {
3605*77c1e3ccSAndroid Build Coastguard Worker if (m_displays_size > m_displays_count)
3606*77c1e3ccSAndroid Build Coastguard Worker return true; // nothing else to do
3607*77c1e3ccSAndroid Build Coastguard Worker
3608*77c1e3ccSAndroid Build Coastguard Worker const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size;
3609*77c1e3ccSAndroid Build Coastguard Worker
3610*77c1e3ccSAndroid Build Coastguard Worker Display* const displays = new (std::nothrow) Display[size];
3611*77c1e3ccSAndroid Build Coastguard Worker
3612*77c1e3ccSAndroid Build Coastguard Worker if (displays == NULL)
3613*77c1e3ccSAndroid Build Coastguard Worker return false;
3614*77c1e3ccSAndroid Build Coastguard Worker
3615*77c1e3ccSAndroid Build Coastguard Worker for (int idx = 0; idx < m_displays_count; ++idx) {
3616*77c1e3ccSAndroid Build Coastguard Worker m_displays[idx].ShallowCopy(displays[idx]);
3617*77c1e3ccSAndroid Build Coastguard Worker }
3618*77c1e3ccSAndroid Build Coastguard Worker
3619*77c1e3ccSAndroid Build Coastguard Worker delete[] m_displays;
3620*77c1e3ccSAndroid Build Coastguard Worker m_displays = displays;
3621*77c1e3ccSAndroid Build Coastguard Worker
3622*77c1e3ccSAndroid Build Coastguard Worker m_displays_size = size;
3623*77c1e3ccSAndroid Build Coastguard Worker return true;
3624*77c1e3ccSAndroid Build Coastguard Worker }
3625*77c1e3ccSAndroid Build Coastguard Worker
Display()3626*77c1e3ccSAndroid Build Coastguard Worker Chapters::Display::Display() {}
3627*77c1e3ccSAndroid Build Coastguard Worker
~Display()3628*77c1e3ccSAndroid Build Coastguard Worker Chapters::Display::~Display() {}
3629*77c1e3ccSAndroid Build Coastguard Worker
GetString() const3630*77c1e3ccSAndroid Build Coastguard Worker const char* Chapters::Display::GetString() const { return m_string; }
3631*77c1e3ccSAndroid Build Coastguard Worker
GetLanguage() const3632*77c1e3ccSAndroid Build Coastguard Worker const char* Chapters::Display::GetLanguage() const { return m_language; }
3633*77c1e3ccSAndroid Build Coastguard Worker
GetCountry() const3634*77c1e3ccSAndroid Build Coastguard Worker const char* Chapters::Display::GetCountry() const { return m_country; }
3635*77c1e3ccSAndroid Build Coastguard Worker
Init()3636*77c1e3ccSAndroid Build Coastguard Worker void Chapters::Display::Init() {
3637*77c1e3ccSAndroid Build Coastguard Worker m_string = NULL;
3638*77c1e3ccSAndroid Build Coastguard Worker m_language = NULL;
3639*77c1e3ccSAndroid Build Coastguard Worker m_country = NULL;
3640*77c1e3ccSAndroid Build Coastguard Worker }
3641*77c1e3ccSAndroid Build Coastguard Worker
ShallowCopy(Display & rhs) const3642*77c1e3ccSAndroid Build Coastguard Worker void Chapters::Display::ShallowCopy(Display& rhs) const {
3643*77c1e3ccSAndroid Build Coastguard Worker rhs.m_string = m_string;
3644*77c1e3ccSAndroid Build Coastguard Worker rhs.m_language = m_language;
3645*77c1e3ccSAndroid Build Coastguard Worker rhs.m_country = m_country;
3646*77c1e3ccSAndroid Build Coastguard Worker }
3647*77c1e3ccSAndroid Build Coastguard Worker
Clear()3648*77c1e3ccSAndroid Build Coastguard Worker void Chapters::Display::Clear() {
3649*77c1e3ccSAndroid Build Coastguard Worker delete[] m_string;
3650*77c1e3ccSAndroid Build Coastguard Worker m_string = NULL;
3651*77c1e3ccSAndroid Build Coastguard Worker
3652*77c1e3ccSAndroid Build Coastguard Worker delete[] m_language;
3653*77c1e3ccSAndroid Build Coastguard Worker m_language = NULL;
3654*77c1e3ccSAndroid Build Coastguard Worker
3655*77c1e3ccSAndroid Build Coastguard Worker delete[] m_country;
3656*77c1e3ccSAndroid Build Coastguard Worker m_country = NULL;
3657*77c1e3ccSAndroid Build Coastguard Worker }
3658*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * pReader,long long pos,long long size)3659*77c1e3ccSAndroid Build Coastguard Worker long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
3660*77c1e3ccSAndroid Build Coastguard Worker long long size) {
3661*77c1e3ccSAndroid Build Coastguard Worker const long long stop = pos + size;
3662*77c1e3ccSAndroid Build Coastguard Worker
3663*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
3664*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
3665*77c1e3ccSAndroid Build Coastguard Worker
3666*77c1e3ccSAndroid Build Coastguard Worker long status = ParseElementHeader(pReader, pos, stop, id, size);
3667*77c1e3ccSAndroid Build Coastguard Worker
3668*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
3669*77c1e3ccSAndroid Build Coastguard Worker return status;
3670*77c1e3ccSAndroid Build Coastguard Worker
3671*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // No payload.
3672*77c1e3ccSAndroid Build Coastguard Worker continue;
3673*77c1e3ccSAndroid Build Coastguard Worker
3674*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvChapString) {
3675*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeString(pReader, pos, size, m_string);
3676*77c1e3ccSAndroid Build Coastguard Worker
3677*77c1e3ccSAndroid Build Coastguard Worker if (status)
3678*77c1e3ccSAndroid Build Coastguard Worker return status;
3679*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvChapLanguage) {
3680*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeString(pReader, pos, size, m_language);
3681*77c1e3ccSAndroid Build Coastguard Worker
3682*77c1e3ccSAndroid Build Coastguard Worker if (status)
3683*77c1e3ccSAndroid Build Coastguard Worker return status;
3684*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvChapCountry) {
3685*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeString(pReader, pos, size, m_country);
3686*77c1e3ccSAndroid Build Coastguard Worker
3687*77c1e3ccSAndroid Build Coastguard Worker if (status)
3688*77c1e3ccSAndroid Build Coastguard Worker return status;
3689*77c1e3ccSAndroid Build Coastguard Worker }
3690*77c1e3ccSAndroid Build Coastguard Worker
3691*77c1e3ccSAndroid Build Coastguard Worker pos += size;
3692*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
3693*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3694*77c1e3ccSAndroid Build Coastguard Worker }
3695*77c1e3ccSAndroid Build Coastguard Worker
3696*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
3697*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3698*77c1e3ccSAndroid Build Coastguard Worker return 0;
3699*77c1e3ccSAndroid Build Coastguard Worker }
3700*77c1e3ccSAndroid Build Coastguard Worker
Tags(Segment * pSegment,long long payload_start,long long payload_size,long long element_start,long long element_size)3701*77c1e3ccSAndroid Build Coastguard Worker Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size,
3702*77c1e3ccSAndroid Build Coastguard Worker long long element_start, long long element_size)
3703*77c1e3ccSAndroid Build Coastguard Worker : m_pSegment(pSegment),
3704*77c1e3ccSAndroid Build Coastguard Worker m_start(payload_start),
3705*77c1e3ccSAndroid Build Coastguard Worker m_size(payload_size),
3706*77c1e3ccSAndroid Build Coastguard Worker m_element_start(element_start),
3707*77c1e3ccSAndroid Build Coastguard Worker m_element_size(element_size),
3708*77c1e3ccSAndroid Build Coastguard Worker m_tags(NULL),
3709*77c1e3ccSAndroid Build Coastguard Worker m_tags_size(0),
3710*77c1e3ccSAndroid Build Coastguard Worker m_tags_count(0) {}
3711*77c1e3ccSAndroid Build Coastguard Worker
~Tags()3712*77c1e3ccSAndroid Build Coastguard Worker Tags::~Tags() {
3713*77c1e3ccSAndroid Build Coastguard Worker while (m_tags_count > 0) {
3714*77c1e3ccSAndroid Build Coastguard Worker Tag& t = m_tags[--m_tags_count];
3715*77c1e3ccSAndroid Build Coastguard Worker t.Clear();
3716*77c1e3ccSAndroid Build Coastguard Worker }
3717*77c1e3ccSAndroid Build Coastguard Worker delete[] m_tags;
3718*77c1e3ccSAndroid Build Coastguard Worker }
3719*77c1e3ccSAndroid Build Coastguard Worker
Parse()3720*77c1e3ccSAndroid Build Coastguard Worker long Tags::Parse() {
3721*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
3722*77c1e3ccSAndroid Build Coastguard Worker
3723*77c1e3ccSAndroid Build Coastguard Worker long long pos = m_start; // payload start
3724*77c1e3ccSAndroid Build Coastguard Worker const long long stop = pos + m_size; // payload stop
3725*77c1e3ccSAndroid Build Coastguard Worker
3726*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
3727*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
3728*77c1e3ccSAndroid Build Coastguard Worker
3729*77c1e3ccSAndroid Build Coastguard Worker long status = ParseElementHeader(pReader, pos, stop, id, size);
3730*77c1e3ccSAndroid Build Coastguard Worker
3731*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
3732*77c1e3ccSAndroid Build Coastguard Worker return status;
3733*77c1e3ccSAndroid Build Coastguard Worker
3734*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // 0 length tag, read another
3735*77c1e3ccSAndroid Build Coastguard Worker continue;
3736*77c1e3ccSAndroid Build Coastguard Worker
3737*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvTag) {
3738*77c1e3ccSAndroid Build Coastguard Worker status = ParseTag(pos, size);
3739*77c1e3ccSAndroid Build Coastguard Worker
3740*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
3741*77c1e3ccSAndroid Build Coastguard Worker return status;
3742*77c1e3ccSAndroid Build Coastguard Worker }
3743*77c1e3ccSAndroid Build Coastguard Worker
3744*77c1e3ccSAndroid Build Coastguard Worker pos += size;
3745*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
3746*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3747*77c1e3ccSAndroid Build Coastguard Worker }
3748*77c1e3ccSAndroid Build Coastguard Worker
3749*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
3750*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3751*77c1e3ccSAndroid Build Coastguard Worker
3752*77c1e3ccSAndroid Build Coastguard Worker return 0;
3753*77c1e3ccSAndroid Build Coastguard Worker }
3754*77c1e3ccSAndroid Build Coastguard Worker
GetTagCount() const3755*77c1e3ccSAndroid Build Coastguard Worker int Tags::GetTagCount() const { return m_tags_count; }
3756*77c1e3ccSAndroid Build Coastguard Worker
GetTag(int idx) const3757*77c1e3ccSAndroid Build Coastguard Worker const Tags::Tag* Tags::GetTag(int idx) const {
3758*77c1e3ccSAndroid Build Coastguard Worker if (idx < 0)
3759*77c1e3ccSAndroid Build Coastguard Worker return NULL;
3760*77c1e3ccSAndroid Build Coastguard Worker
3761*77c1e3ccSAndroid Build Coastguard Worker if (idx >= m_tags_count)
3762*77c1e3ccSAndroid Build Coastguard Worker return NULL;
3763*77c1e3ccSAndroid Build Coastguard Worker
3764*77c1e3ccSAndroid Build Coastguard Worker return m_tags + idx;
3765*77c1e3ccSAndroid Build Coastguard Worker }
3766*77c1e3ccSAndroid Build Coastguard Worker
ExpandTagsArray()3767*77c1e3ccSAndroid Build Coastguard Worker bool Tags::ExpandTagsArray() {
3768*77c1e3ccSAndroid Build Coastguard Worker if (m_tags_size > m_tags_count)
3769*77c1e3ccSAndroid Build Coastguard Worker return true; // nothing else to do
3770*77c1e3ccSAndroid Build Coastguard Worker
3771*77c1e3ccSAndroid Build Coastguard Worker const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size;
3772*77c1e3ccSAndroid Build Coastguard Worker
3773*77c1e3ccSAndroid Build Coastguard Worker Tag* const tags = new (std::nothrow) Tag[size];
3774*77c1e3ccSAndroid Build Coastguard Worker
3775*77c1e3ccSAndroid Build Coastguard Worker if (tags == NULL)
3776*77c1e3ccSAndroid Build Coastguard Worker return false;
3777*77c1e3ccSAndroid Build Coastguard Worker
3778*77c1e3ccSAndroid Build Coastguard Worker for (int idx = 0; idx < m_tags_count; ++idx) {
3779*77c1e3ccSAndroid Build Coastguard Worker m_tags[idx].ShallowCopy(tags[idx]);
3780*77c1e3ccSAndroid Build Coastguard Worker }
3781*77c1e3ccSAndroid Build Coastguard Worker
3782*77c1e3ccSAndroid Build Coastguard Worker delete[] m_tags;
3783*77c1e3ccSAndroid Build Coastguard Worker m_tags = tags;
3784*77c1e3ccSAndroid Build Coastguard Worker
3785*77c1e3ccSAndroid Build Coastguard Worker m_tags_size = size;
3786*77c1e3ccSAndroid Build Coastguard Worker return true;
3787*77c1e3ccSAndroid Build Coastguard Worker }
3788*77c1e3ccSAndroid Build Coastguard Worker
ParseTag(long long pos,long long size)3789*77c1e3ccSAndroid Build Coastguard Worker long Tags::ParseTag(long long pos, long long size) {
3790*77c1e3ccSAndroid Build Coastguard Worker if (!ExpandTagsArray())
3791*77c1e3ccSAndroid Build Coastguard Worker return -1;
3792*77c1e3ccSAndroid Build Coastguard Worker
3793*77c1e3ccSAndroid Build Coastguard Worker Tag& t = m_tags[m_tags_count++];
3794*77c1e3ccSAndroid Build Coastguard Worker t.Init();
3795*77c1e3ccSAndroid Build Coastguard Worker
3796*77c1e3ccSAndroid Build Coastguard Worker return t.Parse(m_pSegment->m_pReader, pos, size);
3797*77c1e3ccSAndroid Build Coastguard Worker }
3798*77c1e3ccSAndroid Build Coastguard Worker
Tag()3799*77c1e3ccSAndroid Build Coastguard Worker Tags::Tag::Tag() {}
3800*77c1e3ccSAndroid Build Coastguard Worker
~Tag()3801*77c1e3ccSAndroid Build Coastguard Worker Tags::Tag::~Tag() {}
3802*77c1e3ccSAndroid Build Coastguard Worker
GetSimpleTagCount() const3803*77c1e3ccSAndroid Build Coastguard Worker int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; }
3804*77c1e3ccSAndroid Build Coastguard Worker
GetSimpleTag(int index) const3805*77c1e3ccSAndroid Build Coastguard Worker const Tags::SimpleTag* Tags::Tag::GetSimpleTag(int index) const {
3806*77c1e3ccSAndroid Build Coastguard Worker if (index < 0)
3807*77c1e3ccSAndroid Build Coastguard Worker return NULL;
3808*77c1e3ccSAndroid Build Coastguard Worker
3809*77c1e3ccSAndroid Build Coastguard Worker if (index >= m_simple_tags_count)
3810*77c1e3ccSAndroid Build Coastguard Worker return NULL;
3811*77c1e3ccSAndroid Build Coastguard Worker
3812*77c1e3ccSAndroid Build Coastguard Worker return m_simple_tags + index;
3813*77c1e3ccSAndroid Build Coastguard Worker }
3814*77c1e3ccSAndroid Build Coastguard Worker
Init()3815*77c1e3ccSAndroid Build Coastguard Worker void Tags::Tag::Init() {
3816*77c1e3ccSAndroid Build Coastguard Worker m_simple_tags = NULL;
3817*77c1e3ccSAndroid Build Coastguard Worker m_simple_tags_size = 0;
3818*77c1e3ccSAndroid Build Coastguard Worker m_simple_tags_count = 0;
3819*77c1e3ccSAndroid Build Coastguard Worker }
3820*77c1e3ccSAndroid Build Coastguard Worker
ShallowCopy(Tag & rhs) const3821*77c1e3ccSAndroid Build Coastguard Worker void Tags::Tag::ShallowCopy(Tag& rhs) const {
3822*77c1e3ccSAndroid Build Coastguard Worker rhs.m_simple_tags = m_simple_tags;
3823*77c1e3ccSAndroid Build Coastguard Worker rhs.m_simple_tags_size = m_simple_tags_size;
3824*77c1e3ccSAndroid Build Coastguard Worker rhs.m_simple_tags_count = m_simple_tags_count;
3825*77c1e3ccSAndroid Build Coastguard Worker }
3826*77c1e3ccSAndroid Build Coastguard Worker
Clear()3827*77c1e3ccSAndroid Build Coastguard Worker void Tags::Tag::Clear() {
3828*77c1e3ccSAndroid Build Coastguard Worker while (m_simple_tags_count > 0) {
3829*77c1e3ccSAndroid Build Coastguard Worker SimpleTag& d = m_simple_tags[--m_simple_tags_count];
3830*77c1e3ccSAndroid Build Coastguard Worker d.Clear();
3831*77c1e3ccSAndroid Build Coastguard Worker }
3832*77c1e3ccSAndroid Build Coastguard Worker
3833*77c1e3ccSAndroid Build Coastguard Worker delete[] m_simple_tags;
3834*77c1e3ccSAndroid Build Coastguard Worker m_simple_tags = NULL;
3835*77c1e3ccSAndroid Build Coastguard Worker
3836*77c1e3ccSAndroid Build Coastguard Worker m_simple_tags_size = 0;
3837*77c1e3ccSAndroid Build Coastguard Worker }
3838*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * pReader,long long pos,long long size)3839*77c1e3ccSAndroid Build Coastguard Worker long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
3840*77c1e3ccSAndroid Build Coastguard Worker const long long stop = pos + size;
3841*77c1e3ccSAndroid Build Coastguard Worker
3842*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
3843*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
3844*77c1e3ccSAndroid Build Coastguard Worker
3845*77c1e3ccSAndroid Build Coastguard Worker long status = ParseElementHeader(pReader, pos, stop, id, size);
3846*77c1e3ccSAndroid Build Coastguard Worker
3847*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
3848*77c1e3ccSAndroid Build Coastguard Worker return status;
3849*77c1e3ccSAndroid Build Coastguard Worker
3850*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // 0 length tag, read another
3851*77c1e3ccSAndroid Build Coastguard Worker continue;
3852*77c1e3ccSAndroid Build Coastguard Worker
3853*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvSimpleTag) {
3854*77c1e3ccSAndroid Build Coastguard Worker status = ParseSimpleTag(pReader, pos, size);
3855*77c1e3ccSAndroid Build Coastguard Worker
3856*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
3857*77c1e3ccSAndroid Build Coastguard Worker return status;
3858*77c1e3ccSAndroid Build Coastguard Worker }
3859*77c1e3ccSAndroid Build Coastguard Worker
3860*77c1e3ccSAndroid Build Coastguard Worker pos += size;
3861*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
3862*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3863*77c1e3ccSAndroid Build Coastguard Worker }
3864*77c1e3ccSAndroid Build Coastguard Worker
3865*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
3866*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3867*77c1e3ccSAndroid Build Coastguard Worker return 0;
3868*77c1e3ccSAndroid Build Coastguard Worker }
3869*77c1e3ccSAndroid Build Coastguard Worker
ParseSimpleTag(IMkvReader * pReader,long long pos,long long size)3870*77c1e3ccSAndroid Build Coastguard Worker long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos,
3871*77c1e3ccSAndroid Build Coastguard Worker long long size) {
3872*77c1e3ccSAndroid Build Coastguard Worker if (!ExpandSimpleTagsArray())
3873*77c1e3ccSAndroid Build Coastguard Worker return -1;
3874*77c1e3ccSAndroid Build Coastguard Worker
3875*77c1e3ccSAndroid Build Coastguard Worker SimpleTag& st = m_simple_tags[m_simple_tags_count++];
3876*77c1e3ccSAndroid Build Coastguard Worker st.Init();
3877*77c1e3ccSAndroid Build Coastguard Worker
3878*77c1e3ccSAndroid Build Coastguard Worker return st.Parse(pReader, pos, size);
3879*77c1e3ccSAndroid Build Coastguard Worker }
3880*77c1e3ccSAndroid Build Coastguard Worker
ExpandSimpleTagsArray()3881*77c1e3ccSAndroid Build Coastguard Worker bool Tags::Tag::ExpandSimpleTagsArray() {
3882*77c1e3ccSAndroid Build Coastguard Worker if (m_simple_tags_size > m_simple_tags_count)
3883*77c1e3ccSAndroid Build Coastguard Worker return true; // nothing else to do
3884*77c1e3ccSAndroid Build Coastguard Worker
3885*77c1e3ccSAndroid Build Coastguard Worker const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size;
3886*77c1e3ccSAndroid Build Coastguard Worker
3887*77c1e3ccSAndroid Build Coastguard Worker SimpleTag* const displays = new (std::nothrow) SimpleTag[size];
3888*77c1e3ccSAndroid Build Coastguard Worker
3889*77c1e3ccSAndroid Build Coastguard Worker if (displays == NULL)
3890*77c1e3ccSAndroid Build Coastguard Worker return false;
3891*77c1e3ccSAndroid Build Coastguard Worker
3892*77c1e3ccSAndroid Build Coastguard Worker for (int idx = 0; idx < m_simple_tags_count; ++idx) {
3893*77c1e3ccSAndroid Build Coastguard Worker m_simple_tags[idx].ShallowCopy(displays[idx]);
3894*77c1e3ccSAndroid Build Coastguard Worker }
3895*77c1e3ccSAndroid Build Coastguard Worker
3896*77c1e3ccSAndroid Build Coastguard Worker delete[] m_simple_tags;
3897*77c1e3ccSAndroid Build Coastguard Worker m_simple_tags = displays;
3898*77c1e3ccSAndroid Build Coastguard Worker
3899*77c1e3ccSAndroid Build Coastguard Worker m_simple_tags_size = size;
3900*77c1e3ccSAndroid Build Coastguard Worker return true;
3901*77c1e3ccSAndroid Build Coastguard Worker }
3902*77c1e3ccSAndroid Build Coastguard Worker
SimpleTag()3903*77c1e3ccSAndroid Build Coastguard Worker Tags::SimpleTag::SimpleTag() {}
3904*77c1e3ccSAndroid Build Coastguard Worker
~SimpleTag()3905*77c1e3ccSAndroid Build Coastguard Worker Tags::SimpleTag::~SimpleTag() {}
3906*77c1e3ccSAndroid Build Coastguard Worker
GetTagName() const3907*77c1e3ccSAndroid Build Coastguard Worker const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; }
3908*77c1e3ccSAndroid Build Coastguard Worker
GetTagString() const3909*77c1e3ccSAndroid Build Coastguard Worker const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; }
3910*77c1e3ccSAndroid Build Coastguard Worker
Init()3911*77c1e3ccSAndroid Build Coastguard Worker void Tags::SimpleTag::Init() {
3912*77c1e3ccSAndroid Build Coastguard Worker m_tag_name = NULL;
3913*77c1e3ccSAndroid Build Coastguard Worker m_tag_string = NULL;
3914*77c1e3ccSAndroid Build Coastguard Worker }
3915*77c1e3ccSAndroid Build Coastguard Worker
ShallowCopy(SimpleTag & rhs) const3916*77c1e3ccSAndroid Build Coastguard Worker void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const {
3917*77c1e3ccSAndroid Build Coastguard Worker rhs.m_tag_name = m_tag_name;
3918*77c1e3ccSAndroid Build Coastguard Worker rhs.m_tag_string = m_tag_string;
3919*77c1e3ccSAndroid Build Coastguard Worker }
3920*77c1e3ccSAndroid Build Coastguard Worker
Clear()3921*77c1e3ccSAndroid Build Coastguard Worker void Tags::SimpleTag::Clear() {
3922*77c1e3ccSAndroid Build Coastguard Worker delete[] m_tag_name;
3923*77c1e3ccSAndroid Build Coastguard Worker m_tag_name = NULL;
3924*77c1e3ccSAndroid Build Coastguard Worker
3925*77c1e3ccSAndroid Build Coastguard Worker delete[] m_tag_string;
3926*77c1e3ccSAndroid Build Coastguard Worker m_tag_string = NULL;
3927*77c1e3ccSAndroid Build Coastguard Worker }
3928*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * pReader,long long pos,long long size)3929*77c1e3ccSAndroid Build Coastguard Worker long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
3930*77c1e3ccSAndroid Build Coastguard Worker long long size) {
3931*77c1e3ccSAndroid Build Coastguard Worker const long long stop = pos + size;
3932*77c1e3ccSAndroid Build Coastguard Worker
3933*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
3934*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
3935*77c1e3ccSAndroid Build Coastguard Worker
3936*77c1e3ccSAndroid Build Coastguard Worker long status = ParseElementHeader(pReader, pos, stop, id, size);
3937*77c1e3ccSAndroid Build Coastguard Worker
3938*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
3939*77c1e3ccSAndroid Build Coastguard Worker return status;
3940*77c1e3ccSAndroid Build Coastguard Worker
3941*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // weird
3942*77c1e3ccSAndroid Build Coastguard Worker continue;
3943*77c1e3ccSAndroid Build Coastguard Worker
3944*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvTagName) {
3945*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeString(pReader, pos, size, m_tag_name);
3946*77c1e3ccSAndroid Build Coastguard Worker
3947*77c1e3ccSAndroid Build Coastguard Worker if (status)
3948*77c1e3ccSAndroid Build Coastguard Worker return status;
3949*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvTagString) {
3950*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeString(pReader, pos, size, m_tag_string);
3951*77c1e3ccSAndroid Build Coastguard Worker
3952*77c1e3ccSAndroid Build Coastguard Worker if (status)
3953*77c1e3ccSAndroid Build Coastguard Worker return status;
3954*77c1e3ccSAndroid Build Coastguard Worker }
3955*77c1e3ccSAndroid Build Coastguard Worker
3956*77c1e3ccSAndroid Build Coastguard Worker pos += size;
3957*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
3958*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3959*77c1e3ccSAndroid Build Coastguard Worker }
3960*77c1e3ccSAndroid Build Coastguard Worker
3961*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
3962*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
3963*77c1e3ccSAndroid Build Coastguard Worker return 0;
3964*77c1e3ccSAndroid Build Coastguard Worker }
3965*77c1e3ccSAndroid Build Coastguard Worker
SegmentInfo(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)3966*77c1e3ccSAndroid Build Coastguard Worker SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_,
3967*77c1e3ccSAndroid Build Coastguard Worker long long element_start, long long element_size)
3968*77c1e3ccSAndroid Build Coastguard Worker : m_pSegment(pSegment),
3969*77c1e3ccSAndroid Build Coastguard Worker m_start(start),
3970*77c1e3ccSAndroid Build Coastguard Worker m_size(size_),
3971*77c1e3ccSAndroid Build Coastguard Worker m_element_start(element_start),
3972*77c1e3ccSAndroid Build Coastguard Worker m_element_size(element_size),
3973*77c1e3ccSAndroid Build Coastguard Worker m_pMuxingAppAsUTF8(NULL),
3974*77c1e3ccSAndroid Build Coastguard Worker m_pWritingAppAsUTF8(NULL),
3975*77c1e3ccSAndroid Build Coastguard Worker m_pTitleAsUTF8(NULL) {}
3976*77c1e3ccSAndroid Build Coastguard Worker
~SegmentInfo()3977*77c1e3ccSAndroid Build Coastguard Worker SegmentInfo::~SegmentInfo() {
3978*77c1e3ccSAndroid Build Coastguard Worker delete[] m_pMuxingAppAsUTF8;
3979*77c1e3ccSAndroid Build Coastguard Worker m_pMuxingAppAsUTF8 = NULL;
3980*77c1e3ccSAndroid Build Coastguard Worker
3981*77c1e3ccSAndroid Build Coastguard Worker delete[] m_pWritingAppAsUTF8;
3982*77c1e3ccSAndroid Build Coastguard Worker m_pWritingAppAsUTF8 = NULL;
3983*77c1e3ccSAndroid Build Coastguard Worker
3984*77c1e3ccSAndroid Build Coastguard Worker delete[] m_pTitleAsUTF8;
3985*77c1e3ccSAndroid Build Coastguard Worker m_pTitleAsUTF8 = NULL;
3986*77c1e3ccSAndroid Build Coastguard Worker }
3987*77c1e3ccSAndroid Build Coastguard Worker
Parse()3988*77c1e3ccSAndroid Build Coastguard Worker long SegmentInfo::Parse() {
3989*77c1e3ccSAndroid Build Coastguard Worker assert(m_pMuxingAppAsUTF8 == NULL);
3990*77c1e3ccSAndroid Build Coastguard Worker assert(m_pWritingAppAsUTF8 == NULL);
3991*77c1e3ccSAndroid Build Coastguard Worker assert(m_pTitleAsUTF8 == NULL);
3992*77c1e3ccSAndroid Build Coastguard Worker
3993*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
3994*77c1e3ccSAndroid Build Coastguard Worker
3995*77c1e3ccSAndroid Build Coastguard Worker long long pos = m_start;
3996*77c1e3ccSAndroid Build Coastguard Worker const long long stop = m_start + m_size;
3997*77c1e3ccSAndroid Build Coastguard Worker
3998*77c1e3ccSAndroid Build Coastguard Worker m_timecodeScale = 1000000;
3999*77c1e3ccSAndroid Build Coastguard Worker m_duration = -1;
4000*77c1e3ccSAndroid Build Coastguard Worker
4001*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
4002*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
4003*77c1e3ccSAndroid Build Coastguard Worker
4004*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, stop, id, size);
4005*77c1e3ccSAndroid Build Coastguard Worker
4006*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4007*77c1e3ccSAndroid Build Coastguard Worker return status;
4008*77c1e3ccSAndroid Build Coastguard Worker
4009*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvTimecodeScale) {
4010*77c1e3ccSAndroid Build Coastguard Worker m_timecodeScale = UnserializeUInt(pReader, pos, size);
4011*77c1e3ccSAndroid Build Coastguard Worker
4012*77c1e3ccSAndroid Build Coastguard Worker if (m_timecodeScale <= 0)
4013*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4014*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvDuration) {
4015*77c1e3ccSAndroid Build Coastguard Worker const long status = UnserializeFloat(pReader, pos, size, m_duration);
4016*77c1e3ccSAndroid Build Coastguard Worker
4017*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
4018*77c1e3ccSAndroid Build Coastguard Worker return status;
4019*77c1e3ccSAndroid Build Coastguard Worker
4020*77c1e3ccSAndroid Build Coastguard Worker if (m_duration < 0)
4021*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4022*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvMuxingApp) {
4023*77c1e3ccSAndroid Build Coastguard Worker const long status =
4024*77c1e3ccSAndroid Build Coastguard Worker UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
4025*77c1e3ccSAndroid Build Coastguard Worker
4026*77c1e3ccSAndroid Build Coastguard Worker if (status)
4027*77c1e3ccSAndroid Build Coastguard Worker return status;
4028*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvWritingApp) {
4029*77c1e3ccSAndroid Build Coastguard Worker const long status =
4030*77c1e3ccSAndroid Build Coastguard Worker UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
4031*77c1e3ccSAndroid Build Coastguard Worker
4032*77c1e3ccSAndroid Build Coastguard Worker if (status)
4033*77c1e3ccSAndroid Build Coastguard Worker return status;
4034*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvTitle) {
4035*77c1e3ccSAndroid Build Coastguard Worker const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
4036*77c1e3ccSAndroid Build Coastguard Worker
4037*77c1e3ccSAndroid Build Coastguard Worker if (status)
4038*77c1e3ccSAndroid Build Coastguard Worker return status;
4039*77c1e3ccSAndroid Build Coastguard Worker }
4040*77c1e3ccSAndroid Build Coastguard Worker
4041*77c1e3ccSAndroid Build Coastguard Worker pos += size;
4042*77c1e3ccSAndroid Build Coastguard Worker
4043*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
4044*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4045*77c1e3ccSAndroid Build Coastguard Worker }
4046*77c1e3ccSAndroid Build Coastguard Worker
4047*77c1e3ccSAndroid Build Coastguard Worker const double rollover_check = m_duration * m_timecodeScale;
4048*77c1e3ccSAndroid Build Coastguard Worker if (rollover_check > static_cast<double>(LLONG_MAX))
4049*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4050*77c1e3ccSAndroid Build Coastguard Worker
4051*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
4052*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4053*77c1e3ccSAndroid Build Coastguard Worker
4054*77c1e3ccSAndroid Build Coastguard Worker return 0;
4055*77c1e3ccSAndroid Build Coastguard Worker }
4056*77c1e3ccSAndroid Build Coastguard Worker
GetTimeCodeScale() const4057*77c1e3ccSAndroid Build Coastguard Worker long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; }
4058*77c1e3ccSAndroid Build Coastguard Worker
GetDuration() const4059*77c1e3ccSAndroid Build Coastguard Worker long long SegmentInfo::GetDuration() const {
4060*77c1e3ccSAndroid Build Coastguard Worker if (m_duration < 0)
4061*77c1e3ccSAndroid Build Coastguard Worker return -1;
4062*77c1e3ccSAndroid Build Coastguard Worker
4063*77c1e3ccSAndroid Build Coastguard Worker assert(m_timecodeScale >= 1);
4064*77c1e3ccSAndroid Build Coastguard Worker
4065*77c1e3ccSAndroid Build Coastguard Worker const double dd = double(m_duration) * double(m_timecodeScale);
4066*77c1e3ccSAndroid Build Coastguard Worker const long long d = static_cast<long long>(dd);
4067*77c1e3ccSAndroid Build Coastguard Worker
4068*77c1e3ccSAndroid Build Coastguard Worker return d;
4069*77c1e3ccSAndroid Build Coastguard Worker }
4070*77c1e3ccSAndroid Build Coastguard Worker
GetMuxingAppAsUTF8() const4071*77c1e3ccSAndroid Build Coastguard Worker const char* SegmentInfo::GetMuxingAppAsUTF8() const {
4072*77c1e3ccSAndroid Build Coastguard Worker return m_pMuxingAppAsUTF8;
4073*77c1e3ccSAndroid Build Coastguard Worker }
4074*77c1e3ccSAndroid Build Coastguard Worker
GetWritingAppAsUTF8() const4075*77c1e3ccSAndroid Build Coastguard Worker const char* SegmentInfo::GetWritingAppAsUTF8() const {
4076*77c1e3ccSAndroid Build Coastguard Worker return m_pWritingAppAsUTF8;
4077*77c1e3ccSAndroid Build Coastguard Worker }
4078*77c1e3ccSAndroid Build Coastguard Worker
GetTitleAsUTF8() const4079*77c1e3ccSAndroid Build Coastguard Worker const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; }
4080*77c1e3ccSAndroid Build Coastguard Worker
4081*77c1e3ccSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////
4082*77c1e3ccSAndroid Build Coastguard Worker // ContentEncoding element
ContentCompression()4083*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding::ContentCompression::ContentCompression()
4084*77c1e3ccSAndroid Build Coastguard Worker : algo(0), settings(NULL), settings_len(0) {}
4085*77c1e3ccSAndroid Build Coastguard Worker
~ContentCompression()4086*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding::ContentCompression::~ContentCompression() {
4087*77c1e3ccSAndroid Build Coastguard Worker delete[] settings;
4088*77c1e3ccSAndroid Build Coastguard Worker }
4089*77c1e3ccSAndroid Build Coastguard Worker
ContentEncryption()4090*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding::ContentEncryption::ContentEncryption()
4091*77c1e3ccSAndroid Build Coastguard Worker : algo(0),
4092*77c1e3ccSAndroid Build Coastguard Worker key_id(NULL),
4093*77c1e3ccSAndroid Build Coastguard Worker key_id_len(0),
4094*77c1e3ccSAndroid Build Coastguard Worker signature(NULL),
4095*77c1e3ccSAndroid Build Coastguard Worker signature_len(0),
4096*77c1e3ccSAndroid Build Coastguard Worker sig_key_id(NULL),
4097*77c1e3ccSAndroid Build Coastguard Worker sig_key_id_len(0),
4098*77c1e3ccSAndroid Build Coastguard Worker sig_algo(0),
4099*77c1e3ccSAndroid Build Coastguard Worker sig_hash_algo(0) {}
4100*77c1e3ccSAndroid Build Coastguard Worker
~ContentEncryption()4101*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding::ContentEncryption::~ContentEncryption() {
4102*77c1e3ccSAndroid Build Coastguard Worker delete[] key_id;
4103*77c1e3ccSAndroid Build Coastguard Worker delete[] signature;
4104*77c1e3ccSAndroid Build Coastguard Worker delete[] sig_key_id;
4105*77c1e3ccSAndroid Build Coastguard Worker }
4106*77c1e3ccSAndroid Build Coastguard Worker
ContentEncoding()4107*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding::ContentEncoding()
4108*77c1e3ccSAndroid Build Coastguard Worker : compression_entries_(NULL),
4109*77c1e3ccSAndroid Build Coastguard Worker compression_entries_end_(NULL),
4110*77c1e3ccSAndroid Build Coastguard Worker encryption_entries_(NULL),
4111*77c1e3ccSAndroid Build Coastguard Worker encryption_entries_end_(NULL),
4112*77c1e3ccSAndroid Build Coastguard Worker encoding_order_(0),
4113*77c1e3ccSAndroid Build Coastguard Worker encoding_scope_(1),
4114*77c1e3ccSAndroid Build Coastguard Worker encoding_type_(0) {}
4115*77c1e3ccSAndroid Build Coastguard Worker
~ContentEncoding()4116*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding::~ContentEncoding() {
4117*77c1e3ccSAndroid Build Coastguard Worker ContentCompression** comp_i = compression_entries_;
4118*77c1e3ccSAndroid Build Coastguard Worker ContentCompression** const comp_j = compression_entries_end_;
4119*77c1e3ccSAndroid Build Coastguard Worker
4120*77c1e3ccSAndroid Build Coastguard Worker while (comp_i != comp_j) {
4121*77c1e3ccSAndroid Build Coastguard Worker ContentCompression* const comp = *comp_i++;
4122*77c1e3ccSAndroid Build Coastguard Worker delete comp;
4123*77c1e3ccSAndroid Build Coastguard Worker }
4124*77c1e3ccSAndroid Build Coastguard Worker
4125*77c1e3ccSAndroid Build Coastguard Worker delete[] compression_entries_;
4126*77c1e3ccSAndroid Build Coastguard Worker
4127*77c1e3ccSAndroid Build Coastguard Worker ContentEncryption** enc_i = encryption_entries_;
4128*77c1e3ccSAndroid Build Coastguard Worker ContentEncryption** const enc_j = encryption_entries_end_;
4129*77c1e3ccSAndroid Build Coastguard Worker
4130*77c1e3ccSAndroid Build Coastguard Worker while (enc_i != enc_j) {
4131*77c1e3ccSAndroid Build Coastguard Worker ContentEncryption* const enc = *enc_i++;
4132*77c1e3ccSAndroid Build Coastguard Worker delete enc;
4133*77c1e3ccSAndroid Build Coastguard Worker }
4134*77c1e3ccSAndroid Build Coastguard Worker
4135*77c1e3ccSAndroid Build Coastguard Worker delete[] encryption_entries_;
4136*77c1e3ccSAndroid Build Coastguard Worker }
4137*77c1e3ccSAndroid Build Coastguard Worker
4138*77c1e3ccSAndroid Build Coastguard Worker const ContentEncoding::ContentCompression*
GetCompressionByIndex(unsigned long idx) const4139*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
4140*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4141*77c1e3ccSAndroid Build Coastguard Worker assert(count >= 0);
4142*77c1e3ccSAndroid Build Coastguard Worker
4143*77c1e3ccSAndroid Build Coastguard Worker if (idx >= static_cast<unsigned long>(count))
4144*77c1e3ccSAndroid Build Coastguard Worker return NULL;
4145*77c1e3ccSAndroid Build Coastguard Worker
4146*77c1e3ccSAndroid Build Coastguard Worker return compression_entries_[idx];
4147*77c1e3ccSAndroid Build Coastguard Worker }
4148*77c1e3ccSAndroid Build Coastguard Worker
GetCompressionCount() const4149*77c1e3ccSAndroid Build Coastguard Worker unsigned long ContentEncoding::GetCompressionCount() const {
4150*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4151*77c1e3ccSAndroid Build Coastguard Worker assert(count >= 0);
4152*77c1e3ccSAndroid Build Coastguard Worker
4153*77c1e3ccSAndroid Build Coastguard Worker return static_cast<unsigned long>(count);
4154*77c1e3ccSAndroid Build Coastguard Worker }
4155*77c1e3ccSAndroid Build Coastguard Worker
GetEncryptionByIndex(unsigned long idx) const4156*77c1e3ccSAndroid Build Coastguard Worker const ContentEncoding::ContentEncryption* ContentEncoding::GetEncryptionByIndex(
4157*77c1e3ccSAndroid Build Coastguard Worker unsigned long idx) const {
4158*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4159*77c1e3ccSAndroid Build Coastguard Worker assert(count >= 0);
4160*77c1e3ccSAndroid Build Coastguard Worker
4161*77c1e3ccSAndroid Build Coastguard Worker if (idx >= static_cast<unsigned long>(count))
4162*77c1e3ccSAndroid Build Coastguard Worker return NULL;
4163*77c1e3ccSAndroid Build Coastguard Worker
4164*77c1e3ccSAndroid Build Coastguard Worker return encryption_entries_[idx];
4165*77c1e3ccSAndroid Build Coastguard Worker }
4166*77c1e3ccSAndroid Build Coastguard Worker
GetEncryptionCount() const4167*77c1e3ccSAndroid Build Coastguard Worker unsigned long ContentEncoding::GetEncryptionCount() const {
4168*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4169*77c1e3ccSAndroid Build Coastguard Worker assert(count >= 0);
4170*77c1e3ccSAndroid Build Coastguard Worker
4171*77c1e3ccSAndroid Build Coastguard Worker return static_cast<unsigned long>(count);
4172*77c1e3ccSAndroid Build Coastguard Worker }
4173*77c1e3ccSAndroid Build Coastguard Worker
ParseContentEncAESSettingsEntry(long long start,long long size,IMkvReader * pReader,ContentEncAESSettings * aes)4174*77c1e3ccSAndroid Build Coastguard Worker long ContentEncoding::ParseContentEncAESSettingsEntry(
4175*77c1e3ccSAndroid Build Coastguard Worker long long start, long long size, IMkvReader* pReader,
4176*77c1e3ccSAndroid Build Coastguard Worker ContentEncAESSettings* aes) {
4177*77c1e3ccSAndroid Build Coastguard Worker assert(pReader);
4178*77c1e3ccSAndroid Build Coastguard Worker assert(aes);
4179*77c1e3ccSAndroid Build Coastguard Worker
4180*77c1e3ccSAndroid Build Coastguard Worker long long pos = start;
4181*77c1e3ccSAndroid Build Coastguard Worker const long long stop = start + size;
4182*77c1e3ccSAndroid Build Coastguard Worker
4183*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
4184*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
4185*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, stop, id, size);
4186*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4187*77c1e3ccSAndroid Build Coastguard Worker return status;
4188*77c1e3ccSAndroid Build Coastguard Worker
4189*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvAESSettingsCipherMode) {
4190*77c1e3ccSAndroid Build Coastguard Worker aes->cipher_mode = UnserializeUInt(pReader, pos, size);
4191*77c1e3ccSAndroid Build Coastguard Worker if (aes->cipher_mode != 1)
4192*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4193*77c1e3ccSAndroid Build Coastguard Worker }
4194*77c1e3ccSAndroid Build Coastguard Worker
4195*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
4196*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
4197*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4198*77c1e3ccSAndroid Build Coastguard Worker }
4199*77c1e3ccSAndroid Build Coastguard Worker
4200*77c1e3ccSAndroid Build Coastguard Worker return 0;
4201*77c1e3ccSAndroid Build Coastguard Worker }
4202*77c1e3ccSAndroid Build Coastguard Worker
ParseContentEncodingEntry(long long start,long long size,IMkvReader * pReader)4203*77c1e3ccSAndroid Build Coastguard Worker long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
4204*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* pReader) {
4205*77c1e3ccSAndroid Build Coastguard Worker assert(pReader);
4206*77c1e3ccSAndroid Build Coastguard Worker
4207*77c1e3ccSAndroid Build Coastguard Worker long long pos = start;
4208*77c1e3ccSAndroid Build Coastguard Worker const long long stop = start + size;
4209*77c1e3ccSAndroid Build Coastguard Worker
4210*77c1e3ccSAndroid Build Coastguard Worker // Count ContentCompression and ContentEncryption elements.
4211*77c1e3ccSAndroid Build Coastguard Worker long long compression_count = 0;
4212*77c1e3ccSAndroid Build Coastguard Worker long long encryption_count = 0;
4213*77c1e3ccSAndroid Build Coastguard Worker
4214*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
4215*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
4216*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, stop, id, size);
4217*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4218*77c1e3ccSAndroid Build Coastguard Worker return status;
4219*77c1e3ccSAndroid Build Coastguard Worker
4220*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvContentCompression) {
4221*77c1e3ccSAndroid Build Coastguard Worker ++compression_count;
4222*77c1e3ccSAndroid Build Coastguard Worker if (compression_count > INT_MAX)
4223*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
4224*77c1e3ccSAndroid Build Coastguard Worker }
4225*77c1e3ccSAndroid Build Coastguard Worker
4226*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvContentEncryption) {
4227*77c1e3ccSAndroid Build Coastguard Worker ++encryption_count;
4228*77c1e3ccSAndroid Build Coastguard Worker if (encryption_count > INT_MAX)
4229*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
4230*77c1e3ccSAndroid Build Coastguard Worker }
4231*77c1e3ccSAndroid Build Coastguard Worker
4232*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
4233*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
4234*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4235*77c1e3ccSAndroid Build Coastguard Worker }
4236*77c1e3ccSAndroid Build Coastguard Worker
4237*77c1e3ccSAndroid Build Coastguard Worker if (compression_count <= 0 && encryption_count <= 0)
4238*77c1e3ccSAndroid Build Coastguard Worker return -1;
4239*77c1e3ccSAndroid Build Coastguard Worker
4240*77c1e3ccSAndroid Build Coastguard Worker if (compression_count > 0) {
4241*77c1e3ccSAndroid Build Coastguard Worker compression_entries_ = new (std::nothrow)
4242*77c1e3ccSAndroid Build Coastguard Worker ContentCompression*[static_cast<size_t>(compression_count)];
4243*77c1e3ccSAndroid Build Coastguard Worker if (!compression_entries_)
4244*77c1e3ccSAndroid Build Coastguard Worker return -1;
4245*77c1e3ccSAndroid Build Coastguard Worker compression_entries_end_ = compression_entries_;
4246*77c1e3ccSAndroid Build Coastguard Worker }
4247*77c1e3ccSAndroid Build Coastguard Worker
4248*77c1e3ccSAndroid Build Coastguard Worker if (encryption_count > 0) {
4249*77c1e3ccSAndroid Build Coastguard Worker encryption_entries_ = new (std::nothrow)
4250*77c1e3ccSAndroid Build Coastguard Worker ContentEncryption*[static_cast<size_t>(encryption_count)];
4251*77c1e3ccSAndroid Build Coastguard Worker if (!encryption_entries_) {
4252*77c1e3ccSAndroid Build Coastguard Worker delete[] compression_entries_;
4253*77c1e3ccSAndroid Build Coastguard Worker compression_entries_ = NULL;
4254*77c1e3ccSAndroid Build Coastguard Worker return -1;
4255*77c1e3ccSAndroid Build Coastguard Worker }
4256*77c1e3ccSAndroid Build Coastguard Worker encryption_entries_end_ = encryption_entries_;
4257*77c1e3ccSAndroid Build Coastguard Worker }
4258*77c1e3ccSAndroid Build Coastguard Worker
4259*77c1e3ccSAndroid Build Coastguard Worker pos = start;
4260*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
4261*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
4262*77c1e3ccSAndroid Build Coastguard Worker long status = ParseElementHeader(pReader, pos, stop, id, size);
4263*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4264*77c1e3ccSAndroid Build Coastguard Worker return status;
4265*77c1e3ccSAndroid Build Coastguard Worker
4266*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvContentEncodingOrder) {
4267*77c1e3ccSAndroid Build Coastguard Worker encoding_order_ = UnserializeUInt(pReader, pos, size);
4268*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentEncodingScope) {
4269*77c1e3ccSAndroid Build Coastguard Worker encoding_scope_ = UnserializeUInt(pReader, pos, size);
4270*77c1e3ccSAndroid Build Coastguard Worker if (encoding_scope_ < 1)
4271*77c1e3ccSAndroid Build Coastguard Worker return -1;
4272*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentEncodingType) {
4273*77c1e3ccSAndroid Build Coastguard Worker encoding_type_ = UnserializeUInt(pReader, pos, size);
4274*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentCompression) {
4275*77c1e3ccSAndroid Build Coastguard Worker ContentCompression* const compression =
4276*77c1e3ccSAndroid Build Coastguard Worker new (std::nothrow) ContentCompression();
4277*77c1e3ccSAndroid Build Coastguard Worker if (!compression)
4278*77c1e3ccSAndroid Build Coastguard Worker return -1;
4279*77c1e3ccSAndroid Build Coastguard Worker
4280*77c1e3ccSAndroid Build Coastguard Worker status = ParseCompressionEntry(pos, size, pReader, compression);
4281*77c1e3ccSAndroid Build Coastguard Worker if (status) {
4282*77c1e3ccSAndroid Build Coastguard Worker delete compression;
4283*77c1e3ccSAndroid Build Coastguard Worker return status;
4284*77c1e3ccSAndroid Build Coastguard Worker }
4285*77c1e3ccSAndroid Build Coastguard Worker assert(compression_count > 0);
4286*77c1e3ccSAndroid Build Coastguard Worker *compression_entries_end_++ = compression;
4287*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentEncryption) {
4288*77c1e3ccSAndroid Build Coastguard Worker ContentEncryption* const encryption =
4289*77c1e3ccSAndroid Build Coastguard Worker new (std::nothrow) ContentEncryption();
4290*77c1e3ccSAndroid Build Coastguard Worker if (!encryption)
4291*77c1e3ccSAndroid Build Coastguard Worker return -1;
4292*77c1e3ccSAndroid Build Coastguard Worker
4293*77c1e3ccSAndroid Build Coastguard Worker status = ParseEncryptionEntry(pos, size, pReader, encryption);
4294*77c1e3ccSAndroid Build Coastguard Worker if (status) {
4295*77c1e3ccSAndroid Build Coastguard Worker delete encryption;
4296*77c1e3ccSAndroid Build Coastguard Worker return status;
4297*77c1e3ccSAndroid Build Coastguard Worker }
4298*77c1e3ccSAndroid Build Coastguard Worker assert(encryption_count > 0);
4299*77c1e3ccSAndroid Build Coastguard Worker *encryption_entries_end_++ = encryption;
4300*77c1e3ccSAndroid Build Coastguard Worker }
4301*77c1e3ccSAndroid Build Coastguard Worker
4302*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
4303*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
4304*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4305*77c1e3ccSAndroid Build Coastguard Worker }
4306*77c1e3ccSAndroid Build Coastguard Worker
4307*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
4308*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4309*77c1e3ccSAndroid Build Coastguard Worker return 0;
4310*77c1e3ccSAndroid Build Coastguard Worker }
4311*77c1e3ccSAndroid Build Coastguard Worker
ParseCompressionEntry(long long start,long long size,IMkvReader * pReader,ContentCompression * compression)4312*77c1e3ccSAndroid Build Coastguard Worker long ContentEncoding::ParseCompressionEntry(long long start, long long size,
4313*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* pReader,
4314*77c1e3ccSAndroid Build Coastguard Worker ContentCompression* compression) {
4315*77c1e3ccSAndroid Build Coastguard Worker assert(pReader);
4316*77c1e3ccSAndroid Build Coastguard Worker assert(compression);
4317*77c1e3ccSAndroid Build Coastguard Worker
4318*77c1e3ccSAndroid Build Coastguard Worker long long pos = start;
4319*77c1e3ccSAndroid Build Coastguard Worker const long long stop = start + size;
4320*77c1e3ccSAndroid Build Coastguard Worker
4321*77c1e3ccSAndroid Build Coastguard Worker bool valid = false;
4322*77c1e3ccSAndroid Build Coastguard Worker
4323*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
4324*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
4325*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, stop, id, size);
4326*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4327*77c1e3ccSAndroid Build Coastguard Worker return status;
4328*77c1e3ccSAndroid Build Coastguard Worker
4329*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvContentCompAlgo) {
4330*77c1e3ccSAndroid Build Coastguard Worker long long algo = UnserializeUInt(pReader, pos, size);
4331*77c1e3ccSAndroid Build Coastguard Worker if (algo < 0)
4332*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4333*77c1e3ccSAndroid Build Coastguard Worker compression->algo = algo;
4334*77c1e3ccSAndroid Build Coastguard Worker valid = true;
4335*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentCompSettings) {
4336*77c1e3ccSAndroid Build Coastguard Worker if (size <= 0)
4337*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4338*77c1e3ccSAndroid Build Coastguard Worker
4339*77c1e3ccSAndroid Build Coastguard Worker const size_t buflen = static_cast<size_t>(size);
4340*77c1e3ccSAndroid Build Coastguard Worker unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4341*77c1e3ccSAndroid Build Coastguard Worker if (buf == NULL)
4342*77c1e3ccSAndroid Build Coastguard Worker return -1;
4343*77c1e3ccSAndroid Build Coastguard Worker
4344*77c1e3ccSAndroid Build Coastguard Worker const int read_status =
4345*77c1e3ccSAndroid Build Coastguard Worker pReader->Read(pos, static_cast<long>(buflen), buf);
4346*77c1e3ccSAndroid Build Coastguard Worker if (read_status) {
4347*77c1e3ccSAndroid Build Coastguard Worker delete[] buf;
4348*77c1e3ccSAndroid Build Coastguard Worker return status;
4349*77c1e3ccSAndroid Build Coastguard Worker }
4350*77c1e3ccSAndroid Build Coastguard Worker
4351*77c1e3ccSAndroid Build Coastguard Worker // There should be only one settings element per content compression.
4352*77c1e3ccSAndroid Build Coastguard Worker if (compression->settings != NULL) {
4353*77c1e3ccSAndroid Build Coastguard Worker delete[] buf;
4354*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4355*77c1e3ccSAndroid Build Coastguard Worker }
4356*77c1e3ccSAndroid Build Coastguard Worker
4357*77c1e3ccSAndroid Build Coastguard Worker compression->settings = buf;
4358*77c1e3ccSAndroid Build Coastguard Worker compression->settings_len = buflen;
4359*77c1e3ccSAndroid Build Coastguard Worker }
4360*77c1e3ccSAndroid Build Coastguard Worker
4361*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
4362*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
4363*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4364*77c1e3ccSAndroid Build Coastguard Worker }
4365*77c1e3ccSAndroid Build Coastguard Worker
4366*77c1e3ccSAndroid Build Coastguard Worker // ContentCompAlgo is mandatory
4367*77c1e3ccSAndroid Build Coastguard Worker if (!valid)
4368*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4369*77c1e3ccSAndroid Build Coastguard Worker
4370*77c1e3ccSAndroid Build Coastguard Worker return 0;
4371*77c1e3ccSAndroid Build Coastguard Worker }
4372*77c1e3ccSAndroid Build Coastguard Worker
ParseEncryptionEntry(long long start,long long size,IMkvReader * pReader,ContentEncryption * encryption)4373*77c1e3ccSAndroid Build Coastguard Worker long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
4374*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* pReader,
4375*77c1e3ccSAndroid Build Coastguard Worker ContentEncryption* encryption) {
4376*77c1e3ccSAndroid Build Coastguard Worker assert(pReader);
4377*77c1e3ccSAndroid Build Coastguard Worker assert(encryption);
4378*77c1e3ccSAndroid Build Coastguard Worker
4379*77c1e3ccSAndroid Build Coastguard Worker long long pos = start;
4380*77c1e3ccSAndroid Build Coastguard Worker const long long stop = start + size;
4381*77c1e3ccSAndroid Build Coastguard Worker
4382*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
4383*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
4384*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, stop, id, size);
4385*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4386*77c1e3ccSAndroid Build Coastguard Worker return status;
4387*77c1e3ccSAndroid Build Coastguard Worker
4388*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvContentEncAlgo) {
4389*77c1e3ccSAndroid Build Coastguard Worker encryption->algo = UnserializeUInt(pReader, pos, size);
4390*77c1e3ccSAndroid Build Coastguard Worker if (encryption->algo != 5)
4391*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4392*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentEncKeyID) {
4393*77c1e3ccSAndroid Build Coastguard Worker delete[] encryption->key_id;
4394*77c1e3ccSAndroid Build Coastguard Worker encryption->key_id = NULL;
4395*77c1e3ccSAndroid Build Coastguard Worker encryption->key_id_len = 0;
4396*77c1e3ccSAndroid Build Coastguard Worker
4397*77c1e3ccSAndroid Build Coastguard Worker if (size <= 0)
4398*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4399*77c1e3ccSAndroid Build Coastguard Worker
4400*77c1e3ccSAndroid Build Coastguard Worker const size_t buflen = static_cast<size_t>(size);
4401*77c1e3ccSAndroid Build Coastguard Worker unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4402*77c1e3ccSAndroid Build Coastguard Worker if (buf == NULL)
4403*77c1e3ccSAndroid Build Coastguard Worker return -1;
4404*77c1e3ccSAndroid Build Coastguard Worker
4405*77c1e3ccSAndroid Build Coastguard Worker const int read_status =
4406*77c1e3ccSAndroid Build Coastguard Worker pReader->Read(pos, static_cast<long>(buflen), buf);
4407*77c1e3ccSAndroid Build Coastguard Worker if (read_status) {
4408*77c1e3ccSAndroid Build Coastguard Worker delete[] buf;
4409*77c1e3ccSAndroid Build Coastguard Worker return status;
4410*77c1e3ccSAndroid Build Coastguard Worker }
4411*77c1e3ccSAndroid Build Coastguard Worker
4412*77c1e3ccSAndroid Build Coastguard Worker encryption->key_id = buf;
4413*77c1e3ccSAndroid Build Coastguard Worker encryption->key_id_len = buflen;
4414*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentSignature) {
4415*77c1e3ccSAndroid Build Coastguard Worker delete[] encryption->signature;
4416*77c1e3ccSAndroid Build Coastguard Worker encryption->signature = NULL;
4417*77c1e3ccSAndroid Build Coastguard Worker encryption->signature_len = 0;
4418*77c1e3ccSAndroid Build Coastguard Worker
4419*77c1e3ccSAndroid Build Coastguard Worker if (size <= 0)
4420*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4421*77c1e3ccSAndroid Build Coastguard Worker
4422*77c1e3ccSAndroid Build Coastguard Worker const size_t buflen = static_cast<size_t>(size);
4423*77c1e3ccSAndroid Build Coastguard Worker unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4424*77c1e3ccSAndroid Build Coastguard Worker if (buf == NULL)
4425*77c1e3ccSAndroid Build Coastguard Worker return -1;
4426*77c1e3ccSAndroid Build Coastguard Worker
4427*77c1e3ccSAndroid Build Coastguard Worker const int read_status =
4428*77c1e3ccSAndroid Build Coastguard Worker pReader->Read(pos, static_cast<long>(buflen), buf);
4429*77c1e3ccSAndroid Build Coastguard Worker if (read_status) {
4430*77c1e3ccSAndroid Build Coastguard Worker delete[] buf;
4431*77c1e3ccSAndroid Build Coastguard Worker return status;
4432*77c1e3ccSAndroid Build Coastguard Worker }
4433*77c1e3ccSAndroid Build Coastguard Worker
4434*77c1e3ccSAndroid Build Coastguard Worker encryption->signature = buf;
4435*77c1e3ccSAndroid Build Coastguard Worker encryption->signature_len = buflen;
4436*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentSigKeyID) {
4437*77c1e3ccSAndroid Build Coastguard Worker delete[] encryption->sig_key_id;
4438*77c1e3ccSAndroid Build Coastguard Worker encryption->sig_key_id = NULL;
4439*77c1e3ccSAndroid Build Coastguard Worker encryption->sig_key_id_len = 0;
4440*77c1e3ccSAndroid Build Coastguard Worker
4441*77c1e3ccSAndroid Build Coastguard Worker if (size <= 0)
4442*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4443*77c1e3ccSAndroid Build Coastguard Worker
4444*77c1e3ccSAndroid Build Coastguard Worker const size_t buflen = static_cast<size_t>(size);
4445*77c1e3ccSAndroid Build Coastguard Worker unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4446*77c1e3ccSAndroid Build Coastguard Worker if (buf == NULL)
4447*77c1e3ccSAndroid Build Coastguard Worker return -1;
4448*77c1e3ccSAndroid Build Coastguard Worker
4449*77c1e3ccSAndroid Build Coastguard Worker const int read_status =
4450*77c1e3ccSAndroid Build Coastguard Worker pReader->Read(pos, static_cast<long>(buflen), buf);
4451*77c1e3ccSAndroid Build Coastguard Worker if (read_status) {
4452*77c1e3ccSAndroid Build Coastguard Worker delete[] buf;
4453*77c1e3ccSAndroid Build Coastguard Worker return status;
4454*77c1e3ccSAndroid Build Coastguard Worker }
4455*77c1e3ccSAndroid Build Coastguard Worker
4456*77c1e3ccSAndroid Build Coastguard Worker encryption->sig_key_id = buf;
4457*77c1e3ccSAndroid Build Coastguard Worker encryption->sig_key_id_len = buflen;
4458*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentSigAlgo) {
4459*77c1e3ccSAndroid Build Coastguard Worker encryption->sig_algo = UnserializeUInt(pReader, pos, size);
4460*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentSigHashAlgo) {
4461*77c1e3ccSAndroid Build Coastguard Worker encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
4462*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentEncAESSettings) {
4463*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseContentEncAESSettingsEntry(
4464*77c1e3ccSAndroid Build Coastguard Worker pos, size, pReader, &encryption->aes_settings);
4465*77c1e3ccSAndroid Build Coastguard Worker if (status)
4466*77c1e3ccSAndroid Build Coastguard Worker return status;
4467*77c1e3ccSAndroid Build Coastguard Worker }
4468*77c1e3ccSAndroid Build Coastguard Worker
4469*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
4470*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
4471*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4472*77c1e3ccSAndroid Build Coastguard Worker }
4473*77c1e3ccSAndroid Build Coastguard Worker
4474*77c1e3ccSAndroid Build Coastguard Worker return 0;
4475*77c1e3ccSAndroid Build Coastguard Worker }
4476*77c1e3ccSAndroid Build Coastguard Worker
Track(Segment * pSegment,long long element_start,long long element_size)4477*77c1e3ccSAndroid Build Coastguard Worker Track::Track(Segment* pSegment, long long element_start, long long element_size)
4478*77c1e3ccSAndroid Build Coastguard Worker : m_pSegment(pSegment),
4479*77c1e3ccSAndroid Build Coastguard Worker m_element_start(element_start),
4480*77c1e3ccSAndroid Build Coastguard Worker m_element_size(element_size),
4481*77c1e3ccSAndroid Build Coastguard Worker content_encoding_entries_(NULL),
4482*77c1e3ccSAndroid Build Coastguard Worker content_encoding_entries_end_(NULL) {}
4483*77c1e3ccSAndroid Build Coastguard Worker
~Track()4484*77c1e3ccSAndroid Build Coastguard Worker Track::~Track() {
4485*77c1e3ccSAndroid Build Coastguard Worker Info& info = const_cast<Info&>(m_info);
4486*77c1e3ccSAndroid Build Coastguard Worker info.Clear();
4487*77c1e3ccSAndroid Build Coastguard Worker
4488*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding** i = content_encoding_entries_;
4489*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding** const j = content_encoding_entries_end_;
4490*77c1e3ccSAndroid Build Coastguard Worker
4491*77c1e3ccSAndroid Build Coastguard Worker while (i != j) {
4492*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding* const encoding = *i++;
4493*77c1e3ccSAndroid Build Coastguard Worker delete encoding;
4494*77c1e3ccSAndroid Build Coastguard Worker }
4495*77c1e3ccSAndroid Build Coastguard Worker
4496*77c1e3ccSAndroid Build Coastguard Worker delete[] content_encoding_entries_;
4497*77c1e3ccSAndroid Build Coastguard Worker }
4498*77c1e3ccSAndroid Build Coastguard Worker
Create(Segment * pSegment,const Info & info,long long element_start,long long element_size,Track * & pResult)4499*77c1e3ccSAndroid Build Coastguard Worker long Track::Create(Segment* pSegment, const Info& info, long long element_start,
4500*77c1e3ccSAndroid Build Coastguard Worker long long element_size, Track*& pResult) {
4501*77c1e3ccSAndroid Build Coastguard Worker if (pResult)
4502*77c1e3ccSAndroid Build Coastguard Worker return -1;
4503*77c1e3ccSAndroid Build Coastguard Worker
4504*77c1e3ccSAndroid Build Coastguard Worker Track* const pTrack =
4505*77c1e3ccSAndroid Build Coastguard Worker new (std::nothrow) Track(pSegment, element_start, element_size);
4506*77c1e3ccSAndroid Build Coastguard Worker
4507*77c1e3ccSAndroid Build Coastguard Worker if (pTrack == NULL)
4508*77c1e3ccSAndroid Build Coastguard Worker return -1; // generic error
4509*77c1e3ccSAndroid Build Coastguard Worker
4510*77c1e3ccSAndroid Build Coastguard Worker const int status = info.Copy(pTrack->m_info);
4511*77c1e3ccSAndroid Build Coastguard Worker
4512*77c1e3ccSAndroid Build Coastguard Worker if (status) { // error
4513*77c1e3ccSAndroid Build Coastguard Worker delete pTrack;
4514*77c1e3ccSAndroid Build Coastguard Worker return status;
4515*77c1e3ccSAndroid Build Coastguard Worker }
4516*77c1e3ccSAndroid Build Coastguard Worker
4517*77c1e3ccSAndroid Build Coastguard Worker pResult = pTrack;
4518*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
4519*77c1e3ccSAndroid Build Coastguard Worker }
4520*77c1e3ccSAndroid Build Coastguard Worker
Info()4521*77c1e3ccSAndroid Build Coastguard Worker Track::Info::Info()
4522*77c1e3ccSAndroid Build Coastguard Worker : uid(0),
4523*77c1e3ccSAndroid Build Coastguard Worker defaultDuration(0),
4524*77c1e3ccSAndroid Build Coastguard Worker codecDelay(0),
4525*77c1e3ccSAndroid Build Coastguard Worker seekPreRoll(0),
4526*77c1e3ccSAndroid Build Coastguard Worker nameAsUTF8(NULL),
4527*77c1e3ccSAndroid Build Coastguard Worker language(NULL),
4528*77c1e3ccSAndroid Build Coastguard Worker codecId(NULL),
4529*77c1e3ccSAndroid Build Coastguard Worker codecNameAsUTF8(NULL),
4530*77c1e3ccSAndroid Build Coastguard Worker codecPrivate(NULL),
4531*77c1e3ccSAndroid Build Coastguard Worker codecPrivateSize(0),
4532*77c1e3ccSAndroid Build Coastguard Worker lacing(false) {}
4533*77c1e3ccSAndroid Build Coastguard Worker
~Info()4534*77c1e3ccSAndroid Build Coastguard Worker Track::Info::~Info() { Clear(); }
4535*77c1e3ccSAndroid Build Coastguard Worker
Clear()4536*77c1e3ccSAndroid Build Coastguard Worker void Track::Info::Clear() {
4537*77c1e3ccSAndroid Build Coastguard Worker delete[] nameAsUTF8;
4538*77c1e3ccSAndroid Build Coastguard Worker nameAsUTF8 = NULL;
4539*77c1e3ccSAndroid Build Coastguard Worker
4540*77c1e3ccSAndroid Build Coastguard Worker delete[] language;
4541*77c1e3ccSAndroid Build Coastguard Worker language = NULL;
4542*77c1e3ccSAndroid Build Coastguard Worker
4543*77c1e3ccSAndroid Build Coastguard Worker delete[] codecId;
4544*77c1e3ccSAndroid Build Coastguard Worker codecId = NULL;
4545*77c1e3ccSAndroid Build Coastguard Worker
4546*77c1e3ccSAndroid Build Coastguard Worker delete[] codecPrivate;
4547*77c1e3ccSAndroid Build Coastguard Worker codecPrivate = NULL;
4548*77c1e3ccSAndroid Build Coastguard Worker codecPrivateSize = 0;
4549*77c1e3ccSAndroid Build Coastguard Worker
4550*77c1e3ccSAndroid Build Coastguard Worker delete[] codecNameAsUTF8;
4551*77c1e3ccSAndroid Build Coastguard Worker codecNameAsUTF8 = NULL;
4552*77c1e3ccSAndroid Build Coastguard Worker }
4553*77c1e3ccSAndroid Build Coastguard Worker
CopyStr(char * Info::* str,Info & dst_) const4554*77c1e3ccSAndroid Build Coastguard Worker int Track::Info::CopyStr(char* Info::*str, Info& dst_) const {
4555*77c1e3ccSAndroid Build Coastguard Worker if (str == static_cast<char * Info::*>(NULL))
4556*77c1e3ccSAndroid Build Coastguard Worker return -1;
4557*77c1e3ccSAndroid Build Coastguard Worker
4558*77c1e3ccSAndroid Build Coastguard Worker char*& dst = dst_.*str;
4559*77c1e3ccSAndroid Build Coastguard Worker
4560*77c1e3ccSAndroid Build Coastguard Worker if (dst) // should be NULL already
4561*77c1e3ccSAndroid Build Coastguard Worker return -1;
4562*77c1e3ccSAndroid Build Coastguard Worker
4563*77c1e3ccSAndroid Build Coastguard Worker const char* const src = this->*str;
4564*77c1e3ccSAndroid Build Coastguard Worker
4565*77c1e3ccSAndroid Build Coastguard Worker if (src == NULL)
4566*77c1e3ccSAndroid Build Coastguard Worker return 0;
4567*77c1e3ccSAndroid Build Coastguard Worker
4568*77c1e3ccSAndroid Build Coastguard Worker const size_t len = strlen(src);
4569*77c1e3ccSAndroid Build Coastguard Worker
4570*77c1e3ccSAndroid Build Coastguard Worker dst = SafeArrayAlloc<char>(1, len + 1);
4571*77c1e3ccSAndroid Build Coastguard Worker
4572*77c1e3ccSAndroid Build Coastguard Worker if (dst == NULL)
4573*77c1e3ccSAndroid Build Coastguard Worker return -1;
4574*77c1e3ccSAndroid Build Coastguard Worker
4575*77c1e3ccSAndroid Build Coastguard Worker memcpy(dst, src, len);
4576*77c1e3ccSAndroid Build Coastguard Worker dst[len] = '\0';
4577*77c1e3ccSAndroid Build Coastguard Worker
4578*77c1e3ccSAndroid Build Coastguard Worker return 0;
4579*77c1e3ccSAndroid Build Coastguard Worker }
4580*77c1e3ccSAndroid Build Coastguard Worker
Copy(Info & dst) const4581*77c1e3ccSAndroid Build Coastguard Worker int Track::Info::Copy(Info& dst) const {
4582*77c1e3ccSAndroid Build Coastguard Worker if (&dst == this)
4583*77c1e3ccSAndroid Build Coastguard Worker return 0;
4584*77c1e3ccSAndroid Build Coastguard Worker
4585*77c1e3ccSAndroid Build Coastguard Worker dst.type = type;
4586*77c1e3ccSAndroid Build Coastguard Worker dst.number = number;
4587*77c1e3ccSAndroid Build Coastguard Worker dst.defaultDuration = defaultDuration;
4588*77c1e3ccSAndroid Build Coastguard Worker dst.codecDelay = codecDelay;
4589*77c1e3ccSAndroid Build Coastguard Worker dst.seekPreRoll = seekPreRoll;
4590*77c1e3ccSAndroid Build Coastguard Worker dst.uid = uid;
4591*77c1e3ccSAndroid Build Coastguard Worker dst.lacing = lacing;
4592*77c1e3ccSAndroid Build Coastguard Worker dst.settings = settings;
4593*77c1e3ccSAndroid Build Coastguard Worker
4594*77c1e3ccSAndroid Build Coastguard Worker // We now copy the string member variables from src to dst.
4595*77c1e3ccSAndroid Build Coastguard Worker // This involves memory allocation so in principle the operation
4596*77c1e3ccSAndroid Build Coastguard Worker // can fail (indeed, that's why we have Info::Copy), so we must
4597*77c1e3ccSAndroid Build Coastguard Worker // report this to the caller. An error return from this function
4598*77c1e3ccSAndroid Build Coastguard Worker // therefore implies that the copy was only partially successful.
4599*77c1e3ccSAndroid Build Coastguard Worker
4600*77c1e3ccSAndroid Build Coastguard Worker if (int status = CopyStr(&Info::nameAsUTF8, dst))
4601*77c1e3ccSAndroid Build Coastguard Worker return status;
4602*77c1e3ccSAndroid Build Coastguard Worker
4603*77c1e3ccSAndroid Build Coastguard Worker if (int status = CopyStr(&Info::language, dst))
4604*77c1e3ccSAndroid Build Coastguard Worker return status;
4605*77c1e3ccSAndroid Build Coastguard Worker
4606*77c1e3ccSAndroid Build Coastguard Worker if (int status = CopyStr(&Info::codecId, dst))
4607*77c1e3ccSAndroid Build Coastguard Worker return status;
4608*77c1e3ccSAndroid Build Coastguard Worker
4609*77c1e3ccSAndroid Build Coastguard Worker if (int status = CopyStr(&Info::codecNameAsUTF8, dst))
4610*77c1e3ccSAndroid Build Coastguard Worker return status;
4611*77c1e3ccSAndroid Build Coastguard Worker
4612*77c1e3ccSAndroid Build Coastguard Worker if (codecPrivateSize > 0) {
4613*77c1e3ccSAndroid Build Coastguard Worker if (codecPrivate == NULL)
4614*77c1e3ccSAndroid Build Coastguard Worker return -1;
4615*77c1e3ccSAndroid Build Coastguard Worker
4616*77c1e3ccSAndroid Build Coastguard Worker if (dst.codecPrivate)
4617*77c1e3ccSAndroid Build Coastguard Worker return -1;
4618*77c1e3ccSAndroid Build Coastguard Worker
4619*77c1e3ccSAndroid Build Coastguard Worker if (dst.codecPrivateSize != 0)
4620*77c1e3ccSAndroid Build Coastguard Worker return -1;
4621*77c1e3ccSAndroid Build Coastguard Worker
4622*77c1e3ccSAndroid Build Coastguard Worker dst.codecPrivate = SafeArrayAlloc<unsigned char>(1, codecPrivateSize);
4623*77c1e3ccSAndroid Build Coastguard Worker
4624*77c1e3ccSAndroid Build Coastguard Worker if (dst.codecPrivate == NULL)
4625*77c1e3ccSAndroid Build Coastguard Worker return -1;
4626*77c1e3ccSAndroid Build Coastguard Worker
4627*77c1e3ccSAndroid Build Coastguard Worker memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);
4628*77c1e3ccSAndroid Build Coastguard Worker dst.codecPrivateSize = codecPrivateSize;
4629*77c1e3ccSAndroid Build Coastguard Worker }
4630*77c1e3ccSAndroid Build Coastguard Worker
4631*77c1e3ccSAndroid Build Coastguard Worker return 0;
4632*77c1e3ccSAndroid Build Coastguard Worker }
4633*77c1e3ccSAndroid Build Coastguard Worker
GetEOS() const4634*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* Track::GetEOS() const { return &m_eos; }
4635*77c1e3ccSAndroid Build Coastguard Worker
GetType() const4636*77c1e3ccSAndroid Build Coastguard Worker long Track::GetType() const { return m_info.type; }
4637*77c1e3ccSAndroid Build Coastguard Worker
GetNumber() const4638*77c1e3ccSAndroid Build Coastguard Worker long Track::GetNumber() const { return m_info.number; }
4639*77c1e3ccSAndroid Build Coastguard Worker
GetUid() const4640*77c1e3ccSAndroid Build Coastguard Worker unsigned long long Track::GetUid() const { return m_info.uid; }
4641*77c1e3ccSAndroid Build Coastguard Worker
GetNameAsUTF8() const4642*77c1e3ccSAndroid Build Coastguard Worker const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; }
4643*77c1e3ccSAndroid Build Coastguard Worker
GetLanguage() const4644*77c1e3ccSAndroid Build Coastguard Worker const char* Track::GetLanguage() const { return m_info.language; }
4645*77c1e3ccSAndroid Build Coastguard Worker
GetCodecNameAsUTF8() const4646*77c1e3ccSAndroid Build Coastguard Worker const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; }
4647*77c1e3ccSAndroid Build Coastguard Worker
GetCodecId() const4648*77c1e3ccSAndroid Build Coastguard Worker const char* Track::GetCodecId() const { return m_info.codecId; }
4649*77c1e3ccSAndroid Build Coastguard Worker
GetCodecPrivate(size_t & size) const4650*77c1e3ccSAndroid Build Coastguard Worker const unsigned char* Track::GetCodecPrivate(size_t& size) const {
4651*77c1e3ccSAndroid Build Coastguard Worker size = m_info.codecPrivateSize;
4652*77c1e3ccSAndroid Build Coastguard Worker return m_info.codecPrivate;
4653*77c1e3ccSAndroid Build Coastguard Worker }
4654*77c1e3ccSAndroid Build Coastguard Worker
GetLacing() const4655*77c1e3ccSAndroid Build Coastguard Worker bool Track::GetLacing() const { return m_info.lacing; }
4656*77c1e3ccSAndroid Build Coastguard Worker
GetDefaultDuration() const4657*77c1e3ccSAndroid Build Coastguard Worker unsigned long long Track::GetDefaultDuration() const {
4658*77c1e3ccSAndroid Build Coastguard Worker return m_info.defaultDuration;
4659*77c1e3ccSAndroid Build Coastguard Worker }
4660*77c1e3ccSAndroid Build Coastguard Worker
GetCodecDelay() const4661*77c1e3ccSAndroid Build Coastguard Worker unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; }
4662*77c1e3ccSAndroid Build Coastguard Worker
GetSeekPreRoll() const4663*77c1e3ccSAndroid Build Coastguard Worker unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; }
4664*77c1e3ccSAndroid Build Coastguard Worker
GetFirst(const BlockEntry * & pBlockEntry) const4665*77c1e3ccSAndroid Build Coastguard Worker long Track::GetFirst(const BlockEntry*& pBlockEntry) const {
4666*77c1e3ccSAndroid Build Coastguard Worker const Cluster* pCluster = m_pSegment->GetFirst();
4667*77c1e3ccSAndroid Build Coastguard Worker
4668*77c1e3ccSAndroid Build Coastguard Worker for (int i = 0;;) {
4669*77c1e3ccSAndroid Build Coastguard Worker if (pCluster == NULL) {
4670*77c1e3ccSAndroid Build Coastguard Worker pBlockEntry = GetEOS();
4671*77c1e3ccSAndroid Build Coastguard Worker return 1;
4672*77c1e3ccSAndroid Build Coastguard Worker }
4673*77c1e3ccSAndroid Build Coastguard Worker
4674*77c1e3ccSAndroid Build Coastguard Worker if (pCluster->EOS()) {
4675*77c1e3ccSAndroid Build Coastguard Worker if (m_pSegment->DoneParsing()) {
4676*77c1e3ccSAndroid Build Coastguard Worker pBlockEntry = GetEOS();
4677*77c1e3ccSAndroid Build Coastguard Worker return 1;
4678*77c1e3ccSAndroid Build Coastguard Worker }
4679*77c1e3ccSAndroid Build Coastguard Worker
4680*77c1e3ccSAndroid Build Coastguard Worker pBlockEntry = 0;
4681*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
4682*77c1e3ccSAndroid Build Coastguard Worker }
4683*77c1e3ccSAndroid Build Coastguard Worker
4684*77c1e3ccSAndroid Build Coastguard Worker long status = pCluster->GetFirst(pBlockEntry);
4685*77c1e3ccSAndroid Build Coastguard Worker
4686*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4687*77c1e3ccSAndroid Build Coastguard Worker return status;
4688*77c1e3ccSAndroid Build Coastguard Worker
4689*77c1e3ccSAndroid Build Coastguard Worker if (pBlockEntry == 0) { // empty cluster
4690*77c1e3ccSAndroid Build Coastguard Worker pCluster = m_pSegment->GetNext(pCluster);
4691*77c1e3ccSAndroid Build Coastguard Worker continue;
4692*77c1e3ccSAndroid Build Coastguard Worker }
4693*77c1e3ccSAndroid Build Coastguard Worker
4694*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
4695*77c1e3ccSAndroid Build Coastguard Worker const Block* const pBlock = pBlockEntry->GetBlock();
4696*77c1e3ccSAndroid Build Coastguard Worker assert(pBlock);
4697*77c1e3ccSAndroid Build Coastguard Worker
4698*77c1e3ccSAndroid Build Coastguard Worker const long long tn = pBlock->GetTrackNumber();
4699*77c1e3ccSAndroid Build Coastguard Worker
4700*77c1e3ccSAndroid Build Coastguard Worker if ((tn == m_info.number) && VetEntry(pBlockEntry))
4701*77c1e3ccSAndroid Build Coastguard Worker return 0;
4702*77c1e3ccSAndroid Build Coastguard Worker
4703*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* pNextEntry;
4704*77c1e3ccSAndroid Build Coastguard Worker
4705*77c1e3ccSAndroid Build Coastguard Worker status = pCluster->GetNext(pBlockEntry, pNextEntry);
4706*77c1e3ccSAndroid Build Coastguard Worker
4707*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4708*77c1e3ccSAndroid Build Coastguard Worker return status;
4709*77c1e3ccSAndroid Build Coastguard Worker
4710*77c1e3ccSAndroid Build Coastguard Worker if (pNextEntry == 0)
4711*77c1e3ccSAndroid Build Coastguard Worker break;
4712*77c1e3ccSAndroid Build Coastguard Worker
4713*77c1e3ccSAndroid Build Coastguard Worker pBlockEntry = pNextEntry;
4714*77c1e3ccSAndroid Build Coastguard Worker }
4715*77c1e3ccSAndroid Build Coastguard Worker
4716*77c1e3ccSAndroid Build Coastguard Worker ++i;
4717*77c1e3ccSAndroid Build Coastguard Worker
4718*77c1e3ccSAndroid Build Coastguard Worker if (i >= 100)
4719*77c1e3ccSAndroid Build Coastguard Worker break;
4720*77c1e3ccSAndroid Build Coastguard Worker
4721*77c1e3ccSAndroid Build Coastguard Worker pCluster = m_pSegment->GetNext(pCluster);
4722*77c1e3ccSAndroid Build Coastguard Worker }
4723*77c1e3ccSAndroid Build Coastguard Worker
4724*77c1e3ccSAndroid Build Coastguard Worker // NOTE: if we get here, it means that we didn't find a block with
4725*77c1e3ccSAndroid Build Coastguard Worker // a matching track number. We interpret that as an error (which
4726*77c1e3ccSAndroid Build Coastguard Worker // might be too conservative).
4727*77c1e3ccSAndroid Build Coastguard Worker
4728*77c1e3ccSAndroid Build Coastguard Worker pBlockEntry = GetEOS(); // so we can return a non-NULL value
4729*77c1e3ccSAndroid Build Coastguard Worker return 1;
4730*77c1e3ccSAndroid Build Coastguard Worker }
4731*77c1e3ccSAndroid Build Coastguard Worker
GetNext(const BlockEntry * pCurrEntry,const BlockEntry * & pNextEntry) const4732*77c1e3ccSAndroid Build Coastguard Worker long Track::GetNext(const BlockEntry* pCurrEntry,
4733*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry*& pNextEntry) const {
4734*77c1e3ccSAndroid Build Coastguard Worker assert(pCurrEntry);
4735*77c1e3ccSAndroid Build Coastguard Worker assert(!pCurrEntry->EOS()); //?
4736*77c1e3ccSAndroid Build Coastguard Worker
4737*77c1e3ccSAndroid Build Coastguard Worker const Block* const pCurrBlock = pCurrEntry->GetBlock();
4738*77c1e3ccSAndroid Build Coastguard Worker assert(pCurrBlock && pCurrBlock->GetTrackNumber() == m_info.number);
4739*77c1e3ccSAndroid Build Coastguard Worker if (!pCurrBlock || pCurrBlock->GetTrackNumber() != m_info.number)
4740*77c1e3ccSAndroid Build Coastguard Worker return -1;
4741*77c1e3ccSAndroid Build Coastguard Worker
4742*77c1e3ccSAndroid Build Coastguard Worker const Cluster* pCluster = pCurrEntry->GetCluster();
4743*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
4744*77c1e3ccSAndroid Build Coastguard Worker assert(!pCluster->EOS());
4745*77c1e3ccSAndroid Build Coastguard Worker
4746*77c1e3ccSAndroid Build Coastguard Worker long status = pCluster->GetNext(pCurrEntry, pNextEntry);
4747*77c1e3ccSAndroid Build Coastguard Worker
4748*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4749*77c1e3ccSAndroid Build Coastguard Worker return status;
4750*77c1e3ccSAndroid Build Coastguard Worker
4751*77c1e3ccSAndroid Build Coastguard Worker for (int i = 0;;) {
4752*77c1e3ccSAndroid Build Coastguard Worker while (pNextEntry) {
4753*77c1e3ccSAndroid Build Coastguard Worker const Block* const pNextBlock = pNextEntry->GetBlock();
4754*77c1e3ccSAndroid Build Coastguard Worker assert(pNextBlock);
4755*77c1e3ccSAndroid Build Coastguard Worker
4756*77c1e3ccSAndroid Build Coastguard Worker if (pNextBlock->GetTrackNumber() == m_info.number)
4757*77c1e3ccSAndroid Build Coastguard Worker return 0;
4758*77c1e3ccSAndroid Build Coastguard Worker
4759*77c1e3ccSAndroid Build Coastguard Worker pCurrEntry = pNextEntry;
4760*77c1e3ccSAndroid Build Coastguard Worker
4761*77c1e3ccSAndroid Build Coastguard Worker status = pCluster->GetNext(pCurrEntry, pNextEntry);
4762*77c1e3ccSAndroid Build Coastguard Worker
4763*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4764*77c1e3ccSAndroid Build Coastguard Worker return status;
4765*77c1e3ccSAndroid Build Coastguard Worker }
4766*77c1e3ccSAndroid Build Coastguard Worker
4767*77c1e3ccSAndroid Build Coastguard Worker pCluster = m_pSegment->GetNext(pCluster);
4768*77c1e3ccSAndroid Build Coastguard Worker
4769*77c1e3ccSAndroid Build Coastguard Worker if (pCluster == NULL) {
4770*77c1e3ccSAndroid Build Coastguard Worker pNextEntry = GetEOS();
4771*77c1e3ccSAndroid Build Coastguard Worker return 1;
4772*77c1e3ccSAndroid Build Coastguard Worker }
4773*77c1e3ccSAndroid Build Coastguard Worker
4774*77c1e3ccSAndroid Build Coastguard Worker if (pCluster->EOS()) {
4775*77c1e3ccSAndroid Build Coastguard Worker if (m_pSegment->DoneParsing()) {
4776*77c1e3ccSAndroid Build Coastguard Worker pNextEntry = GetEOS();
4777*77c1e3ccSAndroid Build Coastguard Worker return 1;
4778*77c1e3ccSAndroid Build Coastguard Worker }
4779*77c1e3ccSAndroid Build Coastguard Worker
4780*77c1e3ccSAndroid Build Coastguard Worker // TODO: there is a potential O(n^2) problem here: we tell the
4781*77c1e3ccSAndroid Build Coastguard Worker // caller to (pre)load another cluster, which he does, but then he
4782*77c1e3ccSAndroid Build Coastguard Worker // calls GetNext again, which repeats the same search. This is
4783*77c1e3ccSAndroid Build Coastguard Worker // a pathological case, since the only way it can happen is if
4784*77c1e3ccSAndroid Build Coastguard Worker // there exists a long sequence of clusters none of which contain a
4785*77c1e3ccSAndroid Build Coastguard Worker // block from this track. One way around this problem is for the
4786*77c1e3ccSAndroid Build Coastguard Worker // caller to be smarter when he loads another cluster: don't call
4787*77c1e3ccSAndroid Build Coastguard Worker // us back until you have a cluster that contains a block from this
4788*77c1e3ccSAndroid Build Coastguard Worker // track. (Of course, that's not cheap either, since our caller
4789*77c1e3ccSAndroid Build Coastguard Worker // would have to scan the each cluster as it's loaded, so that
4790*77c1e3ccSAndroid Build Coastguard Worker // would just push back the problem.)
4791*77c1e3ccSAndroid Build Coastguard Worker
4792*77c1e3ccSAndroid Build Coastguard Worker pNextEntry = NULL;
4793*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
4794*77c1e3ccSAndroid Build Coastguard Worker }
4795*77c1e3ccSAndroid Build Coastguard Worker
4796*77c1e3ccSAndroid Build Coastguard Worker status = pCluster->GetFirst(pNextEntry);
4797*77c1e3ccSAndroid Build Coastguard Worker
4798*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4799*77c1e3ccSAndroid Build Coastguard Worker return status;
4800*77c1e3ccSAndroid Build Coastguard Worker
4801*77c1e3ccSAndroid Build Coastguard Worker if (pNextEntry == NULL) // empty cluster
4802*77c1e3ccSAndroid Build Coastguard Worker continue;
4803*77c1e3ccSAndroid Build Coastguard Worker
4804*77c1e3ccSAndroid Build Coastguard Worker ++i;
4805*77c1e3ccSAndroid Build Coastguard Worker
4806*77c1e3ccSAndroid Build Coastguard Worker if (i >= 100)
4807*77c1e3ccSAndroid Build Coastguard Worker break;
4808*77c1e3ccSAndroid Build Coastguard Worker }
4809*77c1e3ccSAndroid Build Coastguard Worker
4810*77c1e3ccSAndroid Build Coastguard Worker // NOTE: if we get here, it means that we didn't find a block with
4811*77c1e3ccSAndroid Build Coastguard Worker // a matching track number after lots of searching, so we give
4812*77c1e3ccSAndroid Build Coastguard Worker // up trying.
4813*77c1e3ccSAndroid Build Coastguard Worker
4814*77c1e3ccSAndroid Build Coastguard Worker pNextEntry = GetEOS(); // so we can return a non-NULL value
4815*77c1e3ccSAndroid Build Coastguard Worker return 1;
4816*77c1e3ccSAndroid Build Coastguard Worker }
4817*77c1e3ccSAndroid Build Coastguard Worker
VetEntry(const BlockEntry * pBlockEntry) const4818*77c1e3ccSAndroid Build Coastguard Worker bool Track::VetEntry(const BlockEntry* pBlockEntry) const {
4819*77c1e3ccSAndroid Build Coastguard Worker assert(pBlockEntry);
4820*77c1e3ccSAndroid Build Coastguard Worker const Block* const pBlock = pBlockEntry->GetBlock();
4821*77c1e3ccSAndroid Build Coastguard Worker assert(pBlock);
4822*77c1e3ccSAndroid Build Coastguard Worker assert(pBlock->GetTrackNumber() == m_info.number);
4823*77c1e3ccSAndroid Build Coastguard Worker if (!pBlock || pBlock->GetTrackNumber() != m_info.number)
4824*77c1e3ccSAndroid Build Coastguard Worker return false;
4825*77c1e3ccSAndroid Build Coastguard Worker
4826*77c1e3ccSAndroid Build Coastguard Worker // This function is used during a seek to determine whether the
4827*77c1e3ccSAndroid Build Coastguard Worker // frame is a valid seek target. This default function simply
4828*77c1e3ccSAndroid Build Coastguard Worker // returns true, which means all frames are valid seek targets.
4829*77c1e3ccSAndroid Build Coastguard Worker // It gets overridden by the VideoTrack class, because only video
4830*77c1e3ccSAndroid Build Coastguard Worker // keyframes can be used as seek target.
4831*77c1e3ccSAndroid Build Coastguard Worker
4832*77c1e3ccSAndroid Build Coastguard Worker return true;
4833*77c1e3ccSAndroid Build Coastguard Worker }
4834*77c1e3ccSAndroid Build Coastguard Worker
Seek(long long time_ns,const BlockEntry * & pResult) const4835*77c1e3ccSAndroid Build Coastguard Worker long Track::Seek(long long time_ns, const BlockEntry*& pResult) const {
4836*77c1e3ccSAndroid Build Coastguard Worker const long status = GetFirst(pResult);
4837*77c1e3ccSAndroid Build Coastguard Worker
4838*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // buffer underflow, etc
4839*77c1e3ccSAndroid Build Coastguard Worker return status;
4840*77c1e3ccSAndroid Build Coastguard Worker
4841*77c1e3ccSAndroid Build Coastguard Worker assert(pResult);
4842*77c1e3ccSAndroid Build Coastguard Worker
4843*77c1e3ccSAndroid Build Coastguard Worker if (pResult->EOS())
4844*77c1e3ccSAndroid Build Coastguard Worker return 0;
4845*77c1e3ccSAndroid Build Coastguard Worker
4846*77c1e3ccSAndroid Build Coastguard Worker const Cluster* pCluster = pResult->GetCluster();
4847*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
4848*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetIndex() >= 0);
4849*77c1e3ccSAndroid Build Coastguard Worker
4850*77c1e3ccSAndroid Build Coastguard Worker if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
4851*77c1e3ccSAndroid Build Coastguard Worker return 0;
4852*77c1e3ccSAndroid Build Coastguard Worker
4853*77c1e3ccSAndroid Build Coastguard Worker Cluster** const clusters = m_pSegment->m_clusters;
4854*77c1e3ccSAndroid Build Coastguard Worker assert(clusters);
4855*77c1e3ccSAndroid Build Coastguard Worker
4856*77c1e3ccSAndroid Build Coastguard Worker const long count = m_pSegment->GetCount(); // loaded only, not preloaded
4857*77c1e3ccSAndroid Build Coastguard Worker assert(count > 0);
4858*77c1e3ccSAndroid Build Coastguard Worker
4859*77c1e3ccSAndroid Build Coastguard Worker Cluster** const i = clusters + pCluster->GetIndex();
4860*77c1e3ccSAndroid Build Coastguard Worker assert(i);
4861*77c1e3ccSAndroid Build Coastguard Worker assert(*i == pCluster);
4862*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetTime() <= time_ns);
4863*77c1e3ccSAndroid Build Coastguard Worker
4864*77c1e3ccSAndroid Build Coastguard Worker Cluster** const j = clusters + count;
4865*77c1e3ccSAndroid Build Coastguard Worker
4866*77c1e3ccSAndroid Build Coastguard Worker Cluster** lo = i;
4867*77c1e3ccSAndroid Build Coastguard Worker Cluster** hi = j;
4868*77c1e3ccSAndroid Build Coastguard Worker
4869*77c1e3ccSAndroid Build Coastguard Worker while (lo < hi) {
4870*77c1e3ccSAndroid Build Coastguard Worker // INVARIANT:
4871*77c1e3ccSAndroid Build Coastguard Worker //[i, lo) <= time_ns
4872*77c1e3ccSAndroid Build Coastguard Worker //[lo, hi) ?
4873*77c1e3ccSAndroid Build Coastguard Worker //[hi, j) > time_ns
4874*77c1e3ccSAndroid Build Coastguard Worker
4875*77c1e3ccSAndroid Build Coastguard Worker Cluster** const mid = lo + (hi - lo) / 2;
4876*77c1e3ccSAndroid Build Coastguard Worker assert(mid < hi);
4877*77c1e3ccSAndroid Build Coastguard Worker
4878*77c1e3ccSAndroid Build Coastguard Worker pCluster = *mid;
4879*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
4880*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetIndex() >= 0);
4881*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
4882*77c1e3ccSAndroid Build Coastguard Worker
4883*77c1e3ccSAndroid Build Coastguard Worker const long long t = pCluster->GetTime();
4884*77c1e3ccSAndroid Build Coastguard Worker
4885*77c1e3ccSAndroid Build Coastguard Worker if (t <= time_ns)
4886*77c1e3ccSAndroid Build Coastguard Worker lo = mid + 1;
4887*77c1e3ccSAndroid Build Coastguard Worker else
4888*77c1e3ccSAndroid Build Coastguard Worker hi = mid;
4889*77c1e3ccSAndroid Build Coastguard Worker
4890*77c1e3ccSAndroid Build Coastguard Worker assert(lo <= hi);
4891*77c1e3ccSAndroid Build Coastguard Worker }
4892*77c1e3ccSAndroid Build Coastguard Worker
4893*77c1e3ccSAndroid Build Coastguard Worker assert(lo == hi);
4894*77c1e3ccSAndroid Build Coastguard Worker assert(lo > i);
4895*77c1e3ccSAndroid Build Coastguard Worker assert(lo <= j);
4896*77c1e3ccSAndroid Build Coastguard Worker
4897*77c1e3ccSAndroid Build Coastguard Worker while (lo > i) {
4898*77c1e3ccSAndroid Build Coastguard Worker pCluster = *--lo;
4899*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
4900*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetTime() <= time_ns);
4901*77c1e3ccSAndroid Build Coastguard Worker
4902*77c1e3ccSAndroid Build Coastguard Worker pResult = pCluster->GetEntry(this);
4903*77c1e3ccSAndroid Build Coastguard Worker
4904*77c1e3ccSAndroid Build Coastguard Worker if ((pResult != 0) && !pResult->EOS())
4905*77c1e3ccSAndroid Build Coastguard Worker return 0;
4906*77c1e3ccSAndroid Build Coastguard Worker
4907*77c1e3ccSAndroid Build Coastguard Worker // landed on empty cluster (no entries)
4908*77c1e3ccSAndroid Build Coastguard Worker }
4909*77c1e3ccSAndroid Build Coastguard Worker
4910*77c1e3ccSAndroid Build Coastguard Worker pResult = GetEOS(); // weird
4911*77c1e3ccSAndroid Build Coastguard Worker return 0;
4912*77c1e3ccSAndroid Build Coastguard Worker }
4913*77c1e3ccSAndroid Build Coastguard Worker
GetContentEncodingByIndex(unsigned long idx) const4914*77c1e3ccSAndroid Build Coastguard Worker const ContentEncoding* Track::GetContentEncodingByIndex(
4915*77c1e3ccSAndroid Build Coastguard Worker unsigned long idx) const {
4916*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t count =
4917*77c1e3ccSAndroid Build Coastguard Worker content_encoding_entries_end_ - content_encoding_entries_;
4918*77c1e3ccSAndroid Build Coastguard Worker assert(count >= 0);
4919*77c1e3ccSAndroid Build Coastguard Worker
4920*77c1e3ccSAndroid Build Coastguard Worker if (idx >= static_cast<unsigned long>(count))
4921*77c1e3ccSAndroid Build Coastguard Worker return NULL;
4922*77c1e3ccSAndroid Build Coastguard Worker
4923*77c1e3ccSAndroid Build Coastguard Worker return content_encoding_entries_[idx];
4924*77c1e3ccSAndroid Build Coastguard Worker }
4925*77c1e3ccSAndroid Build Coastguard Worker
GetContentEncodingCount() const4926*77c1e3ccSAndroid Build Coastguard Worker unsigned long Track::GetContentEncodingCount() const {
4927*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t count =
4928*77c1e3ccSAndroid Build Coastguard Worker content_encoding_entries_end_ - content_encoding_entries_;
4929*77c1e3ccSAndroid Build Coastguard Worker assert(count >= 0);
4930*77c1e3ccSAndroid Build Coastguard Worker
4931*77c1e3ccSAndroid Build Coastguard Worker return static_cast<unsigned long>(count);
4932*77c1e3ccSAndroid Build Coastguard Worker }
4933*77c1e3ccSAndroid Build Coastguard Worker
ParseContentEncodingsEntry(long long start,long long size)4934*77c1e3ccSAndroid Build Coastguard Worker long Track::ParseContentEncodingsEntry(long long start, long long size) {
4935*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
4936*77c1e3ccSAndroid Build Coastguard Worker assert(pReader);
4937*77c1e3ccSAndroid Build Coastguard Worker
4938*77c1e3ccSAndroid Build Coastguard Worker long long pos = start;
4939*77c1e3ccSAndroid Build Coastguard Worker const long long stop = start + size;
4940*77c1e3ccSAndroid Build Coastguard Worker
4941*77c1e3ccSAndroid Build Coastguard Worker // Count ContentEncoding elements.
4942*77c1e3ccSAndroid Build Coastguard Worker long long count = 0;
4943*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
4944*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
4945*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, stop, id, size);
4946*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4947*77c1e3ccSAndroid Build Coastguard Worker return status;
4948*77c1e3ccSAndroid Build Coastguard Worker
4949*77c1e3ccSAndroid Build Coastguard Worker // pos now designates start of element
4950*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvContentEncoding) {
4951*77c1e3ccSAndroid Build Coastguard Worker ++count;
4952*77c1e3ccSAndroid Build Coastguard Worker if (count > INT_MAX)
4953*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
4954*77c1e3ccSAndroid Build Coastguard Worker }
4955*77c1e3ccSAndroid Build Coastguard Worker
4956*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
4957*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
4958*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4959*77c1e3ccSAndroid Build Coastguard Worker }
4960*77c1e3ccSAndroid Build Coastguard Worker
4961*77c1e3ccSAndroid Build Coastguard Worker if (count <= 0)
4962*77c1e3ccSAndroid Build Coastguard Worker return -1;
4963*77c1e3ccSAndroid Build Coastguard Worker
4964*77c1e3ccSAndroid Build Coastguard Worker content_encoding_entries_ =
4965*77c1e3ccSAndroid Build Coastguard Worker new (std::nothrow) ContentEncoding*[static_cast<size_t>(count)];
4966*77c1e3ccSAndroid Build Coastguard Worker if (!content_encoding_entries_)
4967*77c1e3ccSAndroid Build Coastguard Worker return -1;
4968*77c1e3ccSAndroid Build Coastguard Worker
4969*77c1e3ccSAndroid Build Coastguard Worker content_encoding_entries_end_ = content_encoding_entries_;
4970*77c1e3ccSAndroid Build Coastguard Worker
4971*77c1e3ccSAndroid Build Coastguard Worker pos = start;
4972*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
4973*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
4974*77c1e3ccSAndroid Build Coastguard Worker long status = ParseElementHeader(pReader, pos, stop, id, size);
4975*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
4976*77c1e3ccSAndroid Build Coastguard Worker return status;
4977*77c1e3ccSAndroid Build Coastguard Worker
4978*77c1e3ccSAndroid Build Coastguard Worker // pos now designates start of element
4979*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvContentEncoding) {
4980*77c1e3ccSAndroid Build Coastguard Worker ContentEncoding* const content_encoding =
4981*77c1e3ccSAndroid Build Coastguard Worker new (std::nothrow) ContentEncoding();
4982*77c1e3ccSAndroid Build Coastguard Worker if (!content_encoding)
4983*77c1e3ccSAndroid Build Coastguard Worker return -1;
4984*77c1e3ccSAndroid Build Coastguard Worker
4985*77c1e3ccSAndroid Build Coastguard Worker status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
4986*77c1e3ccSAndroid Build Coastguard Worker if (status) {
4987*77c1e3ccSAndroid Build Coastguard Worker delete content_encoding;
4988*77c1e3ccSAndroid Build Coastguard Worker return status;
4989*77c1e3ccSAndroid Build Coastguard Worker }
4990*77c1e3ccSAndroid Build Coastguard Worker
4991*77c1e3ccSAndroid Build Coastguard Worker *content_encoding_entries_end_++ = content_encoding;
4992*77c1e3ccSAndroid Build Coastguard Worker }
4993*77c1e3ccSAndroid Build Coastguard Worker
4994*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
4995*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
4996*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
4997*77c1e3ccSAndroid Build Coastguard Worker }
4998*77c1e3ccSAndroid Build Coastguard Worker
4999*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
5000*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5001*77c1e3ccSAndroid Build Coastguard Worker
5002*77c1e3ccSAndroid Build Coastguard Worker return 0;
5003*77c1e3ccSAndroid Build Coastguard Worker }
5004*77c1e3ccSAndroid Build Coastguard Worker
EOSBlock()5005*77c1e3ccSAndroid Build Coastguard Worker Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {}
5006*77c1e3ccSAndroid Build Coastguard Worker
GetKind() const5007*77c1e3ccSAndroid Build Coastguard Worker BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
5008*77c1e3ccSAndroid Build Coastguard Worker
GetBlock() const5009*77c1e3ccSAndroid Build Coastguard Worker const Block* Track::EOSBlock::GetBlock() const { return NULL; }
5010*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * reader,long long read_pos,long long value_size,bool is_x,PrimaryChromaticity ** chromaticity)5011*77c1e3ccSAndroid Build Coastguard Worker bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
5012*77c1e3ccSAndroid Build Coastguard Worker long long value_size, bool is_x,
5013*77c1e3ccSAndroid Build Coastguard Worker PrimaryChromaticity** chromaticity) {
5014*77c1e3ccSAndroid Build Coastguard Worker if (!reader)
5015*77c1e3ccSAndroid Build Coastguard Worker return false;
5016*77c1e3ccSAndroid Build Coastguard Worker
5017*77c1e3ccSAndroid Build Coastguard Worker if (!*chromaticity)
5018*77c1e3ccSAndroid Build Coastguard Worker *chromaticity = new PrimaryChromaticity();
5019*77c1e3ccSAndroid Build Coastguard Worker
5020*77c1e3ccSAndroid Build Coastguard Worker if (!*chromaticity)
5021*77c1e3ccSAndroid Build Coastguard Worker return false;
5022*77c1e3ccSAndroid Build Coastguard Worker
5023*77c1e3ccSAndroid Build Coastguard Worker PrimaryChromaticity* pc = *chromaticity;
5024*77c1e3ccSAndroid Build Coastguard Worker float* value = is_x ? &pc->x : &pc->y;
5025*77c1e3ccSAndroid Build Coastguard Worker
5026*77c1e3ccSAndroid Build Coastguard Worker double parser_value = 0;
5027*77c1e3ccSAndroid Build Coastguard Worker const long long parse_status =
5028*77c1e3ccSAndroid Build Coastguard Worker UnserializeFloat(reader, read_pos, value_size, parser_value);
5029*77c1e3ccSAndroid Build Coastguard Worker
5030*77c1e3ccSAndroid Build Coastguard Worker // Valid range is [0, 1]. Make sure the double is representable as a float
5031*77c1e3ccSAndroid Build Coastguard Worker // before casting.
5032*77c1e3ccSAndroid Build Coastguard Worker if (parse_status < 0 || parser_value < 0.0 || parser_value > 1.0 ||
5033*77c1e3ccSAndroid Build Coastguard Worker (parser_value > 0.0 && parser_value < FLT_MIN))
5034*77c1e3ccSAndroid Build Coastguard Worker return false;
5035*77c1e3ccSAndroid Build Coastguard Worker
5036*77c1e3ccSAndroid Build Coastguard Worker *value = static_cast<float>(parser_value);
5037*77c1e3ccSAndroid Build Coastguard Worker
5038*77c1e3ccSAndroid Build Coastguard Worker return true;
5039*77c1e3ccSAndroid Build Coastguard Worker }
5040*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * reader,long long mm_start,long long mm_size,MasteringMetadata ** mm)5041*77c1e3ccSAndroid Build Coastguard Worker bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
5042*77c1e3ccSAndroid Build Coastguard Worker long long mm_size, MasteringMetadata** mm) {
5043*77c1e3ccSAndroid Build Coastguard Worker if (!reader || *mm)
5044*77c1e3ccSAndroid Build Coastguard Worker return false;
5045*77c1e3ccSAndroid Build Coastguard Worker
5046*77c1e3ccSAndroid Build Coastguard Worker std::unique_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
5047*77c1e3ccSAndroid Build Coastguard Worker if (!mm_ptr.get())
5048*77c1e3ccSAndroid Build Coastguard Worker return false;
5049*77c1e3ccSAndroid Build Coastguard Worker
5050*77c1e3ccSAndroid Build Coastguard Worker const long long mm_end = mm_start + mm_size;
5051*77c1e3ccSAndroid Build Coastguard Worker long long read_pos = mm_start;
5052*77c1e3ccSAndroid Build Coastguard Worker
5053*77c1e3ccSAndroid Build Coastguard Worker while (read_pos < mm_end) {
5054*77c1e3ccSAndroid Build Coastguard Worker long long child_id = 0;
5055*77c1e3ccSAndroid Build Coastguard Worker long long child_size = 0;
5056*77c1e3ccSAndroid Build Coastguard Worker
5057*77c1e3ccSAndroid Build Coastguard Worker const long long status =
5058*77c1e3ccSAndroid Build Coastguard Worker ParseElementHeader(reader, read_pos, mm_end, child_id, child_size);
5059*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
5060*77c1e3ccSAndroid Build Coastguard Worker return false;
5061*77c1e3ccSAndroid Build Coastguard Worker
5062*77c1e3ccSAndroid Build Coastguard Worker if (child_id == libwebm::kMkvLuminanceMax) {
5063*77c1e3ccSAndroid Build Coastguard Worker double value = 0;
5064*77c1e3ccSAndroid Build Coastguard Worker const long long value_parse_status =
5065*77c1e3ccSAndroid Build Coastguard Worker UnserializeFloat(reader, read_pos, child_size, value);
5066*77c1e3ccSAndroid Build Coastguard Worker if (value < -FLT_MAX || value > FLT_MAX ||
5067*77c1e3ccSAndroid Build Coastguard Worker (value > 0.0 && value < FLT_MIN)) {
5068*77c1e3ccSAndroid Build Coastguard Worker return false;
5069*77c1e3ccSAndroid Build Coastguard Worker }
5070*77c1e3ccSAndroid Build Coastguard Worker mm_ptr->luminance_max = static_cast<float>(value);
5071*77c1e3ccSAndroid Build Coastguard Worker if (value_parse_status < 0 || mm_ptr->luminance_max < 0.0 ||
5072*77c1e3ccSAndroid Build Coastguard Worker mm_ptr->luminance_max > 9999.99) {
5073*77c1e3ccSAndroid Build Coastguard Worker return false;
5074*77c1e3ccSAndroid Build Coastguard Worker }
5075*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvLuminanceMin) {
5076*77c1e3ccSAndroid Build Coastguard Worker double value = 0;
5077*77c1e3ccSAndroid Build Coastguard Worker const long long value_parse_status =
5078*77c1e3ccSAndroid Build Coastguard Worker UnserializeFloat(reader, read_pos, child_size, value);
5079*77c1e3ccSAndroid Build Coastguard Worker if (value < -FLT_MAX || value > FLT_MAX ||
5080*77c1e3ccSAndroid Build Coastguard Worker (value > 0.0 && value < FLT_MIN)) {
5081*77c1e3ccSAndroid Build Coastguard Worker return false;
5082*77c1e3ccSAndroid Build Coastguard Worker }
5083*77c1e3ccSAndroid Build Coastguard Worker mm_ptr->luminance_min = static_cast<float>(value);
5084*77c1e3ccSAndroid Build Coastguard Worker if (value_parse_status < 0 || mm_ptr->luminance_min < 0.0 ||
5085*77c1e3ccSAndroid Build Coastguard Worker mm_ptr->luminance_min > 999.9999) {
5086*77c1e3ccSAndroid Build Coastguard Worker return false;
5087*77c1e3ccSAndroid Build Coastguard Worker }
5088*77c1e3ccSAndroid Build Coastguard Worker } else {
5089*77c1e3ccSAndroid Build Coastguard Worker bool is_x = false;
5090*77c1e3ccSAndroid Build Coastguard Worker PrimaryChromaticity** chromaticity;
5091*77c1e3ccSAndroid Build Coastguard Worker switch (child_id) {
5092*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvPrimaryRChromaticityX:
5093*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvPrimaryRChromaticityY:
5094*77c1e3ccSAndroid Build Coastguard Worker is_x = child_id == libwebm::kMkvPrimaryRChromaticityX;
5095*77c1e3ccSAndroid Build Coastguard Worker chromaticity = &mm_ptr->r;
5096*77c1e3ccSAndroid Build Coastguard Worker break;
5097*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvPrimaryGChromaticityX:
5098*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvPrimaryGChromaticityY:
5099*77c1e3ccSAndroid Build Coastguard Worker is_x = child_id == libwebm::kMkvPrimaryGChromaticityX;
5100*77c1e3ccSAndroid Build Coastguard Worker chromaticity = &mm_ptr->g;
5101*77c1e3ccSAndroid Build Coastguard Worker break;
5102*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvPrimaryBChromaticityX:
5103*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvPrimaryBChromaticityY:
5104*77c1e3ccSAndroid Build Coastguard Worker is_x = child_id == libwebm::kMkvPrimaryBChromaticityX;
5105*77c1e3ccSAndroid Build Coastguard Worker chromaticity = &mm_ptr->b;
5106*77c1e3ccSAndroid Build Coastguard Worker break;
5107*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvWhitePointChromaticityX:
5108*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvWhitePointChromaticityY:
5109*77c1e3ccSAndroid Build Coastguard Worker is_x = child_id == libwebm::kMkvWhitePointChromaticityX;
5110*77c1e3ccSAndroid Build Coastguard Worker chromaticity = &mm_ptr->white_point;
5111*77c1e3ccSAndroid Build Coastguard Worker break;
5112*77c1e3ccSAndroid Build Coastguard Worker default:
5113*77c1e3ccSAndroid Build Coastguard Worker return false;
5114*77c1e3ccSAndroid Build Coastguard Worker }
5115*77c1e3ccSAndroid Build Coastguard Worker const bool value_parse_status = PrimaryChromaticity::Parse(
5116*77c1e3ccSAndroid Build Coastguard Worker reader, read_pos, child_size, is_x, chromaticity);
5117*77c1e3ccSAndroid Build Coastguard Worker if (!value_parse_status)
5118*77c1e3ccSAndroid Build Coastguard Worker return false;
5119*77c1e3ccSAndroid Build Coastguard Worker }
5120*77c1e3ccSAndroid Build Coastguard Worker
5121*77c1e3ccSAndroid Build Coastguard Worker read_pos += child_size;
5122*77c1e3ccSAndroid Build Coastguard Worker if (read_pos > mm_end)
5123*77c1e3ccSAndroid Build Coastguard Worker return false;
5124*77c1e3ccSAndroid Build Coastguard Worker }
5125*77c1e3ccSAndroid Build Coastguard Worker
5126*77c1e3ccSAndroid Build Coastguard Worker *mm = mm_ptr.release();
5127*77c1e3ccSAndroid Build Coastguard Worker return true;
5128*77c1e3ccSAndroid Build Coastguard Worker }
5129*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * reader,long long colour_start,long long colour_size,Colour ** colour)5130*77c1e3ccSAndroid Build Coastguard Worker bool Colour::Parse(IMkvReader* reader, long long colour_start,
5131*77c1e3ccSAndroid Build Coastguard Worker long long colour_size, Colour** colour) {
5132*77c1e3ccSAndroid Build Coastguard Worker if (!reader || *colour)
5133*77c1e3ccSAndroid Build Coastguard Worker return false;
5134*77c1e3ccSAndroid Build Coastguard Worker
5135*77c1e3ccSAndroid Build Coastguard Worker std::unique_ptr<Colour> colour_ptr(new Colour());
5136*77c1e3ccSAndroid Build Coastguard Worker if (!colour_ptr.get())
5137*77c1e3ccSAndroid Build Coastguard Worker return false;
5138*77c1e3ccSAndroid Build Coastguard Worker
5139*77c1e3ccSAndroid Build Coastguard Worker const long long colour_end = colour_start + colour_size;
5140*77c1e3ccSAndroid Build Coastguard Worker long long read_pos = colour_start;
5141*77c1e3ccSAndroid Build Coastguard Worker
5142*77c1e3ccSAndroid Build Coastguard Worker while (read_pos < colour_end) {
5143*77c1e3ccSAndroid Build Coastguard Worker long long child_id = 0;
5144*77c1e3ccSAndroid Build Coastguard Worker long long child_size = 0;
5145*77c1e3ccSAndroid Build Coastguard Worker
5146*77c1e3ccSAndroid Build Coastguard Worker const long status =
5147*77c1e3ccSAndroid Build Coastguard Worker ParseElementHeader(reader, read_pos, colour_end, child_id, child_size);
5148*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
5149*77c1e3ccSAndroid Build Coastguard Worker return false;
5150*77c1e3ccSAndroid Build Coastguard Worker
5151*77c1e3ccSAndroid Build Coastguard Worker if (child_id == libwebm::kMkvMatrixCoefficients) {
5152*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->matrix_coefficients =
5153*77c1e3ccSAndroid Build Coastguard Worker UnserializeUInt(reader, read_pos, child_size);
5154*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->matrix_coefficients < 0)
5155*77c1e3ccSAndroid Build Coastguard Worker return false;
5156*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvBitsPerChannel) {
5157*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->bits_per_channel =
5158*77c1e3ccSAndroid Build Coastguard Worker UnserializeUInt(reader, read_pos, child_size);
5159*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->bits_per_channel < 0)
5160*77c1e3ccSAndroid Build Coastguard Worker return false;
5161*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvChromaSubsamplingHorz) {
5162*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->chroma_subsampling_horz =
5163*77c1e3ccSAndroid Build Coastguard Worker UnserializeUInt(reader, read_pos, child_size);
5164*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->chroma_subsampling_horz < 0)
5165*77c1e3ccSAndroid Build Coastguard Worker return false;
5166*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvChromaSubsamplingVert) {
5167*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->chroma_subsampling_vert =
5168*77c1e3ccSAndroid Build Coastguard Worker UnserializeUInt(reader, read_pos, child_size);
5169*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->chroma_subsampling_vert < 0)
5170*77c1e3ccSAndroid Build Coastguard Worker return false;
5171*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvCbSubsamplingHorz) {
5172*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->cb_subsampling_horz =
5173*77c1e3ccSAndroid Build Coastguard Worker UnserializeUInt(reader, read_pos, child_size);
5174*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->cb_subsampling_horz < 0)
5175*77c1e3ccSAndroid Build Coastguard Worker return false;
5176*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvCbSubsamplingVert) {
5177*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->cb_subsampling_vert =
5178*77c1e3ccSAndroid Build Coastguard Worker UnserializeUInt(reader, read_pos, child_size);
5179*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->cb_subsampling_vert < 0)
5180*77c1e3ccSAndroid Build Coastguard Worker return false;
5181*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvChromaSitingHorz) {
5182*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->chroma_siting_horz =
5183*77c1e3ccSAndroid Build Coastguard Worker UnserializeUInt(reader, read_pos, child_size);
5184*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->chroma_siting_horz < 0)
5185*77c1e3ccSAndroid Build Coastguard Worker return false;
5186*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvChromaSitingVert) {
5187*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->chroma_siting_vert =
5188*77c1e3ccSAndroid Build Coastguard Worker UnserializeUInt(reader, read_pos, child_size);
5189*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->chroma_siting_vert < 0)
5190*77c1e3ccSAndroid Build Coastguard Worker return false;
5191*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvRange) {
5192*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->range = UnserializeUInt(reader, read_pos, child_size);
5193*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->range < 0)
5194*77c1e3ccSAndroid Build Coastguard Worker return false;
5195*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvTransferCharacteristics) {
5196*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->transfer_characteristics =
5197*77c1e3ccSAndroid Build Coastguard Worker UnserializeUInt(reader, read_pos, child_size);
5198*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->transfer_characteristics < 0)
5199*77c1e3ccSAndroid Build Coastguard Worker return false;
5200*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvPrimaries) {
5201*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->primaries = UnserializeUInt(reader, read_pos, child_size);
5202*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->primaries < 0)
5203*77c1e3ccSAndroid Build Coastguard Worker return false;
5204*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvMaxCLL) {
5205*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->max_cll = UnserializeUInt(reader, read_pos, child_size);
5206*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->max_cll < 0)
5207*77c1e3ccSAndroid Build Coastguard Worker return false;
5208*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvMaxFALL) {
5209*77c1e3ccSAndroid Build Coastguard Worker colour_ptr->max_fall = UnserializeUInt(reader, read_pos, child_size);
5210*77c1e3ccSAndroid Build Coastguard Worker if (colour_ptr->max_fall < 0)
5211*77c1e3ccSAndroid Build Coastguard Worker return false;
5212*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvMasteringMetadata) {
5213*77c1e3ccSAndroid Build Coastguard Worker if (!MasteringMetadata::Parse(reader, read_pos, child_size,
5214*77c1e3ccSAndroid Build Coastguard Worker &colour_ptr->mastering_metadata))
5215*77c1e3ccSAndroid Build Coastguard Worker return false;
5216*77c1e3ccSAndroid Build Coastguard Worker } else {
5217*77c1e3ccSAndroid Build Coastguard Worker return false;
5218*77c1e3ccSAndroid Build Coastguard Worker }
5219*77c1e3ccSAndroid Build Coastguard Worker
5220*77c1e3ccSAndroid Build Coastguard Worker read_pos += child_size;
5221*77c1e3ccSAndroid Build Coastguard Worker if (read_pos > colour_end)
5222*77c1e3ccSAndroid Build Coastguard Worker return false;
5223*77c1e3ccSAndroid Build Coastguard Worker }
5224*77c1e3ccSAndroid Build Coastguard Worker *colour = colour_ptr.release();
5225*77c1e3ccSAndroid Build Coastguard Worker return true;
5226*77c1e3ccSAndroid Build Coastguard Worker }
5227*77c1e3ccSAndroid Build Coastguard Worker
Parse(IMkvReader * reader,long long start,long long size,Projection ** projection)5228*77c1e3ccSAndroid Build Coastguard Worker bool Projection::Parse(IMkvReader* reader, long long start, long long size,
5229*77c1e3ccSAndroid Build Coastguard Worker Projection** projection) {
5230*77c1e3ccSAndroid Build Coastguard Worker if (!reader || *projection)
5231*77c1e3ccSAndroid Build Coastguard Worker return false;
5232*77c1e3ccSAndroid Build Coastguard Worker
5233*77c1e3ccSAndroid Build Coastguard Worker std::unique_ptr<Projection> projection_ptr(new Projection());
5234*77c1e3ccSAndroid Build Coastguard Worker if (!projection_ptr.get())
5235*77c1e3ccSAndroid Build Coastguard Worker return false;
5236*77c1e3ccSAndroid Build Coastguard Worker
5237*77c1e3ccSAndroid Build Coastguard Worker const long long end = start + size;
5238*77c1e3ccSAndroid Build Coastguard Worker long long read_pos = start;
5239*77c1e3ccSAndroid Build Coastguard Worker
5240*77c1e3ccSAndroid Build Coastguard Worker while (read_pos < end) {
5241*77c1e3ccSAndroid Build Coastguard Worker long long child_id = 0;
5242*77c1e3ccSAndroid Build Coastguard Worker long long child_size = 0;
5243*77c1e3ccSAndroid Build Coastguard Worker
5244*77c1e3ccSAndroid Build Coastguard Worker const long long status =
5245*77c1e3ccSAndroid Build Coastguard Worker ParseElementHeader(reader, read_pos, end, child_id, child_size);
5246*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
5247*77c1e3ccSAndroid Build Coastguard Worker return false;
5248*77c1e3ccSAndroid Build Coastguard Worker
5249*77c1e3ccSAndroid Build Coastguard Worker if (child_id == libwebm::kMkvProjectionType) {
5250*77c1e3ccSAndroid Build Coastguard Worker long long projection_type = kTypeNotPresent;
5251*77c1e3ccSAndroid Build Coastguard Worker projection_type = UnserializeUInt(reader, read_pos, child_size);
5252*77c1e3ccSAndroid Build Coastguard Worker if (projection_type < 0)
5253*77c1e3ccSAndroid Build Coastguard Worker return false;
5254*77c1e3ccSAndroid Build Coastguard Worker
5255*77c1e3ccSAndroid Build Coastguard Worker projection_ptr->type = static_cast<ProjectionType>(projection_type);
5256*77c1e3ccSAndroid Build Coastguard Worker } else if (child_id == libwebm::kMkvProjectionPrivate) {
5257*77c1e3ccSAndroid Build Coastguard Worker if (projection_ptr->private_data != NULL)
5258*77c1e3ccSAndroid Build Coastguard Worker return false;
5259*77c1e3ccSAndroid Build Coastguard Worker unsigned char* data = SafeArrayAlloc<unsigned char>(1, child_size);
5260*77c1e3ccSAndroid Build Coastguard Worker
5261*77c1e3ccSAndroid Build Coastguard Worker if (data == NULL)
5262*77c1e3ccSAndroid Build Coastguard Worker return false;
5263*77c1e3ccSAndroid Build Coastguard Worker
5264*77c1e3ccSAndroid Build Coastguard Worker const int status =
5265*77c1e3ccSAndroid Build Coastguard Worker reader->Read(read_pos, static_cast<long>(child_size), data);
5266*77c1e3ccSAndroid Build Coastguard Worker
5267*77c1e3ccSAndroid Build Coastguard Worker if (status) {
5268*77c1e3ccSAndroid Build Coastguard Worker delete[] data;
5269*77c1e3ccSAndroid Build Coastguard Worker return false;
5270*77c1e3ccSAndroid Build Coastguard Worker }
5271*77c1e3ccSAndroid Build Coastguard Worker
5272*77c1e3ccSAndroid Build Coastguard Worker projection_ptr->private_data = data;
5273*77c1e3ccSAndroid Build Coastguard Worker projection_ptr->private_data_length = static_cast<size_t>(child_size);
5274*77c1e3ccSAndroid Build Coastguard Worker } else {
5275*77c1e3ccSAndroid Build Coastguard Worker double value = 0;
5276*77c1e3ccSAndroid Build Coastguard Worker const long long value_parse_status =
5277*77c1e3ccSAndroid Build Coastguard Worker UnserializeFloat(reader, read_pos, child_size, value);
5278*77c1e3ccSAndroid Build Coastguard Worker // Make sure value is representable as a float before casting.
5279*77c1e3ccSAndroid Build Coastguard Worker if (value_parse_status < 0 || value < -FLT_MAX || value > FLT_MAX ||
5280*77c1e3ccSAndroid Build Coastguard Worker (value > 0.0 && value < FLT_MIN)) {
5281*77c1e3ccSAndroid Build Coastguard Worker return false;
5282*77c1e3ccSAndroid Build Coastguard Worker }
5283*77c1e3ccSAndroid Build Coastguard Worker
5284*77c1e3ccSAndroid Build Coastguard Worker switch (child_id) {
5285*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvProjectionPoseYaw:
5286*77c1e3ccSAndroid Build Coastguard Worker projection_ptr->pose_yaw = static_cast<float>(value);
5287*77c1e3ccSAndroid Build Coastguard Worker break;
5288*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvProjectionPosePitch:
5289*77c1e3ccSAndroid Build Coastguard Worker projection_ptr->pose_pitch = static_cast<float>(value);
5290*77c1e3ccSAndroid Build Coastguard Worker break;
5291*77c1e3ccSAndroid Build Coastguard Worker case libwebm::kMkvProjectionPoseRoll:
5292*77c1e3ccSAndroid Build Coastguard Worker projection_ptr->pose_roll = static_cast<float>(value);
5293*77c1e3ccSAndroid Build Coastguard Worker break;
5294*77c1e3ccSAndroid Build Coastguard Worker default:
5295*77c1e3ccSAndroid Build Coastguard Worker return false;
5296*77c1e3ccSAndroid Build Coastguard Worker }
5297*77c1e3ccSAndroid Build Coastguard Worker }
5298*77c1e3ccSAndroid Build Coastguard Worker
5299*77c1e3ccSAndroid Build Coastguard Worker read_pos += child_size;
5300*77c1e3ccSAndroid Build Coastguard Worker if (read_pos > end)
5301*77c1e3ccSAndroid Build Coastguard Worker return false;
5302*77c1e3ccSAndroid Build Coastguard Worker }
5303*77c1e3ccSAndroid Build Coastguard Worker
5304*77c1e3ccSAndroid Build Coastguard Worker *projection = projection_ptr.release();
5305*77c1e3ccSAndroid Build Coastguard Worker return true;
5306*77c1e3ccSAndroid Build Coastguard Worker }
5307*77c1e3ccSAndroid Build Coastguard Worker
VideoTrack(Segment * pSegment,long long element_start,long long element_size)5308*77c1e3ccSAndroid Build Coastguard Worker VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
5309*77c1e3ccSAndroid Build Coastguard Worker long long element_size)
5310*77c1e3ccSAndroid Build Coastguard Worker : Track(pSegment, element_start, element_size),
5311*77c1e3ccSAndroid Build Coastguard Worker m_colour_space(NULL),
5312*77c1e3ccSAndroid Build Coastguard Worker m_colour(NULL),
5313*77c1e3ccSAndroid Build Coastguard Worker m_projection(NULL) {}
5314*77c1e3ccSAndroid Build Coastguard Worker
~VideoTrack()5315*77c1e3ccSAndroid Build Coastguard Worker VideoTrack::~VideoTrack() {
5316*77c1e3ccSAndroid Build Coastguard Worker delete[] m_colour_space;
5317*77c1e3ccSAndroid Build Coastguard Worker delete m_colour;
5318*77c1e3ccSAndroid Build Coastguard Worker delete m_projection;
5319*77c1e3ccSAndroid Build Coastguard Worker }
5320*77c1e3ccSAndroid Build Coastguard Worker
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,VideoTrack * & pResult)5321*77c1e3ccSAndroid Build Coastguard Worker long VideoTrack::Parse(Segment* pSegment, const Info& info,
5322*77c1e3ccSAndroid Build Coastguard Worker long long element_start, long long element_size,
5323*77c1e3ccSAndroid Build Coastguard Worker VideoTrack*& pResult) {
5324*77c1e3ccSAndroid Build Coastguard Worker if (pResult)
5325*77c1e3ccSAndroid Build Coastguard Worker return -1;
5326*77c1e3ccSAndroid Build Coastguard Worker
5327*77c1e3ccSAndroid Build Coastguard Worker if (info.type != Track::kVideo)
5328*77c1e3ccSAndroid Build Coastguard Worker return -1;
5329*77c1e3ccSAndroid Build Coastguard Worker
5330*77c1e3ccSAndroid Build Coastguard Worker long long width = 0;
5331*77c1e3ccSAndroid Build Coastguard Worker long long height = 0;
5332*77c1e3ccSAndroid Build Coastguard Worker long long display_width = 0;
5333*77c1e3ccSAndroid Build Coastguard Worker long long display_height = 0;
5334*77c1e3ccSAndroid Build Coastguard Worker long long display_unit = 0;
5335*77c1e3ccSAndroid Build Coastguard Worker long long stereo_mode = 0;
5336*77c1e3ccSAndroid Build Coastguard Worker
5337*77c1e3ccSAndroid Build Coastguard Worker double rate = 0.0;
5338*77c1e3ccSAndroid Build Coastguard Worker std::unique_ptr<char[]> colour_space_ptr;
5339*77c1e3ccSAndroid Build Coastguard Worker
5340*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = pSegment->m_pReader;
5341*77c1e3ccSAndroid Build Coastguard Worker
5342*77c1e3ccSAndroid Build Coastguard Worker const Settings& s = info.settings;
5343*77c1e3ccSAndroid Build Coastguard Worker assert(s.start >= 0);
5344*77c1e3ccSAndroid Build Coastguard Worker assert(s.size >= 0);
5345*77c1e3ccSAndroid Build Coastguard Worker
5346*77c1e3ccSAndroid Build Coastguard Worker long long pos = s.start;
5347*77c1e3ccSAndroid Build Coastguard Worker assert(pos >= 0);
5348*77c1e3ccSAndroid Build Coastguard Worker
5349*77c1e3ccSAndroid Build Coastguard Worker const long long stop = pos + s.size;
5350*77c1e3ccSAndroid Build Coastguard Worker
5351*77c1e3ccSAndroid Build Coastguard Worker std::unique_ptr<Colour> colour_ptr;
5352*77c1e3ccSAndroid Build Coastguard Worker std::unique_ptr<Projection> projection_ptr;
5353*77c1e3ccSAndroid Build Coastguard Worker
5354*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
5355*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
5356*77c1e3ccSAndroid Build Coastguard Worker
5357*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, stop, id, size);
5358*77c1e3ccSAndroid Build Coastguard Worker
5359*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
5360*77c1e3ccSAndroid Build Coastguard Worker return status;
5361*77c1e3ccSAndroid Build Coastguard Worker
5362*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvPixelWidth) {
5363*77c1e3ccSAndroid Build Coastguard Worker width = UnserializeUInt(pReader, pos, size);
5364*77c1e3ccSAndroid Build Coastguard Worker
5365*77c1e3ccSAndroid Build Coastguard Worker if (width <= 0)
5366*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5367*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvPixelHeight) {
5368*77c1e3ccSAndroid Build Coastguard Worker height = UnserializeUInt(pReader, pos, size);
5369*77c1e3ccSAndroid Build Coastguard Worker
5370*77c1e3ccSAndroid Build Coastguard Worker if (height <= 0)
5371*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5372*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvDisplayWidth) {
5373*77c1e3ccSAndroid Build Coastguard Worker display_width = UnserializeUInt(pReader, pos, size);
5374*77c1e3ccSAndroid Build Coastguard Worker
5375*77c1e3ccSAndroid Build Coastguard Worker if (display_width <= 0)
5376*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5377*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvDisplayHeight) {
5378*77c1e3ccSAndroid Build Coastguard Worker display_height = UnserializeUInt(pReader, pos, size);
5379*77c1e3ccSAndroid Build Coastguard Worker
5380*77c1e3ccSAndroid Build Coastguard Worker if (display_height <= 0)
5381*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5382*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvDisplayUnit) {
5383*77c1e3ccSAndroid Build Coastguard Worker display_unit = UnserializeUInt(pReader, pos, size);
5384*77c1e3ccSAndroid Build Coastguard Worker
5385*77c1e3ccSAndroid Build Coastguard Worker if (display_unit < 0)
5386*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5387*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvStereoMode) {
5388*77c1e3ccSAndroid Build Coastguard Worker stereo_mode = UnserializeUInt(pReader, pos, size);
5389*77c1e3ccSAndroid Build Coastguard Worker
5390*77c1e3ccSAndroid Build Coastguard Worker if (stereo_mode < 0)
5391*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5392*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvFrameRate) {
5393*77c1e3ccSAndroid Build Coastguard Worker const long status = UnserializeFloat(pReader, pos, size, rate);
5394*77c1e3ccSAndroid Build Coastguard Worker
5395*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
5396*77c1e3ccSAndroid Build Coastguard Worker return status;
5397*77c1e3ccSAndroid Build Coastguard Worker
5398*77c1e3ccSAndroid Build Coastguard Worker if (rate <= 0)
5399*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5400*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvColour) {
5401*77c1e3ccSAndroid Build Coastguard Worker Colour* colour = NULL;
5402*77c1e3ccSAndroid Build Coastguard Worker if (!Colour::Parse(pReader, pos, size, &colour)) {
5403*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5404*77c1e3ccSAndroid Build Coastguard Worker } else {
5405*77c1e3ccSAndroid Build Coastguard Worker colour_ptr.reset(colour);
5406*77c1e3ccSAndroid Build Coastguard Worker }
5407*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvProjection) {
5408*77c1e3ccSAndroid Build Coastguard Worker Projection* projection = NULL;
5409*77c1e3ccSAndroid Build Coastguard Worker if (!Projection::Parse(pReader, pos, size, &projection)) {
5410*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5411*77c1e3ccSAndroid Build Coastguard Worker } else {
5412*77c1e3ccSAndroid Build Coastguard Worker projection_ptr.reset(projection);
5413*77c1e3ccSAndroid Build Coastguard Worker }
5414*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvColourSpace) {
5415*77c1e3ccSAndroid Build Coastguard Worker char* colour_space = NULL;
5416*77c1e3ccSAndroid Build Coastguard Worker const long status = UnserializeString(pReader, pos, size, colour_space);
5417*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
5418*77c1e3ccSAndroid Build Coastguard Worker return status;
5419*77c1e3ccSAndroid Build Coastguard Worker colour_space_ptr.reset(colour_space);
5420*77c1e3ccSAndroid Build Coastguard Worker }
5421*77c1e3ccSAndroid Build Coastguard Worker
5422*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
5423*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
5424*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5425*77c1e3ccSAndroid Build Coastguard Worker }
5426*77c1e3ccSAndroid Build Coastguard Worker
5427*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
5428*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5429*77c1e3ccSAndroid Build Coastguard Worker
5430*77c1e3ccSAndroid Build Coastguard Worker VideoTrack* const pTrack =
5431*77c1e3ccSAndroid Build Coastguard Worker new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
5432*77c1e3ccSAndroid Build Coastguard Worker
5433*77c1e3ccSAndroid Build Coastguard Worker if (pTrack == NULL)
5434*77c1e3ccSAndroid Build Coastguard Worker return -1; // generic error
5435*77c1e3ccSAndroid Build Coastguard Worker
5436*77c1e3ccSAndroid Build Coastguard Worker const int status = info.Copy(pTrack->m_info);
5437*77c1e3ccSAndroid Build Coastguard Worker
5438*77c1e3ccSAndroid Build Coastguard Worker if (status) { // error
5439*77c1e3ccSAndroid Build Coastguard Worker delete pTrack;
5440*77c1e3ccSAndroid Build Coastguard Worker return status;
5441*77c1e3ccSAndroid Build Coastguard Worker }
5442*77c1e3ccSAndroid Build Coastguard Worker
5443*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_width = width;
5444*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_height = height;
5445*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_display_width = display_width;
5446*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_display_height = display_height;
5447*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_display_unit = display_unit;
5448*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_stereo_mode = stereo_mode;
5449*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_rate = rate;
5450*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_colour = colour_ptr.release();
5451*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_colour_space = colour_space_ptr.release();
5452*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_projection = projection_ptr.release();
5453*77c1e3ccSAndroid Build Coastguard Worker
5454*77c1e3ccSAndroid Build Coastguard Worker pResult = pTrack;
5455*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
5456*77c1e3ccSAndroid Build Coastguard Worker }
5457*77c1e3ccSAndroid Build Coastguard Worker
VetEntry(const BlockEntry * pBlockEntry) const5458*77c1e3ccSAndroid Build Coastguard Worker bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const {
5459*77c1e3ccSAndroid Build Coastguard Worker return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey();
5460*77c1e3ccSAndroid Build Coastguard Worker }
5461*77c1e3ccSAndroid Build Coastguard Worker
Seek(long long time_ns,const BlockEntry * & pResult) const5462*77c1e3ccSAndroid Build Coastguard Worker long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
5463*77c1e3ccSAndroid Build Coastguard Worker const long status = GetFirst(pResult);
5464*77c1e3ccSAndroid Build Coastguard Worker
5465*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // buffer underflow, etc
5466*77c1e3ccSAndroid Build Coastguard Worker return status;
5467*77c1e3ccSAndroid Build Coastguard Worker
5468*77c1e3ccSAndroid Build Coastguard Worker assert(pResult);
5469*77c1e3ccSAndroid Build Coastguard Worker
5470*77c1e3ccSAndroid Build Coastguard Worker if (pResult->EOS())
5471*77c1e3ccSAndroid Build Coastguard Worker return 0;
5472*77c1e3ccSAndroid Build Coastguard Worker
5473*77c1e3ccSAndroid Build Coastguard Worker const Cluster* pCluster = pResult->GetCluster();
5474*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
5475*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetIndex() >= 0);
5476*77c1e3ccSAndroid Build Coastguard Worker
5477*77c1e3ccSAndroid Build Coastguard Worker if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
5478*77c1e3ccSAndroid Build Coastguard Worker return 0;
5479*77c1e3ccSAndroid Build Coastguard Worker
5480*77c1e3ccSAndroid Build Coastguard Worker Cluster** const clusters = m_pSegment->m_clusters;
5481*77c1e3ccSAndroid Build Coastguard Worker assert(clusters);
5482*77c1e3ccSAndroid Build Coastguard Worker
5483*77c1e3ccSAndroid Build Coastguard Worker const long count = m_pSegment->GetCount(); // loaded only, not pre-loaded
5484*77c1e3ccSAndroid Build Coastguard Worker assert(count > 0);
5485*77c1e3ccSAndroid Build Coastguard Worker
5486*77c1e3ccSAndroid Build Coastguard Worker Cluster** const i = clusters + pCluster->GetIndex();
5487*77c1e3ccSAndroid Build Coastguard Worker assert(i);
5488*77c1e3ccSAndroid Build Coastguard Worker assert(*i == pCluster);
5489*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetTime() <= time_ns);
5490*77c1e3ccSAndroid Build Coastguard Worker
5491*77c1e3ccSAndroid Build Coastguard Worker Cluster** const j = clusters + count;
5492*77c1e3ccSAndroid Build Coastguard Worker
5493*77c1e3ccSAndroid Build Coastguard Worker Cluster** lo = i;
5494*77c1e3ccSAndroid Build Coastguard Worker Cluster** hi = j;
5495*77c1e3ccSAndroid Build Coastguard Worker
5496*77c1e3ccSAndroid Build Coastguard Worker while (lo < hi) {
5497*77c1e3ccSAndroid Build Coastguard Worker // INVARIANT:
5498*77c1e3ccSAndroid Build Coastguard Worker //[i, lo) <= time_ns
5499*77c1e3ccSAndroid Build Coastguard Worker //[lo, hi) ?
5500*77c1e3ccSAndroid Build Coastguard Worker //[hi, j) > time_ns
5501*77c1e3ccSAndroid Build Coastguard Worker
5502*77c1e3ccSAndroid Build Coastguard Worker Cluster** const mid = lo + (hi - lo) / 2;
5503*77c1e3ccSAndroid Build Coastguard Worker assert(mid < hi);
5504*77c1e3ccSAndroid Build Coastguard Worker
5505*77c1e3ccSAndroid Build Coastguard Worker pCluster = *mid;
5506*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
5507*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetIndex() >= 0);
5508*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
5509*77c1e3ccSAndroid Build Coastguard Worker
5510*77c1e3ccSAndroid Build Coastguard Worker const long long t = pCluster->GetTime();
5511*77c1e3ccSAndroid Build Coastguard Worker
5512*77c1e3ccSAndroid Build Coastguard Worker if (t <= time_ns)
5513*77c1e3ccSAndroid Build Coastguard Worker lo = mid + 1;
5514*77c1e3ccSAndroid Build Coastguard Worker else
5515*77c1e3ccSAndroid Build Coastguard Worker hi = mid;
5516*77c1e3ccSAndroid Build Coastguard Worker
5517*77c1e3ccSAndroid Build Coastguard Worker assert(lo <= hi);
5518*77c1e3ccSAndroid Build Coastguard Worker }
5519*77c1e3ccSAndroid Build Coastguard Worker
5520*77c1e3ccSAndroid Build Coastguard Worker assert(lo == hi);
5521*77c1e3ccSAndroid Build Coastguard Worker assert(lo > i);
5522*77c1e3ccSAndroid Build Coastguard Worker assert(lo <= j);
5523*77c1e3ccSAndroid Build Coastguard Worker
5524*77c1e3ccSAndroid Build Coastguard Worker pCluster = *--lo;
5525*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
5526*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetTime() <= time_ns);
5527*77c1e3ccSAndroid Build Coastguard Worker
5528*77c1e3ccSAndroid Build Coastguard Worker pResult = pCluster->GetEntry(this, time_ns);
5529*77c1e3ccSAndroid Build Coastguard Worker
5530*77c1e3ccSAndroid Build Coastguard Worker if ((pResult != 0) && !pResult->EOS()) // found a keyframe
5531*77c1e3ccSAndroid Build Coastguard Worker return 0;
5532*77c1e3ccSAndroid Build Coastguard Worker
5533*77c1e3ccSAndroid Build Coastguard Worker while (lo != i) {
5534*77c1e3ccSAndroid Build Coastguard Worker pCluster = *--lo;
5535*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
5536*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster->GetTime() <= time_ns);
5537*77c1e3ccSAndroid Build Coastguard Worker
5538*77c1e3ccSAndroid Build Coastguard Worker pResult = pCluster->GetEntry(this, time_ns);
5539*77c1e3ccSAndroid Build Coastguard Worker
5540*77c1e3ccSAndroid Build Coastguard Worker if ((pResult != 0) && !pResult->EOS())
5541*77c1e3ccSAndroid Build Coastguard Worker return 0;
5542*77c1e3ccSAndroid Build Coastguard Worker }
5543*77c1e3ccSAndroid Build Coastguard Worker
5544*77c1e3ccSAndroid Build Coastguard Worker // weird: we're on the first cluster, but no keyframe found
5545*77c1e3ccSAndroid Build Coastguard Worker // should never happen but we must return something anyway
5546*77c1e3ccSAndroid Build Coastguard Worker
5547*77c1e3ccSAndroid Build Coastguard Worker pResult = GetEOS();
5548*77c1e3ccSAndroid Build Coastguard Worker return 0;
5549*77c1e3ccSAndroid Build Coastguard Worker }
5550*77c1e3ccSAndroid Build Coastguard Worker
GetColour() const5551*77c1e3ccSAndroid Build Coastguard Worker Colour* VideoTrack::GetColour() const { return m_colour; }
5552*77c1e3ccSAndroid Build Coastguard Worker
GetProjection() const5553*77c1e3ccSAndroid Build Coastguard Worker Projection* VideoTrack::GetProjection() const { return m_projection; }
5554*77c1e3ccSAndroid Build Coastguard Worker
GetWidth() const5555*77c1e3ccSAndroid Build Coastguard Worker long long VideoTrack::GetWidth() const { return m_width; }
5556*77c1e3ccSAndroid Build Coastguard Worker
GetHeight() const5557*77c1e3ccSAndroid Build Coastguard Worker long long VideoTrack::GetHeight() const { return m_height; }
5558*77c1e3ccSAndroid Build Coastguard Worker
GetDisplayWidth() const5559*77c1e3ccSAndroid Build Coastguard Worker long long VideoTrack::GetDisplayWidth() const {
5560*77c1e3ccSAndroid Build Coastguard Worker return m_display_width > 0 ? m_display_width : GetWidth();
5561*77c1e3ccSAndroid Build Coastguard Worker }
5562*77c1e3ccSAndroid Build Coastguard Worker
GetDisplayHeight() const5563*77c1e3ccSAndroid Build Coastguard Worker long long VideoTrack::GetDisplayHeight() const {
5564*77c1e3ccSAndroid Build Coastguard Worker return m_display_height > 0 ? m_display_height : GetHeight();
5565*77c1e3ccSAndroid Build Coastguard Worker }
5566*77c1e3ccSAndroid Build Coastguard Worker
GetDisplayUnit() const5567*77c1e3ccSAndroid Build Coastguard Worker long long VideoTrack::GetDisplayUnit() const { return m_display_unit; }
5568*77c1e3ccSAndroid Build Coastguard Worker
GetStereoMode() const5569*77c1e3ccSAndroid Build Coastguard Worker long long VideoTrack::GetStereoMode() const { return m_stereo_mode; }
5570*77c1e3ccSAndroid Build Coastguard Worker
GetFrameRate() const5571*77c1e3ccSAndroid Build Coastguard Worker double VideoTrack::GetFrameRate() const { return m_rate; }
5572*77c1e3ccSAndroid Build Coastguard Worker
AudioTrack(Segment * pSegment,long long element_start,long long element_size)5573*77c1e3ccSAndroid Build Coastguard Worker AudioTrack::AudioTrack(Segment* pSegment, long long element_start,
5574*77c1e3ccSAndroid Build Coastguard Worker long long element_size)
5575*77c1e3ccSAndroid Build Coastguard Worker : Track(pSegment, element_start, element_size) {}
5576*77c1e3ccSAndroid Build Coastguard Worker
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,AudioTrack * & pResult)5577*77c1e3ccSAndroid Build Coastguard Worker long AudioTrack::Parse(Segment* pSegment, const Info& info,
5578*77c1e3ccSAndroid Build Coastguard Worker long long element_start, long long element_size,
5579*77c1e3ccSAndroid Build Coastguard Worker AudioTrack*& pResult) {
5580*77c1e3ccSAndroid Build Coastguard Worker if (pResult)
5581*77c1e3ccSAndroid Build Coastguard Worker return -1;
5582*77c1e3ccSAndroid Build Coastguard Worker
5583*77c1e3ccSAndroid Build Coastguard Worker if (info.type != Track::kAudio)
5584*77c1e3ccSAndroid Build Coastguard Worker return -1;
5585*77c1e3ccSAndroid Build Coastguard Worker
5586*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = pSegment->m_pReader;
5587*77c1e3ccSAndroid Build Coastguard Worker
5588*77c1e3ccSAndroid Build Coastguard Worker const Settings& s = info.settings;
5589*77c1e3ccSAndroid Build Coastguard Worker assert(s.start >= 0);
5590*77c1e3ccSAndroid Build Coastguard Worker assert(s.size >= 0);
5591*77c1e3ccSAndroid Build Coastguard Worker
5592*77c1e3ccSAndroid Build Coastguard Worker long long pos = s.start;
5593*77c1e3ccSAndroid Build Coastguard Worker assert(pos >= 0);
5594*77c1e3ccSAndroid Build Coastguard Worker
5595*77c1e3ccSAndroid Build Coastguard Worker const long long stop = pos + s.size;
5596*77c1e3ccSAndroid Build Coastguard Worker
5597*77c1e3ccSAndroid Build Coastguard Worker double rate = 8000.0; // MKV default
5598*77c1e3ccSAndroid Build Coastguard Worker long long channels = 1;
5599*77c1e3ccSAndroid Build Coastguard Worker long long bit_depth = 0;
5600*77c1e3ccSAndroid Build Coastguard Worker
5601*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
5602*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
5603*77c1e3ccSAndroid Build Coastguard Worker
5604*77c1e3ccSAndroid Build Coastguard Worker long status = ParseElementHeader(pReader, pos, stop, id, size);
5605*77c1e3ccSAndroid Build Coastguard Worker
5606*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
5607*77c1e3ccSAndroid Build Coastguard Worker return status;
5608*77c1e3ccSAndroid Build Coastguard Worker
5609*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvSamplingFrequency) {
5610*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeFloat(pReader, pos, size, rate);
5611*77c1e3ccSAndroid Build Coastguard Worker
5612*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
5613*77c1e3ccSAndroid Build Coastguard Worker return status;
5614*77c1e3ccSAndroid Build Coastguard Worker
5615*77c1e3ccSAndroid Build Coastguard Worker if (rate <= 0)
5616*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5617*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvChannels) {
5618*77c1e3ccSAndroid Build Coastguard Worker channels = UnserializeUInt(pReader, pos, size);
5619*77c1e3ccSAndroid Build Coastguard Worker
5620*77c1e3ccSAndroid Build Coastguard Worker if (channels <= 0)
5621*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5622*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvBitDepth) {
5623*77c1e3ccSAndroid Build Coastguard Worker bit_depth = UnserializeUInt(pReader, pos, size);
5624*77c1e3ccSAndroid Build Coastguard Worker
5625*77c1e3ccSAndroid Build Coastguard Worker if (bit_depth <= 0)
5626*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5627*77c1e3ccSAndroid Build Coastguard Worker }
5628*77c1e3ccSAndroid Build Coastguard Worker
5629*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
5630*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
5631*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5632*77c1e3ccSAndroid Build Coastguard Worker }
5633*77c1e3ccSAndroid Build Coastguard Worker
5634*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
5635*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5636*77c1e3ccSAndroid Build Coastguard Worker
5637*77c1e3ccSAndroid Build Coastguard Worker AudioTrack* const pTrack =
5638*77c1e3ccSAndroid Build Coastguard Worker new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
5639*77c1e3ccSAndroid Build Coastguard Worker
5640*77c1e3ccSAndroid Build Coastguard Worker if (pTrack == NULL)
5641*77c1e3ccSAndroid Build Coastguard Worker return -1; // generic error
5642*77c1e3ccSAndroid Build Coastguard Worker
5643*77c1e3ccSAndroid Build Coastguard Worker const int status = info.Copy(pTrack->m_info);
5644*77c1e3ccSAndroid Build Coastguard Worker
5645*77c1e3ccSAndroid Build Coastguard Worker if (status) {
5646*77c1e3ccSAndroid Build Coastguard Worker delete pTrack;
5647*77c1e3ccSAndroid Build Coastguard Worker return status;
5648*77c1e3ccSAndroid Build Coastguard Worker }
5649*77c1e3ccSAndroid Build Coastguard Worker
5650*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_rate = rate;
5651*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_channels = channels;
5652*77c1e3ccSAndroid Build Coastguard Worker pTrack->m_bitDepth = bit_depth;
5653*77c1e3ccSAndroid Build Coastguard Worker
5654*77c1e3ccSAndroid Build Coastguard Worker pResult = pTrack;
5655*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
5656*77c1e3ccSAndroid Build Coastguard Worker }
5657*77c1e3ccSAndroid Build Coastguard Worker
GetSamplingRate() const5658*77c1e3ccSAndroid Build Coastguard Worker double AudioTrack::GetSamplingRate() const { return m_rate; }
5659*77c1e3ccSAndroid Build Coastguard Worker
GetChannels() const5660*77c1e3ccSAndroid Build Coastguard Worker long long AudioTrack::GetChannels() const { return m_channels; }
5661*77c1e3ccSAndroid Build Coastguard Worker
GetBitDepth() const5662*77c1e3ccSAndroid Build Coastguard Worker long long AudioTrack::GetBitDepth() const { return m_bitDepth; }
5663*77c1e3ccSAndroid Build Coastguard Worker
Tracks(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)5664*77c1e3ccSAndroid Build Coastguard Worker Tracks::Tracks(Segment* pSegment, long long start, long long size_,
5665*77c1e3ccSAndroid Build Coastguard Worker long long element_start, long long element_size)
5666*77c1e3ccSAndroid Build Coastguard Worker : m_pSegment(pSegment),
5667*77c1e3ccSAndroid Build Coastguard Worker m_start(start),
5668*77c1e3ccSAndroid Build Coastguard Worker m_size(size_),
5669*77c1e3ccSAndroid Build Coastguard Worker m_element_start(element_start),
5670*77c1e3ccSAndroid Build Coastguard Worker m_element_size(element_size),
5671*77c1e3ccSAndroid Build Coastguard Worker m_trackEntries(NULL),
5672*77c1e3ccSAndroid Build Coastguard Worker m_trackEntriesEnd(NULL) {}
5673*77c1e3ccSAndroid Build Coastguard Worker
Parse()5674*77c1e3ccSAndroid Build Coastguard Worker long Tracks::Parse() {
5675*77c1e3ccSAndroid Build Coastguard Worker assert(m_trackEntries == NULL);
5676*77c1e3ccSAndroid Build Coastguard Worker assert(m_trackEntriesEnd == NULL);
5677*77c1e3ccSAndroid Build Coastguard Worker
5678*77c1e3ccSAndroid Build Coastguard Worker const long long stop = m_start + m_size;
5679*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
5680*77c1e3ccSAndroid Build Coastguard Worker
5681*77c1e3ccSAndroid Build Coastguard Worker long long count = 0;
5682*77c1e3ccSAndroid Build Coastguard Worker long long pos = m_start;
5683*77c1e3ccSAndroid Build Coastguard Worker
5684*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
5685*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
5686*77c1e3ccSAndroid Build Coastguard Worker
5687*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, stop, id, size);
5688*77c1e3ccSAndroid Build Coastguard Worker
5689*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
5690*77c1e3ccSAndroid Build Coastguard Worker return status;
5691*77c1e3ccSAndroid Build Coastguard Worker
5692*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // weird
5693*77c1e3ccSAndroid Build Coastguard Worker continue;
5694*77c1e3ccSAndroid Build Coastguard Worker
5695*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvTrackEntry) {
5696*77c1e3ccSAndroid Build Coastguard Worker ++count;
5697*77c1e3ccSAndroid Build Coastguard Worker if (count > INT_MAX)
5698*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
5699*77c1e3ccSAndroid Build Coastguard Worker }
5700*77c1e3ccSAndroid Build Coastguard Worker
5701*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
5702*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
5703*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5704*77c1e3ccSAndroid Build Coastguard Worker }
5705*77c1e3ccSAndroid Build Coastguard Worker
5706*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
5707*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5708*77c1e3ccSAndroid Build Coastguard Worker
5709*77c1e3ccSAndroid Build Coastguard Worker if (count <= 0)
5710*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
5711*77c1e3ccSAndroid Build Coastguard Worker
5712*77c1e3ccSAndroid Build Coastguard Worker m_trackEntries = new (std::nothrow) Track*[static_cast<size_t>(count)];
5713*77c1e3ccSAndroid Build Coastguard Worker
5714*77c1e3ccSAndroid Build Coastguard Worker if (m_trackEntries == NULL)
5715*77c1e3ccSAndroid Build Coastguard Worker return -1;
5716*77c1e3ccSAndroid Build Coastguard Worker
5717*77c1e3ccSAndroid Build Coastguard Worker m_trackEntriesEnd = m_trackEntries;
5718*77c1e3ccSAndroid Build Coastguard Worker
5719*77c1e3ccSAndroid Build Coastguard Worker pos = m_start;
5720*77c1e3ccSAndroid Build Coastguard Worker
5721*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
5722*77c1e3ccSAndroid Build Coastguard Worker const long long element_start = pos;
5723*77c1e3ccSAndroid Build Coastguard Worker
5724*77c1e3ccSAndroid Build Coastguard Worker long long id, payload_size;
5725*77c1e3ccSAndroid Build Coastguard Worker
5726*77c1e3ccSAndroid Build Coastguard Worker const long status =
5727*77c1e3ccSAndroid Build Coastguard Worker ParseElementHeader(pReader, pos, stop, id, payload_size);
5728*77c1e3ccSAndroid Build Coastguard Worker
5729*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
5730*77c1e3ccSAndroid Build Coastguard Worker return status;
5731*77c1e3ccSAndroid Build Coastguard Worker
5732*77c1e3ccSAndroid Build Coastguard Worker if (payload_size == 0) // weird
5733*77c1e3ccSAndroid Build Coastguard Worker continue;
5734*77c1e3ccSAndroid Build Coastguard Worker
5735*77c1e3ccSAndroid Build Coastguard Worker const long long payload_stop = pos + payload_size;
5736*77c1e3ccSAndroid Build Coastguard Worker assert(payload_stop <= stop); // checked in ParseElement
5737*77c1e3ccSAndroid Build Coastguard Worker
5738*77c1e3ccSAndroid Build Coastguard Worker const long long element_size = payload_stop - element_start;
5739*77c1e3ccSAndroid Build Coastguard Worker
5740*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvTrackEntry) {
5741*77c1e3ccSAndroid Build Coastguard Worker Track*& pTrack = *m_trackEntriesEnd;
5742*77c1e3ccSAndroid Build Coastguard Worker pTrack = NULL;
5743*77c1e3ccSAndroid Build Coastguard Worker
5744*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseTrackEntry(pos, payload_size, element_start,
5745*77c1e3ccSAndroid Build Coastguard Worker element_size, pTrack);
5746*77c1e3ccSAndroid Build Coastguard Worker if (status)
5747*77c1e3ccSAndroid Build Coastguard Worker return status;
5748*77c1e3ccSAndroid Build Coastguard Worker
5749*77c1e3ccSAndroid Build Coastguard Worker if (pTrack)
5750*77c1e3ccSAndroid Build Coastguard Worker ++m_trackEntriesEnd;
5751*77c1e3ccSAndroid Build Coastguard Worker }
5752*77c1e3ccSAndroid Build Coastguard Worker
5753*77c1e3ccSAndroid Build Coastguard Worker pos = payload_stop;
5754*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
5755*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5756*77c1e3ccSAndroid Build Coastguard Worker }
5757*77c1e3ccSAndroid Build Coastguard Worker
5758*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
5759*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5760*77c1e3ccSAndroid Build Coastguard Worker
5761*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
5762*77c1e3ccSAndroid Build Coastguard Worker }
5763*77c1e3ccSAndroid Build Coastguard Worker
GetTracksCount() const5764*77c1e3ccSAndroid Build Coastguard Worker unsigned long Tracks::GetTracksCount() const {
5765*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
5766*77c1e3ccSAndroid Build Coastguard Worker assert(result >= 0);
5767*77c1e3ccSAndroid Build Coastguard Worker
5768*77c1e3ccSAndroid Build Coastguard Worker return static_cast<unsigned long>(result);
5769*77c1e3ccSAndroid Build Coastguard Worker }
5770*77c1e3ccSAndroid Build Coastguard Worker
ParseTrackEntry(long long track_start,long long track_size,long long element_start,long long element_size,Track * & pResult) const5771*77c1e3ccSAndroid Build Coastguard Worker long Tracks::ParseTrackEntry(long long track_start, long long track_size,
5772*77c1e3ccSAndroid Build Coastguard Worker long long element_start, long long element_size,
5773*77c1e3ccSAndroid Build Coastguard Worker Track*& pResult) const {
5774*77c1e3ccSAndroid Build Coastguard Worker if (pResult)
5775*77c1e3ccSAndroid Build Coastguard Worker return -1;
5776*77c1e3ccSAndroid Build Coastguard Worker
5777*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
5778*77c1e3ccSAndroid Build Coastguard Worker
5779*77c1e3ccSAndroid Build Coastguard Worker long long pos = track_start;
5780*77c1e3ccSAndroid Build Coastguard Worker const long long track_stop = track_start + track_size;
5781*77c1e3ccSAndroid Build Coastguard Worker
5782*77c1e3ccSAndroid Build Coastguard Worker Track::Info info;
5783*77c1e3ccSAndroid Build Coastguard Worker
5784*77c1e3ccSAndroid Build Coastguard Worker info.type = 0;
5785*77c1e3ccSAndroid Build Coastguard Worker info.number = 0;
5786*77c1e3ccSAndroid Build Coastguard Worker info.uid = 0;
5787*77c1e3ccSAndroid Build Coastguard Worker info.defaultDuration = 0;
5788*77c1e3ccSAndroid Build Coastguard Worker
5789*77c1e3ccSAndroid Build Coastguard Worker Track::Settings v;
5790*77c1e3ccSAndroid Build Coastguard Worker v.start = -1;
5791*77c1e3ccSAndroid Build Coastguard Worker v.size = -1;
5792*77c1e3ccSAndroid Build Coastguard Worker
5793*77c1e3ccSAndroid Build Coastguard Worker Track::Settings a;
5794*77c1e3ccSAndroid Build Coastguard Worker a.start = -1;
5795*77c1e3ccSAndroid Build Coastguard Worker a.size = -1;
5796*77c1e3ccSAndroid Build Coastguard Worker
5797*77c1e3ccSAndroid Build Coastguard Worker Track::Settings e; // content_encodings_settings;
5798*77c1e3ccSAndroid Build Coastguard Worker e.start = -1;
5799*77c1e3ccSAndroid Build Coastguard Worker e.size = -1;
5800*77c1e3ccSAndroid Build Coastguard Worker
5801*77c1e3ccSAndroid Build Coastguard Worker long long lacing = 1; // default is true
5802*77c1e3ccSAndroid Build Coastguard Worker
5803*77c1e3ccSAndroid Build Coastguard Worker while (pos < track_stop) {
5804*77c1e3ccSAndroid Build Coastguard Worker long long id, size;
5805*77c1e3ccSAndroid Build Coastguard Worker
5806*77c1e3ccSAndroid Build Coastguard Worker const long status = ParseElementHeader(pReader, pos, track_stop, id, size);
5807*77c1e3ccSAndroid Build Coastguard Worker
5808*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
5809*77c1e3ccSAndroid Build Coastguard Worker return status;
5810*77c1e3ccSAndroid Build Coastguard Worker
5811*77c1e3ccSAndroid Build Coastguard Worker if (size < 0)
5812*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5813*77c1e3ccSAndroid Build Coastguard Worker
5814*77c1e3ccSAndroid Build Coastguard Worker const long long start = pos;
5815*77c1e3ccSAndroid Build Coastguard Worker
5816*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvVideo) {
5817*77c1e3ccSAndroid Build Coastguard Worker v.start = start;
5818*77c1e3ccSAndroid Build Coastguard Worker v.size = size;
5819*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvAudio) {
5820*77c1e3ccSAndroid Build Coastguard Worker a.start = start;
5821*77c1e3ccSAndroid Build Coastguard Worker a.size = size;
5822*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvContentEncodings) {
5823*77c1e3ccSAndroid Build Coastguard Worker e.start = start;
5824*77c1e3ccSAndroid Build Coastguard Worker e.size = size;
5825*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvTrackUID) {
5826*77c1e3ccSAndroid Build Coastguard Worker if (size > 8)
5827*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5828*77c1e3ccSAndroid Build Coastguard Worker
5829*77c1e3ccSAndroid Build Coastguard Worker info.uid = 0;
5830*77c1e3ccSAndroid Build Coastguard Worker
5831*77c1e3ccSAndroid Build Coastguard Worker long long pos_ = start;
5832*77c1e3ccSAndroid Build Coastguard Worker const long long pos_end = start + size;
5833*77c1e3ccSAndroid Build Coastguard Worker
5834*77c1e3ccSAndroid Build Coastguard Worker while (pos_ != pos_end) {
5835*77c1e3ccSAndroid Build Coastguard Worker unsigned char b;
5836*77c1e3ccSAndroid Build Coastguard Worker
5837*77c1e3ccSAndroid Build Coastguard Worker const int status = pReader->Read(pos_, 1, &b);
5838*77c1e3ccSAndroid Build Coastguard Worker
5839*77c1e3ccSAndroid Build Coastguard Worker if (status)
5840*77c1e3ccSAndroid Build Coastguard Worker return status;
5841*77c1e3ccSAndroid Build Coastguard Worker
5842*77c1e3ccSAndroid Build Coastguard Worker info.uid <<= 8;
5843*77c1e3ccSAndroid Build Coastguard Worker info.uid |= b;
5844*77c1e3ccSAndroid Build Coastguard Worker
5845*77c1e3ccSAndroid Build Coastguard Worker ++pos_;
5846*77c1e3ccSAndroid Build Coastguard Worker }
5847*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvTrackNumber) {
5848*77c1e3ccSAndroid Build Coastguard Worker const long long num = UnserializeUInt(pReader, pos, size);
5849*77c1e3ccSAndroid Build Coastguard Worker
5850*77c1e3ccSAndroid Build Coastguard Worker if ((num <= 0) || (num > 127))
5851*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5852*77c1e3ccSAndroid Build Coastguard Worker
5853*77c1e3ccSAndroid Build Coastguard Worker info.number = static_cast<long>(num);
5854*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvTrackType) {
5855*77c1e3ccSAndroid Build Coastguard Worker const long long type = UnserializeUInt(pReader, pos, size);
5856*77c1e3ccSAndroid Build Coastguard Worker
5857*77c1e3ccSAndroid Build Coastguard Worker if ((type <= 0) || (type > 254))
5858*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5859*77c1e3ccSAndroid Build Coastguard Worker
5860*77c1e3ccSAndroid Build Coastguard Worker info.type = static_cast<long>(type);
5861*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvName) {
5862*77c1e3ccSAndroid Build Coastguard Worker const long status =
5863*77c1e3ccSAndroid Build Coastguard Worker UnserializeString(pReader, pos, size, info.nameAsUTF8);
5864*77c1e3ccSAndroid Build Coastguard Worker
5865*77c1e3ccSAndroid Build Coastguard Worker if (status)
5866*77c1e3ccSAndroid Build Coastguard Worker return status;
5867*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvLanguage) {
5868*77c1e3ccSAndroid Build Coastguard Worker const long status = UnserializeString(pReader, pos, size, info.language);
5869*77c1e3ccSAndroid Build Coastguard Worker
5870*77c1e3ccSAndroid Build Coastguard Worker if (status)
5871*77c1e3ccSAndroid Build Coastguard Worker return status;
5872*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvDefaultDuration) {
5873*77c1e3ccSAndroid Build Coastguard Worker const long long duration = UnserializeUInt(pReader, pos, size);
5874*77c1e3ccSAndroid Build Coastguard Worker
5875*77c1e3ccSAndroid Build Coastguard Worker if (duration < 0)
5876*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5877*77c1e3ccSAndroid Build Coastguard Worker
5878*77c1e3ccSAndroid Build Coastguard Worker info.defaultDuration = static_cast<unsigned long long>(duration);
5879*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvCodecID) {
5880*77c1e3ccSAndroid Build Coastguard Worker const long status = UnserializeString(pReader, pos, size, info.codecId);
5881*77c1e3ccSAndroid Build Coastguard Worker
5882*77c1e3ccSAndroid Build Coastguard Worker if (status)
5883*77c1e3ccSAndroid Build Coastguard Worker return status;
5884*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvFlagLacing) {
5885*77c1e3ccSAndroid Build Coastguard Worker lacing = UnserializeUInt(pReader, pos, size);
5886*77c1e3ccSAndroid Build Coastguard Worker
5887*77c1e3ccSAndroid Build Coastguard Worker if ((lacing < 0) || (lacing > 1))
5888*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5889*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvCodecPrivate) {
5890*77c1e3ccSAndroid Build Coastguard Worker delete[] info.codecPrivate;
5891*77c1e3ccSAndroid Build Coastguard Worker info.codecPrivate = NULL;
5892*77c1e3ccSAndroid Build Coastguard Worker info.codecPrivateSize = 0;
5893*77c1e3ccSAndroid Build Coastguard Worker
5894*77c1e3ccSAndroid Build Coastguard Worker const size_t buflen = static_cast<size_t>(size);
5895*77c1e3ccSAndroid Build Coastguard Worker
5896*77c1e3ccSAndroid Build Coastguard Worker if (buflen) {
5897*77c1e3ccSAndroid Build Coastguard Worker unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
5898*77c1e3ccSAndroid Build Coastguard Worker
5899*77c1e3ccSAndroid Build Coastguard Worker if (buf == NULL)
5900*77c1e3ccSAndroid Build Coastguard Worker return -1;
5901*77c1e3ccSAndroid Build Coastguard Worker
5902*77c1e3ccSAndroid Build Coastguard Worker const int status = pReader->Read(pos, static_cast<long>(buflen), buf);
5903*77c1e3ccSAndroid Build Coastguard Worker
5904*77c1e3ccSAndroid Build Coastguard Worker if (status) {
5905*77c1e3ccSAndroid Build Coastguard Worker delete[] buf;
5906*77c1e3ccSAndroid Build Coastguard Worker return status;
5907*77c1e3ccSAndroid Build Coastguard Worker }
5908*77c1e3ccSAndroid Build Coastguard Worker
5909*77c1e3ccSAndroid Build Coastguard Worker info.codecPrivate = buf;
5910*77c1e3ccSAndroid Build Coastguard Worker info.codecPrivateSize = buflen;
5911*77c1e3ccSAndroid Build Coastguard Worker }
5912*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvCodecName) {
5913*77c1e3ccSAndroid Build Coastguard Worker const long status =
5914*77c1e3ccSAndroid Build Coastguard Worker UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
5915*77c1e3ccSAndroid Build Coastguard Worker
5916*77c1e3ccSAndroid Build Coastguard Worker if (status)
5917*77c1e3ccSAndroid Build Coastguard Worker return status;
5918*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvCodecDelay) {
5919*77c1e3ccSAndroid Build Coastguard Worker info.codecDelay = UnserializeUInt(pReader, pos, size);
5920*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvSeekPreRoll) {
5921*77c1e3ccSAndroid Build Coastguard Worker info.seekPreRoll = UnserializeUInt(pReader, pos, size);
5922*77c1e3ccSAndroid Build Coastguard Worker }
5923*77c1e3ccSAndroid Build Coastguard Worker
5924*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
5925*77c1e3ccSAndroid Build Coastguard Worker if (pos > track_stop)
5926*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5927*77c1e3ccSAndroid Build Coastguard Worker }
5928*77c1e3ccSAndroid Build Coastguard Worker
5929*77c1e3ccSAndroid Build Coastguard Worker if (pos != track_stop)
5930*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5931*77c1e3ccSAndroid Build Coastguard Worker
5932*77c1e3ccSAndroid Build Coastguard Worker if (info.number <= 0) // not specified
5933*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5934*77c1e3ccSAndroid Build Coastguard Worker
5935*77c1e3ccSAndroid Build Coastguard Worker if (GetTrackByNumber(info.number))
5936*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5937*77c1e3ccSAndroid Build Coastguard Worker
5938*77c1e3ccSAndroid Build Coastguard Worker if (info.type <= 0) // not specified
5939*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5940*77c1e3ccSAndroid Build Coastguard Worker
5941*77c1e3ccSAndroid Build Coastguard Worker info.lacing = (lacing > 0) ? true : false;
5942*77c1e3ccSAndroid Build Coastguard Worker
5943*77c1e3ccSAndroid Build Coastguard Worker if (info.type == Track::kVideo) {
5944*77c1e3ccSAndroid Build Coastguard Worker if (v.start < 0)
5945*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5946*77c1e3ccSAndroid Build Coastguard Worker
5947*77c1e3ccSAndroid Build Coastguard Worker if (a.start >= 0)
5948*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5949*77c1e3ccSAndroid Build Coastguard Worker
5950*77c1e3ccSAndroid Build Coastguard Worker info.settings = v;
5951*77c1e3ccSAndroid Build Coastguard Worker
5952*77c1e3ccSAndroid Build Coastguard Worker VideoTrack* pTrack = NULL;
5953*77c1e3ccSAndroid Build Coastguard Worker
5954*77c1e3ccSAndroid Build Coastguard Worker const long status = VideoTrack::Parse(m_pSegment, info, element_start,
5955*77c1e3ccSAndroid Build Coastguard Worker element_size, pTrack);
5956*77c1e3ccSAndroid Build Coastguard Worker
5957*77c1e3ccSAndroid Build Coastguard Worker if (status)
5958*77c1e3ccSAndroid Build Coastguard Worker return status;
5959*77c1e3ccSAndroid Build Coastguard Worker
5960*77c1e3ccSAndroid Build Coastguard Worker pResult = pTrack;
5961*77c1e3ccSAndroid Build Coastguard Worker assert(pResult);
5962*77c1e3ccSAndroid Build Coastguard Worker
5963*77c1e3ccSAndroid Build Coastguard Worker if (e.start >= 0)
5964*77c1e3ccSAndroid Build Coastguard Worker pResult->ParseContentEncodingsEntry(e.start, e.size);
5965*77c1e3ccSAndroid Build Coastguard Worker } else if (info.type == Track::kAudio) {
5966*77c1e3ccSAndroid Build Coastguard Worker if (a.start < 0)
5967*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5968*77c1e3ccSAndroid Build Coastguard Worker
5969*77c1e3ccSAndroid Build Coastguard Worker if (v.start >= 0)
5970*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5971*77c1e3ccSAndroid Build Coastguard Worker
5972*77c1e3ccSAndroid Build Coastguard Worker info.settings = a;
5973*77c1e3ccSAndroid Build Coastguard Worker
5974*77c1e3ccSAndroid Build Coastguard Worker AudioTrack* pTrack = NULL;
5975*77c1e3ccSAndroid Build Coastguard Worker
5976*77c1e3ccSAndroid Build Coastguard Worker const long status = AudioTrack::Parse(m_pSegment, info, element_start,
5977*77c1e3ccSAndroid Build Coastguard Worker element_size, pTrack);
5978*77c1e3ccSAndroid Build Coastguard Worker
5979*77c1e3ccSAndroid Build Coastguard Worker if (status)
5980*77c1e3ccSAndroid Build Coastguard Worker return status;
5981*77c1e3ccSAndroid Build Coastguard Worker
5982*77c1e3ccSAndroid Build Coastguard Worker pResult = pTrack;
5983*77c1e3ccSAndroid Build Coastguard Worker assert(pResult);
5984*77c1e3ccSAndroid Build Coastguard Worker
5985*77c1e3ccSAndroid Build Coastguard Worker if (e.start >= 0)
5986*77c1e3ccSAndroid Build Coastguard Worker pResult->ParseContentEncodingsEntry(e.start, e.size);
5987*77c1e3ccSAndroid Build Coastguard Worker } else {
5988*77c1e3ccSAndroid Build Coastguard Worker // neither video nor audio - probably metadata or subtitles
5989*77c1e3ccSAndroid Build Coastguard Worker
5990*77c1e3ccSAndroid Build Coastguard Worker if (a.start >= 0)
5991*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5992*77c1e3ccSAndroid Build Coastguard Worker
5993*77c1e3ccSAndroid Build Coastguard Worker if (v.start >= 0)
5994*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5995*77c1e3ccSAndroid Build Coastguard Worker
5996*77c1e3ccSAndroid Build Coastguard Worker if (info.type == Track::kMetadata && e.start >= 0)
5997*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
5998*77c1e3ccSAndroid Build Coastguard Worker
5999*77c1e3ccSAndroid Build Coastguard Worker info.settings.start = -1;
6000*77c1e3ccSAndroid Build Coastguard Worker info.settings.size = 0;
6001*77c1e3ccSAndroid Build Coastguard Worker
6002*77c1e3ccSAndroid Build Coastguard Worker Track* pTrack = NULL;
6003*77c1e3ccSAndroid Build Coastguard Worker
6004*77c1e3ccSAndroid Build Coastguard Worker const long status =
6005*77c1e3ccSAndroid Build Coastguard Worker Track::Create(m_pSegment, info, element_start, element_size, pTrack);
6006*77c1e3ccSAndroid Build Coastguard Worker
6007*77c1e3ccSAndroid Build Coastguard Worker if (status)
6008*77c1e3ccSAndroid Build Coastguard Worker return status;
6009*77c1e3ccSAndroid Build Coastguard Worker
6010*77c1e3ccSAndroid Build Coastguard Worker pResult = pTrack;
6011*77c1e3ccSAndroid Build Coastguard Worker assert(pResult);
6012*77c1e3ccSAndroid Build Coastguard Worker }
6013*77c1e3ccSAndroid Build Coastguard Worker
6014*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
6015*77c1e3ccSAndroid Build Coastguard Worker }
6016*77c1e3ccSAndroid Build Coastguard Worker
~Tracks()6017*77c1e3ccSAndroid Build Coastguard Worker Tracks::~Tracks() {
6018*77c1e3ccSAndroid Build Coastguard Worker Track** i = m_trackEntries;
6019*77c1e3ccSAndroid Build Coastguard Worker Track** const j = m_trackEntriesEnd;
6020*77c1e3ccSAndroid Build Coastguard Worker
6021*77c1e3ccSAndroid Build Coastguard Worker while (i != j) {
6022*77c1e3ccSAndroid Build Coastguard Worker Track* const pTrack = *i++;
6023*77c1e3ccSAndroid Build Coastguard Worker delete pTrack;
6024*77c1e3ccSAndroid Build Coastguard Worker }
6025*77c1e3ccSAndroid Build Coastguard Worker
6026*77c1e3ccSAndroid Build Coastguard Worker delete[] m_trackEntries;
6027*77c1e3ccSAndroid Build Coastguard Worker }
6028*77c1e3ccSAndroid Build Coastguard Worker
GetTrackByNumber(long tn) const6029*77c1e3ccSAndroid Build Coastguard Worker const Track* Tracks::GetTrackByNumber(long tn) const {
6030*77c1e3ccSAndroid Build Coastguard Worker if (tn < 0)
6031*77c1e3ccSAndroid Build Coastguard Worker return NULL;
6032*77c1e3ccSAndroid Build Coastguard Worker
6033*77c1e3ccSAndroid Build Coastguard Worker Track** i = m_trackEntries;
6034*77c1e3ccSAndroid Build Coastguard Worker Track** const j = m_trackEntriesEnd;
6035*77c1e3ccSAndroid Build Coastguard Worker
6036*77c1e3ccSAndroid Build Coastguard Worker while (i != j) {
6037*77c1e3ccSAndroid Build Coastguard Worker Track* const pTrack = *i++;
6038*77c1e3ccSAndroid Build Coastguard Worker
6039*77c1e3ccSAndroid Build Coastguard Worker if (pTrack == NULL)
6040*77c1e3ccSAndroid Build Coastguard Worker continue;
6041*77c1e3ccSAndroid Build Coastguard Worker
6042*77c1e3ccSAndroid Build Coastguard Worker if (tn == pTrack->GetNumber())
6043*77c1e3ccSAndroid Build Coastguard Worker return pTrack;
6044*77c1e3ccSAndroid Build Coastguard Worker }
6045*77c1e3ccSAndroid Build Coastguard Worker
6046*77c1e3ccSAndroid Build Coastguard Worker return NULL; // not found
6047*77c1e3ccSAndroid Build Coastguard Worker }
6048*77c1e3ccSAndroid Build Coastguard Worker
GetTrackByIndex(unsigned long idx) const6049*77c1e3ccSAndroid Build Coastguard Worker const Track* Tracks::GetTrackByIndex(unsigned long idx) const {
6050*77c1e3ccSAndroid Build Coastguard Worker const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
6051*77c1e3ccSAndroid Build Coastguard Worker
6052*77c1e3ccSAndroid Build Coastguard Worker if (idx >= static_cast<unsigned long>(count))
6053*77c1e3ccSAndroid Build Coastguard Worker return NULL;
6054*77c1e3ccSAndroid Build Coastguard Worker
6055*77c1e3ccSAndroid Build Coastguard Worker return m_trackEntries[idx];
6056*77c1e3ccSAndroid Build Coastguard Worker }
6057*77c1e3ccSAndroid Build Coastguard Worker
Load(long long & pos,long & len) const6058*77c1e3ccSAndroid Build Coastguard Worker long Cluster::Load(long long& pos, long& len) const {
6059*77c1e3ccSAndroid Build Coastguard Worker if (m_pSegment == NULL)
6060*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
6061*77c1e3ccSAndroid Build Coastguard Worker
6062*77c1e3ccSAndroid Build Coastguard Worker if (m_timecode >= 0) // at least partially loaded
6063*77c1e3ccSAndroid Build Coastguard Worker return 0;
6064*77c1e3ccSAndroid Build Coastguard Worker
6065*77c1e3ccSAndroid Build Coastguard Worker if (m_pos != m_element_start || m_element_size >= 0)
6066*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
6067*77c1e3ccSAndroid Build Coastguard Worker
6068*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
6069*77c1e3ccSAndroid Build Coastguard Worker long long total, avail;
6070*77c1e3ccSAndroid Build Coastguard Worker const int status = pReader->Length(&total, &avail);
6071*77c1e3ccSAndroid Build Coastguard Worker
6072*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
6073*77c1e3ccSAndroid Build Coastguard Worker return status;
6074*77c1e3ccSAndroid Build Coastguard Worker
6075*77c1e3ccSAndroid Build Coastguard Worker if (total >= 0 && (avail > total || m_pos > total))
6076*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6077*77c1e3ccSAndroid Build Coastguard Worker
6078*77c1e3ccSAndroid Build Coastguard Worker pos = m_pos;
6079*77c1e3ccSAndroid Build Coastguard Worker
6080*77c1e3ccSAndroid Build Coastguard Worker long long cluster_size = -1;
6081*77c1e3ccSAndroid Build Coastguard Worker
6082*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6083*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6084*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6085*77c1e3ccSAndroid Build Coastguard Worker }
6086*77c1e3ccSAndroid Build Coastguard Worker
6087*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(pReader, pos, len);
6088*77c1e3ccSAndroid Build Coastguard Worker
6089*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error or underflow
6090*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6091*77c1e3ccSAndroid Build Coastguard Worker
6092*77c1e3ccSAndroid Build Coastguard Worker if (result > 0)
6093*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6094*77c1e3ccSAndroid Build Coastguard Worker
6095*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6096*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6097*77c1e3ccSAndroid Build Coastguard Worker
6098*77c1e3ccSAndroid Build Coastguard Worker const long long id_ = ReadID(pReader, pos, len);
6099*77c1e3ccSAndroid Build Coastguard Worker
6100*77c1e3ccSAndroid Build Coastguard Worker if (id_ < 0) // error
6101*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(id_);
6102*77c1e3ccSAndroid Build Coastguard Worker
6103*77c1e3ccSAndroid Build Coastguard Worker if (id_ != libwebm::kMkvCluster)
6104*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6105*77c1e3ccSAndroid Build Coastguard Worker
6106*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume id
6107*77c1e3ccSAndroid Build Coastguard Worker
6108*77c1e3ccSAndroid Build Coastguard Worker // read cluster size
6109*77c1e3ccSAndroid Build Coastguard Worker
6110*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6111*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6112*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6113*77c1e3ccSAndroid Build Coastguard Worker }
6114*77c1e3ccSAndroid Build Coastguard Worker
6115*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(pReader, pos, len);
6116*77c1e3ccSAndroid Build Coastguard Worker
6117*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6118*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6119*77c1e3ccSAndroid Build Coastguard Worker
6120*77c1e3ccSAndroid Build Coastguard Worker if (result > 0)
6121*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6122*77c1e3ccSAndroid Build Coastguard Worker
6123*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6124*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6125*77c1e3ccSAndroid Build Coastguard Worker
6126*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
6127*77c1e3ccSAndroid Build Coastguard Worker
6128*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
6129*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(cluster_size);
6130*77c1e3ccSAndroid Build Coastguard Worker
6131*77c1e3ccSAndroid Build Coastguard Worker if (size == 0)
6132*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6133*77c1e3ccSAndroid Build Coastguard Worker
6134*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of element
6135*77c1e3ccSAndroid Build Coastguard Worker
6136*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
6137*77c1e3ccSAndroid Build Coastguard Worker
6138*77c1e3ccSAndroid Build Coastguard Worker if (size != unknown_size)
6139*77c1e3ccSAndroid Build Coastguard Worker cluster_size = size;
6140*77c1e3ccSAndroid Build Coastguard Worker
6141*77c1e3ccSAndroid Build Coastguard Worker // pos points to start of payload
6142*77c1e3ccSAndroid Build Coastguard Worker long long timecode = -1;
6143*77c1e3ccSAndroid Build Coastguard Worker long long new_pos = -1;
6144*77c1e3ccSAndroid Build Coastguard Worker bool bBlock = false;
6145*77c1e3ccSAndroid Build Coastguard Worker
6146*77c1e3ccSAndroid Build Coastguard Worker long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size;
6147*77c1e3ccSAndroid Build Coastguard Worker
6148*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
6149*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && (pos >= cluster_stop))
6150*77c1e3ccSAndroid Build Coastguard Worker break;
6151*77c1e3ccSAndroid Build Coastguard Worker
6152*77c1e3ccSAndroid Build Coastguard Worker // Parse ID
6153*77c1e3ccSAndroid Build Coastguard Worker
6154*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6155*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6156*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6157*77c1e3ccSAndroid Build Coastguard Worker }
6158*77c1e3ccSAndroid Build Coastguard Worker
6159*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(pReader, pos, len);
6160*77c1e3ccSAndroid Build Coastguard Worker
6161*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6162*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6163*77c1e3ccSAndroid Build Coastguard Worker
6164*77c1e3ccSAndroid Build Coastguard Worker if (result > 0)
6165*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6166*77c1e3ccSAndroid Build Coastguard Worker
6167*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6168*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6169*77c1e3ccSAndroid Build Coastguard Worker
6170*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6171*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6172*77c1e3ccSAndroid Build Coastguard Worker
6173*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
6174*77c1e3ccSAndroid Build Coastguard Worker
6175*77c1e3ccSAndroid Build Coastguard Worker if (id < 0) // error
6176*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(id);
6177*77c1e3ccSAndroid Build Coastguard Worker
6178*77c1e3ccSAndroid Build Coastguard Worker if (id == 0)
6179*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6180*77c1e3ccSAndroid Build Coastguard Worker
6181*77c1e3ccSAndroid Build Coastguard Worker // This is the distinguished set of ID's we use to determine
6182*77c1e3ccSAndroid Build Coastguard Worker // that we have exhausted the sub-element's inside the cluster
6183*77c1e3ccSAndroid Build Coastguard Worker // whose ID we parsed earlier.
6184*77c1e3ccSAndroid Build Coastguard Worker
6185*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCluster)
6186*77c1e3ccSAndroid Build Coastguard Worker break;
6187*77c1e3ccSAndroid Build Coastguard Worker
6188*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCues)
6189*77c1e3ccSAndroid Build Coastguard Worker break;
6190*77c1e3ccSAndroid Build Coastguard Worker
6191*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID field
6192*77c1e3ccSAndroid Build Coastguard Worker
6193*77c1e3ccSAndroid Build Coastguard Worker // Parse Size
6194*77c1e3ccSAndroid Build Coastguard Worker
6195*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6196*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6197*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6198*77c1e3ccSAndroid Build Coastguard Worker }
6199*77c1e3ccSAndroid Build Coastguard Worker
6200*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(pReader, pos, len);
6201*77c1e3ccSAndroid Build Coastguard Worker
6202*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6203*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6204*77c1e3ccSAndroid Build Coastguard Worker
6205*77c1e3ccSAndroid Build Coastguard Worker if (result > 0)
6206*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6207*77c1e3ccSAndroid Build Coastguard Worker
6208*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6209*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6210*77c1e3ccSAndroid Build Coastguard Worker
6211*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6212*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6213*77c1e3ccSAndroid Build Coastguard Worker
6214*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
6215*77c1e3ccSAndroid Build Coastguard Worker
6216*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
6217*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(size);
6218*77c1e3ccSAndroid Build Coastguard Worker
6219*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
6220*77c1e3ccSAndroid Build Coastguard Worker
6221*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size)
6222*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6223*77c1e3ccSAndroid Build Coastguard Worker
6224*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size field
6225*77c1e3ccSAndroid Build Coastguard Worker
6226*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && (pos > cluster_stop))
6227*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6228*77c1e3ccSAndroid Build Coastguard Worker
6229*77c1e3ccSAndroid Build Coastguard Worker // pos now points to start of payload
6230*77c1e3ccSAndroid Build Coastguard Worker
6231*77c1e3ccSAndroid Build Coastguard Worker if (size == 0)
6232*77c1e3ccSAndroid Build Coastguard Worker continue;
6233*77c1e3ccSAndroid Build Coastguard Worker
6234*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
6235*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6236*77c1e3ccSAndroid Build Coastguard Worker
6237*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvTimecode) {
6238*77c1e3ccSAndroid Build Coastguard Worker len = static_cast<long>(size);
6239*77c1e3ccSAndroid Build Coastguard Worker
6240*77c1e3ccSAndroid Build Coastguard Worker if ((pos + size) > avail)
6241*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6242*77c1e3ccSAndroid Build Coastguard Worker
6243*77c1e3ccSAndroid Build Coastguard Worker timecode = UnserializeUInt(pReader, pos, size);
6244*77c1e3ccSAndroid Build Coastguard Worker
6245*77c1e3ccSAndroid Build Coastguard Worker if (timecode < 0) // error (or underflow)
6246*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(timecode);
6247*77c1e3ccSAndroid Build Coastguard Worker
6248*77c1e3ccSAndroid Build Coastguard Worker new_pos = pos + size;
6249*77c1e3ccSAndroid Build Coastguard Worker
6250*77c1e3ccSAndroid Build Coastguard Worker if (bBlock)
6251*77c1e3ccSAndroid Build Coastguard Worker break;
6252*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvBlockGroup) {
6253*77c1e3ccSAndroid Build Coastguard Worker bBlock = true;
6254*77c1e3ccSAndroid Build Coastguard Worker break;
6255*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvSimpleBlock) {
6256*77c1e3ccSAndroid Build Coastguard Worker bBlock = true;
6257*77c1e3ccSAndroid Build Coastguard Worker break;
6258*77c1e3ccSAndroid Build Coastguard Worker }
6259*77c1e3ccSAndroid Build Coastguard Worker
6260*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
6261*77c1e3ccSAndroid Build Coastguard Worker if (cluster_stop >= 0 && pos > cluster_stop)
6262*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6263*77c1e3ccSAndroid Build Coastguard Worker }
6264*77c1e3ccSAndroid Build Coastguard Worker
6265*77c1e3ccSAndroid Build Coastguard Worker if (cluster_stop >= 0 && pos > cluster_stop)
6266*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6267*77c1e3ccSAndroid Build Coastguard Worker
6268*77c1e3ccSAndroid Build Coastguard Worker if (timecode < 0) // no timecode found
6269*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6270*77c1e3ccSAndroid Build Coastguard Worker
6271*77c1e3ccSAndroid Build Coastguard Worker if (!bBlock)
6272*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6273*77c1e3ccSAndroid Build Coastguard Worker
6274*77c1e3ccSAndroid Build Coastguard Worker m_pos = new_pos; // designates position just beyond timecode payload
6275*77c1e3ccSAndroid Build Coastguard Worker m_timecode = timecode; // m_timecode >= 0 means we're partially loaded
6276*77c1e3ccSAndroid Build Coastguard Worker
6277*77c1e3ccSAndroid Build Coastguard Worker if (cluster_size >= 0)
6278*77c1e3ccSAndroid Build Coastguard Worker m_element_size = cluster_stop - m_element_start;
6279*77c1e3ccSAndroid Build Coastguard Worker
6280*77c1e3ccSAndroid Build Coastguard Worker return 0;
6281*77c1e3ccSAndroid Build Coastguard Worker }
6282*77c1e3ccSAndroid Build Coastguard Worker
Parse(long long & pos,long & len) const6283*77c1e3ccSAndroid Build Coastguard Worker long Cluster::Parse(long long& pos, long& len) const {
6284*77c1e3ccSAndroid Build Coastguard Worker long status = Load(pos, len);
6285*77c1e3ccSAndroid Build Coastguard Worker
6286*77c1e3ccSAndroid Build Coastguard Worker if (status < 0)
6287*77c1e3ccSAndroid Build Coastguard Worker return status;
6288*77c1e3ccSAndroid Build Coastguard Worker
6289*77c1e3ccSAndroid Build Coastguard Worker if (m_pos < m_element_start || m_timecode < 0)
6290*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
6291*77c1e3ccSAndroid Build Coastguard Worker
6292*77c1e3ccSAndroid Build Coastguard Worker const long long cluster_stop =
6293*77c1e3ccSAndroid Build Coastguard Worker (m_element_size < 0) ? -1 : m_element_start + m_element_size;
6294*77c1e3ccSAndroid Build Coastguard Worker
6295*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && (m_pos >= cluster_stop))
6296*77c1e3ccSAndroid Build Coastguard Worker return 1; // nothing else to do
6297*77c1e3ccSAndroid Build Coastguard Worker
6298*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
6299*77c1e3ccSAndroid Build Coastguard Worker
6300*77c1e3ccSAndroid Build Coastguard Worker long long total, avail;
6301*77c1e3ccSAndroid Build Coastguard Worker
6302*77c1e3ccSAndroid Build Coastguard Worker status = pReader->Length(&total, &avail);
6303*77c1e3ccSAndroid Build Coastguard Worker
6304*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
6305*77c1e3ccSAndroid Build Coastguard Worker return status;
6306*77c1e3ccSAndroid Build Coastguard Worker
6307*77c1e3ccSAndroid Build Coastguard Worker if (total >= 0 && avail > total)
6308*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6309*77c1e3ccSAndroid Build Coastguard Worker
6310*77c1e3ccSAndroid Build Coastguard Worker pos = m_pos;
6311*77c1e3ccSAndroid Build Coastguard Worker
6312*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
6313*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && (pos >= cluster_stop))
6314*77c1e3ccSAndroid Build Coastguard Worker break;
6315*77c1e3ccSAndroid Build Coastguard Worker
6316*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (pos >= total)) {
6317*77c1e3ccSAndroid Build Coastguard Worker if (m_element_size < 0)
6318*77c1e3ccSAndroid Build Coastguard Worker m_element_size = pos - m_element_start;
6319*77c1e3ccSAndroid Build Coastguard Worker
6320*77c1e3ccSAndroid Build Coastguard Worker break;
6321*77c1e3ccSAndroid Build Coastguard Worker }
6322*77c1e3ccSAndroid Build Coastguard Worker
6323*77c1e3ccSAndroid Build Coastguard Worker // Parse ID
6324*77c1e3ccSAndroid Build Coastguard Worker
6325*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6326*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6327*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6328*77c1e3ccSAndroid Build Coastguard Worker }
6329*77c1e3ccSAndroid Build Coastguard Worker
6330*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(pReader, pos, len);
6331*77c1e3ccSAndroid Build Coastguard Worker
6332*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6333*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6334*77c1e3ccSAndroid Build Coastguard Worker
6335*77c1e3ccSAndroid Build Coastguard Worker if (result > 0)
6336*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6337*77c1e3ccSAndroid Build Coastguard Worker
6338*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6339*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6340*77c1e3ccSAndroid Build Coastguard Worker
6341*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6342*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6343*77c1e3ccSAndroid Build Coastguard Worker
6344*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
6345*77c1e3ccSAndroid Build Coastguard Worker
6346*77c1e3ccSAndroid Build Coastguard Worker if (id < 0)
6347*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6348*77c1e3ccSAndroid Build Coastguard Worker
6349*77c1e3ccSAndroid Build Coastguard Worker // This is the distinguished set of ID's we use to determine
6350*77c1e3ccSAndroid Build Coastguard Worker // that we have exhausted the sub-element's inside the cluster
6351*77c1e3ccSAndroid Build Coastguard Worker // whose ID we parsed earlier.
6352*77c1e3ccSAndroid Build Coastguard Worker
6353*77c1e3ccSAndroid Build Coastguard Worker if ((id == libwebm::kMkvCluster) || (id == libwebm::kMkvCues)) {
6354*77c1e3ccSAndroid Build Coastguard Worker if (m_element_size < 0)
6355*77c1e3ccSAndroid Build Coastguard Worker m_element_size = pos - m_element_start;
6356*77c1e3ccSAndroid Build Coastguard Worker
6357*77c1e3ccSAndroid Build Coastguard Worker break;
6358*77c1e3ccSAndroid Build Coastguard Worker }
6359*77c1e3ccSAndroid Build Coastguard Worker
6360*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID field
6361*77c1e3ccSAndroid Build Coastguard Worker
6362*77c1e3ccSAndroid Build Coastguard Worker // Parse Size
6363*77c1e3ccSAndroid Build Coastguard Worker
6364*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6365*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6366*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6367*77c1e3ccSAndroid Build Coastguard Worker }
6368*77c1e3ccSAndroid Build Coastguard Worker
6369*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(pReader, pos, len);
6370*77c1e3ccSAndroid Build Coastguard Worker
6371*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6372*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6373*77c1e3ccSAndroid Build Coastguard Worker
6374*77c1e3ccSAndroid Build Coastguard Worker if (result > 0)
6375*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6376*77c1e3ccSAndroid Build Coastguard Worker
6377*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6378*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6379*77c1e3ccSAndroid Build Coastguard Worker
6380*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6381*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6382*77c1e3ccSAndroid Build Coastguard Worker
6383*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
6384*77c1e3ccSAndroid Build Coastguard Worker
6385*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
6386*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(size);
6387*77c1e3ccSAndroid Build Coastguard Worker
6388*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
6389*77c1e3ccSAndroid Build Coastguard Worker
6390*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size)
6391*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6392*77c1e3ccSAndroid Build Coastguard Worker
6393*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size field
6394*77c1e3ccSAndroid Build Coastguard Worker
6395*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && (pos > cluster_stop))
6396*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6397*77c1e3ccSAndroid Build Coastguard Worker
6398*77c1e3ccSAndroid Build Coastguard Worker // pos now points to start of payload
6399*77c1e3ccSAndroid Build Coastguard Worker
6400*77c1e3ccSAndroid Build Coastguard Worker if (size == 0)
6401*77c1e3ccSAndroid Build Coastguard Worker continue;
6402*77c1e3ccSAndroid Build Coastguard Worker
6403*77c1e3ccSAndroid Build Coastguard Worker // const long long block_start = pos;
6404*77c1e3ccSAndroid Build Coastguard Worker const long long block_stop = pos + size;
6405*77c1e3ccSAndroid Build Coastguard Worker
6406*77c1e3ccSAndroid Build Coastguard Worker if (cluster_stop >= 0) {
6407*77c1e3ccSAndroid Build Coastguard Worker if (block_stop > cluster_stop) {
6408*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvBlockGroup || id == libwebm::kMkvSimpleBlock) {
6409*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6410*77c1e3ccSAndroid Build Coastguard Worker }
6411*77c1e3ccSAndroid Build Coastguard Worker
6412*77c1e3ccSAndroid Build Coastguard Worker pos = cluster_stop;
6413*77c1e3ccSAndroid Build Coastguard Worker break;
6414*77c1e3ccSAndroid Build Coastguard Worker }
6415*77c1e3ccSAndroid Build Coastguard Worker } else if ((total >= 0) && (block_stop > total)) {
6416*77c1e3ccSAndroid Build Coastguard Worker m_element_size = total - m_element_start;
6417*77c1e3ccSAndroid Build Coastguard Worker pos = total;
6418*77c1e3ccSAndroid Build Coastguard Worker break;
6419*77c1e3ccSAndroid Build Coastguard Worker } else if (block_stop > avail) {
6420*77c1e3ccSAndroid Build Coastguard Worker len = static_cast<long>(size);
6421*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6422*77c1e3ccSAndroid Build Coastguard Worker }
6423*77c1e3ccSAndroid Build Coastguard Worker
6424*77c1e3ccSAndroid Build Coastguard Worker Cluster* const this_ = const_cast<Cluster*>(this);
6425*77c1e3ccSAndroid Build Coastguard Worker
6426*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvBlockGroup)
6427*77c1e3ccSAndroid Build Coastguard Worker return this_->ParseBlockGroup(size, pos, len);
6428*77c1e3ccSAndroid Build Coastguard Worker
6429*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvSimpleBlock)
6430*77c1e3ccSAndroid Build Coastguard Worker return this_->ParseSimpleBlock(size, pos, len);
6431*77c1e3ccSAndroid Build Coastguard Worker
6432*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
6433*77c1e3ccSAndroid Build Coastguard Worker if (cluster_stop >= 0 && pos > cluster_stop)
6434*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6435*77c1e3ccSAndroid Build Coastguard Worker }
6436*77c1e3ccSAndroid Build Coastguard Worker
6437*77c1e3ccSAndroid Build Coastguard Worker if (m_element_size < 1)
6438*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6439*77c1e3ccSAndroid Build Coastguard Worker
6440*77c1e3ccSAndroid Build Coastguard Worker m_pos = pos;
6441*77c1e3ccSAndroid Build Coastguard Worker if (cluster_stop >= 0 && m_pos > cluster_stop)
6442*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6443*77c1e3ccSAndroid Build Coastguard Worker
6444*77c1e3ccSAndroid Build Coastguard Worker if (m_entries_count > 0) {
6445*77c1e3ccSAndroid Build Coastguard Worker const long idx = m_entries_count - 1;
6446*77c1e3ccSAndroid Build Coastguard Worker
6447*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* const pLast = m_entries[idx];
6448*77c1e3ccSAndroid Build Coastguard Worker if (pLast == NULL)
6449*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
6450*77c1e3ccSAndroid Build Coastguard Worker
6451*77c1e3ccSAndroid Build Coastguard Worker const Block* const pBlock = pLast->GetBlock();
6452*77c1e3ccSAndroid Build Coastguard Worker if (pBlock == NULL)
6453*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
6454*77c1e3ccSAndroid Build Coastguard Worker
6455*77c1e3ccSAndroid Build Coastguard Worker const long long start = pBlock->m_start;
6456*77c1e3ccSAndroid Build Coastguard Worker
6457*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (start > total))
6458*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED; // defend against trucated stream
6459*77c1e3ccSAndroid Build Coastguard Worker
6460*77c1e3ccSAndroid Build Coastguard Worker const long long size = pBlock->m_size;
6461*77c1e3ccSAndroid Build Coastguard Worker
6462*77c1e3ccSAndroid Build Coastguard Worker const long long stop = start + size;
6463*77c1e3ccSAndroid Build Coastguard Worker if (cluster_stop >= 0 && stop > cluster_stop)
6464*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6465*77c1e3ccSAndroid Build Coastguard Worker
6466*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (stop > total))
6467*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED; // defend against trucated stream
6468*77c1e3ccSAndroid Build Coastguard Worker }
6469*77c1e3ccSAndroid Build Coastguard Worker
6470*77c1e3ccSAndroid Build Coastguard Worker return 1; // no more entries
6471*77c1e3ccSAndroid Build Coastguard Worker }
6472*77c1e3ccSAndroid Build Coastguard Worker
ParseSimpleBlock(long long block_size,long long & pos,long & len)6473*77c1e3ccSAndroid Build Coastguard Worker long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
6474*77c1e3ccSAndroid Build Coastguard Worker long& len) {
6475*77c1e3ccSAndroid Build Coastguard Worker const long long block_start = pos;
6476*77c1e3ccSAndroid Build Coastguard Worker const long long block_stop = pos + block_size;
6477*77c1e3ccSAndroid Build Coastguard Worker
6478*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
6479*77c1e3ccSAndroid Build Coastguard Worker
6480*77c1e3ccSAndroid Build Coastguard Worker long long total, avail;
6481*77c1e3ccSAndroid Build Coastguard Worker
6482*77c1e3ccSAndroid Build Coastguard Worker long status = pReader->Length(&total, &avail);
6483*77c1e3ccSAndroid Build Coastguard Worker
6484*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
6485*77c1e3ccSAndroid Build Coastguard Worker return status;
6486*77c1e3ccSAndroid Build Coastguard Worker
6487*77c1e3ccSAndroid Build Coastguard Worker assert((total < 0) || (avail <= total));
6488*77c1e3ccSAndroid Build Coastguard Worker
6489*77c1e3ccSAndroid Build Coastguard Worker // parse track number
6490*77c1e3ccSAndroid Build Coastguard Worker
6491*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6492*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6493*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6494*77c1e3ccSAndroid Build Coastguard Worker }
6495*77c1e3ccSAndroid Build Coastguard Worker
6496*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(pReader, pos, len);
6497*77c1e3ccSAndroid Build Coastguard Worker
6498*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6499*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6500*77c1e3ccSAndroid Build Coastguard Worker
6501*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
6502*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6503*77c1e3ccSAndroid Build Coastguard Worker
6504*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > block_stop)
6505*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6506*77c1e3ccSAndroid Build Coastguard Worker
6507*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6508*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6509*77c1e3ccSAndroid Build Coastguard Worker
6510*77c1e3ccSAndroid Build Coastguard Worker const long long track = ReadUInt(pReader, pos, len);
6511*77c1e3ccSAndroid Build Coastguard Worker
6512*77c1e3ccSAndroid Build Coastguard Worker if (track < 0) // error
6513*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(track);
6514*77c1e3ccSAndroid Build Coastguard Worker
6515*77c1e3ccSAndroid Build Coastguard Worker if (track == 0)
6516*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6517*77c1e3ccSAndroid Build Coastguard Worker
6518*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume track number
6519*77c1e3ccSAndroid Build Coastguard Worker
6520*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 2) > block_stop)
6521*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6522*77c1e3ccSAndroid Build Coastguard Worker
6523*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 2) > avail) {
6524*77c1e3ccSAndroid Build Coastguard Worker len = 2;
6525*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6526*77c1e3ccSAndroid Build Coastguard Worker }
6527*77c1e3ccSAndroid Build Coastguard Worker
6528*77c1e3ccSAndroid Build Coastguard Worker pos += 2; // consume timecode
6529*77c1e3ccSAndroid Build Coastguard Worker
6530*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > block_stop)
6531*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6532*77c1e3ccSAndroid Build Coastguard Worker
6533*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6534*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6535*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6536*77c1e3ccSAndroid Build Coastguard Worker }
6537*77c1e3ccSAndroid Build Coastguard Worker
6538*77c1e3ccSAndroid Build Coastguard Worker unsigned char flags;
6539*77c1e3ccSAndroid Build Coastguard Worker
6540*77c1e3ccSAndroid Build Coastguard Worker status = pReader->Read(pos, 1, &flags);
6541*77c1e3ccSAndroid Build Coastguard Worker
6542*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) { // error or underflow
6543*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6544*77c1e3ccSAndroid Build Coastguard Worker return status;
6545*77c1e3ccSAndroid Build Coastguard Worker }
6546*77c1e3ccSAndroid Build Coastguard Worker
6547*77c1e3ccSAndroid Build Coastguard Worker ++pos; // consume flags byte
6548*77c1e3ccSAndroid Build Coastguard Worker assert(pos <= avail);
6549*77c1e3ccSAndroid Build Coastguard Worker
6550*77c1e3ccSAndroid Build Coastguard Worker if (pos >= block_stop)
6551*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6552*77c1e3ccSAndroid Build Coastguard Worker
6553*77c1e3ccSAndroid Build Coastguard Worker const int lacing = int(flags & 0x06) >> 1;
6554*77c1e3ccSAndroid Build Coastguard Worker
6555*77c1e3ccSAndroid Build Coastguard Worker if ((lacing != 0) && (block_stop > avail)) {
6556*77c1e3ccSAndroid Build Coastguard Worker len = static_cast<long>(block_stop - pos);
6557*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6558*77c1e3ccSAndroid Build Coastguard Worker }
6559*77c1e3ccSAndroid Build Coastguard Worker
6560*77c1e3ccSAndroid Build Coastguard Worker status = CreateBlock(libwebm::kMkvSimpleBlock, block_start, block_size,
6561*77c1e3ccSAndroid Build Coastguard Worker 0); // DiscardPadding
6562*77c1e3ccSAndroid Build Coastguard Worker
6563*77c1e3ccSAndroid Build Coastguard Worker if (status != 0)
6564*77c1e3ccSAndroid Build Coastguard Worker return status;
6565*77c1e3ccSAndroid Build Coastguard Worker
6566*77c1e3ccSAndroid Build Coastguard Worker m_pos = block_stop;
6567*77c1e3ccSAndroid Build Coastguard Worker
6568*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
6569*77c1e3ccSAndroid Build Coastguard Worker }
6570*77c1e3ccSAndroid Build Coastguard Worker
ParseBlockGroup(long long payload_size,long long & pos,long & len)6571*77c1e3ccSAndroid Build Coastguard Worker long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
6572*77c1e3ccSAndroid Build Coastguard Worker long& len) {
6573*77c1e3ccSAndroid Build Coastguard Worker const long long payload_start = pos;
6574*77c1e3ccSAndroid Build Coastguard Worker const long long payload_stop = pos + payload_size;
6575*77c1e3ccSAndroid Build Coastguard Worker
6576*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
6577*77c1e3ccSAndroid Build Coastguard Worker
6578*77c1e3ccSAndroid Build Coastguard Worker long long total, avail;
6579*77c1e3ccSAndroid Build Coastguard Worker
6580*77c1e3ccSAndroid Build Coastguard Worker long status = pReader->Length(&total, &avail);
6581*77c1e3ccSAndroid Build Coastguard Worker
6582*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
6583*77c1e3ccSAndroid Build Coastguard Worker return status;
6584*77c1e3ccSAndroid Build Coastguard Worker
6585*77c1e3ccSAndroid Build Coastguard Worker assert((total < 0) || (avail <= total));
6586*77c1e3ccSAndroid Build Coastguard Worker
6587*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (payload_stop > total))
6588*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6589*77c1e3ccSAndroid Build Coastguard Worker
6590*77c1e3ccSAndroid Build Coastguard Worker if (payload_stop > avail) {
6591*77c1e3ccSAndroid Build Coastguard Worker len = static_cast<long>(payload_size);
6592*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6593*77c1e3ccSAndroid Build Coastguard Worker }
6594*77c1e3ccSAndroid Build Coastguard Worker
6595*77c1e3ccSAndroid Build Coastguard Worker long long discard_padding = 0;
6596*77c1e3ccSAndroid Build Coastguard Worker
6597*77c1e3ccSAndroid Build Coastguard Worker while (pos < payload_stop) {
6598*77c1e3ccSAndroid Build Coastguard Worker // parse sub-block element ID
6599*77c1e3ccSAndroid Build Coastguard Worker
6600*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6601*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6602*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6603*77c1e3ccSAndroid Build Coastguard Worker }
6604*77c1e3ccSAndroid Build Coastguard Worker
6605*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(pReader, pos, len);
6606*77c1e3ccSAndroid Build Coastguard Worker
6607*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6608*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6609*77c1e3ccSAndroid Build Coastguard Worker
6610*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
6611*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6612*77c1e3ccSAndroid Build Coastguard Worker
6613*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > payload_stop)
6614*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6615*77c1e3ccSAndroid Build Coastguard Worker
6616*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6617*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6618*77c1e3ccSAndroid Build Coastguard Worker
6619*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
6620*77c1e3ccSAndroid Build Coastguard Worker
6621*77c1e3ccSAndroid Build Coastguard Worker if (id < 0) // error
6622*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(id);
6623*77c1e3ccSAndroid Build Coastguard Worker
6624*77c1e3ccSAndroid Build Coastguard Worker if (id == 0) // not a valid ID
6625*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6626*77c1e3ccSAndroid Build Coastguard Worker
6627*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID field
6628*77c1e3ccSAndroid Build Coastguard Worker
6629*77c1e3ccSAndroid Build Coastguard Worker // Parse Size
6630*77c1e3ccSAndroid Build Coastguard Worker
6631*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6632*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6633*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6634*77c1e3ccSAndroid Build Coastguard Worker }
6635*77c1e3ccSAndroid Build Coastguard Worker
6636*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(pReader, pos, len);
6637*77c1e3ccSAndroid Build Coastguard Worker
6638*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6639*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6640*77c1e3ccSAndroid Build Coastguard Worker
6641*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
6642*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6643*77c1e3ccSAndroid Build Coastguard Worker
6644*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > payload_stop)
6645*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6646*77c1e3ccSAndroid Build Coastguard Worker
6647*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6648*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6649*77c1e3ccSAndroid Build Coastguard Worker
6650*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
6651*77c1e3ccSAndroid Build Coastguard Worker
6652*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
6653*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(size);
6654*77c1e3ccSAndroid Build Coastguard Worker
6655*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size field
6656*77c1e3ccSAndroid Build Coastguard Worker
6657*77c1e3ccSAndroid Build Coastguard Worker // pos now points to start of sub-block group payload
6658*77c1e3ccSAndroid Build Coastguard Worker
6659*77c1e3ccSAndroid Build Coastguard Worker if (pos > payload_stop)
6660*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6661*77c1e3ccSAndroid Build Coastguard Worker
6662*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // weird
6663*77c1e3ccSAndroid Build Coastguard Worker continue;
6664*77c1e3ccSAndroid Build Coastguard Worker
6665*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
6666*77c1e3ccSAndroid Build Coastguard Worker
6667*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size)
6668*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6669*77c1e3ccSAndroid Build Coastguard Worker
6670*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvDiscardPadding) {
6671*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeInt(pReader, pos, size, discard_padding);
6672*77c1e3ccSAndroid Build Coastguard Worker
6673*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
6674*77c1e3ccSAndroid Build Coastguard Worker return status;
6675*77c1e3ccSAndroid Build Coastguard Worker }
6676*77c1e3ccSAndroid Build Coastguard Worker
6677*77c1e3ccSAndroid Build Coastguard Worker if (id != libwebm::kMkvBlock) {
6678*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume sub-part of block group
6679*77c1e3ccSAndroid Build Coastguard Worker
6680*77c1e3ccSAndroid Build Coastguard Worker if (pos > payload_stop)
6681*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6682*77c1e3ccSAndroid Build Coastguard Worker
6683*77c1e3ccSAndroid Build Coastguard Worker continue;
6684*77c1e3ccSAndroid Build Coastguard Worker }
6685*77c1e3ccSAndroid Build Coastguard Worker
6686*77c1e3ccSAndroid Build Coastguard Worker const long long block_stop = pos + size;
6687*77c1e3ccSAndroid Build Coastguard Worker
6688*77c1e3ccSAndroid Build Coastguard Worker if (block_stop > payload_stop)
6689*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6690*77c1e3ccSAndroid Build Coastguard Worker
6691*77c1e3ccSAndroid Build Coastguard Worker // parse track number
6692*77c1e3ccSAndroid Build Coastguard Worker
6693*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6694*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6695*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6696*77c1e3ccSAndroid Build Coastguard Worker }
6697*77c1e3ccSAndroid Build Coastguard Worker
6698*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(pReader, pos, len);
6699*77c1e3ccSAndroid Build Coastguard Worker
6700*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6701*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6702*77c1e3ccSAndroid Build Coastguard Worker
6703*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
6704*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6705*77c1e3ccSAndroid Build Coastguard Worker
6706*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > block_stop)
6707*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6708*77c1e3ccSAndroid Build Coastguard Worker
6709*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6710*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6711*77c1e3ccSAndroid Build Coastguard Worker
6712*77c1e3ccSAndroid Build Coastguard Worker const long long track = ReadUInt(pReader, pos, len);
6713*77c1e3ccSAndroid Build Coastguard Worker
6714*77c1e3ccSAndroid Build Coastguard Worker if (track < 0) // error
6715*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(track);
6716*77c1e3ccSAndroid Build Coastguard Worker
6717*77c1e3ccSAndroid Build Coastguard Worker if (track == 0)
6718*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6719*77c1e3ccSAndroid Build Coastguard Worker
6720*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume track number
6721*77c1e3ccSAndroid Build Coastguard Worker
6722*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 2) > block_stop)
6723*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6724*77c1e3ccSAndroid Build Coastguard Worker
6725*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 2) > avail) {
6726*77c1e3ccSAndroid Build Coastguard Worker len = 2;
6727*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6728*77c1e3ccSAndroid Build Coastguard Worker }
6729*77c1e3ccSAndroid Build Coastguard Worker
6730*77c1e3ccSAndroid Build Coastguard Worker pos += 2; // consume timecode
6731*77c1e3ccSAndroid Build Coastguard Worker
6732*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > block_stop)
6733*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6734*77c1e3ccSAndroid Build Coastguard Worker
6735*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6736*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6737*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6738*77c1e3ccSAndroid Build Coastguard Worker }
6739*77c1e3ccSAndroid Build Coastguard Worker
6740*77c1e3ccSAndroid Build Coastguard Worker unsigned char flags;
6741*77c1e3ccSAndroid Build Coastguard Worker
6742*77c1e3ccSAndroid Build Coastguard Worker status = pReader->Read(pos, 1, &flags);
6743*77c1e3ccSAndroid Build Coastguard Worker
6744*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) { // error or underflow
6745*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6746*77c1e3ccSAndroid Build Coastguard Worker return status;
6747*77c1e3ccSAndroid Build Coastguard Worker }
6748*77c1e3ccSAndroid Build Coastguard Worker
6749*77c1e3ccSAndroid Build Coastguard Worker ++pos; // consume flags byte
6750*77c1e3ccSAndroid Build Coastguard Worker assert(pos <= avail);
6751*77c1e3ccSAndroid Build Coastguard Worker
6752*77c1e3ccSAndroid Build Coastguard Worker if (pos >= block_stop)
6753*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6754*77c1e3ccSAndroid Build Coastguard Worker
6755*77c1e3ccSAndroid Build Coastguard Worker const int lacing = int(flags & 0x06) >> 1;
6756*77c1e3ccSAndroid Build Coastguard Worker
6757*77c1e3ccSAndroid Build Coastguard Worker if ((lacing != 0) && (block_stop > avail)) {
6758*77c1e3ccSAndroid Build Coastguard Worker len = static_cast<long>(block_stop - pos);
6759*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6760*77c1e3ccSAndroid Build Coastguard Worker }
6761*77c1e3ccSAndroid Build Coastguard Worker
6762*77c1e3ccSAndroid Build Coastguard Worker pos = block_stop; // consume block-part of block group
6763*77c1e3ccSAndroid Build Coastguard Worker if (pos > payload_stop)
6764*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6765*77c1e3ccSAndroid Build Coastguard Worker }
6766*77c1e3ccSAndroid Build Coastguard Worker
6767*77c1e3ccSAndroid Build Coastguard Worker if (pos != payload_stop)
6768*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6769*77c1e3ccSAndroid Build Coastguard Worker
6770*77c1e3ccSAndroid Build Coastguard Worker status = CreateBlock(libwebm::kMkvBlockGroup, payload_start, payload_size,
6771*77c1e3ccSAndroid Build Coastguard Worker discard_padding);
6772*77c1e3ccSAndroid Build Coastguard Worker if (status != 0)
6773*77c1e3ccSAndroid Build Coastguard Worker return status;
6774*77c1e3ccSAndroid Build Coastguard Worker
6775*77c1e3ccSAndroid Build Coastguard Worker m_pos = payload_stop;
6776*77c1e3ccSAndroid Build Coastguard Worker
6777*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
6778*77c1e3ccSAndroid Build Coastguard Worker }
6779*77c1e3ccSAndroid Build Coastguard Worker
GetEntry(long index,const mkvparser::BlockEntry * & pEntry) const6780*77c1e3ccSAndroid Build Coastguard Worker long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const {
6781*77c1e3ccSAndroid Build Coastguard Worker assert(m_pos >= m_element_start);
6782*77c1e3ccSAndroid Build Coastguard Worker
6783*77c1e3ccSAndroid Build Coastguard Worker pEntry = NULL;
6784*77c1e3ccSAndroid Build Coastguard Worker
6785*77c1e3ccSAndroid Build Coastguard Worker if (index < 0)
6786*77c1e3ccSAndroid Build Coastguard Worker return -1; // generic error
6787*77c1e3ccSAndroid Build Coastguard Worker
6788*77c1e3ccSAndroid Build Coastguard Worker if (m_entries_count < 0)
6789*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6790*77c1e3ccSAndroid Build Coastguard Worker
6791*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries);
6792*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_size > 0);
6793*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_count <= m_entries_size);
6794*77c1e3ccSAndroid Build Coastguard Worker
6795*77c1e3ccSAndroid Build Coastguard Worker if (index < m_entries_count) {
6796*77c1e3ccSAndroid Build Coastguard Worker pEntry = m_entries[index];
6797*77c1e3ccSAndroid Build Coastguard Worker assert(pEntry);
6798*77c1e3ccSAndroid Build Coastguard Worker
6799*77c1e3ccSAndroid Build Coastguard Worker return 1; // found entry
6800*77c1e3ccSAndroid Build Coastguard Worker }
6801*77c1e3ccSAndroid Build Coastguard Worker
6802*77c1e3ccSAndroid Build Coastguard Worker if (m_element_size < 0) // we don't know cluster end yet
6803*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL; // underflow
6804*77c1e3ccSAndroid Build Coastguard Worker
6805*77c1e3ccSAndroid Build Coastguard Worker const long long element_stop = m_element_start + m_element_size;
6806*77c1e3ccSAndroid Build Coastguard Worker
6807*77c1e3ccSAndroid Build Coastguard Worker if (m_pos >= element_stop)
6808*77c1e3ccSAndroid Build Coastguard Worker return 0; // nothing left to parse
6809*77c1e3ccSAndroid Build Coastguard Worker
6810*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL; // underflow, since more remains to be parsed
6811*77c1e3ccSAndroid Build Coastguard Worker }
6812*77c1e3ccSAndroid Build Coastguard Worker
Create(Segment * pSegment,long idx,long long off)6813*77c1e3ccSAndroid Build Coastguard Worker Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) {
6814*77c1e3ccSAndroid Build Coastguard Worker if (!pSegment || off < 0)
6815*77c1e3ccSAndroid Build Coastguard Worker return NULL;
6816*77c1e3ccSAndroid Build Coastguard Worker
6817*77c1e3ccSAndroid Build Coastguard Worker const long long element_start = pSegment->m_start + off;
6818*77c1e3ccSAndroid Build Coastguard Worker
6819*77c1e3ccSAndroid Build Coastguard Worker Cluster* const pCluster =
6820*77c1e3ccSAndroid Build Coastguard Worker new (std::nothrow) Cluster(pSegment, idx, element_start);
6821*77c1e3ccSAndroid Build Coastguard Worker
6822*77c1e3ccSAndroid Build Coastguard Worker return pCluster;
6823*77c1e3ccSAndroid Build Coastguard Worker }
6824*77c1e3ccSAndroid Build Coastguard Worker
Cluster()6825*77c1e3ccSAndroid Build Coastguard Worker Cluster::Cluster()
6826*77c1e3ccSAndroid Build Coastguard Worker : m_pSegment(NULL),
6827*77c1e3ccSAndroid Build Coastguard Worker m_element_start(0),
6828*77c1e3ccSAndroid Build Coastguard Worker m_index(0),
6829*77c1e3ccSAndroid Build Coastguard Worker m_pos(0),
6830*77c1e3ccSAndroid Build Coastguard Worker m_element_size(0),
6831*77c1e3ccSAndroid Build Coastguard Worker m_timecode(0),
6832*77c1e3ccSAndroid Build Coastguard Worker m_entries(NULL),
6833*77c1e3ccSAndroid Build Coastguard Worker m_entries_size(0),
6834*77c1e3ccSAndroid Build Coastguard Worker m_entries_count(0) // means "no entries"
6835*77c1e3ccSAndroid Build Coastguard Worker {}
6836*77c1e3ccSAndroid Build Coastguard Worker
Cluster(Segment * pSegment,long idx,long long element_start)6837*77c1e3ccSAndroid Build Coastguard Worker Cluster::Cluster(Segment* pSegment, long idx, long long element_start
6838*77c1e3ccSAndroid Build Coastguard Worker /* long long element_size */)
6839*77c1e3ccSAndroid Build Coastguard Worker : m_pSegment(pSegment),
6840*77c1e3ccSAndroid Build Coastguard Worker m_element_start(element_start),
6841*77c1e3ccSAndroid Build Coastguard Worker m_index(idx),
6842*77c1e3ccSAndroid Build Coastguard Worker m_pos(element_start),
6843*77c1e3ccSAndroid Build Coastguard Worker m_element_size(-1 /* element_size */),
6844*77c1e3ccSAndroid Build Coastguard Worker m_timecode(-1),
6845*77c1e3ccSAndroid Build Coastguard Worker m_entries(NULL),
6846*77c1e3ccSAndroid Build Coastguard Worker m_entries_size(0),
6847*77c1e3ccSAndroid Build Coastguard Worker m_entries_count(-1) // means "has not been parsed yet"
6848*77c1e3ccSAndroid Build Coastguard Worker {}
6849*77c1e3ccSAndroid Build Coastguard Worker
~Cluster()6850*77c1e3ccSAndroid Build Coastguard Worker Cluster::~Cluster() {
6851*77c1e3ccSAndroid Build Coastguard Worker if (m_entries_count <= 0) {
6852*77c1e3ccSAndroid Build Coastguard Worker delete[] m_entries;
6853*77c1e3ccSAndroid Build Coastguard Worker return;
6854*77c1e3ccSAndroid Build Coastguard Worker }
6855*77c1e3ccSAndroid Build Coastguard Worker
6856*77c1e3ccSAndroid Build Coastguard Worker BlockEntry** i = m_entries;
6857*77c1e3ccSAndroid Build Coastguard Worker BlockEntry** const j = m_entries + m_entries_count;
6858*77c1e3ccSAndroid Build Coastguard Worker
6859*77c1e3ccSAndroid Build Coastguard Worker while (i != j) {
6860*77c1e3ccSAndroid Build Coastguard Worker BlockEntry* p = *i++;
6861*77c1e3ccSAndroid Build Coastguard Worker assert(p);
6862*77c1e3ccSAndroid Build Coastguard Worker
6863*77c1e3ccSAndroid Build Coastguard Worker delete p;
6864*77c1e3ccSAndroid Build Coastguard Worker }
6865*77c1e3ccSAndroid Build Coastguard Worker
6866*77c1e3ccSAndroid Build Coastguard Worker delete[] m_entries;
6867*77c1e3ccSAndroid Build Coastguard Worker }
6868*77c1e3ccSAndroid Build Coastguard Worker
EOS() const6869*77c1e3ccSAndroid Build Coastguard Worker bool Cluster::EOS() const { return (m_pSegment == NULL); }
6870*77c1e3ccSAndroid Build Coastguard Worker
GetIndex() const6871*77c1e3ccSAndroid Build Coastguard Worker long Cluster::GetIndex() const { return m_index; }
6872*77c1e3ccSAndroid Build Coastguard Worker
GetPosition() const6873*77c1e3ccSAndroid Build Coastguard Worker long long Cluster::GetPosition() const {
6874*77c1e3ccSAndroid Build Coastguard Worker const long long pos = m_element_start - m_pSegment->m_start;
6875*77c1e3ccSAndroid Build Coastguard Worker assert(pos >= 0);
6876*77c1e3ccSAndroid Build Coastguard Worker
6877*77c1e3ccSAndroid Build Coastguard Worker return pos;
6878*77c1e3ccSAndroid Build Coastguard Worker }
6879*77c1e3ccSAndroid Build Coastguard Worker
GetElementSize() const6880*77c1e3ccSAndroid Build Coastguard Worker long long Cluster::GetElementSize() const { return m_element_size; }
6881*77c1e3ccSAndroid Build Coastguard Worker
HasBlockEntries(const Segment * pSegment,long long off,long long & pos,long & len)6882*77c1e3ccSAndroid Build Coastguard Worker long Cluster::HasBlockEntries(
6883*77c1e3ccSAndroid Build Coastguard Worker const Segment* pSegment,
6884*77c1e3ccSAndroid Build Coastguard Worker long long off, // relative to start of segment payload
6885*77c1e3ccSAndroid Build Coastguard Worker long long& pos, long& len) {
6886*77c1e3ccSAndroid Build Coastguard Worker assert(pSegment);
6887*77c1e3ccSAndroid Build Coastguard Worker assert(off >= 0); // relative to segment
6888*77c1e3ccSAndroid Build Coastguard Worker
6889*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = pSegment->m_pReader;
6890*77c1e3ccSAndroid Build Coastguard Worker
6891*77c1e3ccSAndroid Build Coastguard Worker long long total, avail;
6892*77c1e3ccSAndroid Build Coastguard Worker
6893*77c1e3ccSAndroid Build Coastguard Worker long status = pReader->Length(&total, &avail);
6894*77c1e3ccSAndroid Build Coastguard Worker
6895*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
6896*77c1e3ccSAndroid Build Coastguard Worker return status;
6897*77c1e3ccSAndroid Build Coastguard Worker
6898*77c1e3ccSAndroid Build Coastguard Worker assert((total < 0) || (avail <= total));
6899*77c1e3ccSAndroid Build Coastguard Worker
6900*77c1e3ccSAndroid Build Coastguard Worker pos = pSegment->m_start + off; // absolute
6901*77c1e3ccSAndroid Build Coastguard Worker
6902*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (pos >= total))
6903*77c1e3ccSAndroid Build Coastguard Worker return 0; // we don't even have a complete cluster
6904*77c1e3ccSAndroid Build Coastguard Worker
6905*77c1e3ccSAndroid Build Coastguard Worker const long long segment_stop =
6906*77c1e3ccSAndroid Build Coastguard Worker (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size;
6907*77c1e3ccSAndroid Build Coastguard Worker
6908*77c1e3ccSAndroid Build Coastguard Worker long long cluster_stop = -1; // interpreted later to mean "unknown size"
6909*77c1e3ccSAndroid Build Coastguard Worker
6910*77c1e3ccSAndroid Build Coastguard Worker {
6911*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6912*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6913*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6914*77c1e3ccSAndroid Build Coastguard Worker }
6915*77c1e3ccSAndroid Build Coastguard Worker
6916*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(pReader, pos, len);
6917*77c1e3ccSAndroid Build Coastguard Worker
6918*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6919*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6920*77c1e3ccSAndroid Build Coastguard Worker
6921*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // need more data
6922*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6923*77c1e3ccSAndroid Build Coastguard Worker
6924*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
6925*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6926*77c1e3ccSAndroid Build Coastguard Worker
6927*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && ((pos + len) > total))
6928*77c1e3ccSAndroid Build Coastguard Worker return 0;
6929*77c1e3ccSAndroid Build Coastguard Worker
6930*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6931*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6932*77c1e3ccSAndroid Build Coastguard Worker
6933*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
6934*77c1e3ccSAndroid Build Coastguard Worker
6935*77c1e3ccSAndroid Build Coastguard Worker if (id < 0) // error
6936*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(id);
6937*77c1e3ccSAndroid Build Coastguard Worker
6938*77c1e3ccSAndroid Build Coastguard Worker if (id != libwebm::kMkvCluster)
6939*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
6940*77c1e3ccSAndroid Build Coastguard Worker
6941*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume Cluster ID field
6942*77c1e3ccSAndroid Build Coastguard Worker
6943*77c1e3ccSAndroid Build Coastguard Worker // read size field
6944*77c1e3ccSAndroid Build Coastguard Worker
6945*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6946*77c1e3ccSAndroid Build Coastguard Worker len = 1;
6947*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6948*77c1e3ccSAndroid Build Coastguard Worker }
6949*77c1e3ccSAndroid Build Coastguard Worker
6950*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(pReader, pos, len);
6951*77c1e3ccSAndroid Build Coastguard Worker
6952*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
6953*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
6954*77c1e3ccSAndroid Build Coastguard Worker
6955*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // weird
6956*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6957*77c1e3ccSAndroid Build Coastguard Worker
6958*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && ((pos + len) > segment_stop))
6959*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6960*77c1e3ccSAndroid Build Coastguard Worker
6961*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && ((pos + len) > total))
6962*77c1e3ccSAndroid Build Coastguard Worker return 0;
6963*77c1e3ccSAndroid Build Coastguard Worker
6964*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
6965*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
6966*77c1e3ccSAndroid Build Coastguard Worker
6967*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
6968*77c1e3ccSAndroid Build Coastguard Worker
6969*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
6970*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(size);
6971*77c1e3ccSAndroid Build Coastguard Worker
6972*77c1e3ccSAndroid Build Coastguard Worker if (size == 0)
6973*77c1e3ccSAndroid Build Coastguard Worker return 0; // cluster does not have entries
6974*77c1e3ccSAndroid Build Coastguard Worker
6975*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size field
6976*77c1e3ccSAndroid Build Coastguard Worker
6977*77c1e3ccSAndroid Build Coastguard Worker // pos now points to start of payload
6978*77c1e3ccSAndroid Build Coastguard Worker
6979*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
6980*77c1e3ccSAndroid Build Coastguard Worker
6981*77c1e3ccSAndroid Build Coastguard Worker if (size != unknown_size) {
6982*77c1e3ccSAndroid Build Coastguard Worker cluster_stop = pos + size;
6983*77c1e3ccSAndroid Build Coastguard Worker assert(cluster_stop >= 0);
6984*77c1e3ccSAndroid Build Coastguard Worker
6985*77c1e3ccSAndroid Build Coastguard Worker if ((segment_stop >= 0) && (cluster_stop > segment_stop))
6986*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
6987*77c1e3ccSAndroid Build Coastguard Worker
6988*77c1e3ccSAndroid Build Coastguard Worker if ((total >= 0) && (cluster_stop > total))
6989*77c1e3ccSAndroid Build Coastguard Worker // return E_FILE_FORMAT_INVALID; //too conservative
6990*77c1e3ccSAndroid Build Coastguard Worker return 0; // cluster does not have any entries
6991*77c1e3ccSAndroid Build Coastguard Worker }
6992*77c1e3ccSAndroid Build Coastguard Worker }
6993*77c1e3ccSAndroid Build Coastguard Worker
6994*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
6995*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && (pos >= cluster_stop))
6996*77c1e3ccSAndroid Build Coastguard Worker return 0; // no entries detected
6997*77c1e3ccSAndroid Build Coastguard Worker
6998*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
6999*77c1e3ccSAndroid Build Coastguard Worker len = 1;
7000*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
7001*77c1e3ccSAndroid Build Coastguard Worker }
7002*77c1e3ccSAndroid Build Coastguard Worker
7003*77c1e3ccSAndroid Build Coastguard Worker long long result = GetUIntLength(pReader, pos, len);
7004*77c1e3ccSAndroid Build Coastguard Worker
7005*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
7006*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
7007*77c1e3ccSAndroid Build Coastguard Worker
7008*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // need more data
7009*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
7010*77c1e3ccSAndroid Build Coastguard Worker
7011*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
7012*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7013*77c1e3ccSAndroid Build Coastguard Worker
7014*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
7015*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
7016*77c1e3ccSAndroid Build Coastguard Worker
7017*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
7018*77c1e3ccSAndroid Build Coastguard Worker
7019*77c1e3ccSAndroid Build Coastguard Worker if (id < 0) // error
7020*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(id);
7021*77c1e3ccSAndroid Build Coastguard Worker
7022*77c1e3ccSAndroid Build Coastguard Worker // This is the distinguished set of ID's we use to determine
7023*77c1e3ccSAndroid Build Coastguard Worker // that we have exhausted the sub-element's inside the cluster
7024*77c1e3ccSAndroid Build Coastguard Worker // whose ID we parsed earlier.
7025*77c1e3ccSAndroid Build Coastguard Worker
7026*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCluster)
7027*77c1e3ccSAndroid Build Coastguard Worker return 0; // no entries found
7028*77c1e3ccSAndroid Build Coastguard Worker
7029*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvCues)
7030*77c1e3ccSAndroid Build Coastguard Worker return 0; // no entries found
7031*77c1e3ccSAndroid Build Coastguard Worker
7032*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume id field
7033*77c1e3ccSAndroid Build Coastguard Worker
7034*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && (pos >= cluster_stop))
7035*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7036*77c1e3ccSAndroid Build Coastguard Worker
7037*77c1e3ccSAndroid Build Coastguard Worker // read size field
7038*77c1e3ccSAndroid Build Coastguard Worker
7039*77c1e3ccSAndroid Build Coastguard Worker if ((pos + 1) > avail) {
7040*77c1e3ccSAndroid Build Coastguard Worker len = 1;
7041*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
7042*77c1e3ccSAndroid Build Coastguard Worker }
7043*77c1e3ccSAndroid Build Coastguard Worker
7044*77c1e3ccSAndroid Build Coastguard Worker result = GetUIntLength(pReader, pos, len);
7045*77c1e3ccSAndroid Build Coastguard Worker
7046*77c1e3ccSAndroid Build Coastguard Worker if (result < 0) // error
7047*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(result);
7048*77c1e3ccSAndroid Build Coastguard Worker
7049*77c1e3ccSAndroid Build Coastguard Worker if (result > 0) // underflow
7050*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
7051*77c1e3ccSAndroid Build Coastguard Worker
7052*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
7053*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7054*77c1e3ccSAndroid Build Coastguard Worker
7055*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > avail)
7056*77c1e3ccSAndroid Build Coastguard Worker return E_BUFFER_NOT_FULL;
7057*77c1e3ccSAndroid Build Coastguard Worker
7058*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
7059*77c1e3ccSAndroid Build Coastguard Worker
7060*77c1e3ccSAndroid Build Coastguard Worker if (size < 0) // error
7061*77c1e3ccSAndroid Build Coastguard Worker return static_cast<long>(size);
7062*77c1e3ccSAndroid Build Coastguard Worker
7063*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size field
7064*77c1e3ccSAndroid Build Coastguard Worker
7065*77c1e3ccSAndroid Build Coastguard Worker // pos now points to start of payload
7066*77c1e3ccSAndroid Build Coastguard Worker
7067*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && (pos > cluster_stop))
7068*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7069*77c1e3ccSAndroid Build Coastguard Worker
7070*77c1e3ccSAndroid Build Coastguard Worker if (size == 0) // weird
7071*77c1e3ccSAndroid Build Coastguard Worker continue;
7072*77c1e3ccSAndroid Build Coastguard Worker
7073*77c1e3ccSAndroid Build Coastguard Worker const long long unknown_size = (1LL << (7 * len)) - 1;
7074*77c1e3ccSAndroid Build Coastguard Worker
7075*77c1e3ccSAndroid Build Coastguard Worker if (size == unknown_size)
7076*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID; // not supported inside cluster
7077*77c1e3ccSAndroid Build Coastguard Worker
7078*77c1e3ccSAndroid Build Coastguard Worker if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
7079*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7080*77c1e3ccSAndroid Build Coastguard Worker
7081*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvBlockGroup)
7082*77c1e3ccSAndroid Build Coastguard Worker return 1; // have at least one entry
7083*77c1e3ccSAndroid Build Coastguard Worker
7084*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvSimpleBlock)
7085*77c1e3ccSAndroid Build Coastguard Worker return 1; // have at least one entry
7086*77c1e3ccSAndroid Build Coastguard Worker
7087*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
7088*77c1e3ccSAndroid Build Coastguard Worker if (cluster_stop >= 0 && pos > cluster_stop)
7089*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7090*77c1e3ccSAndroid Build Coastguard Worker }
7091*77c1e3ccSAndroid Build Coastguard Worker }
7092*77c1e3ccSAndroid Build Coastguard Worker
GetTimeCode() const7093*77c1e3ccSAndroid Build Coastguard Worker long long Cluster::GetTimeCode() const {
7094*77c1e3ccSAndroid Build Coastguard Worker long long pos;
7095*77c1e3ccSAndroid Build Coastguard Worker long len;
7096*77c1e3ccSAndroid Build Coastguard Worker
7097*77c1e3ccSAndroid Build Coastguard Worker const long status = Load(pos, len);
7098*77c1e3ccSAndroid Build Coastguard Worker
7099*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
7100*77c1e3ccSAndroid Build Coastguard Worker return status;
7101*77c1e3ccSAndroid Build Coastguard Worker
7102*77c1e3ccSAndroid Build Coastguard Worker return m_timecode;
7103*77c1e3ccSAndroid Build Coastguard Worker }
7104*77c1e3ccSAndroid Build Coastguard Worker
GetTime() const7105*77c1e3ccSAndroid Build Coastguard Worker long long Cluster::GetTime() const {
7106*77c1e3ccSAndroid Build Coastguard Worker const long long tc = GetTimeCode();
7107*77c1e3ccSAndroid Build Coastguard Worker
7108*77c1e3ccSAndroid Build Coastguard Worker if (tc < 0)
7109*77c1e3ccSAndroid Build Coastguard Worker return tc;
7110*77c1e3ccSAndroid Build Coastguard Worker
7111*77c1e3ccSAndroid Build Coastguard Worker const SegmentInfo* const pInfo = m_pSegment->GetInfo();
7112*77c1e3ccSAndroid Build Coastguard Worker assert(pInfo);
7113*77c1e3ccSAndroid Build Coastguard Worker
7114*77c1e3ccSAndroid Build Coastguard Worker const long long scale = pInfo->GetTimeCodeScale();
7115*77c1e3ccSAndroid Build Coastguard Worker assert(scale >= 1);
7116*77c1e3ccSAndroid Build Coastguard Worker
7117*77c1e3ccSAndroid Build Coastguard Worker const long long t = m_timecode * scale;
7118*77c1e3ccSAndroid Build Coastguard Worker
7119*77c1e3ccSAndroid Build Coastguard Worker return t;
7120*77c1e3ccSAndroid Build Coastguard Worker }
7121*77c1e3ccSAndroid Build Coastguard Worker
GetFirstTime() const7122*77c1e3ccSAndroid Build Coastguard Worker long long Cluster::GetFirstTime() const {
7123*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* pEntry;
7124*77c1e3ccSAndroid Build Coastguard Worker
7125*77c1e3ccSAndroid Build Coastguard Worker const long status = GetFirst(pEntry);
7126*77c1e3ccSAndroid Build Coastguard Worker
7127*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
7128*77c1e3ccSAndroid Build Coastguard Worker return status;
7129*77c1e3ccSAndroid Build Coastguard Worker
7130*77c1e3ccSAndroid Build Coastguard Worker if (pEntry == NULL) // empty cluster
7131*77c1e3ccSAndroid Build Coastguard Worker return GetTime();
7132*77c1e3ccSAndroid Build Coastguard Worker
7133*77c1e3ccSAndroid Build Coastguard Worker const Block* const pBlock = pEntry->GetBlock();
7134*77c1e3ccSAndroid Build Coastguard Worker assert(pBlock);
7135*77c1e3ccSAndroid Build Coastguard Worker
7136*77c1e3ccSAndroid Build Coastguard Worker return pBlock->GetTime(this);
7137*77c1e3ccSAndroid Build Coastguard Worker }
7138*77c1e3ccSAndroid Build Coastguard Worker
GetLastTime() const7139*77c1e3ccSAndroid Build Coastguard Worker long long Cluster::GetLastTime() const {
7140*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* pEntry;
7141*77c1e3ccSAndroid Build Coastguard Worker
7142*77c1e3ccSAndroid Build Coastguard Worker const long status = GetLast(pEntry);
7143*77c1e3ccSAndroid Build Coastguard Worker
7144*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // error
7145*77c1e3ccSAndroid Build Coastguard Worker return status;
7146*77c1e3ccSAndroid Build Coastguard Worker
7147*77c1e3ccSAndroid Build Coastguard Worker if (pEntry == NULL) // empty cluster
7148*77c1e3ccSAndroid Build Coastguard Worker return GetTime();
7149*77c1e3ccSAndroid Build Coastguard Worker
7150*77c1e3ccSAndroid Build Coastguard Worker const Block* const pBlock = pEntry->GetBlock();
7151*77c1e3ccSAndroid Build Coastguard Worker assert(pBlock);
7152*77c1e3ccSAndroid Build Coastguard Worker
7153*77c1e3ccSAndroid Build Coastguard Worker return pBlock->GetTime(this);
7154*77c1e3ccSAndroid Build Coastguard Worker }
7155*77c1e3ccSAndroid Build Coastguard Worker
CreateBlock(long long id,long long pos,long long size,long long discard_padding)7156*77c1e3ccSAndroid Build Coastguard Worker long Cluster::CreateBlock(long long id,
7157*77c1e3ccSAndroid Build Coastguard Worker long long pos, // absolute pos of payload
7158*77c1e3ccSAndroid Build Coastguard Worker long long size, long long discard_padding) {
7159*77c1e3ccSAndroid Build Coastguard Worker if (id != libwebm::kMkvBlockGroup && id != libwebm::kMkvSimpleBlock)
7160*77c1e3ccSAndroid Build Coastguard Worker return E_PARSE_FAILED;
7161*77c1e3ccSAndroid Build Coastguard Worker
7162*77c1e3ccSAndroid Build Coastguard Worker if (m_entries_count < 0) { // haven't parsed anything yet
7163*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries == NULL);
7164*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_size == 0);
7165*77c1e3ccSAndroid Build Coastguard Worker
7166*77c1e3ccSAndroid Build Coastguard Worker m_entries_size = 1024;
7167*77c1e3ccSAndroid Build Coastguard Worker m_entries = new (std::nothrow) BlockEntry*[m_entries_size];
7168*77c1e3ccSAndroid Build Coastguard Worker if (m_entries == NULL)
7169*77c1e3ccSAndroid Build Coastguard Worker return -1;
7170*77c1e3ccSAndroid Build Coastguard Worker
7171*77c1e3ccSAndroid Build Coastguard Worker m_entries_count = 0;
7172*77c1e3ccSAndroid Build Coastguard Worker } else {
7173*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries);
7174*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_size > 0);
7175*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_count <= m_entries_size);
7176*77c1e3ccSAndroid Build Coastguard Worker
7177*77c1e3ccSAndroid Build Coastguard Worker if (m_entries_count >= m_entries_size) {
7178*77c1e3ccSAndroid Build Coastguard Worker const long entries_size = 2 * m_entries_size;
7179*77c1e3ccSAndroid Build Coastguard Worker
7180*77c1e3ccSAndroid Build Coastguard Worker BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size];
7181*77c1e3ccSAndroid Build Coastguard Worker if (entries == NULL)
7182*77c1e3ccSAndroid Build Coastguard Worker return -1;
7183*77c1e3ccSAndroid Build Coastguard Worker
7184*77c1e3ccSAndroid Build Coastguard Worker BlockEntry** src = m_entries;
7185*77c1e3ccSAndroid Build Coastguard Worker BlockEntry** const src_end = src + m_entries_count;
7186*77c1e3ccSAndroid Build Coastguard Worker
7187*77c1e3ccSAndroid Build Coastguard Worker BlockEntry** dst = entries;
7188*77c1e3ccSAndroid Build Coastguard Worker
7189*77c1e3ccSAndroid Build Coastguard Worker while (src != src_end)
7190*77c1e3ccSAndroid Build Coastguard Worker *dst++ = *src++;
7191*77c1e3ccSAndroid Build Coastguard Worker
7192*77c1e3ccSAndroid Build Coastguard Worker delete[] m_entries;
7193*77c1e3ccSAndroid Build Coastguard Worker
7194*77c1e3ccSAndroid Build Coastguard Worker m_entries = entries;
7195*77c1e3ccSAndroid Build Coastguard Worker m_entries_size = entries_size;
7196*77c1e3ccSAndroid Build Coastguard Worker }
7197*77c1e3ccSAndroid Build Coastguard Worker }
7198*77c1e3ccSAndroid Build Coastguard Worker
7199*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvBlockGroup)
7200*77c1e3ccSAndroid Build Coastguard Worker return CreateBlockGroup(pos, size, discard_padding);
7201*77c1e3ccSAndroid Build Coastguard Worker else
7202*77c1e3ccSAndroid Build Coastguard Worker return CreateSimpleBlock(pos, size);
7203*77c1e3ccSAndroid Build Coastguard Worker }
7204*77c1e3ccSAndroid Build Coastguard Worker
CreateBlockGroup(long long start_offset,long long size,long long discard_padding)7205*77c1e3ccSAndroid Build Coastguard Worker long Cluster::CreateBlockGroup(long long start_offset, long long size,
7206*77c1e3ccSAndroid Build Coastguard Worker long long discard_padding) {
7207*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries);
7208*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_size > 0);
7209*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_count >= 0);
7210*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_count < m_entries_size);
7211*77c1e3ccSAndroid Build Coastguard Worker
7212*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = m_pSegment->m_pReader;
7213*77c1e3ccSAndroid Build Coastguard Worker
7214*77c1e3ccSAndroid Build Coastguard Worker long long pos = start_offset;
7215*77c1e3ccSAndroid Build Coastguard Worker const long long stop = start_offset + size;
7216*77c1e3ccSAndroid Build Coastguard Worker
7217*77c1e3ccSAndroid Build Coastguard Worker // For WebM files, there is a bias towards previous reference times
7218*77c1e3ccSAndroid Build Coastguard Worker //(in order to support alt-ref frames, which refer back to the previous
7219*77c1e3ccSAndroid Build Coastguard Worker // keyframe). Normally a 0 value is not possible, but here we tenatively
7220*77c1e3ccSAndroid Build Coastguard Worker // allow 0 as the value of a reference frame, with the interpretation
7221*77c1e3ccSAndroid Build Coastguard Worker // that this is a "previous" reference time.
7222*77c1e3ccSAndroid Build Coastguard Worker
7223*77c1e3ccSAndroid Build Coastguard Worker long long prev = 1; // nonce
7224*77c1e3ccSAndroid Build Coastguard Worker long long next = 0; // nonce
7225*77c1e3ccSAndroid Build Coastguard Worker long long duration = -1; // really, this is unsigned
7226*77c1e3ccSAndroid Build Coastguard Worker
7227*77c1e3ccSAndroid Build Coastguard Worker long long bpos = -1;
7228*77c1e3ccSAndroid Build Coastguard Worker long long bsize = -1;
7229*77c1e3ccSAndroid Build Coastguard Worker
7230*77c1e3ccSAndroid Build Coastguard Worker while (pos < stop) {
7231*77c1e3ccSAndroid Build Coastguard Worker long len;
7232*77c1e3ccSAndroid Build Coastguard Worker const long long id = ReadID(pReader, pos, len);
7233*77c1e3ccSAndroid Build Coastguard Worker if (id < 0 || (pos + len) > stop)
7234*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7235*77c1e3ccSAndroid Build Coastguard Worker
7236*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume ID
7237*77c1e3ccSAndroid Build Coastguard Worker
7238*77c1e3ccSAndroid Build Coastguard Worker const long long size = ReadUInt(pReader, pos, len);
7239*77c1e3ccSAndroid Build Coastguard Worker assert(size >= 0); // TODO
7240*77c1e3ccSAndroid Build Coastguard Worker assert((pos + len) <= stop);
7241*77c1e3ccSAndroid Build Coastguard Worker
7242*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume size
7243*77c1e3ccSAndroid Build Coastguard Worker
7244*77c1e3ccSAndroid Build Coastguard Worker if (id == libwebm::kMkvBlock) {
7245*77c1e3ccSAndroid Build Coastguard Worker if (bpos < 0) { // Block ID
7246*77c1e3ccSAndroid Build Coastguard Worker bpos = pos;
7247*77c1e3ccSAndroid Build Coastguard Worker bsize = size;
7248*77c1e3ccSAndroid Build Coastguard Worker }
7249*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvBlockDuration) {
7250*77c1e3ccSAndroid Build Coastguard Worker if (size > 8)
7251*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7252*77c1e3ccSAndroid Build Coastguard Worker
7253*77c1e3ccSAndroid Build Coastguard Worker duration = UnserializeUInt(pReader, pos, size);
7254*77c1e3ccSAndroid Build Coastguard Worker
7255*77c1e3ccSAndroid Build Coastguard Worker if (duration < 0)
7256*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7257*77c1e3ccSAndroid Build Coastguard Worker } else if (id == libwebm::kMkvReferenceBlock) {
7258*77c1e3ccSAndroid Build Coastguard Worker if (size > 8 || size <= 0)
7259*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7260*77c1e3ccSAndroid Build Coastguard Worker const long size_ = static_cast<long>(size);
7261*77c1e3ccSAndroid Build Coastguard Worker
7262*77c1e3ccSAndroid Build Coastguard Worker long long time;
7263*77c1e3ccSAndroid Build Coastguard Worker
7264*77c1e3ccSAndroid Build Coastguard Worker long status = UnserializeInt(pReader, pos, size_, time);
7265*77c1e3ccSAndroid Build Coastguard Worker assert(status == 0);
7266*77c1e3ccSAndroid Build Coastguard Worker if (status != 0)
7267*77c1e3ccSAndroid Build Coastguard Worker return -1;
7268*77c1e3ccSAndroid Build Coastguard Worker
7269*77c1e3ccSAndroid Build Coastguard Worker if (time <= 0) // see note above
7270*77c1e3ccSAndroid Build Coastguard Worker prev = time;
7271*77c1e3ccSAndroid Build Coastguard Worker else
7272*77c1e3ccSAndroid Build Coastguard Worker next = time;
7273*77c1e3ccSAndroid Build Coastguard Worker }
7274*77c1e3ccSAndroid Build Coastguard Worker
7275*77c1e3ccSAndroid Build Coastguard Worker pos += size; // consume payload
7276*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
7277*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7278*77c1e3ccSAndroid Build Coastguard Worker }
7279*77c1e3ccSAndroid Build Coastguard Worker if (bpos < 0)
7280*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7281*77c1e3ccSAndroid Build Coastguard Worker
7282*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
7283*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7284*77c1e3ccSAndroid Build Coastguard Worker assert(bsize >= 0);
7285*77c1e3ccSAndroid Build Coastguard Worker
7286*77c1e3ccSAndroid Build Coastguard Worker const long idx = m_entries_count;
7287*77c1e3ccSAndroid Build Coastguard Worker
7288*77c1e3ccSAndroid Build Coastguard Worker BlockEntry** const ppEntry = m_entries + idx;
7289*77c1e3ccSAndroid Build Coastguard Worker BlockEntry*& pEntry = *ppEntry;
7290*77c1e3ccSAndroid Build Coastguard Worker
7291*77c1e3ccSAndroid Build Coastguard Worker pEntry = new (std::nothrow)
7292*77c1e3ccSAndroid Build Coastguard Worker BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
7293*77c1e3ccSAndroid Build Coastguard Worker
7294*77c1e3ccSAndroid Build Coastguard Worker if (pEntry == NULL)
7295*77c1e3ccSAndroid Build Coastguard Worker return -1; // generic error
7296*77c1e3ccSAndroid Build Coastguard Worker
7297*77c1e3ccSAndroid Build Coastguard Worker BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
7298*77c1e3ccSAndroid Build Coastguard Worker
7299*77c1e3ccSAndroid Build Coastguard Worker const long status = p->Parse();
7300*77c1e3ccSAndroid Build Coastguard Worker
7301*77c1e3ccSAndroid Build Coastguard Worker if (status == 0) { // success
7302*77c1e3ccSAndroid Build Coastguard Worker ++m_entries_count;
7303*77c1e3ccSAndroid Build Coastguard Worker return 0;
7304*77c1e3ccSAndroid Build Coastguard Worker }
7305*77c1e3ccSAndroid Build Coastguard Worker
7306*77c1e3ccSAndroid Build Coastguard Worker delete pEntry;
7307*77c1e3ccSAndroid Build Coastguard Worker pEntry = 0;
7308*77c1e3ccSAndroid Build Coastguard Worker
7309*77c1e3ccSAndroid Build Coastguard Worker return status;
7310*77c1e3ccSAndroid Build Coastguard Worker }
7311*77c1e3ccSAndroid Build Coastguard Worker
CreateSimpleBlock(long long st,long long sz)7312*77c1e3ccSAndroid Build Coastguard Worker long Cluster::CreateSimpleBlock(long long st, long long sz) {
7313*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries);
7314*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_size > 0);
7315*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_count >= 0);
7316*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_count < m_entries_size);
7317*77c1e3ccSAndroid Build Coastguard Worker
7318*77c1e3ccSAndroid Build Coastguard Worker const long idx = m_entries_count;
7319*77c1e3ccSAndroid Build Coastguard Worker
7320*77c1e3ccSAndroid Build Coastguard Worker BlockEntry** const ppEntry = m_entries + idx;
7321*77c1e3ccSAndroid Build Coastguard Worker BlockEntry*& pEntry = *ppEntry;
7322*77c1e3ccSAndroid Build Coastguard Worker
7323*77c1e3ccSAndroid Build Coastguard Worker pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
7324*77c1e3ccSAndroid Build Coastguard Worker
7325*77c1e3ccSAndroid Build Coastguard Worker if (pEntry == NULL)
7326*77c1e3ccSAndroid Build Coastguard Worker return -1; // generic error
7327*77c1e3ccSAndroid Build Coastguard Worker
7328*77c1e3ccSAndroid Build Coastguard Worker SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
7329*77c1e3ccSAndroid Build Coastguard Worker
7330*77c1e3ccSAndroid Build Coastguard Worker const long status = p->Parse();
7331*77c1e3ccSAndroid Build Coastguard Worker
7332*77c1e3ccSAndroid Build Coastguard Worker if (status == 0) {
7333*77c1e3ccSAndroid Build Coastguard Worker ++m_entries_count;
7334*77c1e3ccSAndroid Build Coastguard Worker return 0;
7335*77c1e3ccSAndroid Build Coastguard Worker }
7336*77c1e3ccSAndroid Build Coastguard Worker
7337*77c1e3ccSAndroid Build Coastguard Worker delete pEntry;
7338*77c1e3ccSAndroid Build Coastguard Worker pEntry = 0;
7339*77c1e3ccSAndroid Build Coastguard Worker
7340*77c1e3ccSAndroid Build Coastguard Worker return status;
7341*77c1e3ccSAndroid Build Coastguard Worker }
7342*77c1e3ccSAndroid Build Coastguard Worker
GetFirst(const BlockEntry * & pFirst) const7343*77c1e3ccSAndroid Build Coastguard Worker long Cluster::GetFirst(const BlockEntry*& pFirst) const {
7344*77c1e3ccSAndroid Build Coastguard Worker if (m_entries_count <= 0) {
7345*77c1e3ccSAndroid Build Coastguard Worker long long pos;
7346*77c1e3ccSAndroid Build Coastguard Worker long len;
7347*77c1e3ccSAndroid Build Coastguard Worker
7348*77c1e3ccSAndroid Build Coastguard Worker const long status = Parse(pos, len);
7349*77c1e3ccSAndroid Build Coastguard Worker
7350*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) { // error
7351*77c1e3ccSAndroid Build Coastguard Worker pFirst = NULL;
7352*77c1e3ccSAndroid Build Coastguard Worker return status;
7353*77c1e3ccSAndroid Build Coastguard Worker }
7354*77c1e3ccSAndroid Build Coastguard Worker
7355*77c1e3ccSAndroid Build Coastguard Worker if (m_entries_count <= 0) { // empty cluster
7356*77c1e3ccSAndroid Build Coastguard Worker pFirst = NULL;
7357*77c1e3ccSAndroid Build Coastguard Worker return 0;
7358*77c1e3ccSAndroid Build Coastguard Worker }
7359*77c1e3ccSAndroid Build Coastguard Worker }
7360*77c1e3ccSAndroid Build Coastguard Worker
7361*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries);
7362*77c1e3ccSAndroid Build Coastguard Worker
7363*77c1e3ccSAndroid Build Coastguard Worker pFirst = m_entries[0];
7364*77c1e3ccSAndroid Build Coastguard Worker assert(pFirst);
7365*77c1e3ccSAndroid Build Coastguard Worker
7366*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
7367*77c1e3ccSAndroid Build Coastguard Worker }
7368*77c1e3ccSAndroid Build Coastguard Worker
GetLast(const BlockEntry * & pLast) const7369*77c1e3ccSAndroid Build Coastguard Worker long Cluster::GetLast(const BlockEntry*& pLast) const {
7370*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
7371*77c1e3ccSAndroid Build Coastguard Worker long long pos;
7372*77c1e3ccSAndroid Build Coastguard Worker long len;
7373*77c1e3ccSAndroid Build Coastguard Worker
7374*77c1e3ccSAndroid Build Coastguard Worker const long status = Parse(pos, len);
7375*77c1e3ccSAndroid Build Coastguard Worker
7376*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) { // error
7377*77c1e3ccSAndroid Build Coastguard Worker pLast = NULL;
7378*77c1e3ccSAndroid Build Coastguard Worker return status;
7379*77c1e3ccSAndroid Build Coastguard Worker }
7380*77c1e3ccSAndroid Build Coastguard Worker
7381*77c1e3ccSAndroid Build Coastguard Worker if (status > 0) // no new block
7382*77c1e3ccSAndroid Build Coastguard Worker break;
7383*77c1e3ccSAndroid Build Coastguard Worker }
7384*77c1e3ccSAndroid Build Coastguard Worker
7385*77c1e3ccSAndroid Build Coastguard Worker if (m_entries_count <= 0) {
7386*77c1e3ccSAndroid Build Coastguard Worker pLast = NULL;
7387*77c1e3ccSAndroid Build Coastguard Worker return 0;
7388*77c1e3ccSAndroid Build Coastguard Worker }
7389*77c1e3ccSAndroid Build Coastguard Worker
7390*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries);
7391*77c1e3ccSAndroid Build Coastguard Worker
7392*77c1e3ccSAndroid Build Coastguard Worker const long idx = m_entries_count - 1;
7393*77c1e3ccSAndroid Build Coastguard Worker
7394*77c1e3ccSAndroid Build Coastguard Worker pLast = m_entries[idx];
7395*77c1e3ccSAndroid Build Coastguard Worker assert(pLast);
7396*77c1e3ccSAndroid Build Coastguard Worker
7397*77c1e3ccSAndroid Build Coastguard Worker return 0;
7398*77c1e3ccSAndroid Build Coastguard Worker }
7399*77c1e3ccSAndroid Build Coastguard Worker
GetNext(const BlockEntry * pCurr,const BlockEntry * & pNext) const7400*77c1e3ccSAndroid Build Coastguard Worker long Cluster::GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const {
7401*77c1e3ccSAndroid Build Coastguard Worker assert(pCurr);
7402*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries);
7403*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_count > 0);
7404*77c1e3ccSAndroid Build Coastguard Worker
7405*77c1e3ccSAndroid Build Coastguard Worker size_t idx = pCurr->GetIndex();
7406*77c1e3ccSAndroid Build Coastguard Worker assert(idx < size_t(m_entries_count));
7407*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries[idx] == pCurr);
7408*77c1e3ccSAndroid Build Coastguard Worker
7409*77c1e3ccSAndroid Build Coastguard Worker ++idx;
7410*77c1e3ccSAndroid Build Coastguard Worker
7411*77c1e3ccSAndroid Build Coastguard Worker if (idx >= size_t(m_entries_count)) {
7412*77c1e3ccSAndroid Build Coastguard Worker long long pos;
7413*77c1e3ccSAndroid Build Coastguard Worker long len;
7414*77c1e3ccSAndroid Build Coastguard Worker
7415*77c1e3ccSAndroid Build Coastguard Worker const long status = Parse(pos, len);
7416*77c1e3ccSAndroid Build Coastguard Worker
7417*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) { // error
7418*77c1e3ccSAndroid Build Coastguard Worker pNext = NULL;
7419*77c1e3ccSAndroid Build Coastguard Worker return status;
7420*77c1e3ccSAndroid Build Coastguard Worker }
7421*77c1e3ccSAndroid Build Coastguard Worker
7422*77c1e3ccSAndroid Build Coastguard Worker if (status > 0) {
7423*77c1e3ccSAndroid Build Coastguard Worker pNext = NULL;
7424*77c1e3ccSAndroid Build Coastguard Worker return 0;
7425*77c1e3ccSAndroid Build Coastguard Worker }
7426*77c1e3ccSAndroid Build Coastguard Worker
7427*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries);
7428*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries_count > 0);
7429*77c1e3ccSAndroid Build Coastguard Worker assert(idx < size_t(m_entries_count));
7430*77c1e3ccSAndroid Build Coastguard Worker }
7431*77c1e3ccSAndroid Build Coastguard Worker
7432*77c1e3ccSAndroid Build Coastguard Worker pNext = m_entries[idx];
7433*77c1e3ccSAndroid Build Coastguard Worker assert(pNext);
7434*77c1e3ccSAndroid Build Coastguard Worker
7435*77c1e3ccSAndroid Build Coastguard Worker return 0;
7436*77c1e3ccSAndroid Build Coastguard Worker }
7437*77c1e3ccSAndroid Build Coastguard Worker
GetEntryCount() const7438*77c1e3ccSAndroid Build Coastguard Worker long Cluster::GetEntryCount() const { return m_entries_count; }
7439*77c1e3ccSAndroid Build Coastguard Worker
GetEntry(const Track * pTrack,long long time_ns) const7440*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* Cluster::GetEntry(const Track* pTrack,
7441*77c1e3ccSAndroid Build Coastguard Worker long long time_ns) const {
7442*77c1e3ccSAndroid Build Coastguard Worker assert(pTrack);
7443*77c1e3ccSAndroid Build Coastguard Worker
7444*77c1e3ccSAndroid Build Coastguard Worker if (m_pSegment == NULL) // this is the special EOS cluster
7445*77c1e3ccSAndroid Build Coastguard Worker return pTrack->GetEOS();
7446*77c1e3ccSAndroid Build Coastguard Worker
7447*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* pResult = pTrack->GetEOS();
7448*77c1e3ccSAndroid Build Coastguard Worker
7449*77c1e3ccSAndroid Build Coastguard Worker long index = 0;
7450*77c1e3ccSAndroid Build Coastguard Worker
7451*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
7452*77c1e3ccSAndroid Build Coastguard Worker if (index >= m_entries_count) {
7453*77c1e3ccSAndroid Build Coastguard Worker long long pos;
7454*77c1e3ccSAndroid Build Coastguard Worker long len;
7455*77c1e3ccSAndroid Build Coastguard Worker
7456*77c1e3ccSAndroid Build Coastguard Worker const long status = Parse(pos, len);
7457*77c1e3ccSAndroid Build Coastguard Worker assert(status >= 0);
7458*77c1e3ccSAndroid Build Coastguard Worker
7459*77c1e3ccSAndroid Build Coastguard Worker if (status > 0) // completely parsed, and no more entries
7460*77c1e3ccSAndroid Build Coastguard Worker return pResult;
7461*77c1e3ccSAndroid Build Coastguard Worker
7462*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // should never happen
7463*77c1e3ccSAndroid Build Coastguard Worker return 0;
7464*77c1e3ccSAndroid Build Coastguard Worker
7465*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries);
7466*77c1e3ccSAndroid Build Coastguard Worker assert(index < m_entries_count);
7467*77c1e3ccSAndroid Build Coastguard Worker }
7468*77c1e3ccSAndroid Build Coastguard Worker
7469*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* const pEntry = m_entries[index];
7470*77c1e3ccSAndroid Build Coastguard Worker assert(pEntry);
7471*77c1e3ccSAndroid Build Coastguard Worker assert(!pEntry->EOS());
7472*77c1e3ccSAndroid Build Coastguard Worker
7473*77c1e3ccSAndroid Build Coastguard Worker const Block* const pBlock = pEntry->GetBlock();
7474*77c1e3ccSAndroid Build Coastguard Worker assert(pBlock);
7475*77c1e3ccSAndroid Build Coastguard Worker
7476*77c1e3ccSAndroid Build Coastguard Worker if (pBlock->GetTrackNumber() != pTrack->GetNumber()) {
7477*77c1e3ccSAndroid Build Coastguard Worker ++index;
7478*77c1e3ccSAndroid Build Coastguard Worker continue;
7479*77c1e3ccSAndroid Build Coastguard Worker }
7480*77c1e3ccSAndroid Build Coastguard Worker
7481*77c1e3ccSAndroid Build Coastguard Worker if (pTrack->VetEntry(pEntry)) {
7482*77c1e3ccSAndroid Build Coastguard Worker if (time_ns < 0) // just want first candidate block
7483*77c1e3ccSAndroid Build Coastguard Worker return pEntry;
7484*77c1e3ccSAndroid Build Coastguard Worker
7485*77c1e3ccSAndroid Build Coastguard Worker const long long ns = pBlock->GetTime(this);
7486*77c1e3ccSAndroid Build Coastguard Worker
7487*77c1e3ccSAndroid Build Coastguard Worker if (ns > time_ns)
7488*77c1e3ccSAndroid Build Coastguard Worker return pResult;
7489*77c1e3ccSAndroid Build Coastguard Worker
7490*77c1e3ccSAndroid Build Coastguard Worker pResult = pEntry; // have a candidate
7491*77c1e3ccSAndroid Build Coastguard Worker } else if (time_ns >= 0) {
7492*77c1e3ccSAndroid Build Coastguard Worker const long long ns = pBlock->GetTime(this);
7493*77c1e3ccSAndroid Build Coastguard Worker
7494*77c1e3ccSAndroid Build Coastguard Worker if (ns > time_ns)
7495*77c1e3ccSAndroid Build Coastguard Worker return pResult;
7496*77c1e3ccSAndroid Build Coastguard Worker }
7497*77c1e3ccSAndroid Build Coastguard Worker
7498*77c1e3ccSAndroid Build Coastguard Worker ++index;
7499*77c1e3ccSAndroid Build Coastguard Worker }
7500*77c1e3ccSAndroid Build Coastguard Worker }
7501*77c1e3ccSAndroid Build Coastguard Worker
GetEntry(const CuePoint & cp,const CuePoint::TrackPosition & tp) const7502*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
7503*77c1e3ccSAndroid Build Coastguard Worker const CuePoint::TrackPosition& tp) const {
7504*77c1e3ccSAndroid Build Coastguard Worker assert(m_pSegment);
7505*77c1e3ccSAndroid Build Coastguard Worker const long long tc = cp.GetTimeCode();
7506*77c1e3ccSAndroid Build Coastguard Worker
7507*77c1e3ccSAndroid Build Coastguard Worker if (tp.m_block > 0) {
7508*77c1e3ccSAndroid Build Coastguard Worker const long block = static_cast<long>(tp.m_block);
7509*77c1e3ccSAndroid Build Coastguard Worker const long index = block - 1;
7510*77c1e3ccSAndroid Build Coastguard Worker
7511*77c1e3ccSAndroid Build Coastguard Worker while (index >= m_entries_count) {
7512*77c1e3ccSAndroid Build Coastguard Worker long long pos;
7513*77c1e3ccSAndroid Build Coastguard Worker long len;
7514*77c1e3ccSAndroid Build Coastguard Worker
7515*77c1e3ccSAndroid Build Coastguard Worker const long status = Parse(pos, len);
7516*77c1e3ccSAndroid Build Coastguard Worker
7517*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // TODO: can this happen?
7518*77c1e3ccSAndroid Build Coastguard Worker return NULL;
7519*77c1e3ccSAndroid Build Coastguard Worker
7520*77c1e3ccSAndroid Build Coastguard Worker if (status > 0) // nothing remains to be parsed
7521*77c1e3ccSAndroid Build Coastguard Worker return NULL;
7522*77c1e3ccSAndroid Build Coastguard Worker }
7523*77c1e3ccSAndroid Build Coastguard Worker
7524*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* const pEntry = m_entries[index];
7525*77c1e3ccSAndroid Build Coastguard Worker assert(pEntry);
7526*77c1e3ccSAndroid Build Coastguard Worker assert(!pEntry->EOS());
7527*77c1e3ccSAndroid Build Coastguard Worker
7528*77c1e3ccSAndroid Build Coastguard Worker const Block* const pBlock = pEntry->GetBlock();
7529*77c1e3ccSAndroid Build Coastguard Worker assert(pBlock);
7530*77c1e3ccSAndroid Build Coastguard Worker
7531*77c1e3ccSAndroid Build Coastguard Worker if ((pBlock->GetTrackNumber() == tp.m_track) &&
7532*77c1e3ccSAndroid Build Coastguard Worker (pBlock->GetTimeCode(this) == tc)) {
7533*77c1e3ccSAndroid Build Coastguard Worker return pEntry;
7534*77c1e3ccSAndroid Build Coastguard Worker }
7535*77c1e3ccSAndroid Build Coastguard Worker }
7536*77c1e3ccSAndroid Build Coastguard Worker
7537*77c1e3ccSAndroid Build Coastguard Worker long index = 0;
7538*77c1e3ccSAndroid Build Coastguard Worker
7539*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
7540*77c1e3ccSAndroid Build Coastguard Worker if (index >= m_entries_count) {
7541*77c1e3ccSAndroid Build Coastguard Worker long long pos;
7542*77c1e3ccSAndroid Build Coastguard Worker long len;
7543*77c1e3ccSAndroid Build Coastguard Worker
7544*77c1e3ccSAndroid Build Coastguard Worker const long status = Parse(pos, len);
7545*77c1e3ccSAndroid Build Coastguard Worker
7546*77c1e3ccSAndroid Build Coastguard Worker if (status < 0) // TODO: can this happen?
7547*77c1e3ccSAndroid Build Coastguard Worker return NULL;
7548*77c1e3ccSAndroid Build Coastguard Worker
7549*77c1e3ccSAndroid Build Coastguard Worker if (status > 0) // nothing remains to be parsed
7550*77c1e3ccSAndroid Build Coastguard Worker return NULL;
7551*77c1e3ccSAndroid Build Coastguard Worker
7552*77c1e3ccSAndroid Build Coastguard Worker assert(m_entries);
7553*77c1e3ccSAndroid Build Coastguard Worker assert(index < m_entries_count);
7554*77c1e3ccSAndroid Build Coastguard Worker }
7555*77c1e3ccSAndroid Build Coastguard Worker
7556*77c1e3ccSAndroid Build Coastguard Worker const BlockEntry* const pEntry = m_entries[index];
7557*77c1e3ccSAndroid Build Coastguard Worker assert(pEntry);
7558*77c1e3ccSAndroid Build Coastguard Worker assert(!pEntry->EOS());
7559*77c1e3ccSAndroid Build Coastguard Worker
7560*77c1e3ccSAndroid Build Coastguard Worker const Block* const pBlock = pEntry->GetBlock();
7561*77c1e3ccSAndroid Build Coastguard Worker assert(pBlock);
7562*77c1e3ccSAndroid Build Coastguard Worker
7563*77c1e3ccSAndroid Build Coastguard Worker if (pBlock->GetTrackNumber() != tp.m_track) {
7564*77c1e3ccSAndroid Build Coastguard Worker ++index;
7565*77c1e3ccSAndroid Build Coastguard Worker continue;
7566*77c1e3ccSAndroid Build Coastguard Worker }
7567*77c1e3ccSAndroid Build Coastguard Worker
7568*77c1e3ccSAndroid Build Coastguard Worker const long long tc_ = pBlock->GetTimeCode(this);
7569*77c1e3ccSAndroid Build Coastguard Worker
7570*77c1e3ccSAndroid Build Coastguard Worker if (tc_ < tc) {
7571*77c1e3ccSAndroid Build Coastguard Worker ++index;
7572*77c1e3ccSAndroid Build Coastguard Worker continue;
7573*77c1e3ccSAndroid Build Coastguard Worker }
7574*77c1e3ccSAndroid Build Coastguard Worker
7575*77c1e3ccSAndroid Build Coastguard Worker if (tc_ > tc)
7576*77c1e3ccSAndroid Build Coastguard Worker return NULL;
7577*77c1e3ccSAndroid Build Coastguard Worker
7578*77c1e3ccSAndroid Build Coastguard Worker const Tracks* const pTracks = m_pSegment->GetTracks();
7579*77c1e3ccSAndroid Build Coastguard Worker assert(pTracks);
7580*77c1e3ccSAndroid Build Coastguard Worker
7581*77c1e3ccSAndroid Build Coastguard Worker const long tn = static_cast<long>(tp.m_track);
7582*77c1e3ccSAndroid Build Coastguard Worker const Track* const pTrack = pTracks->GetTrackByNumber(tn);
7583*77c1e3ccSAndroid Build Coastguard Worker
7584*77c1e3ccSAndroid Build Coastguard Worker if (pTrack == NULL)
7585*77c1e3ccSAndroid Build Coastguard Worker return NULL;
7586*77c1e3ccSAndroid Build Coastguard Worker
7587*77c1e3ccSAndroid Build Coastguard Worker const long long type = pTrack->GetType();
7588*77c1e3ccSAndroid Build Coastguard Worker
7589*77c1e3ccSAndroid Build Coastguard Worker if (type == 2) // audio
7590*77c1e3ccSAndroid Build Coastguard Worker return pEntry;
7591*77c1e3ccSAndroid Build Coastguard Worker
7592*77c1e3ccSAndroid Build Coastguard Worker if (type != 1) // not video
7593*77c1e3ccSAndroid Build Coastguard Worker return NULL;
7594*77c1e3ccSAndroid Build Coastguard Worker
7595*77c1e3ccSAndroid Build Coastguard Worker if (!pBlock->IsKey())
7596*77c1e3ccSAndroid Build Coastguard Worker return NULL;
7597*77c1e3ccSAndroid Build Coastguard Worker
7598*77c1e3ccSAndroid Build Coastguard Worker return pEntry;
7599*77c1e3ccSAndroid Build Coastguard Worker }
7600*77c1e3ccSAndroid Build Coastguard Worker }
7601*77c1e3ccSAndroid Build Coastguard Worker
BlockEntry(Cluster * p,long idx)7602*77c1e3ccSAndroid Build Coastguard Worker BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
~BlockEntry()7603*77c1e3ccSAndroid Build Coastguard Worker BlockEntry::~BlockEntry() {}
GetCluster() const7604*77c1e3ccSAndroid Build Coastguard Worker const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
GetIndex() const7605*77c1e3ccSAndroid Build Coastguard Worker long BlockEntry::GetIndex() const { return m_index; }
7606*77c1e3ccSAndroid Build Coastguard Worker
SimpleBlock(Cluster * pCluster,long idx,long long start,long long size)7607*77c1e3ccSAndroid Build Coastguard Worker SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start,
7608*77c1e3ccSAndroid Build Coastguard Worker long long size)
7609*77c1e3ccSAndroid Build Coastguard Worker : BlockEntry(pCluster, idx), m_block(start, size, 0) {}
7610*77c1e3ccSAndroid Build Coastguard Worker
Parse()7611*77c1e3ccSAndroid Build Coastguard Worker long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); }
GetKind() const7612*77c1e3ccSAndroid Build Coastguard Worker BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; }
GetBlock() const7613*77c1e3ccSAndroid Build Coastguard Worker const Block* SimpleBlock::GetBlock() const { return &m_block; }
7614*77c1e3ccSAndroid Build Coastguard Worker
BlockGroup(Cluster * pCluster,long idx,long long block_start,long long block_size,long long prev,long long next,long long duration,long long discard_padding)7615*77c1e3ccSAndroid Build Coastguard Worker BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start,
7616*77c1e3ccSAndroid Build Coastguard Worker long long block_size, long long prev, long long next,
7617*77c1e3ccSAndroid Build Coastguard Worker long long duration, long long discard_padding)
7618*77c1e3ccSAndroid Build Coastguard Worker : BlockEntry(pCluster, idx),
7619*77c1e3ccSAndroid Build Coastguard Worker m_block(block_start, block_size, discard_padding),
7620*77c1e3ccSAndroid Build Coastguard Worker m_prev(prev),
7621*77c1e3ccSAndroid Build Coastguard Worker m_next(next),
7622*77c1e3ccSAndroid Build Coastguard Worker m_duration(duration) {}
7623*77c1e3ccSAndroid Build Coastguard Worker
Parse()7624*77c1e3ccSAndroid Build Coastguard Worker long BlockGroup::Parse() {
7625*77c1e3ccSAndroid Build Coastguard Worker const long status = m_block.Parse(m_pCluster);
7626*77c1e3ccSAndroid Build Coastguard Worker
7627*77c1e3ccSAndroid Build Coastguard Worker if (status)
7628*77c1e3ccSAndroid Build Coastguard Worker return status;
7629*77c1e3ccSAndroid Build Coastguard Worker
7630*77c1e3ccSAndroid Build Coastguard Worker m_block.SetKey((m_prev > 0) && (m_next <= 0));
7631*77c1e3ccSAndroid Build Coastguard Worker
7632*77c1e3ccSAndroid Build Coastguard Worker return 0;
7633*77c1e3ccSAndroid Build Coastguard Worker }
7634*77c1e3ccSAndroid Build Coastguard Worker
GetKind() const7635*77c1e3ccSAndroid Build Coastguard Worker BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; }
GetBlock() const7636*77c1e3ccSAndroid Build Coastguard Worker const Block* BlockGroup::GetBlock() const { return &m_block; }
GetPrevTimeCode() const7637*77c1e3ccSAndroid Build Coastguard Worker long long BlockGroup::GetPrevTimeCode() const { return m_prev; }
GetNextTimeCode() const7638*77c1e3ccSAndroid Build Coastguard Worker long long BlockGroup::GetNextTimeCode() const { return m_next; }
GetDurationTimeCode() const7639*77c1e3ccSAndroid Build Coastguard Worker long long BlockGroup::GetDurationTimeCode() const { return m_duration; }
7640*77c1e3ccSAndroid Build Coastguard Worker
Block(long long start,long long size_,long long discard_padding)7641*77c1e3ccSAndroid Build Coastguard Worker Block::Block(long long start, long long size_, long long discard_padding)
7642*77c1e3ccSAndroid Build Coastguard Worker : m_start(start),
7643*77c1e3ccSAndroid Build Coastguard Worker m_size(size_),
7644*77c1e3ccSAndroid Build Coastguard Worker m_track(0),
7645*77c1e3ccSAndroid Build Coastguard Worker m_timecode(-1),
7646*77c1e3ccSAndroid Build Coastguard Worker m_flags(0),
7647*77c1e3ccSAndroid Build Coastguard Worker m_frames(NULL),
7648*77c1e3ccSAndroid Build Coastguard Worker m_frame_count(-1),
7649*77c1e3ccSAndroid Build Coastguard Worker m_discard_padding(discard_padding) {}
7650*77c1e3ccSAndroid Build Coastguard Worker
~Block()7651*77c1e3ccSAndroid Build Coastguard Worker Block::~Block() { delete[] m_frames; }
7652*77c1e3ccSAndroid Build Coastguard Worker
Parse(const Cluster * pCluster)7653*77c1e3ccSAndroid Build Coastguard Worker long Block::Parse(const Cluster* pCluster) {
7654*77c1e3ccSAndroid Build Coastguard Worker if (pCluster == NULL)
7655*77c1e3ccSAndroid Build Coastguard Worker return -1;
7656*77c1e3ccSAndroid Build Coastguard Worker
7657*77c1e3ccSAndroid Build Coastguard Worker if (pCluster->m_pSegment == NULL)
7658*77c1e3ccSAndroid Build Coastguard Worker return -1;
7659*77c1e3ccSAndroid Build Coastguard Worker
7660*77c1e3ccSAndroid Build Coastguard Worker assert(m_start >= 0);
7661*77c1e3ccSAndroid Build Coastguard Worker assert(m_size >= 0);
7662*77c1e3ccSAndroid Build Coastguard Worker assert(m_track <= 0);
7663*77c1e3ccSAndroid Build Coastguard Worker assert(m_frames == NULL);
7664*77c1e3ccSAndroid Build Coastguard Worker assert(m_frame_count <= 0);
7665*77c1e3ccSAndroid Build Coastguard Worker
7666*77c1e3ccSAndroid Build Coastguard Worker long long pos = m_start;
7667*77c1e3ccSAndroid Build Coastguard Worker const long long stop = m_start + m_size;
7668*77c1e3ccSAndroid Build Coastguard Worker
7669*77c1e3ccSAndroid Build Coastguard Worker long len;
7670*77c1e3ccSAndroid Build Coastguard Worker
7671*77c1e3ccSAndroid Build Coastguard Worker IMkvReader* const pReader = pCluster->m_pSegment->m_pReader;
7672*77c1e3ccSAndroid Build Coastguard Worker
7673*77c1e3ccSAndroid Build Coastguard Worker m_track = ReadUInt(pReader, pos, len);
7674*77c1e3ccSAndroid Build Coastguard Worker
7675*77c1e3ccSAndroid Build Coastguard Worker if (m_track <= 0)
7676*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7677*77c1e3ccSAndroid Build Coastguard Worker
7678*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > stop)
7679*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7680*77c1e3ccSAndroid Build Coastguard Worker
7681*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume track number
7682*77c1e3ccSAndroid Build Coastguard Worker
7683*77c1e3ccSAndroid Build Coastguard Worker if ((stop - pos) < 2)
7684*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7685*77c1e3ccSAndroid Build Coastguard Worker
7686*77c1e3ccSAndroid Build Coastguard Worker long status;
7687*77c1e3ccSAndroid Build Coastguard Worker long long value;
7688*77c1e3ccSAndroid Build Coastguard Worker
7689*77c1e3ccSAndroid Build Coastguard Worker status = UnserializeInt(pReader, pos, 2, value);
7690*77c1e3ccSAndroid Build Coastguard Worker
7691*77c1e3ccSAndroid Build Coastguard Worker if (status)
7692*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7693*77c1e3ccSAndroid Build Coastguard Worker
7694*77c1e3ccSAndroid Build Coastguard Worker if (value < SHRT_MIN)
7695*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7696*77c1e3ccSAndroid Build Coastguard Worker
7697*77c1e3ccSAndroid Build Coastguard Worker if (value > SHRT_MAX)
7698*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7699*77c1e3ccSAndroid Build Coastguard Worker
7700*77c1e3ccSAndroid Build Coastguard Worker m_timecode = static_cast<short>(value);
7701*77c1e3ccSAndroid Build Coastguard Worker
7702*77c1e3ccSAndroid Build Coastguard Worker pos += 2;
7703*77c1e3ccSAndroid Build Coastguard Worker
7704*77c1e3ccSAndroid Build Coastguard Worker if ((stop - pos) <= 0)
7705*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7706*77c1e3ccSAndroid Build Coastguard Worker
7707*77c1e3ccSAndroid Build Coastguard Worker status = pReader->Read(pos, 1, &m_flags);
7708*77c1e3ccSAndroid Build Coastguard Worker
7709*77c1e3ccSAndroid Build Coastguard Worker if (status)
7710*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7711*77c1e3ccSAndroid Build Coastguard Worker
7712*77c1e3ccSAndroid Build Coastguard Worker const int lacing = int(m_flags & 0x06) >> 1;
7713*77c1e3ccSAndroid Build Coastguard Worker
7714*77c1e3ccSAndroid Build Coastguard Worker ++pos; // consume flags byte
7715*77c1e3ccSAndroid Build Coastguard Worker
7716*77c1e3ccSAndroid Build Coastguard Worker if (lacing == 0) { // no lacing
7717*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
7718*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7719*77c1e3ccSAndroid Build Coastguard Worker
7720*77c1e3ccSAndroid Build Coastguard Worker m_frame_count = 1;
7721*77c1e3ccSAndroid Build Coastguard Worker m_frames = new (std::nothrow) Frame[m_frame_count];
7722*77c1e3ccSAndroid Build Coastguard Worker if (m_frames == NULL)
7723*77c1e3ccSAndroid Build Coastguard Worker return -1;
7724*77c1e3ccSAndroid Build Coastguard Worker
7725*77c1e3ccSAndroid Build Coastguard Worker Frame& f = m_frames[0];
7726*77c1e3ccSAndroid Build Coastguard Worker f.pos = pos;
7727*77c1e3ccSAndroid Build Coastguard Worker
7728*77c1e3ccSAndroid Build Coastguard Worker const long long frame_size = stop - pos;
7729*77c1e3ccSAndroid Build Coastguard Worker
7730*77c1e3ccSAndroid Build Coastguard Worker if (frame_size > LONG_MAX || frame_size <= 0)
7731*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7732*77c1e3ccSAndroid Build Coastguard Worker
7733*77c1e3ccSAndroid Build Coastguard Worker f.len = static_cast<long>(frame_size);
7734*77c1e3ccSAndroid Build Coastguard Worker
7735*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
7736*77c1e3ccSAndroid Build Coastguard Worker }
7737*77c1e3ccSAndroid Build Coastguard Worker
7738*77c1e3ccSAndroid Build Coastguard Worker if (pos >= stop)
7739*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7740*77c1e3ccSAndroid Build Coastguard Worker
7741*77c1e3ccSAndroid Build Coastguard Worker unsigned char biased_count;
7742*77c1e3ccSAndroid Build Coastguard Worker
7743*77c1e3ccSAndroid Build Coastguard Worker status = pReader->Read(pos, 1, &biased_count);
7744*77c1e3ccSAndroid Build Coastguard Worker
7745*77c1e3ccSAndroid Build Coastguard Worker if (status)
7746*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7747*77c1e3ccSAndroid Build Coastguard Worker
7748*77c1e3ccSAndroid Build Coastguard Worker ++pos; // consume frame count
7749*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
7750*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7751*77c1e3ccSAndroid Build Coastguard Worker
7752*77c1e3ccSAndroid Build Coastguard Worker m_frame_count = int(biased_count) + 1;
7753*77c1e3ccSAndroid Build Coastguard Worker
7754*77c1e3ccSAndroid Build Coastguard Worker m_frames = new (std::nothrow) Frame[m_frame_count];
7755*77c1e3ccSAndroid Build Coastguard Worker if (m_frames == NULL)
7756*77c1e3ccSAndroid Build Coastguard Worker return -1;
7757*77c1e3ccSAndroid Build Coastguard Worker
7758*77c1e3ccSAndroid Build Coastguard Worker if (!m_frames)
7759*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7760*77c1e3ccSAndroid Build Coastguard Worker
7761*77c1e3ccSAndroid Build Coastguard Worker if (lacing == 1) { // Xiph
7762*77c1e3ccSAndroid Build Coastguard Worker Frame* pf = m_frames;
7763*77c1e3ccSAndroid Build Coastguard Worker Frame* const pf_end = pf + m_frame_count;
7764*77c1e3ccSAndroid Build Coastguard Worker
7765*77c1e3ccSAndroid Build Coastguard Worker long long size = 0;
7766*77c1e3ccSAndroid Build Coastguard Worker int frame_count = m_frame_count;
7767*77c1e3ccSAndroid Build Coastguard Worker
7768*77c1e3ccSAndroid Build Coastguard Worker while (frame_count > 1) {
7769*77c1e3ccSAndroid Build Coastguard Worker long frame_size = 0;
7770*77c1e3ccSAndroid Build Coastguard Worker
7771*77c1e3ccSAndroid Build Coastguard Worker for (;;) {
7772*77c1e3ccSAndroid Build Coastguard Worker unsigned char val;
7773*77c1e3ccSAndroid Build Coastguard Worker
7774*77c1e3ccSAndroid Build Coastguard Worker if (pos >= stop)
7775*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7776*77c1e3ccSAndroid Build Coastguard Worker
7777*77c1e3ccSAndroid Build Coastguard Worker status = pReader->Read(pos, 1, &val);
7778*77c1e3ccSAndroid Build Coastguard Worker
7779*77c1e3ccSAndroid Build Coastguard Worker if (status)
7780*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7781*77c1e3ccSAndroid Build Coastguard Worker
7782*77c1e3ccSAndroid Build Coastguard Worker ++pos; // consume xiph size byte
7783*77c1e3ccSAndroid Build Coastguard Worker
7784*77c1e3ccSAndroid Build Coastguard Worker frame_size += val;
7785*77c1e3ccSAndroid Build Coastguard Worker
7786*77c1e3ccSAndroid Build Coastguard Worker if (val < 255)
7787*77c1e3ccSAndroid Build Coastguard Worker break;
7788*77c1e3ccSAndroid Build Coastguard Worker }
7789*77c1e3ccSAndroid Build Coastguard Worker
7790*77c1e3ccSAndroid Build Coastguard Worker Frame& f = *pf++;
7791*77c1e3ccSAndroid Build Coastguard Worker assert(pf < pf_end);
7792*77c1e3ccSAndroid Build Coastguard Worker if (pf >= pf_end)
7793*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7794*77c1e3ccSAndroid Build Coastguard Worker
7795*77c1e3ccSAndroid Build Coastguard Worker f.pos = 0; // patch later
7796*77c1e3ccSAndroid Build Coastguard Worker
7797*77c1e3ccSAndroid Build Coastguard Worker if (frame_size <= 0)
7798*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7799*77c1e3ccSAndroid Build Coastguard Worker
7800*77c1e3ccSAndroid Build Coastguard Worker f.len = frame_size;
7801*77c1e3ccSAndroid Build Coastguard Worker size += frame_size; // contribution of this frame
7802*77c1e3ccSAndroid Build Coastguard Worker
7803*77c1e3ccSAndroid Build Coastguard Worker --frame_count;
7804*77c1e3ccSAndroid Build Coastguard Worker }
7805*77c1e3ccSAndroid Build Coastguard Worker
7806*77c1e3ccSAndroid Build Coastguard Worker if (pf >= pf_end || pos > stop)
7807*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7808*77c1e3ccSAndroid Build Coastguard Worker
7809*77c1e3ccSAndroid Build Coastguard Worker {
7810*77c1e3ccSAndroid Build Coastguard Worker Frame& f = *pf++;
7811*77c1e3ccSAndroid Build Coastguard Worker
7812*77c1e3ccSAndroid Build Coastguard Worker if (pf != pf_end)
7813*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7814*77c1e3ccSAndroid Build Coastguard Worker
7815*77c1e3ccSAndroid Build Coastguard Worker f.pos = 0; // patch later
7816*77c1e3ccSAndroid Build Coastguard Worker
7817*77c1e3ccSAndroid Build Coastguard Worker const long long total_size = stop - pos;
7818*77c1e3ccSAndroid Build Coastguard Worker
7819*77c1e3ccSAndroid Build Coastguard Worker if (total_size < size)
7820*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7821*77c1e3ccSAndroid Build Coastguard Worker
7822*77c1e3ccSAndroid Build Coastguard Worker const long long frame_size = total_size - size;
7823*77c1e3ccSAndroid Build Coastguard Worker
7824*77c1e3ccSAndroid Build Coastguard Worker if (frame_size > LONG_MAX || frame_size <= 0)
7825*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7826*77c1e3ccSAndroid Build Coastguard Worker
7827*77c1e3ccSAndroid Build Coastguard Worker f.len = static_cast<long>(frame_size);
7828*77c1e3ccSAndroid Build Coastguard Worker }
7829*77c1e3ccSAndroid Build Coastguard Worker
7830*77c1e3ccSAndroid Build Coastguard Worker pf = m_frames;
7831*77c1e3ccSAndroid Build Coastguard Worker while (pf != pf_end) {
7832*77c1e3ccSAndroid Build Coastguard Worker Frame& f = *pf++;
7833*77c1e3ccSAndroid Build Coastguard Worker assert((pos + f.len) <= stop);
7834*77c1e3ccSAndroid Build Coastguard Worker
7835*77c1e3ccSAndroid Build Coastguard Worker if ((pos + f.len) > stop)
7836*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7837*77c1e3ccSAndroid Build Coastguard Worker
7838*77c1e3ccSAndroid Build Coastguard Worker f.pos = pos;
7839*77c1e3ccSAndroid Build Coastguard Worker pos += f.len;
7840*77c1e3ccSAndroid Build Coastguard Worker }
7841*77c1e3ccSAndroid Build Coastguard Worker
7842*77c1e3ccSAndroid Build Coastguard Worker assert(pos == stop);
7843*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
7844*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7845*77c1e3ccSAndroid Build Coastguard Worker
7846*77c1e3ccSAndroid Build Coastguard Worker } else if (lacing == 2) { // fixed-size lacing
7847*77c1e3ccSAndroid Build Coastguard Worker if (pos >= stop)
7848*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7849*77c1e3ccSAndroid Build Coastguard Worker
7850*77c1e3ccSAndroid Build Coastguard Worker const long long total_size = stop - pos;
7851*77c1e3ccSAndroid Build Coastguard Worker
7852*77c1e3ccSAndroid Build Coastguard Worker if ((total_size % m_frame_count) != 0)
7853*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7854*77c1e3ccSAndroid Build Coastguard Worker
7855*77c1e3ccSAndroid Build Coastguard Worker const long long frame_size = total_size / m_frame_count;
7856*77c1e3ccSAndroid Build Coastguard Worker
7857*77c1e3ccSAndroid Build Coastguard Worker if (frame_size > LONG_MAX || frame_size <= 0)
7858*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7859*77c1e3ccSAndroid Build Coastguard Worker
7860*77c1e3ccSAndroid Build Coastguard Worker Frame* pf = m_frames;
7861*77c1e3ccSAndroid Build Coastguard Worker Frame* const pf_end = pf + m_frame_count;
7862*77c1e3ccSAndroid Build Coastguard Worker
7863*77c1e3ccSAndroid Build Coastguard Worker while (pf != pf_end) {
7864*77c1e3ccSAndroid Build Coastguard Worker assert((pos + frame_size) <= stop);
7865*77c1e3ccSAndroid Build Coastguard Worker if ((pos + frame_size) > stop)
7866*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7867*77c1e3ccSAndroid Build Coastguard Worker
7868*77c1e3ccSAndroid Build Coastguard Worker Frame& f = *pf++;
7869*77c1e3ccSAndroid Build Coastguard Worker
7870*77c1e3ccSAndroid Build Coastguard Worker f.pos = pos;
7871*77c1e3ccSAndroid Build Coastguard Worker f.len = static_cast<long>(frame_size);
7872*77c1e3ccSAndroid Build Coastguard Worker
7873*77c1e3ccSAndroid Build Coastguard Worker pos += frame_size;
7874*77c1e3ccSAndroid Build Coastguard Worker }
7875*77c1e3ccSAndroid Build Coastguard Worker
7876*77c1e3ccSAndroid Build Coastguard Worker assert(pos == stop);
7877*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
7878*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7879*77c1e3ccSAndroid Build Coastguard Worker
7880*77c1e3ccSAndroid Build Coastguard Worker } else {
7881*77c1e3ccSAndroid Build Coastguard Worker assert(lacing == 3); // EBML lacing
7882*77c1e3ccSAndroid Build Coastguard Worker
7883*77c1e3ccSAndroid Build Coastguard Worker if (pos >= stop)
7884*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7885*77c1e3ccSAndroid Build Coastguard Worker
7886*77c1e3ccSAndroid Build Coastguard Worker long long size = 0;
7887*77c1e3ccSAndroid Build Coastguard Worker int frame_count = m_frame_count;
7888*77c1e3ccSAndroid Build Coastguard Worker
7889*77c1e3ccSAndroid Build Coastguard Worker long long frame_size = ReadUInt(pReader, pos, len);
7890*77c1e3ccSAndroid Build Coastguard Worker
7891*77c1e3ccSAndroid Build Coastguard Worker if (frame_size <= 0)
7892*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7893*77c1e3ccSAndroid Build Coastguard Worker
7894*77c1e3ccSAndroid Build Coastguard Worker if (frame_size > LONG_MAX)
7895*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7896*77c1e3ccSAndroid Build Coastguard Worker
7897*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > stop)
7898*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7899*77c1e3ccSAndroid Build Coastguard Worker
7900*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of size of first frame
7901*77c1e3ccSAndroid Build Coastguard Worker
7902*77c1e3ccSAndroid Build Coastguard Worker if ((pos + frame_size) > stop)
7903*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7904*77c1e3ccSAndroid Build Coastguard Worker
7905*77c1e3ccSAndroid Build Coastguard Worker Frame* pf = m_frames;
7906*77c1e3ccSAndroid Build Coastguard Worker Frame* const pf_end = pf + m_frame_count;
7907*77c1e3ccSAndroid Build Coastguard Worker
7908*77c1e3ccSAndroid Build Coastguard Worker {
7909*77c1e3ccSAndroid Build Coastguard Worker Frame& curr = *pf;
7910*77c1e3ccSAndroid Build Coastguard Worker
7911*77c1e3ccSAndroid Build Coastguard Worker curr.pos = 0; // patch later
7912*77c1e3ccSAndroid Build Coastguard Worker
7913*77c1e3ccSAndroid Build Coastguard Worker curr.len = static_cast<long>(frame_size);
7914*77c1e3ccSAndroid Build Coastguard Worker size += curr.len; // contribution of this frame
7915*77c1e3ccSAndroid Build Coastguard Worker }
7916*77c1e3ccSAndroid Build Coastguard Worker
7917*77c1e3ccSAndroid Build Coastguard Worker --frame_count;
7918*77c1e3ccSAndroid Build Coastguard Worker
7919*77c1e3ccSAndroid Build Coastguard Worker while (frame_count > 1) {
7920*77c1e3ccSAndroid Build Coastguard Worker if (pos >= stop)
7921*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7922*77c1e3ccSAndroid Build Coastguard Worker
7923*77c1e3ccSAndroid Build Coastguard Worker assert(pf < pf_end);
7924*77c1e3ccSAndroid Build Coastguard Worker if (pf >= pf_end)
7925*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7926*77c1e3ccSAndroid Build Coastguard Worker
7927*77c1e3ccSAndroid Build Coastguard Worker const Frame& prev = *pf++;
7928*77c1e3ccSAndroid Build Coastguard Worker assert(prev.len == frame_size);
7929*77c1e3ccSAndroid Build Coastguard Worker if (prev.len != frame_size)
7930*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7931*77c1e3ccSAndroid Build Coastguard Worker
7932*77c1e3ccSAndroid Build Coastguard Worker assert(pf < pf_end);
7933*77c1e3ccSAndroid Build Coastguard Worker if (pf >= pf_end)
7934*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7935*77c1e3ccSAndroid Build Coastguard Worker
7936*77c1e3ccSAndroid Build Coastguard Worker Frame& curr = *pf;
7937*77c1e3ccSAndroid Build Coastguard Worker
7938*77c1e3ccSAndroid Build Coastguard Worker curr.pos = 0; // patch later
7939*77c1e3ccSAndroid Build Coastguard Worker
7940*77c1e3ccSAndroid Build Coastguard Worker const long long delta_size_ = ReadUInt(pReader, pos, len);
7941*77c1e3ccSAndroid Build Coastguard Worker
7942*77c1e3ccSAndroid Build Coastguard Worker if (delta_size_ < 0)
7943*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7944*77c1e3ccSAndroid Build Coastguard Worker
7945*77c1e3ccSAndroid Build Coastguard Worker if ((pos + len) > stop)
7946*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7947*77c1e3ccSAndroid Build Coastguard Worker
7948*77c1e3ccSAndroid Build Coastguard Worker pos += len; // consume length of (delta) size
7949*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop)
7950*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7951*77c1e3ccSAndroid Build Coastguard Worker
7952*77c1e3ccSAndroid Build Coastguard Worker const long exp = 7 * len - 1;
7953*77c1e3ccSAndroid Build Coastguard Worker const long long bias = (1LL << exp) - 1LL;
7954*77c1e3ccSAndroid Build Coastguard Worker const long long delta_size = delta_size_ - bias;
7955*77c1e3ccSAndroid Build Coastguard Worker
7956*77c1e3ccSAndroid Build Coastguard Worker frame_size += delta_size;
7957*77c1e3ccSAndroid Build Coastguard Worker
7958*77c1e3ccSAndroid Build Coastguard Worker if (frame_size <= 0)
7959*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7960*77c1e3ccSAndroid Build Coastguard Worker
7961*77c1e3ccSAndroid Build Coastguard Worker if (frame_size > LONG_MAX)
7962*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7963*77c1e3ccSAndroid Build Coastguard Worker
7964*77c1e3ccSAndroid Build Coastguard Worker curr.len = static_cast<long>(frame_size);
7965*77c1e3ccSAndroid Build Coastguard Worker // Check if size + curr.len could overflow.
7966*77c1e3ccSAndroid Build Coastguard Worker if (size > LLONG_MAX - curr.len) {
7967*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7968*77c1e3ccSAndroid Build Coastguard Worker }
7969*77c1e3ccSAndroid Build Coastguard Worker size += curr.len; // contribution of this frame
7970*77c1e3ccSAndroid Build Coastguard Worker
7971*77c1e3ccSAndroid Build Coastguard Worker --frame_count;
7972*77c1e3ccSAndroid Build Coastguard Worker }
7973*77c1e3ccSAndroid Build Coastguard Worker
7974*77c1e3ccSAndroid Build Coastguard Worker // parse last frame
7975*77c1e3ccSAndroid Build Coastguard Worker if (frame_count > 0) {
7976*77c1e3ccSAndroid Build Coastguard Worker if (pos > stop || pf >= pf_end)
7977*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7978*77c1e3ccSAndroid Build Coastguard Worker
7979*77c1e3ccSAndroid Build Coastguard Worker const Frame& prev = *pf++;
7980*77c1e3ccSAndroid Build Coastguard Worker assert(prev.len == frame_size);
7981*77c1e3ccSAndroid Build Coastguard Worker if (prev.len != frame_size)
7982*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7983*77c1e3ccSAndroid Build Coastguard Worker
7984*77c1e3ccSAndroid Build Coastguard Worker if (pf >= pf_end)
7985*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7986*77c1e3ccSAndroid Build Coastguard Worker
7987*77c1e3ccSAndroid Build Coastguard Worker Frame& curr = *pf++;
7988*77c1e3ccSAndroid Build Coastguard Worker if (pf != pf_end)
7989*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7990*77c1e3ccSAndroid Build Coastguard Worker
7991*77c1e3ccSAndroid Build Coastguard Worker curr.pos = 0; // patch later
7992*77c1e3ccSAndroid Build Coastguard Worker
7993*77c1e3ccSAndroid Build Coastguard Worker const long long total_size = stop - pos;
7994*77c1e3ccSAndroid Build Coastguard Worker
7995*77c1e3ccSAndroid Build Coastguard Worker if (total_size < size)
7996*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
7997*77c1e3ccSAndroid Build Coastguard Worker
7998*77c1e3ccSAndroid Build Coastguard Worker frame_size = total_size - size;
7999*77c1e3ccSAndroid Build Coastguard Worker
8000*77c1e3ccSAndroid Build Coastguard Worker if (frame_size > LONG_MAX || frame_size <= 0)
8001*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
8002*77c1e3ccSAndroid Build Coastguard Worker
8003*77c1e3ccSAndroid Build Coastguard Worker curr.len = static_cast<long>(frame_size);
8004*77c1e3ccSAndroid Build Coastguard Worker }
8005*77c1e3ccSAndroid Build Coastguard Worker
8006*77c1e3ccSAndroid Build Coastguard Worker pf = m_frames;
8007*77c1e3ccSAndroid Build Coastguard Worker while (pf != pf_end) {
8008*77c1e3ccSAndroid Build Coastguard Worker Frame& f = *pf++;
8009*77c1e3ccSAndroid Build Coastguard Worker if ((pos + f.len) > stop)
8010*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
8011*77c1e3ccSAndroid Build Coastguard Worker
8012*77c1e3ccSAndroid Build Coastguard Worker f.pos = pos;
8013*77c1e3ccSAndroid Build Coastguard Worker pos += f.len;
8014*77c1e3ccSAndroid Build Coastguard Worker }
8015*77c1e3ccSAndroid Build Coastguard Worker
8016*77c1e3ccSAndroid Build Coastguard Worker if (pos != stop)
8017*77c1e3ccSAndroid Build Coastguard Worker return E_FILE_FORMAT_INVALID;
8018*77c1e3ccSAndroid Build Coastguard Worker }
8019*77c1e3ccSAndroid Build Coastguard Worker
8020*77c1e3ccSAndroid Build Coastguard Worker return 0; // success
8021*77c1e3ccSAndroid Build Coastguard Worker }
8022*77c1e3ccSAndroid Build Coastguard Worker
GetTimeCode(const Cluster * pCluster) const8023*77c1e3ccSAndroid Build Coastguard Worker long long Block::GetTimeCode(const Cluster* pCluster) const {
8024*77c1e3ccSAndroid Build Coastguard Worker if (pCluster == 0)
8025*77c1e3ccSAndroid Build Coastguard Worker return m_timecode;
8026*77c1e3ccSAndroid Build Coastguard Worker
8027*77c1e3ccSAndroid Build Coastguard Worker const long long tc0 = pCluster->GetTimeCode();
8028*77c1e3ccSAndroid Build Coastguard Worker assert(tc0 >= 0);
8029*77c1e3ccSAndroid Build Coastguard Worker
8030*77c1e3ccSAndroid Build Coastguard Worker // Check if tc0 + m_timecode would overflow.
8031*77c1e3ccSAndroid Build Coastguard Worker if (tc0 < 0 || LLONG_MAX - tc0 < m_timecode) {
8032*77c1e3ccSAndroid Build Coastguard Worker return -1;
8033*77c1e3ccSAndroid Build Coastguard Worker }
8034*77c1e3ccSAndroid Build Coastguard Worker
8035*77c1e3ccSAndroid Build Coastguard Worker const long long tc = tc0 + m_timecode;
8036*77c1e3ccSAndroid Build Coastguard Worker
8037*77c1e3ccSAndroid Build Coastguard Worker return tc; // unscaled timecode units
8038*77c1e3ccSAndroid Build Coastguard Worker }
8039*77c1e3ccSAndroid Build Coastguard Worker
GetTime(const Cluster * pCluster) const8040*77c1e3ccSAndroid Build Coastguard Worker long long Block::GetTime(const Cluster* pCluster) const {
8041*77c1e3ccSAndroid Build Coastguard Worker assert(pCluster);
8042*77c1e3ccSAndroid Build Coastguard Worker
8043*77c1e3ccSAndroid Build Coastguard Worker const long long tc = GetTimeCode(pCluster);
8044*77c1e3ccSAndroid Build Coastguard Worker
8045*77c1e3ccSAndroid Build Coastguard Worker const Segment* const pSegment = pCluster->m_pSegment;
8046*77c1e3ccSAndroid Build Coastguard Worker const SegmentInfo* const pInfo = pSegment->GetInfo();
8047*77c1e3ccSAndroid Build Coastguard Worker assert(pInfo);
8048*77c1e3ccSAndroid Build Coastguard Worker
8049*77c1e3ccSAndroid Build Coastguard Worker const long long scale = pInfo->GetTimeCodeScale();
8050*77c1e3ccSAndroid Build Coastguard Worker assert(scale >= 1);
8051*77c1e3ccSAndroid Build Coastguard Worker
8052*77c1e3ccSAndroid Build Coastguard Worker // Check if tc * scale could overflow.
8053*77c1e3ccSAndroid Build Coastguard Worker if (tc != 0 && scale > LLONG_MAX / tc) {
8054*77c1e3ccSAndroid Build Coastguard Worker return -1;
8055*77c1e3ccSAndroid Build Coastguard Worker }
8056*77c1e3ccSAndroid Build Coastguard Worker const long long ns = tc * scale;
8057*77c1e3ccSAndroid Build Coastguard Worker
8058*77c1e3ccSAndroid Build Coastguard Worker return ns;
8059*77c1e3ccSAndroid Build Coastguard Worker }
8060*77c1e3ccSAndroid Build Coastguard Worker
GetTrackNumber() const8061*77c1e3ccSAndroid Build Coastguard Worker long long Block::GetTrackNumber() const { return m_track; }
8062*77c1e3ccSAndroid Build Coastguard Worker
IsKey() const8063*77c1e3ccSAndroid Build Coastguard Worker bool Block::IsKey() const {
8064*77c1e3ccSAndroid Build Coastguard Worker return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
8065*77c1e3ccSAndroid Build Coastguard Worker }
8066*77c1e3ccSAndroid Build Coastguard Worker
SetKey(bool bKey)8067*77c1e3ccSAndroid Build Coastguard Worker void Block::SetKey(bool bKey) {
8068*77c1e3ccSAndroid Build Coastguard Worker if (bKey)
8069*77c1e3ccSAndroid Build Coastguard Worker m_flags |= static_cast<unsigned char>(1 << 7);
8070*77c1e3ccSAndroid Build Coastguard Worker else
8071*77c1e3ccSAndroid Build Coastguard Worker m_flags &= 0x7F;
8072*77c1e3ccSAndroid Build Coastguard Worker }
8073*77c1e3ccSAndroid Build Coastguard Worker
IsInvisible() const8074*77c1e3ccSAndroid Build Coastguard Worker bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); }
8075*77c1e3ccSAndroid Build Coastguard Worker
GetLacing() const8076*77c1e3ccSAndroid Build Coastguard Worker Block::Lacing Block::GetLacing() const {
8077*77c1e3ccSAndroid Build Coastguard Worker const int value = int(m_flags & 0x06) >> 1;
8078*77c1e3ccSAndroid Build Coastguard Worker return static_cast<Lacing>(value);
8079*77c1e3ccSAndroid Build Coastguard Worker }
8080*77c1e3ccSAndroid Build Coastguard Worker
GetFrameCount() const8081*77c1e3ccSAndroid Build Coastguard Worker int Block::GetFrameCount() const { return m_frame_count; }
8082*77c1e3ccSAndroid Build Coastguard Worker
GetFrame(int idx) const8083*77c1e3ccSAndroid Build Coastguard Worker const Block::Frame& Block::GetFrame(int idx) const {
8084*77c1e3ccSAndroid Build Coastguard Worker assert(idx >= 0);
8085*77c1e3ccSAndroid Build Coastguard Worker assert(idx < m_frame_count);
8086*77c1e3ccSAndroid Build Coastguard Worker
8087*77c1e3ccSAndroid Build Coastguard Worker const Frame& f = m_frames[idx];
8088*77c1e3ccSAndroid Build Coastguard Worker assert(f.pos > 0);
8089*77c1e3ccSAndroid Build Coastguard Worker assert(f.len > 0);
8090*77c1e3ccSAndroid Build Coastguard Worker
8091*77c1e3ccSAndroid Build Coastguard Worker return f;
8092*77c1e3ccSAndroid Build Coastguard Worker }
8093*77c1e3ccSAndroid Build Coastguard Worker
Read(IMkvReader * pReader,unsigned char * buf) const8094*77c1e3ccSAndroid Build Coastguard Worker long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const {
8095*77c1e3ccSAndroid Build Coastguard Worker assert(pReader);
8096*77c1e3ccSAndroid Build Coastguard Worker assert(buf);
8097*77c1e3ccSAndroid Build Coastguard Worker
8098*77c1e3ccSAndroid Build Coastguard Worker const long status = pReader->Read(pos, len, buf);
8099*77c1e3ccSAndroid Build Coastguard Worker return status;
8100*77c1e3ccSAndroid Build Coastguard Worker }
8101*77c1e3ccSAndroid Build Coastguard Worker
GetDiscardPadding() const8102*77c1e3ccSAndroid Build Coastguard Worker long long Block::GetDiscardPadding() const { return m_discard_padding; }
8103*77c1e3ccSAndroid Build Coastguard Worker
8104*77c1e3ccSAndroid Build Coastguard Worker } // namespace mkvparser
8105