Building FFmpeg from source for iOS on macOS

This page explains how to configure and build FFmpeg for iOS as frameworks. Compilation for iOS is a cross-compilation and presumes using macOS as a host system. The required steps are:

  • Preparing build environment
  • Getting the FFmpeg source code
  • Configuring FFmpeg from the command line
  • Building dynamic libraries
  • Creating iOS frameworks from FFmpeg libraries
  • Creating XCFrameworks
  • Embedding frameworks

Note: The following documentation assumes that you work with FFmpeg libraries and code under ~/ffmpeg.

Preparing build environment

The build environment for iOS is provided by Apple's Xcode application, which includes the toolchain (compiler, linker, and other tools), and the iOS platform-SDK (headers and libraries) that you build and link against.

Getting the FFmpeg source code

You can get the FFmpeg source code in these ways:

  • Download from the FFmpeg download page.
  • Clone from git. For example, these commands clone the version 7.1 of the FFmpeg sources to ~/ffmpeg/ffmpeg_src.
    % cd ~/ffmpeg/
    % git clone --branch n7.1 https://git.ffmpeg.org/ffmpeg.git ffmpeg_src

Note: It is recommended to use the same FFmpeg version as documented in the Qt Multimedia main page.

Configuring and building FFmpeg

Create a build and installed directories inside the ~/ffmpeg directory and navigate into build:

% mkdir ~/ffmpeg/build
% mkdir ~/ffmpeg/installed
% cd ~/ffmpeg/build

To configure FFmpeg, run:

% ../ffmpeg_src/configure --disable-programs --disable-doc --enable-network --enable-shared --disable-static \
   --sysroot="$(xcrun --sdk iphoneos --show-sdk-path)" \
   --enable-cross-compile \
   --arch=arm64 \
   --prefix=../installed \
   --cc="xcrun --sdk iphoneos clang -arch arm64" \
   --cxx="xcrun --sdk iphoneos clang++ -arch arm64" \
   --extra-ldflags="-miphoneos-version-min=16.0" \
   --install-name-dir='@rpath' \
   --disable-audiotoolbox

The command line programs and documentation are not needed; network features should be enabled. We build shared libraries and don't need static libraries (omit --disable-static to build static libraries). --sysroot specifies the root of cross-build tree. The --prefix argument specifies a path where the FFmpeg libraries are installed after building. We build on macOS host for iOS target so we enable cross compilation. --extra-ldflags set the minimum version of iOS. --install-name-dir is a string specifying the directory portion of the "install_name" field of shared libraries on Apple platforms for installed targets. AudioToolBox is disabled, since FFmpeg is using parts of AudioToolBox framework which are not available on iOS.

Note: In the example above, replacing 'iphoneos' with 'iphonesimulator', and 'miphoneos-version' with 'mios-simulator-version-min', configures FFmpeg to be built as libraries suitable for iOS simulator.

To get help on other configuration options, run:

% ../ffmpeg_src/configure --help

After configuration is complete, build FFmpeg libraries:

% make -j install

Creating iOS frameworks from FFmpeg libraries

To work in iOS applications, FFmpeg dynamic libraries have to be converted into frameworks and embedded into application bundles. A framework is a hierarchical directory that encapsulates resources such as a dynamic library, image files, localized strings, header files, and reference documentation in a single package. In our case, FFmpeg frameworks only contain dynamic libraries and corresponding Info.plist files. For example, libavcodec converted to framework becomes libavcodec.framework directory with these contents:

  • Info.plist (containing the description of the framework)
  • libavcodec (dynamic library)

Unlike dynamic libraries we built in the previous step, dynamic libraries inside iOS frameworks are unversioned and have no 'dylib' extensions. This requires fixing library identification names and dependencies in our dynamic libraries. The otool utility helps us to find such names. For example:

%otool -L ../installed/lib/libavcodec.dylib

gives us these names (we only show FFmpeg-related names):

@rpath/libavcodec.61.dylib (compatibility version 61.0.0, current version 61.19.100)
@rpath/libswresample.5.dylib (compatibility version 5.0.0, current version 5.3.100)
@rpath/libavutil.59.dylib (compatibility version 59.0.0, current version 59.39.100)

