TEST(rust, MP4MetadataEmpty) { mp4parse_error rv; mp4parse_io io; // Shouldn't be able to read with no context. rv = mp4parse_read(nullptr); EXPECT_EQ(rv, MP4PARSE_ERROR_BADARG); // Shouldn't be able to wrap an mp4parse_io with null members. io = { nullptr, nullptr }; mp4parse_parser* context = mp4parse_new(&io); EXPECT_EQ(context, nullptr); io = { nullptr, &io }; context = mp4parse_new(&io); EXPECT_EQ(context, nullptr); // FIXME: this should probably be accepted. io = { error_reader, nullptr }; context = mp4parse_new(&io); EXPECT_EQ(context, nullptr); // Read method errors should propagate. io = { error_reader, &io }; context = mp4parse_new(&io); ASSERT_NE(context, nullptr); rv = mp4parse_read(context); EXPECT_EQ(rv, MP4PARSE_ERROR_IO); mp4parse_free(context); // Short buffers should fail. read_vector buf(0); io = { vector_reader, &buf }; context = mp4parse_new(&io); ASSERT_NE(context, nullptr); rv = mp4parse_read(context); EXPECT_EQ(rv, MP4PARSE_ERROR_INVALID); mp4parse_free(context); buf.buffer.reserve(4097); context = mp4parse_new(&io); ASSERT_NE(context, nullptr); rv = mp4parse_read(context); EXPECT_EQ(rv, MP4PARSE_ERROR_INVALID); mp4parse_free(context); // Empty buffers should fail. buf.buffer.resize(4097, 0); context = mp4parse_new(&io); rv = mp4parse_read(context); EXPECT_EQ(rv, MP4PARSE_ERROR_UNSUPPORTED); mp4parse_free(context); }
TEST(rust, MP4Metadata) { FILE* f = fopen("street.mp4", "rb"); ASSERT_TRUE(f != nullptr); // Read just the moov header to work around the parser // treating mid-box eof as an error. //read_vector reader = read_vector(f, 1061); struct stat s; ASSERT_EQ(0, fstat(fileno(f), &s)); read_vector reader = read_vector(f, s.st_size); fclose(f); mp4parse_io io = { vector_reader, &reader }; mp4parse_parser* context = mp4parse_new(&io); ASSERT_NE(nullptr, context); mp4parse_error rv = mp4parse_read(context); EXPECT_EQ(MP4PARSE_OK, rv); uint32_t tracks = 0; rv = mp4parse_get_track_count(context, &tracks); EXPECT_EQ(MP4PARSE_OK, rv); EXPECT_EQ(2U, tracks); mp4parse_free(context); }
nsresult MP4Metadata::Parse() { Mp4parseStatus rv = mp4parse_read(mParser.get()); if (rv != MP4PARSE_STATUS_OK) { MOZ_LOG(gMP4MetadataLog, LogLevel::Debug, ("Parse failed, return code %d\n", rv)); return rv == MP4PARSE_STATUS_OOM ? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_DOM_MEDIA_METADATA_ERR; } UpdateCrypto(); return NS_OK; }
MP4MetadataRust::MP4MetadataRust(Stream* aSource) : mSource(aSource) , mRustState(mp4parse_new()) { static LazyLogModule sLog("MP4Metadata"); std::vector<uint8_t> buffer; int32_t rv = read_source(mSource, buffer); if (rv == MP4PARSE_OK) { rv = mp4parse_read(mRustState.get(), buffer.data(), buffer.size()); } MOZ_LOG(sLog, LogLevel::Debug, ("rust parser returned %d\n", rv)); Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_SUCCESS, rv == MP4PARSE_OK); if (rv != MP4PARSE_OK) { MOZ_ASSERT(rv > 0); Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_ERROR_CODE, rv); } }
// Helper to test the rust parser on a data source. static bool try_rust(const UniquePtr<mp4parse_state, FreeMP4ParseState>& aRustState, RefPtr<Stream> aSource, int32_t* aCount) { static LazyLogModule sLog("MP4Metadata"); int64_t length; if (!aSource->Length(&length) || length <= 0) { MOZ_LOG(sLog, LogLevel::Warning, ("Couldn't get source length")); return false; } MOZ_LOG(sLog, LogLevel::Debug, ("Source length %d bytes\n", (long long int)length)); size_t bytes_read = 0; auto buffer = std::vector<uint8_t>(length); bool rv = aSource->ReadAt(0, buffer.data(), length, &bytes_read); if (!rv || bytes_read != size_t(length)) { MOZ_LOG(sLog, LogLevel::Warning, ("Error copying mp4 data")); return false; } *aCount = mp4parse_read(aRustState.get(), buffer.data(), bytes_read); MOZ_LOG(sLog, LogLevel::Info, ("rust parser found %d tracks", int(*aCount))); return true; }