Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
bash scripts to create VOD HLS stream with ffmpeg almighty (tested on Linux and OS X)

running:

bash create-vod-hls.sh beach.mkv

will produce:

    beach/
      |- playlist.m3u8
      |- 360p.m3u8
      |- 360p_001.ts
      |- 360p_002.ts
      |- 480p.m3u8
      |- 480p_001.ts
      |- 480p_002.ts
      |- 720p.m3u8
      |- 720p_001.ts
      |- 720p_002.ts
      |- 1080p.m3u8
      |- 1080p_001.ts
      |- 1080p_002.ts  

origin: http://docs.peer5.com/guides/production-ready-hls-vod/

#!/usr/bin/env bash
set -e
# Usage create-vod-hls.sh SOURCE_FILE [OUTPUT_NAME]
[[ ! "${1}" ]] && echo "Usage: create-vod-hls.sh SOURCE_FILE [OUTPUT_NAME]" && exit 1
# comment/add lines here to control which renditions would be created
renditions=(
# resolution bitrate audio-rate
# "426x240 400k 64k"
"640x360 800k 96k"
"842x480 1400k 128k"
"1280x720 2800k 128k"
"1920x1080 5000k 192k"
)
segment_target_duration=4 # try to create a new segment every X seconds
max_bitrate_ratio=1.07 # maximum accepted bitrate fluctuations
rate_monitor_buffer_ratio=1.5 # maximum buffer size between bitrate conformance checks
#########################################################################
source="${1}"
target="${2}"
if [[ ! "${target}" ]]; then
target="${source##*/}" # leave only last component of path
target="${target%.*}" # strip extension
fi
mkdir -p ${target}
key_frames_interval="$(echo `ffprobe ${source} 2>&1 | grep -oE '[[:digit:]]+(.[[:digit:]]+)? fps' | grep -oE '[[:digit:]]+(.[[:digit:]]+)?'`*2 | bc || echo '')"
key_frames_interval=${key_frames_interval:-50}
key_frames_interval=$(echo `printf "%.1f\n" $(bc -l <<<"$key_frames_interval/10")`*10 | bc) # round
key_frames_interval=${key_frames_interval%.*} # truncate to integer
# static parameters that are similar for all renditions
static_params="-c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -sc_threshold 0"
static_params+=" -g ${key_frames_interval} -keyint_min ${key_frames_interval} -hls_time ${segment_target_duration}"
static_params+=" -hls_playlist_type vod"
# misc params
misc_params="-hide_banner -y"
master_playlist="#EXTM3U
#EXT-X-VERSION:3
"
cmd=""
for rendition in "${renditions[@]}"; do
# drop extraneous spaces
rendition="${rendition/[[:space:]]+/ }"
# rendition fields
resolution="$(echo ${rendition} | cut -d ' ' -f 1)"
bitrate="$(echo ${rendition} | cut -d ' ' -f 2)"
audiorate="$(echo ${rendition} | cut -d ' ' -f 3)"
# calculated fields
width="$(echo ${resolution} | grep -oE '^[[:digit:]]+')"
height="$(echo ${resolution} | grep -oE '[[:digit:]]+$')"
maxrate="$(echo "`echo ${bitrate} | grep -oE '[[:digit:]]+'`*${max_bitrate_ratio}" | bc)"
bufsize="$(echo "`echo ${bitrate} | grep -oE '[[:digit:]]+'`*${rate_monitor_buffer_ratio}" | bc)"
bandwidth="$(echo ${bitrate} | grep -oE '[[:digit:]]+')000"
name="${height}p"
cmd+=" ${static_params} -vf scale=w=${width}:h=${height}:force_original_aspect_ratio=decrease"
cmd+=" -b:v ${bitrate} -maxrate ${maxrate%.*}k -bufsize ${bufsize%.*}k -b:a ${audiorate}"
cmd+=" -hls_segment_filename ${target}/${name}_%03d.ts ${target}/${name}.m3u8"
# add rendition entry in the master playlist
master_playlist+="#EXT-X-STREAM-INF:BANDWIDTH=${bandwidth},RESOLUTION=${resolution}\n${name}.m3u8\n"
done
# start conversion
echo -e "Executing command:\nffmpeg ${misc_params} -i ${source} ${cmd}"
ffmpeg ${misc_params} -i ${source} ${cmd}
# create master playlist file
echo -e "${master_playlist}" > ${target}/playlist.m3u8
echo "Done - encoded HLS is at ${target}/"
@p3rtinax

