Merge SimpleMpdNotifier and DashIopMpdNotifier

Also removed MpdNotifier::AddContentProtectionElement which is not
used anywhere.

Change-Id: I69eb596ec377c601bb3e45bbef30c248c1d03e86
This commit is contained in:
KongQun Yang 2017-12-19 12:02:28 -08:00
parent 82842407cb
commit 66f713fd23
11 changed files with 97 additions and 578 deletions

View File

@ -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<uint8_t>& new_key_id,
const std::vector<uint8_t>& 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
// <ContentProtection> 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

View File

@ -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 <map>
#include <string>
#include <vector>
#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 <ContentProtection> elements must be right under
/// <AdaptationSet> and cannot be under <Representation>.
/// 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<uint8_t>& new_key_id,
const std::vector<uint8_t>& 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<MpdBuilder> mpd_builder) {
mpd_builder_ = std::move(mpd_builder);
}
// MPD output path.
std::string output_path_;
std::unique_ptr<MpdBuilder> mpd_builder_;
Period* period_ = nullptr; // owned by |mpd_builder_|.
base::Lock lock_;
// Maps representation ID to Representation.
std::map<uint32_t, Representation*> representation_map_;
// Maps Representation ID to AdaptationSet. This is for updating the PSSH.
std::map<uint32_t, AdaptationSet*> representation_id_to_adaptation_set_;
};
} // namespace shaka
#endif // MPD_BASE_DASH_IOP_MPD_NOTIFIER_H_

View File

