Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/gtest/mp4_demuxer/TestParser.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "gtest/gtest.h"
7
#include "MediaData.h"
8
#include "mozilla/ArrayUtils.h"
9
#include "mozilla/Preferences.h"
10
#include "BufferStream.h"
11
#include "MP4Metadata.h"
12
#include "MoofParser.h"
13
14
class TestStream;
15
namespace mozilla {
16
DDLoggedTypeNameAndBase(::TestStream, ByteStream);
17
} // namespace mozilla
18
19
using namespace mozilla;
20
21
static const uint32_t E = MP4Metadata::NumberTracksError();
22
23
class TestStream
24
  : public ByteStream
25
  , public DecoderDoctorLifeLogger<TestStream>
26
{
27
public:
28
  TestStream(const uint8_t* aBuffer, size_t aSize)
29
    : mHighestSuccessfulEndOffset(0)
30
    , mBuffer(aBuffer)
31
    , mSize(aSize)
32
0
  {
33
0
  }
34
  bool ReadAt(int64_t aOffset, void* aData, size_t aLength,
35
              size_t* aBytesRead) override
36
0
  {
37
0
    if (aOffset < 0 || aOffset > static_cast<int64_t>(mSize)) {
38
0
      return false;
39
0
    }
40
0
    // After the test, 0 <= aOffset <= mSize <= SIZE_MAX, so it's safe to cast to size_t.
41
0
    size_t offset = static_cast<size_t>(aOffset);
42
0
    // Don't read past the end (but it's not an error to try).
43
0
    if (aLength > mSize - offset) {
44
0
      aLength = mSize - offset;
45
0
    }
46
0
    // Now, 0 <= offset <= offset + aLength <= mSize <= SIZE_MAX.
47
0
    *aBytesRead = aLength;
48
0
    memcpy(aData, mBuffer + offset, aLength);
49
0
    if (mHighestSuccessfulEndOffset < offset + aLength)
50
0
    {
51
0
      mHighestSuccessfulEndOffset = offset + aLength;
52
0
    }
53
0
    return true;
54
0
  }
55
  bool CachedReadAt(int64_t aOffset, void* aData, size_t aLength,
56
                    size_t* aBytesRead) override
57
0
  {
58
0
    return ReadAt(aOffset, aData, aLength, aBytesRead);
59
0
  }
60
  bool Length(int64_t* aLength) override
61
0
  {
62
0
    *aLength = mSize;
63
0
    return true;
64
0
  }
65
  void DiscardBefore(int64_t aOffset) override
66
0
  {
67
0
  }
68
69
  // Offset past the last character ever read. 0 when nothing read yet.
70
  size_t mHighestSuccessfulEndOffset;
71
protected:
72
  virtual ~TestStream()
73
0
  {
74
0
  }
75
76
  const uint8_t* mBuffer;
77
  size_t mSize;
78
};
79
80
TEST(MP4Metadata, EmptyStream)
81
0
{
82
0
  RefPtr<ByteStream> stream = new TestStream(nullptr, 0);
83
0
84
0
  MP4Metadata::ResultAndByteBuffer metadataBuffer =
85
0
    MP4Metadata::Metadata(stream);
86
0
  EXPECT_TRUE(NS_OK != metadataBuffer.Result());
87
0
  EXPECT_FALSE(static_cast<bool>(metadataBuffer.Ref()));
88
0
89
0
  MP4Metadata metadata(stream);
90
0
  EXPECT_TRUE(0u == metadata.GetNumberTracks(TrackInfo::kUndefinedTrack).Ref() ||
91
0
              E == metadata.GetNumberTracks(TrackInfo::kUndefinedTrack).Ref());
92
0
  EXPECT_TRUE(0u == metadata.GetNumberTracks(TrackInfo::kAudioTrack).Ref() ||
93
0
              E == metadata.GetNumberTracks(TrackInfo::kAudioTrack).Ref());
94
0
  EXPECT_TRUE(0u == metadata.GetNumberTracks(TrackInfo::kVideoTrack).Ref() ||
95
0
              E == metadata.GetNumberTracks(TrackInfo::kVideoTrack).Ref());
96
0
  EXPECT_TRUE(0u == metadata.GetNumberTracks(TrackInfo::kTextTrack).Ref() ||
97
0
              E == metadata.GetNumberTracks(TrackInfo::kTextTrack).Ref());
98
0
  EXPECT_FALSE(metadata.GetTrackInfo(TrackInfo::kAudioTrack, 0).Ref());
99
0
  EXPECT_FALSE(metadata.GetTrackInfo(TrackInfo::kVideoTrack, 0).Ref());
100
0
  EXPECT_FALSE(metadata.GetTrackInfo(TrackInfo::kTextTrack, 0).Ref());
101
0
  // We can seek anywhere in any MPEG4.
102
0
  EXPECT_TRUE(metadata.CanSeek());
103
0
  EXPECT_FALSE(metadata.Crypto().Ref()->valid);
104
0
}
105
106
TEST(MoofParser, EmptyStream)
107
0
{
108
0
  RefPtr<ByteStream> stream = new TestStream(nullptr, 0);
109
0
110
0
  MoofParser parser(stream, 0, false);
111
0
  EXPECT_EQ(0u, parser.mOffset);
112
0
  EXPECT_TRUE(parser.ReachedEnd());
113
0
114
0
  MediaByteRangeSet byteRanges;
115
0
  EXPECT_FALSE(parser.RebuildFragmentedIndex(byteRanges));
116
0
117
0
  EXPECT_TRUE(parser.GetCompositionRange(byteRanges).IsNull());
118
0
  EXPECT_TRUE(parser.mInitRange.IsEmpty());
119
0
  EXPECT_EQ(0u, parser.mOffset);
120
0
  EXPECT_TRUE(parser.ReachedEnd());
121
0
  RefPtr<MediaByteBuffer> metadataBuffer = parser.Metadata();
122
0
  EXPECT_FALSE(metadataBuffer);
123
0
  EXPECT_TRUE(parser.FirstCompleteMediaSegment().IsEmpty());
124
0
  EXPECT_TRUE(parser.FirstCompleteMediaHeader().IsEmpty());
125
0
}
126
127
nsTArray<uint8_t>
128
ReadTestFile(const char* aFilename)
129
0
{
130
0
  if (!aFilename) {
131
0
    return {};
132
0
  }
133
0
  FILE* f = fopen(aFilename, "rb");
134
0
  if (!f) {
135
0
    return {};
136
0
   }
137
0
138
0
  if (fseek(f, 0, SEEK_END) != 0) {
139
0
    fclose(f);
140
0
    return {};
141
0
  }
142
0
  long position = ftell(f);
143
0
  // I know EOF==-1, so this test is made obsolete by '<0', but I don't want
144
0
  // the code to rely on that.
145
0
  if (position == 0 || position == EOF || position < 0) {
146
0
    fclose(f);
147
0
    return {};
148
0
  }
149
0
  if (fseek(f, 0, SEEK_SET) != 0) {
150
0
    fclose(f);
151
0
    return {};
152
0
  }
153
0
154
0
  size_t len = static_cast<size_t>(position);
155
0
  nsTArray<uint8_t> buffer(len);
156
0
  buffer.SetLength(len);
157
0
  size_t read = fread(buffer.Elements(), 1, len, f);
158
0
  fclose(f);
159
0
  if (read != len) {
160
0
    return {};
161
0
  }
162
0
163
0
  return buffer;
164
0
}
165
166
struct TestFileData
167
{
168
  const char* mFilename;
169
  bool mParseResult;
170
  uint32_t mNumberVideoTracks;
171
  bool mHasVideoIndice;
172
  int64_t mVideoDuration; // For first video track, -1 if N/A.
173
  int32_t mWidth;
174
  int32_t mHeight;
175
  uint32_t mNumberAudioTracks;
176
  int64_t mAudioDuration; // For first audio track, -1 if N/A.
177
  bool mHasCrypto;
178
  uint64_t mMoofReachedOffset; // or 0 for the end.
179
  bool mValidMoof;
180
  bool mHeader;
181
  int8_t mAudioProfile;
182
};
183
184
static const TestFileData testFiles[] = {
185
  // filename                     parse #V dur   w    h  #A dur  crypt  off   moof  headr  audio_profile
186
  { "test_case_1156505.mp4",      false, 0, false, -1,   0,   0, 0, -1, false, 152, false, false, 0 },  // invalid ''trak box
187
  { "test_case_1181213.mp4",      true, 1, true, 416666,
188
                                           320, 240, 1, 477460,
189
                                                             true,   0, false, false, 2 },
190
  { "test_case_1181215.mp4",      true, 0, false, -1,   0,   0, 0, -1, false,   0, false, false, 0 },
191
  { "test_case_1181220.mp4",      false, 0, false, -1,   0,   0, 0, -1, false,   0, false, false, 0 },  // invalid audio 'sinf' box
192
  { "test_case_1181223.mp4",      false, 0, false, 416666,
193
                                           320, 240, 0, -1, false,   0, false, false, 0 },
194
  { "test_case_1181719.mp4",      false, 0, false, -1,   0,   0, 0, -1, false,   0, false, false, 0 },
195
  { "test_case_1185230.mp4",      true, 2, true, 416666,
196
                                           320, 240, 2,  5, false,   0, false, false, 2 },
197
  { "test_case_1187067.mp4",      true, 1, true, 80000,
198
                                           160,  90, 0, -1, false,   0, false, false, 0 },
199
  { "test_case_1200326.mp4",      false, 0, false, -1,   0,   0, 0, -1, false,   0, false, false, 0 },
200
  { "test_case_1204580.mp4",      true, 1, true, 502500,
201
                                           320, 180, 0, -1, false,   0, false, false, 0 },
202
  { "test_case_1216748.mp4",      false, 0, false, -1,   0,   0, 0, -1, false, 152, false, false, 0 },  // invalid 'trak' box
203
  { "test_case_1296473.mp4",      false, 0, false, -1,   0,   0, 0, -1, false,   0, false, false, 0 },
204
  { "test_case_1296532.mp4",      true, 1, true, 5589333,
205
                                           560, 320, 1, 5589333,
206
                                                            true,    0, true,  true,  2  },
207
  { "test_case_1301065.mp4",      true, 0, false, -1,   0,   0, 1, 100079991719000000,
208
                                                            false,   0, false, false, 2 },
209
  { "test_case_1301065-u32max.mp4", true, 0, false, -1,   0,   0, 1, 97391548639,
210
                                                            false,   0, false, false, 2 },
211
  { "test_case_1301065-max-ez.mp4", true, 0, false, -1,   0,   0, 1, 209146758205306,
212
                                                            false,   0, false, false, 2 },
213
  { "test_case_1301065-harder.mp4", true, 0, false, -1,   0,   0, 1, 209146758205328,
214
                                                            false,   0, false, false, 2 },
215
  { "test_case_1301065-max-ok.mp4", true, 0, false, -1,   0,   0, 1, 9223372036854775804,
216
                                                            false,   0, false, false, 2 },
217
  // The duration is overflow for int64_t in TestFileData, parser uses uint64_t so
218
  // this file is ignore.
219
  //{ "test_case_1301065-overfl.mp4", 0, -1,   0,   0, 1, 9223372036854775827,
220
  //                                                          false,   0, false, false, 2 },
221
  { "test_case_1301065-i64max.mp4", true, 0, false, -1,   0,   0, 0, -1, false,   0, false, false, 0 },
222
  { "test_case_1301065-i64min.mp4", true, 0, false, -1,   0,   0, 0, -1, false,   0, false, false, 0 },
223
  { "test_case_1301065-u64max.mp4", true, 0, false, -1,   0,   0, 1,  0, false,   0, false, false, 2 },
224
  { "test_case_1329061.mov",        false, 0, false, -1,   0,   0, 1,  234567981,
225
                                                            false,   0, false, false, 2 },
226
  { "test_case_1351094.mp4",        true, 0, false, -1,   0,   0, 0, -1, false,   0, true,  true,  0 },
227
  { "test_case_1389299.mp4",        true, 1, true, 5589333,
228
                                           560, 320, 1, 5589333,
229
                                                            true,    0, true,  true,  2  },
230
231
  { "test_case_1389527.mp4",        true, 1, false, 5005000,
232
                                            80, 128, 1, 4992000, false,   0, false, false, 2 },
233
  { "test_case_1395244.mp4",        true, 1, true, 416666,
234
                                           320, 240, 1,477460, false,0, false, false, 2 },
235
  { "test_case_1388991.mp4",        true, 0, false, -1, 0, 0, 1, 30000181, false, 0, false, false, 2 },
236
  { "test_case_1380468.mp4",        false, 0, false,  0,   0,   0, 0,  0, false,   0, false, false, 0 },
237
  { "test_case_1410565.mp4",        false, 0, false, 0, 0, 0, 0, 0, false, 955100, true, true, 2 },    // negative 'timescale'
238
};
239
240
TEST(MP4Metadata, test_case_mp4)
241
0
{
242
0
  const TestFileData* tests = nullptr;
243
0
  size_t length = 0;
244
0
245
0
  tests = testFiles;
246
0
  length = ArrayLength(testFiles);
247
0
248
0
  for (size_t test = 0; test < length; ++test) {
249
0
    nsTArray<uint8_t> buffer = ReadTestFile(tests[test].mFilename);
250
0
    ASSERT_FALSE(buffer.IsEmpty());
251
0
    RefPtr<ByteStream> stream = new TestStream(buffer.Elements(), buffer.Length());
252
0
253
0
    MP4Metadata::ResultAndByteBuffer metadataBuffer =
254
0
      MP4Metadata::Metadata(stream);
255
0
    EXPECT_EQ(NS_OK, metadataBuffer.Result());
256
0
    EXPECT_TRUE(metadataBuffer.Ref());
257
0
258
0
    MP4Metadata metadata(stream);
259
0
    nsresult res = metadata.Parse();
260
0
    EXPECT_EQ(tests[test].mParseResult, NS_SUCCEEDED(res)) << tests[test].mFilename;
261
0
    if (!tests[test].mParseResult) {
262
0
      continue;
263
0
    }
264
0
265
0
    EXPECT_EQ(tests[test].mNumberAudioTracks,
266
0
              metadata.GetNumberTracks(TrackInfo::kAudioTrack).Ref())
267
0
      << tests[test].mFilename;
268
0
    EXPECT_EQ(tests[test].mNumberVideoTracks,
269
0
              metadata.GetNumberTracks(TrackInfo::kVideoTrack).Ref())
270
0
      << tests[test].mFilename;
271
0
    // If there is an error, we should expect an error code instead of zero
272
0
    // for non-Audio/Video tracks.
273
0
    const uint32_t None = (tests[test].mNumberVideoTracks == E) ? E : 0;
274
0
    EXPECT_EQ(None, metadata.GetNumberTracks(TrackInfo::kUndefinedTrack).Ref())
275
0
      << tests[test].mFilename;
276
0
    EXPECT_EQ(None, metadata.GetNumberTracks(TrackInfo::kTextTrack).Ref())
277
0
      << tests[test].mFilename;
278
0
    EXPECT_FALSE(metadata.GetTrackInfo(TrackInfo::kUndefinedTrack, 0).Ref());
279
0
    MP4Metadata::ResultAndTrackInfo trackInfo =
280
0
      metadata.GetTrackInfo(TrackInfo::kVideoTrack, 0);
281
0
    if (!!tests[test].mNumberVideoTracks) {
282
0
      ASSERT_TRUE(!!trackInfo.Ref());
283
0
      const VideoInfo* videoInfo = trackInfo.Ref()->GetAsVideoInfo();
284
0
      ASSERT_TRUE(!!videoInfo);
285
0
      EXPECT_TRUE(videoInfo->IsValid()) << tests[test].mFilename;
286
0
      EXPECT_TRUE(videoInfo->IsVideo()) << tests[test].mFilename;
287
0
      EXPECT_EQ(tests[test].mVideoDuration,
288
0
                videoInfo->mDuration.ToMicroseconds()) << tests[test].mFilename;
289
0
      EXPECT_EQ(tests[test].mWidth, videoInfo->mDisplay.width) << tests[test].mFilename;
290
0
      EXPECT_EQ(tests[test].mHeight, videoInfo->mDisplay.height) << tests[test].mFilename;
291
0
292
0
      MP4Metadata::ResultAndIndice indices =
293
0
        metadata.GetTrackIndice(videoInfo->mTrackId);
294
0
      EXPECT_EQ(!!indices.Ref(), tests[test].mHasVideoIndice) << tests[test].mFilename;
295
0
      if (tests[test].mHasVideoIndice) {
296
0
        for (size_t i = 0; i < indices.Ref()->Length(); i++) {
297
0
          Index::Indice data;
298
0
          EXPECT_TRUE(indices.Ref()->GetIndice(i, data)) << tests[test].mFilename;
299
0
          EXPECT_TRUE(data.start_offset <= data.end_offset) << tests[test].mFilename;
300
0
          EXPECT_TRUE(data.start_composition <= data.end_composition) << tests[test].mFilename;
301
0
        }
302
0
      }
303
0
    }
304
0
    trackInfo = metadata.GetTrackInfo(TrackInfo::kAudioTrack, 0);
305
0
    if (tests[test].mNumberAudioTracks == 0 ||
306
0
        tests[test].mNumberAudioTracks == E) {
307
0
      EXPECT_TRUE(!trackInfo.Ref()) << tests[test].mFilename;
308
0
    } else {
309
0
      ASSERT_TRUE(!!trackInfo.Ref());
310
0
      const AudioInfo* audioInfo = trackInfo.Ref()->GetAsAudioInfo();
311
0
      ASSERT_TRUE(!!audioInfo);
312
0
      EXPECT_TRUE(audioInfo->IsValid()) << tests[test].mFilename;
313
0
      EXPECT_TRUE(audioInfo->IsAudio()) << tests[test].mFilename;
314
0
      EXPECT_EQ(tests[test].mAudioDuration,
315
0
                audioInfo->mDuration.ToMicroseconds()) << tests[test].mFilename;
316
0
      EXPECT_EQ(tests[test].mAudioProfile, audioInfo->mProfile) << tests[test].mFilename;
317
0
      if (tests[test].mAudioDuration !=
318
0
          audioInfo->mDuration.ToMicroseconds()) {
319
0
        MOZ_RELEASE_ASSERT(false);
320
0
      }
321
0
322
0
      MP4Metadata::ResultAndIndice indices =
323
0
        metadata.GetTrackIndice(audioInfo->mTrackId);
324
0
      EXPECT_TRUE(!!indices.Ref()) << tests[test].mFilename;
325
0
      for (size_t i = 0; i < indices.Ref()->Length(); i++) {
326
0
        Index::Indice data;
327
0
        EXPECT_TRUE(indices.Ref()->GetIndice(i, data)) << tests[test].mFilename;
328
0
        EXPECT_TRUE(data.start_offset <= data.end_offset) << tests[test].mFilename;
329
0
        EXPECT_TRUE(int64_t(data.start_composition) <= int64_t(data.end_composition)) << tests[test].mFilename;
330
0
      }
331
0
    }
332
0
    EXPECT_FALSE(metadata.GetTrackInfo(TrackInfo::kTextTrack, 0).Ref()) << tests[test].mFilename;
333
0
    // We can see anywhere in any MPEG4.
334
0
    EXPECT_TRUE(metadata.CanSeek()) << tests[test].mFilename;
335
0
    EXPECT_EQ(tests[test].mHasCrypto, metadata.Crypto().Ref()->valid) << tests[test].mFilename;
336
0
  }
337
0
}
338
339
// Bug 1224019: This test produces way to much output, disabling for now.
340
#if 0
341
TEST(MPEG4Metadata, test_case_mp4_subsets)
342
{
343
  static const size_t step = 1u;
344
  for (size_t test = 0; test < ArrayLength(testFiles); ++test) {
345
    nsTArray<uint8_t> buffer = ReadTestFile(testFiles[test].mFilename);
346
    ASSERT_FALSE(buffer.IsEmpty());
347
    ASSERT_LE(step, buffer.Length());
348
    // Just exercizing the parser starting at different points through the file,
349
    // making sure it doesn't crash.
350
    // No checks because results would differ for each position.
351
    for (size_t offset = 0; offset < buffer.Length() - step; offset += step) {
352
      size_t size = buffer.Length() - offset;
353
      while (size > 0) {
354
        RefPtr<TestStream> stream =
355
          new TestStream(buffer.Elements() + offset, size);
356
357
        MP4Metadata::ResultAndByteBuffer metadataBuffer =
358
          MP4Metadata::Metadata(stream);
359
        MP4Metadata metadata(stream);
360
361
        if (stream->mHighestSuccessfulEndOffset <= 0) {
362
          // No successful reads -> Cutting down the size won't change anything.
363
          break;
364
        }
365
        if (stream->mHighestSuccessfulEndOffset < size) {
366
          // Read up to a point before the end -> Resize down to that point.
367
          size = stream->mHighestSuccessfulEndOffset;
368
        } else {
369
          // Read up to the end (or after?!) -> Just cut 1 byte.
370
          size -= 1;
371
        }
372
      }
373
    }
374
  }
375
}
376
#endif
377
378
TEST(MoofParser, test_case_mp4)
379
0
{
380
0
  const TestFileData* tests = nullptr;
381
0
  size_t length = 0;
382
0
383
0
  tests = testFiles;
384
0
  length = ArrayLength(testFiles);
385
0
386
0
  for (size_t test = 0; test < length; ++test) {
387
0
    nsTArray<uint8_t> buffer = ReadTestFile(tests[test].mFilename);
388
0
    ASSERT_FALSE(buffer.IsEmpty());
389
0
    RefPtr<ByteStream> stream = new TestStream(buffer.Elements(), buffer.Length());
390
0
391
0
    MoofParser parser(stream, 0, false);
392
0
    EXPECT_EQ(0u, parser.mOffset) << tests[test].mFilename;
393
0
    EXPECT_FALSE(parser.ReachedEnd()) << tests[test].mFilename;
394
0
    EXPECT_TRUE(parser.mInitRange.IsEmpty()) << tests[test].mFilename;
395
0
396
0
    RefPtr<MediaByteBuffer> metadataBuffer = parser.Metadata();
397
0
    EXPECT_TRUE(metadataBuffer) << tests[test].mFilename;
398
0
399
0
    EXPECT_FALSE(parser.mInitRange.IsEmpty()) << tests[test].mFilename;
400
0
    const MediaByteRangeSet byteRanges(
401
0
      MediaByteRange(0, int64_t(buffer.Length())));
402
0
    EXPECT_EQ(tests[test].mValidMoof,
403
0
              parser.RebuildFragmentedIndex(byteRanges))  << tests[test].mFilename;
404
0
    if (tests[test].mMoofReachedOffset == 0) {
405
0
      EXPECT_EQ(buffer.Length(), parser.mOffset) << tests[test].mFilename;
406
0
      EXPECT_TRUE(parser.ReachedEnd()) << tests[test].mFilename;
407
0
    } else {
408
0
      EXPECT_EQ(tests[test].mMoofReachedOffset, parser.mOffset) << tests[test].mFilename;
409
0
      EXPECT_FALSE(parser.ReachedEnd()) << tests[test].mFilename;
410
0
    }
411
0
412
0
    EXPECT_FALSE(parser.mInitRange.IsEmpty()) << tests[test].mFilename;
413
0
    EXPECT_TRUE(parser.GetCompositionRange(byteRanges).IsNull()) << tests[test].mFilename;
414
0
    EXPECT_TRUE(parser.FirstCompleteMediaSegment().IsEmpty()) << tests[test].mFilename;
415
0
    EXPECT_EQ(tests[test].mHeader,
416
0
              !parser.FirstCompleteMediaHeader().IsEmpty()) << tests[test].mFilename;
417
0
  }
418
0
}
419
420
// Bug 1224019: This test produces way to much output, disabling for now.
421
#if 0
422
TEST(MoofParser, test_case_mp4_subsets)
423
{
424
  const size_t step = 1u;
425
  for (size_t test = 0; test < ArrayLength(testFiles); ++test) {
426
    nsTArray<uint8_t> buffer = ReadTestFile(testFiles[test].mFilename);
427
    ASSERT_FALSE(buffer.IsEmpty());
428
    ASSERT_LE(step, buffer.Length());
429
    // Just exercizing the parser starting at different points through the file,
430
    // making sure it doesn't crash.
431
    // No checks because results would differ for each position.
432
    for (size_t offset = 0; offset < buffer.Length() - step; offset += step) {
433
      size_t size = buffer.Length() - offset;
434
      while (size > 0) {
435
        RefPtr<TestStream> stream =
436
          new TestStream(buffer.Elements() + offset, size);
437
438
        MoofParser parser(stream, 0, false);
439
        MediaByteRangeSet byteRanges;
440
        EXPECT_FALSE(parser.RebuildFragmentedIndex(byteRanges));
441
        parser.GetCompositionRange(byteRanges);
442
        RefPtr<MediaByteBuffer> metadataBuffer = parser.Metadata();
443
        parser.FirstCompleteMediaSegment();
444
        parser.FirstCompleteMediaHeader();
445
446
        if (stream->mHighestSuccessfulEndOffset <= 0) {
447
          // No successful reads -> Cutting down the size won't change anything.
448
          break;
449
        }
450
        if (stream->mHighestSuccessfulEndOffset < size) {
451
          // Read up to a point before the end -> Resize down to that point.
452
          size = stream->mHighestSuccessfulEndOffset;
453
        } else {
454
          // Read up to the end (or after?!) -> Just cut 1 byte.
455
          size -= 1;
456
        }
457
      }
458
    }
459
  }
460
}
461
#endif
462
463
uint8_t media_gtest_video_init_mp4[] = {
464
  0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6f, 0x6d,
465
  0x00, 0x00, 0x00, 0x01, 0x69, 0x73, 0x6f, 0x6d, 0x61, 0x76, 0x63, 0x31,
466
  0x00, 0x00, 0x02, 0xd1, 0x6d, 0x6f, 0x6f, 0x76, 0x00, 0x00, 0x00, 0x6c,
467
  0x6d, 0x76, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x49, 0x73, 0xf8,
468
  0xc8, 0x4a, 0xc5, 0x7a, 0x00, 0x00, 0x02, 0x58, 0x00, 0x00, 0x00, 0x00,
469
  0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
470
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
471
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
472
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
473
  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
474
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18,
476
  0x69, 0x6f, 0x64, 0x73, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x80, 0x80,
477
  0x07, 0x00, 0x4f, 0xff, 0xff, 0x29, 0x15, 0xff, 0x00, 0x00, 0x02, 0x0d,
478
  0x74, 0x72, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x5c, 0x74, 0x6b, 0x68, 0x64,
479
  0x00, 0x00, 0x00, 0x01, 0xc8, 0x49, 0x73, 0xf8, 0xc8, 0x49, 0x73, 0xf9,
480
  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
484
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485
  0x40, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00,
486
  0x00, 0x00, 0x01, 0xa9, 0x6d, 0x64, 0x69, 0x61, 0x00, 0x00, 0x00, 0x20,
487
  0x6d, 0x64, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x49, 0x73, 0xf8,
488
  0xc8, 0x49, 0x73, 0xf9, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0x00, 0x00,
489
  0x55, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x68, 0x64, 0x6c, 0x72,
490
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x64, 0x65,
491
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492
  0x47, 0x50, 0x41, 0x43, 0x20, 0x49, 0x53, 0x4f, 0x20, 0x56, 0x69, 0x64,
493
  0x65, 0x6f, 0x20, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00, 0x00,
494
  0x00, 0x00, 0x01, 0x49, 0x6d, 0x69, 0x6e, 0x66, 0x00, 0x00, 0x00, 0x14,
495
  0x76, 0x6d, 0x68, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
496
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x64, 0x69, 0x6e, 0x66,
497
  0x00, 0x00, 0x00, 0x1c, 0x64, 0x72, 0x65, 0x66, 0x00, 0x00, 0x00, 0x00,
498
  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x75, 0x72, 0x6c, 0x20,
499
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0x73, 0x74, 0x62, 0x6c,
500
  0x00, 0x00, 0x00, 0xad, 0x73, 0x74, 0x73, 0x64, 0x00, 0x00, 0x00, 0x00,
501
  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9d, 0x61, 0x76, 0x63, 0x31,
502
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
503
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
504
  0x02, 0x80, 0x01, 0x68, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00,
505
  0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
506
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508
  0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x33, 0x61, 0x76,
509
  0x63, 0x43, 0x01, 0x64, 0x00, 0x1f, 0xff, 0xe1, 0x00, 0x1b, 0x67, 0x64,
510
  0x00, 0x1f, 0xac, 0x2c, 0xc5, 0x02, 0x80, 0xbf, 0xe5, 0xc0, 0x44, 0x00,
511
  0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0xf2, 0x3c, 0x60, 0xc6,
512
  0x58, 0x01, 0x00, 0x05, 0x68, 0xe9, 0x2b, 0x2c, 0x8b, 0x00, 0x00, 0x00,
513
  0x14, 0x62, 0x74, 0x72, 0x74, 0x00, 0x01, 0x5a, 0xc2, 0x00, 0x24, 0x74,
514
  0x38, 0x00, 0x09, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10, 0x73, 0x74, 0x74,
515
  0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
516
  0x10, 0x63, 0x74, 0x74, 0x73, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517
  0x00, 0x00, 0x00, 0x00, 0x10, 0x73, 0x74, 0x73, 0x63, 0x00, 0x00, 0x00,
518
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x73, 0x74, 0x73,
519
  0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520
  0x00, 0x00, 0x00, 0x00, 0x10, 0x73, 0x74, 0x63, 0x6f, 0x00, 0x00, 0x00,
521
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6d, 0x76, 0x65,
522
  0x78, 0x00, 0x00, 0x00, 0x10, 0x6d, 0x65, 0x68, 0x64, 0x00, 0x00, 0x00,
523
  0x00, 0x00, 0x05, 0x76, 0x18, 0x00, 0x00, 0x00, 0x20, 0x74, 0x72, 0x65,
524
  0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
525
  0x01, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
526
  0x00
527
};
528
529
const uint32_t media_gtest_video_init_mp4_len = 745;
530
531
TEST(MP4Metadata, EmptyCTTS)
532
0
{
533
0
  RefPtr<MediaByteBuffer> buffer = new MediaByteBuffer(media_gtest_video_init_mp4_len);
534
0
  buffer->AppendElements(media_gtest_video_init_mp4, media_gtest_video_init_mp4_len);
535
0
  RefPtr<BufferStream> stream = new BufferStream(buffer);
536
0
537
0
  MP4Metadata::ResultAndByteBuffer metadataBuffer =
538
0
    MP4Metadata::Metadata(stream);
539
0
  EXPECT_EQ(NS_OK, metadataBuffer.Result());
540
0
  EXPECT_TRUE(metadataBuffer.Ref());
541
0
542
0
  MP4Metadata metadata(stream);
543
0
  EXPECT_EQ(metadata.Parse(), NS_OK);
544
0
  EXPECT_EQ(1u, metadata.GetNumberTracks(TrackInfo::kVideoTrack).Ref());
545
0
  MP4Metadata::ResultAndTrackInfo track = metadata.GetTrackInfo(TrackInfo::kVideoTrack, 0);
546
0
  EXPECT_TRUE(track.Ref() != nullptr);
547
0
  // We can seek anywhere in any MPEG4.
548
0
  EXPECT_TRUE(metadata.CanSeek());
549
0
  EXPECT_FALSE(metadata.Crypto().Ref()->valid);
550
0
}
551