Skip to content

Instantly share code, notes, and snippets.

@aadm
Last active February 22, 2018 20:40
Show Gist options
  • Save aadm/1ccecda7eece16024f7220b0886feef2 to your computer and use it in GitHub Desktop.
Save aadm/1ccecda7eece16024f7220b0886feef2 to your computer and use it in GitHub Desktop.
Jefferey's ffmpeg recipe.

This is a little help given to Jefferey, co-host of the OTP podcast which I follow since its beginning. Yesterday he sent out a tweet asking for help on something that I knew it could be solved with the power of open source. I hope everything is clear and work as intended. If it does, I'd like for Jefferey to check my suggestions for italian photographers to be featured on OTP! (aadm 22-Feb-2018)

get ffmpeg

First step, get ffmpeg on your Mac.

I recommend brew but other options exist. If you don't have brew, then install this one first (it's a powerful package manager to get all sort of cool open source, unix-like apps on Mac). Instructions are on the website or simply input this at the terminal:

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Once you have brew, install ffmpeg:

$ brew install ffmpeg

how to do it for 1 image+1 audio

Suppose you have one image and one audio file, this is the way to combine them into a video:

$ ffmpeg -loop 1 -i TEST.jpg -i TEST.m4a -c:v libx264 -tune stillimage -c:a copy -pix_fmt yuv420p -shortest TEST.mp4

I am assuming that the image is already in full-HD dimensions (1920x1080). You can also rescale and crop as you want using ffmpeg however (e.g., using the option -vf scale=720:480)

The option -c:a copy makes it for a faster encoding, because it's not re-encoding the audio. The video is encoded in standard H264 format and obviously there are countless options to fine tune the resulting video, just check the docs.

The output option -shortest is essential to keep the final movie duration equal to the input audio file duration (otherwise the encoding never stops because it loops on itself).

My input image and audio files are respectively 1.4 and 8 Mb and the resulting video is 31 Mb. By setting 1 fps with the option -r 1 both in input and output I get a much smaller video (12 Mb):

$ ffmpeg -r 1 -loop 1 -i TEST.jpg -i TEST.m4a -c:v libx264 -tune stillimage  -c:a copy -pix_fmt yuv420p -r 1 -shortest TEST.mp4

However, I'm not sure if youtube accepts video with this unusual framerate. Likewise, the option -pix_fmt yuv420 may be redundant, I would again double check by uploading a file to youtube.

do it on many files

Assuming we have a bunch of image and audio files:

$ for nn in *.mp3; do ffmpeg -loop 1 -i $nn.jpg -i $nn -c:v libx264 -tune stillimage -c:a copy -shortest $nn.mp4; done

This one-liner is convenient but has a problem, i.e. that it assumes that the image files are called exactly like the audio file with its extension and the .jpg extension appended to it, for example FILENAME.mp3.jpg.

The following shell script fixes that and assumes that audio and images have the same basename (the part of the filename before the extension):

#!/bin/sh

DIR=/Users/aadm/audio

for i in $DIR/*.mp3
do
    TMP=`basename ${i} .mp3`
    AUDIO=${TMP}.mp3
    IMAGE=${TMP}.jpg
    MOVIE=${TMP}.mp4
    ffmpeg -framerate 5 -i  -vcodec h264 ${OU}.mp4
    ffmpeg -loop 1 -i ${DIR}/${AUDIO} -i ${DIR}/${IMAGE} -c:v libx264 -tune stillimage -c:a copy -pix_fmt yuv420p -shortest ${MOVIE} 
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment