Skip to content

Instantly share code, notes, and snippets.

@zoncoen
Last active April 22, 2016 08:21
Show Gist options
  • Save zoncoen/5672ad41766ca6a86e5be70861d88bc6 to your computer and use it in GitHub Desktop.
Save zoncoen/5672ad41766ca6a86e5be70861d88bc6 to your computer and use it in GitHub Desktop.
ffmpegで動画の設定チェックする君
#!/bin/bash
declare -A Opts=([verbose]=0)
function main() {
declare -i argc=0
declare -a argv=()
: 'Parse args' && {
while (($# > 0))
do
case "$1" in
--help)
usage
exit 0
;;
--verbose)
OptVerbose=1
shift
;;
--debug)
set -x
shift
;;
--*)
error "[ERROR] Invalid option '${1}'."
usage
exit 1
;;
-*)
declare -i match=0
if [[ "$1" =~ h ]]; then
usage
exit 0
((++match))
fi
if [[ "$1" =~ v ]]; then
OptVerbose=1
((++match))
fi
if [[ "$1" =~ d ]]; then
set -x
((++match))
fi
if [ $match -eq 0 ]; then
error "[ERROR] Invalid option '${1}'."
usage
exit 1
fi
shift
;;
*)
((++argc))
argv=("${argv[@]}" "$1")
shift
;;
esac
done
if [ $argc -ne 1 ]; then
usage
exit 1
fi
}
: 'Get video information' && {
if [ ! -f ${argv[0]} ]; then
error "[ERROR] '${argv[0]}' not found."
exit 1
fi
: 'metadata' && {
streams=$(ffprobe ${argv[0]} -show_format -show_streams -print_format json 2>/dev/null | jq '.streams')
video=$(echo ${streams} | jq 'if .[0].codec_type == "video" then .[0] else null end')
audio=$(echo ${streams} | jq 'if .[1].codec_type == "audio" then .[1] else null end')
if [ "$video" = 'null' ]; then
error '[ERROR] Can not detect video stream.'
exit 1
fi
if [ "$audio" = 'null' ]; then
error '[ERROR] Can not detect audio stream.'
exit 1
fi
}
: 'video avarage key frame interval' && {
tmpfile="$(mktemp "/tmp/${0##*/}.tmp.XXXXXX").${argv[0]##*.}"
ffmpeg -ss 0 -i ${argv[0]} -t 20 -vcodec copy -acodec copy "$tmpfile" 2>/dev/null
declare -a timestamps=($(echo `ffprobe -show_frames -select_streams v -print_format json "$tmpfile" 2>/dev/null | jq -r '.frames | map(select( .key_frame == 1)) | .[].best_effort_timestamp_time'`))
sum=0
for i in $(seq 1 `expr ${#timestamps[*]} - 1`); do
sum=$(echo "${sum} + (${timestamps[$i]} - ${timestamps[((--i))]})" | bc)
done
avg_key_frame_interval=$(echo "scale=3; $sum / `expr ${#timestamps[*]} - 1`" | bc)
}
}
declare -i errors=0
: 'Check video' && {
check 'video codec' "$(echo $video | jq -r '.codec_name')" 'h264'; errors=$(expr $errors + $?)
check 'video profile' "$(echo $video | jq -r '.profile')" 'Constrained Baseline'; errors=$(expr $errors + $?)
check 'video level' "$(echo $video | jq -r '.level')" '30'; errors=$(expr $errors + $?)
check 'video width' "$(echo $video | jq -r '.width')" '640'; errors=$(expr $errors + $?)
check 'video height' "$(echo $video | jq -r '.height')" '360'; errors=$(expr $errors + $?)
check 'video SAR' "$(echo $video | jq -r '.sample_aspect_ratio')" '1:1'; errors=$(expr $errors + $?)
check 'video DAR' "$(echo $video | jq -r '.display_aspect_ratio')" '16:9'; errors=$(expr $errors + $?)
check 'video fps' "$(echo $video | jq -r '.r_frame_rate')" '30/1'; errors=$(expr $errors + $?)
check 'video avarage key frame interval' "$avg_key_frame_interval" '1.000'; errors=$(expr $errors + $?)
}
: 'Check audio' && {
check 'audio codec' "$(echo $audio | jq -r '.codec_name')" 'aac'; errors=$(expr $errors + $?)
check 'audio profile' "$(echo $audio | jq -r '.profile')" 'LC'; errors=$(expr $errors + $?)
}
if [ $errors -ne 0 ]; then
exit 1
fi
}
function usage() {
cat <<EOF
Usage: ${0} [options] {filepath}
Options:
--help, -h show this message
--verbose, -v show details
--debug, -d set -x
EOF
}
function check() {
if [ "$2" = "$3" ]; then
success "✔ $1: $2"
return 0
else
error "✗ $1: expected '$3' got '$2'"
return 1
fi
}
function success() {
if [ ${Opts['verbose']} -eq 1 ]; then
echo -e "\033[33;32m${1}\033[0m"
fi
}
function error() {
echo -e "\033[33;31m${1}\033[0m" 1>&2
}
main $*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment