Skip to content

Commit

Permalink
media: Refactor supported CDM version check
Browse files Browse the repository at this point in the history
- Convert runtime DCHECK to compile time static_assert.
- Add helper function to simplify the check logic.
- Use CDM interface version as CdmWrapperImpl template argument to
  simplify some code and check logic.

Bug: 799169,733821
Test: No functionality change.
Change-Id: I2a97be9a507db853eb91b739bf26511492665eee
Reviewed-on: https://chromium-review.googlesource.com/1018144
Reviewed-by: John Rummell <jrummell@chromium.org>
Commit-Queue: Xiaohan Wang <xhwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#552070}
  • Loading branch information
xhwang-chromium authored and Commit Bot committed Apr 19, 2018
1 parent 0360b9e commit ff1f496
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 94 deletions.
18 changes: 3 additions & 15 deletions media/cdm/cdm_adapter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -412,21 +412,9 @@ void* GetCdmHost(int host_interface_version, void* user_data) {
return nullptr;

static_assert(
cdm::ContentDecryptionModule::Host::kVersion == cdm::Host_9::kVersion,
"update the code below");

// Ensure IsSupportedCdmHostVersion matches implementation of this function.
// Always update this DCHECK when updating this function.
// If this check fails, update this function and DCHECK or update
// IsSupportedCdmHostVersion.

// TODO(xhwang): Static assert these at compile time.
const int kMinVersion = cdm::ContentDecryptionModule_9::kVersion;
const int kMaxVersion = cdm::ContentDecryptionModule_10::kVersion;
DCHECK(!IsSupportedCdmInterfaceVersion(kMinVersion - 1));
for (int version = kMinVersion; version <= kMaxVersion; ++version)
DCHECK(IsSupportedCdmInterfaceVersion(version));
DCHECK(!IsSupportedCdmInterfaceVersion(kMaxVersion + 1));
CheckSupportedCdmHostVersions(9, 10),
"Mismatch between GetCdmHost() and IsSupportedCdmHostVersion()");

DCHECK(IsSupportedCdmHostVersion(host_interface_version));

CdmAdapter* cdm_adapter = static_cast<CdmAdapter*>(user_data);
Expand Down
87 changes: 40 additions & 47 deletions media/cdm/cdm_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,30 +171,49 @@ class CdmWrapper {
DISALLOW_COPY_AND_ASSIGN(CdmWrapper);
};

// Traits for CDM Interfaces
template <int CdmInterfaceVersion>
struct CdmInterfaceTraits {};

template <>
struct CdmInterfaceTraits<9> {
using CdmInterface = cdm::ContentDecryptionModule_9;
};

template <>
struct CdmInterfaceTraits<10> {
using CdmInterface = cdm::ContentDecryptionModule_10;
};

// Template class that does the CdmWrapper -> CdmInterface conversion. Default
// implementations are provided. Any methods that need special treatment should
// be specialized.
template <class CdmInterface>
template <int CdmInterfaceVersion>
class CdmWrapperImpl : public CdmWrapper {
public:
using CdmInterface =
typename CdmInterfaceTraits<CdmInterfaceVersion>::CdmInterface;
static_assert(CdmInterfaceVersion == CdmInterface::kVersion,
"CDM interface version mismatch.");

static CdmWrapper* Create(CreateCdmFunc create_cdm_func,
const char* key_system,
uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func,
void* user_data) {
void* cdm_instance =
create_cdm_func(CdmInterface::kVersion, key_system, key_system_size,
create_cdm_func(CdmInterfaceVersion, key_system, key_system_size,
get_cdm_host_func, user_data);
if (!cdm_instance)
return nullptr;

return new CdmWrapperImpl<CdmInterface>(
return new CdmWrapperImpl<CdmInterfaceVersion>(
static_cast<CdmInterface*>(cdm_instance));
}

~CdmWrapperImpl() override { cdm_->Destroy(); }

int GetInterfaceVersion() override { return CdmInterface::kVersion; }
int GetInterfaceVersion() override { return CdmInterfaceVersion; }

bool Initialize(bool allow_distinctive_identifier,
bool allow_persistent_state,
Expand Down Expand Up @@ -320,17 +339,15 @@ class CdmWrapperImpl : public CdmWrapper {
// TODO(crbug.com/799219): Remove when CDM_9 no longer supported.

template <>
bool CdmWrapperImpl<cdm::ContentDecryptionModule_9>::Initialize(
bool allow_distinctive_identifier,
bool allow_persistent_state,
bool /* use_hw_secure_codecs*/) {
bool CdmWrapperImpl<9>::Initialize(bool allow_distinctive_identifier,
bool allow_persistent_state,
bool /* use_hw_secure_codecs*/) {
cdm_->Initialize(allow_distinctive_identifier, allow_persistent_state);
return false;
}

template <>
cdm::Status
CdmWrapperImpl<cdm::ContentDecryptionModule_9>::InitializeAudioDecoder(
cdm::Status CdmWrapperImpl<9>::InitializeAudioDecoder(
const cdm::AudioDecoderConfig_2& audio_decoder_config) {
if (!IsEncryptionSchemeSupportedByLegacyCdms(
audio_decoder_config.encryption_scheme))
Expand All @@ -341,8 +358,7 @@ CdmWrapperImpl<cdm::ContentDecryptionModule_9>::InitializeAudioDecoder(
}

template <>
cdm::Status
CdmWrapperImpl<cdm::ContentDecryptionModule_9>::InitializeVideoDecoder(
cdm::Status CdmWrapperImpl<9>::InitializeVideoDecoder(
const cdm::VideoDecoderConfig_2& video_decoder_config) {
if (!IsEncryptionSchemeSupportedByLegacyCdms(
video_decoder_config.encryption_scheme))
Expand All @@ -353,7 +369,7 @@ CdmWrapperImpl<cdm::ContentDecryptionModule_9>::InitializeVideoDecoder(
}

template <>
cdm::Status CdmWrapperImpl<cdm::ContentDecryptionModule_9>::Decrypt(
cdm::Status CdmWrapperImpl<9>::Decrypt(
const cdm::InputBuffer_2& encrypted_buffer,
cdm::DecryptedBlock* decrypted_buffer) {
if (!IsEncryptionSchemeSupportedByLegacyCdms(
Expand All @@ -364,8 +380,7 @@ cdm::Status CdmWrapperImpl<cdm::ContentDecryptionModule_9>::Decrypt(
}

template <>
cdm::Status
CdmWrapperImpl<cdm::ContentDecryptionModule_9>::DecryptAndDecodeFrame(
cdm::Status CdmWrapperImpl<9>::DecryptAndDecodeFrame(
const cdm::InputBuffer_2& encrypted_buffer,
cdm::VideoFrame* video_frame) {
if (!IsEncryptionSchemeSupportedByLegacyCdms(
Expand All @@ -377,8 +392,7 @@ CdmWrapperImpl<cdm::ContentDecryptionModule_9>::DecryptAndDecodeFrame(
}

template <>
cdm::Status
CdmWrapperImpl<cdm::ContentDecryptionModule_9>::DecryptAndDecodeSamples(
cdm::Status CdmWrapperImpl<9>::DecryptAndDecodeSamples(
const cdm::InputBuffer_2& encrypted_buffer,
cdm::AudioFrames* audio_frames) {
if (!IsEncryptionSchemeSupportedByLegacyCdms(
Expand All @@ -395,53 +409,32 @@ CdmWrapper* CdmWrapper::Create(CreateCdmFunc create_cdm_func,
uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func,
void* user_data) {
// cdm::ContentDecryptionModule::kVersion is always the latest stable version.
static_assert(cdm::ContentDecryptionModule::kVersion ==
cdm::ContentDecryptionModule_9::kVersion,
"update the code below");

// Ensure IsSupportedCdmInterfaceVersion() matches this implementation.
// Always update this DCHECK when updating this function.
// If this check fails, update this function and DCHECK or update
// IsSupportedCdmInterfaceVersion().
// TODO(xhwang): Static assert these at compile time.
const int kMinVersion = cdm::ContentDecryptionModule_9::kVersion;
const int kMaxVersion = cdm::ContentDecryptionModule_10::kVersion;
DCHECK(!IsSupportedCdmInterfaceVersion(kMinVersion - 1));
for (int version = kMinVersion; version <= kMaxVersion; ++version)
DCHECK(IsSupportedCdmInterfaceVersion(version));
DCHECK(!IsSupportedCdmInterfaceVersion(kMaxVersion + 1));
static_assert(CheckSupportedCdmInterfaceVersions(9, 10),
"Mismatch between CdmWrapper::Create() and "
"IsSupportedCdmInterfaceVersion()");

// Try to create the CDM using the latest CDM interface version.
// This is only attempted if requested.
CdmWrapper* cdm_wrapper = nullptr;

// TODO(xhwang): Check whether we can use static loops to simplify this code.
if (IsExperimentalCdmInterfaceSupported()) {
cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_10>::Create(
create_cdm_func, key_system, key_system_size, get_cdm_host_func,
user_data);
cdm_wrapper =
CdmWrapperImpl<10>::Create(create_cdm_func, key_system, key_system_size,
get_cdm_host_func, user_data);
}

// If |cdm_wrapper| is NULL, try to create the CDM using older supported
// versions of the CDM interface here.
if (!cdm_wrapper) {
cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_9>::Create(
create_cdm_func, key_system, key_system_size, get_cdm_host_func,
user_data);
cdm_wrapper =
CdmWrapperImpl<9>::Create(create_cdm_func, key_system, key_system_size,
get_cdm_host_func, user_data);
}

return cdm_wrapper;
}

// When updating the CdmAdapter, ensure you've updated the CdmWrapper to contain
// stub implementations for new or modified methods that the older CDM interface
// does not have.
// Also update supported_cdm_versions.h.
static_assert(cdm::ContentDecryptionModule::kVersion ==
cdm::ContentDecryptionModule_9::kVersion,
"ensure cdm wrapper templates have old version support");

} // namespace media

#endif // MEDIA_CDM_CDM_WRAPPER_H_
30 changes: 0 additions & 30 deletions media/cdm/supported_cdm_versions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

#include "media/cdm/supported_cdm_versions.h"

#include "media/cdm/api/content_decryption_module.h"

namespace media {

bool IsSupportedCdmModuleVersion(int version) {
Expand All @@ -18,32 +16,4 @@ bool IsSupportedCdmModuleVersion(int version) {
}
}

bool IsSupportedCdmInterfaceVersion(int version) {
static_assert(cdm::ContentDecryptionModule::kVersion ==
cdm::ContentDecryptionModule_9::kVersion,
"update the code below");
switch (version) {
// Supported versions in decreasing order.
case cdm::ContentDecryptionModule_10::kVersion:
case cdm::ContentDecryptionModule_9::kVersion:
return true;
default:
return false;
}
}

bool IsSupportedCdmHostVersion(int version) {
static_assert(cdm::ContentDecryptionModule::Host::kVersion ==
cdm::ContentDecryptionModule_9::Host::kVersion,
"update the code below");
switch (version) {
// Supported versions in decreasing order.
case cdm::Host_10::kVersion:
case cdm::Host_9::kVersion:
return true;
default:
return false;
}
}

} // namespace media
81 changes: 79 additions & 2 deletions media/cdm/supported_cdm_versions.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,91 @@
#define MEDIA_CDM_SUPPORTED_CDM_VERSIONS_H_

#include "media/base/media_export.h"
#include "media/cdm/api/content_decryption_module.h"

namespace media {

namespace {

typedef bool (*VersionCheckFunc)(int version);

// Returns true if all versions in the range [min_version, max_version] and no
// versions outside the range are supported, and false otherwise.
constexpr bool CheckSupportedVersions(VersionCheckFunc check_func,
int min_version,
int max_version) {
// For simplicity, only check one version out of the range boundary.
if (check_func(min_version - 1) || check_func(max_version + 1))
return false;

for (int version = min_version; version <= max_version; ++version) {
if (!check_func(version))
return false;
}

return true;
}

} // namespace

MEDIA_EXPORT bool IsSupportedCdmModuleVersion(int version);

MEDIA_EXPORT bool IsSupportedCdmInterfaceVersion(int version);
constexpr bool IsSupportedCdmInterfaceVersion(int version) {
static_assert(cdm::ContentDecryptionModule::kVersion ==
cdm::ContentDecryptionModule_9::kVersion,
"update the code below");
switch (version) {
// Supported versions in decreasing order.
case cdm::ContentDecryptionModule_10::kVersion:
case cdm::ContentDecryptionModule_9::kVersion:
return true;
default:
return false;
}
}

constexpr bool IsSupportedCdmHostVersion(int version) {
static_assert(cdm::ContentDecryptionModule::Host::kVersion ==
cdm::ContentDecryptionModule_9::Host::kVersion,
"update the code below");
switch (version) {
// Supported versions in decreasing order.
case cdm::Host_10::kVersion:
case cdm::Host_9::kVersion:
return true;
default:
return false;
}
}

// Ensures CDM interface versions in and only in the range [min_version,
// max_version] are supported.
constexpr bool CheckSupportedCdmInterfaceVersions(int min_version,
int max_version) {
// The latest stable CDM interface should always be supported.
int latest_stable_version = cdm::ContentDecryptionModule::kVersion;
if (latest_stable_version < min_version ||
latest_stable_version > max_version) {
return false;
}

return CheckSupportedVersions(IsSupportedCdmInterfaceVersion, min_version,
max_version);
}

// Ensures CDM host interface versions in and only in the range [min_version,
// max_version] are supported.
constexpr bool CheckSupportedCdmHostVersions(int min_version, int max_version) {
// The latest stable CDM Host interface should always be supported.
int latest_stable_version = cdm::ContentDecryptionModule::Host::kVersion;
if (latest_stable_version < min_version ||
latest_stable_version > max_version) {
return false;
}

MEDIA_EXPORT bool IsSupportedCdmHostVersion(int version);
return CheckSupportedVersions(IsSupportedCdmHostVersion, min_version,
max_version);
}

} // namespace media

Expand Down

0 comments on commit ff1f496

Please sign in to comment.