Order Representations and AdaptationSets by id()
Change-Id: I04509819c1f8fa78e4826d53966531bf98e90849
This commit is contained in:
parent
6d0a6bb120
commit
322337a958
|
@ -196,8 +196,9 @@ Representation* AdaptationSet::AddRepresentation(const MediaInfo& media_info) {
|
|||
return NULL;
|
||||
}
|
||||
UpdateFromMediaInfo(media_info);
|
||||
representations_.push_back(std::move(new_representation));
|
||||
return representations_.back().get();
|
||||
Representation* representation_ptr = new_representation.get();
|
||||
representation_map_[representation_ptr->id()] = std::move(new_representation);
|
||||
return representation_ptr;
|
||||
}
|
||||
|
||||
Representation* AdaptationSet::CopyRepresentationWithTimeOffset(
|
||||
|
@ -211,8 +212,9 @@ Representation* AdaptationSet::CopyRepresentationWithTimeOffset(
|
|||
representation, presentation_time_offset, std::move(listener)));
|
||||
|
||||
UpdateFromMediaInfo(new_representation->GetMediaInfo());
|
||||
representations_.push_back(std::move(new_representation));
|
||||
return representations_.back().get();
|
||||
Representation* representation_ptr = new_representation.get();
|
||||
representation_map_[representation_ptr->id()] = std::move(new_representation);
|
||||
return representation_ptr;
|
||||
}
|
||||
|
||||
void AdaptationSet::AddContentProtectionElement(
|
||||
|
@ -320,8 +322,8 @@ xml::scoped_xml_ptr<xmlNode> AdaptationSet::GetXml() {
|
|||
for (AdaptationSet::Role role : roles_)
|
||||
adaptation_set.AddRoleElement("urn:mpeg:dash:role:2011", RoleToText(role));
|
||||
|
||||
for (const std::unique_ptr<Representation>& representation :
|
||||
representations_) {
|
||||
for (const auto& representation_pair : representation_map_) {
|
||||
const auto& representation = representation_pair.second;
|
||||
if (suppress_representation_width)
|
||||
representation->SuppressOnce(Representation::kSuppressWidth);
|
||||
if (suppress_representation_height)
|
||||
|
@ -376,9 +378,8 @@ void AdaptationSet::AddTrickPlayReferenceId(uint32_t id) {
|
|||
|
||||
const std::list<Representation*> AdaptationSet::GetRepresentations() const {
|
||||
std::list<Representation*> representations;
|
||||
for (const std::unique_ptr<Representation>& representation :
|
||||
representations_) {
|
||||
representations.push_back(representation.get());
|
||||
for (const auto& representation_pair : representation_map_) {
|
||||
representations.push_back(representation_pair.second.get());
|
||||
}
|
||||
return representations;
|
||||
}
|
||||
|
@ -450,7 +451,7 @@ void AdaptationSet::CheckLiveSegmentAlignment(uint32_t representation_id,
|
|||
representation_start_times.push_back(start_time);
|
||||
// There's no way to detemine whether the segments are aligned if some
|
||||
// representations do not have any segments.
|
||||
if (representation_segment_start_times_.size() != representations_.size())
|
||||
if (representation_segment_start_times_.size() != representation_map_.size())
|
||||
return;
|
||||
|
||||
DCHECK(!representation_start_times.empty());
|
||||
|
|
|
@ -229,7 +229,9 @@ class AdaptationSet {
|
|||
void RecordFrameRate(uint32_t frame_duration, uint32_t timescale);
|
||||
|
||||
std::list<ContentProtectionElement> content_protection_elements_;
|
||||
std::list<std::unique_ptr<Representation>> representations_;
|
||||
// representation_id => Representation map. It also keeps the representations_
|
||||
// sorted by default.
|
||||
std::map<uint32_t, std::unique_ptr<Representation>> representation_map_;
|
||||
|
||||
base::AtomicSequenceNumber* const representation_counter_;
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
#include "packager/mpd/test/mpd_builder_test_helper.h"
|
||||
#include "packager/mpd/test/xml_compare.h"
|
||||
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Not;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
|
||||
namespace shaka {
|
||||
|
||||
|
@ -590,7 +590,7 @@ TEST_F(AdaptationSetTest, BubbleUpAttributesToAdaptationSet) {
|
|||
}
|
||||
|
||||
TEST_F(AdaptationSetTest, GetRepresentations) {
|
||||
const char k480pMediaInfo[] =
|
||||
const char kMediaInfo1[] =
|
||||
"video_info {\n"
|
||||
" codec: 'avc1'\n"
|
||||
" width: 720\n"
|
||||
|
@ -601,7 +601,7 @@ TEST_F(AdaptationSetTest, GetRepresentations) {
|
|||
" pixel_height: 9\n"
|
||||
"}\n"
|
||||
"container_type: 1\n";
|
||||
const char k360pMediaInfo[] =
|
||||
const char kMediaInfo2[] =
|
||||
"video_info {\n"
|
||||
" codec: 'avc1'\n"
|
||||
" width: 640\n"
|
||||
|
@ -615,15 +615,29 @@ TEST_F(AdaptationSetTest, GetRepresentations) {
|
|||
|
||||
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage);
|
||||
|
||||
Representation* representation_480p =
|
||||
adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pMediaInfo));
|
||||
Representation* representation1 =
|
||||
adaptation_set->AddRepresentation(ConvertToMediaInfo(kMediaInfo1));
|
||||
EXPECT_THAT(adaptation_set->GetRepresentations(),
|
||||
UnorderedElementsAre(representation_480p));
|
||||
ElementsAre(representation1));
|
||||
|
||||
Representation* representation_360p =
|
||||
adaptation_set->AddRepresentation(ConvertToMediaInfo(k360pMediaInfo));
|
||||
Representation* representation2 =
|
||||
adaptation_set->AddRepresentation(ConvertToMediaInfo(kMediaInfo2));
|
||||
EXPECT_THAT(adaptation_set->GetRepresentations(),
|
||||
UnorderedElementsAre(representation_360p, representation_480p));
|
||||
ElementsAre(representation1, representation2));
|
||||
|
||||
auto new_adaptation_set =
|
||||
CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage);
|
||||
const uint64_t kPresentationTimeOffset = 80;
|
||||
Representation* new_representation2 =
|
||||
new_adaptation_set->CopyRepresentationWithTimeOffset(
|
||||
*representation2, kPresentationTimeOffset);
|
||||
Representation* new_representation1 =
|
||||
new_adaptation_set->CopyRepresentationWithTimeOffset(
|
||||
*representation1, kPresentationTimeOffset);
|
||||
|
||||
EXPECT_THAT(new_adaptation_set->GetRepresentations(),
|
||||
// Elements are ordered by id().
|
||||
ElementsAre(new_representation1, new_representation2));
|
||||
}
|
||||
|
||||
// Verify that subsegmentAlignment is set to true if all the Representations'
|
||||
|
|
|
@ -88,9 +88,10 @@ AdaptationSet* Period::GetOrCreateAdaptationSet(
|
|||
}
|
||||
}
|
||||
}
|
||||
adaptation_sets.push_back(new_adaptation_set.get());
|
||||
adaptation_sets_.push_back(std::move(new_adaptation_set));
|
||||
return adaptation_sets_.back().get();
|
||||
AdaptationSet* adaptation_set_ptr = new_adaptation_set.get();
|
||||
adaptation_sets.push_back(adaptation_set_ptr);
|
||||
adaptation_set_map_[adaptation_set_ptr->id()] = std::move(new_adaptation_set);
|
||||
return adaptation_set_ptr;
|
||||
}
|
||||
|
||||
xml::scoped_xml_ptr<xmlNode> Period::GetXml() {
|
||||
|
@ -99,8 +100,8 @@ xml::scoped_xml_ptr<xmlNode> Period::GetXml() {
|
|||
// Required for 'dynamic' MPDs.
|
||||
period.SetId(id_);
|
||||
// Iterate thru AdaptationSets and add them to one big Period element.
|
||||
for (const auto& adaptation_set : adaptation_sets_) {
|
||||
xml::scoped_xml_ptr<xmlNode> child(adaptation_set->GetXml());
|
||||
for (const auto& adaptation_set_pair : adaptation_set_map_) {
|
||||
xml::scoped_xml_ptr<xmlNode> child(adaptation_set_pair.second->GetXml());
|
||||
if (!child || !period.AddChild(std::move(child)))
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -115,9 +116,8 @@ xml::scoped_xml_ptr<xmlNode> Period::GetXml() {
|
|||
|
||||
const std::list<AdaptationSet*> Period::GetAdaptationSets() const {
|
||||
std::list<AdaptationSet*> adaptation_sets;
|
||||
for (const std::unique_ptr<AdaptationSet>& adaptation_set :
|
||||
adaptation_sets_) {
|
||||
adaptation_sets.push_back(adaptation_set.get());
|
||||
for (const auto& adaptation_set_pair : adaptation_set_map_) {
|
||||
adaptation_sets.push_back(adaptation_set_pair.second.get());
|
||||
}
|
||||
return adaptation_sets;
|
||||
}
|
||||
|
|
|
@ -105,8 +105,9 @@ class Period {
|
|||
const MpdOptions& mpd_options_;
|
||||
base::AtomicSequenceNumber* const adaptation_set_counter_;
|
||||
base::AtomicSequenceNumber* const representation_counter_;
|
||||
// The list of AdaptationSets in this Period.
|
||||
std::list<std::unique_ptr<AdaptationSet>> adaptation_sets_;
|
||||
// adaptation_id => Adaptation map. It also keeps the adaptation_sets_ sorted
|
||||
// by default.
|
||||
std::map<uint32_t, std::unique_ptr<AdaptationSet>> adaptation_set_map_;
|
||||
// AdaptationSets grouped by a specific adaptation set grouping key.
|
||||
// AdaptationSets with the same key contain identical parameters except
|
||||
// ContentProtection parameters. A single AdaptationSet would be created
|
||||
|
|
|
@ -21,7 +21,6 @@ using ::testing::Eq;
|
|||
using ::testing::InSequence;
|
||||
using ::testing::Return;
|
||||
using ::testing::StrictMock;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
|
||||
namespace shaka {
|
||||
namespace {
|
||||
|
@ -788,7 +787,7 @@ TEST_P(PeriodTest, SplitAdaptationSetsByLanguageAndCodec) {
|
|||
}
|
||||
|
||||
TEST_P(PeriodTest, GetAdaptationSets) {
|
||||
const char kAacEnglishAudioContent[] =
|
||||
const char kContent1[] =
|
||||
"audio_info {\n"
|
||||
" codec: 'mp4a.40.2'\n"
|
||||
" sampling_frequency: 44100\n"
|
||||
|
@ -799,7 +798,7 @@ TEST_P(PeriodTest, GetAdaptationSets) {
|
|||
"reference_time_scale: 50\n"
|
||||
"container_type: CONTAINER_MP4\n"
|
||||
"media_duration_seconds: 10.5\n";
|
||||
const char kAacGermanAudioContent[] =
|
||||
const char kContent2[] =
|
||||
"audio_info {\n"
|
||||
" codec: 'mp4a.40.2'\n"
|
||||
" sampling_frequency: 44100\n"
|
||||
|
@ -811,33 +810,75 @@ TEST_P(PeriodTest, GetAdaptationSets) {
|
|||
"container_type: CONTAINER_MP4\n"
|
||||
"media_duration_seconds: 10.5\n";
|
||||
|
||||
std::unique_ptr<StrictMock<MockAdaptationSet>> aac_eng_adaptation_set(
|
||||
std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_1(
|
||||
new StrictMock<MockAdaptationSet>(1));
|
||||
auto* aac_eng_adaptation_set_ptr = aac_eng_adaptation_set.get();
|
||||
std::unique_ptr<StrictMock<MockAdaptationSet>> aac_ger_adaptation_set(
|
||||
auto* adaptation_set_1_ptr = adaptation_set_1.get();
|
||||
std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_2(
|
||||
new StrictMock<MockAdaptationSet>(2));
|
||||
auto* aac_ger_adaptation_set_ptr = aac_ger_adaptation_set.get();
|
||||
auto* adaptation_set_2_ptr = adaptation_set_2.get();
|
||||
|
||||
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _))
|
||||
.WillOnce(Return(ByMove(std::move(aac_eng_adaptation_set))))
|
||||
.WillOnce(Return(ByMove(std::move(aac_ger_adaptation_set))));
|
||||
.WillOnce(Return(ByMove(std::move(adaptation_set_1))))
|
||||
.WillOnce(Return(ByMove(std::move(adaptation_set_2))));
|
||||
|
||||
ASSERT_EQ(aac_eng_adaptation_set_ptr,
|
||||
testable_period_.GetOrCreateAdaptationSet(
|
||||
ConvertToMediaInfo(kAacEnglishAudioContent),
|
||||
content_protection_in_adaptation_set_));
|
||||
ASSERT_EQ(adaptation_set_1_ptr, testable_period_.GetOrCreateAdaptationSet(
|
||||
ConvertToMediaInfo(kContent1),
|
||||
content_protection_in_adaptation_set_));
|
||||
EXPECT_THAT(testable_period_.GetAdaptationSets(),
|
||||
UnorderedElementsAre(aac_eng_adaptation_set_ptr));
|
||||
ElementsAre(adaptation_set_1_ptr));
|
||||
|
||||
ASSERT_EQ(aac_ger_adaptation_set_ptr,
|
||||
testable_period_.GetOrCreateAdaptationSet(
|
||||
ConvertToMediaInfo(kAacGermanAudioContent),
|
||||
content_protection_in_adaptation_set_));
|
||||
ASSERT_EQ(adaptation_set_2_ptr, testable_period_.GetOrCreateAdaptationSet(
|
||||
ConvertToMediaInfo(kContent2),
|
||||
content_protection_in_adaptation_set_));
|
||||
EXPECT_THAT(testable_period_.GetAdaptationSets(),
|
||||
UnorderedElementsAre(aac_eng_adaptation_set_ptr,
|
||||
aac_ger_adaptation_set_ptr));
|
||||
ElementsAre(adaptation_set_1_ptr, adaptation_set_2_ptr));
|
||||
}
|
||||
|
||||
TEST_P(PeriodTest, GetAdaptationSetsOrderedByAdaptationSetId) {
|
||||
const char kContent1[] =
|
||||
"audio_info {\n"
|
||||
" codec: 'mp4a.40.2'\n"
|
||||
" sampling_frequency: 44100\n"
|
||||
" time_scale: 1200\n"
|
||||
" num_channels: 2\n"
|
||||
" language: 'eng'\n"
|
||||
"}\n"
|
||||
"reference_time_scale: 50\n"
|
||||
"container_type: CONTAINER_MP4\n"
|
||||
"media_duration_seconds: 10.5\n";
|
||||
const char kContent2[] =
|
||||
"audio_info {\n"
|
||||
" codec: 'mp4a.40.2'\n"
|
||||
" sampling_frequency: 44100\n"
|
||||
" time_scale: 1200\n"
|
||||
" num_channels: 2\n"
|
||||
" language: 'ger'\n"
|
||||
"}\n"
|
||||
"reference_time_scale: 50\n"
|
||||
"container_type: CONTAINER_MP4\n"
|
||||
"media_duration_seconds: 10.5\n";
|
||||
|
||||
std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_1(
|
||||
new StrictMock<MockAdaptationSet>(1));
|
||||
auto* adaptation_set_1_ptr = adaptation_set_1.get();
|
||||
std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_2(
|
||||
new StrictMock<MockAdaptationSet>(2));
|
||||
auto* adaptation_set_2_ptr = adaptation_set_2.get();
|
||||
|
||||
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _))
|
||||
.WillOnce(Return(ByMove(std::move(adaptation_set_2))))
|
||||
.WillOnce(Return(ByMove(std::move(adaptation_set_1))));
|
||||
|
||||
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(
|
||||
ConvertToMediaInfo(kContent1),
|
||||
content_protection_in_adaptation_set_));
|
||||
EXPECT_THAT(testable_period_.GetAdaptationSets(),
|
||||
// Elements are ordered by id().
|
||||
ElementsAre(adaptation_set_1_ptr, adaptation_set_2_ptr));
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(ContentProtectionInAdaptationSet,
|
||||
PeriodTest,
|
||||
::testing::Bool());
|
||||
|
|
Loading…
Reference in New Issue