This comment has been minimized.

Copy link

p3rtinax commented Mar 2, 2018

is it possible to add "ffprobe source.mp4" and detect input height,
then create HLS resolution =< source ?
example :
source.mp4 is 720p ( 1280x720 )
then create HLS 720p, 480p, 360p, 240p
another thing is:
for example if source is between 1080p and 720p then again output will begin from 720p and so on
if source is between 2160p and 1080p then again output will begin from 1080p and so on

@bapfnet

This comment has been minimized.

Copy link

bapfnet commented Mar 10, 2018

Hi, I thank you for this bash but it doesn't work and I have no idea how to fix it ...
errors listed from: Undefined constant or missing '(' in 'keyint_min'
below.....

Bastians-iMac: ffmpeg imac$ bash create-vod-hls.sh orig_homm.mp4 ffprobe orig_homm.mp4
create-vod-hls.sh: line 35: printf: 6.00000000000000000000: invalid number
(standard_in) 1: parse error
Executing command:
ffmpeg -hide_banner -y -i orig_homm.mp4 -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g -keyint_min -hls_time 4 -hls_playlist_type vod -vf scale=w=640:h=360:force_original_aspect_ratio=decrease -b:v 800k -maxrate 856k -bufsize 1200k -b:a 96k -hls_segment_filename ffprobe/360p_%03d.ts ffprobe/360p.m3u8 -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g -keyint_min -hls_time 4 -hls_playlist_type vod -vf scale=w=842:h=480:force_original_aspect_ratio=decrease -b:v 1400k -maxrate 1498k -bufsize 2100k -b:a 128k -hls_segment_filename ffprobe/480p_%03d.ts ffprobe/480p.m3u8 -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g -keyint_min -hls_time 4 -hls_playlist_type vod -vf scale=w=1280:h=720:force_original_aspect_ratio=decrease -b:v 2800k -maxrate 2996k -bufsize 4200k -b:a 128k -hls_segment_filename ffprobe/720p_%03d.ts ffprobe/720p.m3u8 -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g -keyint_min -hls_time 4 -hls_playlist_type vod -vf scale=w=1920:h=1080:force_original_aspect_ratio=decrease -b:v 5000k -maxrate 5350k -bufsize 7500k -b:a 192k -hls_segment_filename ffprobe/1080p_%03d.ts ffprobe/1080p.m3u8
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'orig_homm.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp42isomavc1
creation_time : 2018-01-26T02:37:26.000000Z
encoder : HandBrake 0.9.9 2013051800
Duration: 00:03:57.57, start: 0.000000, bitrate: 16117 kb/s
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 3840x2160 [SAR 1:1 DAR 16:9], 15966 kb/s, 30 fps, 30 tbr, 90k tbn, 180k tbc (default)
Metadata:
creation_time : 2018-01-26T02:37:26.000000Z
encoder : JVT/AVC Coding
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 151 kb/s (default)
Metadata:
creation_time : 2018-01-26T02:37:26.000000Z
Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
Stream #0:1 -> #0:1 (aac (native) -> aac (native))
Stream #0:0 -> #1:0 (h264 (native) -> h264 (libx264))
Stream #0:1 -> #1:1 (aac (native) -> aac (native))
Stream #0:0 -> #2:0 (h264 (native) -> h264 (libx264))
Stream #0:1 -> #2:1 (aac (native) -> aac (native))
Stream #0:0 -> #3:0 (h264 (native) -> h264 (libx264))
Stream #0:1 -> #3:1 (aac (native) -> aac (native))
Press [q] to stop, [?] for help
[libx264 @ 0x7ffd31804c00] [Eval @ 0x7fff577ad7e0] Undefined constant or missing '(' in 'keyint_min'
[libx264 @ 0x7ffd31804c00] Unable to parse option value "-keyint_min"
[libx264 @ 0x7ffd31804c00] Error setting option g to value -keyint_min.
Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height
[aac @ 0x7ffd31806400] Qavg: 20328.691
[aac @ 0x7ffd31806400] 2 frames left in the queue on closing
[aac @ 0x7ffd3180a200] Qavg: 25456.812
[aac @ 0x7ffd3180a200] 2 frames left in the queue on closing
[aac @ 0x7ffd3181b000] Qavg: 25456.812
[aac @ 0x7ffd3181b000] 2 frames left in the queue on closing
[aac @ 0x7ffd3181ee00] Qavg: 52410.695
[aac @ 0x7ffd3181ee00] 2 frames left in the queue on closing
Conversion failed!

@AndriiFed

This comment has been minimized.

Copy link

AndriiFed commented Mar 23, 2018

Your options -g -keyint_min do not have values.
Should be -g 50 -keyint_min 25 for example.

@sybon

This comment has been minimized.

Copy link

sybon commented Oct 2, 2018

Dear Andrii,

On the basis of your code (thank you for this !)
Could you give the right command line or advice to produce such a HLS PLaylist (multi video / multi audio / multi subtitle) HLS playlist (m3u8 with synchro. segments) : http://sample.vodobox.com/planete_interdite/planete_interdite_alternate.m3u8
out of an mp4 video for example.

File content of the expecting results for the MASTER.M38 (planete_interdite_alternate.m3u8):
#EXTM3U
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subtitle",NAME="#1 Fre",DEFAULT=NO,FORCED=NO,LANGUAGE="fre",URI="subtitles/planete_interdite_subtitle3_fre_vtt.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subtitle",NAME="#2 Eng",DEFAULT=NO,FORCED=NO,LANGUAGE="eng",URI="subtitles/planete_interdite_subtitle4_eng_vtt.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subtitle",NAME="#3 Eng",DEFAULT=NO,FORCED=NO,LANGUAGE="eng",URI="subtitles/planete_interdite_subtitle5_eng_vtt.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="low",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="low/planete_interdite_228_h264_144p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="low",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="low/planete_interdite_228_h264_144p_audio2_eng.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="medium",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="medium/planete_interdite_500_h264_240p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="medium",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="medium/planete_interdite_500_h264_240p_audio2_eng.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="high",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="high/planete_interdite_1228_q264_360p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="high",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="high/planete_interdite_1228_q264_360p_audio2_eng.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="veryhigh",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="veryhigh/planete_interdite_2080_q264_480p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="veryhigh",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="veryhigh/planete_interdite_2080_q264_480p_audio2_eng.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="hdready",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="hdready/planete_interdite_4160_n264_720p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="hdready",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="hdready/planete_interdite_4160_n264_720p_audio2_eng.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="fullhd",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="fullhd/planete_interdite_8256_n264_1080p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="fullhd",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="fullhd/planete_interdite_8256_n264_1080p_audio2_eng.m3u8"
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=314000,CODECS="avc1.66.30,mp4a.40.2",RESOLUTION=256x144,AUDIO="low",SUBTITLES="subtitle"
low/planete_interdite_228_h264_144p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=638000,CODECS="avc1.66.30,mp4a.40.2",RESOLUTION=426x240,AUDIO="medium",SUBTITLES="subtitle"
medium/planete_interdite_500_h264_240p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1942000,CODECS="avc1.66.30,mp4a.40.2",RESOLUTION=640x360,AUDIO="high",SUBTITLES="subtitle"
high/planete_interdite_1228_q264_360p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3274000,CODECS="avc1.66.30,mp4a.40.2",RESOLUTION=854x480,AUDIO="veryhigh",SUBTITLES="subtitle"
veryhigh/planete_interdite_2080_q264_480p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4814000,CODECS="avc1.4d001f,mp4a.40.2",RESOLUTION=1280x720,AUDIO="hdready",SUBTITLES="subtitle"
hdready/planete_interdite_4160_n264_720p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=9501000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080,AUDIO="fullhd",SUBTITLES="subtitle"
fullhd/planete_interdite_8256_n264_1080p.m3u8

Thank you if you can help.

Best regards,

Sylvain

@rocketon85

This comment has been minimized.

Copy link

rocketon85 commented Nov 8, 2018

Dear Andrii,

