Skip to content

stream.hls: add option to skip discontinuous segments (eg. ads) #2369

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

Closed

Conversation

beardypig
Copy link
Member

Adds a new option --hls-segment-skip-discontinuity, that will cause Streamlink to skip any part of the stream that is between two #EXT-X-DISCONTINUITY markers.

This can be used to skip ads that are injected in to the stream.

Can be used to skip the pre-roll and in-stream ads add by Twitch, as noted in #2368.

For example

streamlink --hls-segment-skip-discontinuity https://www.twitch.tv/esl_csgo best

@beardypig beardypig added enhancement WIP Work in process labels Mar 20, 2019
@Mathijsz
Copy link

Hi! There seem to be some NULL characters at the end of argparser.py. Removing them (e.g. by running sed -i 's/\x0//g' src/streamlink_cli/argparser.py) fixes the build errors :)

@beardypig
Copy link
Member Author

Ah damn. I’m having some issues with files getting corrupted on my VMs...

@beardypig beardypig force-pushed the hls-skip-discontinuous branch from a425bf3 to ee19a09 Compare March 20, 2019 17:25
@bastimeyer
Copy link
Member

Would it make sense splitting this into two parameters, one which ignores only segments at the beginning of the stream and one which ignores all of these segments?

In case of Twitch, you'd be able to skip the pre-roll ads or all ads, which is quite a difference.

@beardypig
Copy link
Member Author

I made it for twitch, but the idea is for skipping any discontinuity, to avoid borking the output stream.

The true purpose of this option is to avoid discontinuity in the stream output. In the case of twitch, it will drop the ads. But by dropping the ads you don't gain anything in terms of stream latency, or content that might be hidden by ads. You won't see the ads, nor the stream - I imagine you'll see the last frame of the stream before the ad started. Although I didn't encounter any mid-stream ads while testings, so it would be nice to know what actually happens :)

@c133
Copy link

c133 commented Mar 20, 2019

@beardypig Do you think it is possible to both block the pre-roll ad and get back the stream content that was lost because of that pre-roll ad?

@bastimeyer
Copy link
Member

@beardypig yes, I fully understand what it does and how it works... My idea was to add an additional parameter for only blocking initial pre-roll ads when launching the stream, because that is somewhat more acceptable to block than those kinds of ads during the stream. The ignored ads at the beginning will only cause a delay of the stream start, but if you're also blocking regular ads, then the stream will halt, just like when having a timeout, and will continue when the ads are over. Bridging this time can be problematic, depending on the player and its config, or the user expectation, so giving the user a choice here whether to block all ads or just the ones at the beginning sounds better to me.

@c133 No, this doesn't seem to be possible. Just think of ads during a live TV broadcast. Nobody has found a way yet to trick Twitch into listing the live steam segments instead of the ads. And it would be silly of them if they had implemented a way around that system. You'd need a magic request parameter, just like the workaround from a couple of days ago.

@beardypig
Copy link
Member Author

@bastimeyer this is a rather clean way to implement it, if we start messing with pre-roll vs. mid-stream it's going to get ugly. Not for this PR, perhaps a separate one.

@DeVaulted
Copy link

DeVaulted commented Mar 20, 2019

@beardypig I tested it for quite a while, you will simply see the last frame of the stream before the ad until the ad is over. Works like a charm, thank you!

//edit: Tested with both VLC and MPV.

@bastimeyer
Copy link
Member

@beardypig Hm, is it really messy? Wouldn't it be as simple as checking whether the discontinuity tag was set in the first playlist? But yeah, sure, this can be added later of course :)


Default is False.

Note: This option should be used with care, if the stream is running an ad
Copy link
Member

Choose a reason for hiding this comment

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

@beardypig do you think it would make sense filtering plugin specific tags/attributes for detecting this case?
See #2357 (comment)
Twitch live segments are annotated in the format #EXTINF:2.000,live and ad segments in the format #EXTINF:2.002,87d22d0b208d6a47c3bba6f412f7fb43-03-04-2019-05.03.22

Or are the metadata tags included at the beginning of all playlists during stream ads and not just the first one when the channel starts running ads?

Copy link
Member Author

Choose a reason for hiding this comment

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

I didn't want it to be enabled by default in any plugin, but it could be. I didn't check, but I assumed that the format for VOD would be similar to the ads...

Copy link
Member

Choose a reason for hiding this comment

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

Hm, yeah, maybe, I didn't think about that. 😕

Choose a reason for hiding this comment

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

Would appreciate this option — I only watch live streams and right now it's a crapshoot if I get an ad on launch.

Default is False.

Note: This option should be used with care, if the stream is running an ad
when Streamlink connects the ad will play and the actual stream will be
Copy link
Member

Choose a reason for hiding this comment

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

missing comma after "connects"

@bastimeyer
Copy link
Member

bastimeyer commented Mar 21, 2019

Btw, shouldn't the discontinuity state be kept between playlist reloads? I wrote some tests for your changes, and I'm not sure if I'm misinterpreting something here or did something else wrong, but it looks like it doesn't keep it.

