vaapi_image_decode_accelerator_worker.cc 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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_decode_accelerator_worker.h"
  5. #include "base/task/thread_pool.h"
  6. #include "string.h"
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/containers/span.h"
  10. #include "base/feature_list.h"
  11. #include "base/location.h"
  12. #include "base/logging.h"
  13. #include "base/memory/ptr_util.h"
  14. #include "base/metrics/histogram_macros.h"
  15. #include "base/task/sequenced_task_runner.h"
  16. #include "base/trace_event/trace_event.h"
  17. #include "gpu/config/gpu_finch_features.h"
  18. #include "media/gpu/macros.h"
  19. #include "media/gpu/vaapi/va_surface.h"
  20. #include "media/gpu/vaapi/vaapi_image_decoder.h"
  21. #include "media/gpu/vaapi/vaapi_jpeg_decoder.h"
  22. #include "media/gpu/vaapi/vaapi_webp_decoder.h"
  23. #include "media/gpu/vaapi/vaapi_wrapper.h"
  24. #include "media/parsers/webp_parser.h"
  25. #include "mojo/public/cpp/bindings/callback_helpers.h"
  26. #include "ui/gfx/geometry/size.h"
  27. #include "ui/gfx/gpu_memory_buffer.h"
  28. #include "ui/gfx/linux/native_pixmap_dmabuf.h"
  29. #include "ui/gfx/native_pixmap_handle.h"
  30. namespace media {
  31. namespace {
  32. bool IsJpegImage(base::span<const uint8_t> encoded_data) {
  33. if (encoded_data.size() < 3u)
  34. return false;
  35. return memcmp("\xFF\xD8\xFF", encoded_data.data(), 3u) == 0;
  36. }
  37. // Uses |decoder| to decode the image corresponding to |encoded_data|.
  38. // |decode_cb| is called when finished or when an error is encountered. We don't
  39. // support decoding to scale, so |output_size| is only used for tracing.
  40. void DecodeTask(
  41. VaapiImageDecoder* decoder,
  42. std::vector<uint8_t> encoded_data,
  43. const gfx::Size& output_size,
  44. gpu::ImageDecodeAcceleratorWorker::CompletedDecodeCB decode_cb) {
  45. TRACE_EVENT2("jpeg", "VaapiImageDecodeAcceleratorWorker::DecodeTask",
  46. "encoded_bytes", encoded_data.size(), "output_size",
  47. output_size.ToString());
  48. gpu::ImageDecodeAcceleratorWorker::CompletedDecodeCB scoped_decode_callback =
  49. mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(decode_cb),
  50. nullptr);
  51. // Decode into a VAAPI surface.
  52. if (!decoder) {
  53. DVLOGF(1) << "No decoder is available for supplied image";
  54. return;
  55. }
  56. VaapiImageDecodeStatus status = decoder->Decode(encoded_data);
  57. if (status != VaapiImageDecodeStatus::kSuccess) {
  58. DVLOGF(1) << "Failed to decode - status = "
  59. << static_cast<uint32_t>(status);
  60. return;
  61. }
  62. // Export the decode result as a NativePixmap.
  63. std::unique_ptr<NativePixmapAndSizeInfo> exported_pixmap =
  64. decoder->ExportAsNativePixmapDmaBuf(&status);
  65. if (status != VaapiImageDecodeStatus::kSuccess) {
  66. DVLOGF(1) << "Failed to export surface - status = "
  67. << static_cast<uint32_t>(status);
  68. return;
  69. }
  70. DCHECK(exported_pixmap);
  71. DCHECK(exported_pixmap->pixmap);
  72. if (exported_pixmap->pixmap->GetBufferSize() != output_size) {
  73. DVLOGF(1) << "Scaling is not supported";
  74. return;
  75. }
  76. // Output the decoded data.
  77. gfx::NativePixmapHandle pixmap_handle =
  78. exported_pixmap->pixmap->ExportHandle();
  79. // If a dup() failed while exporting the handle, we would get no planes.
  80. if (pixmap_handle.planes.empty()) {
  81. DVLOGF(1) << "Could not export the NativePixmapHandle";
  82. return;
  83. }
  84. auto result =
  85. std::make_unique<gpu::ImageDecodeAcceleratorWorker::DecodeResult>();
  86. result->handle.type = gfx::GpuMemoryBufferType::NATIVE_PIXMAP;
  87. result->handle.native_pixmap_handle = std::move(pixmap_handle);
  88. result->visible_size = exported_pixmap->pixmap->GetBufferSize();
  89. result->buffer_format = exported_pixmap->pixmap->GetBufferFormat();
  90. result->buffer_byte_size = exported_pixmap->byte_size;
  91. result->yuv_color_space = decoder->GetYUVColorSpace();
  92. std::move(scoped_decode_callback).Run(std::move(result));
  93. }
  94. } // namespace
  95. // static
  96. std::unique_ptr<VaapiImageDecodeAcceleratorWorker>
  97. VaapiImageDecodeAcceleratorWorker::Create() {
  98. // TODO(crbug.com/988123): revisit the
  99. // Media.VaapiImageDecodeAcceleratorWorker.VAAPIError UMA to be able to record
  100. // WebP and JPEG failures separately.
  101. const auto uma_cb =
  102. base::BindRepeating(&ReportVaapiErrorToUMA,
  103. "Media.VaapiImageDecodeAcceleratorWorker.VAAPIError");
  104. VaapiImageDecoderVector decoders;
  105. auto jpeg_decoder = std::make_unique<VaapiJpegDecoder>();
  106. // TODO(crbug.com/974438): we can't advertise accelerated image decoding in
  107. // AMD until we support VAAPI surfaces with multiple buffer objects.
  108. if (VaapiWrapper::GetImplementationType() != VAImplementation::kMesaGallium &&
  109. jpeg_decoder->Initialize(uma_cb)) {
  110. decoders.push_back(std::move(jpeg_decoder));
  111. }
  112. auto webp_decoder = std::make_unique<VaapiWebPDecoder>();
  113. if (webp_decoder->Initialize(uma_cb))
  114. decoders.push_back(std::move(webp_decoder));
  115. // If there are no decoders due to disabled flags or initialization failure,
  116. // return nullptr.
  117. if (decoders.empty())
  118. return nullptr;
  119. return base::WrapUnique(
  120. new VaapiImageDecodeAcceleratorWorker(std::move(decoders)));
  121. }
  122. VaapiImageDecodeAcceleratorWorker::VaapiImageDecodeAcceleratorWorker(
  123. VaapiImageDecoderVector decoders) {
  124. DETACH_FROM_SEQUENCE(io_sequence_checker_);
  125. decoder_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner({});
  126. DCHECK(decoder_task_runner_);
  127. DCHECK(!decoders.empty());
  128. for (auto& decoder : decoders) {
  129. supported_profiles_.push_back(decoder->GetSupportedProfile());
  130. const gpu::ImageDecodeAcceleratorType type = decoder->GetType();
  131. decoders_[type] = std::move(decoder);
  132. }
  133. }
  134. VaapiImageDecodeAcceleratorWorker::~VaapiImageDecodeAcceleratorWorker() {
  135. DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
  136. DCHECK(decoder_task_runner_);
  137. for (auto& decoder : decoders_)
  138. decoder_task_runner_->DeleteSoon(FROM_HERE, std::move(decoder.second));
  139. }
  140. gpu::ImageDecodeAcceleratorSupportedProfiles
  141. VaapiImageDecodeAcceleratorWorker::GetSupportedProfiles() {
  142. return supported_profiles_;
  143. }
  144. VaapiImageDecoder* VaapiImageDecodeAcceleratorWorker::GetDecoderForImage(
  145. const std::vector<uint8_t>& encoded_data) {
  146. DCHECK_CALLED_ON_VALID_SEQUENCE(io_sequence_checker_);
  147. auto result = decoders_.end();
  148. if (base::FeatureList::IsEnabled(
  149. features::kVaapiJpegImageDecodeAcceleration) &&
  150. IsJpegImage(encoded_data)) {
  151. result = decoders_.find(gpu::ImageDecodeAcceleratorType::kJpeg);
  152. } else if (base::FeatureList::IsEnabled(
  153. features::kVaapiWebPImageDecodeAcceleration) &&
  154. IsLossyWebPImage(encoded_data)) {
  155. result = decoders_.find(gpu::ImageDecodeAcceleratorType::kWebP);
  156. }
  157. return result == decoders_.end() ? nullptr : result->second.get();
  158. }
  159. void VaapiImageDecodeAcceleratorWorker::Decode(
  160. std::vector<uint8_t> encoded_data,
  161. const gfx::Size& output_size,
  162. CompletedDecodeCB decode_cb) {
  163. DCHECK_CALLED_ON_VALID_SEQUENCE(io_sequence_checker_);
  164. DCHECK(decoder_task_runner_);
  165. // We defer checking for a null |decoder| until DecodeTask() because the
  166. // gpu::ImageDecodeAcceleratorWorker interface mandates that the callback be
  167. // called asynchronously.
  168. VaapiImageDecoder* decoder = GetDecoderForImage(encoded_data);
  169. decoder_task_runner_->PostTask(
  170. FROM_HERE, base::BindOnce(&DecodeTask, decoder, std::move(encoded_data),
  171. output_size, std::move(decode_cb)));
  172. }
  173. } // namespace media