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;
|
return NULL;
|
||||||
}
|
}
|
||||||
UpdateFromMediaInfo(media_info);
|
UpdateFromMediaInfo(media_info);
|
||||||
representations_.push_back(std::move(new_representation));
|
Representation* representation_ptr = new_representation.get();
|
||||||
return representations_.back().get();
|
representation_map_[representation_ptr->id()] = std::move(new_representation);
|
||||||
|
return representation_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Representation* AdaptationSet::CopyRepresentationWithTimeOffset(
|
Representation* AdaptationSet::CopyRepresentationWithTimeOffset(
|
||||||
|
@ -211,8 +212,9 @@ Representation* AdaptationSet::CopyRepresentationWithTimeOffset(
|
||||||
representation, presentation_time_offset, std::move(listener)));
|
representation, presentation_time_offset, std::move(listener)));
|
||||||
|
|
||||||
UpdateFromMediaInfo(new_representation->GetMediaInfo());
|
UpdateFromMediaInfo(new_representation->GetMediaInfo());
|
||||||
representations_.push_back(std::move(new_representation));
|
Representation* representation_ptr = new_representation.get();
|
||||||
return representations_.back().get();
|
representation_map_[representation_ptr->id()] = std::move(new_representation);
|
||||||
|
return representation_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdaptationSet::AddContentProtectionElement(
|
void AdaptationSet::AddContentProtectionElement(
|
||||||
|
@ -320,8 +322,8 @@ xml::scoped_xml_ptr<xmlNode> AdaptationSet::GetXml() {
|
||||||
for (AdaptationSet::Role role : roles_)
|
for (AdaptationSet::Role role : roles_)
|
||||||
adaptation_set.AddRoleElement("urn:mpeg:dash:role:2011", RoleToText(role));
|
adaptation_set.AddRoleElement("urn:mpeg:dash:role:2011", RoleToText(role));
|
||||||
|
|
||||||
for (const std::unique_ptr<Representation>& representation :
|
for (const auto& representation_pair : representation_map_) {
|
||||||
representations_) {
|
const auto& representation = representation_pair.second;
|
||||||
if (suppress_representation_width)
|
if (suppress_representation_width)
|
||||||
representation->SuppressOnce(Representation::kSuppressWidth);
|
representation->SuppressOnce(Representation::kSuppressWidth);
|
||||||
if (suppress_representation_height)
|
if (suppress_representation_height)
|
||||||
|
@ -376,9 +378,8 @@ void AdaptationSet::AddTrickPlayReferenceId(uint32_t id) {
|
||||||
|
|
||||||
const std::list<Representation*> AdaptationSet::GetRepresentations() const {
|
const std::list<Representation*> AdaptationSet::GetRepresentations() const {
|
||||||
std::list<Representation*> representations;
|
std::list<Representation*> representations;
|
||||||
for (const std::unique_ptr<Representation>& representation :
|
for (const auto& representation_pair : representation_map_) {
|
||||||
representations_) {
|
representations.push_back(representation_pair.second.get());
|
||||||
representations.push_back(representation.get());
|
|
||||||
}
|
}
|
||||||
return representations;
|
return representations;
|
||||||
}
|
}
|
||||||
|
@ -450,7 +451,7 @@ void AdaptationSet::CheckLiveSegmentAlignment(uint32_t representation_id,
|
||||||
representation_start_times.push_back(start_time);
|
representation_start_times.push_back(start_time);
|
||||||
// There's no way to detemine whether the segments are aligned if some
|
// There's no way to detemine whether the segments are aligned if some
|
||||||
// representations do not have any segments.
|
// representations do not have any segments.
|
||||||
if (representation_segment_start_times_.size() != representations_.size())
|
if (representation_segment_start_times_.size() != representation_map_.size())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DCHECK(!representation_start_times.empty());
|
DCHECK(!representation_start_times.empty());
|
||||||
|
|
|
@ -229,7 +229,9 @@ class AdaptationSet {
|
||||||
void RecordFrameRate(uint32_t frame_duration, uint32_t timescale);
|
void RecordFrameRate(uint32_t frame_duration, uint32_t timescale);
|
||||||
|
|
||||||
std::list<ContentProtectionElement> content_protection_elements_;
|
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_;
|
base::AtomicSequenceNumber* const representation_counter_;
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
#include "packager/mpd/test/mpd_builder_test_helper.h"
|
#include "packager/mpd/test/mpd_builder_test_helper.h"
|
||||||
#include "packager/mpd/test/xml_compare.h"
|
#include "packager/mpd/test/xml_compare.h"
|
||||||
|
|
||||||
|
using ::testing::ElementsAre;
|
||||||
using ::testing::Not;
|
using ::testing::Not;
|
||||||
using ::testing::UnorderedElementsAre;
|
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
|
|
||||||
|
@ -590,7 +590,7 @@ TEST_F(AdaptationSetTest, BubbleUpAttributesToAdaptationSet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AdaptationSetTest, GetRepresentations) {
|
TEST_F(AdaptationSetTest, GetRepresentations) {
|
||||||
const char k480pMediaInfo[] =
|
const char kMediaInfo1[] =
|
||||||
"video_info {\n"
|
"video_info {\n"
|
||||||
" codec: 'avc1'\n"
|
" codec: 'avc1'\n"
|
||||||
" width: 720\n"
|
" width: 720\n"
|
||||||
|
@ -601,7 +601,7 @@ TEST_F(AdaptationSetTest, GetRepresentations) {
|
||||||
" pixel_height: 9\n"
|
" pixel_height: 9\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"container_type: 1\n";
|
"container_type: 1\n";
|
||||||
const char k360pMediaInfo[] =
|
const char kMediaInfo2[] =
|
||||||
"video_info {\n"
|
"video_info {\n"
|
||||||
" codec: 'avc1'\n"
|
" codec: 'avc1'\n"
|
||||||
" width: 640\n"
|
" width: 640\n"
|
||||||
|
@ -615,15 +615,29 @@ TEST_F(AdaptationSetTest, GetRepresentations) {
|
||||||
|
|
||||||
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage);
|
auto adaptation_set = CreateAdaptationSet(kAnyAdaptationSetId, kNoLanguage);
|
||||||
|
|
||||||
Representation* representation_480p =
|
Representation* representation1 =
|
||||||
adaptation_set->AddRepresentation(ConvertToMediaInfo(k480pMediaInfo));
|
adaptation_set->AddRepresentation(ConvertToMediaInfo(kMediaInfo1));
|
||||||
EXPECT_THAT(adaptation_set->GetRepresentations(),
|
EXPECT_THAT(adaptation_set->GetRepresentations(),
|
||||||
UnorderedElementsAre(representation_480p));
|
ElementsAre(representation1));
|
||||||
|
|
||||||
Representation* representation_360p =
|
Representation* representation2 =
|
||||||
adaptation_set->AddRepresentation(ConvertToMediaInfo(k360pMediaInfo));
|
adaptation_set->AddRepresentation(ConvertToMediaInfo(kMediaInfo2));
|
||||||
EXPECT_THAT(adaptation_set->GetRepresentations(),
|
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'
|
// 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());
|
AdaptationSet* adaptation_set_ptr = new_adaptation_set.get();
|
||||||
adaptation_sets_.push_back(std::move(new_adaptation_set));
|
adaptation_sets.push_back(adaptation_set_ptr);
|
||||||
return adaptation_sets_.back().get();
|
adaptation_set_map_[adaptation_set_ptr->id()] = std::move(new_adaptation_set);
|
||||||
|
return adaptation_set_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
xml::scoped_xml_ptr<xmlNode> Period::GetXml() {
|
xml::scoped_xml_ptr<xmlNode> Period::GetXml() {
|
||||||
|
@ -99,8 +100,8 @@ xml::scoped_xml_ptr<xmlNode> Period::GetXml() {
|
||||||
// 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 : adaptation_sets_) {
|
for (const auto& adaptation_set_pair : adaptation_set_map_) {
|
||||||
xml::scoped_xml_ptr<xmlNode> child(adaptation_set->GetXml());
|
xml::scoped_xml_ptr<xmlNode> child(adaptation_set_pair.second->GetXml());
|
||||||
if (!child || !period.AddChild(std::move(child)))
|
if (!child || !period.AddChild(std::move(child)))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -115,9 +116,8 @@ xml::scoped_xml_ptr<xmlNode> Period::GetXml() {
|
||||||
|
|
||||||
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 std::unique_ptr<AdaptationSet>& adaptation_set :
|
for (const auto& adaptation_set_pair : adaptation_set_map_) {
|
||||||
adaptation_sets_) {
|
adaptation_sets.push_back(adaptation_set_pair.second.get());
|
||||||
adaptation_sets.push_back(adaptation_set.get());
|
|
||||||
}
|
}
|
||||||
return adaptation_sets;
|
return adaptation_sets;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,8 +105,9 @@ class Period {
|
||||||
const MpdOptions& mpd_options_;
|
const MpdOptions& mpd_options_;
|
||||||
base::AtomicSequenceNumber* const adaptation_set_counter_;
|
base::AtomicSequenceNumber* const adaptation_set_counter_;
|
||||||
base::AtomicSequenceNumber* const representation_counter_;
|
base::AtomicSequenceNumber* const representation_counter_;
|
||||||
// The list of AdaptationSets in this Period.
|
// 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
|
||||||
|
|
|
@ -21,7 +21,6 @@ using ::testing::Eq;
|
||||||
using ::testing::InSequence;
|
using ::testing::InSequence;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
using ::testing::StrictMock;
|
using ::testing::StrictMock;
|
||||||
using ::testing::UnorderedElementsAre;
|
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -788,7 +787,7 @@ TEST_P(PeriodTest, SplitAdaptationSetsByLanguageAndCodec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(PeriodTest, GetAdaptationSets) {
|
TEST_P(PeriodTest, GetAdaptationSets) {
|
||||||
const char kAacEnglishAudioContent[] =
|
const char kContent1[] =
|
||||||
"audio_info {\n"
|
"audio_info {\n"
|
||||||
" codec: 'mp4a.40.2'\n"
|
" codec: 'mp4a.40.2'\n"
|
||||||
" sampling_frequency: 44100\n"
|
" sampling_frequency: 44100\n"
|
||||||
|
@ -799,7 +798,7 @@ TEST_P(PeriodTest, GetAdaptationSets) {
|
||||||
"reference_time_scale: 50\n"
|
"reference_time_scale: 50\n"
|
||||||
"container_type: CONTAINER_MP4\n"
|
"container_type: CONTAINER_MP4\n"
|
||||||
"media_duration_seconds: 10.5\n";
|
"media_duration_seconds: 10.5\n";
|
||||||
const char kAacGermanAudioContent[] =
|
const char kContent2[] =
|
||||||
"audio_info {\n"
|
"audio_info {\n"
|
||||||
" codec: 'mp4a.40.2'\n"
|
" codec: 'mp4a.40.2'\n"
|
||||||
" sampling_frequency: 44100\n"
|
" sampling_frequency: 44100\n"
|
||||||
|
@ -811,33 +810,75 @@ TEST_P(PeriodTest, GetAdaptationSets) {
|
||||||
"container_type: CONTAINER_MP4\n"
|
"container_type: CONTAINER_MP4\n"
|
||||||
"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>> adaptation_set_1(
|
||||||
new StrictMock<MockAdaptationSet>(1));
|
new StrictMock<MockAdaptationSet>(1));
|
||||||
auto* aac_eng_adaptation_set_ptr = aac_eng_adaptation_set.get();
|
auto* adaptation_set_1_ptr = adaptation_set_1.get();
|
||||||
std::unique_ptr<StrictMock<MockAdaptationSet>> aac_ger_adaptation_set(
|
std::unique_ptr<StrictMock<MockAdaptationSet>> adaptation_set_2(
|
||||||
new StrictMock<MockAdaptationSet>(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(_, _, _, _))
|
EXPECT_CALL(testable_period_, NewAdaptationSet(_, _, _, _))
|
||||||
.WillOnce(Return(ByMove(std::move(aac_eng_adaptation_set))))
|
.WillOnce(Return(ByMove(std::move(adaptation_set_1))))
|
||||||
.WillOnce(Return(ByMove(std::move(aac_ger_adaptation_set))));
|
.WillOnce(Return(ByMove(std::move(adaptation_set_2))));
|
||||||
|
|
||||||
ASSERT_EQ(aac_eng_adaptation_set_ptr,
|
ASSERT_EQ(adaptation_set_1_ptr, testable_period_.GetOrCreateAdaptationSet(
|
||||||
testable_period_.GetOrCreateAdaptationSet(
|
ConvertToMediaInfo(kContent1),
|
||||||
ConvertToMediaInfo(kAacEnglishAudioContent),
|
|
||||||
content_protection_in_adaptation_set_));
|
content_protection_in_adaptation_set_));
|
||||||
EXPECT_THAT(testable_period_.GetAdaptationSets(),
|
EXPECT_THAT(testable_period_.GetAdaptationSets(),
|
||||||
UnorderedElementsAre(aac_eng_adaptation_set_ptr));
|
ElementsAre(adaptation_set_1_ptr));
|
||||||
|
|
||||||
ASSERT_EQ(aac_ger_adaptation_set_ptr,
|
ASSERT_EQ(adaptation_set_2_ptr, testable_period_.GetOrCreateAdaptationSet(
|
||||||
testable_period_.GetOrCreateAdaptationSet(
|
ConvertToMediaInfo(kContent2),
|
||||||
ConvertToMediaInfo(kAacGermanAudioContent),
|
|
||||||
content_protection_in_adaptation_set_));
|
content_protection_in_adaptation_set_));
|
||||||
EXPECT_THAT(testable_period_.GetAdaptationSets(),
|
EXPECT_THAT(testable_period_.GetAdaptationSets(),
|
||||||
UnorderedElementsAre(aac_eng_adaptation_set_ptr,
|
ElementsAre(adaptation_set_1_ptr, adaptation_set_2_ptr));
|
||||||
aac_ger_adaptation_set_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,
|
INSTANTIATE_TEST_CASE_P(ContentProtectionInAdaptationSet,
|
||||||
PeriodTest,
|
PeriodTest,
|
||||||
::testing::Bool());
|
::testing::Bool());
|
||||||
|
|
Loading…
Reference in New Issue