// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/mojo/services/gpu_mojo_media_client.h"
#include "base/android/build_info.h"
#include "base/task/sequenced_task_runner.h"
#include "gpu/command_buffer/service/ref_counted_lock.h"
#include "gpu/config/gpu_finch_features.h"
#include "media/base/android/android_cdm_factory.h"
#include "media/base/media_log.h"
#include "media/base/media_switches.h"
#include "media/filters/android/media_codec_audio_decoder.h"
#include "media/gpu/android/android_video_surface_chooser_impl.h"
#include "media/gpu/android/codec_allocator.h"
#include "media/gpu/android/direct_shared_image_video_provider.h"
#include "media/gpu/android/maybe_render_early_manager.h"
#include "media/gpu/android/media_codec_video_decoder.h"
#include "media/gpu/android/pooled_shared_image_video_provider.h"
#include "media/gpu/android/video_frame_factory_impl.h"
#include "media/media_buildflags.h"
#include "media/mojo/services/android_mojo_util.h"
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
#include "media/gpu/android/ndk_audio_encoder.h"
#endif
using media::android_mojo_util::CreateMediaDrmStorage;
using media::android_mojo_util::CreateProvisionFetcher;
namespace media {
class GpuMojoMediaClientAndroid final : public GpuMojoMediaClient {
public:
GpuMojoMediaClientAndroid(GpuMojoMediaClientTraits& traits)
: GpuMojoMediaClient(traits) {
android_overlay_factory_cb_ = std::move(traits.android_overlay_factory_cb);
}
~GpuMojoMediaClientAndroid() final = default;
protected:
std::unique_ptr<VideoDecoder> CreatePlatformVideoDecoder(
VideoDecoderTraits& traits) final {
scoped_refptr<gpu::RefCountedLock> ref_counted_lock;
// When this feature is enabled, CodecImage, CodecBufferWaitCoordinator and
// other media classes used in MCVD path will be accessed by multiple gpu
// threads. To implement thread safetyness, we are using a global ref
// counted lock here. CodecImage, CodecOutputBufferRenderer,
// CodecBufferWaitCoordinator expects this ref counted lock to be held by
// the classes which are accessing them (AndroidVideoImageBacking, MRE,
// FrameInfoHelper etc.)
if (features::NeedThreadSafeAndroidMedia()) {
ref_counted_lock = base::MakeRefCounted<gpu::RefCountedLock>();
}
std::unique_ptr<SharedImageVideoProvider> image_provider =
std::make_unique<DirectSharedImageVideoProvider>(
gpu_task_runner_, traits.get_command_buffer_stub_cb,
ref_counted_lock);
if (base::FeatureList::IsEnabled(kUsePooledSharedImageVideoProvider)) {
// Wrap |image_provider| in a pool.
image_provider = PooledSharedImageVideoProvider::Create(
gpu_task_runner_, traits.get_command_buffer_stub_cb,
std::move(image_provider), ref_counted_lock);
}
// TODO(liberato): Create this only if we're using Vulkan, else it's
// ignored. If we can tell that here, then VideoFrameFactory can use it
// as a signal about whether it's supposed to get YCbCrInfo rather than
// requiring the provider to set |is_vulkan| in the ImageRecord.
auto frame_info_helper = FrameInfoHelper::Create(
gpu_task_runner_, traits.get_command_buffer_stub_cb, ref_counted_lock);
return MediaCodecVideoDecoder::Create(
gpu_preferences_, gpu_feature_info_, traits.media_log->Clone(),
DeviceInfo::GetInstance(),
CodecAllocator::GetInstance(gpu_task_runner_),
std::make_unique<AndroidVideoSurfaceChooserImpl>(
DeviceInfo::GetInstance()->IsSetOutputSurfaceSupported()),
android_overlay_factory_cb_, std::move(traits.request_overlay_info_cb),
std::make_unique<VideoFrameFactoryImpl>(
gpu_task_runner_, gpu_preferences_, std::move(image_provider),
MaybeRenderEarlyManager::Create(gpu_task_runner_, ref_counted_lock),
std::move(frame_info_helper), ref_counted_lock),
ref_counted_lock);
}
std::optional<SupportedAudioDecoderConfigs>
GetPlatformSupportedAudioDecoderConfigs() final {
SupportedAudioDecoderConfigs audio_configs;
if (base::android::BuildInfo::GetInstance()->sdk_int() >=
base::android::SDK_VERSION_P) {
audio_configs.emplace_back(AudioCodec::kAAC, AudioCodecProfile::kXHE_AAC);
}
return audio_configs;
}
std::optional<SupportedVideoDecoderConfigs>
GetPlatformSupportedVideoDecoderConfigs() final {
return MediaCodecVideoDecoder::GetSupportedConfigs();
}
std::unique_ptr<AudioDecoder> CreatePlatformAudioDecoder(
scoped_refptr<base::SequencedTaskRunner> task_runner,
std::unique_ptr<MediaLog> media_log) final {
return std::make_unique<MediaCodecAudioDecoder>(std::move(task_runner));
}
std::unique_ptr<AudioEncoder> CreatePlatformAudioEncoder(
scoped_refptr<base::SequencedTaskRunner> task_runner) final {
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
if (__builtin_available(android NDK_MEDIA_CODEC_MIN_API, *)) {
return std::make_unique<NdkAudioEncoder>(std::move(task_runner));
}
#endif
return nullptr;
}
std::unique_ptr<CdmFactory> CreatePlatformCdmFactory(
mojom::FrameInterfaceFactory* frame_interfaces) final {
return std::make_unique<AndroidCdmFactory>(
base::BindRepeating(&CreateProvisionFetcher, frame_interfaces),
base::BindRepeating(&CreateMediaDrmStorage, frame_interfaces));
}
VideoDecoderType GetPlatformDecoderImplementationType() final {
return VideoDecoderType::kMediaCodec;
}
AndroidOverlayMojoFactoryCB android_overlay_factory_cb_;
};
std::unique_ptr<GpuMojoMediaClient> CreateGpuMediaService(
GpuMojoMediaClientTraits& traits) {
return std::make_unique<GpuMojoMediaClientAndroid>(traits);
}
} // namespace media