diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py index 3982839d52..51e3dbb3e5 100755 --- a/packager/app/test/packager_test.py +++ b/packager/app/test/packager_test.py @@ -862,6 +862,13 @@ class PackagerFunctionalTest(PackagerAppTest): self._GetFlags(encryption=True, output_dash=True)) self._CheckTestResults('encryption', verify_decryption=True) + def testEncryptionWithFairplay(self): + self.assertPackageSuccess( + self._GetStreams(['audio', 'video']), + self._GetFlags( + encryption=True, fairplay=True, output_dash=True, output_hls=True)) + self._CheckTestResults('encryption-with-fairplay') + # Test deprecated flag --enable_fixed_key_encryption, which is still # supported currently. def testEncryptionUsingFixedKey(self): diff --git a/packager/app/test/testdata/encryption-with-fairplay/bear-640x360-audio.mp4 b/packager/app/test/testdata/encryption-with-fairplay/bear-640x360-audio.mp4 new file mode 100644 index 0000000000..22fcb0a3ac Binary files /dev/null and b/packager/app/test/testdata/encryption-with-fairplay/bear-640x360-audio.mp4 differ diff --git a/packager/app/test/testdata/encryption-with-fairplay/bear-640x360-video.mp4 b/packager/app/test/testdata/encryption-with-fairplay/bear-640x360-video.mp4 new file mode 100644 index 0000000000..81691dafee Binary files /dev/null and b/packager/app/test/testdata/encryption-with-fairplay/bear-640x360-video.mp4 differ diff --git a/packager/app/test/testdata/encryption-with-fairplay/output.m3u8 b/packager/app/test/testdata/encryption-with-fairplay/output.m3u8 new file mode 100644 index 0000000000..b01af091c9 --- /dev/null +++ b/packager/app/test/testdata/encryption-with-fairplay/output.m3u8 @@ -0,0 +1,7 @@ +#EXTM3U +## Generated with https://github.com/google/shaka-packager version -- + +#EXT-X-MEDIA:TYPE=AUDIO,URI="stream_0.m3u8",GROUP-ID="default-audio-group",NAME="stream_0",AUTOSELECT=YES,CHANNELS="2" + +#EXT-X-STREAM-INF:BANDWIDTH=1111406,AVERAGE-BANDWIDTH=1009412,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group" +stream_1.m3u8 diff --git a/packager/app/test/testdata/encryption-with-fairplay/output.mpd b/packager/app/test/testdata/encryption-with-fairplay/output.mpd new file mode 100644 index 0000000000..a98ef3ed20 --- /dev/null +++ b/packager/app/test/testdata/encryption-with-fairplay/output.mpd @@ -0,0 +1,27 @@ + + + + + + + + + bear-640x360-video.mp4 + + + + + + + + + + + bear-640x360-audio.mp4 + + + + + + + diff --git a/packager/app/test/testdata/encryption-with-fairplay/stream_0.m3u8 b/packager/app/test/testdata/encryption-with-fairplay/stream_0.m3u8 new file mode 100644 index 0000000000..41bfea4b0a --- /dev/null +++ b/packager/app/test/testdata/encryption-with-fairplay/stream_0.m3u8 @@ -0,0 +1,17 @@ +#EXTM3U +#EXT-X-VERSION:6 +## Generated with https://github.com/google/shaka-packager version -- +#EXT-X-TARGETDURATION:2 +#EXT-X-PLAYLIST-TYPE:VOD +#EXT-X-MAP:URI="bear-640x360-audio.mp4",BYTERANGE="951@0" +#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="skd://www.license.com/getkey?KeyId=31323334-3536-3738-3930-313233343536",KEYFORMATVERSIONS="1",KEYFORMAT="com.apple.streamingkeydelivery" +#EXTINF:1.022, +#EXT-X-BYTERANGE:17028@1019 +bear-640x360-audio.mp4 +#EXTINF:0.998, +#EXT-X-BYTERANGE:16682 +bear-640x360-audio.mp4 +#EXTINF:0.720, +#EXT-X-BYTERANGE:9859 +bear-640x360-audio.mp4 +#EXT-X-ENDLIST diff --git a/packager/app/test/testdata/encryption-with-fairplay/stream_1.m3u8 b/packager/app/test/testdata/encryption-with-fairplay/stream_1.m3u8 new file mode 100644 index 0000000000..8ef9329090 --- /dev/null +++ b/packager/app/test/testdata/encryption-with-fairplay/stream_1.m3u8 @@ -0,0 +1,17 @@ +#EXTM3U +#EXT-X-VERSION:6 +## Generated with https://github.com/google/shaka-packager version -- +#EXT-X-TARGETDURATION:2 +#EXT-X-PLAYLIST-TYPE:VOD +#EXT-X-MAP:URI="bear-640x360-video.mp4",BYTERANGE="1075@0" +#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="skd://www.license.com/getkey?KeyId=31323334-3536-3738-3930-313233343536",KEYFORMATVERSIONS="1",KEYFORMAT="com.apple.streamingkeydelivery" +#EXTINF:1.001, +#EXT-X-BYTERANGE:99313@1143 +bear-640x360-video.mp4 +#EXTINF:1.001, +#EXT-X-BYTERANGE:122340 +bear-640x360-video.mp4 +#EXTINF:0.734, +#EXT-X-BYTERANGE:80067 +bear-640x360-video.mp4 +#EXT-X-ENDLIST diff --git a/packager/media/base/fairplay_pssh_generator.cc b/packager/media/base/fairplay_pssh_generator.cc deleted file mode 100644 index 9fd509a413..0000000000 --- a/packager/media/base/fairplay_pssh_generator.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2018 Google LLC. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -#include "packager/media/base/fairplay_pssh_generator.h" - -#include "packager/media/base/protection_system_ids.h" - -namespace shaka { -namespace media { -namespace { -const uint8_t kFairPlayPsshBoxVersion = 1; -} // namespace - -FairPlayPsshGenerator::FairPlayPsshGenerator() - : PsshGenerator(std::vector(std::begin(kFairPlaySystemId), - std::end(kFairPlaySystemId)), - kFairPlayPsshBoxVersion) {} - -FairPlayPsshGenerator::~FairPlayPsshGenerator() = default; - -bool FairPlayPsshGenerator::SupportMultipleKeys() { - return true; -} - -base::Optional> -FairPlayPsshGenerator::GeneratePsshDataFromKeyIdAndKey( - const std::vector& key_id, - const std::vector& key) const { - NOTIMPLEMENTED(); - return base::nullopt; -} - -base::Optional> -FairPlayPsshGenerator::GeneratePsshDataFromKeyIds( - const std::vector>& key_ids) const { - // Intentionally empty PSSH data for FairPlay. - return std::vector(); -} - -} // namespace media -} // namespace shaka diff --git a/packager/media/base/fairplay_pssh_generator.h b/packager/media/base/fairplay_pssh_generator.h deleted file mode 100644 index 285219aaf6..0000000000 --- a/packager/media/base/fairplay_pssh_generator.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 Google LLC. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -#ifndef PACKAGER_MEDIA_BASE_FAIRPLAY_PSSH_GENERATOR_H_ -#define PACKAGER_MEDIA_BASE_FAIRPLAY_PSSH_GENERATOR_H_ - -#include "packager/media/base/pssh_generator.h" - -namespace shaka { -namespace media { - -class FairPlayPsshGenerator : public PsshGenerator { - public: - FairPlayPsshGenerator(); - ~FairPlayPsshGenerator() override; - - /// @name PsshGenerator implemetation overrides. - /// @{ - bool SupportMultipleKeys() override; - /// @} - - private: - FairPlayPsshGenerator& operator=(const FairPlayPsshGenerator&) = delete; - FairPlayPsshGenerator(const FairPlayPsshGenerator&) = delete; - - // PsshGenerator implemetation overrides. - - base::Optional> GeneratePsshDataFromKeyIds( - const std::vector>& key_ids) const override; - - base::Optional> GeneratePsshDataFromKeyIdAndKey( - const std::vector& key_id, - const std::vector& key) const override; -}; - -} // namespace media -} // namespace shaka - -#endif // PACKAGER_MEDIA_BASE_FAIRPLAY_PSSH_GENERATOR_H_ diff --git a/packager/media/base/key_source.cc b/packager/media/base/key_source.cc index 6586d8aa4f..474aa32036 100644 --- a/packager/media/base/key_source.cc +++ b/packager/media/base/key_source.cc @@ -8,8 +8,8 @@ #include "packager/base/logging.h" #include "packager/media/base/common_pssh_generator.h" -#include "packager/media/base/fairplay_pssh_generator.h" #include "packager/media/base/playready_pssh_generator.h" +#include "packager/media/base/protection_system_ids.h" #include "packager/media/base/widevine_pssh_generator.h" #include "packager/status_macros.h" @@ -30,7 +30,8 @@ KeySource::KeySource(int protection_systems_flags, FourCC protection_scheme) { } if (protection_systems_flags & FAIRPLAY_PROTECTION_SYSTEM_FLAG) { - pssh_generators_.emplace_back(new FairPlayPsshGenerator()); + no_pssh_systems_.emplace_back(std::begin(kFairPlaySystemId), + std::end(kFairPlaySystemId)); } } @@ -60,6 +61,14 @@ Status KeySource::UpdateProtectionSystemInfo( } } + for (const auto& no_pssh_system : no_pssh_systems_) { + ProtectionSystemSpecificInfo info; + info.system_id = no_pssh_system; + for (const EncryptionKeyMap::value_type& pair : *encryption_key_map) { + pair.second->key_system_info.push_back(info); + } + } + return Status::OK; } diff --git a/packager/media/base/key_source.h b/packager/media/base/key_source.h index 3e2c11a362..55ea6950e7 100644 --- a/packager/media/base/key_source.h +++ b/packager/media/base/key_source.h @@ -92,6 +92,7 @@ class KeySource { private: std::vector> pssh_generators_; + std::vector> no_pssh_systems_; DISALLOW_COPY_AND_ASSIGN(KeySource); }; diff --git a/packager/media/base/media_base.gyp b/packager/media/base/media_base.gyp index 00fe9f0aef..4b86ac824b 100644 --- a/packager/media/base/media_base.gyp +++ b/packager/media/base/media_base.gyp @@ -46,8 +46,6 @@ 'decryptor_source.cc', 'decryptor_source.h', 'encryption_config.h', - 'fairplay_pssh_generator.cc', - 'fairplay_pssh_generator.h', 'fourccs.h', 'http_key_fetcher.cc', 'http_key_fetcher.h', diff --git a/packager/media/formats/mp4/mp4_muxer.cc b/packager/media/formats/mp4/mp4_muxer.cc index 5314250cae..f0b5e1b887 100644 --- a/packager/media/formats/mp4/mp4_muxer.cc +++ b/packager/media/formats/mp4/mp4_muxer.cc @@ -268,10 +268,15 @@ Status MP4Muxer::DelayInitializeMuxer() { } if (stream->is_encrypted() && options().mp4_params.include_pssh_in_stream) { + moov->pssh.clear(); const auto& key_system_info = stream->encryption_config().key_system_info; - moov->pssh.resize(key_system_info.size()); - for (size_t j = 0; j < key_system_info.size(); j++) - moov->pssh[j].raw_box = key_system_info[j].psshs; + for (const ProtectionSystemSpecificInfo& system : key_system_info) { + if (system.psshs.empty()) + continue; + ProtectionSystemSpecificHeader pssh; + pssh.raw_box = system.psshs; + moov->pssh.push_back(pssh); + } } } diff --git a/packager/media/formats/mp4/segmenter.cc b/packager/media/formats/mp4/segmenter.cc index c9fcefc6ee..cce500dea4 100644 --- a/packager/media/formats/mp4/segmenter.cc +++ b/packager/media/formats/mp4/segmenter.cc @@ -278,11 +278,15 @@ void Segmenter::FinalizeFragmentForKeyRotation( bool fragment_encrypted, const EncryptionConfig& encryption_config) { if (options_.mp4_params.include_pssh_in_stream) { - const std::vector& system_info = - encryption_config.key_system_info; - moof_->pssh.resize(system_info.size()); - for (size_t i = 0; i < system_info.size(); i++) - moof_->pssh[i].raw_box = system_info[i].psshs; + moof_->pssh.clear(); + const auto& key_system_info = encryption_config.key_system_info; + for (const ProtectionSystemSpecificInfo& system : key_system_info) { + if (system.psshs.empty()) + continue; + ProtectionSystemSpecificHeader pssh; + pssh.raw_box = system.psshs; + moof_->pssh.push_back(pssh); + } } else { LOG(WARNING) << "Key rotation and no pssh in stream may not work well together."; diff --git a/packager/mpd/base/mpd_utils.cc b/packager/mpd/base/mpd_utils.cc index fa97e530fb..ed0d308959 100644 --- a/packager/mpd/base/mpd_utils.cc +++ b/packager/mpd/base/mpd_utils.cc @@ -352,7 +352,7 @@ void AddContentProtectionElementsHelperTemplated( if (entry.has_name_version()) drm_content_protection.value = entry.name_version(); - if (entry.has_pssh()) { + if (!entry.pssh().empty()) { std::string base64_encoded_pssh; base::Base64Encode( base::StringPiece(entry.pssh().data(), entry.pssh().size()),