// Copyright 2020 The libgav1 Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "tests/utils.h" #include #include #include #include #include #include #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "gtest/gtest.h" #include "src/dsp/dsp.h" #include "src/gav1/decoder_buffer.h" #include "src/utils/constants.h" #include "tests/third_party/libvpx/md5_helper.h" namespace libgav1 { namespace test_utils { namespace { int CloseFile(FILE* stream) { return fclose(stream); } bool ReadFileToString(absl::string_view file_name, std::string* const string) { using FilePtr = std::unique_ptr; FilePtr file(fopen(std::string(file_name).c_str(), "rb"), &CloseFile); if (file == nullptr) return false; do { int c = fgetc(file.get()); if (ferror(file.get()) != 0) return false; if (c != EOF) { string->append(1, static_cast(c)); } else { break; } } while (true); return true; } } // namespace void ResetDspTable(const int bitdepth) { dsp::Dsp* const dsp = dsp_internal::GetWritableDspTable(bitdepth); ASSERT_NE(dsp, nullptr); memset(dsp, 0, sizeof(dsp::Dsp)); } std::string GetMd5Sum(const void* bytes, size_t size) { libvpx_test::MD5 md5; md5.Add(static_cast(bytes), size); return md5.Get(); } template std::string GetMd5Sum(const Pixel* block, int width, int height, int stride) { libvpx_test::MD5 md5; const Pixel* row = block; for (int i = 0; i < height; ++i) { md5.Add(reinterpret_cast(row), width * sizeof(Pixel)); row += stride; } return md5.Get(); } template std::string GetMd5Sum(const int8_t* block, int width, int height, int stride); template std::string GetMd5Sum(const int16_t* block, int width, int height, int stride); std::string GetMd5Sum(const DecoderBuffer& buffer) { libvpx_test::MD5 md5; const size_t pixel_size = (buffer.bitdepth == 8) ? sizeof(uint8_t) : sizeof(uint16_t); for (int plane = kPlaneY; plane < buffer.NumPlanes(); ++plane) { const int height = buffer.displayed_height[plane]; const size_t width = buffer.displayed_width[plane] * pixel_size; const int stride = buffer.stride[plane]; const uint8_t* plane_buffer = buffer.plane[plane]; for (int row = 0; row < height; ++row) { md5.Add(plane_buffer, width); plane_buffer += stride; } } return md5.Get(); } void CheckMd5Digest(const char name[], const char function_name[], const char expected_digest[], const void* data, size_t size, absl::Duration elapsed_time) { const std::string digest = test_utils::GetMd5Sum(data, size); printf("Mode %s[%31s]: %5d us MD5: %s\n", name, function_name, static_cast(absl::ToInt64Microseconds(elapsed_time)), digest.c_str()); EXPECT_STREQ(expected_digest, digest.c_str()); } template void CheckMd5Digest(const char name[], const char function_name[], const char expected_digest[], const Pixel* block, int width, int height, int stride, absl::Duration elapsed_time) { const std::string digest = test_utils::GetMd5Sum(block, width, height, stride); printf("Mode %s[%31s]: %5d us MD5: %s\n", name, function_name, static_cast(absl::ToInt64Microseconds(elapsed_time)), digest.c_str()); EXPECT_STREQ(expected_digest, digest.c_str()); } template void CheckMd5Digest(const char name[], const char function_name[], const char expected_digest[], const int8_t* block, int width, int height, int stride, absl::Duration elapsed_time); template void CheckMd5Digest(const char name[], const char function_name[], const char expected_digest[], const int16_t* block, int width, int height, int stride, absl::Duration elapsed_time); void CheckMd5Digest(const char name[], const char function_name[], const char expected_digest[], const char actual_digest[], absl::Duration elapsed_time) { printf("Mode %s[%31s]: %5d us MD5: %s\n", name, function_name, static_cast(absl::ToInt64Microseconds(elapsed_time)), actual_digest); EXPECT_STREQ(expected_digest, actual_digest); } namespace { std::string GetSourceDir() { #if defined(__ANDROID__) // Test files must be manually supplied. This path is frequently // available on development devices. return std::string("/data/local/tmp/tests/data"); #elif defined(LIBGAV1_FLAGS_SRCDIR) return std::string(LIBGAV1_FLAGS_SRCDIR) + "/tests/data"; #else return std::string("."); #endif // defined(__ANDROID__) } std::string GetTempDir() { const char* path = getenv("TMPDIR"); if (path == nullptr || path[0] == '\0') path = getenv("TEMP"); if (path != nullptr && path[0] != '\0') return std::string(path); #if defined(__ANDROID__) return std::string("/data/local/tmp"); #elif defined(LIBGAV1_FLAGS_TMPDIR) return std::string(LIBGAV1_FLAGS_TMPDIR); #else return std::string("."); #endif // defined(__ANDROID__) } } // namespace std::string GetTestInputFilePath(absl::string_view file_name) { const char* const path = getenv("LIBGAV1_TEST_DATA_PATH"); if (path != nullptr && path[0] != '\0') { return std::string(path) + "/" + std::string(file_name); } return GetSourceDir() + "/" + std::string(file_name); } std::string GetTestOutputFilePath(absl::string_view file_name) { return GetTempDir() + "/" + std::string(file_name); } void GetTestData(absl::string_view file_name, const bool is_output_file, std::string* const output) { ASSERT_NE(output, nullptr); const std::string absolute_file_path = is_output_file ? GetTestOutputFilePath(file_name) : GetTestInputFilePath(file_name); ASSERT_TRUE(ReadFileToString(absolute_file_path, output)); } } // namespace test_utils } // namespace libgav1