November 27, 2020

VOD DRM support in Nimble Streamer

We've previously introduced DRM support in Nimble Streamer which included Widevine, Playready and FairPlay encryption support for MPEG-DASH and HLS streams in live and DVR mode.

Nimble Streamer now supports DRM for VOD, allowing to encrypt MPEG-DASH and HLS streams generated from VOD files. VOD DRM covers CENC-based encryption for MPEG-DASH and fMP4 HLS.

All encryption is supported for H.264/AVC and H.265/HEVC codecs.

When a viewer connects to MPEG-DASH or fMP4 HLS VOD stream within an application protected by the DRM, its output will be encrypted with respective DRM engine.

  1. For VOD setup please refer to this digest page. Check MPEG-DASH VOD setup and HLS VOD setup articles.
  2. For DRM setup details visit DRM feature set page.
  3. If you use FairPlay, you need to use fmp4 container in playlist name, e.g. https://servername/stream/name/playlist_fmp4.m3u8
  4. You also need to explicitly forbid access to VOD files via progressive download as described in this article.


Watch this video tutorial showing EZDRM setup for live, DVR and VOD content protection.




Contact us if you have any questions regarding this feature.




.

November 24, 2020

Apple Low Latency HLS setup in Nimble Streamer

Apple has introduced Low Latency HLS spec back in 2019 and has officially released the final version of the spec in the fall of 2020, along with making the playback available on iOS and Mac.

Nimble Streamer now has full support for Apple LL HLS in addition to "legacy" RFC8216 HLS. You can read about major advantages on LL HLS digest page. This article describes the setup process of Nimble Streamer.

We assume you already have Nimble Streamer installed on one of your servers,or upgraded to the latest version and you have full access there.


You watch a short version of this article in our video tutorial below.

However we highly recommend reading this article to use this feature efficiently.


LL HLS uses HTTP/2 via SSL as a transport protocol. So you need to enable it before performing any further setup.


1. HTTP/2 setup

1.1 First, install the latest Nimble Streamer or upgrade your existing instance. 

1.2 Now set up the SSL certificate for Nimble Streamer. This is an important steps so please make sure SSL is working before moving forward.

1.3 Add ssl_http2_enabled=true parameter into nimble.conf and restart Nimble Streamer. Read parameters reference to find more about config location and restart.
LiteSpeed HPACK library: Nimble Streamer uses LS-HPACK library for encoding and decoding HTTP headers using HPACK compression mechanism. Softvelum team would like to say thank you to LiteSpeed team, we appreciate their effort and technical expertise.
1.4 After that you'll be able to use HTTP/2 to reach live streams with HLS and MPEG-DASH protocols enabled. You can check if Nimble Streamer delivers HTTP/2 by checking access log. Read this article to get familiar with logging. E.g. you can enable logs by using log_access=file parameter. Once you add it and re-start Nimble, you'll be able to view the log. In Ubuntu it's located in /var/log/nimble/access.log by default.
Now when you try to get your regular HLS live stream via https:// via curl or HTTP/2-capable player, you'll get this kind of record in access log:
Dec 24 17:43:09 nimble[5500]: [nimble-access.log] 192.18.1.2 - - "GET /livell/stream/playlist.m3u8 HTTP/2" 200 84 1114 372 "-" "AppleCoreMedia/1.0.0.17C54 (iPhone; U; CPU OS 13_3 like Mac OS X; en_us)"
You can see HTTP/2 there which means it's working. In other cases it will have HTTP/1.1 and this will mean you need to check what's wrong.

If a client tries to access LL-HLS stream via HTTP/1.1, or if HTTP/2 is not properly set up, then the player will fall back to legacy HLS and will not use any advantages of LL-HLS.

2. Live streaming setup


Now you need to set up transmuxing settings via WMSPanel web service. If you are not familiar with live streaming setup of Nimble Streamer, please refer to live streaming digest page, or respective input protocol pages, such as RTMP streaming.

You may use any RTMP, RTSP, SRT, RIST and MPEG-TS input stream as a source for LLHLS.
Please make sure you have a correctly set up live stream (like regular-latency HLS, RTMP or SLDP) before trying to use LL HLS.

Once you have a live stream set up in WMSPanel, go to Nimble Streamer top menu and select Live streams settings. You will see Global setting tab for selected server. You may create application-specific setting as well if it's needed for your streaming scenario.


Currently, Nimble Streamer supports all 3 container types available for HLS, you can see their respective check boxes on the screenshot above. Those types have the following meaning for Low Latency HLS case:
  • HLS - this type is recommended for audio-only LL streams. It's optimized for audio delivery and it has a reduced chunk size. This allows significantly saving bandwidth for audio streams. The ID3 tags are also inserted in each audio part.
  • fMP4 (CMAF) - fragmented MP4 for video+audio, audio-only and video-only modes. We highly recommend using this type of container for video+audio and video-only cases as it allows utilizing all advantages of LL HLS.
  • HLS (MPEGTS) - this type supports both video+audio, audio-only and video-only modes, however we do not recommend it for LL HLS. It brings a lot overhead which diminishes all advantages and increases the latency. Also it does not support HEVC unlike fMP4. We've added this type support as a fix for a bug of iOS 12 which implemented previous LL HLS spec. So even though you can use it with LL, Apple does not recommend using it and Nimble Streamer team does not as well.
Once you select either of those containers, WMSPanel will show Enable Apple's Low Latency HLS checkbox and you need to select it. You will then see HLS part duration edit box to define parts' duration in milliseconds.
Please consider the following when choosing parts duration:
  • We recommend using part duration of 2000ms with chunk duration of 6 seconds. The expected latency will be about 6 seconds in this case. This duration provides optimal bandwidth and latency as well as good playback buffer.
  • The minimum recommended part duration of 1000ms. The expected latency will be about 4-5 seconds in this case. This duration gives better latency but less playback buffer and more bandwidth consumption as well as server resources' usage.
  • The smallest duration value allowed by the web UI is 500 ms because it's the minimum that makes sense in terms of low latency delivery. The latency will be around 2 seconds in this case. This duration gives very low playback buffer, severe bandwidth consumption and server resources' usage. Use it only if you have a managed network and latency is crucial for your case.
  • Part size smaller than 500ms does not make any practical sense because of the overhead in delivery and processing chain. Even though Nimble is able to produce smaller parts, we just don't want our customers to deal with potential bottlenecks in other areas.
  • You may align key frame interval with chunk size. E.g. for 6 seconds chunk and 1000ms part duration the valid key frame intervals would be 1, 2, 3 seconds. For same chunk size and part duration of 2000, the valid key frame intervals will be 1, 2, 3, 6 seconds.
  • Key frame interval can be set on your encoder side. Nimble Live Transcoder allows setting it as well.

Once LL HLS is enabled, you need to re-start the input stream so Nimble Streamer could start producing LL HLS output stream.

3. Workflow and playlists


Now as the set up has been made, you can use the player to consume the stream using the usual playback URL. The main playlist will have proper chunklists which will have a content according to LL-HLS spec. Here is an example of such chunk list (obtained via video.m3u8).
   #EXTM3U
    #EXT-X-VERSION:7
    #EXT-X-INDEPENDENT-SEGMENTS
    #EXT-X-MAP:URI="audio.fmp4?nimblesessionid=1"
    #EXT-X-TARGETDURATION:7
    #EXT-X-MEDIA-SEQUENCE:1
    #EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.536
    #EXT-X-PART-INF:PART-TARGET=0.512
    #EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:29:02.609Z
    #EXTINF:5.995,
    a_6_6016_1.fmp4?nimblesessionid=1
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_0.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_1.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_2.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_3.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_4.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_5.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_6.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_7.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_8.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_9.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_12011_2_10.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.363,URI="a_6_12011_2_11.fmp4?nimblesessionid=1"
    #EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:29:08.604Z
    #EXTINF:5.995,
    a_6_12011_2.fmp4?nimblesessionid=1
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_0.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_1.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_2.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_3.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_4.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_5.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_6.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_7.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_8.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_9.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_18006_3_10.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.362,URI="a_6_18006_3_11.fmp4?nimblesessionid=1"
    #EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:29:14.599Z
    #EXTINF:5.994,
    a_6_18006_3.fmp4?nimblesessionid=1
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_0.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_1.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_2.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_3.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_4.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_5.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_6.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_7.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_8.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_9.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_10.fmp4?nimblesessionid=1"
    #EXT-X-PART:DURATION=0.384,URI="a_6_24000_4_11.fmp4?nimblesessionid=1"
    #EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:29:20.593Z
    #EXTINF:6.016,
    a_6_24000_4.fmp4?nimblesessionid=1 
    #EXT-X-PRELOAD-HINT:TYPE=PART,URI="a_6_30000_5_0.fmp4?nimblesessionid=1"

      

Parts in chunklist. Comparing to regular HLS, you see a lot of lines representing parts like this:
#EXT-X-PART:DURATION=0.512,URI="a_6_24000_4_0.fmp4?nimblesessionid=1"
The full chunk which contain these parts will be described after all parts' lines:
a_6_24000_4.fmp4?nimblesessionid=1
All parts within chunks are numerated starting from zero. So "a_6_18006_3_0.fmp4" mean its the first part of chunk number 3.

Part length. This attribute declares a designated size of upcoming parts:
#EXT-X-PART-INF:PART-TARGET=0.512
In this example it's 512 milliseconds.

Can block reload
. Check this line:
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.536
The "CAN-BLOCK-RELOAD" declares that media server allows holding playlist request.

Hold playlist request. LL-HLS allows requesting the server to hold sending out the playlist until a specific chunk and/or part is available for the stream.
So a player may request some part which is going to be available within a few seconds from now, then Nimble Streamer will check if that part is available. Once the requested part is ready, Nimble will return a playlist.

Check this request example:
curl -k "https://localhost:8443/livell/stream/chunks.m3u8?nimblesessionid=1&_HLS_msn=59&_HLS_part=5"
The highlighted _HLS_msn=59 and _HLS_part=5 parameters indicate that the server must hold the request until Nimble Streamer has part number 5 of chunk number 59 or later and then it could return a playlist. You can use only _HLS_msn=59 parameter, in this case the playlist will be sent out only once full chunk is available.

The resulting chunklist will look like this:
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MAP:URI="audio.fmp4?nimblesessionid=1"
#EXT-X-TARGETDURATION:7
#EXT-X-MEDIA-SEQUENCE:55
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.536
#EXT-X-PART-INF:PART-TARGET=0.512
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:34:26.599Z
#EXTINF:5.994,
a_6_330006_55.fmp4?nimblesessionid=1
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:34:32.593Z
#EXTINF:6.016,
a_6_336000_56.fmp4?nimblesessionid=1
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_0.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_1.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_2.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_3.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_4.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_5.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_6.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_7.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_8.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_9.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_342016_57_10.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.363,URI="a_6_342016_57_11.fmp4?nimblesessionid=1"
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:34:38.609Z
#EXTINF:5.995,
a_6_342016_57.fmp4?nimblesessionid=1
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_0.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_1.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_2.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_3.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_4.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_5.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_6.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_7.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_8.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_9.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_348011_58_10.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.363,URI="a_6_348011_58_11.fmp4?nimblesessionid=1"
#EXT-X-PROGRAM-DATE-TIME:2019-12-23T02:34:44.604Z
#EXTINF:5.995,
a_6_348011_58.fmp4?nimblesessionid=1

#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_0.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_1.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_2.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_3.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_4.fmp4?nimblesessionid=1"
#EXT-X-PART:DURATION=0.512,URI="a_6_354006_59_5.fmp4?nimblesessionid=1" 
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="
a_6_354006_59_6.fmp4?nimblesessionid=1"

 

You can see it ends with part a_6_354006_59_5.fmp4 - it's part number 5 of the upcoming chunk 59. That chunk will be available only a few seconds later, but the player can already perform the playback, this helps a lot with reducing the latency.

Pre-load hint. Check this line:
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="a_6_354006_59_6.fmp4?nimblesessionid=1"
Here Nimble declares that part 6 of chunk 59 is being created right at this moment. The player may request this part and it will get it as soon as that part is available.

4. Playback


Low Latency HLS is now supported in all Apple devices that are capable of HLS playback. So you can use an iPhone with iOS 14 to play this HLS even in your browser. We also have support for LL HLS in Larix Player for iOS which uses platform playback component.

Also, THEOPlayer has a test page with their implementation of LLHLS which is working in various other browsers on other platforms. You can read configuration guide to see how you can adapt THEO Player to your use case.

Other platforms do not have LL HLS support yet. Once we know of that kind of solutions, we'll mention them here.

5. Known issues and troubleshooting


5.1. Chunk duration and key frame alignment
If the playback has issues, you need to make sure that chunk duration is equal to the duration that you specified for your stream settings.

