Here's a Docker setup I used to help speed up FFmpeg in the containers by using different compiled binaries for each respective architecture. If someone knows of a better way to do this, or a cleaner way to do this, please let me know.
I've tested this on Ubuntu and Apple Silicon host machines.
- SO post with basic compile instructions.
- ssut repo on compiling for macOS ARM
You can also get some ARM builds from John Van Sickle's site if you don't want to compile it yourself. In the end I went with an ARM Linux pre-compiled build for the Alpine Docker container.
In your docker-compose.yml
file make sure to mount the binaries for each architecture in the container's volume
field. Make sure to do this for every container that's going to make use of the ffmpeg
commands:
volumes:
- ./ffmpeg5_x86/usr/local/bin/ffmpeg
- ./ffmpeg5_arm/usr/local/bin/ffprobe
Here's an example Dockerfile that uses an NodeJS-Alpine distro with the apk
installer:
FROM node:14-alpine3.14 as base
I needed to add g++
and make
when building my containers on an Apple Silicon machine. I'm guessing because Docker makes the containers compile x86 things to ARM, but I'm not sure:
# add cURL library
RUN apk --no-cache add curl nano g++ make exiftool
Then you just need to use uname
to check if it's 'aarch64'
, and use the ffmpeg5_x86
if it isn't:
# if aarch64 (Apple Silicon) then use ARM binary of FFmpeg
ENV BASH_PROFILE="/root/.ashrc"
RUN if [[ $(uname -m) == 'aarch64' ]]; \
then printf "\ncp /usr/local/bin/ffmpeg5_arm64 /usr/local/bin/ffmpeg" > "$BASH_PROFILE"; \
else printf "\ncp /usr/local/bin/ffmpeg5_x86 /usr/local/bin/ffmpeg" > "$BASH_PROFILE"; fi
Obviously the above commands won't work if you're running this on an ARM single-board computer or something. You'll need to check for something else, I'm not sure.
# ERROR: cp: can't stat '/usr/local/bin/ffmpeg5_arm64': No such file or directory
# RUN sh /root/.ashrc # <-- THIS DIDN'T WORK
# append the FFmpeg installation to PATH
ENV PATH="/usr/local/bin/:${PATH}"
This last RUN
command didn't work for me, and even RUN source /root/.ashrc
did nothing. After building I had to docker exec -it
into the containers and source the files manually, or use a NodeJS or Python script do it as a child process.
Here's some async NodeJS code that should run the script if the FFmpeg command doesn't work as a child process:
const util = require("util");
const exec = util.promisify(require("child_process").exec);
await exec("ffmpeg -version", { maxBuffer: 1024 * 500, 3000 })
.then((stdout, stderr) => {
if (stdout && stdout.includes("ffmpeg version")) {
} else {
console.log("FFmpeg command not valid. Need to cp binary from target build.");
exec("sh /root/.ashrc") // run the command to move the correct binary file
}
})
.catch((err) => {
console.error("exec() error =>", err);
});
After it's copied the correct target binary to the /usr/local/bin
directory the ffmpeg -version
command, from inside the container, should return something like this:
ffmpeg -version
ffmpeg version 5.0.1 Copyright (c) 2000-2022 the FFmpeg developers
built with Apple clang version 13.0.0 (clang-1300.0.29.30)
..or this is you used a pre-compiled johnvansickle build:
ffmpeg version 5.0.1-static https://johnvansickle.com/ffmpeg/ Copyright (c) 2000-2022 the FFmpeg developers
built with gcc 8 (Debian 8.3.0-6)
An output like zsh: exec format error: ...
means that the binary was not compiled for the Linux distro/container, and you'll need to find or build another one.
Here's how to install Python in your NodeJS/Alpine container:
# Install the latest version of Python 3, PIP, and make 'python' available in path
RUN apk add --update --no-cache \
python3 \
py3-pip && \
ln -sf python3 /usr/bin/python && \
alias python3=/usr/bin/python
FROM node:14-alpine3.14 as base
# Install the latest version of Python 3, PIP, and make 'python' available in path
RUN apk add --update --no-cache \
python3 \
py3-pip && \
ln -sf python3 /usr/bin/python && \
alias python3=/usr/bin/python
# add cURL library
RUN apk --no-cache add curl nano g++ make exiftool
# if aarch64 (Apple Silicon) then use ARM binary of FFmpeg
ENV BASH_PROFILE="/root/.ashrc"
RUN if [[ $(uname -m) == 'aarch64' ]]; \
then printf "\ncp /usr/local/bin/ffmpeg5_arm64 /usr/local/bin/ffmpeg" > "$BASH_PROFILE"; \
else printf "\ncp /usr/local/bin/ffmpeg5_x86 /usr/local/bin/ffmpeg" > "$BASH_PROFILE"; fi
# ERROR: cp: can't stat '/usr/local/bin/ffmpeg5_arm64': No such file or directory
# RUN sh /root/.ashrc # <-- THIS DIDN'T WORK
# append the FFmpeg installation to PATH
ENV PATH="/usr/local/bin/:${PATH}"