-
Notifications
You must be signed in to change notification settings - Fork 32
Using FFmpegKitNext on Windows
This page shows how to use FFmpegKitNext from a Windows C++ application after the Windows bundle has been built. Build the bundle first — see Building Windows. The artifacts live under prebuilt/bundle-windows/ffmpeg-kit-next.
The FFmpegKitNext DLL exposes a C API and, on top of it, the same object-oriented C++ API used on the other platforms. The DLL can be linked from both the MinGW-w64 toolchain it is built with and from MSVC / clang-cl. The examples below use the C++ API.
The bundle ships a separate import library for each toolchain, built against the same DLLs, together with the metadata to discover it:
-
pkg-config(lib/pkgconfig/ffmpeg-kit-next.pc) forMinGW-w64. - a
CMakepackage config (lib/cmake/ffmpeg-kit-next/ffmpeg-kit-next-config.cmake) forMSVC/clang-cl.
At runtime, the DLLs from bin that your executable uses must be next to your executable (or on PATH).
Point pkg-config at the bundle and let it supply the include and library flags:
export PKG_CONFIG_PATH=<path-to>/prebuilt/bundle-windows/ffmpeg-kit-next/lib/pkgconfig
clang++ -std=c++11 app.cpp $(pkg-config --cflags --libs ffmpeg-kit-next) -o app.exeIf the bundle was built with --no-static-mingw-runtime, pkg-config exposes the additional MinGW runtime DLL paths through the runtime_dlls variable:
pkg-config --variable=runtime_dlls ffmpeg-kit-nextThe CMake package config resolves the include directory, the ffmpegkit.lib import library and the transitive FFmpeg targets in one step:
list(APPEND CMAKE_PREFIX_PATH "<path-to>/prebuilt/bundle-windows/ffmpeg-kit-next")
find_package(ffmpeg-kit-next CONFIG REQUIRED)
add_executable(app app.cpp)
target_link_libraries(app PRIVATE ffmpeg-kit-next::ffmpegkit)To copy the runtime DLLs next to the executable after a build, use $<TARGET_RUNTIME_DLLS> together with FFMPEG_KIT_NEXT_RUNTIME_DLLS:
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:app>
${FFMPEG_KIT_NEXT_RUNTIME_DLLS}
$<TARGET_FILE_DIR:app>
COMMAND_EXPAND_LISTS)By default, the MinGW-w64 toolchain runtime is linked statically into the generated DLLs, so the bundle does not need extra MSYS2 runtime DLLs at run time.
When the bundle is built with --no-static-mingw-runtime, the required MinGW runtime DLLs are shipped under bin and listed in the generated metadata. The exact filenames are toolchain-dependent: CLANGARM64 and CLANG64 builds commonly use libc++.dll, libunwind.dll and libwinpthread-1.dll, while MINGW64 and UCRT64 builds may use libstdc++-6.dll, libgcc_s_seh-1.dll and libwinpthread-1.dll. Use runtime_dlls or FFMPEG_KIT_NEXT_RUNTIME_DLLS instead of hardcoding the DLL names.
Use execute for synchronous execution. It returns an FFmpegSession with the result, logs, statistics and failure details.
#include <FFmpegKit.h>
#include <FFmpegKitConfig.h>
using namespace ffmpegkit;
auto session = FFmpegKit::execute("-y -i input.mp4 -c:v mpeg4 output.mp4");
auto returnCode = session->getReturnCode();
if (ReturnCode::isSuccess(returnCode)) {
std::cout << "FFmpeg completed successfully." << std::endl;
} else if (ReturnCode::isCancel(returnCode)) {
std::cout << "FFmpeg command was cancelled." << std::endl;
} else {
std::cout << "FFmpeg failed with state "
<< FFmpegKitConfig::sessionStateToString(session->getState())
<< " and rc " << returnCode << "."
<< session->getFailStackTrace() << std::endl;
}Use executeWithArguments when paths, filter expressions, or user-provided values may contain spaces or shell-sensitive characters.
std::list<std::string> arguments = {
"-y",
"-i", "C:\\media\\input with spaces.mp4",
"-vf", "scale=1280:-2",
"-c:v", "mpeg4",
"C:\\media\\output.mp4"
};
auto session = FFmpegKit::executeWithArguments(arguments);executeAsync starts the command and returns immediately. Use the session callback for the final result, the log callback for FFmpeg log lines and the statistics callback for progress information.
auto asyncSession = FFmpegKit::executeAsync(
"-y -i input.mp4 -c:v mpeg4 output.mp4",
[](const std::shared_ptr<FFmpegSession> session) {
auto returnCode = session->getReturnCode();
std::cout << "FFmpeg ended with state "
<< FFmpegKitConfig::sessionStateToString(session->getState())
<< " and rc " << returnCode << "." << std::endl;
},
[](const std::shared_ptr<Log> log) {
std::cout << log->getMessage();
},
[](const std::shared_ptr<Statistics> statistics) {
std::cout << "frame=" << statistics->getVideoFrameNumber()
<< " time=" << statistics->getTime()
<< " speed=" << statistics->getSpeed() << std::endl;
});Each execution creates a session. Use it to inspect the command, state, output, logs, statistics and timing.
auto session = FFmpegKit::execute("-y -i input.mp4 -f null -");
long sessionId = session->getSessionId();
std::string command = session->getCommand();
auto arguments = session->getArguments();
SessionState state = session->getState();
auto returnCode = session->getReturnCode();
auto startTime = session->getStartTime();
auto endTime = session->getEndTime();
long durationMs = session->getDuration();
std::string output = session->getOutput();
std::string failStackTrace = session->getFailStackTrace();
auto logs = session->getAllLogs();
auto statistics = session->getAllStatistics();
auto lastStatistics = session->getLastReceivedStatistics();For asynchronous sessions, getAllLogs() and getAllStatistics() wait for pending asynchronous messages. getLogs() and getStatistics() return only the messages already delivered.
Session history is managed by FFmpegKitConfig.
FFmpegKitConfig::setSessionHistorySize(100);
auto sessions = FFmpegKitConfig::getSessions();
int index = 0;
for (const auto &session : *sessions) {
std::cout << "Session " << index++
<< " id=" << session->getSessionId()
<< " state=" << FFmpegKitConfig::sessionStateToString(session->getState())
<< " durationMs=" << session->getDuration()
<< " rc=" << session->getReturnCode()
<< std::endl;
}
auto runningSessions = FFmpegKitConfig::getSessionsByState(SessionStateRunning);
auto ffmpegSessions = FFmpegKitConfig::getFFmpegSessions();
auto ffprobeSessions = FFmpegKitConfig::getFFprobeSessions();
auto mediaInformationSessions = FFmpegKitConfig::getMediaInformationSessions();You can also retrieve FFmpegKitConfig::getLastSession(), FFmpegKitConfig::getLastCompletedSession(), or FFmpegKitConfig::getSession(sessionId). Use deleteSession(sessionId) or clearSessions() only when you no longer need the session history; callbacks cannot be triggered for deleted sessions.
Use FFprobeKit for direct ffprobe commands.
auto probeSession = FFprobeKit::execute(
"-v error -show_entries format=duration "
"-of default=noprint_wrappers=1:nokey=1 input.mp4");
if (!ReturnCode::isSuccess(probeSession->getReturnCode())) {
std::cout << "FFprobe failed. Output: "
<< probeSession->getAllLogsAsString() << std::endl;
}The same command can run asynchronously:
auto asyncProbeSession = FFprobeKit::executeAsync(
"-v error -show_streams -of json input.mp4",
[](const std::shared_ptr<FFprobeSession> session) {
std::cout << "FFprobe rc=" << session->getReturnCode() << std::endl;
});For parsed media metadata, use getMediaInformation.
auto mediaSession = FFprobeKit::getMediaInformation("input.mp4");
auto mediaInformation = mediaSession->getMediaInformation();
if (mediaInformation != nullptr) {
auto duration = mediaInformation->getDuration();
auto format = mediaInformation->getFormat();
auto streams = mediaInformation->getStreams();
if (duration != nullptr) {
std::cout << "duration=" << *duration << std::endl;
}
if (format != nullptr) {
std::cout << "format=" << *format << std::endl;
}
if (streams != nullptr) {
std::cout << "stream count=" << streams->size() << std::endl;
}
}Keep log redirection enabled when using getMediaInformation; disabling redirection prevents media information parsing from receiving the JSON output it needs.
Cancellation returns immediately. Check the complete callback or session state later to observe the final result.
auto session = FFmpegKit::executeAsync(
"-i input.mp4 -c:v mpeg4 output.mp4",
[](const std::shared_ptr<FFmpegSession> completedSession) {
if (ReturnCode::isCancel(completedSession->getReturnCode())) {
std::cout << "Cancelled." << std::endl;
}
});
FFmpegKit::cancel(session->getSessionId());
// Or cancel every running FFmpeg session.
FFmpegKit::cancel();Redirection is enabled by default. With redirection enabled, sessions collect logs and statistics, global/session callbacks receive messages and media information parsing works.
FFmpegKitConfig::setLogLevel(LevelAVLogInfo);
FFmpegKitConfig::enableLogCallback(
[](const std::shared_ptr<Log> log) {
std::cout << FFmpegKitConfig::logLevelToString(log->getLevel())
<< ": " << log->getMessage();
});
FFmpegKitConfig::enableStatisticsCallback(
[](const std::shared_ptr<Statistics> statistics) {
std::cout << "session=" << statistics->getSessionId()
<< " frame=" << statistics->getVideoFrameNumber()
<< " bitrate=" << statistics->getBitrate()
<< std::endl;
});
FFmpegKitConfig::enableFFmpegSessionCompleteCallback(
[](const std::shared_ptr<FFmpegSession> session) {
std::cout << "FFmpeg session " << session->getSessionId()
<< " completed." << std::endl;
});
FFmpegKitConfig::enableFFprobeSessionCompleteCallback(
[](const std::shared_ptr<FFprobeSession> session) {
std::cout << "FFprobe session " << session->getSessionId()
<< " completed." << std::endl;
});
FFmpegKitConfig::enableMediaInformationSessionCompleteCallback(
[](const std::shared_ptr<MediaInformationSession> session) {
std::cout << "Media information session " << session->getSessionId()
<< " completed." << std::endl;
});Disable a previously registered global callback by passing nullptr.
FFmpegKitConfig::enableLogCallback(nullptr);
FFmpegKitConfig::enableStatisticsCallback(nullptr);
FFmpegKitConfig::enableFFmpegSessionCompleteCallback(nullptr);Use the log redirection strategy when you need to control whether logs are printed to stderr in addition to being collected by the API.
FFmpegKitConfig::setLogRedirectionStrategy(
LogRedirectionStrategyPrintLogsWhenNoCallbacksDefined);Use FFmpegKitConfig::disableRedirection() only when you want FFmpeg and FFprobe output to go directly to stderr and you do not need logs, statistics callbacks, or getMediaInformation.
The drawtext filter requires a build that includes freetype and harfbuzz. Registering directories and using font family names additionally requires fontconfig.
If the command can use a font file directly, pass fontfile:
auto session = FFmpegKit::execute(
"-y -i input.mp4 "
"-vf \"drawtext=fontfile=C\\\\:/Windows/Fonts/arial.ttf:"
"text='Hello':x=20:y=20:fontsize=32:fontcolor=white\" "
"output.mp4");If fontconfig is enabled, register directories and optional friendly names:
FFmpegKitConfig::setFontDirectoryList(
std::list<std::string>{"C:\\Windows\\Fonts"},
std::map<std::string, std::string>{{"MyFont", "My Font"}});
auto session = FFmpegKit::execute(
"-y -i input.mp4 "
"-vf \"drawtext=font='MyFont':text='Hello':x=20:y=20\" "
"output.mp4");If your application ships a custom fonts.conf, point fontconfig to that configuration directory:
int result = FFmpegKitConfig::setFontconfigConfigurationPath("C:\\myapp\\fontconfig");FFmpegKitInputBuffer and FFmpegKitOutputBuffer expose finite, seekable in-memory resources through ffkitmem: URLs. They are useful when you already have bytes in memory or want the encoded output as bytes without writing a temporary file.
std::vector<uint8_t> inputBytes = loadInputBytes();
auto input = FFmpegKitInputBuffer::fromByteArray(inputBytes, "mp4");
auto output = FFmpegKitOutputBuffer::create("mp4");
std::list<std::string> arguments = {
"-y",
"-i", input->getUrl(),
"-c:v", "mpeg4",
"-f", "mp4",
output->getUrl()
};
auto session = FFmpegKit::executeWithArguments(arguments);
if (ReturnCode::isSuccess(session->getReturnCode())) {
auto outputBytes = output->toByteArray();
std::cout << "encoded bytes=" << outputBytes->size() << std::endl;
}
input->close();
output->close();fromBytes(data, size, extension) is available when your input is already in a raw byte pointer. create(extension, initialCapacity, maxCapacity) lets you control the output buffer capacity.
FFmpegKitStreamInput and FFmpegKitStreamOutput expose non-seekable memory-backed streams through ffkitstream: URLs. Use them for producer/consumer flows. Use ffkitmem: instead when the format needs seeking.
auto streamInput = FFmpegKitStreamInput::create("raw");
auto streamOutput = FFmpegKitStreamOutput::create("wav");
std::list<std::string> arguments = {
"-f", "s16le",
"-ar", "48000",
"-ac", "2",
"-i", streamInput->getUrl(),
"-f", "wav",
streamOutput->getUrl()
};
auto session = FFmpegKit::executeWithArgumentsAsync(
arguments,
[](const std::shared_ptr<FFmpegSession> session) {
std::cout << "streaming session rc=" << session->getReturnCode() << std::endl;
});
std::vector<uint8_t> pcmChunk = readNextPcmChunk();
streamInput->write(pcmChunk, 1000);
streamInput->closeInput();
auto encodedChunk = streamOutput->read(4096, 1000);
if (encodedChunk != nullptr && !encodedChunk->empty()) {
consumeEncodedBytes(*encodedChunk);
}
streamInput->close();
streamOutput->close();A stream read(maxBytes, timeoutMs) returns nullptr on timeout and an empty vector at EOF. Read output while the session runs if the produced data may exceed the stream capacity.
Named pipes are not supported on Windows: FFmpegKitConfig::registerNewFFmpegPipe() returns nullptr and closeFFmpegPipe() does nothing. Use the ffkitmem: and ffkitstream: protocols instead.
Use the configuration and package helpers to inspect the runtime your application loaded.
#include <ArchDetect.h>
#include <Packages.h>
std::cout << "FFmpegKit version: " << FFmpegKitConfig::getVersion() << std::endl;
std::cout << "FFmpeg version: " << FFmpegKitConfig::getFFmpegVersion() << std::endl;
std::cout << "Build date: " << FFmpegKitConfig::getBuildDate() << std::endl;
std::cout << "Package name: " << Packages::getPackageName() << std::endl;
std::cout << "Architecture: " << ArchDetect::getArch() << std::endl;
auto libraries = Packages::getExternalLibraries();
if (libraries->find("freetype") != libraries->end() &&
libraries->find("harfbuzz") != libraries->end()) {
std::cout << "drawtext dependencies are available." << std::endl;
}Packages::getExternalLibraries() returns enabled external library identifiers such as freetype, harfbuzz, fontconfig, x264, x265, or gnutls.
Packages::getPackageName() returns the custom package name configured at build time.
Set process environment variables before running sessions when an FFmpeg library or protocol needs them:
int result = FFmpegKitConfig::setEnvironmentVariable("SSL_CERT_FILE", "C:\\myapp\\ca-certificates.crt");For a runnable Windows example, see the test application developed under the ffmpeg-kit-next-test project. See also Windows Test Application.
Copyright (c) 2026 FFmpegKitNext
- Status
- Versions
- Changelog
- Project Layout
- Using
- Building
- External Libraries
- Patents
- License