Consolidate MpdParams into MpdOptions

Change-Id: I7f37277ef87597548c2fbf219963cd8725ae4c05
This commit is contained in:
KongQun Yang 2017-07-27 11:49:50 -07:00
parent 4e82ab13bd
commit 556ff56559
18 changed files with 143 additions and 163 deletions

View File

@ -26,8 +26,6 @@ namespace shaka {
namespace media { namespace media {
namespace { namespace {
} // namespace
std::unique_ptr<RequestSigner> CreateSigner(const WidevineSigner& signer) { std::unique_ptr<RequestSigner> CreateSigner(const WidevineSigner& signer) {
std::unique_ptr<RequestSigner> request_signer; std::unique_ptr<RequestSigner> request_signer;
switch (signer.signing_key_type) { switch (signer.signing_key_type) {
@ -47,6 +45,8 @@ std::unique_ptr<RequestSigner> CreateSigner(const WidevineSigner& signer) {
return request_signer; return request_signer;
} }
} // namespace
std::unique_ptr<KeySource> CreateEncryptionKeySource( std::unique_ptr<KeySource> CreateEncryptionKeySource(
FourCC protection_scheme, FourCC protection_scheme,
const EncryptionParams& encryption_params) { const EncryptionParams& encryption_params) {
@ -179,12 +179,7 @@ MpdOptions GetMpdOptions(bool on_demand_profile, const MpdParams& mpd_params) {
(on_demand_profile || mpd_params.generate_static_live_mpd) (on_demand_profile || mpd_params.generate_static_live_mpd)
? MpdType::kStatic ? MpdType::kStatic
: MpdType::kDynamic; : MpdType::kDynamic;
mpd_options.minimum_update_period = mpd_params.minimum_update_period; mpd_options.mpd_params = mpd_params;
mpd_options.min_buffer_time = mpd_params.min_buffer_time;
mpd_options.time_shift_buffer_depth = mpd_params.time_shift_buffer_depth;
mpd_options.suggested_presentation_delay =
mpd_params.suggested_presentation_delay;
mpd_options.default_language = mpd_params.default_language;
return mpd_options; return mpd_options;
} }

View File

@ -10,18 +10,15 @@
#define PACKAGER_APP_PACKAGER_UTIL_H_ #define PACKAGER_APP_PACKAGER_UTIL_H_
#include <memory> #include <memory>
#include <vector>
#include "packager/base/optional.h"
#include "packager/media/base/fourccs.h" #include "packager/media/base/fourccs.h"
#include "packager/packager.h"
namespace shaka { namespace shaka {
// TODO(kqyang): Should we consolidate XxxParams and XxxOptions? class Status;
struct ChunkingParams;
struct DecryptionParams; struct DecryptionParams;
struct EncryptionParams; struct EncryptionParams;
struct Mp4OutputParams;
struct MpdOptions; struct MpdOptions;
struct MpdParams; struct MpdParams;
@ -29,12 +26,9 @@ namespace media {
class MediaHandler; class MediaHandler;
class KeySource; class KeySource;
struct ChunkingOptions;
struct EncryptionOptions;
struct MuxerOptions;
/// Create KeySource based on provided command line options for content /// Create KeySource based on provided params for content encryption. Also
/// encryption. Also fetches keys. /// fetches keys.
/// @param protection_scheme specifies the protection scheme to be used for /// @param protection_scheme specifies the protection scheme to be used for
/// encryption. /// encryption.
/// @return A std::unique_ptr containing a new KeySource, or nullptr if /// @return A std::unique_ptr containing a new KeySource, or nullptr if
@ -43,14 +37,14 @@ std::unique_ptr<KeySource> CreateEncryptionKeySource(
FourCC protection_scheme, FourCC protection_scheme,
const EncryptionParams& encryption_params); const EncryptionParams& encryption_params);
/// Create KeySource based on provided command line options for content /// Create KeySource based on provided params for content decryption. Does not
/// decryption. Does not fetch keys. /// fetch keys.
/// @return A std::unique_ptr containing a new KeySource, or nullptr if /// @return A std::unique_ptr containing a new KeySource, or nullptr if
/// decryption is not required. /// decryption is not required.
std::unique_ptr<KeySource> CreateDecryptionKeySource( std::unique_ptr<KeySource> CreateDecryptionKeySource(
const DecryptionParams& decryption_params); const DecryptionParams& decryption_params);
/// @return MpdOptions from provided command line options. /// @return MpdOptions from provided inputs.
MpdOptions GetMpdOptions(bool on_demand_profile, const MpdParams& mpd_params); MpdOptions GetMpdOptions(bool on_demand_profile, const MpdParams& mpd_params);
/// Connect handlers in the vector. /// Connect handlers in the vector.

View File

@ -38,15 +38,12 @@ std::set<std::string> GetUUIDs(
} // namespace } // namespace
DashIopMpdNotifier::DashIopMpdNotifier( DashIopMpdNotifier::DashIopMpdNotifier(const MpdOptions& mpd_options)
const MpdOptions& mpd_options,
const std::vector<std::string>& base_urls,
const std::string& output_path)
: MpdNotifier(mpd_options), : MpdNotifier(mpd_options),
output_path_(output_path), output_path_(mpd_options.mpd_params.mpd_output),
mpd_builder_(new MpdBuilder(mpd_options)) { mpd_builder_(new MpdBuilder(mpd_options)) {
for (size_t i = 0; i < base_urls.size(); ++i) for (const std::string& base_url : mpd_options.mpd_params.base_urls)
mpd_builder_->AddBaseUrl(base_urls[i]); mpd_builder_->AddBaseUrl(base_url);
} }
DashIopMpdNotifier::~DashIopMpdNotifier() {} DashIopMpdNotifier::~DashIopMpdNotifier() {}

View File

@ -29,9 +29,7 @@ namespace shaka {
/// All video Adaptation Sets have Role set to "main". /// All video Adaptation Sets have Role set to "main".
class DashIopMpdNotifier : public MpdNotifier { class DashIopMpdNotifier : public MpdNotifier {
public: public:
DashIopMpdNotifier(const MpdOptions& mpd_options, explicit DashIopMpdNotifier(const MpdOptions& mpd_options);
const std::vector<std::string>& base_urls,
const std::string& output_path);
~DashIopMpdNotifier() override; ~DashIopMpdNotifier() override;
/// None of the methods write out the MPD file until Flush() is called. /// None of the methods write out the MPD file until Flush() is called.

View File

@ -101,7 +101,7 @@ class DashIopMpdNotifierTest : public ::testing::Test {
void SetUp() override { void SetUp() override {
ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_)); ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_));
output_path_ = temp_file_path_.AsUTF8Unsafe(); empty_mpd_option_.mpd_params.mpd_output = temp_file_path_.AsUTF8Unsafe();
} }
void TearDown() override { void TearDown() override {
@ -113,11 +113,9 @@ class DashIopMpdNotifierTest : public ::testing::Test {
notifier->SetMpdBuilderForTesting(std::move(mpd_builder)); notifier->SetMpdBuilderForTesting(std::move(mpd_builder));
} }
// Use output_path_ for specifying the MPD output path so that // Empty mpd options except with output path specified, so that
// WriteMpdToFile() doesn't crash. // WriteMpdToFile() doesn't crash.
std::string output_path_; MpdOptions empty_mpd_option_;
const MpdOptions empty_mpd_option_;
const std::vector<std::string> empty_base_urls_;
// Default mocks that can be used for the tests. // Default mocks that can be used for the tests.
// IOW, if a test only requires one instance of // IOW, if a test only requires one instance of
@ -132,8 +130,7 @@ class DashIopMpdNotifierTest : public ::testing::Test {
// Verify that basic VOD NotifyNewContainer() operation works. // Verify that basic VOD NotifyNewContainer() operation works.
// No encrypted contents. // No encrypted contents.
TEST_F(DashIopMpdNotifierTest, NotifyNewContainer) { TEST_F(DashIopMpdNotifierTest, NotifyNewContainer) {
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
@ -170,8 +167,7 @@ TEST_F(DashIopMpdNotifierTest, NotifyNewContainerForTrickPlay) {
" playback_rate: 10\n" " playback_rate: 10\n"
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
@ -228,8 +224,7 @@ TEST_F(DashIopMpdNotifierTest, NotifyNewTextContainer) {
" language: 'en'\n" " language: 'en'\n"
"}\n" "}\n"
"container_type: CONTAINER_TEXT\n"; "container_type: CONTAINER_TEXT\n";
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
@ -257,8 +252,7 @@ TEST_F(DashIopMpdNotifierTest, NotifyNewTextContainer) {
// AdaptationSets with different DRM won't be switchable. // AdaptationSets with different DRM won't be switchable.
TEST_F(DashIopMpdNotifierTest, TEST_F(DashIopMpdNotifierTest,
NotifyNewContainersWithDifferentProtectedContent) { NotifyNewContainersWithDifferentProtectedContent) {
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
// Note they both have different (bogus) pssh, like real use case. // Note they both have different (bogus) pssh, like real use case.
@ -375,8 +369,7 @@ TEST_F(DashIopMpdNotifierTest,
// MediaInfo::ProtectedContent. Only one AdaptationSet should be // MediaInfo::ProtectedContent. Only one AdaptationSet should be
// created. // created.
TEST_F(DashIopMpdNotifierTest, NotifyNewContainersWithSameProtectedContent) { TEST_F(DashIopMpdNotifierTest, NotifyNewContainersWithSameProtectedContent) {
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
// These have the same default key ID and PSSH. // These have the same default key ID and PSSH.
@ -477,8 +470,7 @@ TEST_F(DashIopMpdNotifierTest, NotifyNewContainersWithSameProtectedContent) {
// AddContentProtection() should not work and should always return false. // AddContentProtection() should not work and should always return false.
TEST_F(DashIopMpdNotifierTest, AddContentProtection) { TEST_F(DashIopMpdNotifierTest, AddContentProtection) {
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
@ -508,8 +500,7 @@ TEST_F(DashIopMpdNotifierTest, AddContentProtection) {
// 3. Add a 4k protected content. This should also make a new AdaptationSet. // 3. Add a 4k protected content. This should also make a new AdaptationSet.
// It should be switchable with SD/HD AdaptationSet. // It should be switchable with SD/HD AdaptationSet.
TEST_F(DashIopMpdNotifierTest, SetAdaptationSetSwitching) { TEST_F(DashIopMpdNotifierTest, SetAdaptationSetSwitching) {
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
// These have the same default key ID and PSSH. // These have the same default key ID and PSSH.
@ -645,8 +636,7 @@ TEST_F(DashIopMpdNotifierTest, SetAdaptationSetSwitching) {
// switchable. // switchable.
TEST_F(DashIopMpdNotifierTest, TEST_F(DashIopMpdNotifierTest,
DoNotSetAdaptationSetSwitchingIfContentTypesDifferent) { DoNotSetAdaptationSetSwitchingIfContentTypesDifferent) {
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
// These have the same default key ID and PSSH. // These have the same default key ID and PSSH.
@ -752,8 +742,7 @@ TEST_F(DashIopMpdNotifierTest, UpdateEncryption) {
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
@ -792,8 +781,7 @@ TEST_F(DashIopMpdNotifierTest, UpdateEncryption) {
// This issue identified a bug where using SimpleMpdNotifier with multiple // This issue identified a bug where using SimpleMpdNotifier with multiple
// threads causes a deadlock. This tests with DashIopMpdNotifier. // threads causes a deadlock. This tests with DashIopMpdNotifier.
TEST_F(DashIopMpdNotifierTest, NotifyNewContainerAndSampleDurationNoMock) { TEST_F(DashIopMpdNotifierTest, NotifyNewContainerAndSampleDurationNoMock) {
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
uint32_t container_id; uint32_t container_id;
EXPECT_TRUE(notifier.NotifyNewContainer(ConvertToMediaInfo(kValidMediaInfo), EXPECT_TRUE(notifier.NotifyNewContainer(ConvertToMediaInfo(kValidMediaInfo),
&container_id)); &container_id));
@ -856,8 +844,7 @@ TEST_F(DashIopMpdNotifierTest, SplitAdaptationSetsByLanguageAndCodec) {
"container_type: CONTAINER_WEBM\n" "container_type: CONTAINER_WEBM\n"
"media_duration_seconds: 10.5\n"; "media_duration_seconds: 10.5\n";
DashIopMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, DashIopMpdNotifier notifier(empty_mpd_option_);
output_path_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
std::unique_ptr<MockAdaptationSet> adaptation_set1(new MockAdaptationSet(1)); std::unique_ptr<MockAdaptationSet> adaptation_set1(new MockAdaptationSet(1));

View File

@ -385,7 +385,7 @@ AdaptationSet* MpdBuilder::AddAdaptationSet(const std::string& lang) {
&representation_counter_)); &representation_counter_));
DCHECK(adaptation_set); DCHECK(adaptation_set);
if (!lang.empty() && lang == mpd_options_.default_language) { if (!lang.empty() && lang == mpd_options_.mpd_params.default_language) {
adaptation_set->AddRole(AdaptationSet::kRoleMain); adaptation_set->AddRole(AdaptationSet::kRoleMain);
} }
@ -503,9 +503,10 @@ xmlDocPtr MpdBuilder::GenerateMpd() {
} }
void MpdBuilder::AddCommonMpdInfo(XmlNode* mpd_node) { void MpdBuilder::AddCommonMpdInfo(XmlNode* mpd_node) {
if (Positive(mpd_options_.min_buffer_time)) { if (Positive(mpd_options_.mpd_params.min_buffer_time)) {
mpd_node->SetStringAttribute( mpd_node->SetStringAttribute(
"minBufferTime", SecondsToXmlDuration(mpd_options_.min_buffer_time)); "minBufferTime",
SecondsToXmlDuration(mpd_options_.mpd_params.min_buffer_time));
} else { } else {
LOG(ERROR) << "minBufferTime value not specified."; LOG(ERROR) << "minBufferTime value not specified.";
// TODO(tinskip): Propagate error. // TODO(tinskip): Propagate error.
@ -551,19 +552,19 @@ void MpdBuilder::AddDynamicMpdInfo(XmlNode* mpd_node) {
mpd_node->SetStringAttribute("availabilityStartTime", mpd_node->SetStringAttribute("availabilityStartTime",
availability_start_time_); availability_start_time_);
if (Positive(mpd_options_.minimum_update_period)) { if (Positive(mpd_options_.mpd_params.minimum_update_period)) {
mpd_node->SetStringAttribute( mpd_node->SetStringAttribute(
"minimumUpdatePeriod", "minimumUpdatePeriod",
SecondsToXmlDuration(mpd_options_.minimum_update_period)); SecondsToXmlDuration(mpd_options_.mpd_params.minimum_update_period));
} else { } else {
LOG(WARNING) << "The profile is dynamic but no minimumUpdatePeriod " LOG(WARNING) << "The profile is dynamic but no minimumUpdatePeriod "
"specified."; "specified.";
} }
SetIfPositive("timeShiftBufferDepth", mpd_options_.time_shift_buffer_depth, SetIfPositive("timeShiftBufferDepth",
mpd_node); mpd_options_.mpd_params.time_shift_buffer_depth, mpd_node);
SetIfPositive("suggestedPresentationDelay", SetIfPositive("suggestedPresentationDelay",
mpd_options_.suggested_presentation_delay, mpd_node); mpd_options_.mpd_params.suggested_presentation_delay, mpd_node);
} }
float MpdBuilder::GetStaticMpdDuration(XmlNode* mpd_node) { float MpdBuilder::GetStaticMpdDuration(XmlNode* mpd_node) {
@ -1287,15 +1288,15 @@ bool Representation::IsContiguous(uint64_t start_time,
void Representation::SlideWindow() { void Representation::SlideWindow() {
DCHECK(!segment_infos_.empty()); DCHECK(!segment_infos_.empty());
if (mpd_options_.time_shift_buffer_depth <= 0.0 || if (mpd_options_.mpd_params.time_shift_buffer_depth <= 0.0 ||
mpd_options_.mpd_type == MpdType::kStatic) mpd_options_.mpd_type == MpdType::kStatic)
return; return;
const uint32_t time_scale = GetTimeScale(media_info_); const uint32_t time_scale = GetTimeScale(media_info_);
DCHECK_GT(time_scale, 0u); DCHECK_GT(time_scale, 0u);
uint64_t time_shift_buffer_depth = uint64_t time_shift_buffer_depth = static_cast<uint64_t>(
static_cast<uint64_t>(mpd_options_.time_shift_buffer_depth * time_scale); mpd_options_.mpd_params.time_shift_buffer_depth * time_scale);
// The start time of the latest segment is considered the current_play_time, // The start time of the latest segment is considered the current_play_time,
// and this should guarantee that the latest segment will stay in the list. // and this should guarantee that the latest segment will stay in the list.

View File

@ -2196,7 +2196,8 @@ TEST_F(SegmentTemplateTest, OverlappingSegmentsWithinErrorRange) {
// All segments have the same duration and size. // All segments have the same duration and size.
TEST_F(TimeShiftBufferDepthTest, Normal) { TEST_F(TimeShiftBufferDepthTest, Normal) {
const int kTimeShiftBufferDepth = 10; // 10 sec. const int kTimeShiftBufferDepth = 10; // 10 sec.
mutable_mpd_options()->time_shift_buffer_depth = kTimeShiftBufferDepth; mutable_mpd_options()->mpd_params.time_shift_buffer_depth =
kTimeShiftBufferDepth;
const uint64_t kInitialStartTime = 0; const uint64_t kInitialStartTime = 0;
// Trick to make every segment 1 second long. // Trick to make every segment 1 second long.
@ -2233,7 +2234,8 @@ TEST_F(TimeShiftBufferDepthTest, Normal) {
// removed from the MPD. // removed from the MPD.
TEST_F(TimeShiftBufferDepthTest, TimeShiftBufferDepthShorterThanSegmentLength) { TEST_F(TimeShiftBufferDepthTest, TimeShiftBufferDepthShorterThanSegmentLength) {
const int kTimeShiftBufferDepth = 10; // 10 sec. const int kTimeShiftBufferDepth = 10; // 10 sec.
mutable_mpd_options()->time_shift_buffer_depth = kTimeShiftBufferDepth; mutable_mpd_options()->mpd_params.time_shift_buffer_depth =
kTimeShiftBufferDepth;
const uint64_t kInitialStartTime = 0; const uint64_t kInitialStartTime = 0;
// Each duration is a second longer than timeShiftBufferDepth. // Each duration is a second longer than timeShiftBufferDepth.
@ -2254,7 +2256,8 @@ TEST_F(TimeShiftBufferDepthTest, TimeShiftBufferDepthShorterThanSegmentLength) {
// More generic version the normal test. // More generic version the normal test.
TEST_F(TimeShiftBufferDepthTest, Generic) { TEST_F(TimeShiftBufferDepthTest, Generic) {
const int kTimeShiftBufferDepth = 30; const int kTimeShiftBufferDepth = 30;
mutable_mpd_options()->time_shift_buffer_depth = kTimeShiftBufferDepth; mutable_mpd_options()->mpd_params.time_shift_buffer_depth =
kTimeShiftBufferDepth;
const uint64_t kInitialStartTime = 123; const uint64_t kInitialStartTime = 123;
const uint64_t kDuration = DefaultTimeScale(); const uint64_t kDuration = DefaultTimeScale();
@ -2296,7 +2299,8 @@ TEST_F(TimeShiftBufferDepthTest, Generic) {
// the most recent segment added does not count // the most recent segment added does not count
TEST_F(TimeShiftBufferDepthTest, MoreThanOneS) { TEST_F(TimeShiftBufferDepthTest, MoreThanOneS) {
const int kTimeShiftBufferDepth = 100; const int kTimeShiftBufferDepth = 100;
mutable_mpd_options()->time_shift_buffer_depth = kTimeShiftBufferDepth; mutable_mpd_options()->mpd_params.time_shift_buffer_depth =
kTimeShiftBufferDepth;
const uint64_t kInitialStartTime = 0; const uint64_t kInitialStartTime = 0;
const uint64_t kSize = 20000; const uint64_t kSize = 20000;
@ -2346,7 +2350,8 @@ TEST_F(TimeShiftBufferDepthTest, MoreThanOneS) {
// Then the first S element's last segment should still be in the MPD. // Then the first S element's last segment should still be in the MPD.
TEST_F(TimeShiftBufferDepthTest, UseLastSegmentInS) { TEST_F(TimeShiftBufferDepthTest, UseLastSegmentInS) {
const int kTimeShiftBufferDepth = 9; const int kTimeShiftBufferDepth = 9;
mutable_mpd_options()->time_shift_buffer_depth = kTimeShiftBufferDepth; mutable_mpd_options()->mpd_params.time_shift_buffer_depth =
kTimeShiftBufferDepth;
const uint64_t kInitialStartTime = 1; const uint64_t kInitialStartTime = 1;
const uint64_t kDuration1 = static_cast<uint64_t>(DefaultTimeScale() * 1.5); const uint64_t kDuration1 = static_cast<uint64_t>(DefaultTimeScale() * 1.5);
@ -2382,7 +2387,8 @@ TEST_F(TimeShiftBufferDepthTest, UseLastSegmentInS) {
// Gap between S elements but both should be included. // Gap between S elements but both should be included.
TEST_F(TimeShiftBufferDepthTest, NormalGap) { TEST_F(TimeShiftBufferDepthTest, NormalGap) {
const int kTimeShiftBufferDepth = 10; const int kTimeShiftBufferDepth = 10;
mutable_mpd_options()->time_shift_buffer_depth = kTimeShiftBufferDepth; mutable_mpd_options()->mpd_params.time_shift_buffer_depth =
kTimeShiftBufferDepth;
const uint64_t kInitialStartTime = 0; const uint64_t kInitialStartTime = 0;
const uint64_t kDuration = DefaultTimeScale(); const uint64_t kDuration = DefaultTimeScale();
@ -2413,7 +2419,8 @@ TEST_F(TimeShiftBufferDepthTest, NormalGap) {
// Case where there is a huge gap so the first S element is removed. // Case where there is a huge gap so the first S element is removed.
TEST_F(TimeShiftBufferDepthTest, HugeGap) { TEST_F(TimeShiftBufferDepthTest, HugeGap) {
const int kTimeShiftBufferDepth = 10; const int kTimeShiftBufferDepth = 10;
mutable_mpd_options()->time_shift_buffer_depth = kTimeShiftBufferDepth; mutable_mpd_options()->mpd_params.time_shift_buffer_depth =
kTimeShiftBufferDepth;
const uint64_t kInitialStartTime = 0; const uint64_t kInitialStartTime = 0;
const uint64_t kDuration = DefaultTimeScale(); const uint64_t kDuration = DefaultTimeScale();
@ -2448,7 +2455,8 @@ TEST_F(TimeShiftBufferDepthTest, HugeGap) {
// Check if startNumber is working correctly. // Check if startNumber is working correctly.
TEST_F(TimeShiftBufferDepthTest, ManySegments) { TEST_F(TimeShiftBufferDepthTest, ManySegments) {
const int kTimeShiftBufferDepth = 1; const int kTimeShiftBufferDepth = 1;
mutable_mpd_options()->time_shift_buffer_depth = kTimeShiftBufferDepth; mutable_mpd_options()->mpd_params.time_shift_buffer_depth =
kTimeShiftBufferDepth;
const uint64_t kInitialStartTime = 0; const uint64_t kInitialStartTime = 0;
const uint64_t kDuration = DefaultTimeScale(); const uint64_t kDuration = DefaultTimeScale();

View File

@ -9,6 +9,8 @@
#include <string> #include <string>
#include "packager/mpd/public/mpd_params.h"
namespace shaka { namespace shaka {
enum class DashProfile { enum class DashProfile {
@ -23,12 +25,7 @@ enum class MpdType { kStatic, kDynamic };
struct MpdOptions { struct MpdOptions {
DashProfile dash_profile = DashProfile::kOnDemand; DashProfile dash_profile = DashProfile::kOnDemand;
MpdType mpd_type = MpdType::kStatic; MpdType mpd_type = MpdType::kStatic;
double minimum_update_period = 0; MpdParams mpd_params;
// TODO(tinskip): Set min_buffer_time in unit tests rather than here.
double min_buffer_time = 2.0;
double time_shift_buffer_depth = 0;
double suggested_presentation_delay = 0;
std::string default_language;
}; };
} // namespace shaka } // namespace shaka

View File

@ -14,14 +14,12 @@
namespace shaka { namespace shaka {
SimpleMpdNotifier::SimpleMpdNotifier(const MpdOptions& mpd_options, SimpleMpdNotifier::SimpleMpdNotifier(const MpdOptions& mpd_options)
const std::vector<std::string>& base_urls,
const std::string& output_path)
: MpdNotifier(mpd_options), : MpdNotifier(mpd_options),
output_path_(output_path), output_path_(mpd_options.mpd_params.mpd_output),
mpd_builder_(new MpdBuilder(mpd_options)) { mpd_builder_(new MpdBuilder(mpd_options)) {
for (size_t i = 0; i < base_urls.size(); ++i) for (const std::string& base_url : mpd_options.mpd_params.base_urls)
mpd_builder_->AddBaseUrl(base_urls[i]); mpd_builder_->AddBaseUrl(base_url);
} }
SimpleMpdNotifier::~SimpleMpdNotifier() { SimpleMpdNotifier::~SimpleMpdNotifier() {

View File

@ -30,9 +30,7 @@ struct MpdOptions;
/// generates an Mpd file. /// generates an Mpd file.
class SimpleMpdNotifier : public MpdNotifier { class SimpleMpdNotifier : public MpdNotifier {
public: public:
SimpleMpdNotifier(const MpdOptions& mpd_options, explicit SimpleMpdNotifier(const MpdOptions& mpd_options);
const std::vector<std::string>& base_urls,
const std::string& output_path);
~SimpleMpdNotifier() override; ~SimpleMpdNotifier() override;
/// @name MpdNotifier implemetation overrides. /// @name MpdNotifier implemetation overrides.

View File

@ -43,7 +43,7 @@ class SimpleMpdNotifierTest : public ::testing::Test {
void SetUp() override { void SetUp() override {
ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_)); ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_));
output_path_ = temp_file_path_.AsUTF8Unsafe(); empty_mpd_option_.mpd_params.mpd_output = temp_file_path_.AsUTF8Unsafe();
} }
void TearDown() override { void TearDown() override {
@ -55,10 +55,9 @@ class SimpleMpdNotifierTest : public ::testing::Test {
notifier->SetMpdBuilderForTesting(std::move(mpd_builder)); notifier->SetMpdBuilderForTesting(std::move(mpd_builder));
} }
// Use output_path_ for specifying the MPD output path so that // Empty mpd options except with output path specified, so that
// WriteMpdToFile() doesn't crash. // WriteMpdToFile() doesn't crash.
std::string output_path_; MpdOptions empty_mpd_option_;
const MpdOptions empty_mpd_option_;
const std::vector<std::string> empty_base_urls_; const std::vector<std::string> empty_base_urls_;
// Default AdaptationSet mock. // Default AdaptationSet mock.
@ -70,7 +69,7 @@ class SimpleMpdNotifierTest : public ::testing::Test {
// Verify NotifyNewContainer() works as expected for VOD. // Verify NotifyNewContainer() works as expected for VOD.
TEST_F(SimpleMpdNotifierTest, NotifyNewContainer) { TEST_F(SimpleMpdNotifierTest, NotifyNewContainer) {
SimpleMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, output_path_); SimpleMpdNotifier notifier(empty_mpd_option_);
const uint32_t kRepresentationId = 1u; const uint32_t kRepresentationId = 1u;
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
@ -94,7 +93,7 @@ TEST_F(SimpleMpdNotifierTest, NotifyNewContainer) {
} }
TEST_F(SimpleMpdNotifierTest, NotifySampleDuration) { TEST_F(SimpleMpdNotifierTest, NotifySampleDuration) {
SimpleMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, output_path_); SimpleMpdNotifier notifier(empty_mpd_option_);
const uint32_t kRepresentationId = 8u; const uint32_t kRepresentationId = 8u;
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
@ -124,7 +123,7 @@ TEST_F(SimpleMpdNotifierTest, NotifySampleDuration) {
// This issue identified a bug where using SimpleMpdNotifier with multiple // This issue identified a bug where using SimpleMpdNotifier with multiple
// threads causes a deadlock. // threads causes a deadlock.
TEST_F(SimpleMpdNotifierTest, NotifyNewContainerAndSampleDurationNoMock) { TEST_F(SimpleMpdNotifierTest, NotifyNewContainerAndSampleDurationNoMock) {
SimpleMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, output_path_); SimpleMpdNotifier notifier(empty_mpd_option_);
uint32_t container_id; uint32_t container_id;
EXPECT_TRUE(notifier.NotifyNewContainer(ConvertToMediaInfo(kValidMediaInfo), EXPECT_TRUE(notifier.NotifyNewContainer(ConvertToMediaInfo(kValidMediaInfo),
&container_id)); &container_id));
@ -134,7 +133,7 @@ TEST_F(SimpleMpdNotifierTest, NotifyNewContainerAndSampleDurationNoMock) {
} }
TEST_F(SimpleMpdNotifierTest, NotifyNewSegment) { TEST_F(SimpleMpdNotifierTest, NotifyNewSegment) {
SimpleMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, output_path_); 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());
@ -163,7 +162,7 @@ TEST_F(SimpleMpdNotifierTest, NotifyNewSegment) {
} }
TEST_F(SimpleMpdNotifierTest, AddContentProtectionElement) { TEST_F(SimpleMpdNotifierTest, AddContentProtectionElement) {
SimpleMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, output_path_); SimpleMpdNotifier notifier(empty_mpd_option_);
const uint32_t kRepresentationId = 0u; const uint32_t kRepresentationId = 0u;
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
@ -206,7 +205,7 @@ TEST_F(SimpleMpdNotifierTest, UpdateEncryption) {
" default_key_id: '_default_key_id_'\n" " default_key_id: '_default_key_id_'\n"
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
SimpleMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, output_path_); 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(
@ -294,7 +293,7 @@ TEST_F(SimpleMpdNotifierTest, SplitAdaptationSetsByLanguageAndCodec) {
"container_type: CONTAINER_WEBM\n" "container_type: CONTAINER_WEBM\n"
"media_duration_seconds: 10.5\n"; "media_duration_seconds: 10.5\n";
SimpleMpdNotifier notifier(empty_mpd_option_, empty_base_urls_, output_path_); SimpleMpdNotifier notifier(empty_mpd_option_);
std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder()); std::unique_ptr<MockMpdBuilder> mock_mpd_builder(new MockMpdBuilder());
std::unique_ptr<MockAdaptationSet> adaptation_set1(new MockAdaptationSet(1)); std::unique_ptr<MockAdaptationSet> adaptation_set1(new MockAdaptationSet(1));

View File

@ -47,6 +47,7 @@
'base/xml/scoped_xml_ptr.h', 'base/xml/scoped_xml_ptr.h',
'base/xml/xml_node.cc', 'base/xml/xml_node.cc',
'base/xml/xml_node.h', 'base/xml/xml_node.h',
'public/mpd_params.h',
], ],
'dependencies': [ 'dependencies': [
'../base/base.gyp:base', '../base/base.gyp:base',

View File

@ -0,0 +1,53 @@
// Copyright 2017 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 PACKAGER_MPD_PUBLIC_MPD_PARAMS_H_
#define PACKAGER_MPD_PUBLIC_MPD_PARAMS_H_
#include <string>
#include <vector>
namespace shaka {
/// DASH MPD related parameters.
struct MpdParams {
/// MPD output file path.
std::string mpd_output;
/// BaseURLs for the MPD. The values will be added as <BaseURL> element(s)
/// under the <MPD> element.
std::vector<std::string> base_urls;
/// Set MPD@minBufferTime attribute, which specifies, in seconds, a common
/// duration used in the definition of the MPD representation data rate. A
/// client can be assured of having enough data for continous playout
/// providing playout begins at min_buffer_time after the first bit is
/// received.
double min_buffer_time = 2.0;
/// Generate static MPD for live profile. Note that this flag has no effect
/// for on-demand profile, in which case static MPD is always used.
bool generate_static_live_mpd = false;
/// Set MPD@timeShiftBufferDepth attribute, which is the guaranteed duration
/// of the time shifting buffer for 'dynamic' media presentations, in seconds.
double time_shift_buffer_depth = 0;
/// Set MPD@suggestedPresentationDelay attribute. For 'dynamic' media
/// presentations, it specifies a delay, in seconds, to be added to the media
/// presentation time. The attribute is not set if the value is 0; the client
/// is expected to choose a suitable value in this case.
static constexpr double kSuggestedPresentationDelayNotSet = 0;
double suggested_presentation_delay = kSuggestedPresentationDelayNotSet;
/// Set MPD@minimumUpdatePeriod attribute, which indicates to the player how
/// often to refresh the MPD in seconds. For dynamic MPD only.
double minimum_update_period = 0;
/// The tracks tagged with this language will have <Role ... value=\"main\" />
/// in the manifest. This allows the player to choose the correct default
/// language for the content.
std::string default_language;
/// Try to generate DASH-IF IOP compliant MPD.
bool generate_dash_if_iop_compliant_mpd = true;
};
} // namespace shaka
#endif // PACKAGER_MPD_PUBLIC_MPD_PARAMS_H_

View File

@ -35,11 +35,8 @@ class DashIopMpdNotifierFactory : public MpdNotifierFactory {
DashIopMpdNotifierFactory() {} DashIopMpdNotifierFactory() {}
~DashIopMpdNotifierFactory() override {} ~DashIopMpdNotifierFactory() override {}
std::unique_ptr<MpdNotifier> Create(const MpdOptions& mpd_options, std::unique_ptr<MpdNotifier> Create(const MpdOptions& mpd_options) override {
const std::vector<std::string>& base_urls, return std::unique_ptr<MpdNotifier>(new DashIopMpdNotifier(mpd_options));
const std::string& output_path) override {
return std::unique_ptr<MpdNotifier>(
new DashIopMpdNotifier(mpd_options, base_urls, output_path));
} }
}; };
@ -49,11 +46,8 @@ class SimpleMpdNotifierFactory : public MpdNotifierFactory {
SimpleMpdNotifierFactory() {} SimpleMpdNotifierFactory() {}
~SimpleMpdNotifierFactory() override {} ~SimpleMpdNotifierFactory() override {}
std::unique_ptr<MpdNotifier> Create(const MpdOptions& mpd_options, std::unique_ptr<MpdNotifier> Create(const MpdOptions& mpd_options) override {
const std::vector<std::string>& base_urls, return std::unique_ptr<MpdNotifier>(new SimpleMpdNotifier(mpd_options));
const std::string& output_path) override {
return std::unique_ptr<MpdNotifier>(
new SimpleMpdNotifier(mpd_options, base_urls, output_path));
} }
}; };
@ -93,8 +87,11 @@ void MpdWriter::AddBaseUrl(const std::string& base_url) {
bool MpdWriter::WriteMpdToFile(const char* file_name) { bool MpdWriter::WriteMpdToFile(const char* file_name) {
CHECK(file_name); CHECK(file_name);
MpdOptions mpd_options;
mpd_options.mpd_params.base_urls = base_urls_;
mpd_options.mpd_params.mpd_output = file_name;
std::unique_ptr<MpdNotifier> notifier = std::unique_ptr<MpdNotifier> notifier =
notifier_factory_->Create(MpdOptions(), base_urls_, file_name); notifier_factory_->Create(mpd_options);
if (!notifier->Init()) { if (!notifier->Init()) {
LOG(ERROR) << "failed to initialize MpdNotifier."; LOG(ERROR) << "failed to initialize MpdNotifier.";
return false; return false;

View File

@ -35,9 +35,7 @@ class MpdNotifierFactory {
virtual ~MpdNotifierFactory() {} virtual ~MpdNotifierFactory() {}
virtual std::unique_ptr<MpdNotifier> Create( virtual std::unique_ptr<MpdNotifier> Create(
const MpdOptions& mpd_options, const MpdOptions& mpd_options) = 0;
const std::vector<std::string>& base_urls,
const std::string& output_path) = 0;
}; };
// An instance of this class takes a set of MediaInfo files and generates an // An instance of this class takes a set of MediaInfo files and generates an

View File

@ -33,10 +33,8 @@ class TestMpdNotifierFactory : public MpdNotifierFactory {
// std::unique_ptr. // std::unique_ptr.
// For now we only need to return MockMpdNotifier() with these set of // For now we only need to return MockMpdNotifier() with these set of
// expectations for all the tests. // expectations for all the tests.
std::unique_ptr<MpdNotifier> Create(const MpdOptions& mpd_options, std::unique_ptr<MpdNotifier> Create(const MpdOptions& mpd_options) override {
const std::vector<std::string>& base_urls, EXPECT_EQ(expected_base_urls_, mpd_options.mpd_params.base_urls);
const std::string& output_path) override {
EXPECT_EQ(expected_base_urls_, base_urls);
std::unique_ptr<MockMpdNotifier> mock_notifier( std::unique_ptr<MockMpdNotifier> mock_notifier(
new MockMpdNotifier(mpd_options)); new MockMpdNotifier(mpd_options));

View File

@ -43,9 +43,7 @@
namespace shaka { namespace shaka {
// TODO(kqyang): Clean up namespaces. // TODO(kqyang): Clean up namespaces.
using media::ChunkingOptions;
using media::Demuxer; using media::Demuxer;
using media::EncryptionOptions;
using media::KeySource; using media::KeySource;
using media::MuxerOptions; using media::MuxerOptions;
@ -602,11 +600,9 @@ Status Packager::Initialize(
const MpdParams& mpd_params = packaging_params.mpd_params; const MpdParams& mpd_params = packaging_params.mpd_params;
if (!mpd_params.mpd_output.empty()) { if (!mpd_params.mpd_output.empty()) {
if (mpd_params.generate_dash_if_iop_compliant_mpd) { if (mpd_params.generate_dash_if_iop_compliant_mpd) {
internal->mpd_notifier.reset(new DashIopMpdNotifier( internal->mpd_notifier.reset(new DashIopMpdNotifier(mpd_options));
mpd_options, mpd_params.base_urls, mpd_params.mpd_output));
} else { } else {
internal->mpd_notifier.reset(new SimpleMpdNotifier( internal->mpd_notifier.reset(new SimpleMpdNotifier(mpd_options));
mpd_options, mpd_params.base_urls, mpd_params.mpd_output));
} }
if (!internal->mpd_notifier->Init()) { if (!internal->mpd_notifier->Init()) {
LOG(ERROR) << "MpdNotifier failed to initialize."; LOG(ERROR) << "MpdNotifier failed to initialize.";

View File

@ -15,46 +15,11 @@
#include "packager/media/public/chunking_params.h" #include "packager/media/public/chunking_params.h"
#include "packager/media/public/crypto_params.h" #include "packager/media/public/crypto_params.h"
#include "packager/media/public/mp4_output_params.h" #include "packager/media/public/mp4_output_params.h"
#include "packager/mpd/public/mpd_params.h"
#include "packager/status.h" #include "packager/status.h"
namespace shaka { namespace shaka {
/// DASH MPD related parameters.
struct MpdParams {
/// MPD output file path.
std::string mpd_output;
/// BaseURLs for the MPD. The values will be added as <BaseURL> element(s)
/// under the <MPD> element.
std::vector<std::string> base_urls;
/// Set MPD@minBufferTime attribute, which specifies, in seconds, a common
/// duration used in the definition of the MPD representation data rate. A
/// client can be assured of having enough data for continous playout
/// providing playout begins at min_buffer_time after the first bit is
/// received.
double min_buffer_time = 2.0;
/// Generate static MPD for live profile. Note that this flag has no effect
/// for on-demand profile, in which case static MPD is always used.
bool generate_static_live_mpd = false;
/// Set MPD@timeShiftBufferDepth attribute, which is the guaranteed duration
/// of the time shifting buffer for 'dynamic' media presentations, in seconds.
double time_shift_buffer_depth = 0;
/// Set MPD@suggestedPresentationDelay attribute. For 'dynamic' media
/// presentations, it specifies a delay, in seconds, to be added to the media
/// presentation time. The attribute is not set if the value is 0; the client
/// is expected to choose a suitable value in this case.
const double kSuggestedPresentationDelayNotSet = 0;
double suggested_presentation_delay = kSuggestedPresentationDelayNotSet;
/// Set MPD@minimumUpdatePeriod attribute, which indicates to the player how
/// often to refresh the MPD in seconds. For dynamic MPD only.
double minimum_update_period = 0;
/// The tracks tagged with this language will have <Role ... value=\"main\" />
/// in the manifest. This allows the player to choose the correct default
/// language for the content.
std::string default_language;
/// Try to generate DASH-IF IOP compliant MPD.
bool generate_dash_if_iop_compliant_mpd = true;
};
/// HLS related parameters. /// HLS related parameters.
struct HlsParams { struct HlsParams {
/// HLS playlist type. See HLS specification for details. /// HLS playlist type. See HLS specification for details.