22

I have HLS playlists that look like this:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:10
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.97667,
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence0.ts
#EXTINF:9.97667,  
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence1.ts
#EXTINF:9.97667,  
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence2.ts
#EXTINF:9.97667,  
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence3.ts

They are of EVENT type, meaning, chunks are appended as they become available, and when all chunks are there, an #EXT-X-ENDLIST tag is appended at the end.

So when all chunks are uploaded, we end up with a playlist that looks something like:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:10
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.97667,  
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence0.ts
#EXTINF:9.97667,  
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence1.ts
#EXTINF:9.97667,  
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence2.ts
#EXTINF:9.97667,  
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence3.ts
#EXTINF:9.97667,  
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence4.ts
#EXTINF:9.97667,  
https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence5.ts
#EXT-X-ENDLIST

We are seeing odd behaviour in all our clients. If you open the m3u8 playlist in iOS and Safari when the first chunk (or even after say, 3 chunks) are uploaded, the player will start playing the video as it should. Occasionally it will stop however, and be unable to resume. More often than not, it won't even begin playing.

Fully formed playlists (i.e. with an #EXT-X-ENDLIST tag) play perfectly. It's just when the playlist is partially done.

We have tried a variety of players: Quicktime, Safari, iOS, VLC, Flowplayer etc. All have a variety of issues, but this is the most pressing.

Any insight into where to look in solving this problem would be greatly appreciated.

Edit: We have tried HLS.js and it plays perfectly. Such a nice user experience too

Edit 2: To reproduce, I recommend having some sort of local HTTP server (I use python -m SimpleHTTPServer serving up a playlist above. Then literally append the files to the playlist to simulate the uploading of files, and watch the players break.

Edit 3: Okay, I have built a simple testing tool to observe the behaviour. https://github.com/dbousamra/m3u8-example Run node app.js and then try and open http://localhost:3001/playlist.m3u8 in Safari or whatever player you want. It should play fine, as it is a complete playlist.**

If however, you add a query param ?start=<some unix timestamp>, it will simulate appending of events, 1 chunk every 6 seconds, from that timestamp, until all chunks are done, at which point it will append an #EXT-X-ENDLIST line.

Example URL: http://localhost:3001/playlist.m3u8?start=1460092250872

Edit 5: I've got it up on Heroku now: http://guarded-mesa-71212.herokuapp.com/playlist.m3u8?start=

Dominic Bou-Samra
  • 14,799
  • 26
  • 100
  • 156
  • could you show us how you write to the m3u8 file? – Allen Apr 03 '16 at 18:55
  • All we do is, as files are uploaded, we append the chunk to the playlist. The playlist is generated on requested (i.e. every single time, from a database of chunks, not saved to a file and updated).Does that make sense? – Dominic Bou-Samra Apr 03 '16 at 21:33
  • then you might need to use wireshark to debug the actual http packets transferred in response, since the file format is correct. – Allen Apr 03 '16 at 21:47
  • @DominicBou-Samra have you try to verify media streaming with `Media Stream Validator Tool`. You can [download it here](https://developer.apple.com/downloads/index.action?=http%20live%20streaming%20tools) as well you can read more in [apple documentation.](https://developer.apple.com/library/ios/technotes/tn2235/_index.html). Another blog `working with media stream validator` is [here](https://support.brightcove.com/en/video-cloud/docs/working-apple-media-stream-validator) – Dipen Panchasara Apr 04 '16 at 09:12
  • Hi Dipen. Thanks for asking. Yeah, we've validated with that tool. Our playlists are valid both when the chunks are being appended (but playlist not completely finished), and also when all chunks are there, and we have an endlist tag. – Dominic Bou-Samra Apr 04 '16 at 09:14
  • @DominicBou-Samra In order to debug this download a sequence of `.ts` files and put them in a local web directory instead of hot-linking them from the Apple site. This way you avoid any potential timeouts with a 3rd party. You can also use relative paths in your playlist. See if it changes anything. – aergistal Apr 07 '16 at 08:19
  • @aergistal We've run this using local files. I am using apple files so people have something to work with. Do you think I should package up an example project? – Dominic Bou-Samra Apr 07 '16 at 08:49
  • @DominicBou-Samra The playlist is OK, I don't think this is your problem. You either have a problem with some of the responses (since you said you're generating the playlist on each request, maybe timeouts) or a problem in the encoding. You should post the HTTP logs and link a few segments on which the playback stops or doesn't start. – aergistal Apr 07 '16 at 12:57
  • Okay will do. Can bad MPEG2 TS files cause issues? Perhaps durations being incorrect? – Dominic Bou-Samra Apr 08 '16 at 00:11
  • @DominicBou-Samra I modified your node example to use version 3 as 6 is not needed and tested with multiple players on Linux (ffplay, VLC), Android and Safari on iOS. In all cases it worked without issues. The only time when it failed to start (as expected) was when the playlist didn't have enough segments in it, you need at least 2-3. It's definitely not the playlist, must be something in your encoding. How are you creating the segments? They must be self-initialized, that is each must start with with a PAT+PMT+IDR frame. – aergistal Apr 08 '16 at 08:44
  • 1
    @aergistal Thanks so much for testing it. Hmm. Yes, I've been suspecting it's in the video too, for the Apple chunks I provided seem to play well enough. I shall do some digging – Dominic Bou-Samra Apr 08 '16 at 08:57
  • 1
    @DominicBou-Samra How are you encoding/segmenting? Also, if you're using some other web-server and the URL doesn't change make sure it's not a caching issue. Disable caching for `m3u8`. – aergistal Apr 08 '16 at 09:03
  • @aergistal I've pushed some examples of our ts files that we are seeing issues with. They are at HEAD of that repo. We have some pretty strict "never cache this" headers on the web server just to rule it out. The playlist also has the ALLOW-CACHE header fwiw. – Dominic Bou-Samra Apr 08 '16 at 09:13
  • @DominicBou-Samra The encoding seems OK for the `bad` samples. Any network issues on your side? – aergistal Apr 08 '16 at 11:01
  • No network issues. I've no idea. – Dominic Bou-Samra Apr 11 '16 at 04:07

2 Answers2

11

Here is what happened:

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:11
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0

if you return the above file, safari will not request the next file at all, the playing just dead.

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:11
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.999367,
https://cammy-bucket-staging-sydney.s3.amazonaws.com/9fc1a264af66e8acb04953bc6634fb6e.ts

if you return the above, safari will request next file around 11/2 seconds, playing will not start at this point.

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:11
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.999367,
https://cammy-bucket-staging-sydney.s3.amazonaws.com/9fc1a264af66e8acb04953bc6634fb6e.ts
#EXTINF:9.968911,
https://cammy-bucket-staging-sydney.s3.amazonaws.com/3e52720b320379de8afc940c3d1b7d34.ts

if you return the above, safari will start playing because the available media 9.999367+9.968911 is great than EXT-X-TARGETDURATION, and you will see another request around 9.999367+9.968911+11/2, it's all about timing!

Allen
  • 6,505
  • 16
  • 19
  • Out of curiosity, did you actually check the request time? Because the standard says it should wait for `TARGETDURATION` the first time or if the playlist changed and for `TARGETDURATION / 2` if it didn't change since the last time. – aergistal Apr 11 '16 at 12:55
  • 1
    @aergistal yes! i did this by capturing actual http packet. – Allen Apr 11 '16 at 13:44
  • 1
    So I think this has actually been the issue. Our target durations weren't always correct. We also now wait till at least 2N chunks are there, and we've not any issues. – Dominic Bou-Samra Apr 12 '16 at 04:37
6

The #EXT-X-DISCONTINUITY tag is used to indicate changes in file format, encoding parameters, number of tracks, and so on. If the segments in the playlist are identical in regard to these things, you can remove the #EXT-X-DISCONTINUITY tags from the playlist - you don't need them.

Some clients may not be compatible with version 6 of the protocol. You don't appear to be using any version 6 specific features so try setting the version number to 3 to see if that helps.

Simon
  • 1,194
  • 7
  • 11