diff --git a/src/common/AdaptationSet.cpp b/src/common/AdaptationSet.cpp index 2d1c4f651..9e26307d6 100644 --- a/src/common/AdaptationSet.cpp +++ b/src/common/AdaptationSet.cpp @@ -23,6 +23,11 @@ void PLAYLIST::CAdaptationSet::AddCodecs(std::string_view codecs) m_codecs.insert(list.begin(), list.end()); } +void PLAYLIST::CAdaptationSet::AddCodecs(const std::set& codecs) +{ + m_codecs.insert(codecs.begin(), codecs.end()); +} + bool PLAYLIST::CAdaptationSet::ContainsCodec(std::string_view codec) { if (std::any_of(m_codecs.begin(), m_codecs.end(), @@ -86,18 +91,7 @@ bool PLAYLIST::CAdaptationSet::IsMergeable(const CAdaptationSet* other) const if (m_streamType != other->m_streamType) return false; - if (m_streamType == StreamType::VIDEO) - { - if (m_group == other->m_group && - std::find(m_switchingIds.begin(), m_switchingIds.end(), other->m_id) != - m_switchingIds.end() && - std::find(other->m_switchingIds.begin(), other->m_switchingIds.end(), m_id) != - other->m_switchingIds.end()) - { - return true; - } - } - else if (m_streamType == StreamType::AUDIO) + if (m_streamType == StreamType::AUDIO) { if (m_id == other->m_id && m_startPts == other->m_startPts && m_startNumber == other->m_startNumber && m_duration == other->m_duration && @@ -114,6 +108,46 @@ bool PLAYLIST::CAdaptationSet::IsMergeable(const CAdaptationSet* other) const return false; } +bool PLAYLIST::CAdaptationSet::CompareSwitchingId(const CAdaptationSet* other) const +{ + if (m_streamType != other->m_streamType || m_switchingIds.empty()) + return false; + + if (m_streamType == StreamType::VIDEO) + { + if (m_group == other->m_group && + std::find(m_switchingIds.cbegin(), m_switchingIds.cend(), other->m_id) != + m_switchingIds.cend() && + std::find(other->m_switchingIds.cbegin(), other->m_switchingIds.cend(), m_id) != + other->m_switchingIds.cend()) + { + //! @todo: we have no way to determine supported codecs by hardware in use + //! and can broken playback, we allow same codec only + for (std::string codec : m_codecs) + { + codec = codec.substr(0, codec.find('.')); // Get fourcc only + if (CODEC::IsVideo(codec) && CODEC::Contains(other->m_codecs, codec)) + { + return true; + } + } + } + } + else if (m_streamType == StreamType::AUDIO) + { + if (m_language == other->m_language && m_group == other->m_group && + std::find(m_switchingIds.cbegin(), m_switchingIds.cend(), other->m_id) != + m_switchingIds.cend() && + std::find(other->m_switchingIds.cbegin(), other->m_switchingIds.cend(), m_id) != + other->m_switchingIds.cend()) + { + return true; + } + } + + return false; +} + bool PLAYLIST::CAdaptationSet::Compare(const std::unique_ptr& left, const std::unique_ptr& right) { diff --git a/src/common/AdaptationSet.h b/src/common/AdaptationSet.h index d1ab8e5ad..4683ca171 100644 --- a/src/common/AdaptationSet.h +++ b/src/common/AdaptationSet.h @@ -65,6 +65,11 @@ class ATTR_DLL_LOCAL CAdaptationSet : public CCommonSegAttribs, public CCommonAt void AddCodecs(std::string_view codecs); const std::set& GetCodecs() { return m_codecs; } + /*! + * \brief Add codec strings + */ + void AddCodecs(const std::set& codecs); + StreamType GetStreamType() const { return m_streamType; } void SetStreamType(StreamType streamType) { m_streamType = streamType; } @@ -106,6 +111,14 @@ class ATTR_DLL_LOCAL CAdaptationSet : public CCommonSegAttribs, public CCommonAt bool IsMergeable(const CAdaptationSet* other) const; + /*! + * \brief Determine if an adaptation set is switchable with another one, + * as urn:mpeg:dash:adaptation-set-switching:2016 scheme + * \param adpSets The adaptation set to compare + * \return True if switchable, otherwise false + */ + bool CompareSwitchingId(const CAdaptationSet* other) const; + static bool Compare(const std::unique_ptr& left, const std::unique_ptr& right); diff --git a/src/common/AdaptiveTree.cpp b/src/common/AdaptiveTree.cpp index 4f167256b..d781c87ac 100644 --- a/src/common/AdaptiveTree.cpp +++ b/src/common/AdaptiveTree.cpp @@ -69,6 +69,8 @@ namespace adaptive void AdaptiveTree::PostOpen(const UTILS::PROPERTIES::KodiProperties& kodiProps) { + SortTree(); + // A manifest can provide live delay value, if not so we use our default // value of 16 secs, this is needed to ensure an appropriate playback, // an add-on can override the delay to try fix edge use cases @@ -141,61 +143,13 @@ namespace adaptive void AdaptiveTree::SortTree() { - for (auto itPeriod = m_periods.begin(); itPeriod != m_periods.end(); itPeriod++) + for (auto& period : m_periods) { - CPeriod* period = (*itPeriod).get(); - auto& periodAdpSets = period->GetAdaptationSets(); - - // Merge VIDEO & AUDIO adaptation sets - //! @todo: seem that merge adpsets is this not safe thing to do, adpsets may have different encryptions - //! and relative different child data (e.g. dash xml child tags) - //! it is needed to investigate if we really need do this, - //! if so maybe limit for some use cases or improve it in some way. - //! audio merging has been impl years ago without give any details of the reasons or for what manifest types - //! video merging has been impl by https://github.com/xbmc/inputstream.adaptive/pull/694 - //! second thing, merge should be decoupled from sort behaviour with different methods - for (auto itAdpSet = periodAdpSets.begin(); itAdpSet != periodAdpSets.end();) - { - auto adpSet = (*itAdpSet).get(); - auto itNextAdpSet = itAdpSet + 1; - - if (itNextAdpSet != periodAdpSets.end() && - (adpSet->GetStreamType() == StreamType::AUDIO || - adpSet->GetStreamType() == StreamType::VIDEO)) - { - auto nextAdpSet = (*itNextAdpSet).get(); - - if (adpSet->IsMergeable(nextAdpSet)) - { - std::vector& psshSets = period->GetPSSHSets(); - for (size_t index = 1; index < psshSets.size(); index++) - { - if (psshSets[index].adaptation_set_ == adpSet) - { - psshSets[index].adaptation_set_ = nextAdpSet; - } - } - - // Move representations unique_ptr from adpSet repr vector to nextAdpSet repr vector - for (auto itRepr = adpSet->GetRepresentations().begin(); - itRepr != adpSet->GetRepresentations().end(); itRepr++) - { - nextAdpSet->GetRepresentations().push_back(std::move(*itRepr)); - // We need to change the parent adaptation set in the representation itself - nextAdpSet->GetRepresentations().back()->SetParent(nextAdpSet); - } - - itAdpSet = periodAdpSets.erase(itAdpSet); - continue; - } - } - itAdpSet++; - } + auto& adpSets = period->GetAdaptationSets(); - std::stable_sort(periodAdpSets.begin(), periodAdpSets.end(), - CAdaptationSet::Compare); + std::stable_sort(adpSets.begin(), adpSets.end(), CAdaptationSet::Compare); - for (auto& adpSet : periodAdpSets) + for (auto& adpSet : adpSets) { std::sort(adpSet->GetRepresentations().begin(), adpSet->GetRepresentations().end(), CRepresentation::CompareBandwidth); diff --git a/src/parser/DASHTree.cpp b/src/parser/DASHTree.cpp index f8dd9a4b9..c332fd8cc 100644 --- a/src/parser/DASHTree.cpp +++ b/src/parser/DASHTree.cpp @@ -109,9 +109,9 @@ bool adaptive::CDashTree::Open(std::string_view url, return false; } - m_currentPeriod = m_periods[0].get(); + MergeAdpSets(); - SortTree(); + m_currentPeriod = m_periods[0].get(); return true; } @@ -348,7 +348,7 @@ void adaptive::CDashTree::ParseTagAdaptationSet(pugi::xml_node nodeAdp, PLAYLIST std::string id; // "audioTrackId" tag is amazon VOD specific, since dont use the standard "id" tag - // this helps to avoid merging adpSets (done with AdaptiveTree::SortTree) for some limit cases + // this to to make MergeAdpSets more effective for some limit case if (XML::QueryAttrib(nodeAdp, "id", id) || XML::QueryAttrib(nodeAdp, "audioTrackId", id)) adpSet->SetId(id); @@ -626,6 +626,12 @@ void adaptive::CDashTree::ParseTagAdaptationSet(pugi::xml_node nodeAdp, PLAYLIST } } + // Copy codecs in the adaptation set to make MergeAdpSets more effective + if (adpSet->GetCodecs().empty()) + { + adpSet->AddCodecs(adpSet->GetRepresentations().front()->GetCodecs()); + } + period->AddAdaptationSet(adpSet); } @@ -1380,6 +1386,53 @@ size_t adaptive::CDashTree::EstimateSegmentsCount(uint64_t duration, return static_cast(totalTimeSecs / lengthSecs); } +void adaptive::CDashTree::MergeAdpSets() +{ + // NOTE: This method wipe out all properties of merged adaptation set + for (auto itPeriod = m_periods.begin(); itPeriod != m_periods.end(); ++itPeriod) + { + auto period = itPeriod->get(); + auto& periodAdpSets = period->GetAdaptationSets(); + for (auto itAdpSet = periodAdpSets.begin(); itAdpSet != periodAdpSets.end(); ++itAdpSet) + { + CAdaptationSet* adpSet = itAdpSet->get(); + for (auto itNextAdpSet = itAdpSet + 1; itNextAdpSet != periodAdpSets.end();) + { + CAdaptationSet* nextAdpSet = itNextAdpSet->get(); + // IsMergeable: + // Some services (e.g. amazon) may have several AdaptationSets of the exact same audio track + // the only difference is in the ContentProtection kid/pssh and the base url, + // in order not to show several identical audio tracks in the Kodi GUI, we must merge adaptation sets + // CompareSwitchingId: + // Some services can provide switchable video adp sets, these could havedifferent codecs, and could be + // used to split HD resolutions from SD, so to allow Chooser's to autoselect the video quality + // we need to merge them all + // CODEC NOTE: since we cannot know in advance the supported video codecs by the hardware in use + // we cannot merge adp sets with different codecs otherwise playback will not work + if (adpSet->CompareSwitchingId(nextAdpSet) || adpSet->IsMergeable(nextAdpSet)) + { + // Sanitize adaptation set references to pssh sets + for (CPeriod::PSSHSet& psshSet : period->GetPSSHSets()) + { + if (psshSet.adaptation_set_ == nextAdpSet) + psshSet.adaptation_set_ = adpSet; + } + // Move representations to the first switchable adaptation set + for (auto itRepr = nextAdpSet->GetRepresentations().begin(); + itRepr < nextAdpSet->GetRepresentations().end(); ++itRepr) + { + itRepr->get()->SetParent(adpSet); + adpSet->GetRepresentations().push_back(std::move(*itRepr)); + } + itNextAdpSet = periodAdpSets.erase(itNextAdpSet); + } + else + ++itNextAdpSet; + } + } + } +} + bool adaptive::CDashTree::DownloadManifestUpd(std::string_view url, const std::map& reqHeaders, const std::vector& respHeaders, diff --git a/src/parser/DASHTree.h b/src/parser/DASHTree.h index ffe8c6e4a..e3854d244 100644 --- a/src/parser/DASHTree.h +++ b/src/parser/DASHTree.h @@ -80,6 +80,8 @@ class ATTR_DLL_LOCAL CDashTree : public adaptive::AdaptiveTree */ size_t EstimateSegmentsCount(uint64_t duration, uint32_t timescale, uint64_t totalTimeSecs = 0); + void MergeAdpSets(); + /*! * \brief Download manifest update, overridable method for test project */ diff --git a/src/parser/HLSTree.cpp b/src/parser/HLSTree.cpp index 91a863af5..52acb246c 100644 --- a/src/parser/HLSTree.cpp +++ b/src/parser/HLSTree.cpp @@ -167,8 +167,6 @@ bool adaptive::CHLSTree::Open(std::string_view url, m_currentPeriod = m_periods[0].get(); - // SortTree(); - return true; } diff --git a/src/parser/SmoothTree.cpp b/src/parser/SmoothTree.cpp index d42b2e0dd..5aab39c07 100644 --- a/src/parser/SmoothTree.cpp +++ b/src/parser/SmoothTree.cpp @@ -47,7 +47,6 @@ bool adaptive::CSmoothTree::Open(std::string_view url, m_currentPeriod = m_periods[0].get(); CreateSegmentTimeline(); - SortTree(); return true; } diff --git a/src/test/TestDASHTree.cpp b/src/test/TestDASHTree.cpp index 94d4bd2a2..05da49d5f 100644 --- a/src/test/TestDASHTree.cpp +++ b/src/test/TestDASHTree.cpp @@ -71,6 +71,7 @@ class DASHTreeTest : public ::testing::Test LOG::Log(LOGERROR, "Cannot open \"%s\" DASH manifest.", url.c_str()); exit(1); } + tree->PostOpen(m_kodiProps); } DASHTestTree* tree; @@ -611,19 +612,40 @@ TEST_F(DASHTreeTest, AdaptionSetSwitching) auto& adpSets = tree->m_periods[0]->GetAdaptationSets(); - EXPECT_EQ(adpSets.size(), 5); + EXPECT_EQ(adpSets.size(), 6); EXPECT_EQ(STR(adpSets[0]->GetRepresentations()[0]->GetId()), "3"); EXPECT_EQ(STR(adpSets[0]->GetRepresentations()[1]->GetId()), "1"); EXPECT_EQ(STR(adpSets[0]->GetRepresentations()[2]->GetId()), "2"); - + // Below adaptation set (id 6) should be merged with previous one + // but since has a different codec will not be merged + // see note on related DASH parser code EXPECT_EQ(STR(adpSets[1]->GetRepresentations()[0]->GetId()), "4"); - EXPECT_EQ(STR(adpSets[1]->GetRepresentations()[1]->GetId()), "5"); - EXPECT_EQ(STR(adpSets[2]->GetRepresentations()[0]->GetId()), "6"); + EXPECT_EQ(STR(adpSets[2]->GetRepresentations()[0]->GetId()), "5"); + EXPECT_EQ(STR(adpSets[2]->GetRepresentations()[1]->GetId()), "6"); EXPECT_EQ(STR(adpSets[3]->GetRepresentations()[0]->GetId()), "7"); EXPECT_EQ(STR(adpSets[4]->GetRepresentations()[0]->GetId()), "8"); + + EXPECT_EQ(STR(adpSets[5]->GetRepresentations()[0]->GetId()), "9"); +} + +TEST_F(DASHTreeTest, AdaptionSetMerge) +{ + OpenTestFile("mpd/adaptation_set_merge.mpd"); + + auto& adpSets = tree->m_periods[0]->GetAdaptationSets(); + + EXPECT_EQ(adpSets.size(), 6); + EXPECT_EQ(STR(adpSets[0]->GetRepresentations()[0]->GetId()), "video=100000"); + EXPECT_EQ(STR(adpSets[1]->GetRepresentations()[0]->GetId()), "audio_ja-JP_3=128000"); + EXPECT_EQ(STR(adpSets[2]->GetRepresentations()[0]->GetId()), "audio_es-419_3=128000"); + EXPECT_EQ(STR(adpSets[3]->GetRepresentations()[0]->GetId()), "audio_en-GB_3=96000"); + EXPECT_EQ(STR(adpSets[4]->GetRepresentations()[0]->GetId()), "audio_es-ES=20000"); + // Below two adaptation sets merged + EXPECT_EQ(STR(adpSets[5]->GetRepresentations()[0]->GetId()), "audio_es-ES_1=64000"); + EXPECT_EQ(STR(adpSets[5]->GetRepresentations()[1]->GetId()), "audio_es-ES_1=64000"); } TEST_F(DASHTreeTest, SuggestedPresentationDelay) diff --git a/src/test/TestHLSTree.cpp b/src/test/TestHLSTree.cpp index 84b262bb4..d32c91283 100644 --- a/src/test/TestHLSTree.cpp +++ b/src/test/TestHLSTree.cpp @@ -67,7 +67,7 @@ class HLSTreeTest : public ::testing::Test LOG::Log(LOGERROR, "Cannot open \"%s\" HLS manifest.", url.c_str()); exit(1); } - + tree->PostOpen(m_kodiProps); tree->m_currentAdpSet = tree->m_periods[0]->GetAdaptationSets()[0].get(); tree->m_currentRepr = tree->m_currentAdpSet->GetRepresentations()[0].get(); } diff --git a/src/test/TestSmoothTree.cpp b/src/test/TestSmoothTree.cpp index c3d0ae923..6254c95b7 100644 --- a/src/test/TestSmoothTree.cpp +++ b/src/test/TestSmoothTree.cpp @@ -62,6 +62,7 @@ class SmoothTreeTest : public ::testing::Test LOG::Log(LOGERROR, "Cannot open \"%s\" Smooth Streaming manifest.", url.c_str()); exit(1); } + tree->PostOpen(m_kodiProps); } SmoothTestTree* tree; diff --git a/src/test/manifests/mpd/adaptation_set_merge.mpd b/src/test/manifests/mpd/adaptation_set_merge.mpd new file mode 100644 index 000000000..d3c256bd1 --- /dev/null +++ b/src/test/manifests/mpd/adaptation_set_merge.mpd @@ -0,0 +1,245 @@ + + + + + + + + bAIAAAEAAQBiAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ARwB1ADYAeQBGAHAASABHAEQAawBXAGgAbgBJAFQAawBEADQANQBpAEkAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBQAFMARQBRAHEANQAwAEoAMwB3AGcAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAHIAbABzAC4AYQB0AHYALQBwAHMALgBhAG0AYQB6AG8AbgAuAGMAbwBtAC8AYwBkAHAAPAAvAEwAQQBfAFUAUgBMAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + CAESEBay7hrGkUUOoZyE5A+OYiEaBmFtYXpvbiI1Y2lkOkZyTHVHc2FSUlE2aG5JVGtENDVpSVE9PSw4MHVYUWxIYlRDU3pyNStuUXFOTHJRPT0qAlNEMgA= + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_video_1.mp4 + + + + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_video_2.mp4 + + + + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_video_3.mp4 + + + + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_video_4.mp4 + + + + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_video_5.mp4 + + + + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_video_6.mp4 + + + + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_video_7.mp4 + + + + + + + + + + + + + + + bAIAAAEAAQBiAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ARwB1ADYAeQBGAHAASABHAEQAawBXAGgAbgBJAFQAawBEADQANQBpAEkAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBQAFMARQBRAHEANQAwAEoAMwB3AGcAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAHIAbABzAC4AYQB0AHYALQBwAHMALgBhAG0AYQB6AG8AbgAuAGMAbwBtAC8AYwBkAHAAPAAvAEwAQQBfAFUAUgBMAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + CAESEBay7hrGkUUOoZyE5A+OYiEaBmFtYXpvbiI1Y2lkOkZyTHVHc2FSUlE2aG5JVGtENDVpSVE9PSw4MHVYUWxIYlRDU3pyNStuUXFOTHJRPT0qAlNEMgA= + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_audio_117.mp4 + + + + + + + + + + + + + + + bAIAAAEAAQBiAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ARwB1ADYAeQBGAHAASABHAEQAawBXAGgAbgBJAFQAawBEADQANQBpAEkAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBQAFMARQBRAHEANQAwAEoAMwB3AGcAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAHIAbABzAC4AYQB0AHYALQBwAHMALgBhAG0AYQB6AG8AbgAuAGMAbwBtAC8AYwBkAHAAPAAvAEwAQQBfAFUAUgBMAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + CAESEBay7hrGkUUOoZyE5A+OYiEaBmFtYXpvbiI1Y2lkOkZyTHVHc2FSUlE2aG5JVGtENDVpSVE9PSw4MHVYUWxIYlRDU3pyNStuUXFOTHJRPT0qAlNEMgA= + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_audio_127.mp4 + + + + + + + + + + + + + + + bAIAAAEAAQBiAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ARwB1ADYAeQBGAHAASABHAEQAawBXAGgAbgBJAFQAawBEADQANQBpAEkAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBQAFMARQBRAHEANQAwAEoAMwB3AGcAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAHIAbABzAC4AYQB0AHYALQBwAHMALgBhAG0AYQB6AG8AbgAuAGMAbwBtAC8AYwBkAHAAPAAvAEwAQQBfAFUAUgBMAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + CAESEBay7hrGkUUOoZyE5A+OYiEaBmFtYXpvbiI1Y2lkOkZyTHVHc2FSUlE2aG5JVGtENDVpSVE9PSw4MHVYUWxIYlRDU3pyNStuUXFOTHJRPT0qAlNEMgA= + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_audio_17.mp4 + + + + + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_audio_39.mp4 + + + + + + + + + + + + + + + bAIAAAEAAQBiAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ARwB1ADYAeQBGAHAASABHAEQAawBXAGgAbgBJAFQAawBEADQANQBpAEkAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBQAFMARQBRAHEANQAwAEoAMwB3AGcAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAHIAbABzAC4AYQB0AHYALQBwAHMALgBhAG0AYQB6AG8AbgAuAGMAbwBtAC8AYwBkAHAAPAAvAEwAQQBfAFUAUgBMAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + CAESEBay7hrGkUUOoZyE5A+OYiEaBmFtYXpvbiI1Y2lkOkZyTHVHc2FSUlE2aG5JVGtENDVpSVE9PSw4MHVYUWxIYlRDU3pyNStuUXFOTHJRPT0qAlNEMgA= + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_audio_83.mp4 + + + + + + + + + + + + + + + bAIAAAEAAQBiAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AUQBwAGQATAA4ADkAdABSAEoARQB5AHoAcgA1ACsAbgBRAHEATgBMAHIAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBjAG8AMgBaAGQAQQBIADgAZgBkAGMAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAHIAbABzAC4AYQB0AHYALQBwAHMALgBhAG0AYQB6AG8AbgAuAGMAbwBtAC8AYwBkAHAAPAAvAEwAQQBfAFUAUgBMAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + CAESEPNLl0JR20wks6+fp0KjS60aBmFtYXpvbiI1Y2lkOkZyTHVHc2FSUlE2aG5JVGtENDVpSVE9PSw4MHVYUWxIYlRDU3pyNStuUXFOTHJRPT0qAlNEMgA= + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_audio_84.mp4 + + + + + + + + + + + + + + + bAIAAAEAAQBiAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AUQBwAGQATAA4ADkAdABSAEoARQB5AHoAcgA1ACsAbgBRAHEATgBMAHIAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBjAG8AMgBaAGQAQQBIADgAZgBkAGMAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAHIAbABzAC4AYQB0AHYALQBwAHMALgBhAG0AYQB6AG8AbgAuAGMAbwBtAC8AYwBkAHAAPAAvAEwAQQBfAFUAUgBMAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + CAESEPNLl0JR20wks6+fp0KjS60aBmFtYXpvbiI1Y2lkOkZyTHVHc2FSUlE2aG5JVGtENDVpSVE9PSw4MHVYUWxIYlRDU3pyNStuUXFOTHJRPT0qAlNEMgA= + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_audio_108.mp4 + + + + + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_audio_120.mp4 + + + + + + + + + 697ce4af-7905-45fb-a910-89d8c6357c61_audio_172.mp4 + + + + + + + + + + + + + diff --git a/src/test/manifests/mpd/adaptation_set_switching.mpd b/src/test/manifests/mpd/adaptation_set_switching.mpd index baf66ffd9..d01e6d8d6 100644 --- a/src/test/manifests/mpd/adaptation_set_switching.mpd +++ b/src/test/manifests/mpd/adaptation_set_switching.mpd @@ -1,53 +1,58 @@ - + - + - + - + + + + + + - + - + - + - + - +