test_utils.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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 "media/gpu/vaapi/test_utils.h"
  5. #include <memory>
  6. #include "base/logging.h"
  7. #include "base/numerics/safe_conversions.h"
  8. #include "media/base/video_types.h"
  9. #include "media/gpu/vaapi/vaapi_utils.h"
  10. #include "third_party/libyuv/include/libyuv.h"
  11. namespace media {
  12. namespace vaapi_test_utils {
  13. std::string TestParamToString(
  14. const testing::TestParamInfo<TestParam>& param_info) {
  15. return param_info.param.test_name;
  16. }
  17. DecodedImage ScopedVAImageToDecodedImage(const ScopedVAImage* scoped_va_image) {
  18. DecodedImage decoded_image{};
  19. decoded_image.fourcc = scoped_va_image->image()->format.fourcc;
  20. decoded_image.number_of_planes = scoped_va_image->image()->num_planes;
  21. decoded_image.size =
  22. gfx::Size(base::strict_cast<int>(scoped_va_image->image()->width),
  23. base::strict_cast<int>(scoped_va_image->image()->height));
  24. DCHECK_LE(base::strict_cast<size_t>(decoded_image.number_of_planes),
  25. kMaxNumberPlanes);
  26. // This is safe because |number_of_planes| is retrieved from the VA-API and it
  27. // can not be greater than 3, which is also the size of the |planes| array.
  28. for (uint32_t i = 0u; i < decoded_image.number_of_planes; ++i) {
  29. decoded_image.planes[i].data =
  30. static_cast<uint8_t*>(scoped_va_image->va_buffer()->data()) +
  31. scoped_va_image->image()->offsets[i];
  32. decoded_image.planes[i].stride =
  33. base::checked_cast<int>(scoped_va_image->image()->pitches[i]);
  34. }
  35. return decoded_image;
  36. }
  37. bool CompareImages(const DecodedImage& reference_image,
  38. const DecodedImage& hw_decoded_image,
  39. double min_ssim) {
  40. if (reference_image.fourcc != VA_FOURCC_I420)
  41. return false;
  42. // Uses the reference image's size as the ground truth.
  43. const gfx::Size image_size = reference_image.size;
  44. if (image_size != hw_decoded_image.size) {
  45. LOG(ERROR) << "Wrong expected software decoded image size, "
  46. << image_size.ToString() << " versus VaAPI provided "
  47. << hw_decoded_image.size.ToString();
  48. return false;
  49. }
  50. double ssim = 0;
  51. const uint32_t hw_fourcc = hw_decoded_image.fourcc;
  52. if (hw_fourcc == VA_FOURCC_I420) {
  53. ssim = libyuv::I420Ssim(
  54. reference_image.planes[0].data, reference_image.planes[0].stride,
  55. reference_image.planes[1].data, reference_image.planes[1].stride,
  56. reference_image.planes[2].data, reference_image.planes[2].stride,
  57. hw_decoded_image.planes[0].data, hw_decoded_image.planes[0].stride,
  58. hw_decoded_image.planes[1].data, hw_decoded_image.planes[1].stride,
  59. hw_decoded_image.planes[2].data, hw_decoded_image.planes[2].stride,
  60. image_size.width(), image_size.height());
  61. } else if (hw_fourcc == VA_FOURCC_NV12 || hw_fourcc == VA_FOURCC_YUY2 ||
  62. hw_fourcc == VA_FOURCC('Y', 'U', 'Y', 'V')) {
  63. // Calculate the stride for the chroma planes.
  64. const gfx::Size half_image_size((image_size.width() + 1) / 2,
  65. (image_size.height() + 1) / 2);
  66. // Temporary planes to hold intermediate conversions to I420 (i.e. NV12 to
  67. // I420 or YUYV/2 to I420).
  68. auto temp_y = std::make_unique<uint8_t[]>(image_size.GetArea());
  69. auto temp_u = std::make_unique<uint8_t[]>(half_image_size.GetArea());
  70. auto temp_v = std::make_unique<uint8_t[]>(half_image_size.GetArea());
  71. int conversion_result = -1;
  72. if (hw_fourcc == VA_FOURCC_NV12) {
  73. conversion_result = libyuv::NV12ToI420(
  74. hw_decoded_image.planes[0].data, hw_decoded_image.planes[0].stride,
  75. hw_decoded_image.planes[1].data, hw_decoded_image.planes[1].stride,
  76. temp_y.get(), image_size.width(), temp_u.get(),
  77. half_image_size.width(), temp_v.get(), half_image_size.width(),
  78. image_size.width(), image_size.height());
  79. } else {
  80. // |hw_fourcc| is YUY2 or YUYV, which are handled the same.
  81. // TODO(crbug.com/868400): support other formats/planarities/pitches.
  82. conversion_result = libyuv::YUY2ToI420(
  83. hw_decoded_image.planes[0].data, hw_decoded_image.planes[0].stride,
  84. temp_y.get(), image_size.width(), temp_u.get(),
  85. half_image_size.width(), temp_v.get(), half_image_size.width(),
  86. image_size.width(), image_size.height());
  87. }
  88. if (conversion_result != 0) {
  89. LOG(ERROR) << "libyuv conversion error";
  90. return false;
  91. }
  92. ssim = libyuv::I420Ssim(
  93. reference_image.planes[0].data, reference_image.planes[0].stride,
  94. reference_image.planes[1].data, reference_image.planes[1].stride,
  95. reference_image.planes[2].data, reference_image.planes[2].stride,
  96. temp_y.get(), image_size.width(), temp_u.get(), half_image_size.width(),
  97. temp_v.get(), half_image_size.width(), image_size.width(),
  98. image_size.height());
  99. } else {
  100. LOG(ERROR) << "HW FourCC not supported: " << FourccToString(hw_fourcc);
  101. return false;
  102. }
  103. if (ssim < min_ssim) {
  104. LOG(ERROR) << "SSIM too low: " << ssim << " < " << min_ssim;
  105. return false;
  106. }
  107. return true;
  108. }
  109. } // namespace vaapi_test_utils
  110. } // namespace media