vaapi_webp_decoder_unittest.cc 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <stddef.h>
  5. #include <stdint.h>
  6. #include <va/va.h>
  7. #include <memory>
  8. #include <string>
  9. // This has to be included first.
  10. // See http://code.google.com/p/googletest/issues/detail?id=371
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. #include "base/containers/span.h"
  13. #include "base/files/file_path.h"
  14. #include "base/files/file_util.h"
  15. #include "base/logging.h"
  16. #include "base/memory/scoped_refptr.h"
  17. #include "base/numerics/safe_conversions.h"
  18. #include "media/gpu/test/local_gpu_memory_buffer_manager.h"
  19. #include "media/gpu/vaapi/test_utils.h"
  20. #include "media/gpu/vaapi/vaapi_image_decoder.h"
  21. #include "media/gpu/vaapi/vaapi_image_decoder_test_common.h"
  22. #include "media/gpu/vaapi/vaapi_utils.h"
  23. #include "media/gpu/vaapi/vaapi_webp_decoder.h"
  24. #include "media/gpu/vaapi/vaapi_wrapper.h"
  25. #include "media/parsers/vp8_parser.h"
  26. #include "media/parsers/webp_parser.h"
  27. #include "third_party/libwebp/src/src/webp/decode.h"
  28. #include "ui/gfx/buffer_format_util.h"
  29. #include "ui/gfx/buffer_types.h"
  30. #include "ui/gfx/geometry/rect.h"
  31. #include "ui/gfx/geometry/size.h"
  32. #include "ui/gfx/gpu_memory_buffer.h"
  33. #include "ui/gfx/linux/native_pixmap_dmabuf.h"
  34. #include "ui/gfx/native_pixmap_handle.h"
  35. namespace media {
  36. namespace {
  37. constexpr const char* kSmallImageFilename =
  38. "RGB_noise_large_pixels_115x115.webp";
  39. constexpr const char* kMediumImageFilename =
  40. "RGB_noise_large_pixels_2015x2015.webp";
  41. constexpr const char* kLargeImageFilename =
  42. "RGB_noise_large_pixels_4000x4000.webp";
  43. constexpr const char* kLowFreqImageFilename = "solid_green_2015x2015.webp";
  44. constexpr const char* kMedFreqImageFilename =
  45. "BlackAndWhite_criss-cross_pattern_2015x2015.webp";
  46. constexpr const char* kHighFreqImageFilename = "RGB_noise_2015x2015.webp";
  47. const vaapi_test_utils::TestParam kTestCases[] = {
  48. {"SmallImage_115x115", kSmallImageFilename},
  49. {"MediumImage_2015x2015", kMediumImageFilename},
  50. {"LargeImage_4000x4000", kLargeImageFilename},
  51. {"LowFreqImage", kLowFreqImageFilename},
  52. {"MedFreqImage", kMedFreqImageFilename},
  53. {"HighFreqImage", kHighFreqImageFilename},
  54. };
  55. // Any number above 99.5% should do. We are being very aggressive here.
  56. constexpr double kMinSsim = 0.999;
  57. // WebpDecode*() returns memory that has to be released in a specific way.
  58. struct WebpDecodeDeleter {
  59. void operator()(void* ptr) { WebPFree(ptr); }
  60. };
  61. } // namespace
  62. class VaapiWebPDecoderTest : public VaapiImageDecoderTestCommon {
  63. protected:
  64. VaapiWebPDecoderTest()
  65. : VaapiImageDecoderTestCommon(std::make_unique<VaapiWebPDecoder>()) {}
  66. void SetUp() override {
  67. if (!VaapiWrapper::IsDecodeSupported(VAProfileVP8Version0_3)) {
  68. DLOG(INFO) << "VP8 decoding is not supported by the VA-API.";
  69. GTEST_SKIP();
  70. }
  71. VaapiImageDecoderTestCommon::SetUp();
  72. }
  73. std::unique_ptr<NativePixmapAndSizeInfo> Decode(
  74. base::span<const uint8_t> encoded_image,
  75. VaapiImageDecodeStatus* status = nullptr) {
  76. const VaapiImageDecodeStatus decode_status =
  77. Decoder()->Decode(encoded_image);
  78. EXPECT_EQ(!!Decoder()->GetScopedVASurface(),
  79. decode_status == VaapiImageDecodeStatus::kSuccess);
  80. // Still try to export the surface when decode fails.
  81. VaapiImageDecodeStatus export_status;
  82. std::unique_ptr<NativePixmapAndSizeInfo> exported_pixmap =
  83. Decoder()->ExportAsNativePixmapDmaBuf(&export_status);
  84. EXPECT_EQ(!!exported_pixmap,
  85. export_status == VaapiImageDecodeStatus::kSuccess);
  86. // Return the first fail status.
  87. if (status) {
  88. *status = decode_status != VaapiImageDecodeStatus::kSuccess
  89. ? decode_status
  90. : export_status;
  91. }
  92. return exported_pixmap;
  93. }
  94. };
  95. TEST_P(VaapiWebPDecoderTest, DecodeAndExportAsNativePixmapDmaBuf) {
  96. base::FilePath input_file = FindTestDataFilePath(GetParam().filename);
  97. std::string webp_data;
  98. ASSERT_TRUE(base::ReadFileToString(input_file, &webp_data))
  99. << "failed to read input data from " << input_file.value();
  100. const auto encoded_image = base::as_bytes(base::make_span(webp_data));
  101. // Decode the image using the VA-API and wrap the decoded image in a
  102. // DecodedImage object.
  103. ASSERT_TRUE(VaapiWrapper::IsDecodingSupportedForInternalFormat(
  104. VAProfileVP8Version0_3, VA_RT_FORMAT_YUV420));
  105. VaapiImageDecodeStatus status;
  106. std::unique_ptr<NativePixmapAndSizeInfo> exported_pixmap =
  107. Decode(encoded_image, &status);
  108. ASSERT_EQ(VaapiImageDecodeStatus::kSuccess, status);
  109. EXPECT_FALSE(Decoder()->GetScopedVASurface());
  110. ASSERT_TRUE(exported_pixmap);
  111. ASSERT_TRUE(exported_pixmap->pixmap);
  112. ASSERT_EQ(gfx::BufferFormat::YUV_420_BIPLANAR,
  113. exported_pixmap->pixmap->GetBufferFormat());
  114. // Make sure the visible area is contained by the surface.
  115. EXPECT_FALSE(exported_pixmap->va_surface_resolution.IsEmpty());
  116. EXPECT_FALSE(exported_pixmap->pixmap->GetBufferSize().IsEmpty());
  117. ASSERT_TRUE(
  118. gfx::Rect(exported_pixmap->va_surface_resolution)
  119. .Contains(gfx::Rect(exported_pixmap->pixmap->GetBufferSize())));
  120. // TODO(andrescj): we could get a better lower bound based on the dimensions
  121. // and the format.
  122. ASSERT_GT(exported_pixmap->byte_size, 0u);
  123. gfx::NativePixmapHandle handle = exported_pixmap->pixmap->ExportHandle();
  124. ASSERT_EQ(gfx::NumberOfPlanesForLinearBufferFormat(
  125. exported_pixmap->pixmap->GetBufferFormat()),
  126. handle.planes.size());
  127. LocalGpuMemoryBufferManager gpu_memory_buffer_manager;
  128. std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
  129. gpu_memory_buffer_manager.ImportDmaBuf(
  130. handle, exported_pixmap->pixmap->GetBufferSize(),
  131. exported_pixmap->pixmap->GetBufferFormat());
  132. ASSERT_TRUE(gpu_memory_buffer);
  133. ASSERT_TRUE(gpu_memory_buffer->Map());
  134. ASSERT_EQ(gfx::BufferFormat::YUV_420_BIPLANAR,
  135. gpu_memory_buffer->GetFormat());
  136. vaapi_test_utils::DecodedImage hw_decoded_webp{};
  137. hw_decoded_webp.fourcc = VA_FOURCC_NV12;
  138. hw_decoded_webp.number_of_planes = 2u;
  139. hw_decoded_webp.size = gpu_memory_buffer->GetSize();
  140. for (size_t plane = 0u;
  141. plane < base::strict_cast<size_t>(hw_decoded_webp.number_of_planes);
  142. plane++) {
  143. hw_decoded_webp.planes[plane].data =
  144. static_cast<uint8_t*>(gpu_memory_buffer->memory(plane));
  145. hw_decoded_webp.planes[plane].stride = gpu_memory_buffer->stride(plane);
  146. }
  147. // Decode the image using libwebp and wrap the decoded image in a
  148. // DecodedImage object.
  149. std::unique_ptr<Vp8FrameHeader> parse_result = ParseWebPImage(encoded_image);
  150. ASSERT_TRUE(parse_result);
  151. int reference_width;
  152. int reference_height;
  153. int y_stride;
  154. int uv_stride;
  155. uint8_t* libwebp_u_plane = nullptr;
  156. uint8_t* libwebp_v_plane = nullptr;
  157. std::unique_ptr<uint8_t, WebpDecodeDeleter> libwebp_y_plane(
  158. WebPDecodeYUV(encoded_image.data(), encoded_image.size(),
  159. &reference_width, &reference_height, &libwebp_u_plane,
  160. &libwebp_v_plane, &y_stride, &uv_stride));
  161. ASSERT_TRUE(libwebp_y_plane && libwebp_u_plane && libwebp_v_plane);
  162. ASSERT_EQ(reference_width, base::strict_cast<int>(parse_result->width));
  163. ASSERT_EQ(reference_height, base::strict_cast<int>(parse_result->height));
  164. // Wrap the software decoded image in a DecodedImage object.
  165. vaapi_test_utils::DecodedImage sw_decoded_webp{};
  166. sw_decoded_webp.fourcc = VA_FOURCC_I420;
  167. sw_decoded_webp.number_of_planes = 3u;
  168. sw_decoded_webp.size = gfx::Size(reference_width, reference_height);
  169. sw_decoded_webp.planes[0].data = libwebp_y_plane.get();
  170. sw_decoded_webp.planes[0].stride = y_stride;
  171. sw_decoded_webp.planes[1].data = libwebp_u_plane;
  172. sw_decoded_webp.planes[1].stride = uv_stride;
  173. sw_decoded_webp.planes[2].data = libwebp_v_plane;
  174. sw_decoded_webp.planes[2].stride = uv_stride;
  175. EXPECT_TRUE(vaapi_test_utils::CompareImages(sw_decoded_webp, hw_decoded_webp,
  176. kMinSsim));
  177. gpu_memory_buffer->Unmap();
  178. }
  179. // TODO(crbug.com/986073): expand test coverage. See
  180. // vaapi_jpeg_decoder_unittest.cc as reference:
  181. // cs.chromium.org/chromium/src/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc
  182. INSTANTIATE_TEST_SUITE_P(All,
  183. VaapiWebPDecoderTest,
  184. testing::ValuesIn(kTestCases),
  185. vaapi_test_utils::TestParamToString);
  186. } // namespace media