Let's check a couple of examples.
In this example we set up chunk of 6 seconds with part duration of 1000ms. So you see 6 parts for each chunk, and every chunk has equal duration:
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MAP:URI="video.fmp4?nimblesessionid=249"
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:1296
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=3
#EXT-X-PART-INF:PART-TARGET=1
#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:14.406Z
#EXTINF:6,
v_80_7777992_1296.fmp4?nimblesessionid=249
#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:20.406Z
#EXTINF:6,
v_80_7783992_1297.fmp4?nimblesessionid=249
#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:26.406Z
#EXTINF:6,
v_80_7789992_1298.fmp4?nimblesessionid=249
#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:32.406Z
#EXTINF:6,
v_80_7795992_1299.fmp4?nimblesessionid=249
#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_0.fmp4?nimblesessionid=249",INDEPENDENT=YES
#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_1.fmp4?nimblesessionid=249"
#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_2.fmp4?nimblesessionid=249"
#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_3.fmp4?nimblesessionid=249",INDEPENDENT=YES
#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_4.fmp4?nimblesessionid=249"
#EXT-X-PART:DURATION=1,URI="v_80_7801992_1300_5.fmp4?nimblesessionid=249"
#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:38.406Z
#EXTINF:6,
v_80_7801992_1300.fmp4?nimblesessionid=249
#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_0.fmp4?nimblesessionid=249",INDEPENDENT=YES
#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_1.fmp4?nimblesessionid=249"
#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_2.fmp4?nimblesessionid=249"
#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_3.fmp4?nimblesessionid=249",INDEPENDENT=YES
#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_4.fmp4?nimblesessionid=249"
#EXT-X-PART:DURATION=1,URI="v_80_7807992_1301_5.fmp4?nimblesessionid=249"
#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:39:44.406Z
#EXTINF:6,
v_80_7807992_1301.fmp4?nimblesessionid=249
#EXT-X-PART:DURATION=1,URI="v_80_7813992_1302_0.fmp4?nimblesessionid=249",INDEPENDENT=YES
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="v_80_7813992_1302_1.fmp4?nimblesessionid=249"

Now check your chunk list. Get your playlist via URL like https://yourdomain.com/test/stream/playlist.m3u8 and then find the chunklist that corresponds to the video, like https://yourdomain.com/test/stream/video.m3u8. You can do that via various tools like "curl".

Check the following real-life example of LLHLS stream.
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MAP:URI="video.fmp4?nimblesessionid=57"
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:9873
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=3.003
#EXT-X-PART-INF:PART-TARGET=1.001
#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:28:36.050Z
#EXTINF:5.338,
v_26_60085735_9873.fmp4?nimblesessionid=57
#EXT-X-PART:DURATION=1.001,URI="v_26_60091073_9874_0.fmp4?nimblesessionid=57",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.001,URI="v_26_60091073_9874_1.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60091073_9874_2.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60091073_9874_3.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=0.333,URI="v_26_60091073_9874_4.fmp4?nimblesessionid=57"
#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:28:41.223Z
#EXTINF:4.338,
v_26_60091073_9874.fmp4?nimblesessionid=57
#EXT-X-PART:DURATION=1.001,URI="v_26_60095411_9875_0.fmp4?nimblesessionid=57",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.001,URI="v_26_60095411_9875_1.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60095411_9875_2.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60095411_9875_3.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60095411_9875_4.fmp4?nimblesessionid=57"
#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:28:45.740Z
#EXTINF:5.005,
v_26_60095411_9875.fmp4?nimblesessionid=57
#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_0.fmp4?nimblesessionid=57",INDEPENDENT=YES
#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_1.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_2.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_3.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_4.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_5.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_6.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_7.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_8.fmp4?nimblesessionid=57"
#EXT-X-PART:DURATION=1.001,URI="v_26_60100416_9876_9.fmp4?nimblesessionid=57"
#EXT-X-PROGRAM-DATE-TIME:2020-12-14T01:28:50.745Z
#EXTINF:10.01,
v_26_60100416_9876.fmp4?nimblesessionid=57
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="v_26_60110426_9877_0.fmp4?nimblesessionid=57"
It has chunks of various durations which differ from the duration requested during the setup (you can see 4.338, 5.005 and even 10.01). This may cause some players to work incorrectly.
So your original stream source need to have proper key frames setup in order to produce playlists for smooth playback.

