From 66f713fd235088a9f619ebe07472f4e1452921a2 Mon Sep 17 00:00:00 2001 From: KongQun Yang Date: Tue, 19 Dec 2017 12:02:28 -0800 Subject: [PATCH] Merge SimpleMpdNotifier and DashIopMpdNotifier Also removed MpdNotifier::AddContentProtectionElement which is not used anywhere. Change-Id: I69eb596ec377c601bb3e45bbef30c248c1d03e86 --- packager/mpd/base/dash_iop_mpd_notifier.cc | 126 --------- packager/mpd/base/dash_iop_mpd_notifier.h | 86 ------ .../base/dash_iop_mpd_notifier_unittest.cc | 252 ------------------ packager/mpd/base/mpd_notifier.h | 10 - packager/mpd/base/simple_mpd_notifier.cc | 56 ++-- packager/mpd/base/simple_mpd_notifier.h | 27 +- .../mpd/base/simple_mpd_notifier_unittest.cc | 84 +++--- packager/mpd/mpd.gyp | 3 - packager/mpd/util/mpd_writer.cc | 21 +- packager/mpd/util/mpd_writer_unittest.cc | 1 - packager/packager.cc | 9 +- 11 files changed, 97 insertions(+), 578 deletions(-) delete mode 100644 packager/mpd/base/dash_iop_mpd_notifier.cc delete mode 100644 packager/mpd/base/dash_iop_mpd_notifier.h delete mode 100644 packager/mpd/base/dash_iop_mpd_notifier_unittest.cc diff --git a/packager/mpd/base/dash_iop_mpd_notifier.cc b/packager/mpd/base/dash_iop_mpd_notifier.cc deleted file mode 100644 index ffea071216..0000000000 --- a/packager/mpd/base/dash_iop_mpd_notifier.cc +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2015 Google Inc. 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/mpd/base/dash_iop_mpd_notifier.h" - -#include "packager/base/stl_util.h" -#include "packager/mpd/base/adaptation_set.h" -#include "packager/mpd/base/media_info.pb.h" -#include "packager/mpd/base/mpd_notifier_util.h" -#include "packager/mpd/base/period.h" -#include "packager/mpd/base/representation.h" - -namespace { -const bool kContentProtectionInAdaptationSet = true; -} // namespace - -namespace shaka { - -DashIopMpdNotifier::DashIopMpdNotifier(const MpdOptions& mpd_options) - : MpdNotifier(mpd_options), - output_path_(mpd_options.mpd_params.mpd_output), - mpd_builder_(new MpdBuilder(mpd_options)) { - for (const std::string& base_url : mpd_options.mpd_params.base_urls) - mpd_builder_->AddBaseUrl(base_url); -} - -DashIopMpdNotifier::~DashIopMpdNotifier() {} - -bool DashIopMpdNotifier::Init() { - return true; -} - -bool DashIopMpdNotifier::NotifyNewContainer(const MediaInfo& media_info, - uint32_t* container_id) { - DCHECK(container_id); - - ContentType content_type = GetContentType(media_info); - if (content_type == kContentTypeUnknown) - return false; - - base::AutoLock auto_lock(lock_); - if (!period_) - period_ = mpd_builder_->AddPeriod(); - AdaptationSet* adaptation_set = period_->GetOrCreateAdaptationSet( - media_info, kContentProtectionInAdaptationSet); - DCHECK(adaptation_set); - - MediaInfo adjusted_media_info(media_info); - MpdBuilder::MakePathsRelativeToMpd(output_path_, &adjusted_media_info); - Representation* representation = - adaptation_set->AddRepresentation(adjusted_media_info); - if (!representation) - return false; - - representation_id_to_adaptation_set_[representation->id()] = adaptation_set; - - *container_id = representation->id(); - DCHECK(!ContainsKey(representation_map_, representation->id())); - representation_map_[representation->id()] = representation; - return true; -} - -bool DashIopMpdNotifier::NotifySampleDuration(uint32_t container_id, - uint32_t sample_duration) { - base::AutoLock auto_lock(lock_); - auto it = representation_map_.find(container_id); - if (it == representation_map_.end()) { - LOG(ERROR) << "Unexpected container_id: " << container_id; - return false; - } - it->second->SetSampleDuration(sample_duration); - return true; -} - -bool DashIopMpdNotifier::NotifyNewSegment(uint32_t container_id, - uint64_t start_time, - uint64_t duration, - uint64_t size) { - base::AutoLock auto_lock(lock_); - auto it = representation_map_.find(container_id); - if (it == representation_map_.end()) { - LOG(ERROR) << "Unexpected container_id: " << container_id; - return false; - } - it->second->AddNewSegment(start_time, duration, size); - return true; -} - -bool DashIopMpdNotifier::NotifyEncryptionUpdate( - uint32_t container_id, - const std::string& drm_uuid, - const std::vector& new_key_id, - const std::vector& new_pssh) { - base::AutoLock auto_lock(lock_); - auto it = representation_map_.find(container_id); - if (it == representation_map_.end()) { - LOG(ERROR) << "Unexpected container_id: " << container_id; - return false; - } - - AdaptationSet* adaptation_set_for_representation = - representation_id_to_adaptation_set_[it->second->id()]; - adaptation_set_for_representation->UpdateContentProtectionPssh( - drm_uuid, Uint8VectorToBase64(new_pssh)); - return true; -} - -bool DashIopMpdNotifier::AddContentProtectionElement( - uint32_t container_id, - const ContentProtectionElement& content_protection_element) { - // Intentionally not implemented because if a Representation gets a new - // element, then it might require moving the - // Representation out of the AdaptationSet. There's no logic to do that - // yet. - return false; -} - -bool DashIopMpdNotifier::Flush() { - base::AutoLock auto_lock(lock_); - return WriteMpdToFile(output_path_, mpd_builder_.get()); -} - -} // namespace shaka diff --git a/packager/mpd/base/dash_iop_mpd_notifier.h b/packager/mpd/base/dash_iop_mpd_notifier.h deleted file mode 100644 index 64e627c460..0000000000 --- a/packager/mpd/base/dash_iop_mpd_notifier.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2015 Google Inc. 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 MPD_BASE_DASH_IOP_MPD_NOTIFIER_H_ -#define MPD_BASE_DASH_IOP_MPD_NOTIFIER_H_ - -#include "packager/mpd/base/mpd_notifier.h" - -#include -#include -#include - -#include "packager/base/synchronization/lock.h" -#include "packager/mpd/base/mpd_notifier_util.h" -#include "packager/mpd/base/mpd_options.h" - -namespace shaka { - -class AdaptationSet; -class MpdBuilder; -class Period; -class Representation; - -/// This class is an MpdNotifier which will try its best to generate a -/// DASH IF IOPv3 compliant MPD. -/// e.g. -/// All elements must be right under -/// and cannot be under . -/// All video Adaptation Sets have Role set to "main". -class DashIopMpdNotifier : public MpdNotifier { - public: - explicit DashIopMpdNotifier(const MpdOptions& mpd_options); - ~DashIopMpdNotifier() override; - - /// None of the methods write out the MPD file until Flush() is called. - /// @name MpdNotifier implemetation overrides. - /// @{ - bool Init() override; - bool NotifyNewContainer(const MediaInfo& media_info, uint32_t* id) override; - bool NotifySampleDuration(uint32_t container_id, - uint32_t sample_duration) override; - bool NotifyNewSegment(uint32_t id, - uint64_t start_time, - uint64_t duration, - uint64_t size) override; - bool NotifyEncryptionUpdate(uint32_t container_id, - const std::string& drm_uuid, - const std::vector& new_key_id, - const std::vector& new_pssh) override; - bool AddContentProtectionElement( - uint32_t id, - const ContentProtectionElement& content_protection_element) override; - bool Flush() override; - /// @} - - private: - friend class DashIopMpdNotifierTest; - - // Testing only method. Returns a pointer to MpdBuilder. - MpdBuilder* MpdBuilderForTesting() const { - return mpd_builder_.get(); - } - - // Testing only method. Sets mpd_builder_. - void SetMpdBuilderForTesting(std::unique_ptr mpd_builder) { - mpd_builder_ = std::move(mpd_builder); - } - - // MPD output path. - std::string output_path_; - std::unique_ptr mpd_builder_; - Period* period_ = nullptr; // owned by |mpd_builder_|. - base::Lock lock_; - - // Maps representation ID to Representation. - std::map representation_map_; - // Maps Representation ID to AdaptationSet. This is for updating the PSSH. - std::map representation_id_to_adaptation_set_; -}; - -} // namespace shaka - -#endif // MPD_BASE_DASH_IOP_MPD_NOTIFIER_H_ diff --git a/packager/mpd/base/dash_iop_mpd_notifier_unittest.cc b/packager/mpd/base/dash_iop_mpd_notifier_unittest.cc deleted file mode 100644 index 5d08f9f303..0000000000 --- a/packager/mpd/base/dash_iop_mpd_notifier_unittest.cc +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2015 Google Inc. 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 -#include -#include - -#include "packager/base/files/file_path.h" -#include "packager/base/files/file_util.h" -#include "packager/mpd/base/dash_iop_mpd_notifier.h" -#include "packager/mpd/base/mock_mpd_builder.h" -#include "packager/mpd/base/mpd_builder.h" -#include "packager/mpd/test/mpd_builder_test_helper.h" - -namespace shaka { - -using ::testing::_; -using ::testing::AnyOf; -using ::testing::Eq; -using ::testing::Return; -using ::testing::StrEq; - -namespace { - -const uint32_t kDefaultAdaptationSetId = 0u; -const uint32_t kDefaultRepresentationId = 1u; -const bool kContentProtectionInAdaptationSet = true; - -MATCHER_P(EqualsProto, message, "") { - return ::google::protobuf::util::MessageDifferencer::Equals(arg, message); -} - -} // namespace - -// TODO(rkuroiwa): This is almost exactly the same as SimpleMpdNotifierTest but -// replaced all SimpleMpd with DashIopMpd, -// use typed tests -// (https://code.google.com/p/googletest/wiki/AdvancedGuide#Typed_Tests); -// also because SimpleMpdNotifier and DashIopMpdNotifier have common behavior -// for most of the public functions. -class DashIopMpdNotifierTest : public ::testing::Test { - protected: - DashIopMpdNotifierTest() - : default_mock_period_(new MockPeriod), - default_mock_adaptation_set_( - new MockAdaptationSet(kDefaultAdaptationSetId)), - default_mock_representation_( - new MockRepresentation(kDefaultRepresentationId)) {} - - void SetUp() override { - ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_)); - empty_mpd_option_.mpd_params.mpd_output = temp_file_path_.AsUTF8Unsafe(); - - // Three valid media info. The actual data does not matter. - const char kValidMediaInfo[] = - "video_info {\n" - " codec: 'avc1'\n" - " width: 1280\n" - " height: 720\n" - " time_scale: 10\n" - " frame_duration: 10\n" - " pixel_width: 1\n" - " pixel_height: 1\n" - "}\n" - "container_type: 1\n"; - valid_media_info1_ = ConvertToMediaInfo(kValidMediaInfo); - valid_media_info2_ = valid_media_info1_; - valid_media_info2_.mutable_video_info()->set_width(960); - valid_media_info3_ = valid_media_info1_; - valid_media_info3_.mutable_video_info()->set_width(480); - } - - void TearDown() override { - base::DeleteFile(temp_file_path_, false /* non recursive, just 1 file */); - } - - void SetMpdBuilder(DashIopMpdNotifier* notifier, - std::unique_ptr mpd_builder) { - notifier->SetMpdBuilderForTesting(std::move(mpd_builder)); - } - - protected: - // Empty mpd options except with output path specified, so that - // WriteMpdToFile() doesn't crash. - MpdOptions empty_mpd_option_; - - // Default mocks that can be used for the tests. - // IOW, if a test only requires one instance of - // Mock{Period,AdaptationSet,Representation}, these can be used. - std::unique_ptr default_mock_period_; - std::unique_ptr default_mock_adaptation_set_; - std::unique_ptr default_mock_representation_; - - // Three valid media info. The actual content does not matter. - MediaInfo valid_media_info1_; - MediaInfo valid_media_info2_; - MediaInfo valid_media_info3_; - - private: - base::FilePath temp_file_path_; -}; - -// Verify that basic VOD NotifyNewContainer() operation works. -// No encrypted contents. -TEST_F(DashIopMpdNotifierTest, NotifyNewContainer) { - DashIopMpdNotifier notifier(empty_mpd_option_); - - std::unique_ptr mock_mpd_builder(new MockMpdBuilder()); - - EXPECT_CALL(*mock_mpd_builder, AddPeriod()) - .WillOnce(Return(default_mock_period_.get())); - EXPECT_CALL(*default_mock_period_, - GetOrCreateAdaptationSet(EqualsProto(valid_media_info1_), - Eq(kContentProtectionInAdaptationSet))) - .WillOnce(Return(default_mock_adaptation_set_.get())); - EXPECT_CALL(*default_mock_adaptation_set_, AddRepresentation(_)) - .WillOnce(Return(default_mock_representation_.get())); - - // This is for the Flush() below but adding expectation here because the next - // std::move(lines) the pointer. - EXPECT_CALL(*mock_mpd_builder, ToString(_)).WillOnce(Return(true)); - - uint32_t unused_container_id; - SetMpdBuilder(¬ifier, std::move(mock_mpd_builder)); - EXPECT_TRUE( - notifier.NotifyNewContainer(valid_media_info1_, &unused_container_id)); - EXPECT_TRUE(notifier.Flush()); -} - -// AddContentProtection() should not work and should always return false. -TEST_F(DashIopMpdNotifierTest, AddContentProtection) { - DashIopMpdNotifier notifier(empty_mpd_option_); - - std::unique_ptr mock_mpd_builder(new MockMpdBuilder()); - - EXPECT_CALL(*mock_mpd_builder, AddPeriod()) - .WillOnce(Return(default_mock_period_.get())); - EXPECT_CALL(*default_mock_period_, GetOrCreateAdaptationSet(_, _)) - .WillOnce(Return(default_mock_adaptation_set_.get())); - EXPECT_CALL(*default_mock_adaptation_set_, AddRepresentation(_)) - .WillOnce(Return(default_mock_representation_.get())); - - uint32_t container_id; - SetMpdBuilder(¬ifier, std::move(mock_mpd_builder)); - EXPECT_TRUE(notifier.NotifyNewContainer(valid_media_info1_, &container_id)); - - ContentProtectionElement empty_content_protection_element; - EXPECT_FALSE(notifier.AddContentProtectionElement( - container_id, empty_content_protection_element)); -} - -TEST_F(DashIopMpdNotifierTest, UpdateEncryption) { - DashIopMpdNotifier notifier(empty_mpd_option_); - - std::unique_ptr mock_mpd_builder(new MockMpdBuilder()); - - EXPECT_CALL(*mock_mpd_builder, AddPeriod()) - .WillOnce(Return(default_mock_period_.get())); - EXPECT_CALL(*default_mock_period_, GetOrCreateAdaptationSet(_, _)) - .WillOnce(Return(default_mock_adaptation_set_.get())); - EXPECT_CALL(*default_mock_adaptation_set_, AddRepresentation(_)) - .WillOnce(Return(default_mock_representation_.get())); - - uint32_t container_id; - SetMpdBuilder(¬ifier, std::move(mock_mpd_builder)); - EXPECT_TRUE(notifier.NotifyNewContainer(valid_media_info1_, &container_id)); - - ::testing::Mock::VerifyAndClearExpectations( - default_mock_adaptation_set_.get()); - - const uint8_t kBogusNewPssh[] = {// "psshsomethingelse" as uint8 array. - 0x70, 0x73, 0x73, 0x68, 0x73, 0x6f, - 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, - 0x67, 0x65, 0x6c, 0x73, 0x65}; - const std::vector kBogusNewPsshVector( - kBogusNewPssh, kBogusNewPssh + arraysize(kBogusNewPssh)); - const char kBogusNewPsshInBase64[] = "cHNzaHNvbWV0aGluZ2Vsc2U="; - - EXPECT_CALL(*default_mock_adaptation_set_, - UpdateContentProtectionPssh(StrEq("myuuid"), - StrEq(kBogusNewPsshInBase64))); - EXPECT_TRUE(notifier.NotifyEncryptionUpdate( - container_id, "myuuid", std::vector(), kBogusNewPsshVector)); -} - -// This test is mainly for tsan. Using both the notifier and the MpdBuilder. -// Although locks in MpdBuilder have been removed, -// https://github.com/google/shaka-packager/issues/45 -// This issue identified a bug where using SimpleMpdNotifier with multiple -// threads causes a deadlock. This tests with DashIopMpdNotifier. -TEST_F(DashIopMpdNotifierTest, NotifyNewContainerAndSampleDurationNoMock) { - DashIopMpdNotifier notifier(empty_mpd_option_); - uint32_t container_id; - EXPECT_TRUE(notifier.NotifyNewContainer(valid_media_info1_, &container_id)); - const uint32_t kAnySampleDuration = 1000; - EXPECT_TRUE(notifier.NotifySampleDuration(container_id, kAnySampleDuration)); - EXPECT_TRUE(notifier.Flush()); -} - -// Test multiple media info with some belongs to the same AdaptationSets. -TEST_F(DashIopMpdNotifierTest, MultipleMediaInfo) { - DashIopMpdNotifier notifier(empty_mpd_option_); - std::unique_ptr mock_mpd_builder(new MockMpdBuilder()); - - std::unique_ptr adaptation_set1(new MockAdaptationSet(1)); - std::unique_ptr adaptation_set2(new MockAdaptationSet(2)); - - std::unique_ptr representation1( - new MockRepresentation(1)); - std::unique_ptr representation2( - new MockRepresentation(2)); - std::unique_ptr representation3( - new MockRepresentation(3)); - - EXPECT_CALL(*mock_mpd_builder, AddPeriod()) - .WillOnce(Return(default_mock_period_.get())); - - EXPECT_CALL(*default_mock_period_, - GetOrCreateAdaptationSet(EqualsProto(valid_media_info1_), _)) - .WillOnce(Return(adaptation_set1.get())); - EXPECT_CALL(*adaptation_set1, - AddRepresentation(EqualsProto(valid_media_info1_))) - .WillOnce(Return(representation1.get())); - // Return the same adaptation set for |valid_media_info2_| and - // |valid_media_info3_|. This results in AddRepresentation to be called twice - // on |adaptation_set2|. - EXPECT_CALL(*default_mock_period_, - GetOrCreateAdaptationSet(AnyOf(EqualsProto(valid_media_info2_), - EqualsProto(valid_media_info3_)), - _)) - .WillOnce(Return(adaptation_set2.get())) - .WillOnce(Return(adaptation_set2.get())); - EXPECT_CALL(*adaptation_set2, - AddRepresentation(AnyOf(EqualsProto(valid_media_info2_), - EqualsProto(valid_media_info3_)))) - .WillOnce(Return(representation2.get())) - .WillOnce(Return(representation3.get())); - - uint32_t unused_container_id; - SetMpdBuilder(¬ifier, std::move(mock_mpd_builder)); - EXPECT_TRUE( - notifier.NotifyNewContainer(valid_media_info1_, &unused_container_id)); - EXPECT_TRUE( - notifier.NotifyNewContainer(valid_media_info2_, &unused_container_id)); - EXPECT_TRUE( - notifier.NotifyNewContainer(valid_media_info3_, &unused_container_id)); -} - -} // namespace shaka diff --git a/packager/mpd/base/mpd_notifier.h b/packager/mpd/base/mpd_notifier.h index a9328426bd..84569651df 100644 --- a/packager/mpd/base/mpd_notifier.h +++ b/packager/mpd/base/mpd_notifier.h @@ -85,16 +85,6 @@ class MpdNotifier { const std::vector& new_key_id, const std::vector& new_pssh) = 0; - /// Adds content protection information to the MPD. - /// @param container_id is the nummeric container ID obtained from calling - /// NotifyNewContainer(). - /// @param content_protection_element New ContentProtection element - /// specification. - /// @return true on success, false otherwise. - virtual bool AddContentProtectionElement( - uint32_t container_id, - const ContentProtectionElement& content_protection_element) = 0; - /// Call this method to force a flush. Implementations might not write out /// the MPD to a stream (file, stdout, etc.) when the MPD is updated, this /// forces a flush. diff --git a/packager/mpd/base/simple_mpd_notifier.cc b/packager/mpd/base/simple_mpd_notifier.cc index de40d91344..5a52f4c735 100644 --- a/packager/mpd/base/simple_mpd_notifier.cc +++ b/packager/mpd/base/simple_mpd_notifier.cc @@ -1,4 +1,4 @@ -// Copyright 2014 Google Inc. All rights reserved. +// Copyright 2015 Google Inc. 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 @@ -15,22 +15,19 @@ #include "packager/mpd/base/period.h" #include "packager/mpd/base/representation.h" -namespace { -const bool kContentProtectionInAdaptationSet = true; -} // namespace - namespace shaka { SimpleMpdNotifier::SimpleMpdNotifier(const MpdOptions& mpd_options) : MpdNotifier(mpd_options), output_path_(mpd_options.mpd_params.mpd_output), - mpd_builder_(new MpdBuilder(mpd_options)) { + mpd_builder_(new MpdBuilder(mpd_options)), + content_protection_in_adaptation_set_( + mpd_options.mpd_params.generate_dash_if_iop_compliant_mpd) { for (const std::string& base_url : mpd_options.mpd_params.base_urls) mpd_builder_->AddBaseUrl(base_url); } -SimpleMpdNotifier::~SimpleMpdNotifier() { -} +SimpleMpdNotifier::~SimpleMpdNotifier() {} bool SimpleMpdNotifier::Init() { return true; @@ -48,19 +45,25 @@ bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info, if (!period_) period_ = mpd_builder_->AddPeriod(); AdaptationSet* adaptation_set = period_->GetOrCreateAdaptationSet( - media_info, !kContentProtectionInAdaptationSet); + media_info, content_protection_in_adaptation_set_); DCHECK(adaptation_set); MediaInfo adjusted_media_info(media_info); MpdBuilder::MakePathsRelativeToMpd(output_path_, &adjusted_media_info); Representation* representation = adaptation_set->AddRepresentation(adjusted_media_info); - if (representation == NULL) + if (!representation) return false; - // For SimpleMpdNotifier, just put it in Representation. It should still - // generate a valid MPD. - AddContentProtectionElements(media_info, representation); + if (content_protection_in_adaptation_set_) { + // ContentProtection elements are already added to AdaptationSet above. + // Use RepresentationId to AdaptationSet map to update ContentProtection + // in AdaptationSet in NotifyEncryptionUpdate. + representation_id_to_adaptation_set_[representation->id()] = adaptation_set; + } else { + AddContentProtectionElements(media_info, representation); + } + *container_id = representation->id(); DCHECK(!ContainsKey(representation_map_, representation->id())); representation_map_[representation->id()] = representation; @@ -70,7 +73,7 @@ bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info, bool SimpleMpdNotifier::NotifySampleDuration(uint32_t container_id, uint32_t sample_duration) { base::AutoLock auto_lock(lock_); - RepresentationMap::iterator it = representation_map_.find(container_id); + auto it = representation_map_.find(container_id); if (it == representation_map_.end()) { LOG(ERROR) << "Unexpected container_id: " << container_id; return false; @@ -84,7 +87,7 @@ bool SimpleMpdNotifier::NotifyNewSegment(uint32_t container_id, uint64_t duration, uint64_t size) { base::AutoLock auto_lock(lock_); - RepresentationMap::iterator it = representation_map_.find(container_id); + auto it = representation_map_.find(container_id); if (it == representation_map_.end()) { LOG(ERROR) << "Unexpected container_id: " << container_id; return false; @@ -99,26 +102,21 @@ bool SimpleMpdNotifier::NotifyEncryptionUpdate( const std::vector& new_key_id, const std::vector& new_pssh) { base::AutoLock auto_lock(lock_); - RepresentationMap::iterator it = representation_map_.find(container_id); + auto it = representation_map_.find(container_id); if (it == representation_map_.end()) { LOG(ERROR) << "Unexpected container_id: " << container_id; return false; } - it->second->UpdateContentProtectionPssh(drm_uuid, - Uint8VectorToBase64(new_pssh)); - return true; -} -bool SimpleMpdNotifier::AddContentProtectionElement( - uint32_t container_id, - const ContentProtectionElement& content_protection_element) { - base::AutoLock auto_lock(lock_); - RepresentationMap::iterator it = representation_map_.find(container_id); - if (it == representation_map_.end()) { - LOG(ERROR) << "Unexpected container_id: " << container_id; - return false; + if (content_protection_in_adaptation_set_) { + AdaptationSet* adaptation_set_for_representation = + representation_id_to_adaptation_set_[it->second->id()]; + adaptation_set_for_representation->UpdateContentProtectionPssh( + drm_uuid, Uint8VectorToBase64(new_pssh)); + } else { + it->second->UpdateContentProtectionPssh(drm_uuid, + Uint8VectorToBase64(new_pssh)); } - it->second->AddContentProtectionElement(content_protection_element); return true; } diff --git a/packager/mpd/base/simple_mpd_notifier.h b/packager/mpd/base/simple_mpd_notifier.h index 906037342e..b7a7c05970 100644 --- a/packager/mpd/base/simple_mpd_notifier.h +++ b/packager/mpd/base/simple_mpd_notifier.h @@ -12,7 +12,6 @@ #include #include -#include "packager/base/gtest_prod_util.h" #include "packager/base/synchronization/lock.h" #include "packager/mpd/base/mpd_notifier.h" #include "packager/mpd/base/mpd_notifier_util.h" @@ -23,7 +22,6 @@ class AdaptationSet; class MpdBuilder; class Period; class Representation; -class SimpleMpdNotifierTest; struct MpdOptions; @@ -34,6 +32,7 @@ class SimpleMpdNotifier : public MpdNotifier { explicit SimpleMpdNotifier(const MpdOptions& mpd_options); ~SimpleMpdNotifier() override; + /// None of the methods write out the MPD file until Flush() is called. /// @name MpdNotifier implemetation overrides. /// @{ bool Init() override; @@ -48,19 +47,17 @@ class SimpleMpdNotifier : public MpdNotifier { const std::string& drm_uuid, const std::vector& new_key_id, const std::vector& new_pssh) override; - bool AddContentProtectionElement( - uint32_t id, - const ContentProtectionElement& content_protection_element) override; bool Flush() override; /// @} private: + SimpleMpdNotifier(const SimpleMpdNotifier&) = delete; + SimpleMpdNotifier& operator=(const SimpleMpdNotifier&) = delete; + friend class SimpleMpdNotifierTest; // Testing only method. Returns a pointer to MpdBuilder. - MpdBuilder* MpdBuilderForTesting() const { - return mpd_builder_.get(); - } + MpdBuilder* MpdBuilderForTesting() const { return mpd_builder_.get(); } // Testing only method. Sets mpd_builder_. void SetMpdBuilderForTesting(std::unique_ptr mpd_builder) { @@ -70,16 +67,14 @@ class SimpleMpdNotifier : public MpdNotifier { // MPD output path. std::string output_path_; std::unique_ptr mpd_builder_; - Period* period_ = nullptr; + Period* period_ = nullptr; // owned by |mpd_builder_|. + bool content_protection_in_adaptation_set_ = true; base::Lock lock_; - typedef std::map AdaptationSetMap; - AdaptationSetMap adaptation_set_map_; - - typedef std::map RepresentationMap; - RepresentationMap representation_map_; - - DISALLOW_COPY_AND_ASSIGN(SimpleMpdNotifier); + // Maps Representation ID to Representation. + std::map representation_map_; + // Maps Representation ID to AdaptationSet. This is for updating the PSSH. + std::map representation_id_to_adaptation_set_; }; } // namespace shaka diff --git a/packager/mpd/base/simple_mpd_notifier_unittest.cc b/packager/mpd/base/simple_mpd_notifier_unittest.cc index 7268541cda..a746e2735e 100644 --- a/packager/mpd/base/simple_mpd_notifier_unittest.cc +++ b/packager/mpd/base/simple_mpd_notifier_unittest.cc @@ -103,8 +103,7 @@ TEST_F(SimpleMpdNotifierTest, NotifyNewContainer) { EXPECT_CALL(*mock_mpd_builder, AddPeriod()) .WillOnce(Return(default_mock_period_.get())); EXPECT_CALL(*default_mock_period_, - GetOrCreateAdaptationSet(EqualsProto(valid_media_info1_), - Eq(!kContentProtectionInAdaptationSet))) + GetOrCreateAdaptationSet(EqualsProto(valid_media_info1_), _)) .WillOnce(Return(default_mock_adaptation_set_.get())); EXPECT_CALL(*default_mock_adaptation_set_, AddRepresentation(EqualsProto(valid_media_info1_))) @@ -157,7 +156,7 @@ TEST_F(SimpleMpdNotifierTest, NotifyNewContainerAndSampleDurationNoMock) { uint32_t container_id; EXPECT_TRUE(notifier.NotifyNewContainer(valid_media_info1_, &container_id)); const uint32_t kAnySampleDuration = 1000; - EXPECT_TRUE(notifier.NotifySampleDuration(container_id, kAnySampleDuration)); + EXPECT_TRUE(notifier.NotifySampleDuration(container_id, kAnySampleDuration)); EXPECT_TRUE(notifier.Flush()); } @@ -191,33 +190,13 @@ TEST_F(SimpleMpdNotifierTest, NotifyNewSegment) { kSegmentDuration, kSegmentSize)); } -TEST_F(SimpleMpdNotifierTest, AddContentProtectionElement) { - SimpleMpdNotifier notifier(empty_mpd_option_); +TEST_F(SimpleMpdNotifierTest, + ContentProtectionInAdaptationSetUpdateEncryption) { + MpdOptions mpd_options = empty_mpd_option_; + mpd_options.mpd_params.generate_dash_if_iop_compliant_mpd = + kContentProtectionInAdaptationSet; + SimpleMpdNotifier notifier(mpd_options); - const uint32_t kRepresentationId = 0u; - std::unique_ptr mock_mpd_builder(new MockMpdBuilder()); - std::unique_ptr mock_representation( - new MockRepresentation(kRepresentationId)); - - EXPECT_CALL(*mock_mpd_builder, AddPeriod()) - .WillOnce(Return(default_mock_period_.get())); - EXPECT_CALL(*default_mock_period_, GetOrCreateAdaptationSet(_, _)) - .WillOnce(Return(default_mock_adaptation_set_.get())); - EXPECT_CALL(*default_mock_adaptation_set_, AddRepresentation(_)) - .WillOnce(Return(mock_representation.get())); - - uint32_t container_id; - SetMpdBuilder(¬ifier, std::move(mock_mpd_builder)); - EXPECT_TRUE(notifier.NotifyNewContainer(valid_media_info1_, &container_id)); - EXPECT_EQ(kRepresentationId, container_id); - - ContentProtectionElement element; - EXPECT_CALL(*mock_representation, AddContentProtectionElement(_)); - EXPECT_TRUE(notifier.AddContentProtectionElement(kRepresentationId, element)); -} - -TEST_F(SimpleMpdNotifierTest, UpdateEncryption) { - SimpleMpdNotifier notifier(empty_mpd_option_); const uint32_t kRepresentationId = 447834u; std::unique_ptr mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr mock_representation( @@ -225,7 +204,52 @@ TEST_F(SimpleMpdNotifierTest, UpdateEncryption) { EXPECT_CALL(*mock_mpd_builder, AddPeriod()) .WillOnce(Return(default_mock_period_.get())); - EXPECT_CALL(*default_mock_period_, GetOrCreateAdaptationSet(_, _)) + EXPECT_CALL( + *default_mock_period_, + GetOrCreateAdaptationSet(_, Eq(kContentProtectionInAdaptationSet))) + .WillOnce(Return(default_mock_adaptation_set_.get())); + EXPECT_CALL(*default_mock_adaptation_set_, AddRepresentation(_)) + .WillOnce(Return(mock_representation.get())); + + uint32_t container_id; + SetMpdBuilder(¬ifier, std::move(mock_mpd_builder)); + EXPECT_TRUE(notifier.NotifyNewContainer(valid_media_info1_, &container_id)); + + ::testing::Mock::VerifyAndClearExpectations( + default_mock_adaptation_set_.get()); + + // "psshsomethingelse" as uint8 array. + const uint8_t kBogusNewPssh[] = {0x70, 0x73, 0x73, 0x68, 0x73, 0x6f, + 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, + 0x67, 0x65, 0x6c, 0x73, 0x65}; + const std::vector kBogusNewPsshVector( + kBogusNewPssh, kBogusNewPssh + arraysize(kBogusNewPssh)); + const char kBogusNewPsshInBase64[] = "cHNzaHNvbWV0aGluZ2Vsc2U="; + + EXPECT_CALL(*default_mock_adaptation_set_, + UpdateContentProtectionPssh(StrEq("myuuid"), + StrEq(kBogusNewPsshInBase64))); + EXPECT_TRUE(notifier.NotifyEncryptionUpdate( + container_id, "myuuid", std::vector(), kBogusNewPsshVector)); +} + +TEST_F(SimpleMpdNotifierTest, + ContentProtectionNotInAdaptationSetUpdateEncryption) { + MpdOptions mpd_options = empty_mpd_option_; + mpd_options.mpd_params.generate_dash_if_iop_compliant_mpd = + !kContentProtectionInAdaptationSet; + SimpleMpdNotifier notifier(mpd_options); + + const uint32_t kRepresentationId = 447834u; + std::unique_ptr mock_mpd_builder(new MockMpdBuilder()); + std::unique_ptr mock_representation( + new MockRepresentation(kRepresentationId)); + + EXPECT_CALL(*mock_mpd_builder, AddPeriod()) + .WillOnce(Return(default_mock_period_.get())); + EXPECT_CALL( + *default_mock_period_, + GetOrCreateAdaptationSet(_, Eq(!kContentProtectionInAdaptationSet))) .WillOnce(Return(default_mock_adaptation_set_.get())); EXPECT_CALL(*default_mock_adaptation_set_, AddRepresentation(_)) .WillOnce(Return(mock_representation.get())); diff --git a/packager/mpd/mpd.gyp b/packager/mpd/mpd.gyp index 9eb04ea12d..b5cd65a56d 100644 --- a/packager/mpd/mpd.gyp +++ b/packager/mpd/mpd.gyp @@ -33,8 +33,6 @@ 'base/bandwidth_estimator.h', 'base/content_protection_element.cc', 'base/content_protection_element.h', - 'base/dash_iop_mpd_notifier.cc', - 'base/dash_iop_mpd_notifier.h', 'base/mpd_builder.cc', 'base/mpd_builder.h', 'base/mpd_notifier_util.cc', @@ -88,7 +86,6 @@ 'sources': [ 'base/adaptation_set_unittest.cc', 'base/bandwidth_estimator_unittest.cc', - 'base/dash_iop_mpd_notifier_unittest.cc', 'base/mpd_builder_unittest.cc', 'base/period_unittest.cc', 'base/representation_unittest.cc', diff --git a/packager/mpd/util/mpd_writer.cc b/packager/mpd/util/mpd_writer.cc index cd1a83f7fd..26fd1ade2e 100644 --- a/packager/mpd/util/mpd_writer.cc +++ b/packager/mpd/util/mpd_writer.cc @@ -13,7 +13,6 @@ #include "packager/base/files/file_path.h" #include "packager/base/files/file_util.h" #include "packager/file/file.h" -#include "packager/mpd/base/dash_iop_mpd_notifier.h" #include "packager/mpd/base/mpd_builder.h" #include "packager/mpd/base/mpd_notifier.h" #include "packager/mpd/base/mpd_utils.h" @@ -29,17 +28,6 @@ namespace shaka { namespace { -// Factory that creates DashIopMpdNotifier instances. -class DashIopMpdNotifierFactory : public MpdNotifierFactory { - public: - DashIopMpdNotifierFactory() {} - ~DashIopMpdNotifierFactory() override {} - - std::unique_ptr Create(const MpdOptions& mpd_options) override { - return std::unique_ptr(new DashIopMpdNotifier(mpd_options)); - } -}; - // Factory that creates SimpleMpdNotifier instances. class SimpleMpdNotifierFactory : public MpdNotifierFactory { public: @@ -53,12 +41,7 @@ class SimpleMpdNotifierFactory : public MpdNotifierFactory { } // namespace -MpdWriter::MpdWriter() - : notifier_factory_(FLAGS_generate_dash_if_iop_compliant_mpd - ? static_cast( - new DashIopMpdNotifierFactory()) - : static_cast( - new SimpleMpdNotifierFactory())) {} +MpdWriter::MpdWriter() : notifier_factory_(new SimpleMpdNotifierFactory()) {} MpdWriter::~MpdWriter() {} bool MpdWriter::AddFile(const std::string& media_info_path, @@ -90,6 +73,8 @@ bool MpdWriter::WriteMpdToFile(const char* file_name) { MpdOptions mpd_options; mpd_options.mpd_params.base_urls = base_urls_; mpd_options.mpd_params.mpd_output = file_name; + mpd_options.mpd_params.generate_dash_if_iop_compliant_mpd = + FLAGS_generate_dash_if_iop_compliant_mpd; std::unique_ptr notifier = notifier_factory_->Create(mpd_options); if (!notifier->Init()) { diff --git a/packager/mpd/util/mpd_writer_unittest.cc b/packager/mpd/util/mpd_writer_unittest.cc index 49a47baf2d..ff1910a66b 100644 --- a/packager/mpd/util/mpd_writer_unittest.cc +++ b/packager/mpd/util/mpd_writer_unittest.cc @@ -9,7 +9,6 @@ #include "packager/base/files/file_util.h" #include "packager/base/path_service.h" -#include "packager/mpd/base/dash_iop_mpd_notifier.h" #include "packager/mpd/base/mock_mpd_notifier.h" #include "packager/mpd/base/mpd_options.h" #include "packager/mpd/test/mpd_builder_test_helper.h" diff --git a/packager/packager.cc b/packager/packager.cc index e6f3ea3bce..110b073d9a 100644 --- a/packager/packager.cc +++ b/packager/packager.cc @@ -41,7 +41,6 @@ #include "packager/media/formats/webm/webm_muxer.h" #include "packager/media/replicator/replicator.h" #include "packager/media/trick_play/trick_play_handler.h" -#include "packager/mpd/base/dash_iop_mpd_notifier.h" #include "packager/mpd/base/media_info.pb.h" #include "packager/mpd/base/mpd_builder.h" #include "packager/mpd/base/simple_mpd_notifier.h" @@ -702,13 +701,9 @@ Status Packager::Initialize( if (!mpd_params.mpd_output.empty()) { const bool on_demand_dash_profile = stream_descriptors.begin()->segment_template.empty(); - MpdOptions mpd_options = + const MpdOptions mpd_options = media::GetMpdOptions(on_demand_dash_profile, mpd_params); - if (mpd_params.generate_dash_if_iop_compliant_mpd) { - internal->mpd_notifier.reset(new DashIopMpdNotifier(mpd_options)); - } else { - internal->mpd_notifier.reset(new SimpleMpdNotifier(mpd_options)); - } + internal->mpd_notifier.reset(new SimpleMpdNotifier(mpd_options)); if (!internal->mpd_notifier->Init()) { LOG(ERROR) << "MpdNotifier failed to initialize."; return Status(error::INVALID_ARGUMENT,