123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include <stddef.h>
- #include <stdint.h>
- #include <va/va.h>
- #include <memory>
- #include <string>
- // This has to be included first.
- // See http://code.google.com/p/googletest/issues/detail?id=371
- #include "testing/gtest/include/gtest/gtest.h"
- #include "base/containers/span.h"
- #include "base/files/file_path.h"
- #include "base/files/file_util.h"
- #include "base/logging.h"
- #include "base/memory/scoped_refptr.h"
- #include "base/numerics/safe_conversions.h"
- #include "media/gpu/test/local_gpu_memory_buffer_manager.h"
- #include "media/gpu/vaapi/test_utils.h"
- #include "media/gpu/vaapi/vaapi_image_decoder.h"
- #include "media/gpu/vaapi/vaapi_image_decoder_test_common.h"
- #include "media/gpu/vaapi/vaapi_utils.h"
- #include "media/gpu/vaapi/vaapi_webp_decoder.h"
- #include "media/gpu/vaapi/vaapi_wrapper.h"
- #include "media/parsers/vp8_parser.h"
- #include "media/parsers/webp_parser.h"
- #include "third_party/libwebp/src/src/webp/decode.h"
- #include "ui/gfx/buffer_format_util.h"
- #include "ui/gfx/buffer_types.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/gfx/gpu_memory_buffer.h"
- #include "ui/gfx/linux/native_pixmap_dmabuf.h"
- #include "ui/gfx/native_pixmap_handle.h"
- namespace media {
- namespace {
- constexpr const char* kSmallImageFilename =
- "RGB_noise_large_pixels_115x115.webp";
- constexpr const char* kMediumImageFilename =
- "RGB_noise_large_pixels_2015x2015.webp";
- constexpr const char* kLargeImageFilename =
- "RGB_noise_large_pixels_4000x4000.webp";
- constexpr const char* kLowFreqImageFilename = "solid_green_2015x2015.webp";
- constexpr const char* kMedFreqImageFilename =
- "BlackAndWhite_criss-cross_pattern_2015x2015.webp";
- constexpr const char* kHighFreqImageFilename = "RGB_noise_2015x2015.webp";
- const vaapi_test_utils::TestParam kTestCases[] = {
- {"SmallImage_115x115", kSmallImageFilename},
- {"MediumImage_2015x2015", kMediumImageFilename},
- {"LargeImage_4000x4000", kLargeImageFilename},
- {"LowFreqImage", kLowFreqImageFilename},
- {"MedFreqImage", kMedFreqImageFilename},
- {"HighFreqImage", kHighFreqImageFilename},
- };
- // Any number above 99.5% should do. We are being very aggressive here.
- constexpr double kMinSsim = 0.999;
- // WebpDecode*() returns memory that has to be released in a specific way.
- struct WebpDecodeDeleter {
- void operator()(void* ptr) { WebPFree(ptr); }
- };
- } // namespace
- class VaapiWebPDecoderTest : public VaapiImageDecoderTestCommon {
- protected:
- VaapiWebPDecoderTest()
- : VaapiImageDecoderTestCommon(std::make_unique<VaapiWebPDecoder>()) {}
- void SetUp() override {
- if (!VaapiWrapper::IsDecodeSupported(VAProfileVP8Version0_3)) {
- DLOG(INFO) << "VP8 decoding is not supported by the VA-API.";
- GTEST_SKIP();
- }
- VaapiImageDecoderTestCommon::SetUp();
- }
- std::unique_ptr<NativePixmapAndSizeInfo> Decode(
- base::span<const uint8_t> encoded_image,
- VaapiImageDecodeStatus* status = nullptr) {
- const VaapiImageDecodeStatus decode_status =
- Decoder()->Decode(encoded_image);
- EXPECT_EQ(!!Decoder()->GetScopedVASurface(),
- decode_status == VaapiImageDecodeStatus::kSuccess);
- // Still try to export the surface when decode fails.
- VaapiImageDecodeStatus export_status;
- std::unique_ptr<NativePixmapAndSizeInfo> exported_pixmap =
- Decoder()->ExportAsNativePixmapDmaBuf(&export_status);
- EXPECT_EQ(!!exported_pixmap,
- export_status == VaapiImageDecodeStatus::kSuccess);
- // Return the first fail status.
- if (status) {
- *status = decode_status != VaapiImageDecodeStatus::kSuccess
- ? decode_status
- : export_status;
- }
- return exported_pixmap;
- }
- };
- TEST_P(VaapiWebPDecoderTest, DecodeAndExportAsNativePixmapDmaBuf) {
- base::FilePath input_file = FindTestDataFilePath(GetParam().filename);
- std::string webp_data;
- ASSERT_TRUE(base::ReadFileToString(input_file, &webp_data))
- << "failed to read input data from " << input_file.value();
- const auto encoded_image = base::as_bytes(base::make_span(webp_data));
- // Decode the image using the VA-API and wrap the decoded image in a
- // DecodedImage object.
- ASSERT_TRUE(VaapiWrapper::IsDecodingSupportedForInternalFormat(
- VAProfileVP8Version0_3, VA_RT_FORMAT_YUV420));
- VaapiImageDecodeStatus status;
- std::unique_ptr<NativePixmapAndSizeInfo> exported_pixmap =
- Decode(encoded_image, &status);
- ASSERT_EQ(VaapiImageDecodeStatus::kSuccess, status);
- EXPECT_FALSE(Decoder()->GetScopedVASurface());
- ASSERT_TRUE(exported_pixmap);
- ASSERT_TRUE(exported_pixmap->pixmap);
- ASSERT_EQ(gfx::BufferFormat::YUV_420_BIPLANAR,
- exported_pixmap->pixmap->GetBufferFormat());
- // Make sure the visible area is contained by the surface.
- EXPECT_FALSE(exported_pixmap->va_surface_resolution.IsEmpty());
- EXPECT_FALSE(exported_pixmap->pixmap->GetBufferSize().IsEmpty());
- ASSERT_TRUE(
- gfx::Rect(exported_pixmap->va_surface_resolution)
- .Contains(gfx::Rect(exported_pixmap->pixmap->GetBufferSize())));
- // TODO(andrescj): we could get a better lower bound based on the dimensions
- // and the format.
- ASSERT_GT(exported_pixmap->byte_size, 0u);
- gfx::NativePixmapHandle handle = exported_pixmap->pixmap->ExportHandle();
- ASSERT_EQ(gfx::NumberOfPlanesForLinearBufferFormat(
- exported_pixmap->pixmap->GetBufferFormat()),
- handle.planes.size());
- LocalGpuMemoryBufferManager gpu_memory_buffer_manager;
- std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
- gpu_memory_buffer_manager.ImportDmaBuf(
- handle, exported_pixmap->pixmap->GetBufferSize(),
- exported_pixmap->pixmap->GetBufferFormat());
- ASSERT_TRUE(gpu_memory_buffer);
- ASSERT_TRUE(gpu_memory_buffer->Map());
- ASSERT_EQ(gfx::BufferFormat::YUV_420_BIPLANAR,
- gpu_memory_buffer->GetFormat());
- vaapi_test_utils::DecodedImage hw_decoded_webp{};
- hw_decoded_webp.fourcc = VA_FOURCC_NV12;
- hw_decoded_webp.number_of_planes = 2u;
- hw_decoded_webp.size = gpu_memory_buffer->GetSize();
- for (size_t plane = 0u;
- plane < base::strict_cast<size_t>(hw_decoded_webp.number_of_planes);
- plane++) {
- hw_decoded_webp.planes[plane].data =
- static_cast<uint8_t*>(gpu_memory_buffer->memory(plane));
- hw_decoded_webp.planes[plane].stride = gpu_memory_buffer->stride(plane);
- }
- // Decode the image using libwebp and wrap the decoded image in a
- // DecodedImage object.
- std::unique_ptr<Vp8FrameHeader> parse_result = ParseWebPImage(encoded_image);
- ASSERT_TRUE(parse_result);
- int reference_width;
- int reference_height;
- int y_stride;
- int uv_stride;
- uint8_t* libwebp_u_plane = nullptr;
- uint8_t* libwebp_v_plane = nullptr;
- std::unique_ptr<uint8_t, WebpDecodeDeleter> libwebp_y_plane(
- WebPDecodeYUV(encoded_image.data(), encoded_image.size(),
- &reference_width, &reference_height, &libwebp_u_plane,
- &libwebp_v_plane, &y_stride, &uv_stride));
- ASSERT_TRUE(libwebp_y_plane && libwebp_u_plane && libwebp_v_plane);
- ASSERT_EQ(reference_width, base::strict_cast<int>(parse_result->width));
- ASSERT_EQ(reference_height, base::strict_cast<int>(parse_result->height));
- // Wrap the software decoded image in a DecodedImage object.
- vaapi_test_utils::DecodedImage sw_decoded_webp{};
- sw_decoded_webp.fourcc = VA_FOURCC_I420;
- sw_decoded_webp.number_of_planes = 3u;
- sw_decoded_webp.size = gfx::Size(reference_width, reference_height);
- sw_decoded_webp.planes[0].data = libwebp_y_plane.get();
- sw_decoded_webp.planes[0].stride = y_stride;
- sw_decoded_webp.planes[1].data = libwebp_u_plane;
- sw_decoded_webp.planes[1].stride = uv_stride;
- sw_decoded_webp.planes[2].data = libwebp_v_plane;
- sw_decoded_webp.planes[2].stride = uv_stride;
- EXPECT_TRUE(vaapi_test_utils::CompareImages(sw_decoded_webp, hw_decoded_webp,
- kMinSsim));
- gpu_memory_buffer->Unmap();
- }
- // TODO(crbug.com/986073): expand test coverage. See
- // vaapi_jpeg_decoder_unittest.cc as reference:
- // cs.chromium.org/chromium/src/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc
- INSTANTIATE_TEST_SUITE_P(All,
- VaapiWebPDecoderTest,
- testing::ValuesIn(kTestCases),
- vaapi_test_utils::TestParamToString);
- } // namespace media
|