As you can see, LLHLS can be capricious when it comes to key frame alignment. So you have to make sure that your initial source stream is properly encoded and delivered prior to re-packaging into LLHLS. Reliable delivery protocols like SRT are excellent for the vast majority of streaming scenarios but this case may require additional efforts prior to transmuxing.
If you want to produce reliable output for last-mile delivery regardless of your source, you need to consider SLDP low latency protocol. We designed and implemented it having various real-life cases in mind and whatever you bring into Nimble Streamer, it will be properly played in SLDP-powered players.

5.2. Interleaving compensation
If you have video+audio stream you may have issues with playback due to interleaving as described in this article. This kind of issues becomes even more severe in case of low latency playback. In order to fix this you can try enabling interleaving compensation with Min. delay set to zero, see the image below.



Related materials


Watch Converting NDI to Apple Low Latency HLS video which demonstrates hot to get NDI source input and produce LLHLS output with proper latency.


Feel free to try Nimble Streamer with Low Latency HLS and let us know if you have any questions.

Follow us in social media to get updates about our new features and products: YouTubeTwitterFacebookLinkedInRedditTelegram

November 22, 2020

BuyDRM KeyOS support in Nimble Streamer

Softvelum team is glad to announce that Nimble Streamer DRM framework now supports BuyDRM KeyOS DRM solution for protecting the content using Widevine, FairPlay and Playready encryption technologies.


In order to use KeyOS, please follow setup instructions on Nimble DRM page and let us know of any questions.

November 20, 2020

Nimble Streamer on Amazon EC2: installation and SRT setup

We've released a new video tutorial about Nimble Streamer on Amazon EC2.

In this video we do the following:

  • create Amazon EC2 instance;
  • install Nimble Streamer there;
  • set it up to receive SRT stream;
  • run vMix to publish SRT stream;
  • test the playback via HLS, MPEG-DASH and SLDP.

You can watch it now:


Feel free to subscribe to Softvelum YouTube channel to watch more videos as they come out.

November 18, 2020

Nimble Live Transcoder API

Nimble Streamer Live Transcoder add-on has a convenient web UI allowing to control transcoding scenarios and pipelines via browsers. However many customers need even more flexibility so they'd like to use API to control server behavior.

WMSPanel control API now has Transcoder scenarios section which provides a list of methods to control Live Transcoder behavior via API calls.

The overall approach for Transcoder API usage is as follows.

  • Use web UI to create some general-purpose scenarios which you consider as templates. You may use your existing scenarios as well. The rest is done via the API calls.
  • Clone a designated scenario on the same server. This is what you will change via further API calls.
  • Apply any scenario to multiple servers just like you would do via the web UI by making its update and setting servers_to_apply parameter in your call.
  • Besides an update, each scenarios can be paused, resumed and even removed.
  • Each scenario has its video and audio pipelines (you can see them via UI) and you can remove them if they are not needed in some particular case.
  • For each pipeline, you will be able to change applications and streams names for encoders input and decoders output.
  • For each pipeline you can change some basic parameters of existing filters.

This way you may create some general purpose scenarios, pause them to make them to be templates, then clone a many as you want and then narrow them to specific cases.

Read more about WMSPanel API and transcoder control API methods on API reference page.


In addition to that, take a look at Transcoder documentation reference just to see if you've missed some of latest features. Our YouTube channel has Transcoder playlist with video tutorials on some popular use cases.

If you have any questions regarding the Transcoder or its API, please feel free to contact our heldpesk.

November 2, 2020

DRM-powered DVR in Nimble Streamer

Earlier this year we introduced DRM support in Nimble Streamer which included Widevine, Playready and FairPlay encryption support for MPEG-DASH and HLS live streams. Our customers like using live streaming along with DVR functionality which allows recording their streams for later playback via HLS and DASH.

Nimble Streamer now combines these two feature sets into one, allowing to encrypt recorded live streams when providing their playback.

When a viewer connects to MPEG-DASH or fMP4 HLS stream within an application protected by the DRM, its output will be encrypted with respective DRM engine, it's that simple.

Also notice that DVR DRM covers CENC-based encryption for MPEG-DASH and fMP4 HLS.

All encryption is supported for H.264/AVC and H.265/HEVC codecs.

For DRM setup details visit DRM feature set page.

For DVR setup please refer to this digest page and to this DVR setup article as example.


Watch this video tutorial showing EZDRM setup for live, DVR and VOD content protection.


Contact us if you have any questions regarding this feature.