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