Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AdaptiveTree] Rework of manifest update params #1288

Merged
merged 1 commit into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion inputstream.adaptive/addon.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
name="adaptive"
extension=""
tags="true"
listitemprops="license_type|license_key|license_data|license_flags|manifest_type|server_certificate|manifest_update_parameter|manifest_params|manifest_headers|stream_params|stream_headers|original_audio_language|play_timeshift_buffer|pre_init_data|stream_selection_type|chooser_bandwidth_max|chooser_resolution_max|chooser_resolution_secure_max|live_delay"
listitemprops="license_type|license_key|license_data|license_flags|manifest_type|server_certificate|manifest_update_parameter|manifest_upd_params|manifest_params|manifest_headers|stream_params|stream_headers|original_audio_language|play_timeshift_buffer|pre_init_data|stream_selection_type|chooser_bandwidth_max|chooser_resolution_max|chooser_resolution_secure_max|live_delay"
library_@PLATFORM@="@LIBRARY_FILENAME@"/>
<extension point="xbmc.addon.metadata">
<platform>@PLATFORM@</platform>
Expand Down
30 changes: 17 additions & 13 deletions src/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,20 +238,24 @@ bool CSession::Initialize()
}

std::string manifestUrl = m_manifestUrl;
std::string manifestUpdateParam = m_kodiProps.m_manifestUpdParams;

//! @todo: In the next version of kodi, remove this hack of adding the $START_NUMBER$ parameter
//! to the manifest url which is forcibly cut and copied to the manifest update request url,
//! this seem used by YouTube addon only, adaptations are relatively simple
std::string manifestUpdateParam = m_kodiProps.m_manifestUpdateParam;
if (manifestUpdateParam.empty() && STRING::Contains(manifestUrl, "$START_NUMBER$"))
if (manifestUpdateParam.empty() && !m_kodiProps.m_manifestUpdateParam.empty())
{
LOG::Log(LOGWARNING,
"The misuse of adding params with $START_NUMBER$ placeholder to the "
"manifest url has been deprecated and will be removed on next Kodi version.\n"
"Please use \"manifest_update_parameter\" Kodi property to set manifest update "
"parameters, see Wiki integration page.");
manifestUpdateParam = URL::GetParametersFromPlaceholder(manifestUrl, "$START_NUMBER$");
manifestUrl.resize(manifestUrl.size() - manifestUpdateParam.size());
//! @todo: In the next version of kodi, remove this hack of adding the $START_NUMBER$ parameter
//! to the manifest url which is forcibly cut and copied to the manifest update request url,
//! this seem used by YouTube addon only, adaptations are relatively simple
std::string manifestUpdateParam = m_kodiProps.m_manifestUpdateParam;
if (manifestUpdateParam.empty() && STRING::Contains(manifestUrl, "$START_NUMBER$"))
{
LOG::Log(LOGWARNING,
"The misuse of adding params with $START_NUMBER$ placeholder to the "
"manifest url has been deprecated and will be removed on next Kodi version.\n"
"Please use \"manifest_upd_params\" Kodi property to set manifest update "
"parameters, see Wiki integration page.");
manifestUpdateParam = URL::GetParametersFromPlaceholder(manifestUrl, "$START_NUMBER$");
manifestUrl.resize(manifestUrl.size() - manifestUpdateParam.size());
}
}

CURL::HTTPResponse manifestResp;
Expand Down Expand Up @@ -1272,7 +1276,7 @@ bool CSession::SeekTime(double seekTime, unsigned int streamId, bool preceeding)
seekTime -= chapterTime;

// don't try to seek past the end of the stream, leave a sensible amount so we can buffer properly
if (m_adaptiveTree->has_timeshift_buffer_)
if (m_adaptiveTree->IsLive())
{
double maxSeek{0};
uint64_t curTime;
Expand Down
2 changes: 1 addition & 1 deletion src/Session.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ class ATTR_DLL_LOCAL CSession : public adaptive::AdaptiveStreamObserver
/*! \brief Report if the current content is dynamic/live
* \return True if live, false if VOD
*/
bool IsLive() const { return m_adaptiveTree->has_timeshift_buffer_; };
bool IsLive() const { return m_adaptiveTree->IsLive(); };

/*! \brief Get the type of manifest being played
* \return ManifestType - MPD/ISM/HLS
Expand Down
14 changes: 6 additions & 8 deletions src/common/AdaptiveStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,17 +407,15 @@ void AdaptiveStream::worker()
thread_data_->signal_dl_.notify_one();
lckdl.unlock();

bool isLive = tree_.has_timeshift_buffer_;

//! @todo: for live content we should calculate max attempts and sleep timing
//! based on segment duration / playlist updates timing
size_t maxAttempts = isLive ? 10 : 6;
std::chrono::milliseconds msSleep = isLive ? 1000ms : 500ms;
size_t maxAttempts = tree_.IsLive() ? 10 : 6;
std::chrono::milliseconds msSleep = tree_.IsLive() ? 1000ms : 500ms;

//! @todo: Some streaming software offers subtitle tracks with missing fragments, usually live tv
//! When a programme is broadcasted that has subtitles, subtitles fragments are offered,
//! Ensure we continue with the next segment after one retry on errors
if (current_adp_->GetStreamType() == StreamType::SUBTITLE && isLive)
if (current_adp_->GetStreamType() == StreamType::SUBTITLE && tree_.IsLive())
maxAttempts = 2;

size_t downloadAttempts = 1;
Expand Down Expand Up @@ -659,13 +657,13 @@ bool AdaptiveStream::start_stream()

if (!current_rep_->current_segment_)
{
if (!play_timeshift_buffer_ && tree_.has_timeshift_buffer_ &&
if (!play_timeshift_buffer_ && tree_.IsLive() &&
current_rep_->SegmentTimeline().GetSize() > 1 && tree_.m_periods.size() == 1)
{
if (!last_rep_)
{
std::size_t pos;
if (tree_.has_timeshift_buffer_ || tree_.available_time_ >= tree_.stream_start_)
if (tree_.IsLive() || tree_.available_time_ >= tree_.stream_start_)
{
pos = current_rep_->SegmentTimeline().GetSize() - 1;
}
Expand Down Expand Up @@ -914,7 +912,7 @@ bool AdaptiveStream::ensureSegment()
if (tree_.SecondsSinceRepUpdate(newRep) > 1)
{
tree_.prepareRepresentation(
current_period_, current_adp_, newRep, tree_.has_timeshift_buffer_);
current_period_, current_adp_, newRep, tree_.IsLive());
}

size_t nextsegmentPos = static_cast<size_t>(nextsegno - newRep->GetStartNumber());
Expand Down
8 changes: 4 additions & 4 deletions src/common/AdaptiveTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace adaptive
void AdaptiveTree::Configure(const UTILS::PROPERTIES::KodiProperties& kodiProps,
CHOOSER::IRepresentationChooser* reprChooser,
std::string_view supportedKeySystem,
std::string_view manifestUpdateParam)
std::string_view manifestUpdParams)
{
m_reprChooser = reprChooser;
m_supportedKeySystem = supportedKeySystem;
Expand All @@ -56,7 +56,7 @@ namespace adaptive

m_manifestParams = kodiProps.m_manifestParams;
m_manifestHeaders = kodiProps.m_manifestHeaders;
m_manifestUpdateParam = manifestUpdateParam;
m_manifestUpdParams = manifestUpdParams;

// Convenience way to share common addon settings we avoid
// calling the API many times to improve parsing performance
Expand All @@ -81,7 +81,7 @@ namespace adaptive
LOG::Log(LOGINFO,
"Manifest successfully parsed (Periods: %zu, Streams in first period: %zu, Type: %s)",
m_periods.size(), m_currentPeriod->GetAdaptationSets().size(),
has_timeshift_buffer_ ? "live" : "VOD");
m_isLive ? "live" : "VOD");
}

void AdaptiveTree::FreeSegments(CPeriod* period, CRepresentation* repr)
Expand All @@ -106,7 +106,7 @@ namespace adaptive
uint32_t fragmentDuration,
uint32_t movie_timescale)
{
if (!has_timeshift_buffer_ || HasManifestUpdates() || repr->HasSegmentsUrl())
if (!m_isLive || HasManifestUpdates() || repr->HasSegmentsUrl())
return;

// Check if its the last frame we watch
Expand Down
26 changes: 12 additions & 14 deletions src/common/AdaptiveTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,12 @@ class ATTR_DLL_LOCAL AdaptiveTree
std::string manifest_url_;
std::string base_url_;

//! @todo: m_manifestUpdateParam is used to force enabling manifest updates and to
//! be able to set also parameters to the manifest update url, we should start decouple
//! the "full" use case and the parameters case with appropriate separate properties,
//! in a future "full" use case should be dropped and possible broken dash live manifest fixed
std::string m_manifestUpdateParam;

std::optional<uint32_t> initial_sequence_; // HLS only
uint64_t m_totalTimeSecs{0}; // Total playing time in seconds
uint64_t stream_start_{0};
uint64_t available_time_{0};
uint64_t base_time_{0}; // SmoothTree only, the lower start PTS time between all StreamIndex tags
uint64_t m_liveDelay{0}; // Apply a delay in seconds from the live edge
bool has_timeshift_buffer_{false}; // Returns true when there is timeshift buffer for live content

std::string m_supportedKeySystem;
std::string location_;
Expand All @@ -85,15 +78,12 @@ class ATTR_DLL_LOCAL AdaptiveTree
/*!
* \brief Configure the adaptive tree.
* \param kodiProps The Kodi properties
* \param manifestUpdateParam Set to "full" to force enabling future manifest updates or set parameters
* that will be add to manifest request url, with an optional support
* of placeholder $START_NUMBER$ to allow set the segment start number
* to the parameter e.g. ?start_seq=$START_NUMBER$ become ?start_seq=10
* \param manifestUpdParams Parameters to be add to manifest request url, depends on manifest implementation
*/
virtual void Configure(const UTILS::PROPERTIES::KodiProperties& kodiProps,
CHOOSER::IRepresentationChooser* reprChooser,
std::string_view supportedKeySystem,
std::string_view manifestUpdateParam);
std::string_view manifestUpdParams);

/*!
* \brief Open manifest data for parsing.
Expand Down Expand Up @@ -168,10 +158,15 @@ class ATTR_DLL_LOCAL AdaptiveTree

std::string BuildDownloadUrl(const std::string& url) const;

/*!
* \brief Check for live streaming content (timeshift buffer)
* \return True for live streaming content, otherwise false for VOD content
*/
bool IsLive() const { return m_isLive; }

bool HasManifestUpdates() const
{
return ~m_updateInterval && m_updateInterval > 0 && has_timeshift_buffer_ &&
!m_manifestUpdateParam.empty();
return m_isLive && ~m_updateInterval && m_updateInterval > 0;
}

const std::chrono::time_point<std::chrono::system_clock> GetLastUpdated() const { return lastUpdated_; };
Expand Down Expand Up @@ -257,12 +252,15 @@ class ATTR_DLL_LOCAL AdaptiveTree
void SortTree();

// Live segment update section
bool m_isLive{false};
virtual void StartUpdateThread();
virtual void RefreshLiveSegments() { lastUpdated_ = std::chrono::system_clock::now(); }
std::atomic<uint32_t> m_updateInterval{~0U};
TreeUpdateThread m_updThread;
std::atomic<std::chrono::time_point<std::chrono::system_clock>> lastUpdated_{std::chrono::system_clock::now()};

// Optionals URL parameters to add to the manifest update requests
std::string m_manifestUpdParams;
std::string m_manifestParams;
std::map<std::string, std::string> m_manifestHeaders;
CHOOSER::IRepresentationChooser* m_reprChooser{nullptr};
Expand Down
28 changes: 14 additions & 14 deletions src/parser/DASHTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,14 @@ void adaptive::CDashTree::ParseTagMPDAttribs(pugi::xml_node nodeMPD)
double mediaPresDuration =
XML::ParseDuration(XML::GetAttrib(nodeMPD, "mediaPresentationDuration"));

has_timeshift_buffer_ = XML::GetAttrib(nodeMPD, "type") == "dynamic";
m_isLive = XML::GetAttrib(nodeMPD, "type") == "dynamic";

double timeShiftBufferDepth{0};
std::string timeShiftBufferDepthStr;
if (XML::QueryAttrib(nodeMPD, "timeShiftBufferDepth", timeShiftBufferDepthStr))
{
timeShiftBufferDepth = XML::ParseDuration(timeShiftBufferDepthStr);
has_timeshift_buffer_ = true;
m_isLive = true;
}

std::string availabilityStartTimeStr;
Expand Down Expand Up @@ -511,9 +511,6 @@ void adaptive::CDashTree::ParseTagAdaptationSet(pugi::xml_node nodeAdp, PLAYLIST

adpSet->SetStartPTS(startPts);

if (m_manifestUpdateParam.empty() && has_timeshift_buffer_)
m_manifestUpdateParam = "full";

if (period->GetDuration() == 0 && segTemplate.GetTimescale() > 0)
{
// Calculate total duration of segments
Expand Down Expand Up @@ -818,9 +815,6 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr,
ParseTagSegmentTimeline(nodeSegTL, repr->SegmentTimeline(), segTemplate.GetTimescale(),
totalTimeSecs, &segTemplate);

if (m_manifestUpdateParam.empty() && has_timeshift_buffer_)
m_manifestUpdateParam = "full";

repr->nextPts_ = startPts;

if (!repr->SegmentTimeline().IsEmpty())
Expand Down Expand Up @@ -1061,7 +1055,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr,
segTl.range_end_ = repr->GetStartNumber();
segTl.startPTS_ = adpSet->GetStartPTS();

if (has_timeshift_buffer_ && !segTemplate->HasVariableTime() &&
if (m_isLive && !segTemplate->HasVariableTime() &&
segTemplate->GetDuration() > 0)
{
uint64_t sampleTime = period->GetStart() / 1000;
Expand Down Expand Up @@ -1498,12 +1492,18 @@ void adaptive::CDashTree::RefreshLiveSegments()

std::unique_ptr<CDashTree> updateTree{std::move(Clone())};

std::string manifestUrl = location_.empty() ? manifest_url_ : location_;

// Custom manifest update url parameters
std::string manifestParams;
if (m_manifestUpdateParam != "full")
manifestParams = m_manifestUpdateParam;
std::string manifestParams = m_manifestUpdParams;

std::string manifestUrl;
if (location_.empty())
{
manifestUrl = manifest_url_;
if (!manifestParams.empty())
manifestUrl = URL::RemoveParameters(manifestUrl, false);
}
else
manifestUrl = location_;

// YouTube needs segment start number as parameter
bool urlHaveStartNumber = manifestParams.find("$START_NUMBER$") != std::string::npos;
Expand Down
11 changes: 5 additions & 6 deletions src/parser/HLSTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ PLAYLIST::PrepareRepStatus adaptive::CHLSTree::prepareRepresentation(PLAYLIST::C
if (STRING::CompareNoCase(tagValue, "VOD"))
{
m_refreshPlayList = false;
has_timeshift_buffer_ = false;
m_isLive = false;
}
}
else if (tagName == "#EXT-X-TARGETDURATION")
Expand Down Expand Up @@ -546,7 +546,7 @@ PLAYLIST::PrepareRepStatus adaptive::CHLSTree::prepareRepresentation(PLAYLIST::C
else if (tagName == "#EXT-X-ENDLIST")
{
m_refreshPlayList = false;
has_timeshift_buffer_ = false;
m_isLive = false;
}
}

Expand Down Expand Up @@ -593,7 +593,7 @@ PLAYLIST::PrepareRepStatus adaptive::CHLSTree::prepareRepresentation(PLAYLIST::C
for (auto& p : m_periods)
{
totalTimeSecs += p->GetDuration() / p->GetTimescale();
if (!has_timeshift_buffer_ && !m_refreshPlayList)
if (!m_isLive && !m_refreshPlayList)
{
auto& adpSet = p->GetAdaptationSets()[adpSetPos];
adpSet->GetRepresentations()[reprPos]->m_isDownloaded = true;
Expand All @@ -603,7 +603,7 @@ PLAYLIST::PrepareRepStatus adaptive::CHLSTree::prepareRepresentation(PLAYLIST::C
else
{
totalTimeSecs = rep->GetDuration() / rep->GetTimescale();
if (!has_timeshift_buffer_ && !m_refreshPlayList)
if (!m_isLive && !m_refreshPlayList)
{
rep->m_isDownloaded = true;
}
Expand Down Expand Up @@ -1083,8 +1083,7 @@ bool adaptive::CHLSTree::ParseManifest(const std::string& data)
m_extGroups.clear();

// Set Live as default
has_timeshift_buffer_ = true;
m_manifestUpdateParam = "full";
m_isLive = true;

m_periods.push_back(std::move(period));

Expand Down
2 changes: 1 addition & 1 deletion src/parser/SmoothTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ bool adaptive::CSmoothTree::ParseManifest(const std::string& data)

if (STRING::CompareNoCase(XML::GetAttrib(nodeSSM, "IsLive"), "true"))
{
has_timeshift_buffer_ = true;
m_isLive = true;
stream_start_ = UTILS::GetTimestamp();
available_time_ = stream_start_;
}
Expand Down
Loading