DASH - Adaptive H.264 Videos erstellen


Skript zur Generierung von DASH-Videos, die je nach zur Verfügung stehenden Bandbreite das qualitativ beste Video dem Client bereitstellen.

brew install MP4box
brew install ffmpeg

~/bin/mp4-to-dash:

 
#!/usr/bin/env bash
set -e

SAVEDIR="$(pwd)/"
mkdir -p "${SAVEDIR}"

renderAudio() {
    filename="$1"
    bitrate="$2"
    if [ ! -f "${filename}_audio_${bitrate}.m4a" ]; then
	ffmpeg -y -i "${inputfile}" -c:a aac -ac 2 -ab "${bitrate}k" -vn "${filename}_audio_${bitrate}.m4a"
    fi
}

renderVideo() {
    filename="$1"
    bitrate="$2"
    height="$3"
    if [ ! -f "${filename}_${height}_${bitrate}.mp4" ]; then
#	ffmpeg -y -i "${inputfile}" -an -c:v libx264 -x264opts 'keyint=25:min-keyint=25:no-scenecut' \
#            -movflags frag_keyframe+empty_moov -g 25 -b:v ${bitrate}k -vf "scale=-2:${height}" -f mp4 -pass 1 -y /dev/null
	ffmpeg -y -i "${inputfile}" -an -c:v libx264 -x264opts 'keyint=25:min-keyint=25:no-scenecut' \
	    -movflags frag_keyframe+empty_moov -g 25 -b:v ${bitrate}k -vf "scale=-2:${height}" -f mp4 "${filename}_${height}_${bitrate}.mp4"
    fi

}

for inputfile in $@
do
    fname=$(basename "${inputfile}") # fullname of the file
    fname="${fname%.*}" # name without extension

    echo "Converting \"${inputfile}\" to multi-bitrate video in MPEG-DASH"

    renderAudio "${SAVEDIR}/${fname}" 96
    renderAudio "${SAVEDIR}/${fname}" 48

    renderVideo "${SAVEDIR}/${fname}" 1500 540
    renderVideo "${SAVEDIR}/${fname}" 0500 540
    renderVideo "${SAVEDIR}/${fname}" 0300 270
    renderVideo "${SAVEDIR}/${fname}" 0200 180

    ffmpeg -i "${SAVEDIR}/${fname}_540_0500.mp4" -i "${SAVEDIR}/${fname}_audio_96.m4a" \
           -acodec copy -vcodec copy \
           "${fname}_stream.mp4"
    MP4Box -inter 500 "${fname}_stream.mp4"

    MP4Box -dash 2000 -min-buffer 3000 -frag 2000 -rap -out "${fname}_mp4.mpd" \
	"${SAVEDIR}/${fname}_540_1500.mp4" \
	"${SAVEDIR}/${fname}_540_0500.mp4" \
	"${SAVEDIR}/${fname}_270_0300.mp4" \
	"${SAVEDIR}/${fname}_180_0200.mp4" \
	"${SAVEDIR}/${fname}_audio_96.m4a" \
	"${SAVEDIR}/${fname}_audio_48.m4a"
#	"${SAVEDIR}/${fname}_360_0400.mp4"
#	"${SAVEDIR}/${fname}_audio_32.m4a"

#    rm 	"${SAVEDIR}/${fname}_540_1500.mp4" "${SAVEDIR}/${fname}_540_0500.mp4" \
#	"${SAVEDIR}/${fname}_360_0400.mp4" "${SAVEDIR}/${fname}_270_0300.mp4" \
#	"${SAVEDIR}/${fname}_180_0200.mp4" \
#	"${SAVEDIR}/${fname}_audio_96.m4a" "${SAVEDIR}/${fname}_audio_48.m4a" "${SAVEDIR}/${fname}_audio_32.m4a"


done

Konvertieren via:

mp4-to-dash sample.mp4

Abspielen dann via dash-if player (Auszug aus dem _video.html.erb-Renderer einer Camaleon Instanz):

...
<script src="http://cdn.dashjs.org/latest/dash.all.min.js"></script>
...
    <video data-dashjs-player id="video-<%= post.the_id %>"
           poster="<%= post.the_thumb_url %>"
           width="960" height="540"
           controls="controls"
           preload="auto"
           data-src="/streams/<%= post.the_field('video-file') %>/<%= post.the_field('video-file') %>_mp4.mpd">
      <source src="/streams/<%= post.the_field('video-file') %>/<%= post.the_field('video-file') %>_stream.mp4">
    </video>

...              

Da alle 2 Sekunden ein neues Fragment geladen wird, sollten im access-log vom nginx diese Requests ausgeblendet werden:

    location /streams/ {
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS, HEAD';
            add_header 'Access-Control-Allow-Headers' 'range, content-type';
            return 204;
        }
        access_log none;
        add_header 'Access-Control-Allow-Origin' '*';
    }

Die Konfiguration der Access-Control-Allow-Flags kann entfallen, falls die Videos nicht von einer anderen URL heraus aufgerufen werden.

Kommentare per Mail an post@wolfgang-jung.net.