How to have OpenCV built process use self-built ffmpeg?

Building OpenCV in “default” way (CMake/ Code::Blocks/ mingw-64)
it uses a prebuilt ffmpeg, wrapped in “opencv_videoio_ffmpeg480_64.dll”.

My CMake’s output:

Video I/O:
DC1394: NO
FFMPEG: YES (prebuilt binaries)
avcodec: YES (58.134.100)
avformat: YES (58.76.100)
avutil: YES (56.70.100)
swscale: YES (5.9.100)
avresample: YES (4.0.0)
GStreamer: NO
DirectShow: YES

But this ffmpeg seems to offer only “rudimentary” (video) codecs.
Especially the most-used h264 codec with acceptable quality lacks.

My question:
What exactly has to be done to let OpenCV build use a pre-built
(full-featured) ffmpeg of one’s own?
(Which probably means to have let OpenCV built the ffmpeg wrapper anew?)


Note: You may have to modify the CMake script if you use a more recent version of FFMpeg than I described there.

1 Like

Thank you very much for your help!

As I don’t know much about building/ dependencies etc. I couldn’t assess at all which is the right direction, and which completely misleading.

I had a closer look at your proposition; and it seems that I either have to build ffmpeg by myself (being at windows, I will have to install m2sys, and doing in unix world),
or somehow have to make ffmpeg use x264 instead of openh264.
Both are external but OpenCV’s ffmpeg asks/ uses openh264, not x264 (?)

The chain becomes longer and longer; and every step in unknown territory
(which gives an uneasy feeling: if the simplest thing goes wrong, I’m at loss again).

The version linked to in the post uses x264

ffmpeg version n5.0.1-5-g240d82f26e-20220611 Copyright (c) 2000-2022 the FFmpeg developers
built with gcc 11.2.0 (crosstool-NG
configuration: --prefix=/ffbuild/prefix --pkg-config-flags=–static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --enable-shared --disable-static --disable-w32threads --enable-pthreads --enable-iconv --enable-libxml2 --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-lzma --enable-fontconfig --enable-libvorbis --enable-opencl --disable-libpulse --enable-libvmaf --disable-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --enable-libdav1d --enable-libdavs2 --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-frei0r --enable-libgme --enable-libass --enable-libbluray --enable-libmp3lame --enable-libopus --enable-librist --enable-libtheora --enable-libvpx --enable-libwebp --enable-lv2 --enable-libmfx --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --disable-vaapi --enable-libvidstab --enable-vulkan --enable-libshaderc --enable-libplacebo --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-ldflags=-pthread --extra-ldexeflags= --extra-libs=-lgomp --extra-version=20220611
libavutil 57. 17.100 / 57. 17.100
libavcodec 59. 18.100 / 59. 18.100
libavformat 59. 16.100 / 59. 16.100
libavdevice 59. 4.100 / 59. 4.100
libavfilter 8. 24.100 / 8. 24.100
libswscale 6. 4.100 / 6. 4.100
libswresample 4. 3.100 / 4. 3.100
libpostproc 56. 3.100 / 56. 3.100

My feedback after all - all does as expected now! :smile:

There’s only that setting OPENCV_FFMPEG_WRITER_OPTIONS (e.g. to “crf;18|tune;grain”) before starting my app or before building my app has no effect.
It seems to have been done once and forever when building OpenCV itself?
So there would be no way to use different encoding parameters?

I don’t know as I have not tried changing the writer options myself. That said documentation

Note: extra FFmpeg options should be pased in form key;value|key;value|key;value, for example hwaccel;cuvid|video_codec;h264_cuvid|vsync;0 or vcodec;x264|vprofile;high|vlevel;4.0

implies you should be able to tweak some parameters but maybe not all of them.

Yes, that’s exactly the way I tried it very first time (with default OpenH264 encoder).

Console window @ Windows:

Ran MyApp

(VideoWriter VW (“output.mp4”, CAP_FFMPEG, VideoWriter::fourcc(‘a’,‘v’,‘c’,‘1’), capt.get(CAP_PROP_FPS), refS))

Produces a strange avc1 file (quality very bad/ file size very large).



then ran my app.

Produces… the same file!

Now my assumption was OpenH264 was not capable to use the env var.
That’s why I installed newest OpenCV 4.8.0 with built-in x264 (with your kind help).

The produced avc1 file is coded with default crf23 (= standard) alright.
But in both cases!

My next supposition (until now) was that the env var have to be set when building OpenCV (as the names are similar to the CMake entries).
But your link to the documentation contradicts that (thank god).

It would be nice if somebody would check if/ how these env var do have an effect at all.
Maybe a bug/ lack in documenation?

@crackwitz has already raised an issue to this effect.

If it was me I would check that the env var is being passed correctly to OpenCV either by placing a breakpoint

or increasing the log level


I would also double check that OpenCV is using the supplied version of FFMpeg, not the automaitically downloaded OpenCV shared library and that calling that version outside of OpenCV (ffmpeg.exe) with the arguments you mention has the desired result.

you’re supposed to set them at runtime, not before starting your program. either should work.

Curiously I tried using HEVC for output codec.
It works - producing (nearly) lossless output;
taking very long and producing file size abt. half FFV1.
But crf=28 is default for HEVC - not lossless.

It produces only that (nearly) lossless - setting “crf;18” has no effect here either.

So the problem of wrong handling of codec settings is severe.

Would be nice if anybody would retrace that
and either confirm or reject it,
to possibly enter an issue.