Skip to content

Instantly share code, notes, and snippets.

@hfossli
Last active May 12, 2022 07:32
Show Gist options
  • Save hfossli/6003302 to your computer and use it in GitHub Desktop.
Save hfossli/6003302 to your computer and use it in GitHub Desktop.
A bash script for reversing videos using ffmpeg and sox.
#!/bin/bash
# Created by Håvard Fossli <[email protected]> in 2013
# This is free and unencumbered software released into the public domain.
# For more information, please refer to <http://unlicense.org/>
#
# Description
# A bash script for reversing videos using ffmpeg and sox.
#
# Keywords
# Terminal, bash, unix, mac, shell, script, video, movie, reverse, inverse, audio, video, ffmpeg, sox.
#
# Usefull links when working with ffmpeg
# - https://sites.google.com/site/linuxencoding/ffmpeg-tips
# - http://pvdm.xs4all.nl/wiki/index.php/Convert_an_AVCHD_/_MTS_file_to_MP4_using_ffmpeg
# - http://rodrigopolo.com/ffmpeg/cheats.php
# - http://www.catswhocode.com/blog/19-ffmpeg-commands-for-all-needs
#
# arg1: name of program
function assert_program_exists() {
command -v $1 >/dev/null 2>&1 || {
echo >&2 "You must have $1 installed in order to run this script. Try:";
echo "\$ brew install $1"
exit 1;
}
}
# arg1: path to input file / source
function fallback_output_path() {
if [[ -z "$1" ]] ; then
echo "Bad input to get_video_duration_in_seconds_from_ffmpeg_info()"
echo "Input givven $1"
exit 1
else
__FILE_NAME=`rev <<< "$1" | cut -d"." -f2- | rev`
__FILE_EXT=`rev <<< "$1" | cut -d"." -f1 | rev`
__OUT_FILE_FORMAT="${__FILE_NAME}-reversed.mp4"
echo $__OUT_FILE_FORMAT
exit 1
fi
}
function echo_variables {
echo
echo "### Variables ###"
echo
}
function usage {
echo "For help and detailed guide type:"
echo "\$ $0 -h"
}
function detailed_guide {
echo "
Example:
\$ $0 input.file output-filename
Info:
- input file may be any kind of file reconginzed by ffmpeg
Flags:
-i Path to input (string)
-o Path to output (string)
-o Path to output (string)
-o Path to output (string)
-o Path to output (string)
"
}
# Allow to be terminated with ctrl + c
trap "exit" INT
# Assert ffmpeg is installed
assert_program_exists "ffmpeg"
# Set variables and default values
typeset -i CHUNK_LEN
INPUT_PATH=''
OUTPUT_PATH=''
INCLUDE_AUDIO_STREAM=true
VERBOSE=false
PLAY_SOUND=false
HELP=false
DEINTERLACE=false
FFMPEG_IN_PARAMS=''
FFMPEG_OUT_PARAMS=''
# Grab input arguments
while getopts “i:o:dvip:q:sh” OPTION
do
case $OPTION in
i) INPUT_PATH=$(echo "$OPTARG" | sed 's/ /\\ /g' ) ;;
o) OUTPUT_PATH=$(echo "$OPTARG" | sed 's/ /\\ /g' ) ;;
d) DEINTERLACE=true ;;
v) VERBOSE=true ;;
a) INCLUDE_AUDIO_STREAM=false ;;
p) FFMPEG_IN_PARAMS="$OPTARG" ;;
q) FFMPEG_OUT_PARAMS="$OPTARG" ;;
s) PLAY_SOUND=true ;;
h) HELP=true ;;
?) usage
exit 1
;;
esac
done
if $HELP ; then
detailed_guide
exit 1
fi
if [[ -z $INPUT_PATH ]] ; then
echo "Invalid source"
usage
exit 1
fi
if [ -z "$OUTPUT_PATH" ] ; then
OUTPUT_PATH=$(fallback_output_path $INPUT_PATH)
fi
TMP_DIR=$(mktemp -dt "test")
AUDIO_PATH=${TMP_DIR}/backwards.wav
AUDIO_PARAMS=''
if $VERBOSE ; then
echo "Created empty directory $TMP_DIR"
ls -la $TMP_DIR
fi
if $DEINTERLACE ; then
ffmpeg -i $INPUT_PATH -an -qscale 1 -vf yadif $FFMPEG_IN_PARAMS ${TMP_DIR}/%06d.jpg
else
ffmpeg -i $INPUT_PATH -an -qscale 1 $FFMPEG_IN_PARAMS ${TMP_DIR}/%06d.jpg
fi
if $INCLUDE_AUDIO_STREAM ; then
assert_program_exists "sox"
ffmpeg -i $INPUT_PATH -vn -ac 2 ${TMP_DIR}/audio.wav
sox -V ${TMP_DIR}/audio.wav ${TMP_DIR}/audio_reverse.wav reverse
AUDIO_PARAMS="-i ${TMP_DIR}/audio_reverse.wav"
fi
cat $(ls -r $TMP_DIR/*jpg) | ffmpeg -f image2pipe -vcodec mjpeg -r 25 -i - -i $TMP_DIR/audio_reverse.wav $FFMPEG_OUT_PARAMS $OUTPUT_PATH
if $VERBOSE ; then
echo
echo "Will $TMP_DIR"
ls -la $TMP_DIR
fi
echo "Done!"
exit 1
rm -rf $TMP_DIR
if $PLAY_SOUND ; then
# & means async
say "Done! ." &
fi
@richardpl
Copy link

Do not use abandoned sox. ffmpeg have areverse filter already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment