-
Notifications
You must be signed in to change notification settings - Fork 242
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
[AdaptiveStream] Rework to improve HLS manifest updates #1459
Conversation
fdab26d
to
a06883a
Compare
@@ -720,15 +722,32 @@ bool AdaptiveStream::start_stream(uint64_t startPts) | |||
current_rep_->get_segment(static_cast<size_t>(segmentId - current_rep_->GetStartNumber())); | |||
} | |||
} | |||
else if (stream_changed_) // switching streams, align new stream segment no. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have lost most of the time due to this method AdaptiveStream::start_stream
because i was not aware that the AdaptiveStream::start_stream method is used to adjust/set the "current segment" and so all my changes that i was doing on ensure_segment always was failing.
After discovered this, i realized that was missing set "current segment" for a stream quality switching case
//! @todo: THIS MUST BE CHANGED - !! BUG !! | ||
//! this will broken/stop playback on live streams when adaptive stream change stream quality (so representation) | ||
//! and there are no new segments because not immediately available (despite child manifest updated), | ||
//! because we cant be ensure next segment without wait the appropriate timing...imo its not the right place here. | ||
//! Can be reproduced with HLS live and by using "Stream selection" setting to "Test" by switching per 1 segment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also found this problem (read todo) i tried force remove this block of code that stop playback, and a bit below avoid set currentPTSOffset_ when there is no next_segment, playback works but show weird pts on Kodi GUI the value of time becomes sometimes negative and it can lead to weirdness in the long run.
Need to be changed on other way but idk atm, can be done separately, maybe can you help here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes the scenario makes sense why it fails. We could try a hacky workaround until something better comes along - assume when the next segment comes it will be the same size (usually is) and add that PTS to current segment's start PTS. Sound good or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i understood but as you said its hacky im not 100% sure that could be so good
i found this problem even when trying to fix bugs to make this live sample playable
https://livesim.dashif.org/livesim/periods_20/testpic_2s/Manifest.mpd
This live sample have periods but no new segments provided,
then its required the use of "InsertLiveSegment" in conjuction with the manifest update worker.
This sample somewhat works on kodi <=v20 because of old code hacks and periods seem "ignored",
on kodi 21 is ofc broken, from what i see seem there are multiple problems on CDashTree::RefreshLiveSegments
that seem dont take in account of "inserted" segments on timeline, delete them all and so seem to loose the last inserted segment with the updated pts (because you have to take in account that the downloaded updated manifest dont provide new segments), this will make problems with AdaptiveStream::ensureSegment
that its not able to find next segment, AdaptiveStream::start_stream
have problem when switch period, and also with CSession::OnSegmentChangedRead
that its not able to insert new segments anymore
(these problems may be also similar with #1461)
if (newRep->SegmentTimeline().IsEmpty()) | ||
GenerateSidxSegments(newRep); | ||
|
||
if (!newRep->IsPrepared() && m_tree->SecondsSinceRepUpdate(newRep) > 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On representation class IsPrepared
and m_isDownloaded
plus the SecondsSinceRepUpdate
imo was really a mess of behaviours, i have removed them all, and add a new IsNeedsUpdates
, used only internally in the HLSParser to distinguish whether a representation needs an update of some thing (in this case for live updates)
return !checkTime || | ||
(current_adp_->GetStreamType() != StreamType::VIDEO && | ||
current_adp_->GetStreamType() != StreamType::AUDIO) || | ||
SecondsSinceUpdate() < 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SecondsSinceUpdate
uses (now removed) above and here should be the cause of the RAI buzz/frezze sound, by debugging this waitingForSegment method, was producing messed up return values
|
||
// We can fall here when we are waiting for new segments, but the download it not started yet | ||
// so return true only when checkTime is false, to avoid trigger EOS on sample reader and stop playback | ||
return !checkTime; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the main cause because the Pluto TV stream was stopping playback (before was returning "false")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good find!
// Disable representation only after stopped the worker | ||
// otherwise if read some segments may invalidate this change | ||
if (current_rep_) | ||
current_rep_->SetIsEnabled(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here the problem should be due to AdaptiveStream::ensureSegment
since force change SetIsEnabled
on the representation and race condition may happens
@@ -1552,7 +1552,6 @@ void adaptive::CDashTree::RefreshSegments(PLAYLIST::CPeriod* period, | |||
{ | |||
if (adp->GetStreamType() == StreamType::VIDEO || adp->GetStreamType() == StreamType::AUDIO) | |||
{ | |||
m_updThread.ResetStartTime(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be a remnant of the old manifest update code, has no sense reset the worker thread here, isnt used when we update manifest at each new segment request "manually"
PLAYLIST::CAdaptationSet* adp, | ||
PLAYLIST::CRepresentation* rep, | ||
bool update) | ||
bool adaptive::CHLSTree::PrepareRepresentation(PLAYLIST::CPeriod* period, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here github show a big mess on code diff, there are no functional code changes on PrepareRepresentation, the only difference is that has been decoupled per functionality.
The old prepareRepresentation
now has been splitted on more methods:
- PrepareRepresentation: Act more or less as before
- DownloadChildManifest: To download the child manifest only
- ParseChildManifest: Parse the child manifest data
- PrepareSegments: Update the segments (to adjust/set "current segment")
now ParseChildManifest could be reused in future to parse in right way the media playlist on CHLSTree::ParseManifest (see todo), not tested now, but a step forward to achieve it
@glennguy when you will have time try test this PR and review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks so much for this work and fixing some of the issues in adaptivestream.
//! @todo: THIS MUST BE CHANGED - !! BUG !! | ||
//! this will broken/stop playback on live streams when adaptive stream change stream quality (so representation) | ||
//! and there are no new segments because not immediately available (despite child manifest updated), | ||
//! because we cant be ensure next segment without wait the appropriate timing...imo its not the right place here. | ||
//! Can be reproduced with HLS live and by using "Stream selection" setting to "Test" by switching per 1 segment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes the scenario makes sense why it fails. We could try a hacky workaround until something better comes along - assume when the next segment comes it will be the same size (usually is) and add that PTS to current segment's start PTS. Sound good or not?
|
||
// We can fall here when we are waiting for new segments, but the download it not started yet | ||
// so return true only when checkTime is false, to avoid trigger EOS on sample reader and stop playback | ||
return !checkTime; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good find!
bddc3c0
to
9296d63
Compare
Description
While was developing this i found many weirdness that i think are not new bugs,
most of these bugs can be reproduced by using "Stream selection" setting to "Test" by switching per 1 segment.
That could happens for example on live stream, that when switch quality kodi call OpenStream, but when AdaptiveStream::start_stream is called, dont find the next segment because not yet available and stop the playback wrongly....
One single time, i catched two kodi freeze/crash, when played "akmai" local stream:
1 case when doing video seek, two times, in fast way on the "same" point (with mouse)
1 case when stop playback
more likely i think are already existings bugs
PR Changes for live streams:
Unsolved bug was already existing:
if you play a HLS live stream with subtitles that are disabled,
when switch to a new period (DEMUX_SPECIALID_STREAMCHANGE) the subtitle stream will be re-enabled, this cause error
GenerateSidxSegments: [AS-20] Cannot generate segments
due to not downloaded child manifest
Unsolved bug i think was already existing:
Chapter change (DEMUX_SPECIALID_STREAMCHANGE) may be executed 2 times! by audio and video stream, i think due to slight differrent pts, could be?!, not easy to catch but its happened to me 1 or 2 times
idk if kodi expect one single chapter change?
tomorrow i will comment some code parts... to give some details on code changesdoneMotivation and context
I have lost 2 weeks of nights on this also because its a big mess from old messy implementations and things that from my part i find difficult to learn how works
i think however that what i have done here should be better of what was there before and after estenuants tests seem almost stable, at least without hard use of adaptive streaming quality switching (on my tests always: "Test" mode per 1 segment)
fix #1438
this will fix also subtitles segment problem of #1109
where subtitles was displayed only for the first segments only and then stopped
How has this been tested?
For multiperiod/chapters/ads:
Live Pluto TV i cant post the master manifest m3u8 link because expire after hours, but can be found on network flow of:
https://pluto.tv/en/live-tv/
http://mcdn.daserste.de/daserste/de/master.m3u8 (also for subs, not always there are news/tvshow)
"Akmai local stream"
Other live, no chapters:
https://cdndai.pl/tvp1hd/index.m3u8 (sometime the server may temporary ban your IP for ~30minuts)
RAI:
#KODIPROP:inputstream.adaptive.live_delay=30
https://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=2606803&output=7
Screenshots (if appropriate):
Types of change
Checklist: