Repository: streamlink/streamlink

Issue:
pluto.tv: audio and video async after ad-break
### Checklist

- [X] This is a plugin issue and not a different kind of issue
- [X] [I have read the contribution guidelines](https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#contributing-to-streamlink)
- [X] [I have checked the list of open and recently closed plugin issues](https://github.com/streamlink/streamlink/issues?q=is%3Aissue+label%3A%22plugin+issue%22)
- [X] [I have checked the commit log of the master branch](https://github.com/streamlink/streamlink/commits/master)

### Streamlink version

Latest build from the master branch

### Description

I've installed the latest master with pip on my ubuntu 21.04 desktop and tested the new pluto.tv plugin. Good work, ads no longer stop the playback from OnDemand videos, but there is still one small issue left, at least on ubuntu.
If I playback an OnDemand video with
`streamlink https://pluto.tv...` 
it finds the plugin and downloads the video. But when the ad starts (black window with colorful font "Werbung" after about 20mins) it shows a few frames of it from the beginning and a few frames from the end of the ad-break. This seems to be only video, because if I download the file with the -o option, it has no timestamps, because of the incomplete GOP in these few frames. If I remux the file with mkvtoolnix, it has timestamps, but then audio and video are out of sync after the ad-break (audio and video are sync before the break). I've checked a few movies, all show the same behaviour. If I pipe the stream to ffplay, bad players crash (propably because of the incomplete GOP) at the ad-break, good players show only pixelation for a sec or two.

Is it possible to filter these few ad-frames ("Werbung"), too?

### Debug log

```text
./streamlink https://pluto.tv/de/on-demand/movies/meatballs-de-1978-1-1 best 
-o /home/user/Videos/Babyspeck_und_Fleischkloesschen.mp4 -l debug
[cli][debug] OS:         Linux-5.11.0-41-generic-x86_64-with-glibc2.33
[cli][debug] Python:     3.9.5
[cli][debug] Streamlink: 3.0.3+7.ge999ac5
[cli][debug] Requests(2.26.0), Socks(1.7.1), Websocket(1.2.3)
[cli][debug] Arguments:
[cli][debug]  url=https://pluto.tv/de/on-demand/movies/meatballs-de-1978-1-1
[cli][debug]  stream=['best']
[cli][debug]  --loglevel=debug
[cli][debug]  --output=/home/user/Videos/Babyspeck_und_Fleischkloesschen.mp4
[cli][info] Found matching plugin pluto for URL https://pluto.tv/de/on-demand/
movies/meatballs-de-1978-1-1
[plugins.pluto][debug] slug=meatballs-de-1978-1-1
[plugins.pluto][debug] app_version=5.106.0-
f3e2ac48d1dbe8189dc784777108b725b4be6be2
[plugins.pluto][debug] path=/stitch/hls/episode/6041ea2ae7c979001a897fe4/
master.m3u8
[utils.l10n][debug] Language code: de_DE
[cli][info] Available streams: 570k (worst), 1000k, 1500k, 2100k, 3100k (best)
[cli][info] Opening stream: 3100k (hls-pluto)
[stream.hls][debug] Reloading playlist
[cli][debug] Pre-buffering 8192 bytes
[stream.hls][debug] Segments in this playlist are encrypted
[stream.hls][debug] First Sequence: 0; Last Sequence: 1171
[stream.hls][debug] Start offset: 0; Duration: None; Start Sequence: 0; End 
Sequence: 1171
[stream.hls][debug] Adding segment 0 to queue
[stream.hls][debug] Adding segment 1 to queue
[stream.hls][debug] Adding segment 2 to queue
[stream.hls][debug] Adding segment 3 to queue
[stream.hls][debug] Adding segment 4 to queue
[stream.hls][debug] Adding segment 5 to queue
[stream.hls][debug] Adding segment 6 to queue
[stream.hls][debug] Adding segment 7 to queue
[stream.hls][debug] Adding segment 8 to queue
[stream.hls][debug] Adding segment 9 to queue
[stream.hls][debug] Adding segment 10 to queue
[stream.hls][debug] Adding segment 11 to queue
[stream.hls][debug] Adding segment 12 to queue
[stream.hls][debug] Adding segment 13 to queue
[stream.hls][debug] Adding segment 14 to queue
[stream.hls][debug] Adding segment 15 to queue
[stream.hls][debug] Adding segment 16 to queue
[stream.hls][debug] Adding segment 17 to queue
[stream.hls][debug] Adding segment 18 to queue
[stream.hls][debug] Adding segment 19 to queue
[stream.hls][debug] Adding segment 20 to queue
[stream.hls][debug] Adding segment 21 to queue
[stream.hls][debug] Segment 0 complete
[cli][debug] Checking file output
[stream.hls][debug] Adding segment 22 to queue
[cli][debug] Writing stream to output
[stream.hls][debug] Segment 1 complete
[stream.hls][debug] Adding segment 23 to queue
[stream.hls][debug] Segment 2 complete
[stream.hls][debug] Adding segment 24 to queue
[stream.hls][debug] Segment 3 complete
[stream.hls][debug] Adding segment 25 to queue
[download][.._Fleischkloesschen.mp4] Written 3.4 MB (0s @ 4.9 MB/s)                                                                                                                                                                        
[stream.hls][debug] Segment 4 complete
[stream.hls][debug] Adding segment 26 to queue
[stream.hls][debug] Segment 5 complete
[stream.hls][debug] Adding segment 27 to queue
[download][.._Fleischkloesschen.mp4] Written 6.1 MB (1s @ 4.8 MB/s)                                                                                                                                                                        
[stream.hls][debug] Segment 6 complete
[stream.hls][debug] Adding segment 28 to queue
[stream.hls][debug] Segment 7 complete
[stream.hls][debug] Adding segment 29 to queue
[download][.._Fleischkloesschen.mp4] Written 9.2 MB (1s @ 4.8 MB/s)                                                                                                                                                                        
[stream.hls][debug] Segment 8 complete
[stream.hls][debug] Adding segment 30 to queue
[download][.._Fleischkloesschen.mp4] Written 10.7 MB (2s @ 4.2 MB/s)                                                                                                                                                                       
[stream.hls][debug] Segment 9 complete
[stream.hls][debug] Adding segment 31 to queue
[stream.hls][debug] Segment 10 complete
[download][.._Fleischkloesschen.mp4] Written 13.7 MB (3s @ 4.1 MB/s)
[stream.hls][debug] Adding segment 32 to queue
                                                                                                                                                                       [stream.hls]
[debug] Segment 11 complete
[stream.hls][debug] Adding segment 33 to queue
[stream.hls][debug] Segment 12 complete
[download][.._Fleischkloesschen.mp4] Written 16.9 MB (4s @ 4.0 MB/s)
[stream.hls][debug] Adding segment 34 to queue
                                                                                                                                                                       [stream.hls]
[debug] Segment 13 complete
[stream.hls][debug] Adding segment 35 to queue
[stream.hls][debug] Segment 14 complete
[stream.hls][debug] Adding segment 36 to queue
[download][.._Fleischkloesschen.mp4] Written 20.0 MB (4s @ 3.8 MB/s)                                                                                                                                                                       
[stream.hls][debug] Segment 15 complete
[stream.hls][debug] Adding segment 37 to queue
[stream.hls][debug] Segment 16 complete
[download][.._Fleischkloesschen.mp4] Written 23.2 MB (5s @ 3.7 MB/s)
[stream.hls][debug] Adding segment 38 to queue
                                                                                                                                                                       [stream.hls]
[debug] Segment 17 complete
[stream.hls][debug] Adding segment 39 to queue
[stream.hls][debug] Segment 18 complete
[stream.hls][debug] Adding segment 40 to queue
[download][.._Fleischkloesschen.mp4] Written 26.1 MB (6s @ 4.3 MB/s)     
...
```



Discussion:
At the very end of [this comment](https://github.com/streamlink/streamlink/issues/3462#issuecomment-982884257) is:

> I would like to keep the bumper segments

...which I guess is what you are talking about here.

Regarding the timestamps on the downloaded file, have you tried running `ffmpeg -c copy` over the file in order to fix the timestamps before any further processing?  It is claimed [here](https://github.com/streamlink/streamlink/issues/3462#issuecomment-985402948) that doing so can fix the timestamps.

If I remux the downloaded file with
`ffmpeg -c copy`
then the timestamps are OK (as with mkvtoolnix alone) but after that I can convert the file to mkv without getting async. 
If the bumper segments are there by design, not by accident, then everything is OK. They are a bit annoying while watching, but if they are technical necessary, no problem.
Sorry, I should have been a bit more clear (my bad) - the retaining of the bumpers was by request, not technical necessity.

I don't know why @AdamNo wanted to keep them.  Perhaps it's because it makes it obvious that the adverts are currently playing when you see the first one.  Without them it would not be clear whether the video had stopped for the adverts or some other reason.

I could look at removing them also.  It depends what the overall consensus of the Pluto plugin users is.  I have no view one way or the other.

Recordings aren't the problem, and I recommend the remux to NextPVR users anyway.  For live streaming It would depend if losing the bumper segments, causes long gaps in the stream causing the stream reader to exit, typically after the m3u8 "cache" is exhausted.
> I could look at removing them also. It depends what the overall consensus of the Pluto plugin users is. I have no view one way or the other.

Is there any way of passing a command line option to control this behaviour? I think that recordings probably don't want them but live streaming might?

i vote for keeping the ad bumper.
when i watch live tv via tvheadend & kodi, the picture freezes with the start ad bumper and resumes with end ad bumper.
it's a clear indicator what's going on.

tvh applies some tsfix and it plays just fine.
```
2021-12-15 14:22:41.346 tsfix: transport stream AAC-LATM, DTS discontinuity. DTS = 4777922, last = 4779840
2021-12-15 14:22:41.845 tsfix: transport stream AAC-LATM, DTS discontinuity. DTS = 4791360, last = 4793282
```
on the other hand and for the sake of having no timestamp issues, you can remove the ad bumpers.

i'll keep for my streamlink installation in file streamlink/src/streamlink/plugins/pluto.py the current filter.
```
    ad_re = re.compile(r"_ad/creative/|dai\.google\.com")
```
so, whatever you guys decide, it's fine with me.


If it's only a change of the regex, does someone here know the regular expression to remove the bumpers?
Than everyone can adjust the behavior and patch the file, no matter what gets the default. I would prefer "no bumpers", but I understand, that the bumpers are an advantage if you stream and don't download

Resolving patch:
diff --git a/src/streamlink/plugins/pluto.py b/src/streamlink/plugins/pluto.py
--- a/src/streamlink/plugins/pluto.py
+++ b/src/streamlink/plugins/pluto.py
@@ -12,7 +12,7 @@
 
 
 class PlutoHLSStreamWriter(HLSStreamWriter):
-    ad_re = re.compile(r"_ad/creative/|dai\.google\.com")
+    ad_re = re.compile(r"_ad/creative/|dai\.google\.com|Pluto_TV_OandO/.*Bumper")
 
     def should_filter_sequence(self, sequence):
         return self.ad_re.search(sequence.segment.uri) is not None or super().should_filter_sequence(sequence)


Test patch: