Commit a4513e6f authored by Jeffrey Kardatzke's avatar Jeffrey Kardatzke Committed by Commit Bot

Add USE_CHROMEOS_PROTECTED_MEDIA build flag

This adds a buildflag that enables handling encrypted content in the HW
accelerated video decoders for Chrome OS. Initially this will be for
VAAPI only. No builders are enabling this flag yet, it is still in
development.

BUG=b:153111783
TEST=Built/deployed Chrome with flag enabled/disabled

Change-Id: Idcf50f3c302d619f8586306db9cf85164e051dee
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2461993
Commit-Queue: Jeffrey Kardatzke <jkardatzke@google.com>
Reviewed-by: default avatarXiaohan Wang <xhwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#815424}
parent b2441b0d
...@@ -41,6 +41,7 @@ buildflag_header("media_buildflags") { ...@@ -41,6 +41,7 @@ buildflag_header("media_buildflags") {
"ENABLE_PLATFORM_MPEG_H_AUDIO=$enable_platform_mpeg_h_audio", "ENABLE_PLATFORM_MPEG_H_AUDIO=$enable_platform_mpeg_h_audio",
"ENABLE_MSE_MPEG2TS_STREAM_PARSER=$enable_mse_mpeg2ts_stream_parser", "ENABLE_MSE_MPEG2TS_STREAM_PARSER=$enable_mse_mpeg2ts_stream_parser",
"USE_CHROMEOS_MEDIA_ACCELERATION=$use_vaapi||$use_v4l2_codec", "USE_CHROMEOS_MEDIA_ACCELERATION=$use_vaapi||$use_v4l2_codec",
"USE_CHROMEOS_PROTECTED_MEDIA=$use_chromeos_protected_media",
"USE_PROPRIETARY_CODECS=$proprietary_codecs", "USE_PROPRIETARY_CODECS=$proprietary_codecs",
] ]
} }
......
...@@ -17,4 +17,9 @@ declare_args() { ...@@ -17,4 +17,9 @@ declare_args() {
# Indicates if VA-API-based hardware acceleration is to be used. This # Indicates if VA-API-based hardware acceleration is to be used. This
# is typically the case on x86-based ChromeOS devices. # is typically the case on x86-based ChromeOS devices.
use_vaapi = false use_vaapi = false
# Indicates if ChromeOS protected media support exists. This is used
# to enable the CDM daemon in Chrome OS as well as support for
# encrypted content with HW video decoders.
use_chromeos_protected_media = false
} }
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "media/gpu/chromeos/image_processor_factory.h" #include "media/gpu/chromeos/image_processor_factory.h"
#include "media/gpu/chromeos/platform_video_frame_pool.h" #include "media/gpu/chromeos/platform_video_frame_pool.h"
#include "media/gpu/macros.h" #include "media/gpu/macros.h"
#include "media/media_buildflags.h"
namespace media { namespace media {
namespace { namespace {
...@@ -198,6 +199,13 @@ void VideoDecoderPipeline::Initialize(const VideoDecoderConfig& config, ...@@ -198,6 +199,13 @@ void VideoDecoderPipeline::Initialize(const VideoDecoderConfig& config,
std::move(init_cb).Run(StatusCode::kDecoderUnsupportedConfig); std::move(init_cb).Run(StatusCode::kDecoderUnsupportedConfig);
return; return;
} }
#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
if (config.is_encrypted() && !cdm_context) {
VLOGF(1) << "Encrypted streams require a CdmContext";
std::move(init_cb).Run(StatusCode::kDecoderUnsupportedConfig);
return;
}
#else // BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
if (config.is_encrypted()) { if (config.is_encrypted()) {
VLOGF(1) << "Encrypted streams are not supported for this VD"; VLOGF(1) << "Encrypted streams are not supported for this VD";
std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported); std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported);
...@@ -208,16 +216,18 @@ void VideoDecoderPipeline::Initialize(const VideoDecoderConfig& config, ...@@ -208,16 +216,18 @@ void VideoDecoderPipeline::Initialize(const VideoDecoderConfig& config,
std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported); std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported);
return; return;
} }
#endif // !BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
needs_bitstream_conversion_ = (config.codec() == kCodecH264); needs_bitstream_conversion_ = (config.codec() == kCodecH264);
decoder_task_runner_->PostTask( decoder_task_runner_->PostTask(
FROM_HERE, FROM_HERE, base::BindOnce(&VideoDecoderPipeline::InitializeTask,
base::BindOnce(&VideoDecoderPipeline::InitializeTask, decoder_weak_this_, decoder_weak_this_, config, cdm_context,
config, std::move(init_cb), std::move(output_cb))); std::move(init_cb), std::move(output_cb)));
} }
void VideoDecoderPipeline::InitializeTask(const VideoDecoderConfig& config, void VideoDecoderPipeline::InitializeTask(const VideoDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb, InitCB init_cb,
const OutputCB& output_cb) { const OutputCB& output_cb) {
DVLOGF(3); DVLOGF(3);
...@@ -232,18 +242,19 @@ void VideoDecoderPipeline::InitializeTask(const VideoDecoderConfig& config, ...@@ -232,18 +242,19 @@ void VideoDecoderPipeline::InitializeTask(const VideoDecoderConfig& config,
// resolution. Subsequent initializations are marked by |decoder_| already // resolution. Subsequent initializations are marked by |decoder_| already
// existing. // existing.
if (!decoder_) { if (!decoder_) {
CreateAndInitializeVD(config, Status()); CreateAndInitializeVD(config, cdm_context, Status());
} else { } else {
decoder_->Initialize( decoder_->Initialize(
config, config, cdm_context,
base::BindOnce(&VideoDecoderPipeline::OnInitializeDone, base::BindOnce(&VideoDecoderPipeline::OnInitializeDone,
decoder_weak_this_, config, Status()), decoder_weak_this_, config, cdm_context, Status()),
base::BindRepeating(&VideoDecoderPipeline::OnFrameDecoded, base::BindRepeating(&VideoDecoderPipeline::OnFrameDecoded,
decoder_weak_this_)); decoder_weak_this_));
} }
} }
void VideoDecoderPipeline::CreateAndInitializeVD(VideoDecoderConfig config, void VideoDecoderPipeline::CreateAndInitializeVD(VideoDecoderConfig config,
CdmContext* cdm_context,
Status parent_error) { Status parent_error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
DCHECK(init_cb_); DCHECK(init_cb_);
...@@ -269,19 +280,22 @@ void VideoDecoderPipeline::CreateAndInitializeVD(VideoDecoderConfig config, ...@@ -269,19 +280,22 @@ void VideoDecoderPipeline::CreateAndInitializeVD(VideoDecoderConfig config,
DVLOGF(2) << "|decoder_| creation failed, trying again with the next " DVLOGF(2) << "|decoder_| creation failed, trying again with the next "
"available create function."; "available create function.";
return CreateAndInitializeVD( return CreateAndInitializeVD(
config, AppendOrForwardStatus(parent_error, config, cdm_context,
StatusCode::kDecoderFailedCreation)); AppendOrForwardStatus(parent_error,
StatusCode::kDecoderFailedCreation));
} }
decoder_->Initialize( decoder_->Initialize(
config, config, cdm_context,
base::BindOnce(&VideoDecoderPipeline::OnInitializeDone, base::BindOnce(&VideoDecoderPipeline::OnInitializeDone,
decoder_weak_this_, config, std::move(parent_error)), decoder_weak_this_, config, cdm_context,
std::move(parent_error)),
base::BindRepeating(&VideoDecoderPipeline::OnFrameDecoded, base::BindRepeating(&VideoDecoderPipeline::OnFrameDecoded,
decoder_weak_this_)); decoder_weak_this_));
} }
void VideoDecoderPipeline::OnInitializeDone(VideoDecoderConfig config, void VideoDecoderPipeline::OnInitializeDone(VideoDecoderConfig config,
CdmContext* cdm_context,
Status parent_error, Status parent_error,
Status status) { Status status) {
DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
...@@ -300,7 +314,7 @@ void VideoDecoderPipeline::OnInitializeDone(VideoDecoderConfig config, ...@@ -300,7 +314,7 @@ void VideoDecoderPipeline::OnInitializeDone(VideoDecoderConfig config,
DVLOGF(3) << "|decoder_| initialization failed, trying again with the next " DVLOGF(3) << "|decoder_| initialization failed, trying again with the next "
"available create function."; "available create function.";
decoder_ = nullptr; decoder_ = nullptr;
CreateAndInitializeVD(config, CreateAndInitializeVD(config, cdm_context,
AppendOrForwardStatus(parent_error, std::move(status))); AppendOrForwardStatus(parent_error, std::move(status)));
} }
......
...@@ -85,6 +85,7 @@ class MEDIA_GPU_EXPORT DecoderInterface { ...@@ -85,6 +85,7 @@ class MEDIA_GPU_EXPORT DecoderInterface {
// TODO(akahuang): Add an error notification method to handle misused case. // TODO(akahuang): Add an error notification method to handle misused case.
// 4) |init_cb| may be called before this returns. // 4) |init_cb| may be called before this returns.
virtual void Initialize(const VideoDecoderConfig& config, virtual void Initialize(const VideoDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb, InitCB init_cb,
const OutputCB& output_cb) = 0; const OutputCB& output_cb) = 0;
...@@ -180,13 +181,17 @@ class MEDIA_GPU_EXPORT VideoDecoderPipeline : public VideoDecoder, ...@@ -180,13 +181,17 @@ class MEDIA_GPU_EXPORT VideoDecoderPipeline : public VideoDecoder,
GetCreateDecoderFunctionsCB get_create_decoder_functions_cb); GetCreateDecoderFunctionsCB get_create_decoder_functions_cb);
void InitializeTask(const VideoDecoderConfig& config, void InitializeTask(const VideoDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb, InitCB init_cb,
const OutputCB& output_cb); const OutputCB& output_cb);
void ResetTask(base::OnceClosure closure); void ResetTask(base::OnceClosure closure);
void DecodeTask(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb); void DecodeTask(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb);
void CreateAndInitializeVD(VideoDecoderConfig config, Status parent_error); void CreateAndInitializeVD(VideoDecoderConfig config,
CdmContext* cdm_context,
Status parent_error);
void OnInitializeDone(VideoDecoderConfig config, void OnInitializeDone(VideoDecoderConfig config,
CdmContext* cdm_context,
Status parent_error, Status parent_error,
Status status); Status status);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/test/gmock_callback_support.h" #include "base/test/gmock_callback_support.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "media/base/cdm_context.h"
#include "media/base/media_util.h" #include "media/base/media_util.h"
#include "media/base/status.h" #include "media/base/status.h"
#include "media/base/video_decoder_config.h" #include "media/base/video_decoder_config.h"
...@@ -54,8 +55,9 @@ class MockDecoder : public DecoderInterface { ...@@ -54,8 +55,9 @@ class MockDecoder : public DecoderInterface {
base::WeakPtr<DecoderInterface::Client>(nullptr)) {} base::WeakPtr<DecoderInterface::Client>(nullptr)) {}
~MockDecoder() override = default; ~MockDecoder() override = default;
MOCK_METHOD3(Initialize, MOCK_METHOD4(
void(const VideoDecoderConfig&, InitCB, const OutputCB&)); Initialize,
void(const VideoDecoderConfig&, CdmContext*, InitCB, const OutputCB&));
MOCK_METHOD2(Decode, void(scoped_refptr<DecoderBuffer>, DecodeCB)); MOCK_METHOD2(Decode, void(scoped_refptr<DecoderBuffer>, DecodeCB));
MOCK_METHOD1(Reset, void(base::OnceClosure)); MOCK_METHOD1(Reset, void(base::OnceClosure));
MOCK_METHOD0(ApplyResolutionChange, void()); MOCK_METHOD0(ApplyResolutionChange, void());
...@@ -125,8 +127,8 @@ class VideoDecoderPipelineTest ...@@ -125,8 +127,8 @@ class VideoDecoderPipelineTest
scoped_refptr<base::SequencedTaskRunner> /* decoder_task_runner */, scoped_refptr<base::SequencedTaskRunner> /* decoder_task_runner */,
base::WeakPtr<DecoderInterface::Client> /* client */) { base::WeakPtr<DecoderInterface::Client> /* client */) {
std::unique_ptr<MockDecoder> decoder(new MockDecoder()); std::unique_ptr<MockDecoder> decoder(new MockDecoder());
EXPECT_CALL(*decoder, Initialize(_, _, _)) EXPECT_CALL(*decoder, Initialize(_, _, _, _))
.WillOnce(::testing::WithArgs<1>([](VideoDecoder::InitCB init_cb) { .WillOnce(::testing::WithArgs<2>([](VideoDecoder::InitCB init_cb) {
std::move(init_cb).Run(OkStatus()); std::move(init_cb).Run(OkStatus());
})); }));
return std::move(decoder); return std::move(decoder);
...@@ -137,8 +139,8 @@ class VideoDecoderPipelineTest ...@@ -137,8 +139,8 @@ class VideoDecoderPipelineTest
scoped_refptr<base::SequencedTaskRunner> /* decoder_task_runner */, scoped_refptr<base::SequencedTaskRunner> /* decoder_task_runner */,
base::WeakPtr<DecoderInterface::Client> /* client */) { base::WeakPtr<DecoderInterface::Client> /* client */) {
std::unique_ptr<MockDecoder> decoder(new MockDecoder()); std::unique_ptr<MockDecoder> decoder(new MockDecoder());
EXPECT_CALL(*decoder, Initialize(_, _, _)) EXPECT_CALL(*decoder, Initialize(_, _, _, _))
.WillOnce(::testing::WithArgs<1>([](VideoDecoder::InitCB init_cb) { .WillOnce(::testing::WithArgs<2>([](VideoDecoder::InitCB init_cb) {
std::move(init_cb).Run(StatusCode::kDecoderFailedInitialization); std::move(init_cb).Run(StatusCode::kDecoderFailedInitialization);
})); }));
return std::move(decoder); return std::move(decoder);
......
...@@ -113,6 +113,7 @@ V4L2VideoDecoder::~V4L2VideoDecoder() { ...@@ -113,6 +113,7 @@ V4L2VideoDecoder::~V4L2VideoDecoder() {
} }
void V4L2VideoDecoder::Initialize(const VideoDecoderConfig& config, void V4L2VideoDecoder::Initialize(const VideoDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb, InitCB init_cb,
const OutputCB& output_cb) { const OutputCB& output_cb) {
DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
...@@ -120,6 +121,12 @@ void V4L2VideoDecoder::Initialize(const VideoDecoderConfig& config, ...@@ -120,6 +121,12 @@ void V4L2VideoDecoder::Initialize(const VideoDecoderConfig& config,
DCHECK(state_ == State::kUninitialized || state_ == State::kDecoding); DCHECK(state_ == State::kUninitialized || state_ == State::kDecoding);
DVLOGF(3); DVLOGF(3);
if (cdm_context || config.is_encrypted()) {
VLOGF(1) << "V4L2 decoder does not support encrypted stream";
std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported);
return;
}
// Reset V4L2 device and queue if reinitializing decoder. // Reset V4L2 device and queue if reinitializing decoder.
if (state_ != State::kUninitialized) { if (state_ != State::kUninitialized) {
if (!StopStreamV4L2Queue(true)) { if (!StopStreamV4L2Queue(true)) {
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "media/base/cdm_context.h"
#include "media/base/video_types.h" #include "media/base/video_types.h"
#include "media/gpu/chromeos/gpu_buffer_layout.h" #include "media/gpu/chromeos/gpu_buffer_layout.h"
#include "media/gpu/chromeos/video_decoder_pipeline.h" #include "media/gpu/chromeos/video_decoder_pipeline.h"
...@@ -51,6 +52,7 @@ class MEDIA_GPU_EXPORT V4L2VideoDecoder ...@@ -51,6 +52,7 @@ class MEDIA_GPU_EXPORT V4L2VideoDecoder
// DecoderInterface implementation. // DecoderInterface implementation.
void Initialize(const VideoDecoderConfig& config, void Initialize(const VideoDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb, InitCB init_cb,
const OutputCB& output_cb) override; const OutputCB& output_cb) override;
void Reset(base::OnceClosure closure) override; void Reset(base::OnceClosure closure) override;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "media/gpu/vaapi/vaapi_wrapper.h" #include "media/gpu/vaapi/vaapi_wrapper.h"
#include "media/gpu/vaapi/vp8_vaapi_video_decoder_delegate.h" #include "media/gpu/vaapi/vp8_vaapi_video_decoder_delegate.h"
#include "media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.h" #include "media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.h"
#include "media/media_buildflags.h"
namespace media { namespace media {
...@@ -76,7 +77,12 @@ std::unique_ptr<DecoderInterface> VaapiVideoDecoder::Create( ...@@ -76,7 +77,12 @@ std::unique_ptr<DecoderInterface> VaapiVideoDecoder::Create(
SupportedVideoDecoderConfigs VaapiVideoDecoder::GetSupportedConfigs( SupportedVideoDecoderConfigs VaapiVideoDecoder::GetSupportedConfigs(
const gpu::GpuDriverBugWorkarounds& workarounds) { const gpu::GpuDriverBugWorkarounds& workarounds) {
return ConvertFromSupportedProfiles( return ConvertFromSupportedProfiles(
VaapiWrapper::GetSupportedDecodeProfiles(workarounds), false); VaapiWrapper::GetSupportedDecodeProfiles(workarounds),
#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
true /* allow_encrypted */);
#else
false /* allow_encrypted */);
#endif
} }
VaapiVideoDecoder::VaapiVideoDecoder( VaapiVideoDecoder::VaapiVideoDecoder(
...@@ -121,6 +127,7 @@ VaapiVideoDecoder::~VaapiVideoDecoder() { ...@@ -121,6 +127,7 @@ VaapiVideoDecoder::~VaapiVideoDecoder() {
} }
void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config, void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb, InitCB init_cb,
const OutputCB& output_cb) { const OutputCB& output_cb) {
DVLOGF(2) << config.AsHumanReadableString(); DVLOGF(2) << config.AsHumanReadableString();
...@@ -136,6 +143,17 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config, ...@@ -136,6 +143,17 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
return; return;
} }
#if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
// TODO(jkardatzke): Implement protected media handling.
NOTREACHED();
#else
if (cdm_context || config.is_encrypted()) {
VLOGF(1) << "Vaapi decoder does not support encrypted stream";
std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported);
return;
}
#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
// triggering a flush or reset), even if the // triggering a flush or reset), even if the
// DecoderInterface API doesn't explicitly specify this. // DecoderInterface API doesn't explicitly specify this.
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#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 "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"
#include "media/base/video_frame_layout.h" #include "media/base/video_frame_layout.h"
...@@ -57,6 +58,7 @@ class VaapiVideoDecoder : public DecoderInterface, ...@@ -57,6 +58,7 @@ class VaapiVideoDecoder : public DecoderInterface,
// DecoderInterface implementation. // DecoderInterface implementation.
void Initialize(const VideoDecoderConfig& config, void Initialize(const VideoDecoderConfig& config,
CdmContext* cdm_context,
InitCB init_cb, InitCB init_cb,
const OutputCB& output_cb) override; const OutputCB& output_cb) override;
void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override; void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#include "media/base/overlay_info.h" #include "media/base/overlay_info.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "media/media_buildflags.h"
#include "media/mojo/common/media_type_converters.h" #include "media/mojo/common/media_type_converters.h"
#include "media/mojo/common/mojo_decoder_buffer_converter.h" #include "media/mojo/common/mojo_decoder_buffer_converter.h"
#include "media/mojo/mojom/media_types.mojom.h" #include "media/mojo/mojom/media_types.mojom.h"
...@@ -133,8 +134,9 @@ bool MojoVideoDecoder::IsPlatformDecoder() const { ...@@ -133,8 +134,9 @@ bool MojoVideoDecoder::IsPlatformDecoder() const {
} }
bool MojoVideoDecoder::SupportsDecryption() const { bool MojoVideoDecoder::SupportsDecryption() const {
// Currently only the android backends support decryption // Currently only the Android backends and specific ChromeOS configurations
#if defined(OS_ANDROID) // support decryption.
#if defined(OS_ANDROID) || BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA)
return true; return true;
#else #else
return false; return false;
......
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