#include "media/renderers/decrypting_renderer.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/task/sequenced_task_runner.h"
#include "media/base/cdm_context.h"
#include "media/base/demuxer_stream.h"
#include "media/base/media_log.h"
#include "media/base/media_resource.h"
#include "media/base/renderer_client.h"
#include "media/filters/decrypting_demuxer_stream.h"
#include "media/filters/decrypting_media_resource.h"
namespace media {
DecryptingRenderer::DecryptingRenderer(
std::unique_ptr<Renderer> renderer,
MediaLog* media_log,
const scoped_refptr<base::SequencedTaskRunner> media_task_runner)
: renderer_(std::move(renderer)),
media_log_(media_log),
media_task_runner_(media_task_runner),
client_(nullptr),
media_resource_(nullptr),
decrypting_media_resource_(nullptr) {
DCHECK(renderer_);
}
DecryptingRenderer::~DecryptingRenderer() {}
void DecryptingRenderer::Initialize(MediaResource* media_resource,
RendererClient* client,
#if BUILDFLAG(ARKWEB_VIDEO_ASSISTANT)
RequestSurfaceCB request_surface_cb,
VideoDecoderChangedCB decoder_changed_cb,
#endif
PipelineStatusCallback init_cb) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
DCHECK(media_resource);
DCHECK(client);
media_resource_ = media_resource;
client_ = client;
init_cb_ = std::move(init_cb);
#if BUILDFLAG(ARKWEB_VIDEO_ASSISTANT)
request_surface_cb_ = std::move(request_surface_cb);
decoder_changed_cb_ = std::move(decoder_changed_cb);
#endif
bool has_encrypted_stream = HasEncryptedStream();
if (!cdm_context_ && has_encrypted_stream) {
waiting_for_cdm_ = true;
return;
}
if (cdm_context_ && cdm_context_->GetDecryptor() &&
cdm_context_->GetDecryptor()->CanAlwaysDecrypt()) {
CreateAndInitializeDecryptingMediaResource();
return;
}
InitializeRenderer(true);
}
void DecryptingRenderer::SetCdm(CdmContext* cdm_context,
CdmAttachedCB cdm_attached_cb) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
if (cdm_context_) {
DVLOG(1) << "Switching CDM not supported.";
std::move(cdm_attached_cb).Run(false);
return;
}
cdm_context_ = cdm_context;
if (cdm_context_->GetDecryptor() &&
cdm_context_->GetDecryptor()->CanAlwaysDecrypt()) {
if (waiting_for_cdm_)
CreateAndInitializeDecryptingMediaResource();
std::move(cdm_attached_cb).Run(true);
return;
}
renderer_->SetCdm(cdm_context_, std::move(cdm_attached_cb));
if (waiting_for_cdm_)
InitializeRenderer(true);
}
void DecryptingRenderer::SetLatencyHint(
std::optional<base::TimeDelta> latency_hint) {
renderer_->SetLatencyHint(latency_hint);
}
void DecryptingRenderer::SetPreservesPitch(bool preserves_pitch) {
renderer_->SetPreservesPitch(preserves_pitch);
}
void DecryptingRenderer::SetWasPlayedWithUserActivationAndHighMediaEngagement(
bool was_played_with_user_activation_and_high_media_engagement) {
renderer_->SetWasPlayedWithUserActivationAndHighMediaEngagement(
was_played_with_user_activation_and_high_media_engagement);
}
void DecryptingRenderer::Flush(base::OnceClosure flush_cb) {
renderer_->Flush(std::move(flush_cb));
}
void DecryptingRenderer::StartPlayingFrom(base::TimeDelta time) {
renderer_->StartPlayingFrom(time);
}
void DecryptingRenderer::SetPlaybackRate(double playback_rate) {
renderer_->SetPlaybackRate(playback_rate);
}
void DecryptingRenderer::SetVolume(float volume) {
renderer_->SetVolume(volume);
}
base::TimeDelta DecryptingRenderer::GetMediaTime() {
return renderer_->GetMediaTime();
}
void DecryptingRenderer::OnTracksChanged(
DemuxerStream::Type track_type,
DemuxerStream* enabled_track,
base::OnceClosure change_completed_cb) {
renderer_->OnTracksChanged(track_type, enabled_track,
std::move(change_completed_cb));
}
RendererType DecryptingRenderer::GetRendererType() {
return renderer_->GetRendererType();
}
void DecryptingRenderer::CreateAndInitializeDecryptingMediaResource() {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
DCHECK(init_cb_);
decrypting_media_resource_ = std::make_unique<DecryptingMediaResource>(
media_resource_, cdm_context_, media_log_, media_task_runner_);
decrypting_media_resource_->Initialize(
base::BindOnce(&DecryptingRenderer::InitializeRenderer,
weak_factory_.GetWeakPtr()),
base::BindRepeating(&DecryptingRenderer::OnWaiting,
weak_factory_.GetWeakPtr()));
}
void DecryptingRenderer::InitializeRenderer(bool success) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
if (!success) {
std::move(init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
return;
}
MediaResource* const maybe_decrypting_media_resource =
decrypting_media_resource_ ? decrypting_media_resource_.get()
: media_resource_.get();
renderer_->Initialize(maybe_decrypting_media_resource, client_,
#if BUILDFLAG(ARKWEB_VIDEO_ASSISTANT)
std::move(request_surface_cb_),
std::move(decoder_changed_cb_),
#endif
std::move(init_cb_));
}
bool DecryptingRenderer::HasEncryptedStream() {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
for (media::DemuxerStream* stream : media_resource_->GetAllStreams()) {
if ((stream->type() == DemuxerStream::AUDIO &&
stream->audio_decoder_config().is_encrypted()) ||
(stream->type() == DemuxerStream::VIDEO &&
stream->video_decoder_config().is_encrypted())) {
return true;
}
}
return false;
}
bool DecryptingRenderer::HasDecryptingMediaResourceForTesting() const {
return decrypting_media_resource_ != nullptr;
}
void DecryptingRenderer::OnWaiting(WaitingReason reason) {
DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
client_->OnWaiting(reason);
}
}