123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- // 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 "media/gpu/vaapi/vaapi_image_decode_accelerator_worker.h"
- #include "base/task/thread_pool.h"
- #include "string.h"
- #include <utility>
- #include "base/bind.h"
- #include "base/containers/span.h"
- #include "base/feature_list.h"
- #include "base/location.h"
- #include "base/logging.h"
- #include "base/memory/ptr_util.h"
- #include "base/metrics/histogram_macros.h"
- #include "base/task/sequenced_task_runner.h"
- #include "base/trace_event/trace_event.h"
- #include "gpu/config/gpu_finch_features.h"
- #include "media/gpu/macros.h"
- #include "media/gpu/vaapi/va_surface.h"
- #include "media/gpu/vaapi/vaapi_image_decoder.h"
- #include "media/gpu/vaapi/vaapi_jpeg_decoder.h"
- #include "media/gpu/vaapi/vaapi_webp_decoder.h"
- #include "media/gpu/vaapi/vaapi_wrapper.h"
- #include "media/parsers/webp_parser.h"
- #include "mojo/public/cpp/bindings/callback_helpers.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 {
- bool IsJpegImage(base::span<const uint8_t> encoded_data) {
- if (encoded_data.size() < 3u)
- return false;
- return memcmp("\xFF\xD8\xFF", encoded_data.data(), 3u) == 0;
- }
- // Uses |decoder| to decode the image corresponding to |encoded_data|.
- // |decode_cb| is called when finished or when an error is encountered. We don't
- // support decoding to scale, so |output_size| is only used for tracing.
- void DecodeTask(
- VaapiImageDecoder* decoder,
- std::vector<uint8_t> encoded_data,
- const gfx::Size& output_size,
- gpu::ImageDecodeAcceleratorWorker::CompletedDecodeCB decode_cb) {
- TRACE_EVENT2("jpeg", "VaapiImageDecodeAcceleratorWorker::DecodeTask",
- "encoded_bytes", encoded_data.size(), "output_size",
- output_size.ToString());
- gpu::ImageDecodeAcceleratorWorker::CompletedDecodeCB scoped_decode_callback =
- mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(decode_cb),
- nullptr);
- // Decode into a VAAPI surface.
- if (!decoder) {
- DVLOGF(1) << "No decoder is available for supplied image";
- return;
- }
- VaapiImageDecodeStatus status = decoder->Decode(encoded_data);
- if (status != VaapiImageDecodeStatus::kSuccess) {
- DVLOGF(1) << "Failed to decode - status = "
- << static_cast<uint32_t>(status);
- return;
- }
- // Export the decode result as a NativePixmap.
- std::unique_ptr<NativePixmapAndSizeInfo> exported_pixmap =
- decoder->ExportAsNativePixmapDmaBuf(&status);
- if (status != VaapiImageDecodeStatus::kSuccess) {
- DVLOGF(1) << "Failed to export surface - status = "
- << static_cast<uint32_t>(status);
- return;
- }
- DCHECK(exported_pixmap);
- DCHECK(exported_pixmap->pixmap);
- if (exported_pixmap->pixmap->GetBufferSize() != output_size) {
- DVLOGF(1) << "Scaling is not supported";
- return;
- }
- // Output the decoded data.
- gfx::NativePixmapHandle pixmap_handle =
- exported_pixmap->pixmap->ExportHandle();
- // If a dup() failed while exporting the handle, we would get no planes.
- if (pixmap_handle.planes.empty()) {
- DVLOGF(1) << "Could not export the NativePixmapHandle";
- return;
- }
- auto result =
- std::make_unique<gpu::ImageDecodeAcceleratorWorker::DecodeResult>();
- result->handle.type = gfx::GpuMemoryBufferType::NATIVE_PIXMAP;
- result->handle.native_pixmap_handle = std::move(pixmap_handle);
- result->visible_size = exported_pixmap->pixmap->GetBufferSize();
- result->buffer_format = exported_pixmap->pixmap->GetBufferFormat();
- result->buffer_byte_size = exported_pixmap->byte_size;
- result->yuv_color_space = decoder->GetYUVColorSpace();
- std::move(scoped_decode_callback).Run(std::move(result));
- }
- } // namespace
- // static
- std::unique_ptr<VaapiImageDecodeAcceleratorWorker>
- VaapiImageDecodeAcceleratorWorker::Create() {
- // TODO(crbug.com/988123): revisit the
- // Media.VaapiImageDecodeAcceleratorWorker.VAAPIError UMA to be able to record
- // WebP and JPEG failures separately.
- const auto uma_cb =
- base::BindRepeating(&ReportVaapiErrorToUMA,
- "Media.VaapiImageDecodeAcceleratorWorker.VAAPIError");
- VaapiImageDecoderVector decoders;
- auto jpeg_decoder = std::make_unique<VaapiJpegDecoder>();
- // TODO(crbug.com/974438): we can't advertise accelerated image decoding in
- // AMD until we support VAAPI surfaces with multiple buffer objects.
- if (VaapiWrapper::GetImplementationType() != VAImplementation::kMesaGallium &&
- jpeg_decoder->Initialize(uma_cb)) {
- decoders.push_back(std::move(jpeg_decoder));
- }
- auto webp_decoder = std::make_unique<VaapiWebPDecoder>();
- if (webp_decoder->Initialize(uma_cb))
- decoders.push_back(std::move(webp_decoder));
- // If there are no decoders due to disabled flags or initialization failure,
- // return nullptr.
- if (decoders.empty())
- return nullptr;
- return base::WrapUnique(
- new VaapiImageDecodeAcceleratorWorker(std::move(decoders)));
- }
- VaapiImageDecodeAcceleratorWorker::VaapiImageDecodeAcceleratorWorker(
- VaapiImageDecoderVector decoders) {
- DETACH_FROM_SEQUENCE(io_sequence_checker_);
- decoder_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner({});
- DCHECK(decoder_task_runner_);
- DCHECK(!decoders.empty());
- for (auto& decoder : decoders) {
- supported_profiles_.push_back(decoder->GetSupportedProfile());
- const gpu::ImageDecodeAcceleratorType type = decoder->GetType();
- decoders_[type] = std::move(decoder);
- }
- }
- VaapiImageDecodeAcceleratorWorker::~VaapiImageDecodeAcceleratorWorker() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
- DCHECK(decoder_task_runner_);
- for (auto& decoder : decoders_)
- decoder_task_runner_->DeleteSoon(FROM_HERE, std::move(decoder.second));
- }
- gpu::ImageDecodeAcceleratorSupportedProfiles
- VaapiImageDecodeAcceleratorWorker::GetSupportedProfiles() {
- return supported_profiles_;
- }
- VaapiImageDecoder* VaapiImageDecodeAcceleratorWorker::GetDecoderForImage(
- const std::vector<uint8_t>& encoded_data) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(io_sequence_checker_);
- auto result = decoders_.end();
- if (base::FeatureList::IsEnabled(
- features::kVaapiJpegImageDecodeAcceleration) &&
- IsJpegImage(encoded_data)) {
- result = decoders_.find(gpu::ImageDecodeAcceleratorType::kJpeg);
- } else if (base::FeatureList::IsEnabled(
- features::kVaapiWebPImageDecodeAcceleration) &&
- IsLossyWebPImage(encoded_data)) {
- result = decoders_.find(gpu::ImageDecodeAcceleratorType::kWebP);
- }
- return result == decoders_.end() ? nullptr : result->second.get();
- }
- void VaapiImageDecodeAcceleratorWorker::Decode(
- std::vector<uint8_t> encoded_data,
- const gfx::Size& output_size,
- CompletedDecodeCB decode_cb) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(io_sequence_checker_);
- DCHECK(decoder_task_runner_);
- // We defer checking for a null |decoder| until DecodeTask() because the
- // gpu::ImageDecodeAcceleratorWorker interface mandates that the callback be
- // called asynchronously.
- VaapiImageDecoder* decoder = GetDecoderForImage(encoded_data);
- decoder_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&DecodeTask, decoder, std::move(encoded_data),
- output_size, std::move(decode_cb)));
- }
- } // namespace media
|