FFmpeg dependency management with Nix overlays

FFmpeg is weird...

...and it has to be! As the undisputed multimedia tool that interfaces with tons of other dependencies, it needs to work alongside, and with, conflicting licenses, patents, etc.

The result is that to access the best of what the multimedia world has to offer, you'd need to compile FFmpeg yourself - a tedious process that has spawned tons and tons of scripts that purport to "help" users who need specific FFmpeg dependencies.

I personally find these schemes to be terrible, and working with FFmpeg to be terrible as a whole (not the CLI - I actually think the FFmpeg CLI is pretty intuitive if you have a good understanding of multimedia fundamentals) as such. It took me working on FFmpeg itself to understand how to actually compile FFmpeg with specific dependencies.

Enter: Nix

Pulling out the "Purely Functional Software Deployment Model" paper is now kind of a meme at this point - but deterministic environments like the ones afforded to us by Nix actually solves the FFmpeg issue!

Wait, but isn't this just a variation of the "build scripts" that you purport to hate?

It's roughly in the same idea-space, but since we're piggybacking outselves onto the Nix package manager rather than some script that is undocumented and easy to break

Wait but the Nix package manager is pretty inscrutible itself

Yeah. I hope it gets better too. I don't think Nix's issues with being absolutely difficult to use is quite the same as my gripe with the typical build scripts, though.

Example 1: Dev flake

This example only requries the presense of the Nix package manager, and is how I invoke FFmpeg on my server. We define a flake our usual way:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };
  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem
      (system:
        let
          pkgs = import nixpkgs {
            inherit system;
          };
        in
        with pkgs;
        {
          devShells.default = mkShell {
            buildInputs = [
                # We add our packages here
            ];
          };
        }
      );
}

