Created repo
|
@ -0,0 +1,3 @@
|
|||
videos
|
||||
output
|
||||
node/node_modules
|
|
@ -0,0 +1,222 @@
|
|||
---
|
||||
header-includes:
|
||||
- \hypersetup{colorlinks=true,
|
||||
allbordercolors={0 0 1},
|
||||
pdfborderstyle={/S/U/W 1}}
|
||||
---
|
||||
|
||||
# UNIX FOR ARTISTS
|
||||
### Fun with FFMPEG
|
||||
|
||||
## Requirements
|
||||
|
||||
The following applications and runtime environments are needed to run the scripts used in the workshop.
|
||||
Installation instructions are available below, broken down by operating system.
|
||||
|
||||
* [Bash](https://www.gnu.org/software/bash/) - *You probably have it already!*
|
||||
* [FFMPEG](https://www.ffmpeg.org/)
|
||||
* [ImageMagick](https://imagemagick.org/index.php)
|
||||
* [Youtube-dl](https://ytdl-org.github.io/youtube-dl/index.html)
|
||||
* [Golang](https://golang.org/)
|
||||
* \*[Python3](https://www.python.org/downloads/) (*optional*)
|
||||
* \*[Node.js](https://nodejs.org/en/) (*optional*)
|
||||
|
||||
It's very helpful to have a text editor that you can comfortably read and edit scripts in.
|
||||
This selection of text editors ranges from free and open source to "free to use" and "free to try".
|
||||
You can also use TextEdit or Notepad or any text editing application you prefer as long as it's capable of editing in plaintext.
|
||||
|
||||
* [Atom](https://atom.io/) - Free. *macOS, Windows and Linux.*
|
||||
* [GNU Emacs](https://www.gnu.org/software/emacs/download.html) - Free. *Linux, macOS and Windows.*
|
||||
* [Visual Studio Code](https://code.visualstudio.com/download) - Free. *macOS, Windows and Linux.*
|
||||
* [Sublime Text 3](https://www.sublimetext.com/3) - Free to evaluate. *macOS, Windows and Linux.*
|
||||
* [Notepad++](https://notepad-plus-plus.org/downloads/) - Free to use. *Windows only.*
|
||||
* [BBEdit](http://www.barebones.com/products/bbedit/download.html) - Freemium. *macOS only.*
|
||||
|
||||
-------
|
||||
|
||||
## macOS
|
||||
|
||||

|
||||
|
||||
Open the Terminal app located in your Applications folder.
|
||||
Bash 3.2 is available by default on macOS.
|
||||
|
||||
|
||||
##### Install Homebrew
|
||||
|
||||
Go to [https://brew.sh](https://brew.sh) and run the command under the "Install Homebrew" heading after pasting it into your Terminal.
|
||||
|
||||
You will be asked to confirm a few things while Homebrew installs.
|
||||
|
||||
Once the installation process is complete you can install the applications we will be using in this workshop by running the following commands:
|
||||
|
||||
```bash
|
||||
brew install ffmpeg imagemagick youtube-dl
|
||||
```
|
||||
|
||||
Optionally, you can install Node.js for a single example that we will be covering in the workshop.
|
||||
|
||||
```bash
|
||||
brew install node
|
||||
```
|
||||
|
||||
Make sure that you have a compatible version of Python installed by running the following command:
|
||||
|
||||
```bash
|
||||
python3 --version
|
||||
```
|
||||
|
||||
It should print out a value similar to `Python 3.8.2`.
|
||||
Anything higher than 3.7.0 will work.
|
||||
|
||||
##### Install Golang on macOS
|
||||
|
||||
Go to the [Golang download site](https://golang.org/doc/install).
|
||||
|
||||
Select the "Mac" tab under "2. Go install." if not already selected and download the .pkg installer using the "Download Go for Mac" button.
|
||||
|
||||
Open the installer and follow the instructions.
|
||||
|
||||
Confirm that Go is installed by running the following command in Terminal:
|
||||
|
||||
```bash
|
||||
go version
|
||||
```
|
||||
|
||||
If Golang has been installed correctly you can now install `primitive`.
|
||||
|
||||
```bash
|
||||
go get -u github.com/fogleman/primitive
|
||||
```
|
||||
|
||||
-------
|
||||
|
||||
## Windows 10
|
||||
|
||||
Windows has its own command-line interpreter, but in order to keep code and examples consistent across different operating systems you will need to install the Windows Subsystem for Linux (WSL).
|
||||
|
||||
##### Enable WSL
|
||||
|
||||
Open the "Turn Windows Features on or off" dialog by searching in your command bar.
|
||||
|
||||

|
||||
|
||||
Enable "Virtual Machine Platform" and "Windows Subsystem for Linux" by selecting the checkboxes next to the items and hit "OK".
|
||||
|
||||

|
||||
|
||||
Restart your computer for changes to apply.
|
||||
|
||||
|
||||
##### Install Ubuntu 20.04 LTS
|
||||
|
||||
Open the Microsoft Store and search for "Ubuntu".
|
||||
For the latest LTS version, install `Ubuntu 20.04`.
|
||||
|
||||

|
||||
|
||||
Other versions of Ubuntu or openSUSE may work, but will be subject to differences in behavior.
|
||||
|
||||

|
||||
|
||||
Once you've installed Ubuntu, you can open the shell and begin running commands using Bash.
|
||||
|
||||
|
||||
##### Install Requirements on Windows 10
|
||||
|
||||

|
||||
|
||||
You can now run the following commands to install the applications for this workshop:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y ffmpeg imagemagick youtube-dl
|
||||
```
|
||||
|
||||
Optionally install Node.js.
|
||||
|
||||
```bash
|
||||
sudo apt install -y nodejs npm
|
||||
```
|
||||
|
||||
|
||||
##### Install Golang on Windows 10
|
||||
|
||||
Go to the [Golang download site](https://golang.org/doc/install).
|
||||
|
||||
Select the "Windows" tab under "2. Go install." if not already selected and download the .msi installer by using the "Download Go for Windows" button.
|
||||
|
||||
Confirm that Go is installed by running the following command in your shell:
|
||||
|
||||
```bash
|
||||
go version
|
||||
```
|
||||
|
||||
If Golang has been installed correctly you can now install `primitive`.
|
||||
|
||||
```bash
|
||||
go get -u github.com/fogleman/primitive
|
||||
```
|
||||
|
||||
-------
|
||||
|
||||
Additional tutorials for installing Bash on Windows 10.
|
||||
|
||||
* [How to Install Linux Bash Shell on Windows 10](https://itsfoss.com/install-bash-on-windows/)
|
||||
* [Install Bash on Windows 10](https://bayton.org/docs/linux/ubuntu/install-bash-on-windows-10-build-14316/)
|
||||
|
||||
-------
|
||||
|
||||
## Linux
|
||||
|
||||
Open up your preferred terminal application and install the required applications on a Debian-based system.
|
||||
|
||||
```bash
|
||||
sudo apt install -y ffmpeg imagemagick youtube-dl
|
||||
```
|
||||
|
||||
Or, if your distribution uses the `yum` package manager.
|
||||
|
||||
```bash
|
||||
yum install ffmpeg imagemagick youtube-dl
|
||||
```
|
||||
|
||||
Optionally install Node.js.
|
||||
|
||||
```bash
|
||||
sudo apt install -y nodejs npm
|
||||
```
|
||||
Or using yum.
|
||||
|
||||
```
|
||||
yum install nodejs
|
||||
```
|
||||
|
||||
##### Install Golang on Linux
|
||||
|
||||
Go to the [Golang download site](https://golang.org/doc/install).
|
||||
|
||||
Select the "Linux" tab under "2. Go install." if not already selected and download the .tar.gz archive using the "Download Go for Linux" button.
|
||||
|
||||
Navigate to the folder you downloaded the archive into.
|
||||
For the following commands, `go1.16.3.linux-amd64.tar.gz` can be replaced by the filename of the version that you just downloaded.
|
||||
|
||||
```bash
|
||||
sudo rm -rf /usr/local/go
|
||||
sudo tar -C /usr/local -xzf go1.16.3.linux-amd64.tar.gz
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
```
|
||||
|
||||
Either restart your terminal or run the command `source $HOME/.profile` to apply the changes just made to your system.
|
||||
|
||||
Confirm that Go is installed by running the following command:
|
||||
|
||||
```bash
|
||||
go version
|
||||
```
|
||||
|
||||
If Golang has been correctly installed you can now install `primitive`.
|
||||
|
||||
```bash
|
||||
go get -u github.com/fogleman/primitive
|
||||
```
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# Arguments are provided to commands and scripts usually
|
||||
# separated by a space. They can be read and used within
|
||||
# bash scripts by referencing them with the "$#" notation.
|
||||
#
|
||||
# Usage: bash bash/arguments.sh <first> <second> <third> <etc>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
echo "You entered \"$1\" as the first argument"
|
||||
|
||||
# Using a slightly different notation
|
||||
if [ "${2}" != "" ]; then
|
||||
echo "You entered \"${2}\" as the second argument"
|
||||
fi
|
||||
|
||||
if [ "${3}" != "" ]; then
|
||||
echo "All of the arguments you entered \"${@}\""
|
||||
fi
|
|
@ -0,0 +1,28 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# "cat" is an application that prints text files
|
||||
# into your terminal and allows you to concatinate
|
||||
# multiple files together.
|
||||
#
|
||||
# Usage: bash bash/cat.sh
|
||||
#
|
||||
#####################################################
|
||||
|
||||
cat "text/cat1.txt"
|
||||
|
||||
sleep 2
|
||||
|
||||
# Concatinate multiple files and print the result
|
||||
cat "text/cat2.txt" "text/cat3.txt"
|
||||
|
||||
sleep 2
|
||||
|
||||
# Concatinate all files into a new file using the ">" redirect operator
|
||||
cat "text/cat1.txt" "text/cat2.txt" "text/cat3.txt" > "text/all.txt"
|
||||
|
||||
sleep 2
|
||||
|
||||
# Print the contents of this file
|
||||
cat bash/cat.sh
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# Functions can be defined using the "name () {}"
|
||||
# notation where the code is contained within the
|
||||
# brackets. Functions receive arguments the same way
|
||||
# a script does, using the "$#" notation.
|
||||
#
|
||||
#####################################################
|
||||
|
||||
myFunction () {
|
||||
if [ "${1}" != "" ]; then
|
||||
echo "Your first argument is \"${1}\""
|
||||
else
|
||||
echo "Called myFunction with no arguments"
|
||||
fi
|
||||
}
|
||||
|
||||
# Invoke your function as if it were any other command
|
||||
# or application located in your $PATH.
|
||||
myFunction
|
||||
|
||||
sleep 2
|
||||
|
||||
myFunction "First argument"
|
|
@ -0,0 +1,72 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# If/else statements allow you to run select commands
|
||||
# if conditions are met or if they are not.
|
||||
#
|
||||
# Usage: bash bash/ifelse.sh
|
||||
#
|
||||
#####################################################
|
||||
|
||||
NUMBER=3
|
||||
COMPARE="Compare this string"
|
||||
SUBSTRING="not"
|
||||
SUBSTRING2="this"
|
||||
|
||||
# Evaluate whether two numbers are equal with the "-eq" operator
|
||||
if [ ${NUMBER} -eq 3 ]; then
|
||||
echo "Variable \$NUMBER is equal to 3"
|
||||
else
|
||||
echo "Variable \$NUMBER is NOT equal to 3"
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
|
||||
# Evaluate whether a string contains substrings. Uses the
|
||||
# "elif" operator to check if a second condition is met if
|
||||
# the first one fails.
|
||||
if [[ "${COMPARE}" == *"${SUBSTRING}"* ]]; then
|
||||
echo "String \$COMPARE contains substring \"${SUBSTRING}\""
|
||||
elif [[ "${COMPARE}" == *"${SUBSTRING2}"* ]]; then
|
||||
echo "String \$COMPARE contains substring \"${SUBSTRING2}\""
|
||||
else
|
||||
echo "String \$COMPARE contains none of the substrings"
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
|
||||
# Evaluate whether a file exists with the "-f" operator
|
||||
if [ -f "text/cat1.txt" ]; then
|
||||
echo "File text/cat1.txt exists. Here are the contents:"
|
||||
cat text/cat1.txt
|
||||
else
|
||||
echo "File text/cat1.txt does NOT exist"
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
|
||||
# Evaluate whether a directory exists with the "-d" operator
|
||||
if [ -d "not_here" ]; then
|
||||
echo "Directory not_here exists. Here are the contents:"
|
||||
ls not_here
|
||||
else
|
||||
echo "Directory not_here does NOT exist"
|
||||
fi
|
||||
|
||||
# Evaluate whether or not one condition OR another
|
||||
# is met using the "||" operators.
|
||||
# The "-gt" operator determines if a number is
|
||||
# greater than a compared number and "-lt" for
|
||||
# less than.
|
||||
if [ $NUMBER -gt 1 ] || [ $NUMBER -lt 5]; then
|
||||
echo "Variable \$NUMBER is greater than 1 or less than 5"
|
||||
fi
|
||||
|
||||
# Evaluate whether both conditions are met using
|
||||
# the AND operator "&&"
|
||||
if [[ "${COMPARE}" == *"${SUBSTRING}"* ]] && [[ "${COMPARE}" == *"${SUBSTRING2}"* ]]; then
|
||||
echo "String \$COMPARE contains both substrings"
|
||||
else
|
||||
echo "String \$COMPARE does not contain both substrings"
|
||||
fi
|
|
@ -0,0 +1,50 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# The commands "cd",
|
||||
#
|
||||
# Usage: bash bash/paths.sh
|
||||
#
|
||||
#####################################################
|
||||
|
||||
THIS_DIRECTORY=`pwd`
|
||||
echo "${THIS_DIRECTORY}"
|
||||
|
||||
sleep 2
|
||||
|
||||
# Go to your "home" directory for your user
|
||||
cd ~/
|
||||
echo "You are now in:"
|
||||
pwd
|
||||
|
||||
sleep 2
|
||||
|
||||
# Go to the root of your filesystem
|
||||
cd /
|
||||
echo "You are now in:"
|
||||
pwd
|
||||
|
||||
sleep 2
|
||||
# List all files and directories in "long" and "readable" format
|
||||
ls -lh
|
||||
|
||||
sleep 10
|
||||
|
||||
# Return to the directory you started in
|
||||
cd "${THIS_DIRECTORY}"
|
||||
echo "You are now back in:"
|
||||
pwd
|
||||
|
||||
sleep 2
|
||||
|
||||
# Go into the "bash" sub-directory
|
||||
cd bash
|
||||
echo "You are now in:"
|
||||
pwd
|
||||
|
||||
# Return to the parent directory, the one you started in,
|
||||
# by using the double period ".." notation
|
||||
cd ../
|
||||
echo "You are now back in:"
|
||||
pwd
|
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# Variables are stored values that can be set locally
|
||||
# in the script or inherited from your environment.
|
||||
#
|
||||
# Usage: bash bash/variables.sh
|
||||
#
|
||||
#####################################################
|
||||
|
||||
# Set this variable to run the script
|
||||
VARIABLE=""
|
||||
NUMBER=3
|
||||
|
||||
# Save output of the command "pwd" to a variable
|
||||
# by running it in a subshell
|
||||
CURRENT_DIR=`pwd`
|
||||
|
||||
# A different notation for subshells, this time
|
||||
# saving the contents of a text file to a variable
|
||||
FILE=$(cat text/cat1.txt)
|
||||
|
||||
if [ "${VARIABLE}" != "" ]; then
|
||||
echo "Your variable: ${VARIABLE}"
|
||||
echo "Your number: ${NUMBER}"
|
||||
echo "Your current dir: ${CURRENT_DIR}"
|
||||
# $PATH is an environment variable set by your system
|
||||
echo "Your username: ${USER}"
|
||||
echo "Your system \$PATH: ${PATH}"
|
||||
else
|
||||
echo "Please create within the quotes on line 13"
|
||||
fi
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
VIDEOS=(
|
||||
bear.mkv
|
||||
bird.mkv
|
||||
flower.mkv
|
||||
ice.mkv
|
||||
metamorphosis.mkv
|
||||
negative.mkv
|
||||
net.mkv
|
||||
pig.mkv
|
||||
stream.mkv
|
||||
surface.mkv
|
||||
water.mkv
|
||||
)
|
||||
|
||||
mkdir -p videos
|
||||
mkdir -p output
|
||||
|
||||
for video in ${VIDEOS[@]}; do
|
||||
curl "https://sixteenmillimeter.com/unix4artists/${video}" -o "videos/${video}"
|
||||
sleep 2
|
||||
done
|
|
@ -0,0 +1,28 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will combine the audio from one file and the
|
||||
# video from another file.
|
||||
#
|
||||
# Usage: bash ffmpeg/audio/audiovideo.sh <input audio> <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
AUDIO="${1}"
|
||||
VIDEO="${2}"
|
||||
OUTPUT="${3}"
|
||||
|
||||
# Check if output file extension is .mkv
|
||||
if [[ "${OUTPUT}" != *".mkv" ]]; then
|
||||
echo "Please use an .mkv extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ffmpeg -i "${VIDEO}" \
|
||||
-i "${AUDIO}" \
|
||||
-c copy \
|
||||
-map 0:v:0 \
|
||||
-map 1:a:0 \
|
||||
-shortest \
|
||||
"${OUTPUT}"
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will extract the audio from a video
|
||||
# losslessly into a .wav file.
|
||||
#
|
||||
# Usage: bash ffmpeg/audio/extract.sh <input video> <output audio>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if output file extension is .wav
|
||||
if [[ "${OUTPUT}" != *".wav" ]]; then
|
||||
echo "Please use an .wav extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ffmpeg -i "${INPUT}" -vn "${OUTPUT}"
|
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will take an audio file and an image and
|
||||
# combine them to create a video.
|
||||
#
|
||||
# Usage: bash ffmpeg/audio/stillaudio.sh <input audio> <input image> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
AUDIO="${1}"
|
||||
IMAGE="${2}"
|
||||
OUTPUT="${3}"
|
||||
|
||||
# Check if file extension is .mkv or .MKV
|
||||
if [[ "${OUTPUT}" != *".mkv" ]]; then
|
||||
echo "Please use an .mkv extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ffmpeg -loop 1 \
|
||||
-framerate 2 \
|
||||
-i "${IMAGE}" \
|
||||
-i "${AUDIO}" \
|
||||
-c:v libx264 \
|
||||
-preset slow \
|
||||
-tune stillimage \
|
||||
-pix_fmt yuv420p \
|
||||
-crf 12 \
|
||||
-vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:-1:-1:color=black" \
|
||||
-c:a aac \
|
||||
-b:a 192k \
|
||||
-shortest \
|
||||
"${OUTPUT}"
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# "ffprobe" is an application that comes bundled with
|
||||
# the ffmpeg installation. It will print file
|
||||
# information about the streams within video and audio
|
||||
# files.
|
||||
#
|
||||
# Usage: bash ffmpeg/basic/info.sh <file>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
if [ "${1}" == "" ]; then
|
||||
echo "Please include a path to a file as the first argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${2}" != "json" ]; then
|
||||
ffprobe -v quiet -show_format -show_streams "${1}"
|
||||
else
|
||||
ffprobe -v quiet -print_format json -show_format -show_streams "${1}"
|
||||
fi
|
|
@ -0,0 +1,55 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This command will re-encode a video into an MOV
|
||||
# container with a ProRes HQ (422) video stream and
|
||||
# audio preserved in its original format.
|
||||
#
|
||||
# -i "${INPUT}"
|
||||
# Sets the first argument, saved as variable "$INPUT"
|
||||
# as the input file that ffmpeg will re-encode. Must
|
||||
# go at the beginning of your command.
|
||||
#
|
||||
# -c:v prores_ks
|
||||
# Sets the video codec of the output video to be ProRes
|
||||
# using the "prores_kostya" library.
|
||||
#
|
||||
# -profile:v 3
|
||||
# Sets the ProRes profile to 3 or "HQ" use on the output
|
||||
# video stream. The profiles available: 0 = proxy (PR),
|
||||
# 1 = light (LT), 2 = standard (ST), 3 = high quality (HQ),
|
||||
# 4 = 4444, 5 = 4444 (XQ)
|
||||
#
|
||||
# -c:a copy
|
||||
# Copies the audio stream and preserves the format
|
||||
# and codec from the original file.
|
||||
#
|
||||
# "${OUTPUT}"
|
||||
# The output video file, which should be the last
|
||||
# argument you provide.
|
||||
#
|
||||
# More info: https://avpres.net/FFmpeg/im_ProRes.html
|
||||
# https://codecs.multimedia.cx/2012/03/a-few-words-about-my-prores-encoder/
|
||||
#
|
||||
# Usage: bash ffmpeg/basic/prores.sh <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if input and output arguments are supplied
|
||||
if [ "${INPUT}" == "" ] || [ "${OUTPUT}" == "" ]; then
|
||||
echo "Please provide input and output files as your first and second arguments"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Command to re-encode the input video into ProRes
|
||||
ffmpeg -i "${INPUT}" -c:v prores_ks -profile:v 3 -c:a copy "${OUTPUT}"
|
|
@ -0,0 +1,61 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This command will re-encode a video into an MP4
|
||||
# container with H264 video and AAC audio encoded to
|
||||
# 96K. Each of the arguments are explained as follows:
|
||||
#
|
||||
# -i "${INPUT}"
|
||||
# Sets the first argument, saved as variable "$INPUT"
|
||||
# as the input file that ffmpeg will re-encode. Must
|
||||
# go at the beginning of your command.
|
||||
#
|
||||
# -codec:video libx264
|
||||
# Sets the video codec to libx264, which is the library
|
||||
# ffmpeg uses to encode H264 video streams.
|
||||
#
|
||||
# -preset slow
|
||||
# Sets the preset of the H264 encoding process to run
|
||||
# slow, which can yield higher quality imagery at the
|
||||
# expense of speed. Available options:
|
||||
# ultrafast, superfast, veryfast, faster, medium (default),
|
||||
# slow, slower, veryslow, placebo
|
||||
#
|
||||
# -crf 22
|
||||
# Sets the Constant Rate Factor of the video stream,
|
||||
# which determines the data rate. The range of -crf
|
||||
# values range from 0 to 51, with 0 being visually
|
||||
# lossless and 51 being extremely compressed.
|
||||
#
|
||||
# -codec:audio aac
|
||||
# Sets the codec of the output audio stream to AAC.
|
||||
#
|
||||
# -b:a
|
||||
# Sets the data rate of the audio to 192kbit/s.
|
||||
#
|
||||
# "${OUTPUT}"
|
||||
# The output video file, which should be the last
|
||||
# argument you provide.
|
||||
#
|
||||
# Usage: bash ffmpeg/basic/reencode.sh <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if input and output arguments are supplied
|
||||
if [ "${INPUT}" == "" ] || [ "${OUTPUT}" == "" ]; then
|
||||
echo "Please provide input and output files as your first and second arguments"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if file extension is .mp4
|
||||
if [[ "${OUTPUT}" != *".mp4" ]]; then
|
||||
echo "Please use an .mp4 extension on your output file argument"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Command to re-encode the input video into H264/AAC
|
||||
ffmpeg -i "${INPUT}" -codec:video libx264 -preset slow -crf 22 -codec:audio aac -bitrate:audio 192k "${OUTPUT}"
|
|
@ -0,0 +1,74 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# Youtube: https://trac.ffmpeg.org/wiki/Encode/YouTube
|
||||
# Vimeo: https://vimeo.zendesk.com/hc/en-us/articles/360056550451-Video-and-audio-compression-guidelines
|
||||
#
|
||||
# Usage: bash ffmpeg/basic/social.sh <input video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT=`realpath "${1}"`
|
||||
FILENAME=`basename "${INPUT}"`
|
||||
FILE="${FILENAME%.*}"
|
||||
INPUTDIR=`dirname "${INPUT}"`
|
||||
|
||||
if [ "${INPUT}" == "" ]; then
|
||||
echo "Please provide an input video as your first argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
YOUTUBE="${INPUTDIR}/${FILE}-youtube.mkv"
|
||||
VIMEO="${INPUTDIR}/${FILE}-vimeo.mkv"
|
||||
TWITTER="${INPUTDIR}/${FILE}-twitter.mp4"
|
||||
INSTAGRAM="${INPUTDIR}/${FILE}-instagram.mp4"
|
||||
|
||||
# Encode a video for YouTube
|
||||
ffmpeg -i "${INPUT}" \
|
||||
-vcodec libx264 \
|
||||
-preset slow \
|
||||
-vf "pad=ceil(iw/2)*2:ceil(ih/2)*2" \
|
||||
-pix_fmt yuv420p \
|
||||
-crf 12 \
|
||||
-c:a aac \
|
||||
-b:a 192k \
|
||||
"${YOUTUBE}"
|
||||
|
||||
# Encode a video for Vimeo using the
|
||||
# recommended settings for 720p video
|
||||
ffmpeg -i "${INPUT}" \
|
||||
-vcodec libx264 \
|
||||
-preset slow \
|
||||
-pix_fmt yuv420p \
|
||||
-profile:v main \
|
||||
-b:v 7500k \
|
||||
-minrate 5000k \
|
||||
-maxrate 10000k \
|
||||
-c:a aac \
|
||||
-ar 48000 \
|
||||
"${VIMEO}"
|
||||
|
||||
# Encode video for Twitter
|
||||
ffmpeg -i "${INPUT}" \
|
||||
-pix_fmt yuv420p \
|
||||
-vcodec libx264 \
|
||||
-acodec aac \
|
||||
-vb 2048k\
|
||||
-minrate 1024k \
|
||||
-maxrate 4096k \
|
||||
-bufsize 1024k \
|
||||
-ar 44100 \
|
||||
-ac 2 \
|
||||
-strict experimental \
|
||||
"${TWITTER}"
|
||||
|
||||
# Crop and encode for Instagram
|
||||
ffmpeg -i "${INPUT}" \
|
||||
-vf "crop=w='min(iw\,ih)':h='min(iw\,ih)',setsar=1" \
|
||||
-framerate 30 \
|
||||
-vcodec mpeg4 \
|
||||
-vb 8000k \
|
||||
-strict experimental \
|
||||
-q:v 0 \
|
||||
"${INSTAGRAM}"
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# These commands print out the formats and codecs that
|
||||
# your installation of ffmpeg supports. You can customize
|
||||
# ffmpeg to support additional formats, codecs and features
|
||||
# by using installation options or flags when compiling
|
||||
# from source.
|
||||
#
|
||||
# Mac (Homebrew): https://gist.github.com/Piasy/b5dfd5c048eb69d1b91719988c0325d8
|
||||
# Linux & Windows: https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu
|
||||
#
|
||||
# Usage: bash ffmpeg/format/support.sh
|
||||
#
|
||||
#####################################################
|
||||
|
||||
echo "Formats your FFMPEG install supports:"
|
||||
ffmpeg -formats
|
||||
|
||||
sleep 10
|
||||
|
||||
echo "Codecs your FFMPEG install supports:"
|
||||
ffmpeg -codecs
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will trim your video to a 5 second length
|
||||
# starting 2 seconds into it and write the output as a
|
||||
# ProRes video file.
|
||||
#
|
||||
# Usage: bash ffmpeg/basic/trim.sh <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Trim the video using the "-t" argument with the value 5 (seconds)
|
||||
# and starting at 00:00:02 (h:m:s) using the "-ss" seeking argument
|
||||
ffmpeg -ss 00:00:02 -i "${INPUT}" -t 5 -c:v prores_ks -profile:v 3 -c:a copy "${OUTPUT}"
|
|
@ -0,0 +1,41 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# Bipack.sh will simulate the optical printing effect
|
||||
# of superimposing video A over video B with a third
|
||||
# video (the matte) as the alpha layer.
|
||||
#
|
||||
# Usage: bash ffmpeg/filter/bipack.sh <input video A> <input video B> <input video matte> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
A=${1}
|
||||
B=${2}
|
||||
MATTE=${3}
|
||||
OUTPUT_FILE=${4}
|
||||
|
||||
CONTRAST=100
|
||||
W=1280
|
||||
H=720
|
||||
RATE=24
|
||||
|
||||
echo "Running bipack on image sources ${A} and ${B} with ${MATTE} as the matte layer..."
|
||||
|
||||
time ffmpeg -y -i $A -i $B -i $MATTE \
|
||||
-filter_complex "
|
||||
color=0x000000:size=${W}x${H}, format=rgb24[bla];
|
||||
[0] fps=${RATE},scale=${W}:${H}:force_original_aspect_ratio=decrease,format=rgb24 [a];
|
||||
[1] fps=${RATE},scale=${W}:${H}:force_original_aspect_ratio=decrease,format=rgb24 [b];
|
||||
[2] fps=${RATE},scale=${W}:${H}:force_original_aspect_ratio=decrease,format=gray,
|
||||
smartblur=1, eq=contrast=$CONTRAST, format=rgb24 [maska];
|
||||
[2] fps=${RATE},scale=${W}:${H}:force_original_aspect_ratio=decrease,format=gray,
|
||||
smartblur=1, eq=contrast=$CONTRAST, negate, format=rgb24 [maskb];
|
||||
[bla][a][maska] maskedmerge, format=rgb24 [pass1];
|
||||
[pass1][b][maskb] maskedmerge, format=rgb24
|
||||
" \
|
||||
-r $RATE \
|
||||
-c:v prores_ks \
|
||||
-profile:v 3 \
|
||||
-shortest \
|
||||
$OUTPUT_FILE
|
|
@ -0,0 +1,58 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
W=1280
|
||||
H=720
|
||||
|
||||
A=${1}
|
||||
B=${2}
|
||||
MATTE=${3}
|
||||
OUTPUT=${4}
|
||||
|
||||
MATTE1=matte1.mov
|
||||
MATTE2=matte2.mov
|
||||
PASS1=pass1.mov
|
||||
PASS2=pass2.mov
|
||||
|
||||
echo "Generating mattes from $MATTE..."
|
||||
|
||||
ffmpeg -y -i "$MATTE" -vf eq=saturation=0:contrast=100,smartblur=1 -c:v prores_ks -profile:v 4 "$MATTE1"
|
||||
ffmpeg -y -i "$MATTE1" -vf negate -c:v prores_ks -profile:v 4 "$MATTE2"
|
||||
|
||||
echo "Applying matte to $A..."
|
||||
|
||||
ffmpeg -y -i "$A" -i "$MATTE1" \
|
||||
-filter_complex 'color=0x000000:size=1280x720,format=rgb24[bla];[bla][0][1]maskedmerge' \
|
||||
-c:v prores_ks \
|
||||
-profile:v 4 \
|
||||
-shortest \
|
||||
"$PASS1"
|
||||
|
||||
echo "Applying matte to $B..."
|
||||
|
||||
ffmpeg -y -i "$B" -i "$MATTE2" \
|
||||
-filter_complex 'color=0x000000:size=1280x720,format=rgb24[bla];[bla][0][1]maskedmerge' \
|
||||
-c:v prores_ks \
|
||||
-profile:v 4 \
|
||||
-shortest \
|
||||
"$PASS2"
|
||||
|
||||
echo "Cleaning up tmp matte files..."
|
||||
|
||||
rm "$MATTE1"
|
||||
rm "$MATTE2"
|
||||
|
||||
echo "Combining matted layers together into $OUTPUT_FILE..."
|
||||
|
||||
ffmpeg -y -i "$PASS1" -i "$PASS2" \
|
||||
-filter_complex "[0][1]blend=all_mode='lighten'" \
|
||||
-c:v prores_ks \
|
||||
-profile:v 3 \
|
||||
-shortest \
|
||||
"$OUTPUT"
|
||||
|
||||
echo "Cleaning up temp files..."
|
||||
|
||||
rm "$PASS1"
|
||||
rm "$PASS2"
|
|
@ -0,0 +1,27 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will increase the contrast of an input
|
||||
# video by 2 (acceptable values -1000 to 1000) and
|
||||
# increases the brightness by 0.4 (-1 to 1)
|
||||
#
|
||||
# Usage: bash ffmpeg/filter/brightness.sh <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ffmpeg -i "${INPUT}" \
|
||||
-vf eq=contrast=2:brightness=0.4 \
|
||||
-c:v prores_ks \
|
||||
-profile:v 3 \
|
||||
"${OUTPUT}"
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will convert a color video to black &
|
||||
# white by reducing color saturation to 0.
|
||||
#
|
||||
# Usage: bash ffmpeg/filter/desaturate.sh <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ffmpeg -i "${INPUT}" \
|
||||
-vf hue=s=0 \
|
||||
-c:v prores_ks \
|
||||
-profile:v 3 \
|
||||
"${OUTPUT}"
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will convert a color video to black &
|
||||
# white by converting to grayscale format.
|
||||
#
|
||||
# Usage: bash ffmpeg/filter/grayscale.sh <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ffmpeg -i "${INPUT}" \
|
||||
-vf format=gray \
|
||||
-c:v prores_ks \
|
||||
-profile:v 3 \
|
||||
"${OUTPUT}"
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will invert all colors of a video and
|
||||
# save the output in a ProRes video.
|
||||
#
|
||||
# Usage: bash ffmpeg/filter/negative.sh <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ffmpeg -i "${INPUT}" \
|
||||
-vf negate \
|
||||
-c:v prores_ks \
|
||||
-profile:v 3 \
|
||||
"${OUTPUT}"
|
|
@ -0,0 +1,98 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will create a 10 second title and
|
||||
# overlay it on a video with a blend mode:
|
||||
#
|
||||
# addition
|
||||
# grainmerge
|
||||
# and
|
||||
# average
|
||||
# darken
|
||||
# difference
|
||||
# grainextract
|
||||
# divide
|
||||
# dodge
|
||||
# freeze
|
||||
# exlusion
|
||||
# extremity
|
||||
# glow
|
||||
# hardlight
|
||||
# hardmix
|
||||
# heat
|
||||
# lighten
|
||||
# linearlight
|
||||
# multiply
|
||||
# multiply128
|
||||
# negation
|
||||
# normal
|
||||
# or
|
||||
# overlay
|
||||
# pheonix
|
||||
# pinlight
|
||||
# reflect
|
||||
# screen
|
||||
# softlight
|
||||
# subtract
|
||||
# vividlight
|
||||
# xor
|
||||
#
|
||||
# Usage: bash ffmpeg/filter/title.sh <title text> <input video> <output video> <blendmode> "invert" (optional)
|
||||
#
|
||||
#####################################################
|
||||
|
||||
|
||||
W=720
|
||||
H=480
|
||||
|
||||
TEXT="${1}"
|
||||
INPUT="${2}"
|
||||
OUTPUT="${3}"
|
||||
BLENDMODE="${4}"
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${BLENDMODE}" == "" ]; then
|
||||
BLENDMODE="multiply"
|
||||
fi
|
||||
|
||||
if [ "${5}" == "invert" ]; then
|
||||
convert -size ${W}x${H} \
|
||||
-background white \
|
||||
-fill black \
|
||||
-gravity Center \
|
||||
-weight 700 \
|
||||
-pointsize 100 \
|
||||
label:"${TEXT}" \
|
||||
title.png
|
||||
else
|
||||
convert -size ${W}x${H} \
|
||||
-background black \
|
||||
-fill white \
|
||||
-gravity Center \
|
||||
-weight 700 \
|
||||
-pointsize 100 \
|
||||
label:"${TEXT}" \
|
||||
title.png
|
||||
fi
|
||||
|
||||
ffmpeg -y -loop 1 \
|
||||
-framerate 24 \
|
||||
-f image2 \
|
||||
-i title.png \
|
||||
-s ${W}x${H} \
|
||||
-c:v prores_ks \
|
||||
-profile:v 3 \
|
||||
-t 10 \
|
||||
"title.mov"
|
||||
|
||||
ffmpeg -i "${INPUT}" -i "title.mov" -filter_complex "[0][1]blend=${BLENDMODE}" "${OUTPUT}"
|
||||
|
||||
# Clean up by removing the image and title video
|
||||
rm title.png
|
||||
rm title.mov
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script splits a video into an image sequence
|
||||
# and then stitches the image sequence back into a
|
||||
# ProRes video.
|
||||
#
|
||||
# Usage: bash ffmpeg/frames/basic.sh <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p frames
|
||||
|
||||
ffmpeg -i "${INPUT}" frames/frame-%06d.png
|
||||
|
||||
sleep 20
|
||||
|
||||
ffmpeg -f image2 -i frames/frame-%06d.png -c:v prores_ks -profile:v 3 "${OUTPUT}"
|
||||
|
||||
rm -rf frames
|
|
@ -0,0 +1,41 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# Frameloom is a script that exports all frames from
|
||||
# two videos and alternates them in
|
||||
#
|
||||
# Usage: bash ffmpeg/frames/frameloom.sh <input video1> <input video2> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
TMPDIR=`mktemp -d`
|
||||
i=0
|
||||
|
||||
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] ;
|
||||
then
|
||||
echo "Not enough arguments supplied"
|
||||
fi
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${3}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p $TMPDIR
|
||||
|
||||
ffmpeg -i "$1" -compression_algo raw -pix_fmt rgb24 "${TMPDIR}export-%08d_a.tif"
|
||||
ffmpeg -i "$2" -compression_algo raw -pix_fmt rgb24 "${TMPDIR}export-%08d_b.tif"
|
||||
|
||||
#rm -r $TMP
|
||||
|
||||
for filename in ${TMPDIR}*.tif; do
|
||||
value=`printf %08d $i`
|
||||
mv "$filename" "${TMPDIR}render_${value}.tif"
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
|
||||
ffmpeg -r 24 -f image2 -s 1280x720 -i "${TMPDIR}render_%08d.tif" -c:v prores_ks -profile:v 3 -y "$3"
|
||||
|
||||
rm -r "$TMPDIR"
|
|
@ -0,0 +1,39 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script exports all frames of your video into
|
||||
# a directory named "frames" and then runs a convert
|
||||
# command which does edge detection on each frame.
|
||||
# Then all frames are stitched back into a ProRes
|
||||
# video.
|
||||
#
|
||||
# Usage: bash ffmpeg/frames/loop.sh <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p frames
|
||||
|
||||
ffmpeg -i "${INPUT}" frames/frame-%06d.png
|
||||
|
||||
FRAMES=frames/*.png
|
||||
|
||||
for frame in ${FRAMES}; do
|
||||
echo "Running edge detection on $frame..."
|
||||
convert "${frame}" -edge 1 "${frame}"
|
||||
done
|
||||
|
||||
sleep 10
|
||||
|
||||
ffmpeg -f image2 -i frames/frame-%06d.png -c:v prores_ks -profile:v 3 "${OUTPUT}"
|
||||
|
||||
rm -rf frames
|
|
@ -0,0 +1,53 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will export your video to frames and
|
||||
# use the application "primitive" to reproduce the
|
||||
# image with polygonal primitive shapes. Then the
|
||||
# converted frames are p
|
||||
#
|
||||
# The modes available for the -m argument are:
|
||||
# 0=combo
|
||||
# 1=triangle
|
||||
# 2=rect
|
||||
# 3=ellipse
|
||||
# 4=circle
|
||||
# 5=rotatedrect
|
||||
# 6=beziers
|
||||
# 7=rotatedellipse
|
||||
# 8=polygon
|
||||
#
|
||||
# primitive repo : https://github.com/fogleman/primitive
|
||||
#
|
||||
# Usage: bash ffmpeg/frames/primitive.sh <input video> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
INPUT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
MODE=1
|
||||
NUMBER=100
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p frames
|
||||
|
||||
ffmpeg -i "${INPUT}" frames/frame-%06d.png
|
||||
|
||||
FRAMES=frames/*.png
|
||||
|
||||
for frame in ${FRAMES}; do
|
||||
echo "Processing $frame with primitive..."
|
||||
# Run the "primitive" application on every frame
|
||||
primitive -i "${frame}" -o "${frame}" -n 200 -m 4
|
||||
done
|
||||
|
||||
ffmpeg -f image2 -i frames/frame-%06d.png -c:v prores_ks -profile:v 3 "${OUTPUT}"
|
||||
|
||||
rm -rf frames
|
|
@ -0,0 +1,42 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# This script will create a 15 second title with a
|
||||
# 5 second fade in and a 5 second fade out
|
||||
#
|
||||
# Usage: bash im/title.sh <title text> <output video>
|
||||
#
|
||||
#####################################################
|
||||
|
||||
TEXT="${1}"
|
||||
OUTPUT="${2}"
|
||||
|
||||
# Check if output file extension is .mov
|
||||
if [[ "${OUTPUT}" != *".mov" ]]; then
|
||||
echo "Please use an .mov extension on your output file argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
convert -size 1280x720 \
|
||||
-background black \
|
||||
-fill white \
|
||||
-gravity Center \
|
||||
-weight 700 \
|
||||
-pointsize 200 \
|
||||
label:"${TEXT}" \
|
||||
title.png
|
||||
|
||||
ffmpeg -loop 1 \
|
||||
-framerate 24 \
|
||||
-f image2 \
|
||||
-i title.png \
|
||||
-s 1280x720 \
|
||||
-vf "fade=t=in:st=0:d=5,fade=t=out:st=10:d=5" \
|
||||
-c:v prores_ks \
|
||||
-profile:v 3 \
|
||||
-t 15 \
|
||||
"${OUTPUT}"
|
||||
|
||||
# Clean up by removing the image
|
||||
rm title.png
|
After Width: | Height: | Size: 792 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 309 KiB |
After Width: | Height: | Size: 160 KiB |
After Width: | Height: | Size: 308 KiB |
After Width: | Height: | Size: 280 KiB |
After Width: | Height: | Size: 538 KiB |
After Width: | Height: | Size: 227 KiB |
After Width: | Height: | Size: 139 KiB |
|
@ -0,0 +1,84 @@
|
|||
'use strict';
|
||||
|
||||
const PORT = typeof process.env.PORT !== 'undefined' ? parseInt(process.env.PORT) : 3000;
|
||||
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const app = express();
|
||||
|
||||
const HOME = `<html>
|
||||
<head><title>FFMPEG demo</title></head>
|
||||
<body>
|
||||
<form method="POST">
|
||||
<input name="title" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const VIDEO = `<html>
|
||||
<head><title>FFMPEG demo</title></head>
|
||||
<body>
|
||||
<video controls autoplay>
|
||||
<source src="/title.mp4" type="video/mp4" />
|
||||
</video>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
function generateTitle (text) {
|
||||
const title = `convert \
|
||||
-size 720x480 \
|
||||
-background black \
|
||||
-fill white \
|
||||
-gravity Center \
|
||||
-weight 700 \
|
||||
-pointsize 100 \
|
||||
label:"${text}" \
|
||||
title.png`;
|
||||
|
||||
const ffmpeg = `ffmpeg -y \
|
||||
-loop 1 \
|
||||
-framerate 24 \
|
||||
-f image2 \
|
||||
-i title.png \
|
||||
-s 720x480 \
|
||||
-vf "fade=t=in:st=0:d=5,fade=t=out:st=10:d=5" \
|
||||
-c:v libx264 \
|
||||
-preset slow \
|
||||
-crf 22 \
|
||||
-f mp4 \
|
||||
-strict -2 \
|
||||
-pix_fmt yuv420p \
|
||||
-t 15 \
|
||||
-an \
|
||||
title.mp4`;
|
||||
|
||||
const cleanup = `rm title.png`;
|
||||
|
||||
execSync(title);
|
||||
execSync(ffmpeg);
|
||||
execSync(cleanup);
|
||||
}
|
||||
|
||||
app.use(express.static('./'));
|
||||
app.use(bodyParser.urlencoded({ extended : true }));
|
||||
|
||||
app.get('/', (req, res, next) => {
|
||||
res.end(HOME);
|
||||
return next();
|
||||
});
|
||||
|
||||
app.post('/', (req, res, next) => {
|
||||
|
||||
generateTitle(req.body.title);
|
||||
|
||||
res.end(VIDEO);
|
||||
return next();
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running on port ${PORT}`);
|
||||
execSync('rm -f title.mp4');
|
||||
});
|
|
@ -0,0 +1,860 @@
|
|||
{
|
||||
"name": "ffmpeg-demo",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ffmpeg-demo",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
"express": "^4.17.1"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
|
||||
"dependencies": {
|
||||
"mime-types": "~2.1.24",
|
||||
"negotiator": "0.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.19.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
|
||||
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.0",
|
||||
"content-type": "~1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.2",
|
||||
"http-errors": "1.7.2",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "~2.3.0",
|
||||
"qs": "6.7.0",
|
||||
"raw-body": "2.4.0",
|
||||
"type-is": "~1.6.17"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||