From c9d2206c62f65e29b141e08df2b2dcb88f54162f Mon Sep 17 00:00:00 2001 From: dougsteed Date: Fri, 11 Mar 2016 11:55:02 -0800 Subject: media config: expand is_encrypted to a struct. Provide more complete encryption metadata, rather than just a bool. EncryptionScheme also allows specification of the mode and the pattern, as will be allowed by CENC (ISO's Common Encryption standard), 3rd Edition. BUG=568326 Review URL: https://codereview.chromium.org/1490613005 Cr-Commit-Position: refs/heads/master@{#380710} --- chromecast/common/media/cma_param_traits.cc | 71 +++++++++++++++--- chromecast/common/media/cma_param_traits.h | 10 +++ chromecast/common/media/cma_param_traits_macros.h | 2 + chromecast/media/audio/cast_audio_output_stream.cc | 1 - .../audio/cast_audio_output_stream_unittest.cc | 2 +- .../audio_video_pipeline_device_unittest.cc | 5 +- .../media/cma/base/decoder_config_adapter.cc | 67 +++++++++++++++-- .../media/cma/base/demuxer_stream_for_test.cc | 2 +- chromecast/media/cma/ipc_streamer/BUILD.gn | 2 + .../audio_decoder_config_marshaller.cc | 9 +-- .../ipc_streamer/encryption_scheme_marshaller.cc | 54 ++++++++++++++ .../ipc_streamer/encryption_scheme_marshaller.h | 27 +++++++ .../video_decoder_config_marshaller.cc | 9 +-- .../cma/pipeline/audio_decoder_software_wrapper.cc | 4 +- .../pipeline/audio_video_pipeline_impl_unittest.cc | 4 +- chromecast/media/cma/test/mock_frame_provider.cc | 4 +- chromecast/media/media.gyp | 2 + chromecast/public/media/decoder_config.h | 83 +++++++++++++++++++--- 18 files changed, 318 insertions(+), 40 deletions(-) create mode 100644 chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.cc create mode 100644 chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h (limited to 'chromecast') diff --git a/chromecast/common/media/cma_param_traits.cc b/chromecast/common/media/cma_param_traits.cc index f27043d..f0ddc49 100644 --- a/chromecast/common/media/cma_param_traits.cc +++ b/chromecast/common/media/cma_param_traits.cc @@ -12,6 +12,7 @@ #include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" #include "media/base/audio_decoder_config.h" +#include "media/base/encryption_scheme.h" #include "media/base/video_decoder_config.h" #include "ui/gfx/ipc/gfx_param_traits.h" @@ -29,6 +30,16 @@ IPC_ENUM_TRAITS_MAX_VALUE(media::VideoPixelFormat, media::PIXEL_FORMAT_MAX) namespace IPC { +template <> +struct ParamTraits { + typedef media::EncryptionScheme::Pattern param_type; + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, + param_type* r); + static void Log(const param_type& p, std::string* l); +}; + + void ParamTraits::Write( base::Pickle* m, const media::AudioDecoderConfig& p) { @@ -36,7 +47,7 @@ void ParamTraits::Write( WriteParam(m, p.sample_format()); WriteParam(m, p.channel_layout()); WriteParam(m, p.samples_per_second()); - WriteParam(m, p.is_encrypted()); + WriteParam(m, p.encryption_scheme()); WriteParam(m, p.extra_data()); } @@ -48,15 +59,17 @@ bool ParamTraits::Read( media::SampleFormat sample_format; media::ChannelLayout channel_layout; int samples_per_second; - bool is_encrypted; + media::EncryptionScheme encryption_scheme; std::vector extra_data; if (!ReadParam(m, iter, &codec) || !ReadParam(m, iter, &sample_format) || !ReadParam(m, iter, &channel_layout) || !ReadParam(m, iter, &samples_per_second) || - !ReadParam(m, iter, &is_encrypted) || !ReadParam(m, iter, &extra_data)) + !ReadParam(m, iter, &encryption_scheme) || + !ReadParam(m, iter, &extra_data)) return false; *r = media::AudioDecoderConfig(codec, sample_format, channel_layout, - samples_per_second, extra_data, is_encrypted); + samples_per_second, extra_data, + encryption_scheme); return true; } @@ -75,7 +88,7 @@ void ParamTraits::Write( WriteParam(m, p.coded_size()); WriteParam(m, p.visible_rect()); WriteParam(m, p.natural_size()); - WriteParam(m, p.is_encrypted()); + WriteParam(m, p.encryption_scheme()); WriteParam(m, p.extra_data()); } @@ -90,17 +103,18 @@ bool ParamTraits::Read( gfx::Size coded_size; gfx::Rect visible_rect; gfx::Size natural_size; - bool is_encrypted; + media::EncryptionScheme encryption_scheme; std::vector extra_data; if (!ReadParam(m, iter, &codec) || !ReadParam(m, iter, &profile) || !ReadParam(m, iter, &format) || !ReadParam(m, iter, &color_space) || !ReadParam(m, iter, &coded_size) || !ReadParam(m, iter, &visible_rect) || !ReadParam(m, iter, &natural_size) || - !ReadParam(m, iter, &is_encrypted) || !ReadParam(m, iter, &extra_data)) + !ReadParam(m, iter, &encryption_scheme) || + !ReadParam(m, iter, &extra_data)) return false; *r = media::VideoDecoderConfig(codec, profile, format, color_space, coded_size, visible_rect, natural_size, - extra_data, is_encrypted); + extra_data, encryption_scheme); return true; } @@ -109,4 +123,45 @@ void ParamTraits::Log( l->append(base::StringPrintf("")); } +void ParamTraits::Write( + base::Pickle* m, const param_type& p) { + WriteParam(m, p.mode()); + WriteParam(m, p.pattern()); +} + +bool ParamTraits::Read( + const base::Pickle* m, base::PickleIterator* iter, param_type* r) { + media::EncryptionScheme::CipherMode mode; + media::EncryptionScheme::Pattern pattern; + if (!ReadParam(m, iter, &mode) || !ReadParam(m, iter, &pattern)) + return false; + *r = media::EncryptionScheme(mode, pattern); + return true; +} + +void ParamTraits::Log( + const param_type& p, std::string* l) { + l->append(base::StringPrintf("")); +} + +void ParamTraits::Write( + base::Pickle* m, const param_type& p) { + WriteParam(m, p.encrypt_blocks()); + WriteParam(m, p.skip_blocks()); +} + +bool ParamTraits::Read( + const base::Pickle* m, base::PickleIterator* iter, param_type* r) { + uint32_t encrypt_blocks, skip_blocks; + if (!ReadParam(m, iter, &encrypt_blocks) || !ReadParam(m, iter, &skip_blocks)) + return false; + *r = media::EncryptionScheme::Pattern(encrypt_blocks, skip_blocks); + return true; +} + +void ParamTraits::Log( + const param_type& p, std::string* l) { + l->append(base::StringPrintf("")); +} + } // namespace IPC diff --git a/chromecast/common/media/cma_param_traits.h b/chromecast/common/media/cma_param_traits.h index c8609a5..879bbf1 100644 --- a/chromecast/common/media/cma_param_traits.h +++ b/chromecast/common/media/cma_param_traits.h @@ -10,6 +10,7 @@ namespace media { class AudioDecoderConfig; class VideoDecoderConfig; +class EncryptionScheme; } namespace IPC { @@ -34,6 +35,15 @@ struct ParamTraits { static void Log(const param_type& p, std::string* l); }; +template <> +struct ParamTraits { + typedef media::EncryptionScheme param_type; + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, + param_type* r); + static void Log(const param_type& p, std::string* l); +}; + } // namespace IPC #endif // CHROMECAST_COMMON_MEDIA_CMA_PARAM_TRAITS_H_ diff --git a/chromecast/common/media/cma_param_traits_macros.h b/chromecast/common/media/cma_param_traits_macros.h index a25e53f..2aae996 100644 --- a/chromecast/common/media/cma_param_traits_macros.h +++ b/chromecast/common/media/cma_param_traits_macros.h @@ -44,6 +44,8 @@ IPC_ENUM_TRAITS_MIN_MAX_VALUE(media::VideoCodec, media::VideoCodec::kUnknownVideoCodec, media::VideoCodec::kVideoCodecMax) IPC_ENUM_TRAITS_MAX_VALUE(media::ColorSpace, media::COLOR_SPACE_MAX) +IPC_ENUM_TRAITS_MAX_VALUE(media::EncryptionScheme::CipherMode, + media::EncryptionScheme::CIPHER_MODE_MAX); IPC_STRUCT_TRAITS_BEGIN(media::PipelineStatistics) IPC_STRUCT_TRAITS_MEMBER(audio_bytes_decoded) diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc index ec415d7..fc91d50 100644 --- a/chromecast/media/audio/cast_audio_output_stream.cc +++ b/chromecast/media/audio/cast_audio_output_stream.cc @@ -47,7 +47,6 @@ MediaPipelineBackend::AudioDecoder* InitializeBackend( audio_config.bytes_per_channel = audio_params.bits_per_sample() / 8; audio_config.channel_number = audio_params.channels(); audio_config.samples_per_second = audio_params.sample_rate(); - audio_config.is_encrypted = false; if (!decoder->SetConfig(audio_config)) return nullptr; diff --git a/chromecast/media/audio/cast_audio_output_stream_unittest.cc b/chromecast/media/audio/cast_audio_output_stream_unittest.cc index a8ad0f0..8402a6a 100644 --- a/chromecast/media/audio/cast_audio_output_stream_unittest.cc +++ b/chromecast/media/audio/cast_audio_output_stream_unittest.cc @@ -385,7 +385,7 @@ TEST_F(CastAudioOutputStreamTest, Format) { const AudioConfig& audio_config = audio_decoder->config(); EXPECT_EQ(kCodecPCM, audio_config.codec); EXPECT_EQ(kSampleFormatS16, audio_config.sample_format); - EXPECT_FALSE(audio_config.is_encrypted); + EXPECT_FALSE(audio_config.encryption_scheme.is_encrypted()); CloseStream(stream); } diff --git a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc index 7fd2d1d..18de287 100644 --- a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc +++ b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc @@ -35,6 +35,7 @@ #include "media/base/audio_decoder_config.h" #include "media/base/audio_timestamp_helper.h" #include "media/base/decoder_buffer.h" +#include "media/base/encryption_scheme.h" #include "media/base/video_decoder_config.h" #include "testing/gtest/include/gtest/gtest.h" @@ -68,7 +69,7 @@ VideoConfig DefaultVideoConfig() { default_config.codec = kCodecH264; default_config.profile = kH264Main; default_config.additional_config = nullptr; - default_config.is_encrypted = false; + default_config.encryption_scheme = Unencrypted(); return default_config; } @@ -564,7 +565,7 @@ scoped_ptr BufferFeeder::LoadVideo(MediaPipelineBackend* backend, video_config.codec = kCodecH264; video_config.profile = kH264Main; video_config.additional_config = nullptr; - video_config.is_encrypted = false; + video_config.encryption_scheme = Unencrypted(); } else { base::FilePath file_path = GetTestDataFilePath(filename); DemuxResult demux_result = FFmpegDemuxForTest(file_path, false /* audio */); diff --git a/chromecast/media/cma/base/decoder_config_adapter.cc b/chromecast/media/cma/base/decoder_config_adapter.cc index 3a8ab39..24e8b41 100644 --- a/chromecast/media/cma/base/decoder_config_adapter.cc +++ b/chromecast/media/cma/base/decoder_config_adapter.cc @@ -85,7 +85,7 @@ VideoCodec ToVideoCodec(const ::media::VideoCodec video_codec) { // Converts ::media::VideoCodecProfile to chromecast::media::VideoProfile. VideoProfile ToVideoProfile(const ::media::VideoCodecProfile codec_profile) { - switch(codec_profile) { + switch (codec_profile) { case ::media::H264PROFILE_BASELINE: return kH264Baseline; case ::media::H264PROFILE_MAIN: @@ -183,6 +183,62 @@ VideoProfile ToVideoProfile(const ::media::VideoCodecProfile codec_profile) { } } +::media::EncryptionScheme::CipherMode ToMediaCipherMode( + EncryptionScheme::CipherMode mode) { + switch (mode) { + case EncryptionScheme::CIPHER_MODE_UNENCRYPTED: + return ::media::EncryptionScheme::CIPHER_MODE_UNENCRYPTED; + case EncryptionScheme::CIPHER_MODE_AES_CTR: + return ::media::EncryptionScheme::CIPHER_MODE_AES_CTR; + case EncryptionScheme::CIPHER_MODE_AES_CBC: + return ::media::EncryptionScheme::CIPHER_MODE_AES_CBC; + default: + NOTREACHED(); + return ::media::EncryptionScheme::CIPHER_MODE_UNENCRYPTED; + } +} + +EncryptionScheme::CipherMode ToCipherMode( + ::media::EncryptionScheme::CipherMode mode) { + switch (mode) { + case ::media::EncryptionScheme::CIPHER_MODE_UNENCRYPTED: + return EncryptionScheme::CIPHER_MODE_UNENCRYPTED; + case ::media::EncryptionScheme::CIPHER_MODE_AES_CTR: + return EncryptionScheme::CIPHER_MODE_AES_CTR; + case ::media::EncryptionScheme::CIPHER_MODE_AES_CBC: + return EncryptionScheme::CIPHER_MODE_AES_CBC; + default: + NOTREACHED(); + return EncryptionScheme::CIPHER_MODE_UNENCRYPTED; + } +} + +EncryptionScheme::Pattern ToPatternSpec( + const ::media::EncryptionScheme::Pattern& pattern) { + return EncryptionScheme::Pattern( + pattern.encrypt_blocks(), pattern.skip_blocks()); +} + +::media::EncryptionScheme::Pattern ToMediaPatternSpec( + const EncryptionScheme::Pattern& pattern) { + return ::media::EncryptionScheme::Pattern( + pattern.encrypt_blocks, pattern.skip_blocks); +} + +EncryptionScheme ToEncryptionScheme( + const ::media::EncryptionScheme& scheme) { + return EncryptionScheme( + ToCipherMode(scheme.mode()), + ToPatternSpec(scheme.pattern())); +} + +::media::EncryptionScheme ToMediaEncryptionScheme( + const EncryptionScheme& scheme) { + return ::media::EncryptionScheme( + ToMediaCipherMode(scheme.mode), + ToMediaPatternSpec(scheme.pattern)); +} + } // namespace // static @@ -201,7 +257,8 @@ AudioConfig DecoderConfigAdapter::ToCastAudioConfig( ::media::ChannelLayoutToChannelCount(config.channel_layout()), audio_config.samples_per_second = config.samples_per_second(); audio_config.extra_data = config.extra_data(); - audio_config.is_encrypted = config.is_encrypted(); + audio_config.encryption_scheme = ToEncryptionScheme( + config.encryption_scheme()); return audio_config; } @@ -212,7 +269,8 @@ AudioConfig DecoderConfigAdapter::ToCastAudioConfig( ToMediaAudioCodec(config.codec), ToMediaSampleFormat(config.sample_format), ToMediaChannelLayout(config.channel_number), config.samples_per_second, - config.extra_data, config.is_encrypted); + config.extra_data, + ToMediaEncryptionScheme(config.encryption_scheme)); } // static @@ -228,7 +286,8 @@ VideoConfig DecoderConfigAdapter::ToCastVideoConfig( video_config.codec = ToVideoCodec(config.codec()); video_config.profile = ToVideoProfile(config.profile()); video_config.extra_data = config.extra_data(); - video_config.is_encrypted = config.is_encrypted(); + video_config.encryption_scheme = ToEncryptionScheme( + config.encryption_scheme()); return video_config; } diff --git a/chromecast/media/cma/base/demuxer_stream_for_test.cc b/chromecast/media/cma/base/demuxer_stream_for_test.cc index 9942545..32ee27b 100644 --- a/chromecast/media/cma/base/demuxer_stream_for_test.cc +++ b/chromecast/media/cma/base/demuxer_stream_for_test.cc @@ -63,7 +63,7 @@ void DemuxerStreamForTest::Read(const ReadCB& read_cb) { visible_rect, natural_size, ::media::EmptyExtraData(), - false); + ::media::Unencrypted()); } ::media::DemuxerStream::Type DemuxerStreamForTest::type() const { diff --git a/chromecast/media/cma/ipc_streamer/BUILD.gn b/chromecast/media/cma/ipc_streamer/BUILD.gn index a3429d6..7d25f45 100644 --- a/chromecast/media/cma/ipc_streamer/BUILD.gn +++ b/chromecast/media/cma/ipc_streamer/BUILD.gn @@ -14,6 +14,8 @@ source_set("ipc_streamer") { "decoder_buffer_base_marshaller.h", "decrypt_config_marshaller.cc", "decrypt_config_marshaller.h", + "encryption_scheme_marshaller.cc", + "encryption_scheme_marshaller.h", "video_decoder_config_marshaller.cc", "video_decoder_config_marshaller.h", ] diff --git a/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc b/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc index 2798c6b..031571a 100644 --- a/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc +++ b/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "chromecast/media/cma/ipc/media_message.h" +#include "chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h" #include "media/base/audio_decoder_config.h" namespace chromecast { @@ -27,7 +28,7 @@ void AudioDecoderConfigMarshaller::Write( CHECK(msg->WritePod(config.channel_layout())); CHECK(msg->WritePod(config.samples_per_second())); CHECK(msg->WritePod(config.sample_format())); - CHECK(msg->WritePod(config.is_encrypted())); + EncryptionSchemeMarshaller::Write(config.encryption_scheme(), msg); CHECK(msg->WritePod(config.extra_data().size())); if (!config.extra_data().empty()) CHECK(msg->WriteBuffer(&config.extra_data()[0], @@ -41,15 +42,15 @@ void AudioDecoderConfigMarshaller::Write( ::media::SampleFormat sample_format; ::media::ChannelLayout channel_layout; int samples_per_second; - bool is_encrypted; size_t extra_data_size; std::vector extra_data; + ::media::EncryptionScheme encryption_scheme; CHECK(msg->ReadPod(&codec)); CHECK(msg->ReadPod(&channel_layout)); CHECK(msg->ReadPod(&samples_per_second)); CHECK(msg->ReadPod(&sample_format)); - CHECK(msg->ReadPod(&is_encrypted)); + encryption_scheme = EncryptionSchemeMarshaller::Read(msg); CHECK(msg->ReadPod(&extra_data_size)); CHECK_GE(codec, ::media::kUnknownAudioCodec); @@ -67,7 +68,7 @@ void AudioDecoderConfigMarshaller::Write( return ::media::AudioDecoderConfig( codec, sample_format, channel_layout, samples_per_second, - extra_data, is_encrypted); + extra_data, encryption_scheme); } } // namespace media diff --git a/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.cc b/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.cc new file mode 100644 index 0000000..a88cfc5 --- /dev/null +++ b/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.cc @@ -0,0 +1,54 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h" + +#include + +#include "base/logging.h" +#include "chromecast/media/cma/ipc/media_message.h" + +namespace chromecast { +namespace media { + +namespace { + +class PatternSpecMarshaller { + public: + static void Write(const ::media::EncryptionScheme::Pattern& pattern, + MediaMessage* msg) { + CHECK(msg->WritePod(pattern.encrypt_blocks())); + CHECK(msg->WritePod(pattern.skip_blocks())); + } + + static ::media::EncryptionScheme::Pattern Read(MediaMessage* msg) { + uint32_t encrypt_blocks; + uint32_t skip_blocks; + CHECK(msg->ReadPod(&encrypt_blocks)); + CHECK(msg->ReadPod(&skip_blocks)); + return ::media::EncryptionScheme::Pattern(encrypt_blocks, skip_blocks); + } +}; + +} // namespace + +// static +void EncryptionSchemeMarshaller::Write( + const ::media::EncryptionScheme& encryption_scheme, + MediaMessage* msg) { + CHECK(msg->WritePod(encryption_scheme.mode())); + PatternSpecMarshaller::Write(encryption_scheme.pattern(), msg); +} + +// static +::media::EncryptionScheme EncryptionSchemeMarshaller::Read(MediaMessage* msg) { + ::media::EncryptionScheme::CipherMode mode; + ::media::EncryptionScheme::Pattern pattern; + CHECK(msg->ReadPod(&mode)); + pattern = PatternSpecMarshaller::Read(msg); + return ::media::EncryptionScheme(mode, pattern); +} + +} // namespace media +} // namespace chromecast diff --git a/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h b/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h new file mode 100644 index 0000000..0b3371b --- /dev/null +++ b/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h @@ -0,0 +1,27 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_MEDIA_CMA_IPC_STREAMER_ENCRYPTION_SCHEME_MARSHALLER_H_ +#define CHROMECAST_MEDIA_CMA_IPC_STREAMER_ENCRYPTION_SCHEME_MARSHALLER_H_ + +#include "media/base/encryption_scheme.h" + +namespace chromecast { +namespace media { +class MediaMessage; + +class EncryptionSchemeMarshaller { + public: + // Writes the serialized structure of |encryption_scheme| into |msg|. + static void Write( + const ::media::EncryptionScheme& encryption_scheme, MediaMessage* msg); + + // Returns an EncryptionScheme from its serialized structure. + static ::media::EncryptionScheme Read(MediaMessage* msg); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_IPC_STREAMER_ENCRYPTION_SCHEME_MARSHALLER_H_ diff --git a/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc b/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc index b2e9aaa..a471eb6 100644 --- a/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc +++ b/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "chromecast/media/cma/ipc/media_message.h" +#include "chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h" #include "media/base/video_decoder_config.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -67,7 +68,7 @@ void VideoDecoderConfigMarshaller::Write( SizeMarshaller::Write(config.coded_size(), msg); RectMarshaller::Write(config.visible_rect(), msg); SizeMarshaller::Write(config.natural_size(), msg); - CHECK(msg->WritePod(config.is_encrypted())); + EncryptionSchemeMarshaller::Write(config.encryption_scheme(), msg); CHECK(msg->WritePod(config.extra_data().size())); if (!config.extra_data().empty()) CHECK(msg->WriteBuffer(&config.extra_data()[0], @@ -84,8 +85,8 @@ void VideoDecoderConfigMarshaller::Write( gfx::Size coded_size; gfx::Rect visible_rect; gfx::Size natural_size; - bool is_encrypted; size_t extra_data_size; + ::media::EncryptionScheme encryption_scheme; std::vector extra_data; CHECK(msg->ReadPod(&codec)); @@ -95,7 +96,7 @@ void VideoDecoderConfigMarshaller::Write( coded_size = SizeMarshaller::Read(msg); visible_rect = RectMarshaller::Read(msg); natural_size = SizeMarshaller::Read(msg); - CHECK(msg->ReadPod(&is_encrypted)); + encryption_scheme = EncryptionSchemeMarshaller::Read(msg); CHECK(msg->ReadPod(&extra_data_size)); CHECK_GE(codec, ::media::kUnknownVideoCodec); @@ -115,7 +116,7 @@ void VideoDecoderConfigMarshaller::Write( return ::media::VideoDecoderConfig( codec, profile, format, color_space, coded_size, visible_rect, natural_size, - extra_data, is_encrypted); + extra_data, encryption_scheme); } } // namespace media diff --git a/chromecast/media/cma/pipeline/audio_decoder_software_wrapper.cc b/chromecast/media/cma/pipeline/audio_decoder_software_wrapper.cc index 4b15bcc..a1cdf95 100644 --- a/chromecast/media/cma/pipeline/audio_decoder_software_wrapper.cc +++ b/chromecast/media/cma/pipeline/audio_decoder_software_wrapper.cc @@ -59,7 +59,7 @@ bool AudioDecoderSoftwareWrapper::SetConfig(const AudioConfig& config) { return true; } - if (config.is_encrypted || !CreateSoftwareDecoder(config)) + if (config.is_encrypted() || !CreateSoftwareDecoder(config)) return false; output_config_.codec = media::kCodecPCM; @@ -67,7 +67,7 @@ bool AudioDecoderSoftwareWrapper::SetConfig(const AudioConfig& config) { output_config_.channel_number = 2; output_config_.bytes_per_channel = 2; output_config_.samples_per_second = config.samples_per_second; - output_config_.is_encrypted = false; + output_config_.encryption_scheme = Unencrypted(); return backend_decoder_->SetConfig(output_config_); } diff --git a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc index bd747dd..eba1961 100644 --- a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc +++ b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc @@ -66,7 +66,7 @@ class AudioVideoPipelineImplTest ::media::AudioDecoderConfig audio_config( ::media::kCodecMP3, ::media::kSampleFormatS16, ::media::CHANNEL_LAYOUT_STEREO, 44100, ::media::EmptyExtraData(), - false); + ::media::Unencrypted()); AvPipelineClient client; client.eos_cb = base::Bind(&AudioVideoPipelineImplTest::OnEos, base::Unretained(this), STREAM_AUDIO); @@ -80,7 +80,7 @@ class AudioVideoPipelineImplTest ::media::kCodecH264, ::media::H264PROFILE_MAIN, ::media::PIXEL_FORMAT_I420, ::media::COLOR_SPACE_UNSPECIFIED, gfx::Size(640, 480), gfx::Rect(0, 0, 640, 480), gfx::Size(640, 480), - ::media::EmptyExtraData(), false)); + ::media::EmptyExtraData(), ::media::Unencrypted())); VideoPipelineClient client; client.av_pipeline_client.eos_cb = base::Bind(&AudioVideoPipelineImplTest::OnEos, base::Unretained(this), diff --git a/chromecast/media/cma/test/mock_frame_provider.cc b/chromecast/media/cma/test/mock_frame_provider.cc index fdab889..16d6393 100644 --- a/chromecast/media/cma/test/mock_frame_provider.cc +++ b/chromecast/media/cma/test/mock_frame_provider.cc @@ -82,7 +82,7 @@ void MockFrameProvider::DoRead(const ReadCB& read_cb) { ::media::kCodecH264, ::media::VIDEO_CODEC_PROFILE_UNKNOWN, ::media::PIXEL_FORMAT_YV12, ::media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_rect, natural_size, ::media::EmptyExtraData(), - false); + ::media::Unencrypted()); audio_config = ::media::AudioDecoderConfig( ::media::kCodecAAC, @@ -90,7 +90,7 @@ void MockFrameProvider::DoRead(const ReadCB& read_cb) { ::media::CHANNEL_LAYOUT_STEREO, 44100, ::media::EmptyExtraData(), - false); + ::media::Unencrypted()); } read_cb.Run(buffer, audio_config, video_config); diff --git a/chromecast/media/media.gyp b/chromecast/media/media.gyp index 6cabfc7..077ea0c 100644 --- a/chromecast/media/media.gyp +++ b/chromecast/media/media.gyp @@ -229,6 +229,8 @@ 'cma/ipc_streamer/decoder_buffer_base_marshaller.h', 'cma/ipc_streamer/decrypt_config_marshaller.cc', 'cma/ipc_streamer/decrypt_config_marshaller.h', + 'cma/ipc_streamer/encryption_scheme_marshaller.cc', + 'cma/ipc_streamer/encryption_scheme_marshaller.h', 'cma/ipc_streamer/video_decoder_config_marshaller.cc', 'cma/ipc_streamer/video_decoder_config_marshaller.h', ], diff --git a/chromecast/public/media/decoder_config.h b/chromecast/public/media/decoder_config.h index 261b3f1..b82c5c1 100644 --- a/chromecast/public/media/decoder_config.h +++ b/chromecast/public/media/decoder_config.h @@ -93,13 +93,78 @@ enum VideoProfile { kVideoProfileMax = kDolbyVisionNonCompatible_BL_EL_MD, }; -// TODO(erickung): Remove constructor once CMA backend implementation does't +// Specification of whether and how the stream is encrypted (in whole or part). +struct EncryptionScheme { + // Algorithm and mode that was used to encrypt the stream. + enum CipherMode { + CIPHER_MODE_UNENCRYPTED, + CIPHER_MODE_AES_CTR, + CIPHER_MODE_AES_CBC + }; + + // CENC 3rd Edition adds pattern encryption, through two new protection + // schemes: 'cens' (with AES-CTR) and 'cbcs' (with AES-CBC). + // The pattern applies independently to each 'encrypted' part of the frame (as + // defined by the relevant subsample entries), and reduces further the + // actual encryption applied through a repeating pattern of (encrypt:skip) + // 16 byte blocks. For example, in a (1:9) pattern, the first block is + // encrypted, and the next nine are skipped. This pattern is applied + // repeatedly until the end of the last 16-byte block in the subsample. + // Any remaining bytes are left clear. + // If either of encrypt_blocks or skip_blocks is 0, pattern encryption is + // disabled. + struct Pattern { + Pattern() {} + Pattern(uint32_t encrypt_blocks, uint32_t skip_blocks); + ~Pattern() {} + bool IsInEffect() const; + + uint32_t encrypt_blocks = 0; + uint32_t skip_blocks = 0; + }; + + EncryptionScheme() {} + EncryptionScheme(CipherMode mode, const Pattern& pattern); + ~EncryptionScheme() {} + bool is_encrypted() const { return mode != CIPHER_MODE_UNENCRYPTED; } + + CipherMode mode = CIPHER_MODE_UNENCRYPTED; + Pattern pattern; +}; + +inline EncryptionScheme::Pattern::Pattern(uint32_t encrypt_blocks, + uint32_t skip_blocks) + : encrypt_blocks(encrypt_blocks), skip_blocks(skip_blocks) { +} + +inline bool EncryptionScheme::Pattern::IsInEffect() const { + return encrypt_blocks != 0 && skip_blocks != 0; +} + +inline EncryptionScheme::EncryptionScheme(CipherMode mode, + const Pattern& pattern) + : mode(mode), pattern(pattern) { +} + +inline EncryptionScheme Unencrypted() { + return EncryptionScheme(); +} + +inline EncryptionScheme AesCtrEncryptionScheme() { + return EncryptionScheme(EncryptionScheme::CIPHER_MODE_AES_CTR, + EncryptionScheme::Pattern()); +} + + +// TODO(erickung): Remove constructor once CMA backend implementation doesn't // create a new object to reset the configuration and use IsValidConfig() to // determine if the configuration is still valid or not. struct AudioConfig { AudioConfig(); ~AudioConfig(); + bool is_encrypted() const { return encryption_scheme.is_encrypted(); } + // Stream id. StreamId id; // Audio codec. @@ -114,8 +179,8 @@ struct AudioConfig { int samples_per_second; // Extra data buffer for certain codec initialization. std::vector extra_data; - // content is encrypted or not. - bool is_encrypted; + // Encryption scheme (if any) used for the content. + EncryptionScheme encryption_scheme; }; inline AudioConfig::AudioConfig() @@ -124,8 +189,7 @@ inline AudioConfig::AudioConfig() sample_format(kUnknownSampleFormat), bytes_per_channel(0), channel_number(0), - samples_per_second(0), - is_encrypted(false) { + samples_per_second(0) { } inline AudioConfig::~AudioConfig() { @@ -138,6 +202,8 @@ struct VideoConfig { VideoConfig(); ~VideoConfig(); + bool is_encrypted() const { return encryption_scheme.is_encrypted(); } + // Stream Id. StreamId id; // Video codec. @@ -150,16 +216,15 @@ struct VideoConfig { VideoConfig* additional_config; // Extra data buffer for certain codec initialization. std::vector extra_data; - // content is encrypted or not. - bool is_encrypted; + // Encryption scheme (if any) used for the content. + EncryptionScheme encryption_scheme; }; inline VideoConfig::VideoConfig() : id(kPrimary), codec(kVideoCodecUnknown), profile(kVideoProfileUnknown), - additional_config(nullptr), - is_encrypted(false) { + additional_config(nullptr) { } inline VideoConfig::~VideoConfig() { -- cgit v1.1