then add an overlay to the output

    ...
    flake-utils.lib.eachDefaultSystem
      (system:
        let
          pkgs = import nixpkgs {
            inherit system;
            overlays = [
                (self: super: {ffmpeg-c = super.ffmpeg.override {
                    ## We define the build options here
                    withUnfree = true; 
                    withDav1d = true;
                };})
            ];
          };
        in
    ...

and then add this newly defined package to our devShell

        ...
        with pkgs;
        {
          devShells.default = mkShell {
            buildInputs = [
                ffmpeg-c
            ];
          };
        }
        ...

Hey, why are we defining the package to a new name? I thought the point with overlays is to override packages?

I'm glad you asked! In this example, because only the devShell is depenedent on our new ffmpeg-c package, we don't see big issues by naming it ffmpeg, but of course, this just forshadowing for the next part, where...

Example 2: Overriding in NixOS

...we're no longer just defining just a devShell, but a NixOS system as a whole.

In a "system" flake for NixOS or nix-darwin, instead of devShells.default as the output of our flake, we have nixOSConfigurations and darwinConfigurations. Also remember - FFmpeg is everywhere. Most fresh Linux systems have a non-encumbered version of FFmpeg somewhere to handle video - the first step in making a system usable is making it play cat videos.

So let's try defining an overlay module in overlays/default.nix that overrides ffmpeg!

# ./overlays/default.nix
{ config, pkgs, lib, ... }:

{
  nixpkgs.overlays = [
    (self: super: {
        ffmpeg = super.ffmpeg.override {
            withUnfree = true;
            withDav1d = true;
        };
    })
  ];
}

and let our system use it,

    ...
    mySystem = nixpkgs.lib.nixosSystem {
        specialArgs = { inherit inputs; }; # Pass flake inputs to our config
        modules = [
            ...
            ./nixos/atlantis/configuration.nix
            (import ./overlays/default.nix)
            ...
        ];
    };
    ...

then try running nixos-rebuild switch...

Hey, it's been three hours and nixos is trying to rebuild all of KDE from source. What the hell is going on?

We're running into the issue that the ffmpeg package is no longer what nixpkgs says it is - we've overridden it, and NixOS needs to evaluate if the system even compiles with the new config. Obviously, we want to avoid that. We want to use binaries that other people spent their precious machine hours on.

The solution is what I alluded to earlier in Example 1:

# ./overlays/default.nix
{ config, pkgs, lib, ... }:

{
  nixpkgs.overlays = [
    (self: super: {
        ffmpeg-c = super.ffmpeg.override {
            withUnfree = true;
            withDav1d = true;
        };
    })
  ];
}

Introducing a new package that other packages don't depend on. This does mean that you'll have two FFmpeg binaries floating around in your system, but that's a small price to pay.

Despite all that, this system of managing FFmpeg's dependencies is still the cleanest and most robust solution to the FFmpeg dependency problem. Not only that, but you also learn a little bit about how to manage your own devShells for niche use cases - something that will almost certainly help.

Have fun with your multimedia!

-r/c/s

music production software just kinda sucks: a rant

quick update

yeah I haven't updated my site in a year. i've gone thru quite a lot. i doubt anyone really is keeping track tho, so w/e. i'll make a life update post at some point but right now i just need to rant.

(also shoutout to adam neely for the idea of labelling the subpoints as chords :3)

music production software sucks

part I - the blissful, ignorant world of the FOSS-adjacent ecosystem

If you're reading this, chances are you come from the FOSS-adjacent ecosystem where DRM for software is more or less a non-issue - even with proprietary software (firmware, drivers, licensed software) it's just a matter of grabbing the package and installing the binary first and performing the registration later. At worst, an AppImage, or a flatpak (but that's a different issue compared to the hellworld to """professional""" audio software).

In the music production world, the only analog to this paradism is REAPER. It's a rather powerful, proprietary DAW that costs 225 dollars for commercial use (which they define as generating over 20k dollars in revenue yearly) or 60 dollars for noncommercial use. It's even available on Linux (bless those guys for dealing with Linux audio bullshit). They also provide a 60-day trial without needing you to even create an account - you can just install the binary!

This is how software should be distributed. Unfortunately, this is a rarity in the audio world.

part IIm - the ilok

Everyone - meet the iLok.

Made by PACE, iLok is a DRM soulution that the audio companies all fawn for.

Initially, the iLok was created as a USB hardware DRM storage pool where your licenses are stored on the USB key itself - when the software in question (whether it is your DAW or it's one of the many plugins you use) needs to authenticate, it will do some shenanigans with the iLok USB key to verify that the computer is authorized to use the plugin. (IDEA: R.E the iLok?)

We all know how flaky USB keys are. Countless horror iLok stories can be found with a quick Google search. The music world does seem to have settled on the iLok pretty early on though, so there really wasn't a need to have 15 different proprietary hardware DRM schemes.

But you know what? For an era where software was mainly distributed with firm releases (and a price tag to match), that was fair game.

part IIIm7b5 - SaaS strikes

...and then the SaaS business model hits.

It's not a secret that the "as a service" model kinda doesn't work - see the profitability figures of the barrage of streaming services, Xbox Game Pass, and other consumer-facing services for proof of that. Generally speaking, the "as a service" model only really works if your product is on the cusp of taking over the entire market - the early days of Netflix comes to mind, with the less-thought-of example of Ma Bell a close second (yes, all you SaaS companies are just wannabe monopolies, come at me).

So it's not a surprise that in a world where name matters more than technical superiority and subjective quality, the SaaS model works awfully well for pro audio companies - brand loyalty is one hell of a drug and many-a-mixing engineer are guilty of this - even me!

It's also not a secret that SaaS demands a different scheme of DRM as opposed to the big-box model of software - WideVine/Fairplay is our analog to the eldrich horror that I will explain in the next part. WideVine and Fairplay both demand a certain set of features from your device (namely - the OS you run, the level of hardware acceleration, and most importantly the ability for zero-copy) as well as a constant online-only connection - the cardinal sin of SaaS is to go off the internet.

Of course the pro audio world has it's own analog to this.

part IVmaj7 - iLok Cloud , or "Mom they SaaSed my hardware DRM!"

To be honest - I think that iLok Cloud is an improvement over the design of the original iLok USB - it stores your licences on PACE's servers and all you need to do is log in to gain access to all the software you're licensed to! Sounds great, but remember the cardinal sin of SaaS - you must never be offline.

iLok Cloud is completely inaccessible without the a connection to PACE servers. Not even for a second - you must have a constant connection or the iLok software on your own computer will tell all your plugins and even your DAW to stop working.

This. Is. A. Problem.

Especially since PACE servers aren't the most reliable. Just look for "ilok server down" on Google for proof.

Always-online applications are unacceptable in the professional world - work must always be done at work time, and the iLok Cloud scheme is completely at odds with this scheme.

The silver lining is that the traditional iLok USB scheme is still available as an option, but most pro audio companies are trending toward iLok Cloud as the main option.

part V - A symptom, not the cause.

Really, there isn't a pushback against SaaS even in the pro audio world - the effect of provenance and the status of brands far outweight the technical deficiency of the DRM scheme that cripples the industry and makes it less accessible to all.

And this is not unique to the pro audio world - this is merely a foil to get you, the reader, to think about how DRM affects you in personal life - maybe you're a FOSShead and can't watch some sporting event that's behind a restrictive FairPlay policy after already paying the monthly fee. Maybe you're an artist who needs to make ends meet by cutting out your Adobe subscription only to realize you can't pay the cancellation fee without selling your soul to the devil.

SaaS is a cancer among the world of both consumer and professional software alike. The best part? This is only one example!

part VIm

So what do we do from here?

I don't know the full answer to counter this monopolistic "as a service" model. But I know one thing for sure - we cannot let this terrible model stop us from consuming and creating - doing so will only mean that the monopolists win.

Note that I'm not advocating for piracy or breaking DRM here - I'm merely stating that isolating yourself from creating and enjoying works of art will not help the cause. Some perfectly fine solutions are buying physical media, purchasing perpetual licenses whenever available, and buying music off Bandcamp - spending as much of your money outside the SaaS ecosystem and making it as unappetizing to shareholders as possible is probbaly a good start.

Keep doing you - watching, listening, enjoying, creating, by however you see fit!

End of rant,

r/c/s