To fix these names, use the install_name_tool utility. The utility options are:

  • -id - allows changing the shared library identification name.
  • -change - allows changing the dependent shared library install name.

This script converts the previously built dynamic libraries to frameworks. The code assumes that you run it from the build directory and the frameworks are located in ~/ffmpeg/installed/framework:

#!/usr/bin/env bash

# Creates an Info.plist file for a given framework:
build_info_plist() {
    local file_path="$1"
    local framework_name="$2"
    local framework_id="$3"

    # Minimum version must be the same we used when building FFmpeg.
    local minimum_version_key="MinimumOSVersion"
    local minimum_os_version="16.0"

    local supported_platforms="iPhoneOS"

    info_plist="<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleExecutable</key>
    <string>${framework_name}</string>
    <key>CFBundleIdentifier</key>
    <string>${framework_id}</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>${framework_name}</string>
    <key>CFBundlePackageType</key>
    <string>FMWK</string>
    <key>CFBundleShortVersionString</key>
    <string>7.0.2</string>
    <key>CFBundleVersion</key>
    <string>7.0.2</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>${minimum_version_key}</key>
    <string>${minimum_os_version}</string>
    <key>CFBundleSupportedPlatforms</key>
    <array>
        <string>${supported_platforms}</string>
    </array>
    <key>NSPrincipalClass</key>
    <string></string>
</dict>
</plist>"
    echo $info_plist | tee ${file_path} 1>/dev/null
}

dylib_regex="^@rpath/.*\.dylib$"

# Creates framework from a dylib file:
create_framework() {
    local framework_name="$1"
    local ffmpeg_library_path="../installed"
    local framework_complete_path="${ffmpeg_library_path}/framework/${framework_name}.framework/${framework_name}"

    # Create framework directory and copy dylib file to this directory:
    mkdir -p "${ffmpeg_library_path}/framework/${framework_name}.framework"
    cp "${ffmpeg_library_path}/lib/${framework_name}.dylib" "${ffmpeg_library_path}/framework/${framework_name}.framework/${framework_name}"

    # Change the shared library identification name, removing version number and 'dylib' extension;
    # \c Frameworks part of the name is needed since this is where frameworks will be installed in
    # an application bundle:
    install_name_tool -id @rpath/Frameworks/${framework_name}.framework/${framework_name} "${framework_complete_path}"

    # Add Info.plist file into the framework directory:
    build_info_plist "${ffmpeg_library_path}/framework/${framework_name}.framework/Info.plist" "${framework_name}" "io.qt.ffmpegkit."${framework_name}
    otool -L "$framework_complete_path" | awk '/\t/ {print $1}' | egrep "$dylib_regex" | while read -r dependency_path; do
        found_name=$(tmp=${dependency_path/*\/}; echo ${tmp/\.*})
        if [ "$found_name" != "$framework_name" ]
        then
            # Change the dependent shared library install name to remove version number and 'dylib' extension:
            install_name_tool -change "$dependency_path" @rpath/Frameworks/${found_name}.framework/${found_name} "${framework_complete_path}"
        fi
    done
}

ffmpeg_libs="libavcodec libavformat libavutil libswresample libswscale"

for name in $ffmpeg_libs; do
    create_framework $name
done

Creating a multiplatform binary framework bundle

An XCFramework bundle is a package that includes frameworks and libraries necessary to build for multiple platforms, for example, iOS and iOS simulator. To create such a framework, use the xcodebuild utility. For example, if you have frameworks for iOS and simulator located in ~/ffmpeg/installed/arm64 and ~/ffmpeg/installed/arm64-simulator directories, the utility arguments look like follows:

%xcodebuild -create-xcframework -framework ../installed/arm64/libavcodec.framework -framework ../installed/arm64-simulator/libavcodec.framework -output ../installed/framework/libavcodec.xcframework

Embedding frameworks

Embed the FFmpeg frameworks into an application bundle. For information on how to embed frameworks using XCode, refer to

Embedding Frameworks In An App.

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.