Integrate libdav1d AV1 Decoder in iOS
This article provides a straightforward guide on how iOS developers
can integrate libdav1d, the high-performance open-source
AV1 video decoder, into their mobile applications. It covers the
essential steps of acquiring or compiling the library for iOS, bridging
the C-based library into a Swift or Objective-C environment, and
handling the core decoding loop to render AV1 video frames.
Step 1: Obtain or Compile libdav1d for iOS
Because libdav1d is written in C and assembly, it must
be compiled for the iOS architecture (arm64 for physical
devices, and arm64/x86_64 for the iOS
Simulator). Developers can compile it manually using Meson and Ninja
with an iOS toolchain file, or use pre-compiled binaries via dependency
managers.
Option A: Using CocoaPods or Swift Package Manager (Recommended)
The easiest way to integrate libdav1d is through
community-maintained wrappers or podspecs. For example, adding the
following to your Podfile pulls in the pre-compiled
binaries:
pod 'dav1d'Option B: Compiling from Source
To compile manually, clone the official VideoLAN repository and use Meson to set up a cross-compilation build targeting iOS:
git clone https://code.videolan.org/videolan/dav1d.git
cd dav1d
meson build --cross-file package/crossfiles/ios64.meson --buildtype release
ninja -C buildThis generates static (.a) or dynamic
(.dylib) libraries that you must manually drag and drop
into your Xcode project under Frameworks, Libraries, and
Embedded Content.
Step 2: Configure the Xcode Project
After adding the compiled libdav1d.a and its header
files (the include directory) to Xcode, you need to
configure your build settings so your code can interact with the
library.
Header Search Paths: Go to your target’s Build Settings and add the path to the
libdav1dheader files (containingdav1d/dav1d.h) to Header Search Paths.Bridging Header (for Swift): If your project uses Swift, create a bridging header (e.g.,
YourProject-Bridging-Header.h) and import the main header:#import <dav1d/dav1d.h>
Step 3: Implement the Decoding Loop
With the C headers exposed to your Swift or Objective-C code, you can initialize the decoder and feed it raw AV1 bitstream packets.
1. Initialize the Decoder Context
Create and configure the Dav1dContext:
var context: OpaquePointer? = nil
var settings = Dav1dSettings()
// Initialize default settings
dav1d_default_settings(&settings)
// Allocate the context
let result = dav1d_open(&context, &settings)
if result < 0 {
print("Failed to initialize dav1d decoder")
}2. Send Bitstream Data to the Decoder
For every compressed AV1 frame (packet) you receive from your
demuxer, wrap it in a Dav1dData structure and send it to
the decoder:
var data = Dav1dData()
let rawDataPointer = ... // Pointer to your AV1 frame buffer
let dataSize = ... // Size of the frame buffer
// Pass the data buffer to the dav1d data structure
dav1d_data_wrap(&data, rawDataPointer, dataSize, nil, nil)
// Submit packet to the decoder
let sendResult = dav1d_send_data(context, &data)
if sendResult < 0 && sendResult != -EAGAIN {
print("Error feeding data to the decoder")
}3. Retrieve Decoded YUV Frames
Once data is submitted, retrieve the decoded picture frame from the decoder pipeline:
var picture = Dav1dPicture()
let getResult = dav1d_get_picture(context, &picture)
if getResult == 0 {
// Successfully retrieved a decoded frame
processDecodedFrame(picture)
// Release the picture when done
dav1d_picture_unref(&picture)
}Step 4: Render the Decoded Frames
libdav1d outputs raw YUV frames (usually YUV420p). iOS
devices cannot display this format directly using standard
UIImageViews without conversion.
To display the decoded frames on screen: 1. Metal or OpenGL
ES: Upload the Y, U, and V planes as separate textures to a
custom Metal shader, and perform YUV-to-RGB conversion directly on the
GPU for maximum performance. 2. CoreVideo: Convert the
Dav1dPicture buffer into a CVPixelBuffer
(using kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange),
which can then be rendered using an
AVSampleBufferDisplayLayer or converted into a
CIImage/UIImage.