@ -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 <gmock/gmock.h>
#include <google/protobuf/util/message_differencer.h>
#include <gtest/gtest.h>
#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<MpdBuilder> 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<MockPeriod> default_mock_period_;
std::unique_ptr<MockAdaptationSet> default_mock_adaptation_set_;
std::unique_ptr<MockRepresentation> 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<MockMpdBuilder> 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(&notifier, 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<MockMpdBuilder> 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(&notifier, 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<MockMpdBuilder> 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(&notifier, 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<uint8_t> 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<uint8_t>(), 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<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
std::unique_ptr<MockAdaptationSet> adaptation_set1(new MockAdaptationSet(1));
std::unique_ptr<MockAdaptationSet> adaptation_set2(new MockAdaptationSet(2));
std::unique_ptr<MockRepresentation> representation1(
new MockRepresentation(1));
std::unique_ptr<MockRepresentation> representation2(
new MockRepresentation(2));
std::unique_ptr<MockRepresentation> 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(&notifier, 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

View File

@ -85,16 +85,6 @@ class MpdNotifier {
const std::vector<uint8_t>& new_key_id, const std::vector<uint8_t>& new_key_id,
const std::vector<uint8_t>& new_pssh) = 0; const std::vector<uint8_t>& 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 /// 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 /// the MPD to a stream (file, stdout, etc.) when the MPD is updated, this
/// forces a flush. /// forces a flush.

View File

@ -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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at // 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/period.h"
#include "packager/mpd/base/representation.h" #include "packager/mpd/base/representation.h"
namespace {
const bool kContentProtectionInAdaptationSet = true;
} // namespace
namespace shaka { namespace shaka {
SimpleMpdNotifier::SimpleMpdNotifier(const MpdOptions& mpd_options) SimpleMpdNotifier::SimpleMpdNotifier(const MpdOptions& mpd_options)
: MpdNotifier(mpd_options), : MpdNotifier(mpd_options),
output_path_(mpd_options.mpd_params.mpd_output), 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) for (const std::string& base_url : mpd_options.mpd_params.base_urls)
mpd_builder_->AddBaseUrl(base_url); mpd_builder_->AddBaseUrl(base_url);
} }
SimpleMpdNotifier::~SimpleMpdNotifier() { SimpleMpdNotifier::~SimpleMpdNotifier() {}
}
bool SimpleMpdNotifier::Init() { bool SimpleMpdNotifier::Init() {
return true; return true;
@ -48,19 +45,25 @@ bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info,
if (!period_) if (!period_)
period_ = mpd_builder_->AddPeriod(); period_ = mpd_builder_->AddPeriod();
AdaptationSet* adaptation_set = period_->GetOrCreateAdaptationSet( AdaptationSet* adaptation_set = period_->GetOrCreateAdaptationSet(
media_info, !kContentProtectionInAdaptationSet); media_info, content_protection_in_adaptation_set_);
DCHECK(adaptation_set); DCHECK(adaptation_set);
MediaInfo adjusted_media_info(media_info); MediaInfo adjusted_media_info(media_info);
MpdBuilder::MakePathsRelativeToMpd(output_path_, &adjusted_media_info); MpdBuilder::MakePathsRelativeToMpd(output_path_, &adjusted_media_info);
Representation* representation = Representation* representation =
adaptation_set->AddRepresentation(adjusted_media_info); adaptation_set->AddRepresentation(adjusted_media_info);
if (representation == NULL) if (!representation)
return false; return false;
// For SimpleMpdNotifier, just put it in Representation. It should still if (content_protection_in_adaptation_set_) {
// generate a valid MPD. // 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); AddContentProtectionElements(media_info, representation);
}
*container_id = representation->id(); *container_id = representation->id();
DCHECK(!ContainsKey(representation_map_, representation->id())); DCHECK(!ContainsKey(representation_map_, representation->id()));
representation_map_[representation->id()] = representation; representation_map_[representation->id()] = representation;
@ -70,7 +73,7 @@ bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info,
bool SimpleMpdNotifier::NotifySampleDuration(uint32_t container_id, bool SimpleMpdNotifier::NotifySampleDuration(uint32_t container_id,
uint32_t sample_duration) { uint32_t sample_duration) {
base::AutoLock auto_lock(lock_); 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()) { if (it == representation_map_.end()) {
LOG(ERROR) << "Unexpected container_id: " << container_id; LOG(ERROR) << "Unexpected container_id: " << container_id;
return false; return false;
@ -84,7 +87,7 @@ bool SimpleMpdNotifier::NotifyNewSegment(uint32_t container_id,
uint64_t duration, uint64_t duration,
uint64_t size) { uint64_t size) {
base::AutoLock auto_lock(lock_); 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()) { if (it == representation_map_.end()) {
LOG(ERROR) << "Unexpected container_id: " << container_id; LOG(ERROR) << "Unexpected container_id: " << container_id;
return false; return false;
@ -99,26 +102,21 @@ bool SimpleMpdNotifier::NotifyEncryptionUpdate(
const std::vector<uint8_t>& new_key_id, const std::vector<uint8_t>& new_key_id,
const std::vector<uint8_t>& new_pssh) { const std::vector<uint8_t>& new_pssh) {
base::AutoLock auto_lock(lock_); 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()) { if (it == representation_map_.end()) {
LOG(ERROR) << "Unexpected container_id: " << container_id; LOG(ERROR) << "Unexpected container_id: " << container_id;
return false; 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, it->second->UpdateContentProtectionPssh(drm_uuid,
Uint8VectorToBase64(new_pssh)); 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;
} }
it->second->AddContentProtectionElement(content_protection_element);
return true; return true;
} }

View File

@ -12,7 +12,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "packager/base/gtest_prod_util.h"
#include "packager/base/synchronization/lock.h" #include "packager/base/synchronization/lock.h"
#include "packager/mpd/base/mpd_notifier.h" #include "packager/mpd/base/mpd_notifier.h"
#include "packager/mpd/base/mpd_notifier_util.h" #include "packager/mpd/base/mpd_notifier_util.h"
@ -23,7 +22,6 @@ class AdaptationSet;
class MpdBuilder; class MpdBuilder;
class Period; class Period;
class Representation; class Representation;
class SimpleMpdNotifierTest;
struct MpdOptions; struct MpdOptions;
@ -34,6 +32,7 @@ class SimpleMpdNotifier : public MpdNotifier {
explicit SimpleMpdNotifier(const MpdOptions& mpd_options); explicit SimpleMpdNotifier(const MpdOptions& mpd_options);
~SimpleMpdNotifier() override; ~SimpleMpdNotifier() override;
/// None of the methods write out the MPD file until Flush() is called.
/// @name MpdNotifier implemetation overrides. /// @name MpdNotifier implemetation overrides.
/// @{ /// @{
bool Init() override; bool Init() override;
@ -48,19 +47,17 @@ class SimpleMpdNotifier : public MpdNotifier {
const std::string& drm_uuid, const std::string& drm_uuid,
const std::vector<uint8_t>& new_key_id, const std::vector<uint8_t>& new_key_id,
const std::vector<uint8_t>& new_pssh) override; const std::vector<uint8_t>& new_pssh) override;
bool AddContentProtectionElement(
uint32_t id,
const ContentProtectionElement& content_protection_element) override;
bool Flush() override; bool Flush() override;
/// @} /// @}
private: private:
SimpleMpdNotifier(const SimpleMpdNotifier&) = delete;
SimpleMpdNotifier& operator=(const SimpleMpdNotifier&) = delete;
friend class SimpleMpdNotifierTest; friend class SimpleMpdNotifierTest;
// Testing only method. Returns a pointer to MpdBuilder. // Testing only method. Returns a pointer to MpdBuilder.
MpdBuilder* MpdBuilderForTesting() const { MpdBuilder* MpdBuilderForTesting() const { return mpd_builder_.get(); }
return mpd_builder_.get();
}
// Testing only method. Sets mpd_builder_. // Testing only method. Sets mpd_builder_.
void SetMpdBuilderForTesting(std::unique_ptr<MpdBuilder> mpd_builder) { void SetMpdBuilderForTesting(std::unique_ptr<MpdBuilder> mpd_builder) {
@ -70,16 +67,14 @@ class SimpleMpdNotifier : public MpdNotifier {
// MPD output path. // MPD output path.
std::string output_path_; std::string output_path_;
std::unique_ptr<MpdBuilder> mpd_builder_; std::unique_ptr<MpdBuilder> mpd_builder_;
Period* period_ = nullptr; Period* period_ = nullptr; // owned by |mpd_builder_|.
bool content_protection_in_adaptation_set_ = true;
base::Lock lock_; base::Lock lock_;
typedef std::map<std::string, AdaptationSet*> AdaptationSetMap; // Maps Representation ID to Representation.
AdaptationSetMap adaptation_set_map_; std::map<uint32_t, Representation*> representation_map_;
// Maps Representation ID to AdaptationSet. This is for updating the PSSH.
typedef std::map<uint32_t, Representation*> RepresentationMap; std::map<uint32_t, AdaptationSet*> representation_id_to_adaptation_set_;
RepresentationMap representation_map_;
DISALLOW_COPY_AND_ASSIGN(SimpleMpdNotifier);
}; };
} // namespace shaka } // namespace shaka

View File

@ -103,8 +103,7 @@ TEST_F(SimpleMpdNotifierTest, NotifyNewContainer) {
EXPECT_CALL(*mock_mpd_builder, AddPeriod()) EXPECT_CALL(*mock_mpd_builder, AddPeriod())
.WillOnce(Return(default_mock_period_.get())); .WillOnce(Return(default_mock_period_.get()));
EXPECT_CALL(*default_mock_period_, EXPECT_CALL(*default_mock_period_,
GetOrCreateAdaptationSet(EqualsProto(valid_media_info1_), GetOrCreateAdaptationSet(EqualsProto(valid_media_info1_), _))
Eq(!kContentProtectionInAdaptationSet)))
.WillOnce(Return(default_mock_adaptation_set_.get())); .WillOnce(Return(default_mock_adaptation_set_.get()));
EXPECT_CALL(*default_mock_adaptation_set_, EXPECT_CALL(*default_mock_adaptation_set_,
AddRepresentation(EqualsProto(valid_media_info1_))) AddRepresentation(EqualsProto(valid_media_info1_)))
@ -191,33 +190,13 @@ TEST_F(SimpleMpdNotifierTest, NotifyNewSegment) {
kSegmentDuration, kSegmentSize)); kSegmentDuration, kSegmentSize));
} }
TEST_F(SimpleMpdNotifierTest, AddContentProtectionElement) { TEST_F(SimpleMpdNotifierTest,
SimpleMpdNotifier notifier(empty_mpd_option_); 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<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
std::unique_ptr<MockRepresentation> 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(&notifier, 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; const uint32_t kRepresentationId = 447834u;
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
std::unique_ptr<MockRepresentation> mock_representation( std::unique_ptr<MockRepresentation> mock_representation(
@ -225,7 +204,52 @@ TEST_F(SimpleMpdNotifierTest, UpdateEncryption) {
EXPECT_CALL(*mock_mpd_builder, AddPeriod()) EXPECT_CALL(*mock_mpd_builder, AddPeriod())
.WillOnce(Return(default_mock_period_.get())); .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(&notifier, 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<uint8_t> 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<uint8_t>(), 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<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
std::unique_ptr<MockRepresentation> 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())); .WillOnce(Return(default_mock_adaptation_set_.get()));
EXPECT_CALL(*default_mock_adaptation_set_, AddRepresentation(_)) EXPECT_CALL(*default_mock_adaptation_set_, AddRepresentation(_))
.WillOnce(Return(mock_representation.get())); .WillOnce(Return(mock_representation.get()));

View File

@ -33,8 +33,6 @@
'base/bandwidth_estimator.h', 'base/bandwidth_estimator.h',
'base/content_protection_element.cc', 'base/content_protection_element.cc',
'base/content_protection_element.h', 'base/content_protection_element.h',
'base/dash_iop_mpd_notifier.cc',
'base/dash_iop_mpd_notifier.h',
'base/mpd_builder.cc', 'base/mpd_builder.cc',
'base/mpd_builder.h', 'base/mpd_builder.h',
'base/mpd_notifier_util.cc', 'base/mpd_notifier_util.cc',
@ -88,7 +86,6 @@
'sources': [ 'sources': [
'base/adaptation_set_unittest.cc', 'base/adaptation_set_unittest.cc',
'base/bandwidth_estimator_unittest.cc', 'base/bandwidth_estimator_unittest.cc',
'base/dash_iop_mpd_notifier_unittest.cc',
'base/mpd_builder_unittest.cc', 'base/mpd_builder_unittest.cc',
'base/period_unittest.cc', 'base/period_unittest.cc',
'base/representation_unittest.cc', 'base/representation_unittest.cc',

View File

@ -13,7 +13,6 @@
#include "packager/base/files/file_path.h" #include "packager/base/files/file_path.h"
#include "packager/base/files/file_util.h" #include "packager/base/files/file_util.h"
#include "packager/file/file.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_builder.h"
#include "packager/mpd/base/mpd_notifier.h" #include "packager/mpd/base/mpd_notifier.h"
#include "packager/mpd/base/mpd_utils.h" #include "packager/mpd/base/mpd_utils.h"
@ -29,17 +28,6 @@ namespace shaka {
namespace { namespace {
// Factory that creates DashIopMpdNotifier instances.
class DashIopMpdNotifierFactory : public MpdNotifierFactory {
public:
DashIopMpdNotifierFactory() {}
~DashIopMpdNotifierFactory() override {}
std::unique_ptr<MpdNotifier> Create(const MpdOptions& mpd_options) override {
return std::unique_ptr<MpdNotifier>(new DashIopMpdNotifier(mpd_options));
}
};
// Factory that creates SimpleMpdNotifier instances. // Factory that creates SimpleMpdNotifier instances.
class SimpleMpdNotifierFactory : public MpdNotifierFactory { class SimpleMpdNotifierFactory : public MpdNotifierFactory {
public: public:
@ -53,12 +41,7 @@ class SimpleMpdNotifierFactory : public MpdNotifierFactory {
} // namespace } // namespace
MpdWriter::MpdWriter() MpdWriter::MpdWriter() : notifier_factory_(new SimpleMpdNotifierFactory()) {}
: notifier_factory_(FLAGS_generate_dash_if_iop_compliant_mpd
? static_cast<MpdNotifierFactory*>(
new DashIopMpdNotifierFactory())
: static_cast<MpdNotifierFactory*>(
new SimpleMpdNotifierFactory())) {}
MpdWriter::~MpdWriter() {} MpdWriter::~MpdWriter() {}
bool MpdWriter::AddFile(const std::string& media_info_path, bool MpdWriter::AddFile(const std::string& media_info_path,
@ -90,6 +73,8 @@ bool MpdWriter::WriteMpdToFile(const char* file_name) {
MpdOptions mpd_options; MpdOptions mpd_options;
mpd_options.mpd_params.base_urls = base_urls_; mpd_options.mpd_params.base_urls = base_urls_;
mpd_options.mpd_params.mpd_output = file_name; 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<MpdNotifier> notifier = std::unique_ptr<MpdNotifier> notifier =
notifier_factory_->Create(mpd_options); notifier_factory_->Create(mpd_options);
if (!notifier->Init()) { if (!notifier->Init()) {

View File

@ -9,7 +9,6 @@
#include "packager/base/files/file_util.h" #include "packager/base/files/file_util.h"
#include "packager/base/path_service.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/mock_mpd_notifier.h"
#include "packager/mpd/base/mpd_options.h" #include "packager/mpd/base/mpd_options.h"
#include "packager/mpd/test/mpd_builder_test_helper.h" #include "packager/mpd/test/mpd_builder_test_helper.h"

View File

@ -41,7 +41,6 @@
#include "packager/media/formats/webm/webm_muxer.h" #include "packager/media/formats/webm/webm_muxer.h"
#include "packager/media/replicator/replicator.h" #include "packager/media/replicator/replicator.h"
#include "packager/media/trick_play/trick_play_handler.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/media_info.pb.h"
#include "packager/mpd/base/mpd_builder.h" #include "packager/mpd/base/mpd_builder.h"
#include "packager/mpd/base/simple_mpd_notifier.h" #include "packager/mpd/base/simple_mpd_notifier.h"
@ -702,13 +701,9 @@ Status Packager::Initialize(
if (!mpd_params.mpd_output.empty()) { if (!mpd_params.mpd_output.empty()) {
const bool on_demand_dash_profile = const bool on_demand_dash_profile =
stream_descriptors.begin()->segment_template.empty(); stream_descriptors.begin()->segment_template.empty();
MpdOptions mpd_options = const MpdOptions mpd_options =
media::GetMpdOptions(on_demand_dash_profile, mpd_params); 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()) { if (!internal->mpd_notifier->Init()) {
LOG(ERROR) << "MpdNotifier failed to initialize."; LOG(ERROR) << "MpdNotifier failed to initialize.";
return Status(error::INVALID_ARGUMENT, return Status(error::INVALID_ARGUMENT,