Commit 521664a4 authored by Jeffrey Kardatzke's avatar Jeffrey Kardatzke Committed by Commit Bot

VaapiVideoDecoder changes for protected playback

This adds a few things to the VaapiVideoDecoder for
protected content.
-Accepts encrypted/CDM configurations in Initialize
-Registers a callback with the CDM to get notified
 when new decryptions keys are available
-When in protected mode, configures VaapiWrapper that way
-Adds a new kWaitingForProtected state when it is waiting
 for keys, hw config, full sample decryption.
-Callback to be used by accelerators to notify when
 protected decode should resume

BUG=b:153111783,b:155509236
TEST=Builds, protected playback works w/ full set of changes

Change-Id: Ibd52ddd90af732d5ae736989c2008f4f4fdcd38f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2535578
Commit-Queue: Jeffrey Kardatzke <jkardatzke@google.com>
Reviewed-by: default avatarJao-ke Chin-Lee <jchinlee@chromium.org>
Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#829083}
parent b1a178d4
......@@ -152,10 +152,21 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
return;
}
if (cdm_context || config.is_encrypted()) {
VLOGF(1) << "Vaapi decoder does not support encrypted stream";
if (config.is_encrypted()) {
#if !BUILDFLAG(IS_CHROMEOS_ASH)
std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported);
return;
#else
if (!cdm_context || !cdm_context->GetChromeOsCdmContext()) {
LOG(ERROR) << "Cannot support encrypted stream w/out ChromeOsCdmContext";
std::move(init_cb).Run(StatusCode::kDecoderMissingCdmForEncryptedContent);
return;
}
cdm_context_ = cdm_context;
cdm_event_cb_registration_ = cdm_context_->RegisterEventCB(
base::BindRepeating(&VaapiVideoDecoder::OnCdmContextEvent,
weak_this_factory_.GetWeakPtr()));
#endif
}
// We expect the decoder to have released all output buffers (by the client
......@@ -185,7 +196,12 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
// Initialize VAAPI wrapper.
const VideoCodecProfile profile = config.profile();
vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec(
VaapiWrapper::kDecode, profile,
#if BUILDFLAG(IS_CHROMEOS_ASH)
!cdm_context_ ? VaapiWrapper::kDecode : VaapiWrapper::kDecodeProtected,
#else
VaapiWrapper::kDecode,
#endif
profile,
base::BindRepeating(&ReportVaapiErrorToUMA,
"Media.VaapiVideoDecoder.VAAPIError"));
UMA_HISTOGRAM_BOOLEAN("Media.VaapiVideoDecoder.VaapiWrapperCreationSuccess",
......@@ -218,6 +234,17 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
std::move(init_cb).Run(OkStatus());
}
void VaapiVideoDecoder::OnCdmContextEvent(CdmContext::Event event) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (event != CdmContext::Event::kHasAdditionalUsableKey)
return;
// Invoke the callback we'd get for a protected session update because this is
// the same thing, it's a trigger that there are new keys, so if we were
// waiting for a key we should fetch them again.
ProtectedSessionUpdate(true);
}
void VaapiVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
DecodeCB decode_cb) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
......@@ -321,8 +348,8 @@ void VaapiVideoDecoder::HandleDecodeTask() {
SetState(State::kError);
break;
case AcceleratedVideoDecoder::kTryAgain:
LOG(ERROR) << "Encrypted streams not supported";
SetState(State::kError);
DVLOG(1) << "Decoder going into the waiting for protected state";
SetState(State::kWaitingForProtected);
break;
}
}
......@@ -477,11 +504,9 @@ void VaapiVideoDecoder::ApplyResolutionChange() {
CHECK(format);
auto format_fourcc = Fourcc::FromVideoPixelFormat(*format);
CHECK(format_fourcc);
// TODO(jkardatzke): Pass true for the last argument when we are in protected
// mode.
if (!frame_pool_->Initialize(
*format_fourcc, pic_size, visible_rect, natural_size,
decoder_->GetRequiredNumOfPictures(), /*use_protected=*/false)) {
decoder_->GetRequiredNumOfPictures(), !!cdm_context_)) {
DLOG(WARNING) << "Failed Initialize()ing the frame pool.";
SetState(State::kError);
return;
......@@ -501,7 +526,12 @@ void VaapiVideoDecoder::ApplyResolutionChange() {
// When a profile is changed, we need to re-initialize VaapiWrapper.
profile_ = decoder_->GetProfile();
auto new_vaapi_wrapper = VaapiWrapper::CreateForVideoCodec(
VaapiWrapper::kDecode, profile_,
#if BUILDFLAG(IS_CHROMEOS_ASH)
!cdm_context_ ? VaapiWrapper::kDecode : VaapiWrapper::kDecodeProtected,
#else
VaapiWrapper::kDecode,
#endif
profile_,
base::BindRepeating(&ReportVaapiErrorToUMA,
"Media.VaapiVideoDecoder.VAAPIError"));
if (!new_vaapi_wrapper.get()) {
......@@ -557,6 +587,27 @@ void VaapiVideoDecoder::NotifyFrameAvailable() {
}
}
void VaapiVideoDecoder::ProtectedSessionUpdate(bool success) {
DVLOGF(4);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!success) {
LOG(ERROR) << "Terminating decoding after failed protected update";
SetState(State::kError);
return;
}
// If we were waiting for a protected update, retry the current decode task.
if (state_ != State::kWaitingForProtected)
return;
DCHECK(current_decode_task_);
SetState(State::kDecoding);
decoder_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&VaapiVideoDecoder::HandleDecodeTask, weak_this_));
}
void VaapiVideoDecoder::Flush() {
DVLOGF(2);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
......@@ -702,6 +753,9 @@ void VaapiVideoDecoder::SetState(State state) {
DCHECK(state_ == State::kUninitialized || state_ == State::kDecoding ||
state_ == State::kResetting);
break;
case State::kWaitingForProtected:
DCHECK(!!cdm_context_);
FALLTHROUGH;
case State::kWaitingForOutput:
DCHECK(current_decode_task_);
DCHECK_EQ(state_, State::kDecoding);
......
......@@ -22,6 +22,8 @@
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "build/chromeos_buildflags.h"
#include "media/base/callback_registry.h"
#include "media/base/cdm_context.h"
#include "media/base/status.h"
#include "media/base/video_codecs.h"
......@@ -88,14 +90,16 @@ class VaapiVideoDecoder : public DecoderInterface,
};
enum class State {
kUninitialized, // not initialized yet or initialization failed.
kWaitingForInput, // waiting for input buffers.
kWaitingForOutput, // waiting for output buffers.
kDecoding, // decoding buffers.
kChangingResolution, // need to change resolution, waiting for pipeline to
// be flushed.
kResetting, // resetting decoder.
kError, // decoder encountered an error.
kUninitialized, // not initialized yet or initialization failed.
kWaitingForInput, // waiting for input buffers.
kWaitingForOutput, // waiting for output buffers.
kWaitingForProtected, // waiting on something related to protected content,
// either setup, full sample parsing or key loading.
kDecoding, // decoding buffers.
kChangingResolution, // need to change resolution, waiting for pipeline to
// be flushed.
kResetting, // resetting decoder.
kError, // decoder encountered an error.
};
VaapiVideoDecoder(
......@@ -119,6 +123,9 @@ class VaapiVideoDecoder : public DecoderInterface,
void ReleaseVideoFrame(VASurfaceID surface_id);
// Callback for |frame_pool_| to notify of available resources.
void NotifyFrameAvailable();
// Callback from accelerator to indicate the protected state has been updated
// so we can proceed or fail.
void ProtectedSessionUpdate(bool success);
// Flushes |decoder_|, blocking until all pending decode tasks have been
// executed and all frames have been output.
......@@ -133,6 +140,9 @@ class VaapiVideoDecoder : public DecoderInterface,
// Change the current |state_| to the specified |state|.
void SetState(State state);
// Callback for the CDM to notify |this|.
void OnCdmContextEvent(CdmContext::Event event);
// The video decoder's state.
State state_ = State::kUninitialized;
......@@ -174,6 +184,12 @@ class VaapiVideoDecoder : public DecoderInterface,
// TODO(crbug.com/1040291): remove this keep-alive when using SharedImages.
base::small_map<std::map<gfx::GpuMemoryBufferId, scoped_refptr<VASurface>>>
allocated_va_surfaces_;
#if BUILDFLAG(IS_CHROMEOS_ASH)
// To keep the CdmContext event callback registered.
std::unique_ptr<CallbackRegistration> cdm_event_cb_registration_;
#endif
CdmContext* cdm_context_ = nullptr; // Not owned.
// Platform and codec specific video decoder.
std::unique_ptr<AcceleratedVideoDecoder> decoder_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment