Commit b069339e authored by Jeffrey Kardatzke's avatar Jeffrey Kardatzke Committed by Chromium LUCI CQ

vaapi: Establish protected session before decode starts

This resolves issues with the driver misinterpreting what frames
are encrypted during the clear lead. The main effect is now we will only
be using protected surfaces with an active protected session.

NOTE: This breaks full sample encryption, we are sorting that out with
Intel, but that's a tiny corner case compared to the benefit this has so
we will enable this now.

BUG=b:153111783,
TEST=Protected playback works for VP9/H264 subsample

Change-Id: Id189f856a911140c5a4a9b9c57d539eeeb24c901
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2583111
Commit-Queue: Jeffrey Kardatzke <jkardatzke@google.com>
Reviewed-by: default avatarJao-ke Chin-Lee <jchinlee@chromium.org>
Cr-Commit-Position: refs/heads/master@{#835962}
parent b95a476f
......@@ -49,11 +49,13 @@ H264VaapiVideoDecoderDelegate::H264VaapiVideoDecoderDelegate(
DecodeSurfaceHandler<VASurface>* const vaapi_dec,
scoped_refptr<VaapiWrapper> vaapi_wrapper,
ProtectedSessionUpdateCB on_protected_session_update_cb,
CdmContext* cdm_context)
CdmContext* cdm_context,
EncryptionScheme encryption_scheme)
: VaapiVideoDecoderDelegate(vaapi_dec,
std::move(vaapi_wrapper),
std::move(on_protected_session_update_cb),
cdm_context) {}
cdm_context,
encryption_scheme) {}
H264VaapiVideoDecoderDelegate::~H264VaapiVideoDecoderDelegate() = default;
......@@ -366,14 +368,15 @@ DecodeStatus H264VaapiVideoDecoderDelegate::SubmitSlice(
bool uses_crypto = false;
VAEncryptionParameters crypto_params = {};
const bool encrypted_bytes_present =
!subsamples.empty() && subsamples[0].cypher_bytes;
if (encrypted_bytes_present || IsProtectedSession()) {
// If there is only one clear byte, then this is CENC v1, full sample
// encryption (i.e. only the NALU header is unencrypted).
if (IsEncryptedSession()) {
// Always indicate full sample since H264 can support that and we don't know
// yet which it is.
// TODO(jkardatzke): Fix full sample encryption, specifying true for it here
// always will cause H264 subsample to fail and we don't know which it is
// yet.
const ProtectedSessionState state = SetupDecryptDecode(
!subsamples.empty() && subsamples[0].clear_bytes == 1, size,
&crypto_params, &encryption_segment_info_, subsamples);
/*full_sample=*/false, size, &crypto_params, &encryption_segment_info_,
subsamples);
if (state == ProtectedSessionState::kFailed) {
LOG(ERROR) << "SubmitSlice fails because we couldn't setup the protected "
"session";
......
......@@ -28,7 +28,8 @@ class H264VaapiVideoDecoderDelegate : public H264Decoder::H264Accelerator,
scoped_refptr<VaapiWrapper> vaapi_wrapper,
ProtectedSessionUpdateCB on_protected_session_update_cb =
base::DoNothing(),
CdmContext* cdm_context = nullptr);
CdmContext* cdm_context = nullptr,
EncryptionScheme encryption_scheme = EncryptionScheme::kUnencrypted);
~H264VaapiVideoDecoderDelegate() override;
// H264Decoder::H264Accelerator implementation.
......
......@@ -41,11 +41,13 @@ H265VaapiVideoDecoderDelegate::H265VaapiVideoDecoderDelegate(
DecodeSurfaceHandler<VASurface>* const vaapi_dec,
scoped_refptr<VaapiWrapper> vaapi_wrapper,
ProtectedSessionUpdateCB on_protected_session_update_cb,
CdmContext* cdm_context)
CdmContext* cdm_context,
EncryptionScheme encryption_scheme)
: VaapiVideoDecoderDelegate(vaapi_dec,
std::move(vaapi_wrapper),
std::move(on_protected_session_update_cb),
cdm_context) {
cdm_context,
encryption_scheme) {
ref_pic_list_pocs_.reserve(kMaxRefIdxActive);
}
......@@ -297,9 +299,7 @@ DecodeStatus H265VaapiVideoDecoderDelegate::SubmitSlice(
bool uses_crypto = false;
VAEncryptionParameters crypto_params = {};
const bool encrypted_bytes_present =
!subsamples.empty() && subsamples[0].cypher_bytes;
if (encrypted_bytes_present || IsProtectedSession()) {
if (IsEncryptedSession()) {
const ProtectedSessionState state =
SetupDecryptDecode(/*full_sample=*/false, size, &crypto_params,
&encryption_segment_info_, subsamples);
......
......@@ -28,7 +28,8 @@ class H265VaapiVideoDecoderDelegate : public H265Decoder::H265Accelerator,
DecodeSurfaceHandler<VASurface>* vaapi_dec,
scoped_refptr<VaapiWrapper> vaapi_wrapper,
ProtectedSessionUpdateCB on_protected_session_update_cb,
CdmContext* cdm_context);
CdmContext* cdm_context,
EncryptionScheme encryption_scheme);
H265VaapiVideoDecoderDelegate(const H265VaapiVideoDecoderDelegate&) = delete;
H265VaapiVideoDecoderDelegate& operator=(
......
......@@ -234,6 +234,7 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
profile_ = profile;
color_space_ = config.color_space_info();
encryption_scheme_ = config.encryption_scheme();
auto accel_status = CreateAcceleratedVideoDecoder();
if (!accel_status.is_ok()) {
std::move(init_cb).Run(std::move(accel_status));
......@@ -707,7 +708,8 @@ Status VaapiVideoDecoder::CreateAcceleratedVideoDecoder() {
if (profile_ >= H264PROFILE_MIN && profile_ <= H264PROFILE_MAX) {
auto accelerator = std::make_unique<H264VaapiVideoDecoderDelegate>(
this, vaapi_wrapper_, std::move(protected_update_cb),
cdm_context_ref_ ? cdm_context_ref_->GetCdmContext() : nullptr);
cdm_context_ref_ ? cdm_context_ref_->GetCdmContext() : nullptr,
encryption_scheme_);
decoder_delegate_ = accelerator.get();
decoder_.reset(
......@@ -721,7 +723,8 @@ Status VaapiVideoDecoder::CreateAcceleratedVideoDecoder() {
} else if (profile_ >= VP9PROFILE_MIN && profile_ <= VP9PROFILE_MAX) {
auto accelerator = std::make_unique<VP9VaapiVideoDecoderDelegate>(
this, vaapi_wrapper_, std::move(protected_update_cb),
cdm_context_ref_ ? cdm_context_ref_->GetCdmContext() : nullptr);
cdm_context_ref_ ? cdm_context_ref_->GetCdmContext() : nullptr,
encryption_scheme_);
decoder_delegate_ = accelerator.get();
decoder_.reset(
......@@ -731,7 +734,8 @@ Status VaapiVideoDecoder::CreateAcceleratedVideoDecoder() {
else if (profile_ >= HEVCPROFILE_MIN && profile_ <= HEVCPROFILE_MAX) {
auto accelerator = std::make_unique<H265VaapiVideoDecoderDelegate>(
this, vaapi_wrapper_, std::move(protected_update_cb),
cdm_context_ref_ ? cdm_context_ref_->GetCdmContext() : nullptr);
cdm_context_ref_ ? cdm_context_ref_->GetCdmContext() : nullptr,
encryption_scheme_);
decoder_delegate_ = accelerator.get();
decoder_.reset(
......
......@@ -196,6 +196,8 @@ class VaapiVideoDecoder : public DecoderInterface,
// pipeline (and thus the VaapiVideoDecoder) on the decoder thread.
std::unique_ptr<CdmContextRef> cdm_context_ref_;
EncryptionScheme encryption_scheme_;
#if BUILDFLAG(IS_CHROMEOS_ASH)
// To keep the CdmContext event callback registered.
std::unique_ptr<CallbackRegistration> cdm_event_cb_registration_;
......
......@@ -22,11 +22,13 @@ VaapiVideoDecoderDelegate::VaapiVideoDecoderDelegate(
DecodeSurfaceHandler<VASurface>* const vaapi_dec,
scoped_refptr<VaapiWrapper> vaapi_wrapper,
ProtectedSessionUpdateCB on_protected_session_update_cb,
CdmContext* cdm_context)
CdmContext* cdm_context,
EncryptionScheme encryption_scheme)
: vaapi_dec_(vaapi_dec),
vaapi_wrapper_(std::move(vaapi_wrapper)),
on_protected_session_update_cb_(
std::move(on_protected_session_update_cb)),
encryption_scheme_(encryption_scheme),
protected_session_state_(ProtectedSessionState::kNotCreated) {
DCHECK(vaapi_wrapper_);
DCHECK(vaapi_dec_);
......@@ -56,17 +58,14 @@ bool VaapiVideoDecoderDelegate::SetDecryptConfig(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// It is possible to switch between clear and encrypted (and vice versa), but
// we should not be changing encryption schemes across encrypted portions.
if (decrypt_config_) {
if (!decrypt_config)
return true;
// TODO(jkardatzke): Handle changing encryption modes midstream, the latest
// OEMCrypto spec allows this, although we won't hit it in reality for now.
// Check to make sure they are compatible.
if (decrypt_config_->encryption_scheme() !=
decrypt_config->encryption_scheme()) {
LOG(ERROR) << "Cannot change encryption modes midstream";
return false;
}
if (!decrypt_config)
return true;
// TODO(jkardatzke): Handle changing encryption modes midstream, the latest
// OEMCrypto spec allows this, although we won't hit it in reality for now.
// Check to make sure they are compatible.
if (decrypt_config->encryption_scheme() != encryption_scheme_) {
LOG(ERROR) << "Cannot change encryption modes midstream";
return false;
}
decrypt_config_ = std::move(decrypt_config);
return true;
......@@ -83,15 +82,13 @@ VaapiVideoDecoderDelegate::SetupDecryptDecode(
#if BUILDFLAG(IS_CHROMEOS_ASH)
DCHECK(crypto_params);
DCHECK(segments);
DCHECK(decrypt_config_);
if (protected_session_state_ == ProtectedSessionState::kInProcess ||
protected_session_state_ == ProtectedSessionState::kFailed) {
return protected_session_state_;
}
if (protected_session_state_ == ProtectedSessionState::kNotCreated) {
if (!decrypt_config_ || !chromeos_cdm_context_) {
LOG(ERROR) << "Cannot create protected session w/out "
"DecryptConfig/ChromeOsCdmContext";
if (!chromeos_cdm_context_) {
LOG(ERROR) << "Cannot create protected session w/out ChromeOsCdmContext";
protected_session_state_ = ProtectedSessionState::kFailed;
return protected_session_state_;
}
......@@ -107,7 +104,7 @@ VaapiVideoDecoderDelegate::SetupDecryptDecode(
DCHECK_EQ(protected_session_state_, ProtectedSessionState::kCreated);
if (decrypt_config_->encryption_scheme() == EncryptionScheme::kCenc) {
if (encryption_scheme_ == EncryptionScheme::kCenc) {
crypto_params->encryption_type =
full_sample_ ? VA_ENCRYPTION_TYPE_CENC_CTR : VA_ENCRYPTION_TYPE_CTR_128;
} else {
......@@ -119,7 +116,8 @@ VaapiVideoDecoderDelegate::SetupDecryptDecode(
crypto_params->encryption_type = VA_ENCRYPTION_TYPE_CBC;
}
if (subsamples.empty()) {
if (subsamples.empty() ||
(subsamples.size() == 1 && subsamples[0].cypher_bytes == 0)) {
// We still need to specify the crypto params to the driver for some reason
// and indicate the entire content is clear.
VAEncryptionSegmentInfo segment_info = {};
......@@ -136,6 +134,7 @@ VaapiVideoDecoderDelegate::SetupDecryptDecode(
return protected_session_state_;
}
DCHECK(decrypt_config_);
// We also need to make sure we have the key data for the active
// DecryptConfig now that the protected session exists.
if (!hw_key_data_map_.count(decrypt_config_->key_id())) {
......@@ -206,9 +205,8 @@ void VaapiVideoDecoderDelegate::OnGetHwConfigData(
}
hw_identifier_.clear();
if (!vaapi_wrapper_->CreateProtectedSession(
decrypt_config_->encryption_scheme(), full_sample_, config_data,
&hw_identifier_)) {
if (!vaapi_wrapper_->CreateProtectedSession(encryption_scheme_, full_sample_,
config_data, &hw_identifier_)) {
LOG(ERROR) << "Failed to setup protected session";
protected_session_state_ = ProtectedSessionState::kFailed;
on_protected_session_update_cb_.Run(false);
......
......@@ -17,6 +17,7 @@
#include "base/sequence_checker.h"
#include "build/chromeos_buildflags.h"
#include "media/base/decryptor.h"
#include "media/base/encryption_scheme.h"
#include "media/base/subsample_entry.h"
#include "third_party/libva_protected_content/va_protected_content.h"
......@@ -49,7 +50,8 @@ class VaapiVideoDecoderDelegate {
DecodeSurfaceHandler<VASurface>* const vaapi_dec,
scoped_refptr<VaapiWrapper> vaapi_wrapper,
ProtectedSessionUpdateCB on_protected_session_update_cb,
CdmContext* cdm_context);
CdmContext* cdm_context,
EncryptionScheme encryption_scheme = EncryptionScheme::kUnencrypted);
virtual ~VaapiVideoDecoderDelegate();
void set_vaapi_wrapper(scoped_refptr<VaapiWrapper> vaapi_wrapper);
......@@ -79,9 +81,8 @@ class VaapiVideoDecoderDelegate {
// is setup for a protected session, it will fill in the |crypto_params|.
// |segments| must retain its memory until the frame is submitted.
// |subsamples| is for the current slice. |size| is the size of the slice
// data. This should be called if IsProtectedSession() is true even if the
// data is not encrypted (i.e. |subsamples| is empty), and in that case the
// |full_sample| parameter is ignored.
// data. This should be called if IsEncrypted() is true even if the current
// data is not encrypted (i.e. |subsamples| is empty).
ProtectedSessionState SetupDecryptDecode(
bool full_sample,
size_t size,
......@@ -89,10 +90,10 @@ class VaapiVideoDecoderDelegate {
std::vector<VAEncryptionSegmentInfo>* segments,
const std::vector<SubsampleEntry>& subsamples);
// Returns true if we have established a protected session, in which case
// SetupDecryptDecode() should be called for every slice after that.
bool IsProtectedSession() const {
return protected_session_state_ == ProtectedSessionState::kCreated;
// Returns true if we are handling encrypted content, in which case
// SetupDecryptDecode() should be called for every slice.
bool IsEncryptedSession() const {
return encryption_scheme_ != EncryptionScheme::kUnencrypted;
}
// Both owned by caller.
......@@ -112,6 +113,7 @@ class VaapiVideoDecoderDelegate {
#if BUILDFLAG(IS_CHROMEOS_ASH)
chromeos::ChromeOsCdmContext* chromeos_cdm_context_{nullptr}; // Not owned.
#endif
EncryptionScheme encryption_scheme_;
ProtectedSessionState protected_session_state_;
std::unique_ptr<DecryptConfig> decrypt_config_;
bool full_sample_;
......
......@@ -22,11 +22,13 @@ VP9VaapiVideoDecoderDelegate::VP9VaapiVideoDecoderDelegate(
DecodeSurfaceHandler<VASurface>* const vaapi_dec,
scoped_refptr<VaapiWrapper> vaapi_wrapper,
ProtectedSessionUpdateCB on_protected_session_update_cb,
CdmContext* cdm_context)
CdmContext* cdm_context,
EncryptionScheme encryption_scheme)
: VaapiVideoDecoderDelegate(vaapi_dec,
std::move(vaapi_wrapper),
std::move(on_protected_session_update_cb),
cdm_context) {}
cdm_context,
encryption_scheme) {}
VP9VaapiVideoDecoderDelegate::~VP9VaapiVideoDecoderDelegate() {
DCHECK(!picture_params_);
......@@ -86,10 +88,7 @@ DecodeStatus VP9VaapiVideoDecoderDelegate::SubmitDecode(
return DecodeStatus::kFail;
VAEncryptionParameters crypto_param{};
const bool encrypted_bytes_present =
decrypt_config && !decrypt_config->subsamples().empty() &&
decrypt_config->subsamples()[0].cypher_bytes;
if (encrypted_bytes_present || IsProtectedSession()) {
if (IsEncryptedSession()) {
const ProtectedSessionState state = SetupDecryptDecode(
/*full_sample=*/false, frame_hdr->frame_size, &crypto_param,
&encryption_segment_info,
......
......@@ -24,7 +24,8 @@ class VP9VaapiVideoDecoderDelegate : public VP9Decoder::VP9Accelerator,
scoped_refptr<VaapiWrapper> vaapi_wrapper,
ProtectedSessionUpdateCB on_protected_session_update_cb =
base::DoNothing(),
CdmContext* cdm_context = nullptr);
CdmContext* cdm_context = nullptr,
EncryptionScheme encryption_scheme = EncryptionScheme::kUnencrypted);
~VP9VaapiVideoDecoderDelegate() override;
// VP9Decoder::VP9Accelerator implementation.
......
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