beardypig/streamlink@hls-skip-discontinuous...bastimeyer:hls/skip-discontinuity

edit: had one test assertion wrong... branch is now updated and both tests (properly) failing

@beardypig
Copy link
Member Author

Yep, needs more work :D

@bastimeyer
Copy link
Member

If you move the discontinuity state to the worker and pass it to the playlist parser so that it can toggle the state, it should be working fine. I've updated the tests again and added a commit which includes these changes. It's probably a bit messy and not done the right way, but at least you can see what I mean.

@bastimeyer
Copy link
Member

I don't think this boolean discontinuity approach works... I just got two ads in a row. The first one was properly skipped, the second one was shown, and then the regular live stream got skipped again.

This is what needs to be done: #2357 (comment)
#EXT-X-SCTE35-OUT and #EXT-X-SCTE35-IN mark the start and end of an ad.

@bastimeyer
Copy link
Member

bastimeyer commented Mar 22, 2019

Since I don't know much about the actual HLS specs (especially regarding these tags), I did a little bit of more research and from how I understand this, it looks like Twitch is using their own implementation here which differs from other standards.

While Twitch is using the EXT-X-SCTE35-OUT and EXT-X-SCTE35-IN tags, data about the start+end and length of the ad segments can also be defined in the attributes of the EXT-X-DATERANGE tag. These attributes are START-DATE, (PLANNED-)?DURATION (which they are both including) and also SCTE35-{IN,OUT} with a unique ID value (which they are not including). I don't know though how useful the EXT-X-DATERANGE data is for skipping the ads.
Then there are also the EXT-X-CUE-OUT, EXT-X-CUE-OUT-CONT and EXT-X-CUE-IN tags, which are basically the same as the EXT-X-SCTE35-{IN,OUT} ones, but with an additional -CONT tag meant to be included in media sequences in between ad breaks.

This makes me think whether this kind of stuff belongs into the twitch plugin with a custom HLSStream implementation and whether the CLI parameter should be specific to the twitch plugin.

I've changed my branch to the SCTE35 stuff now (not yet pushed to my fork though), but since I haven't got any ads on Twitch, I can't verify if it's actually working. The tests alone don't say much.

I would appreciate if we could find a solution here as quickly as possible, because this is blocking the 1.1.0 release which I have been waiting for for far too long now.

@Zero3K
Copy link

Zero3K commented Mar 23, 2019

Any news regarding it?

@bastimeyer
Copy link
Member

@beardypig Can you take a look at this please before I open a pull request? (see each individual commit)
master...bastimeyer:plugins/twitch/disable-ads

This adds the --twitch-disable-ads parameter, is based on the SCTE35-{OUT,IN} HLS tags and implements a custom HLSStream solution for the Twitch plugin. Required a bit of refactoring here and there and the code is probably a bit messy. I haven't got any ads on Twitch since 2 days unfortunately, so I can't test this on real streams. The unittests however should be fine for the custom HLSStream* classes.

@Zero3K
Copy link

Zero3K commented Mar 23, 2019

@bastimeyer Why not just have it disable Twitch ads automatically without having to use the parameter that you mentioned?

@bastimeyer
Copy link
Member

Because it's skipping segments and that will cause the stream launch to be delayed. And ads during the stream will cause it to freeze until there's regular stream data again. This will probably confuse everyone who's not aware of the embedded streams situation.
The default value can still be debated (not in this PR though), but I think this implementation should be behind a parameter.

@Zero3K
Copy link

Zero3K commented Mar 23, 2019

There's no way to prevent those issues?

@bastimeyer
Copy link
Member

#2369 (comment)

No, this doesn't seem to be possible. Just think of ads during a live TV broadcast. Nobody has found a way yet to trick Twitch into listing the live steam segments instead of the ads. And it would be silly of them if they had implemented a way around that system. You'd need a magic request parameter, just like the workaround from a couple of days ago.

@dojima
Copy link

dojima commented Mar 23, 2019

Nobody has found a way yet to trick Twitch into listing the live steam segments instead of the ads. And it would be silly of them if they had implemented a way around that system. You'd need a magic request parameter, just like the workaround from a couple of days ago.

I wanted to test it more thoroughly before I mentioned it, but a few days ago when they were vigorously testing direct ad injection, I did notice that I didn't receive any ads on the official Twitch app on iOS when using an adblocking DNS. This leads me to believe that they were still using the old system of displaying ads for some platforms. It's not likely to matter much if their testing was a success, since they'd eventually move over to direct injection for all platforms, but it's interesting nonetheless.

@beardypig
Copy link
Member Author

@bastimeyer, yeah not so simple as I hoped. Your approach sounds much better, right now I don’t have time to review it - I will on Monday/Tuesday, it looks quite substantial. I’d like to get @back-to to take a look too.

Create a PR, and we’ll move discussion over there as this PR is dead :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement WIP Work in process
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants