Moves AdaptationSet@id management out of Period class

It is now managed in SimpleMpdNotifier.

This avoids unnecessary increment in AdaptationSet id counter.

Also makes sure the AdaptationSet is sorted by id in XML output.

Change-Id: Ibcd0b047a71c19cd30ad7d8af9a2ed0bb05e043e
This commit is contained in:
KongQun Yang 2018-01-25 15:04:59 -08:00
parent 3b5b2bccca
commit 6ffa344553
18 changed files with 288 additions and 290 deletions

View File

@ -14,7 +14,7 @@
</SegmentBase> </SegmentBase>
</Representation> </Representation>
</AdaptationSet> </AdaptationSet>
<AdaptationSet id="2" contentType="audio" subsegmentAlignment="true"> <AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/> <ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"> <ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh> <cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh>
@ -41,7 +41,7 @@
</SegmentBase> </SegmentBase>
</Representation> </Representation>
</AdaptationSet> </AdaptationSet>
<AdaptationSet id="2" contentType="audio" subsegmentAlignment="true"> <AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/> <ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"> <ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh> <cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh>

View File

@ -23,6 +23,15 @@
</AdaptationSet> </AdaptationSet>
</Period> </Period>
<Period id="1" duration="PT0.734067S"> <Period id="1" duration="PT0.734067S">
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
<Representation id="0" bandwidth="869044" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
<SegmentTemplate timescale="30000" presentationTimeOffset="62061" initialization="bear-640x360-video-init.mp4" media="bear-640x360-video-$Number$.m4s" startNumber="3">
<SegmentTimeline>
<S t="62062" d="22022"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
<AdaptationSet id="1" contentType="audio" segmentAlignment="true"> <AdaptationSet id="1" contentType="audio" segmentAlignment="true">
<Representation id="1" bandwidth="108486" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100"> <Representation id="1" bandwidth="108486" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/> <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
@ -33,14 +42,5 @@
</SegmentTemplate> </SegmentTemplate>
</Representation> </Representation>
</AdaptationSet> </AdaptationSet>
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
<Representation id="0" bandwidth="869044" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
<SegmentTemplate timescale="30000" presentationTimeOffset="62061" initialization="bear-640x360-video-init.mp4" media="bear-640x360-video-$Number$.m4s" startNumber="3">
<SegmentTimeline>
<S t="62062" d="22022"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period> </Period>
</MPD> </MPD>

View File

@ -167,12 +167,10 @@ class RepresentationStateChangeListenerImpl
} // namespace } // namespace
AdaptationSet::AdaptationSet(uint32_t adaptation_set_id, AdaptationSet::AdaptationSet(const std::string& lang,
const std::string& lang,
const MpdOptions& mpd_options, const MpdOptions& mpd_options,
base::AtomicSequenceNumber* counter) base::AtomicSequenceNumber* counter)
: representation_counter_(counter), : representation_counter_(counter),
id_(adaptation_set_id),
lang_(lang), lang_(lang),
mpd_options_(mpd_options), mpd_options_(mpd_options),
segments_aligned_(kSegmentAlignmentUnknown), segments_aligned_(kSegmentAlignmentUnknown),
@ -245,7 +243,8 @@ xml::scoped_xml_ptr<xmlNode> AdaptationSet::GetXml() {
bool suppress_representation_height = false; bool suppress_representation_height = false;
bool suppress_representation_frame_rate = false; bool suppress_representation_frame_rate = false;
adaptation_set.SetId(id_); if (id_)
adaptation_set.SetId(id_.value());
adaptation_set.SetStringAttribute("contentType", content_type_); adaptation_set.SetStringAttribute("contentType", content_type_);
if (!lang_.empty() && lang_ != "und") { if (!lang_.empty() && lang_ != "und") {
adaptation_set.SetStringAttribute("lang", LanguageToShortestForm(lang_)); adaptation_set.SetStringAttribute("lang", LanguageToShortestForm(lang_));
@ -296,22 +295,24 @@ xml::scoped_xml_ptr<xmlNode> AdaptationSet::GetXml() {
return xml::scoped_xml_ptr<xmlNode>(); return xml::scoped_xml_ptr<xmlNode>();
} }
if (!trick_play_reference_ids_.empty()) { std::string trick_play_reference_ids;
std::string id_string; for (const AdaptationSet* adaptation_set : trick_play_references_) {
for (uint32_t id : trick_play_reference_ids_) { if (!trick_play_reference_ids.empty())
id_string += std::to_string(id) + ","; trick_play_reference_ids += ',';
} CHECK(adaptation_set->has_id());
DCHECK(!id_string.empty()); trick_play_reference_ids += std::to_string(adaptation_set->id());
id_string.resize(id_string.size() - 1); }
if (!trick_play_reference_ids.empty()) {
adaptation_set.AddEssentialProperty( adaptation_set.AddEssentialProperty(
"http://dashif.org/guidelines/trickmode", id_string); "http://dashif.org/guidelines/trickmode", trick_play_reference_ids);
} }
std::string switching_ids; std::string switching_ids;
for (uint32_t id : adaptation_set_switching_ids_) { for (const AdaptationSet* adaptation_set : switchable_adaptation_sets_) {
if (!switching_ids.empty()) if (!switching_ids.empty())
switching_ids += ','; switching_ids += ',';
switching_ids += base::UintToString(id); CHECK(adaptation_set->has_id());
switching_ids += std::to_string(adaptation_set->id());
} }
if (!switching_ids.empty()) { if (!switching_ids.empty()) {
adaptation_set.AddSupplementalProperty( adaptation_set.AddSupplementalProperty(
@ -343,8 +344,9 @@ void AdaptationSet::ForceSetSegmentAlignment(bool segment_alignment) {
force_set_segment_alignment_ = true; force_set_segment_alignment_ = true;
} }
void AdaptationSet::AddAdaptationSetSwitching(uint32_t adaptation_set_id) { void AdaptationSet::AddAdaptationSetSwitching(
adaptation_set_switching_ids_.push_back(adaptation_set_id); const AdaptationSet* adaptation_set) {
switchable_adaptation_sets_.push_back(adaptation_set);
} }
// Check segmentAlignment for Live here. Storing all start_time and duration // Check segmentAlignment for Live here. Storing all start_time and duration
@ -371,8 +373,8 @@ void AdaptationSet::OnSetFrameRateForRepresentation(uint32_t representation_id,
RecordFrameRate(frame_duration, timescale); RecordFrameRate(frame_duration, timescale);
} }
void AdaptationSet::AddTrickPlayReferenceId(uint32_t id) { void AdaptationSet::AddTrickPlayReference(const AdaptationSet* adaptation_set) {
trick_play_reference_ids_.insert(id); trick_play_references_.push_back(adaptation_set);
} }
const std::list<Representation*> AdaptationSet::GetRepresentations() const { const std::list<Representation*> AdaptationSet::GetRepresentations() const {

View File

@ -18,6 +18,7 @@
#include <vector> #include <vector>
#include "packager/base/atomic_sequence_num.h" #include "packager/base/atomic_sequence_num.h"
#include "packager/base/optional.h"
#include "packager/mpd/base/xml/scoped_xml_ptr.h" #include "packager/mpd/base/xml/scoped_xml_ptr.h"
namespace shaka { namespace shaka {
@ -113,12 +114,15 @@ class AdaptationSet {
/// attribute. /// attribute.
virtual void ForceSetSegmentAlignment(bool segment_alignment); virtual void ForceSetSegmentAlignment(bool segment_alignment);
/// Adds the id of the adaptation set this adaptation set can switch to. /// Adds the adaptation set this adaptation set can switch to.
/// @param adaptation_set_id is the id of the switchable adaptation set. /// @param adaptation_set points to the switchable adaptation set.
virtual void AddAdaptationSetSwitching(uint32_t adaptation_set_id); virtual void AddAdaptationSetSwitching(const AdaptationSet* adaptation_set);
/// @return true if id is set, false otherwise.
bool has_id() const { return static_cast<bool>(id_); }
// Must be unique in the Period. // Must be unique in the Period.
uint32_t id() const { return id_; } uint32_t id() const { return id_.value(); }
/// Set AdaptationSet@id. /// Set AdaptationSet@id.
/// @param id is the new ID to be set. /// @param id is the new ID to be set.
@ -155,10 +159,9 @@ class AdaptationSet {
uint32_t frame_duration, uint32_t frame_duration,
uint32_t timescale); uint32_t timescale);
/// Add the id of the adaptation set this trick play adaptation set belongs /// Add the adaptation set this trick play adaptation set belongs to.
/// to. /// @param adaptation_set points to the reference (or main) adapation set.
/// @param id the id of the reference (or main) adapation set. virtual void AddTrickPlayReference(const AdaptationSet* adaptation_set);
virtual void AddTrickPlayReferenceId(uint32_t id);
// Return the list of Representations in this AdaptationSet. // Return the list of Representations in this AdaptationSet.
const std::list<Representation*> GetRepresentations() const; const std::list<Representation*> GetRepresentations() const;
@ -167,15 +170,13 @@ class AdaptationSet {
bool IsVideo() const; bool IsVideo() const;
protected: protected:
/// @param adaptation_set_id is an ID number for this AdaptationSet.
/// @param lang is the language of this AdaptationSet. Mainly relevant for /// @param lang is the language of this AdaptationSet. Mainly relevant for
/// audio. /// audio.
/// @param mpd_options is the options for this MPD. /// @param mpd_options is the options for this MPD.
/// @param mpd_type is the type of this MPD. /// @param mpd_type is the type of this MPD.
/// @param representation_counter is a Counter for assigning ID numbers to /// @param representation_counter is a Counter for assigning ID numbers to
/// Representation. It can not be NULL. /// Representation. It can not be NULL.
AdaptationSet(uint32_t adaptation_set_id, AdaptationSet(const std::string& lang,
const std::string& lang,
const MpdOptions& mpd_options, const MpdOptions& mpd_options,
base::AtomicSequenceNumber* representation_counter); base::AtomicSequenceNumber* representation_counter);
@ -235,12 +236,12 @@ class AdaptationSet {
base::AtomicSequenceNumber* const representation_counter_; base::AtomicSequenceNumber* const representation_counter_;
uint32_t id_; base::Optional<uint32_t> id_;
const std::string lang_; const std::string lang_;
const MpdOptions& mpd_options_; const MpdOptions& mpd_options_;
// The ids of the adaptation sets this adaptation set can switch to. // An array of adaptation sets this adaptation set can switch to.
std::vector<uint32_t> adaptation_set_switching_ids_; std::vector<const AdaptationSet*> switchable_adaptation_sets_;
// Video widths and heights of Representations. Note that this is a set; if // Video widths and heights of Representations. Note that this is a set; if
// there is only 1 resolution, then @width & @height should be set, otherwise // there is only 1 resolution, then @width & @height should be set, otherwise
@ -286,11 +287,11 @@ class AdaptationSet {
// reasonable and may cause an out-of-memory problem. // reasonable and may cause an out-of-memory problem.
RepresentationTimeline representation_segment_start_times_; RepresentationTimeline representation_segment_start_times_;
// Record the reference id for the original adaptation sets the trick play // Record the original AdaptationSets the trick play stream belongs to. There
// stream belongs to. This is a set because the trick play streams may be for // can be more than one reference AdaptationSets as multiple streams e.g. SD
// multiple AdaptationSets (e.g. SD and HD videos in different AdaptationSets // and HD videos in different AdaptationSets can share the same trick play
// can share the same trick play stream.) // stream.
std::set<uint32_t> trick_play_reference_ids_; std::vector<const AdaptationSet*> trick_play_references_;
}; };
} // namespace shaka } // namespace shaka

View File

@ -21,16 +21,14 @@ using ::testing::Not;
namespace shaka { namespace shaka {
namespace { namespace {
const uint32_t kAnyAdaptationSetId = 1;
const char kNoLanguage[] = ""; const char kNoLanguage[] = "";
} // namespace } // namespace
class AdaptationSetTest : public ::testing::Test { class AdaptationSetTest : public ::testing::Test {
public: public:
std::unique_ptr<AdaptationSet> CreateAdaptationSet(uint32_t adaptation_set_id, std::unique_ptr<AdaptationSet> CreateAdaptationSet(const std::string& lang) {
const std::string& lang) { return std::unique_ptr<AdaptationSet>(
return std::unique_ptr<AdaptationSet>(new AdaptationSet( new AdaptationSet(lang, mpd_options_, &representation_counter_));
adaptation_set_id, lang, mpd_options_, &representation_counter_));
} }
protected: protected:
@ -49,15 +47,24 @@ class LiveAdaptationSetTest : public AdaptationSetTest {
}; };
TEST_F(AdaptationSetTest, AddAdaptationSetSwitching) { TEST_F(AdaptationSetTest, AddAdaptationSetSwitching) {
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
adaptation_set->AddAdaptationSetSwitching(1);
adaptation_set->AddAdaptationSetSwitching(2); auto adaptation_set_1 = CreateAdaptationSet(kNoLanguage);
adaptation_set->AddAdaptationSetSwitching(8); adaptation_set_1->set_id(1);
adaptation_set->AddAdaptationSetSwitching(adaptation_set_1.get());
auto adaptation_set_2 = CreateAdaptationSet(kNoLanguage);
adaptation_set_2->set_id(2);
adaptation_set->AddAdaptationSetSwitching(adaptation_set_2.get());
auto adaptation_set_8 = CreateAdaptationSet(kNoLanguage);
adaptation_set_8->set_id(8);
adaptation_set->AddAdaptationSetSwitching(adaptation_set_8.get());
// The empty contentType is sort of a side effect of being able to generate an // The empty contentType is sort of a side effect of being able to generate an
// MPD without adding any Representations. // MPD without adding any Representations.
const char kExpectedOutput[] = const char kExpectedOutput[] =
"<AdaptationSet id=\"1\" contentType=\"\">" "<AdaptationSet contentType=\"\">"
" <SupplementalProperty " " <SupplementalProperty "
" schemeIdUri=\"urn:mpeg:dash:adaptation-set-switching:2016\" " " schemeIdUri=\"urn:mpeg:dash:adaptation-set-switching:2016\" "
" value=\"1,2,8\"/>" " value=\"1,2,8\"/>"
@ -80,7 +87,7 @@ TEST_F(AdaptationSetTest, CheckAdaptationSetVideoContentType) {
"}\n" "}\n"
"container_type: CONTAINER_MP4\n"; "container_type: CONTAINER_MP4\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo)); adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo));
EXPECT_THAT(adaptation_set->GetXml().get(), EXPECT_THAT(adaptation_set->GetXml().get(),
AttributeEqual("contentType", "video")); AttributeEqual("contentType", "video"));
@ -98,7 +105,7 @@ TEST_F(AdaptationSetTest, CheckAdaptationSetAudioContentType) {
"}\n" "}\n"
"container_type: CONTAINER_MP4\n"; "container_type: CONTAINER_MP4\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
adaptation_set->AddRepresentation(ConvertToMediaInfo(kAudioMediaInfo)); adaptation_set->AddRepresentation(ConvertToMediaInfo(kAudioMediaInfo));
EXPECT_THAT(adaptation_set->GetXml().get(), EXPECT_THAT(adaptation_set->GetXml().get(),
AttributeEqual("contentType", "audio")); AttributeEqual("contentType", "audio"));
@ -114,7 +121,7 @@ TEST_F(AdaptationSetTest, CheckAdaptationSetTextContentType) {
"}\n" "}\n"
"container_type: CONTAINER_TEXT\n"; "container_type: CONTAINER_TEXT\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, "en"); auto adaptation_set = CreateAdaptationSet("en");
adaptation_set->AddRepresentation(ConvertToMediaInfo(kTextMediaInfo)); adaptation_set->AddRepresentation(ConvertToMediaInfo(kTextMediaInfo));
EXPECT_THAT(adaptation_set->GetXml().get(), EXPECT_THAT(adaptation_set->GetXml().get(),
AttributeEqual("contentType", "text")); AttributeEqual("contentType", "text"));
@ -133,7 +140,7 @@ TEST_F(AdaptationSetTest, CopyRepresentation) {
"}\n" "}\n"
"container_type: CONTAINER_MP4\n"; "container_type: CONTAINER_MP4\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
Representation* representation = Representation* representation =
adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo)); adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo));
@ -144,7 +151,7 @@ TEST_F(AdaptationSetTest, CopyRepresentation) {
// Verify that language passed to the constructor sets the @lang field is set. // Verify that language passed to the constructor sets the @lang field is set.
TEST_F(AdaptationSetTest, CheckLanguageAttributeSet) { TEST_F(AdaptationSetTest, CheckLanguageAttributeSet) {
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, "en"); auto adaptation_set = CreateAdaptationSet("en");
EXPECT_THAT(adaptation_set->GetXml().get(), AttributeEqual("lang", "en")); EXPECT_THAT(adaptation_set->GetXml().get(), AttributeEqual("lang", "en"));
} }
@ -152,26 +159,27 @@ TEST_F(AdaptationSetTest, CheckLanguageAttributeSet) {
TEST_F(AdaptationSetTest, CheckConvertLanguageWithSubtag) { TEST_F(AdaptationSetTest, CheckConvertLanguageWithSubtag) {
// "por-BR" is the long tag for Brazillian Portuguese. The short tag // "por-BR" is the long tag for Brazillian Portuguese. The short tag
// is "pt-BR", which is what should appear in the manifest. // is "pt-BR", which is what should appear in the manifest.
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, "por-BR"); auto adaptation_set = CreateAdaptationSet("por-BR");
EXPECT_THAT(adaptation_set->GetXml().get(), AttributeEqual("lang", "pt-BR")); EXPECT_THAT(adaptation_set->GetXml().get(), AttributeEqual("lang", "pt-BR"));
} }
TEST_F(AdaptationSetTest, CheckAdaptationSetId) { TEST_F(AdaptationSetTest, CheckAdaptationSetId) {
auto adaptation_set = CreateAdaptationSet(kNoLanguage);
const uint32_t kAdaptationSetId = 42; const uint32_t kAdaptationSetId = 42;
auto adaptation_set = CreateAdaptationSet(kAdaptationSetId, kNoLanguage); adaptation_set->set_id(kAdaptationSetId);
EXPECT_THAT(adaptation_set->GetXml().get(), EXPECT_THAT(adaptation_set->GetXml().get(),
AttributeEqual("id", std::to_string(kAdaptationSetId))); AttributeEqual("id", std::to_string(kAdaptationSetId)));
} }
// Verify AdaptationSet::AddRole() works for "main" role. // Verify AdaptationSet::AddRole() works for "main" role.
TEST_F(AdaptationSetTest, AdaptationAddRoleElementMain) { TEST_F(AdaptationSetTest, AdaptationAddRoleElementMain) {
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
adaptation_set->AddRole(AdaptationSet::kRoleMain); adaptation_set->AddRole(AdaptationSet::kRoleMain);
// The empty contentType is sort of a side effect of being able to generate an // The empty contentType is sort of a side effect of being able to generate an
// MPD without adding any Representations. // MPD without adding any Representations.
const char kExpectedOutput[] = const char kExpectedOutput[] =
"<AdaptationSet id=\"1\" contentType=\"\">\n" "<AdaptationSet contentType=\"\">\n"
" <Role schemeIdUri=\"urn:mpeg:dash:role:2011\" value=\"main\"/>\n" " <Role schemeIdUri=\"urn:mpeg:dash:role:2011\" value=\"main\"/>\n"
"</AdaptationSet>"; "</AdaptationSet>";
EXPECT_THAT(adaptation_set->GetXml().get(), XmlNodeEqual(kExpectedOutput)); EXPECT_THAT(adaptation_set->GetXml().get(), XmlNodeEqual(kExpectedOutput));
@ -180,7 +188,7 @@ TEST_F(AdaptationSetTest, AdaptationAddRoleElementMain) {
// Add Role, ContentProtection, and Representation elements. Verify that // Add Role, ContentProtection, and Representation elements. Verify that
// ContentProtection -> Role -> Representation are in order. // ContentProtection -> Role -> Representation are in order.
TEST_F(AdaptationSetTest, CheckContentProtectionRoleRepresentationOrder) { TEST_F(AdaptationSetTest, CheckContentProtectionRoleRepresentationOrder) {
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
adaptation_set->AddRole(AdaptationSet::kRoleMain); adaptation_set->AddRole(AdaptationSet::kRoleMain);
ContentProtectionElement any_content_protection; ContentProtectionElement any_content_protection;
any_content_protection.scheme_id_uri = "any_scheme"; any_content_protection.scheme_id_uri = "any_scheme";
@ -197,7 +205,7 @@ TEST_F(AdaptationSetTest, CheckContentProtectionRoleRepresentationOrder) {
xml::scoped_xml_ptr<xmlNode> adaptation_set_xml(adaptation_set->GetXml()); xml::scoped_xml_ptr<xmlNode> adaptation_set_xml(adaptation_set->GetXml());
const char kExpectedOutput[] = const char kExpectedOutput[] =
"<AdaptationSet id=\"1\" contentType=\"audio\">\n" "<AdaptationSet contentType=\"audio\">\n"
" <ContentProtection schemeIdUri=\"any_scheme\"/>\n" " <ContentProtection schemeIdUri=\"any_scheme\"/>\n"
" <Role schemeIdUri=\"urn:mpeg:dash:role:2011\" value=\"main\"/>\n" " <Role schemeIdUri=\"urn:mpeg:dash:role:2011\" value=\"main\"/>\n"
" <Representation id=\"0\" bandwidth=\"0\" codecs=\"mp4a.40.2\"\n" " <Representation id=\"0\" bandwidth=\"0\" codecs=\"mp4a.40.2\"\n"
@ -232,7 +240,7 @@ TEST_F(AdaptationSetTest, AdapatationSetFrameRate) {
" frame_duration: 3\n" " frame_duration: 3\n"
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE( ASSERT_TRUE(
adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo1))); adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo1)));
ASSERT_TRUE( ASSERT_TRUE(
@ -265,7 +273,7 @@ TEST_F(AdaptationSetTest, AdapatationSetMaxFrameRate) {
" frame_duration: 200\n" " frame_duration: 200\n"
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE(adaptation_set->AddRepresentation( ASSERT_TRUE(adaptation_set->AddRepresentation(
ConvertToMediaInfo(kVideoMediaInfo30fps))); ConvertToMediaInfo(kVideoMediaInfo30fps)));
ASSERT_TRUE(adaptation_set->AddRepresentation( ASSERT_TRUE(adaptation_set->AddRepresentation(
@ -307,7 +315,7 @@ TEST_F(AdaptationSetTest,
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
Representation* representation_480p = Representation* representation_480p =
adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pMediaInfo)); adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pMediaInfo));
Representation* representation_360p = Representation* representation_360p =
@ -391,7 +399,7 @@ TEST_F(AdaptationSetTest, AdaptationSetParAllSame) {
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE( ASSERT_TRUE(
adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pVideoInfo))); adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pVideoInfo)));
ASSERT_TRUE( ASSERT_TRUE(
@ -432,7 +440,7 @@ TEST_F(AdaptationSetTest, AdaptationSetParDifferent) {
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE( ASSERT_TRUE(
adaptation_set->AddRepresentation(ConvertToMediaInfo(k16by9VideoInfo))); adaptation_set->AddRepresentation(ConvertToMediaInfo(k16by9VideoInfo)));
ASSERT_TRUE( ASSERT_TRUE(
@ -455,7 +463,7 @@ TEST_F(AdaptationSetTest, AdaptationSetParUnknown) {
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE(adaptation_set->AddRepresentation( ASSERT_TRUE(adaptation_set->AddRepresentation(
ConvertToMediaInfo(kUknownPixelWidthAndHeight))); ConvertToMediaInfo(kUknownPixelWidthAndHeight)));
@ -487,7 +495,7 @@ TEST_F(AdaptationSetTest, AdapatationSetMaxFrameRateIntegerDivisionEdgeCase) {
" frame_duration: 3\n" " frame_duration: 3\n"
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE( ASSERT_TRUE(
adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo1))); adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo1)));
ASSERT_TRUE( ASSERT_TRUE(
@ -552,7 +560,7 @@ TEST_F(AdaptationSetTest, BubbleUpAttributesToAdaptationSet) {
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE(adaptation_set->AddRepresentation(ConvertToMediaInfo(k1080p))); ASSERT_TRUE(adaptation_set->AddRepresentation(ConvertToMediaInfo(k1080p)));
xml::scoped_xml_ptr<xmlNode> all_attributes_on_adaptation_set( xml::scoped_xml_ptr<xmlNode> all_attributes_on_adaptation_set(
@ -610,7 +618,7 @@ TEST_F(AdaptationSetTest, GetRepresentations) {
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
Representation* representation1 = Representation* representation1 =
adaptation_set->AddRepresentation(ConvertToMediaInfo(kMediaInfo1)); adaptation_set->AddRepresentation(ConvertToMediaInfo(kMediaInfo1));
@ -622,8 +630,7 @@ TEST_F(AdaptationSetTest, GetRepresentations) {
EXPECT_THAT(adaptation_set->GetRepresentations(), EXPECT_THAT(adaptation_set->GetRepresentations(),
ElementsAre(representation1, representation2)); ElementsAre(representation1, representation2));
auto new_adaptation_set = auto new_adaptation_set = CreateAdaptationSet(kNoLanguage);
CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage);
Representation* new_representation2 = Representation* new_representation2 =
new_adaptation_set->CopyRepresentation(*representation2); new_adaptation_set->CopyRepresentation(*representation2);
Representation* new_representation1 = Representation* new_representation1 =
@ -668,7 +675,7 @@ TEST_F(OnDemandAdaptationSetTest, SubsegmentAlignment) {
const uint64_t kDuration = 10u; const uint64_t kDuration = 10u;
const uint64_t kAnySize = 19834u; const uint64_t kAnySize = 19834u;
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
Representation* representation_480p = Representation* representation_480p =
adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pMediaInfo)); adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pMediaInfo));
// Add a subsegment immediately before adding the 360p Representation. // Add a subsegment immediately before adding the 360p Representation.
@ -720,7 +727,7 @@ TEST_F(OnDemandAdaptationSetTest, ForceSetsubsegmentAlignment) {
" pixel_height: 1\n" " pixel_height: 1\n"
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
Representation* representation_480p = Representation* representation_480p =
adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pMediaInfo)); adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pMediaInfo));
Representation* representation_360p = Representation* representation_360p =
@ -768,7 +775,7 @@ TEST_F(LiveAdaptationSetTest, SegmentAlignment) {
" pixel_height: 1\n" " pixel_height: 1\n"
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
Representation* representation_480p = Representation* representation_480p =
adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pMediaInfo)); adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pMediaInfo));
Representation* representation_360p = Representation* representation_360p =
@ -815,7 +822,7 @@ TEST_F(OnDemandAdaptationSetTest, AdapatationSetWidthAndHeight) {
" frame_duration: 200\n" " frame_duration: 200\n"
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE( ASSERT_TRUE(
adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo1))); adaptation_set->AddRepresentation(ConvertToMediaInfo(kVideoMediaInfo1)));
ASSERT_TRUE( ASSERT_TRUE(
@ -849,7 +856,7 @@ TEST_F(OnDemandAdaptationSetTest, AdaptationSetMaxWidthAndMaxHeight) {
" frame_duration: 100\n" " frame_duration: 100\n"
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE(adaptation_set->AddRepresentation( ASSERT_TRUE(adaptation_set->AddRepresentation(
ConvertToMediaInfo(kVideoMediaInfo1080p))); ConvertToMediaInfo(kVideoMediaInfo1080p)));
ASSERT_TRUE(adaptation_set->AddRepresentation( ASSERT_TRUE(adaptation_set->AddRepresentation(
@ -875,7 +882,7 @@ TEST_F(AdaptationSetTest, SetSampleDuration) {
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
const MediaInfo video_media_info = ConvertToMediaInfo(kVideoMediaInfo); const MediaInfo video_media_info = ConvertToMediaInfo(kVideoMediaInfo);
Representation* representation = Representation* representation =
@ -911,13 +918,13 @@ TEST_F(AdaptationSetTest, AdaptationSetAddContentProtectionAndUpdate) {
pssh.content = "any value"; pssh.content = "any value";
content_protection.subelements.push_back(pssh); content_protection.subelements.push_back(pssh);
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE(adaptation_set->AddRepresentation( ASSERT_TRUE(adaptation_set->AddRepresentation(
ConvertToMediaInfo(kVideoMediaInfo1080p))); ConvertToMediaInfo(kVideoMediaInfo1080p)));
adaptation_set->AddContentProtectionElement(content_protection); adaptation_set->AddContentProtectionElement(content_protection);
const char kExpectedOutput1[] = const char kExpectedOutput1[] =
"<AdaptationSet id=\"1\" contentType=\"video\" width=\"1920\"" "<AdaptationSet contentType=\"video\" width=\"1920\""
" height=\"1080\" frameRate=\"3000/100\">" " height=\"1080\" frameRate=\"3000/100\">"
" <ContentProtection" " <ContentProtection"
" schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\"" " schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\""
@ -932,7 +939,7 @@ TEST_F(AdaptationSetTest, AdaptationSetAddContentProtectionAndUpdate) {
adaptation_set->UpdateContentProtectionPssh( adaptation_set->UpdateContentProtectionPssh(
"edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", "new pssh value"); "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", "new pssh value");
const char kExpectedOutput2[] = const char kExpectedOutput2[] =
"<AdaptationSet id=\"1\" contentType=\"video\" width=\"1920\"" "<AdaptationSet contentType=\"video\" width=\"1920\""
" height=\"1080\" frameRate=\"3000/100\">" " height=\"1080\" frameRate=\"3000/100\">"
" <ContentProtection" " <ContentProtection"
" schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\"" " schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\""
@ -967,13 +974,13 @@ TEST_F(AdaptationSetTest, UpdateToRemovePsshElement) {
"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"; "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed";
content_protection.value = "some value"; content_protection.value = "some value";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
ASSERT_TRUE(adaptation_set->AddRepresentation( ASSERT_TRUE(adaptation_set->AddRepresentation(
ConvertToMediaInfo(kVideoMediaInfo1080p))); ConvertToMediaInfo(kVideoMediaInfo1080p)));
adaptation_set->AddContentProtectionElement(content_protection); adaptation_set->AddContentProtectionElement(content_protection);
const char kExpectedOutput1[] = const char kExpectedOutput1[] =
"<AdaptationSet id=\"1\" contentType=\"video\" width=\"1920\"" "<AdaptationSet contentType=\"video\" width=\"1920\""
" height=\"1080\" frameRate=\"3000/100\">" " height=\"1080\" frameRate=\"3000/100\">"
" <ContentProtection" " <ContentProtection"
" schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\"" " schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\""
@ -987,7 +994,7 @@ TEST_F(AdaptationSetTest, UpdateToRemovePsshElement) {
adaptation_set->UpdateContentProtectionPssh( adaptation_set->UpdateContentProtectionPssh(
"edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", "added pssh value"); "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", "added pssh value");
const char kExpectedOutput2[] = const char kExpectedOutput2[] =
"<AdaptationSet id=\"1\" contentType=\"video\" width=\"1920\"" "<AdaptationSet contentType=\"video\" width=\"1920\""
" height=\"1080\" frameRate=\"3000/100\">" " height=\"1080\" frameRate=\"3000/100\">"
" <ContentProtection" " <ContentProtection"
" schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\"" " schemeIdUri=\"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\""
@ -1030,7 +1037,7 @@ TEST_F(OnDemandAdaptationSetTest,
"container_type: CONTAINER_MP4\n"; "container_type: CONTAINER_MP4\n";
const char kExpectedOutput[] = const char kExpectedOutput[] =
"<AdaptationSet id=\"1\" contentType=\"audio\">" "<AdaptationSet contentType=\"audio\">"
" <Representation id=\"0\" bandwidth=\"195857\" codecs=\"mp4a.40.2\"" " <Representation id=\"0\" bandwidth=\"195857\" codecs=\"mp4a.40.2\""
" mimeType=\"audio/mp4\" audioSamplingRate=\"44100\">" " mimeType=\"audio/mp4\" audioSamplingRate=\"44100\">"
" <AudioChannelConfiguration" " <AudioChannelConfiguration"
@ -1054,7 +1061,7 @@ TEST_F(OnDemandAdaptationSetTest,
pssh.content = "anything"; pssh.content = "anything";
content_protection.subelements.push_back(pssh); content_protection.subelements.push_back(pssh);
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage); auto adaptation_set = CreateAdaptationSet(kNoLanguage);
Representation* audio_representation = Representation* audio_representation =
adaptation_set->AddRepresentation(ConvertToMediaInfo(kTestMediaInfo)); adaptation_set->AddRepresentation(ConvertToMediaInfo(kTestMediaInfo));
ASSERT_TRUE(audio_representation); ASSERT_TRUE(audio_representation);
@ -1076,7 +1083,7 @@ TEST_F(OnDemandAdaptationSetTest, Text) {
"container_type: CONTAINER_TEXT\n"; "container_type: CONTAINER_TEXT\n";
const char kExpectedOutput[] = const char kExpectedOutput[] =
"<AdaptationSet id=\"1\" contentType=\"text\" lang=\"en\">" "<AdaptationSet contentType=\"text\" lang=\"en\">"
" <Role schemeIdUri=\"urn:mpeg:dash:role:2011\"" " <Role schemeIdUri=\"urn:mpeg:dash:role:2011\""
" value=\"subtitle\"/>\n" " value=\"subtitle\"/>\n"
" <Representation id=\"0\" bandwidth=\"1000\"" " <Representation id=\"0\" bandwidth=\"1000\""
@ -1085,7 +1092,7 @@ TEST_F(OnDemandAdaptationSetTest, Text) {
" </Representation>" " </Representation>"
"</AdaptationSet>"; "</AdaptationSet>";
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, "en"); auto adaptation_set = CreateAdaptationSet("en");
Representation* text_representation = Representation* text_representation =
adaptation_set->AddRepresentation(ConvertToMediaInfo(kTextMediaInfo)); adaptation_set->AddRepresentation(ConvertToMediaInfo(kTextMediaInfo));
ASSERT_TRUE(text_representation); ASSERT_TRUE(text_representation);

View File

@ -17,14 +17,10 @@ MockPeriod::MockPeriod(uint32_t period_id, double start_time_in_seconds)
: Period(period_id, : Period(period_id,
start_time_in_seconds, start_time_in_seconds,
kDefaultMpdOptions, kDefaultMpdOptions,
&sequence_counter_,
&sequence_counter_) {} &sequence_counter_) {}
MockAdaptationSet::MockAdaptationSet(uint32_t adaptation_set_id) MockAdaptationSet::MockAdaptationSet()
: AdaptationSet(adaptation_set_id, : AdaptationSet(kEmptyLang, kDefaultMpdOptions, &sequence_counter_) {}
kEmptyLang,
kDefaultMpdOptions,
&sequence_counter_) {}
MockAdaptationSet::~MockAdaptationSet() {} MockAdaptationSet::~MockAdaptationSet() {}
MockRepresentation::MockRepresentation(uint32_t representation_id) MockRepresentation::MockRepresentation(uint32_t representation_id)

View File

@ -43,8 +43,7 @@ class MockPeriod : public Period {
class MockAdaptationSet : public AdaptationSet { class MockAdaptationSet : public AdaptationSet {
public: public:
// |adaptation_set_id| is the id for the AdaptationSet. MockAdaptationSet();
explicit MockAdaptationSet(uint32_t adaptation_set_id);
~MockAdaptationSet() override; ~MockAdaptationSet() override;
MOCK_METHOD1(AddRepresentation, Representation*(const MediaInfo& media_info)); MOCK_METHOD1(AddRepresentation, Representation*(const MediaInfo& media_info));
@ -56,8 +55,10 @@ class MockAdaptationSet : public AdaptationSet {
void(const std::string& drm_uuid, const std::string& pssh)); void(const std::string& drm_uuid, const std::string& pssh));
MOCK_METHOD1(AddRole, void(AdaptationSet::Role role)); MOCK_METHOD1(AddRole, void(AdaptationSet::Role role));
MOCK_METHOD1(ForceSetSegmentAlignment, void(bool segment_alignment)); MOCK_METHOD1(ForceSetSegmentAlignment, void(bool segment_alignment));
MOCK_METHOD1(AddAdaptationSetSwitching, void(uint32_t adaptation_set_id)); MOCK_METHOD1(AddAdaptationSetSwitching,
MOCK_METHOD1(AddTrickPlayReferenceId, void(uint32_t id)); void(const AdaptationSet* adaptation_set));
MOCK_METHOD1(AddTrickPlayReference,
void(const AdaptationSet* adaptation_set));
private: private:
// Only for constructing the super class. Not used for testing. // Only for constructing the super class. Not used for testing.

View File

@ -131,9 +131,9 @@ Period* MpdBuilder::GetOrCreatePeriod(double start_time_in_seconds) {
if (match) if (match)
return period.get(); return period.get();
} }
periods_.emplace_back( periods_.emplace_back(new Period(period_counter_.GetNext(),
new Period(period_counter_.GetNext(), start_time_in_seconds, mpd_options_, start_time_in_seconds, mpd_options_,
&adaptation_set_counter_, &representation_counter_)); &representation_counter_));
return periods_.back().get(); return periods_.back().get();
} }

View File

@ -120,7 +120,6 @@ class MpdBuilder {
std::string availability_start_time_; std::string availability_start_time_;
base::AtomicSequenceNumber period_counter_; base::AtomicSequenceNumber period_counter_;
base::AtomicSequenceNumber adaptation_set_counter_;
base::AtomicSequenceNumber representation_counter_; base::AtomicSequenceNumber representation_counter_;
// By default, this returns the current time. This can be injected for // By default, this returns the current time. This can be injected for

View File

@ -37,12 +37,10 @@ std::set<std::string> GetUUIDs(
Period::Period(uint32_t period_id, Period::Period(uint32_t period_id,
double start_time_in_seconds, double start_time_in_seconds,
const MpdOptions& mpd_options, const MpdOptions& mpd_options,
base::AtomicSequenceNumber* adaptation_set_counter,
base::AtomicSequenceNumber* representation_counter) base::AtomicSequenceNumber* representation_counter)
: id_(period_id), : id_(period_id),
start_time_in_seconds_(start_time_in_seconds), start_time_in_seconds_(start_time_in_seconds),
mpd_options_(mpd_options), mpd_options_(mpd_options),
adaptation_set_counter_(adaptation_set_counter),
representation_counter_(representation_counter) {} representation_counter_(representation_counter) {}
AdaptationSet* Period::GetOrCreateAdaptationSet( AdaptationSet* Period::GetOrCreateAdaptationSet(
@ -66,10 +64,9 @@ AdaptationSet* Period::GetOrCreateAdaptationSet(
} }
// None of the adaptation sets match with the new content protection. // None of the adaptation sets match with the new content protection.
// Need a new one. // Need a new one.
std::string language = GetLanguage(media_info); const std::string language = GetLanguage(media_info);
std::unique_ptr<AdaptationSet> new_adaptation_set = std::unique_ptr<AdaptationSet> new_adaptation_set =
NewAdaptationSet(adaptation_set_counter_->GetNext(), language, NewAdaptationSet(language, mpd_options_, representation_counter_);
mpd_options_, representation_counter_);
if (!SetNewAdaptationSetAttributes(language, media_info, adaptation_sets, if (!SetNewAdaptationSetAttributes(language, media_info, adaptation_sets,
new_adaptation_set.get())) { new_adaptation_set.get())) {
return nullptr; return nullptr;
@ -83,25 +80,35 @@ AdaptationSet* Period::GetOrCreateAdaptationSet(
for (AdaptationSet* adaptation_set : adaptation_sets) { for (AdaptationSet* adaptation_set : adaptation_sets) {
if (protected_adaptation_set_map_.Switchable(*adaptation_set, if (protected_adaptation_set_map_.Switchable(*adaptation_set,
*new_adaptation_set)) { *new_adaptation_set)) {
adaptation_set->AddAdaptationSetSwitching(new_adaptation_set->id()); adaptation_set->AddAdaptationSetSwitching(new_adaptation_set.get());
new_adaptation_set->AddAdaptationSetSwitching(adaptation_set->id()); new_adaptation_set->AddAdaptationSetSwitching(adaptation_set);
} }
} }
} }
AdaptationSet* adaptation_set_ptr = new_adaptation_set.get(); AdaptationSet* adaptation_set_ptr = new_adaptation_set.get();
adaptation_sets.push_back(adaptation_set_ptr); adaptation_sets.push_back(adaptation_set_ptr);
adaptation_set_map_[adaptation_set_ptr->id()] = std::move(new_adaptation_set); adaptation_sets_.emplace_back(std::move(new_adaptation_set));
return adaptation_set_ptr; return adaptation_set_ptr;
} }
xml::scoped_xml_ptr<xmlNode> Period::GetXml(bool output_period_duration) const { xml::scoped_xml_ptr<xmlNode> Period::GetXml(bool output_period_duration) {
adaptation_sets_.sort(
[](const std::unique_ptr<AdaptationSet>& adaptation_set_a,
const std::unique_ptr<AdaptationSet>& adaptation_set_b) {
if (!adaptation_set_a->has_id())
return false;
if (!adaptation_set_b->has_id())
return true;
return adaptation_set_a->id() < adaptation_set_b->id();
});
xml::XmlNode period("Period"); xml::XmlNode period("Period");
// Required for 'dynamic' MPDs. // Required for 'dynamic' MPDs.
period.SetId(id_); period.SetId(id_);
// Iterate thru AdaptationSets and add them to one big Period element. // Iterate thru AdaptationSets and add them to one big Period element.
for (const auto& adaptation_set_pair : adaptation_set_map_) { for (const auto& adaptation_set : adaptation_sets_) {
xml::scoped_xml_ptr<xmlNode> child(adaptation_set_pair.second->GetXml()); xml::scoped_xml_ptr<xmlNode> child(adaptation_set->GetXml());
if (!child || !period.AddChild(std::move(child))) if (!child || !period.AddChild(std::move(child)))
return nullptr; return nullptr;
} }
@ -118,19 +125,18 @@ xml::scoped_xml_ptr<xmlNode> Period::GetXml(bool output_period_duration) const {
const std::list<AdaptationSet*> Period::GetAdaptationSets() const { const std::list<AdaptationSet*> Period::GetAdaptationSets() const {
std::list<AdaptationSet*> adaptation_sets; std::list<AdaptationSet*> adaptation_sets;
for (const auto& adaptation_set_pair : adaptation_set_map_) { for (const auto& adaptation_set : adaptation_sets_) {
adaptation_sets.push_back(adaptation_set_pair.second.get()); adaptation_sets.push_back(adaptation_set.get());
} }
return adaptation_sets; return adaptation_sets;
} }
std::unique_ptr<AdaptationSet> Period::NewAdaptationSet( std::unique_ptr<AdaptationSet> Period::NewAdaptationSet(
uint32_t adaptation_set_id,
const std::string& language, const std::string& language,
const MpdOptions& options, const MpdOptions& options,
base::AtomicSequenceNumber* representation_counter) { base::AtomicSequenceNumber* representation_counter) {
return std::unique_ptr<AdaptationSet>(new AdaptationSet( return std::unique_ptr<AdaptationSet>(
adaptation_set_id, language, options, representation_counter)); new AdaptationSet(language, options, representation_counter));
} }
bool Period::SetNewAdaptationSetAttributes( bool Period::SetNewAdaptationSetAttributes(
@ -152,14 +158,14 @@ bool Period::SetNewAdaptationSetAttributes(
} }
if (media_info.video_info().has_playback_rate()) { if (media_info.video_info().has_playback_rate()) {
uint32_t trick_play_reference_id = 0; const AdaptationSet* trick_play_reference_adaptation_set =
if (!FindOriginalAdaptationSetForTrickPlay(media_info, FindOriginalAdaptationSetForTrickPlay(media_info);
&trick_play_reference_id)) { if (!trick_play_reference_adaptation_set) {
LOG(ERROR) << "Failed to find main adaptation set for trick play."; LOG(ERROR) << "Failed to find original AdaptationSet for trick play.";
return false; return false;
} }
DCHECK_NE(new_adaptation_set->id(), trick_play_reference_id); new_adaptation_set->AddTrickPlayReference(
new_adaptation_set->AddTrickPlayReferenceId(trick_play_reference_id); trick_play_reference_adaptation_set);
} }
} else if (media_info.has_text_info()) { } else if (media_info.has_text_info()) {
// IOP requires all AdaptationSets to have (sub)segmentAlignment set to // IOP requires all AdaptationSets to have (sub)segmentAlignment set to
@ -170,9 +176,8 @@ bool Period::SetNewAdaptationSetAttributes(
return true; return true;
} }
bool Period::FindOriginalAdaptationSetForTrickPlay( const AdaptationSet* Period::FindOriginalAdaptationSetForTrickPlay(
const MediaInfo& media_info, const MediaInfo& media_info) {
uint32_t* main_adaptation_set_id) {
MediaInfo media_info_no_trickplay = media_info; MediaInfo media_info_no_trickplay = media_info;
media_info_no_trickplay.mutable_video_info()->clear_playback_rate(); media_info_no_trickplay.mutable_video_info()->clear_playback_rate();
@ -181,25 +186,24 @@ bool Period::FindOriginalAdaptationSetForTrickPlay(
adaptation_set_list_map_[key]; adaptation_set_list_map_[key];
for (AdaptationSet* adaptation_set : adaptation_sets) { for (AdaptationSet* adaptation_set : adaptation_sets) {
if (protected_adaptation_set_map_.Match(*adaptation_set, media_info)) { if (protected_adaptation_set_map_.Match(*adaptation_set, media_info)) {
*main_adaptation_set_id = adaptation_set->id(); return adaptation_set;
return true;
} }
} }
return false; return nullptr;
} }
void Period::ProtectedAdaptationSetMap::Register( void Period::ProtectedAdaptationSetMap::Register(
const AdaptationSet& adaptation_set, const AdaptationSet& adaptation_set,
const MediaInfo& media_info) { const MediaInfo& media_info) {
DCHECK(!ContainsKey(protected_content_map_, adaptation_set.id())); DCHECK(!ContainsKey(protected_content_map_, &adaptation_set));
protected_content_map_[adaptation_set.id()] = media_info.protected_content(); protected_content_map_[&adaptation_set] = media_info.protected_content();
} }
bool Period::ProtectedAdaptationSetMap::Match( bool Period::ProtectedAdaptationSetMap::Match(
const AdaptationSet& adaptation_set, const AdaptationSet& adaptation_set,
const MediaInfo& media_info) { const MediaInfo& media_info) {
const auto protected_content_it = const auto protected_content_it =
protected_content_map_.find(adaptation_set.id()); protected_content_map_.find(&adaptation_set);
// If the AdaptationSet ID is not registered in the map, then it is clear // If the AdaptationSet ID is not registered in the map, then it is clear
// content. // content.
if (protected_content_it == protected_content_map_.end()) if (protected_content_it == protected_content_map_.end())
@ -214,9 +218,9 @@ bool Period::ProtectedAdaptationSetMap::Switchable(
const AdaptationSet& adaptation_set_a, const AdaptationSet& adaptation_set_a,
const AdaptationSet& adaptation_set_b) { const AdaptationSet& adaptation_set_b) {
const auto protected_content_it_a = const auto protected_content_it_a =
protected_content_map_.find(adaptation_set_a.id()); protected_content_map_.find(&adaptation_set_a);
const auto protected_content_it_b = const auto protected_content_it_b =
protected_content_map_.find(adaptation_set_b.id()); protected_content_map_.find(&adaptation_set_b);
if (protected_content_it_a == protected_content_map_.end()) if (protected_content_it_a == protected_content_map_.end())
return protected_content_it_b == protected_content_map_.end(); return protected_content_it_b == protected_content_map_.end();

View File

@ -13,6 +13,7 @@
#include <map> #include <map>
#include "packager/base/atomic_sequence_num.h" #include "packager/base/atomic_sequence_num.h"
#include "packager/base/optional.h"
#include "packager/mpd/base/adaptation_set.h" #include "packager/mpd/base/adaptation_set.h"
#include "packager/mpd/base/media_info.pb.h" #include "packager/mpd/base/media_info.pb.h"
#include "packager/mpd/base/xml/scoped_xml_ptr.h" #include "packager/mpd/base/xml/scoped_xml_ptr.h"
@ -41,6 +42,8 @@ class Period {
/// element. This affects how MediaInfo in AdaptationSets are matched. /// element. This affects how MediaInfo in AdaptationSets are matched.
/// @return the AdaptationSet matching @a media_info if found; otherwise /// @return the AdaptationSet matching @a media_info if found; otherwise
/// return a new AdaptationSet. /// return a new AdaptationSet.
// TODO(kqyang): Move |content_protection_in_adaptation_set| to Period
// constructor.
virtual AdaptationSet* GetOrCreateAdaptationSet( virtual AdaptationSet* GetOrCreateAdaptationSet(
const MediaInfo& media_info, const MediaInfo& media_info,
bool content_protection_in_adaptation_set); bool content_protection_in_adaptation_set);
@ -48,7 +51,7 @@ class Period {
/// Generates <Period> xml element with its child AdaptationSet elements. /// Generates <Period> xml element with its child AdaptationSet elements.
/// @return On success returns a non-NULL scoped_xml_ptr. Otherwise returns a /// @return On success returns a non-NULL scoped_xml_ptr. Otherwise returns a
/// NULL scoped_xml_ptr. /// NULL scoped_xml_ptr.
xml::scoped_xml_ptr<xmlNode> GetXml(bool output_period_duration) const; xml::scoped_xml_ptr<xmlNode> GetXml(bool output_period_duration);
/// @return The list of AdaptationSets in this Period. /// @return The list of AdaptationSets in this Period.
const std::list<AdaptationSet*> GetAdaptationSets() const; const std::list<AdaptationSet*> GetAdaptationSets() const;
@ -68,14 +71,11 @@ class Period {
/// @param period_id is an ID number for this Period. /// @param period_id is an ID number for this Period.
/// @param start_time_in_seconds is the start time for this Period. /// @param start_time_in_seconds is the start time for this Period.
/// @param mpd_options is the options for this MPD. /// @param mpd_options is the options for this MPD.
/// @param adaptation_set_counter is a counter for assigning ID numbers to
/// AdaptationSet. It can not be NULL.
/// @param representation_counter is a counter for assigning ID numbers to /// @param representation_counter is a counter for assigning ID numbers to
/// Representation. It can not be NULL. /// Representation. It can not be NULL.
Period(uint32_t period_id, Period(uint32_t period_id,
double start_time_in_seconds, double start_time_in_seconds,
const MpdOptions& mpd_options, const MpdOptions& mpd_options,
base::AtomicSequenceNumber* adaptation_set_counter,
base::AtomicSequenceNumber* representation_counter); base::AtomicSequenceNumber* representation_counter);
private: private:
@ -87,7 +87,6 @@ class Period {
// Calls AdaptationSet constructor. For mock injection. // Calls AdaptationSet constructor. For mock injection.
virtual std::unique_ptr<AdaptationSet> NewAdaptationSet( virtual std::unique_ptr<AdaptationSet> NewAdaptationSet(
uint32_t adaptation_set_id,
const std::string& lang, const std::string& lang,
const MpdOptions& options, const MpdOptions& options,
base::AtomicSequenceNumber* representation_counter); base::AtomicSequenceNumber* representation_counter);
@ -99,24 +98,19 @@ class Period {
const std::list<AdaptationSet*>& adaptation_sets, const std::list<AdaptationSet*>& adaptation_sets,
AdaptationSet* new_adaptation_set); AdaptationSet* new_adaptation_set);
// Gets the original AdaptationSet which the trick play video belongs // Gets the original AdaptationSet which the trick play video belongs to.
// to and returns the id of the original adapatation set.
// It is assumed that the corresponding AdaptationSet has been created before // It is assumed that the corresponding AdaptationSet has been created before
// the trick play AdaptationSet. // the trick play AdaptationSet.
// Returns true if main_adaptation_id is found, otherwise false; // Returns the original AdaptationSet if found, otherwise returns nullptr;
bool FindOriginalAdaptationSetForTrickPlay( const AdaptationSet* FindOriginalAdaptationSetForTrickPlay(
const MediaInfo& media_info, const MediaInfo& media_info);
uint32_t* original_adaptation_set_id);
const uint32_t id_; const uint32_t id_;
const double start_time_in_seconds_; const double start_time_in_seconds_;
double duration_seconds_ = 0; double duration_seconds_ = 0;
const MpdOptions& mpd_options_; const MpdOptions& mpd_options_;
base::AtomicSequenceNumber* const adaptation_set_counter_;
base::AtomicSequenceNumber* const representation_counter_; base::AtomicSequenceNumber* const representation_counter_;
// adaptation_id => Adaptation map. It also keeps the adaptation_sets_ sorted std::list<std::unique_ptr<AdaptationSet>> adaptation_sets_;
// by default.
std::map<uint32_t, std::unique_ptr<AdaptationSet>> adaptation_set_map_;
// AdaptationSets grouped by a specific adaptation set grouping key. // AdaptationSets grouped by a specific adaptation set grouping key.
// AdaptationSets with the same key contain identical parameters except // AdaptationSets with the same key contain identical parameters except
// ContentProtection parameters. A single AdaptationSet would be created // ContentProtection parameters. A single AdaptationSet would be created
@ -144,8 +138,9 @@ class Period {
ProtectedAdaptationSetMap& operator=(const ProtectedAdaptationSetMap&) = ProtectedAdaptationSetMap& operator=(const ProtectedAdaptationSetMap&) =
delete; delete;
// AdaptationSet id => ProtectedContent map. // AdaptationSet => ProtectedContent map.
std::map<uint32_t, MediaInfo::ProtectedContent> protected_content_map_; std::map<const AdaptationSet*, MediaInfo::ProtectedContent>
protected_content_map_;
}; };
ProtectedAdaptationSetMap protected_adaptation_set_map_; ProtectedAdaptationSetMap protected_adaptation_set_map_;
}; };

View File

@ -26,8 +26,6 @@ namespace shaka {
namespace { namespace {
const uint32_t kDefaultPeriodId = 9u; const uint32_t kDefaultPeriodId = 9u;
const double kDefaultPeriodStartTime = 5.6; const double kDefaultPeriodStartTime = 5.6;
const uint32_t kDefaultAdaptationSetId = 0u;
const uint32_t kTrickPlayAdaptationSetId = 1u;
const bool kOutputPeriodDuration = true; const bool kOutputPeriodDuration = true;
bool ElementEqual(const Element& lhs, const Element& rhs) { bool ElementEqual(const Element& lhs, const Element& rhs) {
@ -80,12 +78,10 @@ class TestablePeriod : public Period {
: Period(kDefaultPeriodId, : Period(kDefaultPeriodId,
kDefaultPeriodStartTime, kDefaultPeriodStartTime,
mpd_options, mpd_options,
&sequence_number_,
&sequence_number_) {} &sequence_number_) {}
MOCK_METHOD4(NewAdaptationSet, MOCK_METHOD3(NewAdaptationSet,
std::unique_ptr<AdaptationSet>( std::unique_ptr<AdaptationSet>(
uint32_t adaptation_set_id,
const std::string& lang, const std::string& lang,
const MpdOptions& options, const MpdOptions& options,
base::AtomicSequenceNumber* representation_counter)); base::AtomicSequenceNumber* representation_counter));
@ -101,8 +97,7 @@ class PeriodTest : public ::testing::TestWithParam<bool> {
public: public:
PeriodTest() PeriodTest()
: testable_period_(mpd_options_), : testable_period_(mpd_options_),
default_adaptation_set_( default_adaptation_set_(new StrictMock<MockAdaptationSet>()),
new StrictMock<MockAdaptationSet>(kDefaultAdaptationSetId)),
default_adaptation_set_ptr_(default_adaptation_set_.get()) {} default_adaptation_set_ptr_(default_adaptation_set_.get()) {}
void SetUp() override { content_protection_in_adaptation_set_ = GetParam(); } void SetUp() override { content_protection_in_adaptation_set_ = GetParam(); }
@ -130,7 +125,7 @@ TEST_P(PeriodTest, GetXml) {
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(default_adaptation_set_)))); .WillOnce(Return(ByMove(std::move(default_adaptation_set_))));
ASSERT_EQ(default_adaptation_set_ptr_, ASSERT_EQ(default_adaptation_set_ptr_,
@ -142,7 +137,7 @@ TEST_P(PeriodTest, GetXml) {
"<Period id=\"9\">" "<Period id=\"9\">"
// ContentType and Representation elements are populated after // ContentType and Representation elements are populated after
// Representation::Init() is called. // Representation::Init() is called.
" <AdaptationSet id=\"0\" contentType=\"\"/>" " <AdaptationSet contentType=\"\"/>"
"</Period>"; "</Period>";
EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(), EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(),
XmlNodeEqual(kExpectedXml)); XmlNodeEqual(kExpectedXml));
@ -162,7 +157,7 @@ TEST_P(PeriodTest, DynamicMpdGetXml) {
"container_type: 1\n"; "container_type: 1\n";
mpd_options_.mpd_type = MpdType::kDynamic; mpd_options_.mpd_type = MpdType::kDynamic;
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(default_adaptation_set_)))); .WillOnce(Return(ByMove(std::move(default_adaptation_set_))));
ASSERT_EQ(default_adaptation_set_ptr_, ASSERT_EQ(default_adaptation_set_ptr_,
@ -174,7 +169,7 @@ TEST_P(PeriodTest, DynamicMpdGetXml) {
"<Period id=\"9\" start=\"PT5.6S\">" "<Period id=\"9\" start=\"PT5.6S\">"
// ContentType and Representation elements are populated after // ContentType and Representation elements are populated after
// Representation::Init() is called. // Representation::Init() is called.
" <AdaptationSet id=\"0\" contentType=\"\"/>" " <AdaptationSet contentType=\"\"/>"
"</Period>"; "</Period>";
EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(), EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(),
XmlNodeEqual(kExpectedXml)); XmlNodeEqual(kExpectedXml));
@ -193,7 +188,7 @@ TEST_P(PeriodTest, SetDurationAndGetXml) {
"}\n" "}\n"
"container_type: 1\n"; "container_type: 1\n";
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(default_adaptation_set_)))); .WillOnce(Return(ByMove(std::move(default_adaptation_set_))));
ASSERT_EQ(default_adaptation_set_ptr_, ASSERT_EQ(default_adaptation_set_ptr_,
@ -207,7 +202,7 @@ TEST_P(PeriodTest, SetDurationAndGetXml) {
"<Period id=\"9\" duration=\"PT100.234S\">" "<Period id=\"9\" duration=\"PT100.234S\">"
// ContentType and Representation elements are populated after // ContentType and Representation elements are populated after
// Representation::Init() is called. // Representation::Init() is called.
" <AdaptationSet id=\"0\" contentType=\"\"/>" " <AdaptationSet contentType=\"\"/>"
"</Period>"; "</Period>";
EXPECT_THAT(testable_period_.GetXml(kOutputPeriodDuration).get(), EXPECT_THAT(testable_period_.GetXml(kOutputPeriodDuration).get(),
XmlNodeEqual(kExpectedXml)); XmlNodeEqual(kExpectedXml));
@ -215,7 +210,7 @@ TEST_P(PeriodTest, SetDurationAndGetXml) {
"<Period id=\"9\">" "<Period id=\"9\">"
// ContentType and Representation elements are populated after // ContentType and Representation elements are populated after
// Representation::Init() is called. // Representation::Init() is called.
" <AdaptationSet id=\"0\" contentType=\"\"/>" " <AdaptationSet contentType=\"\"/>"
"</Period>"; "</Period>";
EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(), EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(),
XmlNodeEqual(kExpectedXmlSuppressDuration)); XmlNodeEqual(kExpectedXmlSuppressDuration));
@ -230,7 +225,7 @@ TEST_P(PeriodTest, Text) {
"}\n" "}\n"
"container_type: CONTAINER_TEXT\n"; "container_type: CONTAINER_TEXT\n";
EXPECT_CALL(testable_period_, NewAdaptationSet(_, Eq("en"), _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(Eq("en"), _, _))
.WillOnce(Return(ByMove(std::move(default_adaptation_set_)))); .WillOnce(Return(ByMove(std::move(default_adaptation_set_))));
EXPECT_CALL(*default_adaptation_set_ptr_, ForceSetSegmentAlignment(true)); EXPECT_CALL(*default_adaptation_set_ptr_, ForceSetSegmentAlignment(true));
@ -240,7 +235,6 @@ TEST_P(PeriodTest, Text) {
content_protection_in_adaptation_set_)); content_protection_in_adaptation_set_));
} }
// Verify AddTrickPlayReferenceId is called.
TEST_P(PeriodTest, TrickPlayWithMatchingAdaptationSet) { TEST_P(PeriodTest, TrickPlayWithMatchingAdaptationSet) {
const char kVideoMediaInfo[] = const char kVideoMediaInfo[] =
"video_info {\n" "video_info {\n"
@ -267,15 +261,15 @@ TEST_P(PeriodTest, TrickPlayWithMatchingAdaptationSet) {
"container_type: 1\n"; "container_type: 1\n";
std::unique_ptr<StrictMock<MockAdaptationSet>> trick_play_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> trick_play_adaptation_set(
new StrictMock<MockAdaptationSet>(kTrickPlayAdaptationSetId)); new StrictMock<MockAdaptationSet>());
auto* trick_play_adaptation_set_ptr = trick_play_adaptation_set.get(); auto* trick_play_adaptation_set_ptr = trick_play_adaptation_set.get();
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(default_adaptation_set_)))) .WillOnce(Return(ByMove(std::move(default_adaptation_set_))))
.WillOnce(Return(ByMove(std::move(trick_play_adaptation_set)))); .WillOnce(Return(ByMove(std::move(trick_play_adaptation_set))));
EXPECT_CALL(*trick_play_adaptation_set_ptr, EXPECT_CALL(*trick_play_adaptation_set_ptr,
AddTrickPlayReferenceId(Eq(kDefaultAdaptationSetId))); AddTrickPlayReference(Eq(default_adaptation_set_ptr_)));
ASSERT_EQ(default_adaptation_set_ptr_, ASSERT_EQ(default_adaptation_set_ptr_,
testable_period_.GetOrCreateAdaptationSet( testable_period_.GetOrCreateAdaptationSet(
@ -314,9 +308,9 @@ TEST_P(PeriodTest, TrickPlayWithNoMatchingAdaptationSet) {
"container_type: 1\n"; "container_type: 1\n";
std::unique_ptr<StrictMock<MockAdaptationSet>> trick_play_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> trick_play_adaptation_set(
new StrictMock<MockAdaptationSet>(kTrickPlayAdaptationSetId)); new StrictMock<MockAdaptationSet>());
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(default_adaptation_set_)))) .WillOnce(Return(ByMove(std::move(default_adaptation_set_))))
.WillOnce(Return(ByMove(std::move(trick_play_adaptation_set)))); .WillOnce(Return(ByMove(std::move(trick_play_adaptation_set))));
@ -396,18 +390,16 @@ TEST_P(PeriodTest, DifferentProtectedContent) {
// Not using default mocks in this test so that we can keep track of // Not using default mocks in this test so that we can keep track of
// mocks by named mocks. // mocks by named mocks.
const uint32_t kSdAdaptationSetId = 2u;
const uint32_t kHdAdaptationSetId = 3u;
std::unique_ptr<StrictMock<MockAdaptationSet>> sd_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> sd_adaptation_set(
new StrictMock<MockAdaptationSet>(kSdAdaptationSetId)); new StrictMock<MockAdaptationSet>());
auto* sd_adaptation_set_ptr = sd_adaptation_set.get(); auto* sd_adaptation_set_ptr = sd_adaptation_set.get();
std::unique_ptr<StrictMock<MockAdaptationSet>> hd_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> hd_adaptation_set(
new StrictMock<MockAdaptationSet>(kHdAdaptationSetId)); new StrictMock<MockAdaptationSet>());
auto* hd_adaptation_set_ptr = hd_adaptation_set.get(); auto* hd_adaptation_set_ptr = hd_adaptation_set.get();
InSequence in_sequence; InSequence in_sequence;
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(sd_adaptation_set)))); .WillOnce(Return(ByMove(std::move(sd_adaptation_set))));
if (content_protection_in_adaptation_set_) { if (content_protection_in_adaptation_set_) {
@ -418,7 +410,7 @@ TEST_P(PeriodTest, DifferentProtectedContent) {
*sd_adaptation_set_ptr, *sd_adaptation_set_ptr,
AddContentProtectionElement(ContentProtectionElementEq(sd_my_drm))); AddContentProtectionElement(ContentProtectionElementEq(sd_my_drm)));
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(hd_adaptation_set)))); .WillOnce(Return(ByMove(std::move(hd_adaptation_set))));
// Add main Role here for both. // Add main Role here for both.
@ -502,7 +494,7 @@ TEST_P(PeriodTest, SameProtectedContent) {
InSequence in_sequence; InSequence in_sequence;
// Only called once. // Only called once.
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(default_adaptation_set_)))); .WillOnce(Return(ByMove(std::move(default_adaptation_set_))));
if (content_protection_in_adaptation_set_) { if (content_protection_in_adaptation_set_) {
@ -579,22 +571,24 @@ TEST_P(PeriodTest, SetAdaptationSetSwitching) {
const uint32_t kSdAdaptationSetId = 6u; const uint32_t kSdAdaptationSetId = 6u;
const uint32_t kHdAdaptationSetId = 7u; const uint32_t kHdAdaptationSetId = 7u;
std::unique_ptr<StrictMock<MockAdaptationSet>> sd_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> sd_adaptation_set(
new StrictMock<MockAdaptationSet>(kSdAdaptationSetId)); new StrictMock<MockAdaptationSet>());
auto* sd_adaptation_set_ptr = sd_adaptation_set.get(); auto* sd_adaptation_set_ptr = sd_adaptation_set.get();
sd_adaptation_set_ptr->set_id(kSdAdaptationSetId);
std::unique_ptr<StrictMock<MockAdaptationSet>> hd_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> hd_adaptation_set(
new StrictMock<MockAdaptationSet>(kHdAdaptationSetId)); new StrictMock<MockAdaptationSet>());
auto* hd_adaptation_set_ptr = hd_adaptation_set.get(); auto* hd_adaptation_set_ptr = hd_adaptation_set.get();
hd_adaptation_set_ptr->set_id(kHdAdaptationSetId);
InSequence in_sequence; InSequence in_sequence;
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(sd_adaptation_set)))); .WillOnce(Return(ByMove(std::move(sd_adaptation_set))));
if (content_protection_in_adaptation_set_) { if (content_protection_in_adaptation_set_) {
EXPECT_CALL(*sd_adaptation_set_ptr, AddContentProtectionElement(_)) EXPECT_CALL(*sd_adaptation_set_ptr, AddContentProtectionElement(_))
.Times(2); .Times(2);
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(hd_adaptation_set)))); .WillOnce(Return(ByMove(std::move(hd_adaptation_set))));
// Add main Role here for both. // Add main Role here for both.
@ -605,9 +599,9 @@ TEST_P(PeriodTest, SetAdaptationSetSwitching) {
.Times(2); .Times(2);
EXPECT_CALL(*sd_adaptation_set_ptr, EXPECT_CALL(*sd_adaptation_set_ptr,
AddAdaptationSetSwitching(kHdAdaptationSetId)); AddAdaptationSetSwitching(hd_adaptation_set_ptr));
EXPECT_CALL(*hd_adaptation_set_ptr, EXPECT_CALL(*hd_adaptation_set_ptr,
AddAdaptationSetSwitching(kSdAdaptationSetId)); AddAdaptationSetSwitching(sd_adaptation_set_ptr));
} }
ASSERT_EQ(sd_adaptation_set_ptr, testable_period_.GetOrCreateAdaptationSet( ASSERT_EQ(sd_adaptation_set_ptr, testable_period_.GetOrCreateAdaptationSet(
@ -643,11 +637,12 @@ TEST_P(PeriodTest, SetAdaptationSetSwitching) {
const uint32_t k4kAdaptationSetId = 4000u; const uint32_t k4kAdaptationSetId = 4000u;
std::unique_ptr<StrictMock<MockAdaptationSet>> fourk_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> fourk_adaptation_set(
new StrictMock<MockAdaptationSet>(k4kAdaptationSetId)); new StrictMock<MockAdaptationSet>());
auto* fourk_adaptation_set_ptr = fourk_adaptation_set.get(); auto* fourk_adaptation_set_ptr = fourk_adaptation_set.get();
fourk_adaptation_set_ptr->set_id(k4kAdaptationSetId);
if (content_protection_in_adaptation_set_) { if (content_protection_in_adaptation_set_) {
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(fourk_adaptation_set)))); .WillOnce(Return(ByMove(std::move(fourk_adaptation_set))));
EXPECT_CALL(*fourk_adaptation_set_ptr, AddRole(AdaptationSet::kRoleMain)); EXPECT_CALL(*fourk_adaptation_set_ptr, AddRole(AdaptationSet::kRoleMain));
@ -655,13 +650,13 @@ TEST_P(PeriodTest, SetAdaptationSetSwitching) {
.Times(2); .Times(2);
EXPECT_CALL(*sd_adaptation_set_ptr, EXPECT_CALL(*sd_adaptation_set_ptr,
AddAdaptationSetSwitching(k4kAdaptationSetId)); AddAdaptationSetSwitching(fourk_adaptation_set_ptr));
EXPECT_CALL(*fourk_adaptation_set_ptr, EXPECT_CALL(*fourk_adaptation_set_ptr,
AddAdaptationSetSwitching(kSdAdaptationSetId)); AddAdaptationSetSwitching(sd_adaptation_set_ptr));
EXPECT_CALL(*hd_adaptation_set_ptr, EXPECT_CALL(*hd_adaptation_set_ptr,
AddAdaptationSetSwitching(k4kAdaptationSetId)); AddAdaptationSetSwitching(fourk_adaptation_set_ptr));
EXPECT_CALL(*fourk_adaptation_set_ptr, EXPECT_CALL(*fourk_adaptation_set_ptr,
AddAdaptationSetSwitching(kHdAdaptationSetId)); AddAdaptationSetSwitching(hd_adaptation_set_ptr));
} }
ASSERT_EQ(content_protection_in_adaptation_set_ ? fourk_adaptation_set_ptr ASSERT_EQ(content_protection_in_adaptation_set_ ? fourk_adaptation_set_ptr
@ -716,22 +711,24 @@ TEST_P(PeriodTest, DoNotSetAdaptationSetSwitchingIfContentTypesDifferent) {
const uint32_t kVideoAdaptationSetId = 6u; const uint32_t kVideoAdaptationSetId = 6u;
const uint32_t kAudioAdaptationSetId = 7u; const uint32_t kAudioAdaptationSetId = 7u;
std::unique_ptr<StrictMock<MockAdaptationSet>> video_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> video_adaptation_set(
new StrictMock<MockAdaptationSet>(kVideoAdaptationSetId)); new StrictMock<MockAdaptationSet>());
auto* video_adaptation_set_ptr = video_adaptation_set.get(); auto* video_adaptation_set_ptr = video_adaptation_set.get();
video_adaptation_set_ptr->set_id(kVideoAdaptationSetId);
std::unique_ptr<StrictMock<MockAdaptationSet>> audio_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> audio_adaptation_set(
new StrictMock<MockAdaptationSet>(kAudioAdaptationSetId)); new StrictMock<MockAdaptationSet>());
auto* audio_adaptation_set_ptr = audio_adaptation_set.get(); auto* audio_adaptation_set_ptr = audio_adaptation_set.get();
audio_adaptation_set_ptr->set_id(kAudioAdaptationSetId);
InSequence in_sequence; InSequence in_sequence;
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(video_adaptation_set)))); .WillOnce(Return(ByMove(std::move(video_adaptation_set))));
if (content_protection_in_adaptation_set_) { if (content_protection_in_adaptation_set_) {
EXPECT_CALL(*video_adaptation_set_ptr, AddContentProtectionElement(_)) EXPECT_CALL(*video_adaptation_set_ptr, AddContentProtectionElement(_))
.Times(2); .Times(2);
} }
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(audio_adaptation_set)))); .WillOnce(Return(ByMove(std::move(audio_adaptation_set))));
if (content_protection_in_adaptation_set_) { if (content_protection_in_adaptation_set_) {
EXPECT_CALL(*audio_adaptation_set_ptr, AddContentProtectionElement(_)) EXPECT_CALL(*audio_adaptation_set_ptr, AddContentProtectionElement(_))
@ -796,17 +793,17 @@ TEST_P(PeriodTest, SplitAdaptationSetsByLanguageAndCodec) {
"media_duration_seconds: 10.5\n"; "media_duration_seconds: 10.5\n";
std::unique_ptr<StrictMock<MockAdaptationSet>> aac_eng_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> aac_eng_adaptation_set(
new StrictMock<MockAdaptationSet>(1)); new StrictMock<MockAdaptationSet>());
auto* aac_eng_adaptation_set_ptr = aac_eng_adaptation_set.get(); auto* aac_eng_adaptation_set_ptr = aac_eng_adaptation_set.get();
std::unique_ptr<StrictMock<MockAdaptationSet>> aac_ger_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> aac_ger_adaptation_set(
new StrictMock<MockAdaptationSet>(2)); new StrictMock<MockAdaptationSet>());
auto* aac_ger_adaptation_set_ptr = aac_ger_adaptation_set.get(); auto* aac_ger_adaptation_set_ptr = aac_ger_adaptation_set.get();
std::unique_ptr<StrictMock<MockAdaptationSet>> vorbis_german_adaptation_set( std::unique_ptr<StrictMock<MockAdaptationSet>> vorbis_german_adaptation_set(
new StrictMock<MockAdaptationSet>(3)); new StrictMock<MockAdaptationSet>());
auto* vorbis_german_adaptation_set_ptr = vorbis_german_adaptation_set.get(); auto* vorbis_german_adaptation_set_ptr = vorbis_german_adaptation_set.get();
// We expect three AdaptationSets. // We expect three AdaptationSets.
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(aac_eng_adaptation_set)))) .WillOnce(Return(ByMove(std::move(aac_eng_adaptation_set))))
.WillOnce(Return(ByMove(std::move(aac_ger_adaptation_set)))) .WillOnce(Return(ByMove(std::move(aac_ger_adaptation_set))))
.WillOnce(Return(ByMove(std::move(vorbis_german_adaptation_set)))); .WillOnce(Return(ByMove(std::move(vorbis_german_adaptation_set))));
@ -855,13 +852,13 @@ TEST_P(PeriodTest, GetAdaptationSets) {
"media_duration_seconds: 10.5\n"; "media_duration_seconds: 10.5\n";
std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_1( std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_1(
new StrictMock<MockAdaptationSet>(1)); new StrictMock<MockAdaptationSet>());
auto* adaptation_set_1_ptr = adaptation_set_1.get(); auto* adaptation_set_1_ptr = adaptation_set_1.get();
std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_2( std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_2(
new StrictMock<MockAdaptationSet>(2)); new StrictMock<MockAdaptationSet>());
auto* adaptation_set_2_ptr = adaptation_set_2.get(); auto* adaptation_set_2_ptr = adaptation_set_2.get();
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(adaptation_set_1)))) .WillOnce(Return(ByMove(std::move(adaptation_set_1))))
.WillOnce(Return(ByMove(std::move(adaptation_set_2)))); .WillOnce(Return(ByMove(std::move(adaptation_set_2))));
@ -878,7 +875,7 @@ TEST_P(PeriodTest, GetAdaptationSets) {
ElementsAre(adaptation_set_1_ptr, adaptation_set_2_ptr)); ElementsAre(adaptation_set_1_ptr, adaptation_set_2_ptr));
} }
TEST_P(PeriodTest, GetAdaptationSetsOrderedByAdaptationSetId) { TEST_P(PeriodTest, OrderedByAdaptationSetId) {
const char kContent1[] = const char kContent1[] =
"audio_info {\n" "audio_info {\n"
" codec: 'mp4a.40.2'\n" " codec: 'mp4a.40.2'\n"
@ -903,25 +900,34 @@ TEST_P(PeriodTest, GetAdaptationSetsOrderedByAdaptationSetId) {
"media_duration_seconds: 10.5\n"; "media_duration_seconds: 10.5\n";
std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_1( std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_1(
new StrictMock<MockAdaptationSet>(1)); new StrictMock<MockAdaptationSet>());
auto* adaptation_set_1_ptr = adaptation_set_1.get(); auto* adaptation_set_1_ptr = adaptation_set_1.get();
std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_2( std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_2(
new StrictMock<MockAdaptationSet>(2)); new StrictMock<MockAdaptationSet>());
auto* adaptation_set_2_ptr = adaptation_set_2.get(); auto* adaptation_set_2_ptr = adaptation_set_2.get();
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _)) EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _))
.WillOnce(Return(ByMove(std::move(adaptation_set_2)))) .WillOnce(Return(ByMove(std::move(adaptation_set_1))))
.WillOnce(Return(ByMove(std::move(adaptation_set_1)))); .WillOnce(Return(ByMove(std::move(adaptation_set_2))));
ASSERT_EQ(adaptation_set_2_ptr, testable_period_.GetOrCreateAdaptationSet(
ConvertToMediaInfo(kContent2),
content_protection_in_adaptation_set_));
ASSERT_EQ(adaptation_set_1_ptr, testable_period_.GetOrCreateAdaptationSet( ASSERT_EQ(adaptation_set_1_ptr, testable_period_.GetOrCreateAdaptationSet(
ConvertToMediaInfo(kContent1), ConvertToMediaInfo(kContent1),
content_protection_in_adaptation_set_)); content_protection_in_adaptation_set_));
EXPECT_THAT(testable_period_.GetAdaptationSets(), ASSERT_EQ(adaptation_set_2_ptr, testable_period_.GetOrCreateAdaptationSet(
// Elements are ordered by id(). ConvertToMediaInfo(kContent2),
ElementsAre(adaptation_set_1_ptr, adaptation_set_2_ptr)); content_protection_in_adaptation_set_));
adaptation_set_1_ptr->set_id(2);
adaptation_set_2_ptr->set_id(1);
const char kExpectedXml[] =
R"(<Period id="9">)"
// ContentType and Representation elements are populated after
// Representation::Init() is called.
R"( <AdaptationSet id="1" contentType=""/>)"
R"( <AdaptationSet id="2" contentType=""/>)"
R"(</Period>)";
EXPECT_THAT(testable_period_.GetXml(!kOutputPeriodDuration).get(),
XmlNodeEqual(kExpectedXml));
} }
INSTANTIATE_TEST_CASE_P(ContentProtectionInAdaptationSet, INSTANTIATE_TEST_CASE_P(ContentProtectionInAdaptationSet,
PeriodTest, PeriodTest,

View File

@ -43,15 +43,31 @@ bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info,
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);
const Representation* kNoOriginalRepresentation = nullptr;
const double kPeriodStartTimeSeconds = 0.0;
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
const Representation* representation = AddRepresentationToPeriod( const double kPeriodStartTimeSeconds = 0.0;
adjusted_media_info, kNoOriginalRepresentation, kPeriodStartTimeSeconds); Period* period = mpd_builder_->GetOrCreatePeriod(kPeriodStartTimeSeconds);
DCHECK(period);
AdaptationSet* adaptation_set = period->GetOrCreateAdaptationSet(
media_info, content_protection_in_adaptation_set_);
DCHECK(adaptation_set);
if (!adaptation_set->has_id())
adaptation_set->set_id(next_adaptation_set_id_++);
Representation* representation =
adaptation_set->AddRepresentation(adjusted_media_info);
if (!representation) if (!representation)
return false; return false;
*container_id = representation->id(); *container_id = representation->id();
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);
}
representation_map_[representation->id()] = representation;
return true; return true;
} }
@ -96,16 +112,32 @@ bool SimpleMpdNotifier::NotifyCueEvent(uint32_t container_id,
const MediaInfo& media_info = original_representation->GetMediaInfo(); const MediaInfo& media_info = original_representation->GetMediaInfo();
const double period_start_time_seconds = const double period_start_time_seconds =
static_cast<double>(timestamp) / media_info.reference_time_scale(); static_cast<double>(timestamp) / media_info.reference_time_scale();
const Representation* new_representation = AddRepresentationToPeriod(
media_info, original_representation, period_start_time_seconds); Period* period = mpd_builder_->GetOrCreatePeriod(period_start_time_seconds);
if (!new_representation) DCHECK(period);
AdaptationSet* adaptation_set = period->GetOrCreateAdaptationSet(
media_info, content_protection_in_adaptation_set_);
DCHECK(adaptation_set);
if (!adaptation_set->has_id()) {
adaptation_set->set_id(original_adaptation_set->id());
} else {
DCHECK_EQ(adaptation_set->id(), original_adaptation_set->id());
}
Representation* representation =
adaptation_set->CopyRepresentation(*original_representation);
if (!representation)
return false; return false;
// TODO(kqyang): Pass the ID to GetOrCreateAdaptationSet instead? if (content_protection_in_adaptation_set_) {
AdaptationSet* new_adaptation_set = // ContentProtection elements are already added to AdaptationSet above.
representation_id_to_adaptation_set_[container_id]; // Use RepresentationId to AdaptationSet map to update ContentProtection
DCHECK(new_adaptation_set); // in AdaptationSet in NotifyEncryptionUpdate.
new_adaptation_set->set_id(original_adaptation_set->id()); representation_id_to_adaptation_set_[representation->id()] = adaptation_set;
} else {
AddContentProtectionElements(media_info, representation);
}
representation_map_[representation->id()] = representation;
return true; return true;
} }
@ -138,37 +170,4 @@ bool SimpleMpdNotifier::Flush() {
return WriteMpdToFile(output_path_, mpd_builder_.get()); return WriteMpdToFile(output_path_, mpd_builder_.get());
} }
Representation* SimpleMpdNotifier::AddRepresentationToPeriod(
const MediaInfo& media_info,
const Representation* original_representation,
double period_start_time_seconds) {
Period* period = mpd_builder_->GetOrCreatePeriod(period_start_time_seconds);
DCHECK(period);
AdaptationSet* adaptation_set = period->GetOrCreateAdaptationSet(
media_info, content_protection_in_adaptation_set_);
DCHECK(adaptation_set);
Representation* representation = nullptr;
if (original_representation) {
representation =
adaptation_set->CopyRepresentation(*original_representation);
} else {
representation = adaptation_set->AddRepresentation(media_info);
}
if (!representation)
return nullptr;
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);
}
representation_map_[representation->id()] = representation;
return representation;
}
} // namespace shaka } // namespace shaka

View File

@ -56,17 +56,6 @@ class SimpleMpdNotifier : public MpdNotifier {
friend class SimpleMpdNotifierTest; friend class SimpleMpdNotifierTest;
// Add a new representation. If |original_representation| is not nullptr, the
// new Representation will clone from it; otherwise the new Representation is
// created from |media_info|.
// The new Representation will be added to Period with the specified start
// time.
// Returns the new Representation on success; otherwise a nullptr is returned.
Representation* AddRepresentationToPeriod(
const MediaInfo& media_info,
const Representation* original_representation,
double period_start_time_seconds);
// Testing only method. Returns a pointer to MpdBuilder. // Testing only method. Returns a pointer to MpdBuilder.
MpdBuilder* MpdBuilderForTesting() const { return mpd_builder_.get(); } MpdBuilder* MpdBuilderForTesting() const { return mpd_builder_.get(); }
@ -81,6 +70,7 @@ class SimpleMpdNotifier : public MpdNotifier {
bool content_protection_in_adaptation_set_ = true; bool content_protection_in_adaptation_set_ = true;
base::Lock lock_; base::Lock lock_;
uint32_t next_adaptation_set_id_ = 0;
// Maps Representation ID to Representation. // Maps Representation ID to Representation.
std::map<uint32_t, Representation*> representation_map_; std::map<uint32_t, Representation*> representation_map_;
// Maps Representation ID to AdaptationSet. This is for updating the PSSH. // Maps Representation ID to AdaptationSet. This is for updating the PSSH.

View File

@ -28,7 +28,6 @@ using ::testing::StrEq;
namespace { namespace {
const uint32_t kDefaultPeriodId = 0u; const uint32_t kDefaultPeriodId = 0u;
const double kDefaultPeriodStartTime = 0.0; const double kDefaultPeriodStartTime = 0.0;
const uint32_t kDefaultAdaptationSetId = 0u;
const uint32_t kDefaultTimeScale = 10; const uint32_t kDefaultTimeScale = 10;
const bool kContentProtectionInAdaptationSet = true; const bool kContentProtectionInAdaptationSet = true;
@ -43,8 +42,7 @@ class SimpleMpdNotifierTest : public ::testing::Test {
SimpleMpdNotifierTest() SimpleMpdNotifierTest()
: default_mock_period_( : default_mock_period_(
new MockPeriod(kDefaultPeriodId, kDefaultPeriodStartTime)), new MockPeriod(kDefaultPeriodId, kDefaultPeriodStartTime)),
default_mock_adaptation_set_( default_mock_adaptation_set_(new MockAdaptationSet()) {}
new MockAdaptationSet(kDefaultAdaptationSetId)) {}
void SetUp() override { void SetUp() override {
ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_)); ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_));
@ -207,7 +205,7 @@ TEST_F(SimpleMpdNotifierTest, NotifyCueEvent) {
std::unique_ptr<MockPeriod> mock_period( std::unique_ptr<MockPeriod> mock_period(
new MockPeriod(kDefaultPeriodId, kDefaultPeriodStartTime)); new MockPeriod(kDefaultPeriodId, kDefaultPeriodStartTime));
std::unique_ptr<MockAdaptationSet> mock_adaptation_set( std::unique_ptr<MockAdaptationSet> mock_adaptation_set(
new MockAdaptationSet(kDefaultAdaptationSetId)); new MockAdaptationSet());
std::unique_ptr<MockRepresentation> mock_representation( std::unique_ptr<MockRepresentation> mock_representation(
new MockRepresentation(kRepresentationId)); new MockRepresentation(kRepresentationId));
@ -229,7 +227,7 @@ TEST_F(SimpleMpdNotifierTest, NotifyCueEvent) {
std::unique_ptr<MockPeriod> mock_period2( std::unique_ptr<MockPeriod> mock_period2(
new MockPeriod(kAnotherPeriodId, kArbitraryPeriodStartTime)); new MockPeriod(kAnotherPeriodId, kArbitraryPeriodStartTime));
std::unique_ptr<MockAdaptationSet> mock_adaptation_set2( std::unique_ptr<MockAdaptationSet> mock_adaptation_set2(
new MockAdaptationSet(kDefaultAdaptationSetId)); new MockAdaptationSet());
std::unique_ptr<MockRepresentation> mock_representation2( std::unique_ptr<MockRepresentation> mock_representation2(
new MockRepresentation(kRepresentationId)); new MockRepresentation(kRepresentationId));
@ -339,8 +337,8 @@ TEST_F(SimpleMpdNotifierTest, MultipleMediaInfo) {
SimpleMpdNotifier notifier(empty_mpd_option_); 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());
std::unique_ptr<MockAdaptationSet> adaptation_set2(new MockAdaptationSet(2)); std::unique_ptr<MockAdaptationSet> adaptation_set2(new MockAdaptationSet());
std::unique_ptr<MockRepresentation> representation1( std::unique_ptr<MockRepresentation> representation1(
new MockRepresentation(1)); new MockRepresentation(1));

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S"> <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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S">
<Period id="0"> <Period id="0">
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video" par="3:2"> <AdaptationSet contentType="video" width="720" height="480" frameRate="10/1" par="3:2">
<Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" sar="1:1"> <Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" sar="1:1">
<BaseURL>test_output_file_name1.mp4</BaseURL> <BaseURL>test_output_file_name1.mp4</BaseURL>
<SegmentBase indexRange="121-221" timescale="1000"> <SegmentBase indexRange="121-221" timescale="1000">
@ -9,7 +9,7 @@
</SegmentBase> </SegmentBase>
</Representation> </Representation>
</AdaptationSet> </AdaptationSet>
<AdaptationSet id="1" contentType="audio"> <AdaptationSet contentType="audio">
<Representation id="1" bandwidth="400" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100"> <Representation id="1" bandwidth="400" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/> <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
<BaseURL>test_output_file_name_audio1.mp4</BaseURL> <BaseURL>test_output_file_name_audio1.mp4</BaseURL>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S"> <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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S">
<Period id="0"> <Period id="0">
<AdaptationSet id="0" width="720" height="480" frameRate="10/1" contentType="video" par="3:2"> <AdaptationSet width="720" height="480" frameRate="10/1" contentType="video" par="3:2">
<Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" sar="1:1"> <Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" sar="1:1">
<BaseURL>test_output_file_name1.mp4</BaseURL> <BaseURL>test_output_file_name1.mp4</BaseURL>
<SegmentBase indexRange="121-221" timescale="1000"> <SegmentBase indexRange="121-221" timescale="1000">

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S"> <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" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S">
<Period id="0"> <Period id="0">
<AdaptationSet id="0" maxWidth="720" maxHeight="480" maxFrameRate="10/1" contentType="video"> <AdaptationSet contentType="video" maxWidth="720" maxHeight="480" maxFrameRate="10/1">
<Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1"> <Representation id="0" bandwidth="7620" codecs="avc1.010101" mimeType="video/mp4" width="720" height="480" frameRate="10/1" sar="1:1">
<BaseURL>test_output_file_name1.mp4</BaseURL> <BaseURL>test_output_file_name1.mp4</BaseURL>
<SegmentBase indexRange="121-221" timescale="1000"> <SegmentBase indexRange="121-221" timescale="1000">