CLI tool
dirkvdb/ffmpegthumbnailer avatar
dirkvdb/ffmpegthumbnailer

FFmpegthumbnailer and the case for a thumbnailer that owns almost nothing

Lightweight video thumbnailer that can be used by file managers to create thumbnails for video files

639 stars81 forksC++GPL-2.0

At a glance

What is it?
FFmpegthumbnailer is a small C++ command line thumbnailer that delegates decoding to ffmpeg and keeps its own dependency list down to libpng and libjpeg. It is a good fit for desktop file managers and a poor fit for anyone who needs deterministic output across machines.
Who is it for?
Adopt ffmpegthumbnailer if you are wiring thumbnails into a file manager, a media browser, or a small server-side preview job and you control the ffmpeg build on the host. Skip it if your pipeline needs reproducible output across machines, because format support follows the local ffmpeg configuration rather than the project.
Can I use it commercially?
Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 31 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Decoding is delegated to ffmpeg, so the format matrix is out of the project's hands

ffmpegthumbnailer exists to solve one narrow problem: turning a video file into a still image small enough to sit inside a file manager icon. The README describes it as a lightweight thumbnailer that file managers can call, and it can also extract embedded album art from audio files to produce thumbnails. The implementation is C++, with the command line entry points sitting at main.c and main.cpp and the reusable pieces collected under libffmpegthumbnailer/, which ships its own pkg-config template in libffmpegthumbnailer.pc.in.

The decoding path is not written in this repository. Video frames come out of ffmpeg, which means the set of containers and codecs the tool can open is decided by the configuration flags of the ffmpeg installed on the machine. The README says it plainly: supported formats depend on the configuration flags of ffmpeg. This is the central trade-off of the design. It costs almost nothing to add support for a new format, because the work happens upstream. It also means a build of ffmpegthumbnailer can behave differently on two machines that run the same binary, and that the maintainers of this project cannot fix a missing codec without asking someone else to change their ffmpeg.

Because of that dependency, the tool itself stays small. The README lists only ffmpeg and libpng/libjpeg as dependencies, which is a reasonable profile for a helper that a desktop environment runs once per directory listing.

The default thumbnail is 128 pixels and ten percent into the file

The option list is short enough to read in one pass, and the defaults are conservative in a way that suits an icon cache. The generated thumbnail is 128 pixels by default, and passing 0 for the size requests the original dimensions instead of a scaled frame. Seeking defaults to 10 percent of the file duration, so the frame is taken from somewhere past the opening titles rather than from a black fade-in. The time option also accepts an absolute time in hh:mm:ss form, which is the option you want when a batch job knows where the interesting part of a video starts.

Image quality is a separate number, from 0 for bad to 10 for best, and it defaults to 8. The README restricts that setting to jpeg output, so raising it does nothing for a png. Format selection has two routes. By default the output filename decides: a name ending in .jpg or .jpeg produces jpeg, anything else produces png. The -c option overrides that decision with an explicit jpeg or png value, which matters when a downstream consumer wants a specific container regardless of how the caller named its temporary file.

Together these defaults describe a tool tuned for a thumbnail cache rather than for a poster frame. If you want a large, high quality still for a web page, you have to change the size and the seek point yourself.

Building and testing with CMake, Ninja and ctest

The repository includes a justfile that captures the whole build cycle in three targets, so there is no need to guess at generator flags or test invocation. The configure target creates a Release build directory with Ninja as the generator, the build target compiles it, and the test target runs the test suite through ctest against that build directory.

bash
configure:
    cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release

build: configure
    cmake --build ./build        

test: build
    ctest --test-dir ./build

Ninja is not a hard requirement of the project, it is simply the generator chosen in this file. The top-level CMakeLists.txt, the cmake/ directory and the config.h.in template are what a different build system would hook into instead. The presence of a test/ directory and a ctest target tells you the project expects its own behaviour to be checked automatically, which is worth more than it sounds for a component that a file manager invokes unattended.

Other build paths exist in the tree as well. flake.nix and flake.lock indicate a Nix flake, .envrc is a direnv environment file, and .travis.yml plus the .github/ directory show that continuous integration is configured. The INSTALL file and CMakeUninstall.cmake.in cover installation and removal, and dist/ and man/ hold packaging and manual page sources. A release helper sits at MakeRelease.sh, which pairs with the ChangeLog, NEWS and TODO files that track what the maintainers intend to do next.

Square crops and the filmstrip overlay change the shape of the output

Two options exist purely for presentation. The -a flag ignores the aspect ratio and generates a square thumbnail, which is what you need when the output has to fill a fixed icon slot without letterboxing. The -f flag overlays a movie strip on the generated thumbnail, a visual cue that tells a user browsing a folder that the file behind the icon is moving pictures rather than a still image.

Neither option is a post-processing stage inside the project, and the README does not document any pipeline for resizing or compositing beyond them. That is worth noting for anyone planning a custom look. The tool produces one image from one frame, with an optional strip burned into it. There is no documented way to request a contact sheet, a filmstrip of several frames, a blurred background, or a subtitle overlay. If your design calls for those, you would be doing that work outside the tool.

The square option also interacts with seeking in an obvious but unautomated way. Because the thumbnail is taken at one point in time, a video that opens on a dark scene will look wrong in a folder even when the frame extraction worked exactly as specified.

Embedded art takes priority when the -m flag is set

For audio files the source of a thumbnail is either the audio stream itself or artwork already embedded in the file. The -m flag makes the tool prefer embedded image metadata over video content. This is the interesting choice for music libraries, where an album cover attached to the file is a better icon than a frame pulled from the audio stream.

The README does not describe the fallback behaviour in detail, so the safe reading is that -m changes the preference rather than the only path. It also does not document how image formats inside the audio container are handled, or whether a file with several embedded images picks one or another.

The audio path is the part of the tool most likely to surprise you in a batch run. A folder of music with inconsistent tagging will produce a mixture of cover thumbnails and stream frames, and the only control the README offers is whether embedded metadata is preferred. There is no documented switch to force one behaviour for a whole batch.

The workaround flag exists because old ffmpeg builds can spin on certain files

One option is clearly a legacy escape hatch. The -w flag is documented as a workaround for issues in older versions of ffmpeg, and the README advises using it only if you hit problems such as 100 percent CPU usage on certain files. That phrasing tells you two things. First, the pathological behaviour belongs to ffmpeg rather than to this project, so the fix here is a mitigation, not a patch. Second, the intended usage is reactive, per file or per machine, rather than a permanent part of a wrapper script.

Two more options are diagnostic rather than functional. The -v option prints the version number, and -h displays the usage text. The usage text in the README is the full list of what the command line offers, and it is worth keeping open while writing a wrapper, because there is no long form flag and no configuration file described anywhere in the repository.

What the README does not document is any logging, retry behaviour, or timeout handling. A file manager that shells out to this binary has to manage those concerns itself, and the -w flag is the only hint that pathological inputs are a known category.

A shared library, a KDE component and a plain command line in one tree

The top level of the repository mixes three different kinds of deliverable. There is the standalone executable driven by main.c and main.cpp. There is libffmpegthumbnailer/, with the pkg-config template libffmpegthumbnailer.pc.in, which indicates the decoding and thumbnail logic is packaged as a library that other programs can link against rather than only being reachable through the command line. And there is kffmpegthumbnailer/, a component named for KDE, sitting next to a directory literally called thunar files, which points at integration with the Thunar file manager.

The practical consequence is that there are two reasonable ways to adopt this project. A shell script can call the binary once per file and read the resulting image. A larger application can link the library and avoid process startup for each thumbnail. The README, however, only documents the command line. It does not describe the library API, its headers, or its thread safety, so anyone planning to link against libffmpegthumbnailer has to read the source before committing to that path.

The .clang-format file and the .vscode/ directory suggest the project is developed with clang tooling in mind. The .github/ directory, .travis.yml and flake.nix mean there are several ways to build the same source, which is helpful when you need to match a distribution's toolchain.

GPL-2.0, a recent push and three releases in the past year

The project is distributed under GPL-2.0, with the text in COPYING and the authors listed in AUTHORS. That matters for adoption in two practical ways. Anyone who links libffmpegthumbnailer into a distributed product inherits the copyleft obligations of that library, and the separate existence of the library directory means the linking question is real rather than hypothetical. Anyone who only runs the binary as a separate process faces a different, and usually lighter, set of obligations. This is a description of how the licences are arranged, not legal advice.

On maintenance, the repository is not archived, and the last push was on 2026-09-22. Three releases appear in the recent history: v2.3.1 on 2026-08-28, v2.3.0 on 2025-12-14 and v2.2.4 on 2025-11-15. The gap between the last push and the most recent release is short, and the project is still moving.

For upgrading, the option surface is small enough to check by eye. A version bump can change the ffmpeg expectations, since the -w flag exists for older ffmpeg behaviour and newer ffmpeg may make it unnecessary or harmful. Because the CLI has no long options and no config file, an upgrade affects a wrapper script only through the release notes and the printed version.

Editorial conclusion

Adopt ffmpegthumbnailer if you are wiring thumbnails into a file manager, a media browser, or a small server-side preview job and you control the ffmpeg build on the host. Skip it if your pipeline needs reproducible output across machines, because format support follows the local ffmpeg configuration rather than the project. Before you commit, verify the ffmpeg codecs on the target machine, confirm the C++ build passes ctest, and check how the -t seek default behaves on short clips.

Frequently asked questions

How do I build ffmpegthumbnailer from source?

The justfile in the repository provides three targets. configure sets up a Release build with CMake and Ninja, build compiles it, and test runs ctest against the build directory. The build needs ffmpeg plus libpng and libjpeg.

Which video formats can ffmpegthumbnailer handle?

Supported formats depend on the configuration flags of the ffmpeg that is installed on the machine, because the tool uses ffmpeg to decode video frames. The project itself has no independent codec list.

How do I control the output size and format in ffmpegthumbnailer?

The -s option sets the size in pixels and 0 asks for the original size, while -c forces jpeg or png output regardless of the filename. The -q option sets jpeg quality from 0 to 10 and does not apply to png output.

Can ffmpegthumbnailer make thumbnails for music files?

Yes. It can extract embedded album art from audio files to create thumbnails, and the -m flag makes it prefer embedded image metadata over video content.

What is the -w flag for in ffmpegthumbnailer?

The -w flag works around issues in older versions of ffmpeg, and the README advises using it only if you experience problems such as 100 percent CPU usage on certain files.

Official sources

  1. dirkvdb/ffmpegthumbnailer on GitHub
  2. Issues
  3. License: GPL-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dirkvdb-ffmpegthumbnailer.svg)](https://hysenlabs.com/projects/dirkvdb-ffmpegthumbnailer)

Was this useful?