Skip to content

Instantly share code, notes, and snippets.

@SCG82
Last active April 11, 2023 04:38
Show Gist options
  • Save SCG82/463e99d13adb32efefcab80a0311674d to your computer and use it in GitHub Desktop.
Save SCG82/463e99d13adb32efefcab80a0311674d to your computer and use it in GitHub Desktop.
Convert HDR video to SDR with tone mapping (especially for iPhone 12)
#!/bin/bash
#************************************************
# hdrtosdr.sh *
# v1.0.0 *
# developer: SCG82 ([email protected]) *
#************************************************
USAGE_S="Usage: $0 -s [start time hh:mm:ss] -e [end time hh:mm:ss] -w width -h height -p preset FILE"
USAGE="Usage (arguments are optional): $0 -s [start time hh:mm:ss] -e [end time hh:mm:ss] -w [output width] -h [output height] -p [preset: ultrafast,superfast,veryfast,faster,fast,medium,slow,slower,veryslow,placebo] FILE"
VERSION="1.0.0"
# if filename not supplied display usage message and die
[ $# -eq 0 ] && { echo "$USAGE_S"; exit 1; }
_file=""
hsize=-1
vsize=-1
fps=30
preset="medium"
start="0:0:0"
endtime=""
has_start=0
has_end=0
aspect_changed=0
pix_fmt="yuv420p"
in_width=1920
in_height=1080
out_height=-1
while getopts ":w:h:p:a:f:l:s:e:vH" optname
do
case "$optname" in
"v")
echo "Version $VERSION"
exit 0;
;;
"w")
if [[ "$OPTARG" =~ ^[0-9]+$ ]] && [ "$OPTARG" -ge 1 ]; then
hsize=$OPTARG
else
echo "invalid width: \"$OPTARG\"" && exit 1
fi
;;
"h")
if [[ "$OPTARG" =~ ^[0-9]+$ ]] && [ "$OPTARG" -ge 1 ]; then
vsize=$OPTARG
else
echo "invalid height: \"$OPTARG\"" && exit 1
fi
;;
"p")
if [[ "$OPTARG" =~ [a-zA-Z0-9_]+$ ]]; then
echo "preset: $OPTARG"
preset=$OPTARG
else
echo "invalid preset: \"$OPTARG\"" && exit 1
fi
;;
"s")
if [[ "$OPTARG" =~ ^[0-9:.]+$ ]]; then
echo "start time: $OPTARG"
start=$OPTARG
has_start=1
else
echo "invalid start time: \"$OPTARG\"" && exit 1
fi
;;
"e")
if [[ "$OPTARG" =~ ^[0-9:.]+$ ]]; then
echo "end time: $OPTARG"
endtime=$OPTARG
has_end=1
else
echo "invalid end time: \"$OPTARG\"" && exit 1
fi
;;
"H")
echo "$USAGE"
exit 0;
;;
"?")
echo "Unknown option $OPTARG"
exit -1;
;;
":")
echo "No argument value for option $OPTARG"
exit -1;
;;
*)
echo "Unknown error while processing options"
exit -1;
;;
esac
done
shift $((OPTIND - 1))
_file=$1
# if file not found, display an error and die
[ ! -f "$_file" ] && { echo "$0: $_file file not found."; exit 2; }
file_inc_ext="$(basename "$_file")"
file_no_ext="${file_inc_ext%.*}"
in_dir="$(cd "$(dirname "$1")" && pwd -P)"
fps_tbr=$(ffprobe -v error -show_entries stream=r_frame_rate -of default=noprint_wrappers=1:nokey=1 -select_streams v:0 "$_file")
fps_num=${fps_tbr%%/*}
fps_den=${fps_tbr##*/}
fps=$(echo "scale=4; $fps_num / $fps_den" | bc)
out_fps=$(echo "scale=4; $fps" | bc)
in_width=$(ffprobe -v error -show_entries stream=width -of default=noprint_wrappers=1:nokey=1 -select_streams v:0 "$_file")
in_height=$(ffprobe -v error -show_entries stream=height -of default=noprint_wrappers=1:nokey=1 -select_streams v:0 "$_file")
in_sar_raw=$(ffprobe -v error -show_entries stream=sample_aspect_ratio -of default=noprint_wrappers=1:nokey=1 -select_streams v:0 "$_file")
in_sar_num=${in_sar_raw%%:*}
in_sar_den=${in_sar_raw##*:}
in_sar=$(echo "scale=4; $in_sar_num / $in_sar_den" | bc)
if [ $hsize -ne -1 ]; then
out_width=$hsize
else
out_width=$in_width
fi
out_height_calc="($out_width*$in_height*$in_sar_den)/($in_width*$in_sar_num)"
out_height_bc=$(echo "scale=2; ($out_height_calc+0.5)/1" | bc)
out_height=$(echo "scale=0; $out_height_bc/1" | bc)
if [ $vsize -ne -1 ]; then
if [ $out_height -ne $vsize ]; then
aspect_changed=1
fi
out_height=$vsize
fi
duration=$(echo "scale=0; 1000 / $fps" | bc)
color_range_probe=$(ffprobe -v error -show_entries stream=color_range -of default=noprint_wrappers=1:nokey=1 -select_streams v:0 "$_file")
color_space_probe=$(ffprobe -v error -show_entries stream=color_space -of default=noprint_wrappers=1:nokey=1 -select_streams v:0 "$_file")
color_primaries_probe=$(ffprobe -v error -show_entries stream=color_primaries -of default=noprint_wrappers=1:nokey=1 -select_streams v:0 "$_file")
pix_fmt_probe=$(ffprobe -v error -show_entries stream=pix_fmt -of default=noprint_wrappers=1:nokey=1 -select_streams v:0 "$_file")
if [[ "$pix_fmt_probe" =~ ^unknown$ ]]; then
pix_fmt="yuv420p"
elif [[ "$pix_fmt_probe" =~ ^[y|u][u|y]y?v[j|y|y]?y?[0-9b-p]+$ ]]; then
pix_fmt="yuv420p"
elif [[ "$pix_fmt_probe" =~ ^yuva[0-9b-p]+ ]] || [[ "$pix_fmt_probe" =~ ^ayuv[0-9b-p]+ ]]; then
pix_fmt="yuva420p"
elif [[ "$pix_fmt_probe" =~ ^[a|r|g|b][a|r|g|b][a|r|g|b][a|r|g|b][a-z0-9]*$ ]]; then
pix_fmt="rgba"
else
pix_fmt="rgb24"
fi
echo "input size: $in_width x $in_height"
echo "output size: $out_width x $out_height"
if [ $aspect_changed -eq 1 ]; then
echo "(note: aspect ratio will be changed from original)"
fi
echo "duration: $duration"
echo "in fps: $fps"
echo "out fps: $out_fps"
echo "in pix_fmt: $pix_fmt_probe"
echo "out pix_fmt: $pix_fmt"
echo "color_range: $color_range_probe"
echo "color_space: $color_space_probe"
echo "color_primaries: $color_primaries_probe"
TEMPDIR=$(mktemp -d 2>/dev/null)
trap 'rm -rf "$TEMPDIR" >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 13 15
filter="zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p"
sws_flags="lanczos+accurate_rnd+full_chroma_int+full_chroma_inp+bitexact"
if [ $has_end -eq 1 ]; then
ffmpeg -ss "$start" -i "$_file" -to "$endtime" -vf "$filter" -c:v libx264 -preset "$preset" -r:v "$fps_num/$fps_den" -c:a copy -max_muxing_queue_size 1024 -sws_flags "$sws_flags" -color_range 1 -colorspace 1 -color_primaries 1 -color_trc 1 -vsync vfr -pix_fmt "$pix_fmt" "${in_dir}/${file_no_ext}-sdr.mp4"
elif [ $has_start -eq 1 ] && [ $has_end -eq 0 ]; then
ffmpeg -ss "$start" -i "$_file" -vf "$filter" -c:v libx264 -preset "$preset" -r:v "$fps_num/$fps_den" -c:a copy -max_muxing_queue_size 1024 -sws_flags "$sws_flags" -color_range 1 -colorspace 1 -color_primaries 1 -color_trc 1 -vsync vfr -pix_fmt "$pix_fmt" "${in_dir}/${file_no_ext}-sdr.mp4"
else
ffmpeg -i "$_file" -vf "$filter" -c:v libx264 -preset "$preset" -r:v "$fps_num/$fps_den" -c:a copy -max_muxing_queue_size 1024 -sws_flags "$sws_flags" -color_range 1 -colorspace 1 -color_primaries 1 -color_trc 1 -vsync vfr -pix_fmt "$pix_fmt" "${in_dir}/${file_no_ext}-sdr.mp4"
fi
exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment