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

[AdaptiveStream] Rework to improve HLS manifest updates #1459

Merged
merged 1 commit into from
Jan 28, 2024

Conversation

CastagnaIT
Copy link
Collaborator

@CastagnaIT CastagnaIT commented Jan 21, 2024

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 changes done

Motivation 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

  • Bug fix (non-breaking change which fixes an issue)
  • Clean up (non-breaking change which removes non-working, unmaintained functionality)
  • Improvement (non-breaking change which improves existing functionality)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that will cause existing functionality to change)
  • Cosmetic change (non-breaking change that doesn't touch code)
  • None of the above (please explain below)

Checklist:

  • I have read the Contributing document
  • My code follows the Code Guidelines of this project
  • My change requires a change to the Wiki documentation
  • I have updated the documentation accordingly

@CastagnaIT CastagnaIT added Type: Fix non-breaking change which fixes an issue Type: Cleanup non-breaking change which removes non-working or unmaintained functionality v21 Omega labels Jan 21, 2024
@@ -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.
Copy link
Collaborator Author

@CastagnaIT CastagnaIT Jan 22, 2024

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

Comment on lines +746 to +750
//! @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
Copy link
Collaborator Author

@CastagnaIT CastagnaIT Jan 22, 2024

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

Copy link
Contributor

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?

Copy link
Collaborator Author

@CastagnaIT CastagnaIT Jan 28, 2024

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)
Copy link
Collaborator Author

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;
Copy link
Collaborator Author

@CastagnaIT CastagnaIT Jan 22, 2024

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;
Copy link
Collaborator Author

@CastagnaIT CastagnaIT Jan 22, 2024

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")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good find!

Comment on lines +1328 to +1331
// Disable representation only after stopped the worker
// otherwise if read some segments may invalidate this change
if (current_rep_)
current_rep_->SetIsEnabled(false);
Copy link
Collaborator Author

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();
Copy link
Collaborator Author

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,
Copy link
Collaborator Author

@CastagnaIT CastagnaIT Jan 22, 2024

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

@CastagnaIT CastagnaIT marked this pull request as ready for review January 22, 2024 08:52
@CastagnaIT
Copy link
Collaborator Author

@glennguy when you will have time try test this PR and review
i add some comments in code and also on github to try explain the code changes

@CastagnaIT CastagnaIT linked an issue Jan 22, 2024 that may be closed by this pull request
6 tasks
Copy link
Contributor

@glennguy glennguy left a 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.

Comment on lines +746 to +750
//! @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
Copy link
Contributor

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good find!

@CastagnaIT CastagnaIT merged commit a3bc41d into xbmc:Omega Jan 28, 2024
10 checks passed
@CastagnaIT CastagnaIT deleted the fix_hls_man_new branch January 28, 2024 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Cleanup non-breaking change which removes non-working or unmaintained functionality Type: Fix non-breaking change which fixes an issue v21 Omega
Projects
None yet
2 participants