vaapi_image_decoder.cc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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/vaapi_image_decoder.h"
  5. #include <utility>
  6. #include "base/logging.h"
  7. #include "media/gpu/macros.h"
  8. #include "media/gpu/vaapi/va_surface.h"
  9. #include "media/gpu/vaapi/vaapi_utils.h"
  10. #include "media/gpu/vaapi/vaapi_wrapper.h"
  11. #include "ui/gfx/geometry/size.h"
  12. #include "ui/gfx/linux/native_pixmap_dmabuf.h"
  13. namespace media {
  14. void VAContextAndScopedVASurfaceDeleter::operator()(
  15. ScopedVASurface* scoped_va_surface) const {
  16. scoped_va_surface->vaapi_wrapper_->DestroyContext();
  17. delete scoped_va_surface;
  18. }
  19. VaapiImageDecoder::VaapiImageDecoder(VAProfile va_profile)
  20. : va_profile_(va_profile) {}
  21. VaapiImageDecoder::~VaapiImageDecoder() = default;
  22. bool VaapiImageDecoder::Initialize(const ReportErrorToUMACB& error_uma_cb) {
  23. vaapi_wrapper_ =
  24. VaapiWrapper::Create(VaapiWrapper::kDecode, va_profile_,
  25. EncryptionScheme::kUnencrypted, error_uma_cb);
  26. return !!vaapi_wrapper_;
  27. }
  28. VaapiImageDecodeStatus VaapiImageDecoder::Decode(
  29. base::span<const uint8_t> encoded_image) {
  30. if (!vaapi_wrapper_) {
  31. VLOGF(1) << "VaapiImageDecoder has not been initialized";
  32. scoped_va_context_and_surface_.reset();
  33. return VaapiImageDecodeStatus::kInvalidState;
  34. }
  35. const VaapiImageDecodeStatus status =
  36. AllocateVASurfaceAndSubmitVABuffers(encoded_image);
  37. if (status != VaapiImageDecodeStatus::kSuccess) {
  38. scoped_va_context_and_surface_.reset();
  39. return status;
  40. }
  41. if (!vaapi_wrapper_->ExecuteAndDestroyPendingBuffers(
  42. scoped_va_context_and_surface_->id())) {
  43. VLOGF(1) << "ExecuteAndDestroyPendingBuffers() failed";
  44. scoped_va_context_and_surface_.reset();
  45. return VaapiImageDecodeStatus::kExecuteDecodeFailed;
  46. }
  47. return VaapiImageDecodeStatus::kSuccess;
  48. }
  49. const ScopedVASurface* VaapiImageDecoder::GetScopedVASurface() const {
  50. return scoped_va_context_and_surface_.get();
  51. }
  52. gpu::ImageDecodeAcceleratorSupportedProfile
  53. VaapiImageDecoder::GetSupportedProfile() const {
  54. if (!vaapi_wrapper_) {
  55. DVLOGF(1) << "The VAAPI has not been initialized";
  56. return gpu::ImageDecodeAcceleratorSupportedProfile();
  57. }
  58. gpu::ImageDecodeAcceleratorSupportedProfile profile;
  59. profile.image_type = GetType();
  60. DCHECK_NE(gpu::ImageDecodeAcceleratorType::kUnknown, profile.image_type);
  61. // Note that since |vaapi_wrapper_| was created successfully, we expect the
  62. // following call to be successful. Hence the DCHECK.
  63. const bool got_supported_resolutions = VaapiWrapper::GetSupportedResolutions(
  64. va_profile_, VaapiWrapper::CodecMode::kDecode,
  65. profile.min_encoded_dimensions, profile.max_encoded_dimensions);
  66. DCHECK(got_supported_resolutions);
  67. // TODO(andrescj): Ideally, we would advertise support for all the formats
  68. // supported by the driver. However, for now, we will only support exposing
  69. // YUV 4:2:0 surfaces as DmaBufs.
  70. DCHECK(VaapiWrapper::GetDecodeSupportedInternalFormats(va_profile_).yuv420);
  71. profile.subsamplings.push_back(gpu::ImageDecodeAcceleratorSubsampling::k420);
  72. return profile;
  73. }
  74. std::unique_ptr<NativePixmapAndSizeInfo>
  75. VaapiImageDecoder::ExportAsNativePixmapDmaBuf(VaapiImageDecodeStatus* status) {
  76. DCHECK(status);
  77. // We need to take ownership of the ScopedVASurface so that the next Decode()
  78. // doesn't attempt to use the same ScopedVASurface. Otherwise, it could
  79. // overwrite the result of the current decode before it's used by the caller.
  80. // This ScopedVASurface will self-clean at the end of this scope, but the
  81. // underlying buffer should stay alive because of the exported FDs.
  82. ScopedVAContextAndSurface temp_scoped_va_surface =
  83. std::move(scoped_va_context_and_surface_);
  84. if (!temp_scoped_va_surface) {
  85. DVLOGF(1) << "No decoded image available";
  86. *status = VaapiImageDecodeStatus::kInvalidState;
  87. return nullptr;
  88. }
  89. DCHECK(temp_scoped_va_surface->IsValid());
  90. std::unique_ptr<NativePixmapAndSizeInfo> exported_pixmap =
  91. vaapi_wrapper_->ExportVASurfaceAsNativePixmapDmaBuf(
  92. *temp_scoped_va_surface);
  93. if (!exported_pixmap) {
  94. *status = VaapiImageDecodeStatus::kCannotExportSurface;
  95. return nullptr;
  96. }
  97. DCHECK_EQ(temp_scoped_va_surface->size(),
  98. exported_pixmap->pixmap->GetBufferSize());
  99. *status = VaapiImageDecodeStatus::kSuccess;
  100. return exported_pixmap;
  101. }
  102. } // namespace media