/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 | | |