On the basis of your code (thank you for this !)
Could you give the right command line or advice to produce such a HLS PLaylist (multi video / multi audio / multi subtitle) HLS playlist (m3u8 with synchro. segments) : http://sample.vodobox.com/planete_interdite/planete_interdite_alternate.m3u8
out of an mp4 video for example.

File content of the expecting results for the MASTER.M38 (planete_interdite_alternate.m3u8):
#EXTM3U
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subtitle",NAME="#1 Fre",DEFAULT=NO,FORCED=NO,LANGUAGE="fre",URI="subtitles/planete_interdite_subtitle3_fre_vtt.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subtitle",NAME="#2 Eng",DEFAULT=NO,FORCED=NO,LANGUAGE="eng",URI="subtitles/planete_interdite_subtitle4_eng_vtt.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subtitle",NAME="#3 Eng",DEFAULT=NO,FORCED=NO,LANGUAGE="eng",URI="subtitles/planete_interdite_subtitle5_eng_vtt.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="low",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="low/planete_interdite_228_h264_144p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="low",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="low/planete_interdite_228_h264_144p_audio2_eng.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="medium",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="medium/planete_interdite_500_h264_240p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="medium",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="medium/planete_interdite_500_h264_240p_audio2_eng.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="high",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="high/planete_interdite_1228_q264_360p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="high",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="high/planete_interdite_1228_q264_360p_audio2_eng.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="veryhigh",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="veryhigh/planete_interdite_2080_q264_480p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="veryhigh",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="veryhigh/planete_interdite_2080_q264_480p_audio2_eng.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="hdready",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="hdready/planete_interdite_4160_n264_720p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="hdready",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="hdready/planete_interdite_4160_n264_720p_audio2_eng.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="fullhd",NAME="#1 Fre",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="fre",URI="fullhd/planete_interdite_8256_n264_1080p_audio1_fre.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="fullhd",NAME="#2 Eng",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="eng",URI="fullhd/planete_interdite_8256_n264_1080p_audio2_eng.m3u8"
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=314000,CODECS="avc1.66.30,mp4a.40.2",RESOLUTION=256x144,AUDIO="low",SUBTITLES="subtitle"
low/planete_interdite_228_h264_144p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=638000,CODECS="avc1.66.30,mp4a.40.2",RESOLUTION=426x240,AUDIO="medium",SUBTITLES="subtitle"
medium/planete_interdite_500_h264_240p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1942000,CODECS="avc1.66.30,mp4a.40.2",RESOLUTION=640x360,AUDIO="high",SUBTITLES="subtitle"
high/planete_interdite_1228_q264_360p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3274000,CODECS="avc1.66.30,mp4a.40.2",RESOLUTION=854x480,AUDIO="veryhigh",SUBTITLES="subtitle"
veryhigh/planete_interdite_2080_q264_480p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4814000,CODECS="avc1.4d001f,mp4a.40.2",RESOLUTION=1280x720,AUDIO="hdready",SUBTITLES="subtitle"
hdready/planete_interdite_4160_n264_720p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=9501000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080,AUDIO="fullhd",SUBTITLES="subtitle"
fullhd/planete_interdite_8256_n264_1080p.m3u8

Thank you if you can help.

Best regards,

Sylvain

Uy that would be very good, configure the nginx, but if I use ffmpeg on rtmp I see the video in live, and I can not handle audio, subtitles, etc ... I found some examples but with VideoJs they give me error in "slice .... "

Thanks

@pberthol

This comment has been minimized.

Copy link

pberthol commented Nov 13, 2018

great script but i have error when i use your script :

Press [q] to stop, [?] for help
[libx264 @ 0x7febe5808a00] [Eval @ 0x7ffee8d08820] Undefined constant or missing '(' in 'keyint_min'
[libx264 @ 0x7febe5808a00] Unable to parse option value "-keyint_min"
[libx264 @ 0x7febe5808a00] Error setting option g to value -keyint_min.
Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height
Conversion failed!

this part :

  key_frames_interval="$(echo `ffprobe ${source} 2>&1 | grep -oE '[[:digit:]]+(.[[:digit:]]+)? fps' | grep -oE '[[:digit:]]+(.[[:digit:]]+)?'`*2 | bc || echo '')"
 key_frames_interval=${key_frames_interval:-50}
 key_frames_interval=$(echo `printf "%.1f\n" $(bc -l <<<"$key_frames_interval/10")`*10 | bc) # round
