Automatically updating ffmpeg on Windows using Zeranoe’s builds

Building ffmpeg from source on Windows is a royal pain.

For those who came in late, ffmpeg is the best reason for a video nerd to learn the command line.
For every question: “is it possible to automatically do x to some video?”, or I have 10,000 video files in format y, I want to convert them to format z, is that possible in my lifetime?”, the answer is usually: yes, you can do it with ffmpeg.


The up side is that you get to learn the command line. The down side is that since ffmpeg is distributed as source code you need to build it. And building it on windows is a royal pain. Just making sure you’ve got the build environment working properly is a full time job, and if you’re paid to be a video nerd you don’t want to be mucking around with minGW and Cygwin and so on. That’s a whole pile of tedium that you don’t need. Fortunately there’s someone who does it for you, for nothing — the wonderful Zeranoe. Aren’t humans the best people?

Machines will do our work for us…

So I was downloading and linking the latest update and making sure it all went into the right place and got to thinking that checking for updates is the kind of task best left to a machine, and given that I’ve been gaining in PowerShell powers for a while I thought it might be a job I could tackle.

So below is a function called updateFFMPEG. This script checks for new builds, downloads them, unzips them, and makes a hardlink to the executables — ffmpeg, ffprobe, ffplay — in C:\Program Files\ffmpeg. If you add this folder to your PATH environment variable you can call ffmpeg from the Powershell prompt without having to specify the path to it every time.

The way I use this script is to add it to my Microsoft.PowerShell_profile.ps1 file (found in <your home directory>\Documents\WindowsPowerShell). I call the function so that it runs every time I open a new PowerShell window, but don’t worry, to make sure it’s not off browsing the internet every time you want use PowerShell the script checks to see if it has been run today, and only checks for new builds if it hasn’t. You could change this to every month if your connection speed is slow, or hour if you’re crazy, by editing the date format string on the second line.

function updateFFMPEG {
    # change this to -Format MM-yyy for once a month,
    # or HH-dd-MM-yyyy for once an hour
    $theDate = (Get-Date -Format dd-MM-yyyy) 
    # this will be the ffmpeg executable directory:
    $ffmpegDir = 'C:\Program Files\ffmpeg\' 
    # Zeranoe's latest build:
    $URL = "" 

    # check to see if it has been updated today
    if (!(test-Path ($ffmpegDir + "last_update-" + $theDate))){
        echo "Updating FFMPEG"
        $downloadPath = ($ffmpegDir + 'latest.7z')

        # check to see if ImageMagick has been installed
        $IMVersion = (ls 'C:\Program Files\ImageMagick*\ffmpeg.exe')

        # make an FFMPEG directory if it doesn't exist
        if (!(test-path $ffmpegDir)){ mkdir $ffmpegDir}
        # delete any old downloads
        rm $downloadPath -ErrorAction SilentlyContinue
        # look in the ffmpeg directory for latest current versions
        $f=(ls $ffmpegDir -directory -filter "ffmpeg-*"| sort lastWriteTime)
        if ($f.length -gt 0) { 
            # there are current versions locally
            # get the last write time of the latest version
            $D = (get-date $f[-1].LastWriteTime -format "yyyyMMdd HH:mm:ss")
            # download a newer version if it exists
            curl --silent --time-cond $D $URL -o $downloadPath
        } else { 
        # no current versions
            curl --silent $URL -o $downloadPath
        if (test-Path $downloadPath){
            # there was a new version available
            echo "New build of FFMPEG found, installing"
            # unpack it to the ffmpeg program dir 
            #(silently, remove "2>&1 1>$null" if you want to know what it's doing)
            7z.exe x -y -o"$ffmpegDir" $downloadPath 2>&1 1>$null
            # delete the old links
            ls $ffmpegDir -file -filter "ff*.exe"|%{rm $_.fullname}
            # update the latest version
            $f=(ls $ffmpegDir -directory -filter "ffmpeg-*"|sort lastWriteTime)
            # make new symlinks, er hardlinks, whateverr
            ls ($f[-1].fullname + "\bin")|%{
                New-Hardlink ($ffmpegDir + $ $_.FullName
            # Imagemagick brings its own version of ffmpeg, 
            # which ends up on the PATH, so replace it with a hardlink to this one
            #-------if you don't want this cut here ------
            if ($IMVersion.length -gt 0) {
                echo "replacing the Image Magick version of FFMPEG"
                if (Test-Path ($IMVersion.fullname + ".dist")) {
                    rm $IMVersion #already made a backup
                } else {
                    mv $IMVersion ($IMVersion.fullname + ".dist")
                New-Hardlink $IMVersion.fullname ($ffmpegDir + "ffmpeg.exe")`
                -ErrorAction SilentlyContinue
            #-------to here-------------------------
            rm $downloadPath
        } else {
            echo "Current build of FFMPEG is up to date."
        rm ($ffmpegDir + "last_update-*")
        New-Item ($ffmpegDir + "last_update-" + $theDate) -type file

To make this script run every time you open a PowerShell window put the above code in your PowerShell profile file (see above for where to find it), and add the line


to actually run it.

You might notice the ImageMagick palaver in the code. I added it because ImageMagick installs its own version of ffmpeg, and if ImageMagick is in the $Path then that version could get used instead. So this swaps the new build for ImageMagick’s version. You can safely cut this section out of the code if you don’t have ImageMagick, or if you don’t want some random script from the internet faffing about wi’ it.

Oh, and it relies on 7z.exe being in your PATH. You can download 7z here, and for easily editing the PATH environment variable I recommend Rapid Environment Editor.

Leave a Reply

Your email address will not be published. Required fields are marked *