Blog

Encoding HLS video for JW Player 6

The newest JW Player supports reading HLS segmented content in a Flash player (which is very cool). However it didn’t work for me using HLS content created with Apple Compressor or FFmpeg + mediafilesegmenter. What did work was generating transport streams with FFmpeg and the m3u8-segmenter from https://github.com/johnf/m3u8-segmenter.

Generated multiple different bitrates using ffmpeg: (these are the http://developer.apple.com/library/ios/#technotes/tn2224/_index.html Apple recommended HLS profiles) It’s possible to use named pipes to send the transport streams directly to m3u8-segmenter.

mkdir bbb.mpegts
ffmpeg -y -i bbb.mp4 -threads 0 -f mpegts 
  -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile baseline 
    -x264opts “fps=12:keyint=36:bitrate=200”  -s 416×234  bbb.mpegts/p1.ts 
  -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile baseline 
    -x264opts “fps=12:keyint=36:bitrate=400”  -s 480×270  bbb.mpegts/p2.ts 
  -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile baseline 
    -x264opts “fps=24:keyint=72:bitrate=600”  -s 640×360  bbb.mpegts/p3.ts 
  -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile baseline 
    -x264opts “fps=24:keyint=72:bitrate=1200” -s 640×360  bbb.mpegts/p4.ts 
  -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile main     
    -x264opts “fps=24:keyint=72:bitrate=1800” -s 960×540  bbb.mpegts/p5.ts 
  -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile main     
    -x264opts “fps=24:keyint=72:bitrate=2500” -s 960×540  bbb.mpegts/p6.ts 
  -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile main     
    -x264opts “fps=24:keyint=72:bitrate=4500” -s 1280×720 bbb.mpegts/p7.ts

Created segments at six-second intervals, to fit the keyframes generated by ffmpeg:

mkdir bbb.hls
for p in p1 p2 p3 p4 p5 p6 p7; do mkdir bbb.hls/$p.seg; (cd bbb.hls; m3u8-segmenter –input ../bbb.mpegts/$p.ts –duration 6 –output-prefix $p.seg/$p –m3u8-file $p.m3u8 –url-prefix “”); done

Wrote a variant playlist that links all the profiles in ‘bbb.hls’:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=264000,RESOLUTION=416×234
p1.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=464000,RESOLUTION=480×270
p2.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=664000,RESOLUTION=640×360
p3.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1264000,RESOLUTION=640×360
p4.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1864000,RESOLUTION=960×540
p5.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2564000,RESOLUTION=960×540
p6.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4564000,RESOLUTION=1280×720
p7.m3u8

The mpegts files can then be deleted, and the on-disk layout should look like this: (probably with many more TS files)

./p1.m3u8
./p1.seg
./p1.seg/p1-1.ts
./p1.seg/p1-2.ts
./p1.seg/p1-3.ts
./p2.m3u8
./p2.seg
./p2.seg/p2-1.ts
./p2.seg/p2-2.ts
./p2.seg/p2-3.ts
./p3.m3u8
./p3.seg
./p3.seg/p3-1.ts
./p3.seg/p3-2.ts
./p3.seg/p3-3.ts
./p4.m3u8
./p4.seg
./p4.seg/p4-1.ts
./p4.seg/p4-2.ts
./p4.seg/p4-3.ts
./p5.m3u8
./p5.seg
./p5.seg/p5-1.ts
./p5.seg/p5-2.ts
./p5.seg/p5-3.ts
./p6.m3u8
./p6.seg
./p6.seg/p6-1.ts
./p6.seg/p6-2.ts
./p6.seg/p6-3.ts
./p7.m3u8
./p7.seg
./p7.seg/p7-1.ts
./p7.seg/p7-2.ts
./p7.seg/p7-3.ts
./playlist.m3u8

If all these files are exposed via an HTTP server, you can pass playlist.m3u8 as the source to JW Player and it should work.

1 Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

Comment replies are not available offline

Great post. Thanks!

on July 24, 2014 at 1:29 am Reply |