key_frames_interval=${key_frames_interval%.*} # truncate to integer

seems doesn't work.

tested on osx mojave
ffmpeg 4.1 ffprobe 4.1

enhanced :
i want sperate resolution per subfolder
bleach /360p/001.ts 002ts 003.ts...
/720p/001.ts 002ts 003.ts...
how do that ?

@rishcool

This comment has been minimized.

Copy link

rishcool commented Dec 5, 2018

Hey!

I need to your help for adding overlay so i made below changes in script and my new "cmd" is below:

filter="movie=test.png[watermark];[watermark][0]scale2ref=200iw/1280:200iw/1280[wm][v];[wm]setsar=1[logo];[v][logo] overlay=main_w-overlay_w-5:main_h-overlay_h-5, scale=floor(iw*min(1,min(${width}/iw,${height}/ih))/2+0.4999999)*2:-2 [out]"

cmd+="-filter_complex "${filter}" -map [out] -map 0:a -c:a copy"
cmd+=" ${static_params} -movflags faststart"
cmd+=" -b:v ${bitrate} -maxrate ${maxrate%.}k -bufsize ${bufsize%.}k -b:a ${audiorate}"
cmd+=" -hls_segment_filename ${target}${name}/${hash}_%03d.ts ${target}${name}/${hash}.m3u8 -strict -1"

but its not taking "' (quotes)" and giving and error
[AVFilterGraph @ 0x2e85280] No such filter: ''

and if i am running below command its working fine:

ffmpeg -hide_banner -y -i test.mp4 -filter_complex movie=test.png[watermark];[watermark][0]scale2ref=200iw/1280:200iw/1280[wm][v];[wm]setsar=1[logo];[v][logo] overlay=main_w-overlay_w-5:main_h-overlay_h-5, scale=floor(iw*min(1,min(426/iw,240/ih))/2+0.4999999)*2:-2 [out] -map [out] -map 0:a -c:a copy -c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g 60 -keyint_min 60 -hls_time 4 -hls_playlist_type vod -movflags faststart -b:v 400k -maxrate 428k -bufsize 600k -b:a 64k -hls_segment_filename videos/240p/test_%03d.ts videos/240p/test.m3u8 -strict -1 -c copy -f flv

@Sergerant

This comment has been minimized.

Copy link

Sergerant commented Dec 9, 2018

Also having issue on latest Mac OS etc.

./create-vod-hls.sh: line 35: printf: 10.00000000000000000000: invalid number
(standard_in) 1: parse error

[libx264 @ 0x7ff756099e00] [Eval @ 0x7ffee3708760] Undefined constant or missing '(' in 'keyint_min'
[libx264 @ 0x7ff756099e00] Unable to parse option value "-keyint_min"
[libx264 @ 0x7ff756099e00] Error setting option g to value -keyint_min.
Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height

@jisln

This comment has been minimized.

Copy link

jisln commented Dec 17, 2018

For mac OS users who get create-vod-hls.sh: line 35: printf: 6.00000000000000000000: invalid number
you can consider adding export LC_NUMERIC="en_US.UTF-8" in the very beginning of your script.

Thanks for the job !

@tamir-maoz

This comment has been minimized.

Copy link

tamir-maoz commented Dec 24, 2018

Hi,
I have a multi-rendition video, segmented in 10sec intervals using the above script.
i'm trying to add subtitles (webVTT format).
since my videos are short (~2 min) i don't mind having a single subtitle file (for each language) that will be used for all renditions and segments.
is it possible?
i'm unable to find where and which command should i add to achieve it.
if the above is not possible, what would be the best approach?
Thanks.

@FullstackJack

This comment has been minimized.

Copy link

FullstackJack commented Jan 30, 2019

Thanks for sharing this, I'll keep testing it out and see if we can make any improvements.

Seems to work on macOS Mojave 10.14.2 with latest brew version of ffmpeg.

Input File: http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4

