2014-02-14 23:21:05 +00:00
|
|
|
// Copyright 2014 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
|
|
|
|
|
2014-08-21 22:40:44 +00:00
|
|
|
#include <gtest/gtest.h>
|
2017-12-14 21:58:53 +00:00
|
|
|
|
2017-12-13 01:26:37 +00:00
|
|
|
#include "packager/mpd/base/adaptation_set.h"
|
2014-10-01 22:10:21 +00:00
|
|
|
#include "packager/mpd/base/mpd_builder.h"
|
|
|
|
#include "packager/mpd/test/mpd_builder_test_helper.h"
|
2016-07-07 19:34:07 +00:00
|
|
|
#include "packager/version/version.h"
|
2013-12-30 23:05:27 +00:00
|
|
|
|
2016-05-20 21:19:33 +00:00
|
|
|
namespace shaka {
|
2013-12-30 23:05:27 +00:00
|
|
|
|
2014-02-05 18:55:37 +00:00
|
|
|
namespace {
|
2014-05-27 22:21:42 +00:00
|
|
|
|
2016-01-11 23:58:02 +00:00
|
|
|
class TestClock : public base::Clock {
|
|
|
|
public:
|
|
|
|
explicit TestClock(const base::Time& t) : time_(t) {}
|
|
|
|
~TestClock() override {}
|
|
|
|
base::Time Now() override { return time_; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
base::Time time_;
|
|
|
|
};
|
|
|
|
|
2014-02-05 18:55:37 +00:00
|
|
|
} // namespace
|
|
|
|
|
2016-12-21 23:28:56 +00:00
|
|
|
template <DashProfile profile>
|
2015-10-29 22:48:13 +00:00
|
|
|
class MpdBuilderTest : public ::testing::Test {
|
2014-02-28 22:34:26 +00:00
|
|
|
public:
|
2016-12-21 23:28:56 +00:00
|
|
|
MpdBuilderTest() : mpd_(MpdOptions()), representation_() {
|
|
|
|
mpd_.mpd_options_.dash_profile = profile;
|
|
|
|
}
|
2015-07-22 23:40:45 +00:00
|
|
|
~MpdBuilderTest() override {}
|
2014-02-28 22:34:26 +00:00
|
|
|
|
2016-12-21 23:28:56 +00:00
|
|
|
MpdOptions* mutable_mpd_options() { return &mpd_.mpd_options_; }
|
|
|
|
|
2014-02-28 22:34:26 +00:00
|
|
|
void CheckMpd(const std::string& expected_output_file) {
|
|
|
|
std::string mpd_doc;
|
|
|
|
ASSERT_TRUE(mpd_.ToString(&mpd_doc));
|
|
|
|
ASSERT_TRUE(ValidateMpdSchema(mpd_doc));
|
|
|
|
|
|
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
|
|
ExpectMpdToEqualExpectedOutputFile(mpd_doc, expected_output_file));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2016-01-05 00:33:53 +00:00
|
|
|
// Creates a new AdaptationSet and adds a Representation element using
|
|
|
|
// |media_info|.
|
2014-05-22 02:16:17 +00:00
|
|
|
void AddRepresentation(const MediaInfo& media_info) {
|
2015-02-02 17:26:09 +00:00
|
|
|
AdaptationSet* adaptation_set = mpd_.AddAdaptationSet("");
|
2014-05-22 02:16:17 +00:00
|
|
|
ASSERT_TRUE(adaptation_set);
|
|
|
|
|
|
|
|
Representation* representation =
|
|
|
|
adaptation_set->AddRepresentation(media_info);
|
|
|
|
ASSERT_TRUE(representation);
|
|
|
|
|
|
|
|
representation_ = representation;
|
|
|
|
}
|
|
|
|
|
2014-02-28 22:34:26 +00:00
|
|
|
MpdBuilder mpd_;
|
|
|
|
|
2014-05-22 02:16:17 +00:00
|
|
|
// We usually need only one representation.
|
|
|
|
Representation* representation_; // Owned by |mpd_|.
|
|
|
|
|
2014-02-28 22:34:26 +00:00
|
|
|
private:
|
2017-12-14 06:33:47 +00:00
|
|
|
base::AtomicSequenceNumber representation_counter_;
|
2016-12-21 23:28:56 +00:00
|
|
|
|
2014-05-22 02:16:17 +00:00
|
|
|
DISALLOW_COPY_AND_ASSIGN(MpdBuilderTest);
|
2014-02-28 22:34:26 +00:00
|
|
|
};
|
|
|
|
|
2016-12-21 23:28:56 +00:00
|
|
|
class OnDemandMpdBuilderTest : public MpdBuilderTest<DashProfile::kOnDemand> {};
|
2013-12-30 23:05:27 +00:00
|
|
|
|
2016-12-21 23:28:56 +00:00
|
|
|
class LiveMpdBuilderTest : public MpdBuilderTest<DashProfile::kLive> {
|
2014-05-22 02:16:17 +00:00
|
|
|
public:
|
2016-12-21 23:28:56 +00:00
|
|
|
~LiveMpdBuilderTest() override {}
|
2013-12-30 23:05:27 +00:00
|
|
|
|
2014-05-22 02:16:17 +00:00
|
|
|
// Anchors availabilityStartTime so that the test result doesn't depend on the
|
|
|
|
// current time.
|
2015-07-22 23:40:45 +00:00
|
|
|
void SetUp() override {
|
2016-07-07 19:34:07 +00:00
|
|
|
SetPackagerVersionForTesting("<tag>-<hash>-<test>");
|
2016-12-21 23:28:56 +00:00
|
|
|
mpd_.mpd_options_.mpd_type = MpdType::kDynamic;
|
2014-06-26 01:33:09 +00:00
|
|
|
mpd_.availability_start_time_ = "2011-12-25T12:30:00";
|
2016-01-11 23:58:02 +00:00
|
|
|
InjectTestClock();
|
2014-05-22 02:16:17 +00:00
|
|
|
}
|
2013-12-30 23:05:27 +00:00
|
|
|
|
2016-01-11 23:58:02 +00:00
|
|
|
// Injects a clock that always returns 2016 Jan 11 15:10:24 in UTC.
|
|
|
|
void InjectTestClock() {
|
2016-08-14 22:28:21 +00:00
|
|
|
base::Time::Exploded test_time = { 2016, // year.
|
|
|
|
1, // month
|
|
|
|
1, // day_of_week = Monday.
|
|
|
|
11, // day_of_month
|
|
|
|
15, // hour.
|
|
|
|
10, // minute.
|
|
|
|
24, // second.
|
|
|
|
0 }; // millisecond.
|
2016-01-11 23:58:02 +00:00
|
|
|
ASSERT_TRUE(test_time.HasValidValues());
|
2016-08-17 17:41:40 +00:00
|
|
|
mpd_.InjectClockForTesting(std::unique_ptr<base::Clock>(
|
2016-01-11 23:58:02 +00:00
|
|
|
new TestClock(base::Time::FromUTCExploded(test_time))));
|
|
|
|
}
|
2014-05-27 22:21:42 +00:00
|
|
|
};
|
|
|
|
|
2014-05-22 02:16:17 +00:00
|
|
|
// Add one video check the output.
|
2016-12-21 23:28:56 +00:00
|
|
|
TEST_F(OnDemandMpdBuilderTest, Video) {
|
2014-05-22 02:16:17 +00:00
|
|
|
MediaInfo video_media_info = GetTestMediaInfo(kFileNameVideoMediaInfo1);
|
|
|
|
ASSERT_NO_FATAL_FAILURE(AddRepresentation(video_media_info));
|
2014-02-28 22:34:26 +00:00
|
|
|
EXPECT_NO_FATAL_FAILURE(CheckMpd(kFileNameExpectedMpdOutputVideo1));
|
2013-12-30 23:05:27 +00:00
|
|
|
}
|
|
|
|
|
2016-12-21 23:28:56 +00:00
|
|
|
TEST_F(OnDemandMpdBuilderTest, TwoVideosWithDifferentResolutions) {
|
2016-01-05 00:33:53 +00:00
|
|
|
AdaptationSet* adaptation_set = mpd_.AddAdaptationSet("");
|
|
|
|
|
|
|
|
MediaInfo media_info1 = GetTestMediaInfo(kFileNameVideoMediaInfo1);
|
|
|
|
ASSERT_TRUE(adaptation_set->AddRepresentation(media_info1));
|
|
|
|
|
|
|
|
MediaInfo media_info2 = GetTestMediaInfo(kFileNameVideoMediaInfo2);
|
|
|
|
ASSERT_TRUE(adaptation_set->AddRepresentation(media_info2));
|
|
|
|
|
|
|
|
EXPECT_NO_FATAL_FAILURE(CheckMpd(kFileNameExpectedMpdOutputVideo1And2));
|
|
|
|
}
|
|
|
|
|
2014-05-22 02:16:17 +00:00
|
|
|
// Add both video and audio and check the output.
|
2016-12-21 23:28:56 +00:00
|
|
|
TEST_F(OnDemandMpdBuilderTest, VideoAndAudio) {
|
2014-02-05 02:32:46 +00:00
|
|
|
MediaInfo video_media_info = GetTestMediaInfo(kFileNameVideoMediaInfo1);
|
|
|
|
MediaInfo audio_media_info = GetTestMediaInfo(kFileNameAudioMediaInfo1);
|
|
|
|
|
|
|
|
// The order matters here to check against expected output.
|
2015-02-02 17:26:09 +00:00
|
|
|
AdaptationSet* video_adaptation_set = mpd_.AddAdaptationSet("");
|
2014-02-05 02:32:46 +00:00
|
|
|
ASSERT_TRUE(video_adaptation_set);
|
2013-12-30 23:05:27 +00:00
|
|
|
|
2015-02-02 17:26:09 +00:00
|
|
|
AdaptationSet* audio_adaptation_set = mpd_.AddAdaptationSet("");
|
2014-02-05 02:32:46 +00:00
|
|
|
ASSERT_TRUE(audio_adaptation_set);
|
2013-12-30 23:05:27 +00:00
|
|
|
|
2014-02-05 02:32:46 +00:00
|
|
|
Representation* audio_representation =
|
|
|
|
audio_adaptation_set->AddRepresentation(audio_media_info);
|
|
|
|
ASSERT_TRUE(audio_representation);
|
|
|
|
|
|
|
|
Representation* video_representation =
|
|
|
|
video_adaptation_set->AddRepresentation(video_media_info);
|
2014-03-21 17:26:49 +00:00
|
|
|
ASSERT_TRUE(video_representation);
|
2013-12-30 23:05:27 +00:00
|
|
|
|
2014-02-28 22:34:26 +00:00
|
|
|
EXPECT_NO_FATAL_FAILURE(CheckMpd(kFileNameExpectedMpdOutputAudio1AndVideo1));
|
|
|
|
}
|
|
|
|
|
2014-05-22 02:16:17 +00:00
|
|
|
// Static profile requires bandwidth to be set because it has no other way to
|
|
|
|
// get the bandwidth for the Representation.
|
2016-12-21 23:28:56 +00:00
|
|
|
TEST_F(OnDemandMpdBuilderTest, MediaInfoMissingBandwidth) {
|
2014-05-22 02:16:17 +00:00
|
|
|
MediaInfo video_media_info = GetTestMediaInfo(kFileNameVideoMediaInfo1);
|
|
|
|
video_media_info.clear_bandwidth();
|
|
|
|
AddRepresentation(video_media_info);
|
|
|
|
|
|
|
|
std::string mpd_doc;
|
|
|
|
ASSERT_FALSE(mpd_.ToString(&mpd_doc));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether the attributes are set correctly for dynamic <MPD> element.
|
2015-07-15 21:57:47 +00:00
|
|
|
// This test must use ASSERT_EQ for comparison because XmlEqual() cannot
|
|
|
|
// handle namespaces correctly yet.
|
2016-12-21 23:28:56 +00:00
|
|
|
TEST_F(LiveMpdBuilderTest, DynamicCheckMpdAttributes) {
|
2014-05-22 02:16:17 +00:00
|
|
|
static const char kExpectedOutput[] =
|
|
|
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
2016-05-20 21:28:13 +00:00
|
|
|
"<!--Generated with https://github.com/google/shaka-packager "
|
2015-12-21 23:10:17 +00:00
|
|
|
"version <tag>-<hash>-<test>-->\n"
|
2016-01-04 22:21:01 +00:00
|
|
|
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\" "
|
2014-05-22 02:16:17 +00:00
|
|
|
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
|
|
|
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
|
2015-07-15 21:57:47 +00:00
|
|
|
"xsi:schemaLocation="
|
2016-01-04 22:21:01 +00:00
|
|
|
"\"urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd\" "
|
2015-07-15 21:57:47 +00:00
|
|
|
"xmlns:cenc=\"urn:mpeg:cenc:2013\" "
|
2016-12-21 23:28:56 +00:00
|
|
|
"profiles=\"urn:mpeg:dash:profile:isoff-live:2011\" "
|
2015-07-15 21:57:47 +00:00
|
|
|
"minBufferTime=\"PT2S\" "
|
|
|
|
"type=\"dynamic\" "
|
2016-01-11 23:58:02 +00:00
|
|
|
"publishTime=\"2016-01-11T15:10:24Z\" "
|
2014-06-26 01:33:09 +00:00
|
|
|
"availabilityStartTime=\"2011-12-25T12:30:00\">\n"
|
2016-01-11 23:58:02 +00:00
|
|
|
" <Period id=\"0\" start=\"PT0S\"/>\n"
|
2014-05-22 02:16:17 +00:00
|
|
|
"</MPD>\n";
|
|
|
|
|
|
|
|
std::string mpd_doc;
|
2016-12-21 23:28:56 +00:00
|
|
|
mutable_mpd_options()->mpd_type = MpdType::kDynamic;
|
|
|
|
ASSERT_TRUE(mpd_.ToString(&mpd_doc));
|
|
|
|
ASSERT_EQ(kExpectedOutput, mpd_doc);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LiveMpdBuilderTest, StaticCheckMpdAttributes) {
|
|
|
|
static const char kExpectedOutput[] =
|
|
|
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
|
|
|
"<!--Generated with https://github.com/google/shaka-packager "
|
|
|
|
"version <tag>-<hash>-<test>-->\n"
|
|
|
|
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\" "
|
|
|
|
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
|
|
|
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
|
|
|
|
"xsi:schemaLocation="
|
|
|
|
"\"urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd\" "
|
|
|
|
"xmlns:cenc=\"urn:mpeg:cenc:2013\" "
|
|
|
|
"profiles=\"urn:mpeg:dash:profile:isoff-live:2011\" "
|
|
|
|
"minBufferTime=\"PT2S\" "
|
|
|
|
"type=\"static\" "
|
|
|
|
"mediaPresentationDuration=\"PT0S\">\n"
|
|
|
|
" <Period id=\"0\"/>\n"
|
|
|
|
"</MPD>\n";
|
|
|
|
|
|
|
|
std::string mpd_doc;
|
|
|
|
mutable_mpd_options()->mpd_type = MpdType::kStatic;
|
2014-05-22 02:16:17 +00:00
|
|
|
ASSERT_TRUE(mpd_.ToString(&mpd_doc));
|
|
|
|
ASSERT_EQ(kExpectedOutput, mpd_doc);
|
|
|
|
}
|
|
|
|
|
2017-09-08 17:52:48 +00:00
|
|
|
namespace {
|
|
|
|
const char kMediaFile[] = "foo/bar/media.mp4";
|
|
|
|
const char kMediaFileBase[] = "media.mp4";
|
|
|
|
const char kInitSegment[] = "foo/bar/init.mp4";
|
|
|
|
const char kInitSegmentBase[] = "init.mp4";
|
|
|
|
const char kSegmentTemplate[] = "foo/bar/segment-$Number$.mp4";
|
|
|
|
const char kSegmentTemplateBase[] = "segment-$Number$.mp4";
|
|
|
|
const char kPathModifiedMpd[] = "foo/bar/media.mpd";
|
|
|
|
const char kPathNotModifiedMpd[] = "foo/baz/media.mpd";
|
|
|
|
} // namespace
|
|
|
|
|
2014-12-16 01:32:19 +00:00
|
|
|
TEST(RelativePaths, PathsModified) {
|
|
|
|
MediaInfo media_info;
|
|
|
|
|
|
|
|
media_info.set_media_file_name(kMediaFile);
|
|
|
|
media_info.set_init_segment_name(kInitSegment);
|
|
|
|
media_info.set_segment_template(kSegmentTemplate);
|
2017-09-08 17:52:48 +00:00
|
|
|
MpdBuilder::MakePathsRelativeToMpd(kPathModifiedMpd, &media_info);
|
2014-12-16 01:32:19 +00:00
|
|
|
EXPECT_EQ(kMediaFileBase, media_info.media_file_name());
|
|
|
|
EXPECT_EQ(kInitSegmentBase, media_info.init_segment_name());
|
|
|
|
EXPECT_EQ(kSegmentTemplateBase, media_info.segment_template());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(RelativePaths, PathsNotModified) {
|
|
|
|
MediaInfo media_info;
|
|
|
|
|
|
|
|
media_info.set_media_file_name(kMediaFile);
|
|
|
|
media_info.set_init_segment_name(kInitSegment);
|
|
|
|
media_info.set_segment_template(kSegmentTemplate);
|
2017-09-08 17:52:48 +00:00
|
|
|
MpdBuilder::MakePathsRelativeToMpd(kPathNotModifiedMpd, &media_info);
|
2014-12-16 01:32:19 +00:00
|
|
|
EXPECT_EQ(kMediaFile, media_info.media_file_name());
|
|
|
|
EXPECT_EQ(kInitSegment, media_info.init_segment_name());
|
|
|
|
EXPECT_EQ(kSegmentTemplate, media_info.segment_template());
|
|
|
|
}
|
|
|
|
|
2016-05-20 21:19:33 +00:00
|
|
|
} // namespace shaka
|