Kodi Community Forum

Full Version: Internet streaming - HLS - switching between streams
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I watch a lot of live internet streams, and mainly they use HLS - HTTP Live Streaming. This seems to work just fine in general with XBMC. However, some particular sources (notably, partnered Twitch channels) offer multiple streams for viewing. This is usually done to allow streaming in low-bandwidth situations.

These alternate streams are listed in an extm3u file, as can be seen below. Currently, these are loaded by essentially running
Code:
xbmc.Player().play(url_of_extm3u_file)

That is, the XBMC Player loads the whole extm3u file. It then passes this file through to ffmpeg for playback, as evidenced in the log snippet below. The log file also shows that ffmpeg does recognise all 4 distinct streams. I was wondering, is it possible to tell ffmpeg to switch to a different stream somehow? I tried hitting buttons on my remote, and my keyboard, but nothing seemed to work. I couldn't find any documentation on whether this was even possible, so if it's not possible just let me know.


Sample EXTM3U file with multiple sources.
Code:
#EXTM3U
#EXT-X-TWITCH-INFO:NODE="video30.lax01",MANIFEST-NODE="video30.lax01",SERVER-TIME="1393237933.48",USER-IP="124.148.51.249",CLUSTER="lax01",MANIFEST-CLUSTER="lax01"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="chunked",NAME="Source",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4126734,RESOLUTION=1920x1080,VIDEO="chunked"
http://video30.lax01.hls.twitch.tv/hls95/sc2proleague_8655128880_67465345/chunked/index-live.m3u8?token=id=DELETED,bid=8655128880,exp=1393324333,node=video30-1.lax01.hls.justin.tv,nname=video30.lax01,fmt=chunked&sig=330518d2cf27ac6fd7015710136bc724316b67ce
#EXT-X-TWITCH-RESTRICTED:GROUP-ID="high",NAME="High",RESTRICTION="chansub"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="medium",NAME="Medium",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=928000,VIDEO="medium"
http://video30.lax01.hls.twitch.tv/hls95/sc2proleague_8655128880_67465345/medium/index-live.m3u8?token=id=DELETED,bid=8655128880,exp=1393324333,node=video30-1.lax01.hls.justin.tv,nname=video30.lax01,fmt=medium&sig=fa0b1c9200293ba842115befd2f252247dcf2445
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Low",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=596000,VIDEO="low"
http://video30.lax01.hls.twitch.tv/hls95/sc2proleague_8655128880_67465345/low/index-live.m3u8?token=id=DELETED,bid=8655128880,exp=1393324333,node=video30-1.lax01.hls.justin.tv,nname=video30.lax01,fmt=low&sig=5e9943abbc0a811ab36d77886d2ca9c7b654b20a
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mobile",NAME="Mobile",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=164000,VIDEO="mobile"
http://video30.lax01.hls.twitch.tv/hls95/sc2proleague_8655128880_67465345/mobile/index-live.m3u8?token=id=DELETED,bid=8655128880,exp=1393324333,node=video30-1.lax01.hls.justin.tv,nname=video30.lax01,fmt=mobile&sig=62d3a2c1774f75fac9eb0ec5dfc26d85cd80f1c2

Log snippet
Code:
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]: Input #0, applehttp, from 'http://usher.twitch.tv/select/sc2proleague.json?nauthsig=975ae3f7d80fa3d4cebfc9725da2dbb762cdd403&player=jtvweb&private_code=null&type=any&nauth=%7B%22user_id%22%3Anull%2C%22channel%22%3A%22sc2proleague%22%2C%22expires%22%3A1393242740%2C%22chansub%22%3A%7B%22view_until%22%3A1924905600%2C%22restricted_bitrates%22%3A%5B%22archives%22%2C%22source%22%2C%22high%22%5D%7D%2C%22private%22%3A%7B%22allowed_to_view%22%3Atrue%7D%2C%22privileged%22%3Afalse%7D&allow_source=true':mpeg[BE4D0700]:     Metadata:
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:       variant_bitrate : 4271367
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Stream #0:1: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 29.97 tbr, 90k tbn, 59.94 tbc9971881928448    INFO: ffmpeg[BE4D0700]:     Metadata:
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:       variant_bitrate : 4271367
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Stream #0:2: Audio: aac ([15][0][0][0] / 0x000F), 44100 Hz, stereo, s16
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Metadata:
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:       variant_bitrate : 928000
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Stream #0:3: Video: h264 (Constrained Baseline) ([27][0][0][0] / 0x001B), yuv420p, 852x480, 29.97 tbr, 90k tbn, 2k tbc:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Metadata:
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:       variant_bitrate : 928000
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Stream #0:4: Audio: aac ([15][0][0][0] / 0x000F), 44100 Hz, stereo, s16
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Metadata:
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:       variant_bitrate : 596000
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Stream #0:5: Video: h264 (Constrained Baseline) ([27][0][0][0] / 0x001B), yuv420p, 640x360, 29.97 tbr, 90k tbn, 2k tbc:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Metadata:
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:       variant_bitrate : 596000
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Stream #0:6: Audio: aac ([15][0][0][0] / 0x000F), 44100 Hz, stereo, s16
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Metadata:
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:       variant_bitrate : 164000
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Stream #0:7: Video: h264 (Constrained Baseline) ([27][0][0][0] / 0x001B), yuv420p, 400x226, 14.99 tbr, 90k tbn, 2k tbc:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:     Metadata:
21:32:27 T:139971881928448    INFO: ffmpeg[BE4D0700]:       variant_bitrate : 164000
21:32:27 T:139971881928448  NOTICE: Opening video stream: 1 source: 256
21:32:27 T:139971881928448  NOTICE: Creating video codec with codec id: 28
I thought that HLS was suposed to automatically switch streams based on available bandwidth, although whether that is the responsibility of the client or the server, I am not sure. The client I suppose.

Then there is the question of whether ffmpeg does this automatically, or if it is up to the program calling ffmpeg (ie xbmc) to instruct ffmpeg to do this.

Sorry that probably wasn't much help.
I did try watching the stream for about 5 minutes, and I was definitely getting lag problems. I mean unwatchable type lag, seeing 2-3s of video then freeze frame for 8-10s or something similar. On my regular PC I get the same issue, and have to drop to the Medium stream for things to be smooth. I'd guess from that experience that at the very least, XBMC/ffmpeg doesn't switch streams automatically.

Might start digging through source code, I guess.
Yeah looking at the HLS page on wikipedia, it certainly is the client that is supposed to change streams. I did think of referring to the mythtv implementation, but that is server, not client.
This is a rough worklog of me reading code to try to find something. I'm hopeful that the code to change streams already exists, just isn't documented/has no shortcut assigned that I can find.

Ok, so ffmpeg does seem to parse all streams (as noted in OP). There is a "av_find_best_stream()" function in ffmpeg, which takes a parameter "wanted_stream_nb".

It also seems like XBMC does realise how many streams ffmpeg discovers (see xbmc/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp). There is even a CDVDDemuxFFmpeg::GetNrOfStreams() function.

There seems to be "SetSubtitle" and "SetAudioStream" functions in xbmc/xbmc/cores/IPlayer.h, but nothing for video streams (or streams in general). However, DVDPlayer.h does have OpenVideoStream() which takes iStream as one int parameter. Looks promising.

I checked, and it seems I can select the audio streams for alternate streams via the XBMC GUI. I'm now trying to work out if maybe I can just tweak a skin to show the video streams too, but I'm learning so no idea how this will go.


Final edit, giving up. In the git repo, xbmc/Application.h defines the global g_application. This, in turn, has a member called m_pPlayer, which governs the player, defined in xbmc/ApplicationPlayer.h. This ApplicationPlayer class has a SetAudioStream function, but no SetVideoStream function. I don't have the time required to learn enough about XBMC to implement this myself, but at a guess I think it involves:

* Add a SetVideoStream function to ApplicationPlayer
* Add a SetVideoStream function to IPlayer
* Add a SetVideoStream function to DVDPlayer
* Check other players. If they support changing VideoStreams, add it. If they don't, do something suitable.
* Add code to GUIDialogVideoSettings to populate a "selector" of video sources, similar to the audio one in GUIDialogAudioSubtitleSettings I assume.
* Possibly (not sure how skins work) rework skins so that the new selector shows up in the video settings

For now, there's a nasty workaround for me. Download the extm3u playlist, select a suitable stream and delete all others. Save the resulting file, and just load that resulting file. It's manual, but it works at least.
There is a difference between knowing how any streams are available, and being able to switch between them.

I understood that a HLS client should automatically switch between streams based on available bandwidth. Are you wanting that, or are you wanting to switch manually via, say, a popup (that allows you to choose) or a keypress (that cycles between the available)??
(2014-02-25, 10:20)nickr Wrote: [ -> ]There is a difference between knowing how any streams are available, and being able to switch between them.
Yeah, I realise this. See my work above for this. It seems the first is "known" to xbmc (not really known to a user though), but it's not currently possible to switch between them.

(2014-02-25, 10:20)nickr Wrote: [ -> ]I understood that a HLS client should automatically switch between streams based on available bandwidth. Are you wanting that, or are you wanting to switch manually via, say, a popup (that allows you to choose) or a keypress (that cycles between the available)??

I'd be happy (and was looking for) the same option that exists with multiple audio streams, where you can go into options and select an alternate video stream. A pop-up would work too.

If auto-selection were to work, sure, that'd be awesome. But I haven't found anything in ffmpeg that suggest that ffmpeg can do it. Maybe XBMC could be asked to do it, but I feel it's simpler to start with a simple "option to change video stream". Basically, my reason for not looking for auto-selection is that I figured simpler would be easier.