ffmpeg version 4.1 Copyright (c) 2000-2018 the FFmpeg developers
  built with Apple LLVM version 10.0.0 (clang-1000.11.45.5)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.1_3 --enable-shared --enable-pthreads --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gpl --enable-libmp3lame --enable-libopus --enable-libsnappy --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-librtmp --enable-libspeex --enable-videotoolbox
  libavutil      56. 22.100 / 56. 22.100
  libavcodec     58. 35.100 / 58. 35.100
  libavformat    58. 20.100 / 58. 20.100
  libavdevice    58.  5.100 / 58.  5.100
  libavfilter     7. 40.101 /  7. 40.101
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  3.100 /  5.  3.100
  libswresample   3.  3.100 /  3.  3.100
  libpostproc    55.  3.100 / 55.  3.100
@FullstackJack

This comment has been minimized.

Copy link

FullstackJack commented Jan 30, 2019

In the terminal, is the time string on the frame line the time elapsed?
For instance, my last frame of transcode for Big Buck Bunny was the following:
frame=19038 fps= 22 q=-1.0 Lq=-1.0 q=-1.0 q=-1.0 size=N/A time=00:10:34.53 bitrate=N/A dup=8 drop=0 speed=0.741

@appserv64

This comment has been minimized.

Copy link

appserv64 commented Feb 10, 2019

Ubuntu 16.04 , ffmpeg 4.1.1
create-vod-hls.sh: line 33: bc: command not found
create-vod-hls.sh: line 35: bc: command not found
create-vod-hls.sh: line 35: bc: command not found

@m-emelchenkov

This comment has been minimized.

Copy link

m-emelchenkov commented Feb 11, 2019

@appserv64 bc is a text-mode calculator, not ffmpeg-related tool. You can install it via apt install bc.

@havishmanakkina

This comment has been minimized.

Copy link

havishmanakkina commented Apr 1, 2019

Thank you for the script...
It works completely fine...
but takes a lot of time to process when we try to convert a video which is 39 min and 200MB of a size
we are using a dual core processor and 4 gb RAM
it is nearly taking more than an hour to process it
can you help us if there is anything that we can do to speed up the process...
thank you in advance

@elmadkoun

This comment has been minimized.

Copy link

elmadkoun commented Apr 9, 2019

/usr/bin/create-vod-hls.sh: line 33: bc: command not found
/usr/bin/create-vod-hls.sh: line 35: bc: command not found
/usr/bin/create-vod-hls.sh: line 35: bc: command not found

@FrancoJoaquinTorres

This comment has been minimized.

Copy link

FrancoJoaquinTorres commented Apr 23, 2019

Hi, thanks for you script. I need help with other problem. I have one video with multiple quality and multiple audios. The audio have the same quality. How i can modify script for this.
Example
video1 --> 1080 | 720 | 480
audio --> english | spanish (same quality)
It possible?
Thanks!

@dangayle

This comment has been minimized.

Copy link

dangayle commented Apr 24, 2019

Thank you sir, this is exactly the script I've been looking for.

@Teranode

This comment has been minimized.

Copy link

Teranode commented May 19, 2019

@elmadkoun
apt-get install bc
or
yum install bc

@Das-Sreedeep

This comment has been minimized.

Copy link

Das-Sreedeep commented Jun 17, 2019

Unrecognized option 'hls_playlist_type'.
Error splitting the argument list: Option not found

Getting in ubuntu

@monokal

This comment has been minimized.

Copy link

monokal commented Jul 2, 2019

Here's a re-write in Python which includes IPFS support. PRs very welcome:
https://github.com/desiredState/IPFSStreamingVideo

@obender75

This comment has been minimized.

Copy link

obender75 commented Jul 9, 2019

in key_frames_interval you just get frame rate it has nothing to do with gop size, you may be lucky though 'cuz most of the time gop would be multiple of framerate, but you'll get wrong values of your source was enoded with adaptative gop (which is totally legit in h264). you can even get ts sources where gop changes somemewhere in the middle of the flight. you need to dump frame types, parce it and compute gop size checking the distance b/w idr frames (and may be check if gop is constant and closed as well). check how it's done ~correctly here : https://snippets.bentasker.co.uk/page-1707191206-Get-Video-Keyframe-Interval-(ffprobe)-BASH.html
.
it's a useless stage in fract try to duplicate the gop of your source as you reencode, it might have been pretty useful if you wanted to just repackage mp4 sources encoded for segmented http without transcoding...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.