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, ...@@ -152,10 +152,21 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
return; return;
} }
if (cdm_context || config.is_encrypted()) { if (config.is_encrypted()) {
VLOGF(1) << "Vaapi decoder does not support encrypted stream"; #if !BUILDFLAG(IS_CHROMEOS_ASH)
std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported); std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported);
return; 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 // We expect the decoder to have released all output buffers (by the client
...@@ -185,7 +196,12 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config, ...@@ -185,7 +196,12 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
// Initialize VAAPI wrapper. // Initialize VAAPI wrapper.
const VideoCodecProfile profile = config.profile(); const VideoCodecProfile profile = config.profile();
vaapi_wrapper_ = VaapiWrapper::CreateForVideoCodec( 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, base::BindRepeating(&ReportVaapiErrorToUMA,
"Media.VaapiVideoDecoder.VAAPIError")); "Media.VaapiVideoDecoder.VAAPIError"));
UMA_HISTOGRAM_BOOLEAN("Media.VaapiVideoDecoder.VaapiWrapperCreationSuccess", UMA_HISTOGRAM_BOOLEAN("Media.VaapiVideoDecoder.VaapiWrapperCreationSuccess",
...@@ -218,6 +234,17 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config, ...@@ -218,6 +234,17 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
std::move(init_cb).Run(OkStatus()); 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, void VaapiVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
DecodeCB decode_cb) { DecodeCB decode_cb) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
...@@ -321,8 +348,8 @@ void VaapiVideoDecoder::HandleDecodeTask() { ...@@ -321,8 +348,8 @@ void VaapiVideoDecoder::HandleDecodeTask() {
SetState(State::kError); SetState(State::kError);
break; break;
case AcceleratedVideoDecoder::kTryAgain: case AcceleratedVideoDecoder::kTryAgain:
LOG(ERROR) << "Encrypted streams not supported"; DVLOG(1) << "Decoder going into the waiting for protected state";
SetState(State::kError); SetState(State::kWaitingForProtected);
break; break;
} }
} }
...@@ -477,11 +504,9 @@ void VaapiVideoDecoder::ApplyResolutionChange() { ...@@ -477,11 +504,9 @@ void VaapiVideoDecoder::ApplyResolutionChange() {
CHECK(format); CHECK(format);
auto format_fourcc = Fourcc::FromVideoPixelFormat(*format); auto format_fourcc = Fourcc::FromVideoPixelFormat(*format);
CHECK(format_fourcc); CHECK(format_fourcc);
// TODO(jkardatzke): Pass true for the last argument when we are in protected
// mode.
if (!frame_pool_->Initialize( if (!frame_pool_->Initialize(
*format_fourcc, pic_size, visible_rect, natural_size, *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."; DLOG(WARNING) << "Failed Initialize()ing the frame pool.";
SetState(State::kError); SetState(State::kError);
return; return;
...@@ -501,7 +526,12 @@ void VaapiVideoDecoder::ApplyResolutionChange() { ...@@ -501,7 +526,12 @@ void VaapiVideoDecoder::ApplyResolutionChange() {
// When a profile is changed, we need to re-initialize VaapiWrapper. // When a profile is changed, we need to re-initialize VaapiWrapper.
profile_ = decoder_->GetProfile(); profile_ = decoder_->GetProfile();
auto new_vaapi_wrapper = VaapiWrapper::CreateForVideoCodec( 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, base::BindRepeating(&ReportVaapiErrorToUMA,
"Media.VaapiVideoDecoder.VAAPIError")); "Media.VaapiVideoDecoder.VAAPIError"));
if (!new_vaapi_wrapper.get()) { if (!new_vaapi_wrapper.get()) {
...@@ -557,6 +587,27 @@ void VaapiVideoDecoder::NotifyFrameAvailable() { ...@@ -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() { void VaapiVideoDecoder::Flush() {
DVLOGF(2); DVLOGF(2);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
...@@ -702,6 +753,9 @@ void VaapiVideoDecoder::SetState(State state) { ...@@ -702,6 +753,9 @@ void VaapiVideoDecoder::SetState(State state) {
DCHECK(state_ == State::kUninitialized || state_ == State::kDecoding || DCHECK(state_ == State::kUninitialized || state_ == State::kDecoding ||
state_ == State::kResetting); state_ == State::kResetting);
break; break;
case State::kWaitingForProtected:
DCHECK(!!cdm_context_);
FALLTHROUGH;
case State::kWaitingForOutput: case State::kWaitingForOutput:
DCHECK(current_decode_task_); DCHECK(current_decode_task_);
DCHECK_EQ(state_, State::kDecoding); DCHECK_EQ(state_, State::kDecoding);
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include "base/optional.h" #include "base/optional.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/time/time.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/cdm_context.h"
#include "media/base/status.h" #include "media/base/status.h"
#include "media/base/video_codecs.h" #include "media/base/video_codecs.h"
...@@ -88,14 +90,16 @@ class VaapiVideoDecoder : public DecoderInterface, ...@@ -88,14 +90,16 @@ class VaapiVideoDecoder : public DecoderInterface,
}; };
enum class State { enum class State {
kUninitialized, // not initialized yet or initialization failed. kUninitialized, // not initialized yet or initialization failed.
kWaitingForInput, // waiting for input buffers. kWaitingForInput, // waiting for input buffers.
kWaitingForOutput, // waiting for output buffers. kWaitingForOutput, // waiting for output buffers.
kDecoding, // decoding buffers. kWaitingForProtected, // waiting on something related to protected content,
kChangingResolution, // need to change resolution, waiting for pipeline to // either setup, full sample parsing or key loading.
// be flushed. kDecoding, // decoding buffers.
kResetting, // resetting decoder. kChangingResolution, // need to change resolution, waiting for pipeline to
kError, // decoder encountered an error. // be flushed.
kResetting, // resetting decoder.
kError, // decoder encountered an error.
}; };
VaapiVideoDecoder( VaapiVideoDecoder(
...@@ -119,6 +123,9 @@ class VaapiVideoDecoder : public DecoderInterface, ...@@ -119,6 +123,9 @@ class VaapiVideoDecoder : public DecoderInterface,
void ReleaseVideoFrame(VASurfaceID surface_id); void ReleaseVideoFrame(VASurfaceID surface_id);
// Callback for |frame_pool_| to notify of available resources. // Callback for |frame_pool_| to notify of available resources.
void NotifyFrameAvailable(); 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 // Flushes |decoder_|, blocking until all pending decode tasks have been
// executed and all frames have been output. // executed and all frames have been output.
...@@ -133,6 +140,9 @@ class VaapiVideoDecoder : public DecoderInterface, ...@@ -133,6 +140,9 @@ class VaapiVideoDecoder : public DecoderInterface,
// Change the current |state_| to the specified |state|. // Change the current |state_| to the specified |state|.
void SetState(State state); void SetState(State state);
// Callback for the CDM to notify |this|.
void OnCdmContextEvent(CdmContext::Event event);
// The video decoder's state. // The video decoder's state.
State state_ = State::kUninitialized; State state_ = State::kUninitialized;
...@@ -174,6 +184,12 @@ class VaapiVideoDecoder : public DecoderInterface, ...@@ -174,6 +184,12 @@ class VaapiVideoDecoder : public DecoderInterface,
// TODO(crbug.com/1040291): remove this keep-alive when using SharedImages. // TODO(crbug.com/1040291): remove this keep-alive when using SharedImages.
base::small_map<std::map<gfx::GpuMemoryBufferId, scoped_refptr<VASurface>>> base::small_map<std::map<gfx::GpuMemoryBufferId, scoped_refptr<VASurface>>>
allocated_va_surfaces_; 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. // Platform and codec specific video decoder.
std::unique_ptr<AcceleratedVideoDecoder> 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