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 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 416x234 bbb.mpegts/p1.ts \ -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile baseline \ -x264opts "fps=12:keyint=36:bitrate=400" -s 480x270 bbb.mpegts/p2.ts \ -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile baseline \ -x264opts "fps=24:keyint=72:bitrate=600" -s 640x360 bbb.mpegts/p3.ts \ -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile baseline \ -x264opts "fps=24:keyint=72:bitrate=1200" -s 640x360 bbb.mpegts/p4.ts \ -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile main \ -x264opts "fps=24:keyint=72:bitrate=1800" -s 960x540 bbb.mpegts/p5.ts \ -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile main \ -x264opts "fps=24:keyint=72:bitrate=2500" -s 960x540 bbb.mpegts/p6.ts \ -acodec libfaac -ab 64k -ar 44100 -vcodec libx264 -vprofile main \ -x264opts "fps=24:keyint=72:bitrate=4500" -s 1280x720 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=416x234 p1.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=464000,RESOLUTION=480x270 p2.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=664000,RESOLUTION=640x360 p3.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1264000,RESOLUTION=640x360 p4.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1864000,RESOLUTION=960x540 p5.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2564000,RESOLUTION=960x540 p6.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4564000,RESOLUTION=1280x720 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.
Great post. Thanks!