I've found some crude bash script for encoding and encrypting video file, into a HLS stream, and I've edited it slightly (I have no idea about bash):
#!/bin/bash
set -e # Exit on errors
tsFile="$1"
if ! [ -f "$tsFile" -a -r "$tsFile" ]; then
echo "First argument is required" >&2
exit 2
fi
if [ -z "$3" ]; then
output="output"
else
output="$3"
fi
keyFile="$output.key"
keyInfoFile="$output.keyinfo"
playList="$output.m3u8"
if [ -z "$4" ]; then
separator='-'
else
separator="$4"
fi
splitFilePrefix="$output$separator"
if [ -d "$2" ]; then
outDir="$2"
else
mkdir "$2" || exit 1
outDir="$2"
fi
tempDir="$outDir/.$$_tmp"
keyFile="$outDir/$keyFile"
mkdir $tempDir
echo "$outdir/$keyFile\n$outdir/$keyFile" > "$outdir/$keyInfoFile"
ffmpeg -i "$tsFile" -hls_time 5 -hls_list_size 0 -hls_segment_filename "$tempDir/$splitFilePrefix%03d.ts" -strict -2 "$tempDir/$playList"
openssl rand 16 > $keyFile
encryptionKey=`cat $keyFile | hexdump -e '16/1 "%02x"'`
numberOfTsFiles=$(( `ls "$tempDir/$splitFilePrefix"*.ts | wc -l` -1 ))
for i in $(seq -f "%03g" 0 $numberOfTsFiles); do
initializationVector=`printf '%032x' $(( 10#$i))`
openssl aes-128-cbc -e -in "$tempDir/$splitFilePrefix"$i.ts \
-out "$outDir/$splitFilePrefix"$i.ts -nosalt -iv $initializationVector -K $encryptionKey
done
{
head -4 "$tempDir/$playList"
echo '#EXT-X-KEY:METHOD=AES-128,URI='"$keyFile"
egrep "$tempDir/$playList" -vie '#EXT-X-TARGETDURATION:' \
| tail -n +4
} > "$outDir/$playList"
#rm -r "$tempDir"
This results in a something like this:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI=output.key
#EXT-X-TARGETDURATION:11
#EXTINF:10.176833,
output-000.ts
#EXTINF:8.341667,
output-001.ts
#EXTINF:8.341667,
output-002.ts
#EXTINF:3.136467,
output-003.ts
#EXT-X-ENDLIST
This almost works. However I need an VOD, not a live stream. So, I added line:
#EXT-X-PLAYLIST-TYPE:VOD
And now it doesn't work with encrypted segments, only with unencrypted ones. I thought all segments are crypted separately? Also, even with unencrypted files, the info about total length isn't present. How can I fix that?
Here are a few pointers based on my own experiments which seem to work on VLC, iOS and Android.
Initialization Vectors
When no IV
is specified in the playlist each segment has a default IV
equal to the media sequence. Make sure segment-000 has IV=0, segment-001 has IV=1 and so on.
Quoting the URI
iOS doesn't seem to like a playlist where the URI
doesn't use quotes so use EXT-X-KEY:METHOD=AES-128,URI="output.key"
Playlist type VOD
EXT-X-PLAYLIST-TYPE
is optional and, as long as you have the EXT-X-ENDLIST
at the end, the playlist is treated as static and allows you to seek. With or without this tag both VLC and iOS treat your playlist as VOD.
Concerning the media duration, VLC shows 0 wile iOS shows the correct value.
If you do specify EXT-X-PLAYLIST-TYPE:VOD
make sure it comes after EXT-X-VERSION:3
or VLC won't like it.