Skip to content

Commit e1f2fac

Browse files
committed
Add AV1 video codec support
This commit adds support for AV1 video decoding in lilliput, following the same pattern as HEVC support with build flag gating. Changes: - Add AV1 decoder enablement behind build flag (av1Enabled) - Update FFmpeg build scripts to include --enable-decoder=av1 and --enable-libaom - Add codec gating logic to reject AV1 when disabled (default) - Add basic tests for AV1 support and decoder creation - Include test AV1 video file for validation Usage: Enable AV1 support: go build -ldflags="-X=github.com/discord/lilliput.av1Enabled=true" Features: - AV1 video detection in containers (MP4, WebM, etc.) - First-frame extraction from AV1 videos - Same security model as HEVC (disabled by default)
1 parent 93305eb commit e1f2fac

File tree

7 files changed

+74
-4
lines changed

7 files changed

+74
-4
lines changed

avcodec.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ bool avcodec_decoder_is_streamable(const opencv_mat mat)
154154
return false;
155155
}
156156

157-
avcodec_decoder avcodec_decoder_create(const opencv_mat buf, const bool hevc_enabled)
157+
avcodec_decoder avcodec_decoder_create(const opencv_mat buf, const bool hevc_enabled, const bool av1_enabled)
158158
{
159159
avcodec_decoder d = new struct avcodec_decoder_struct();
160160
memset(d, 0, sizeof(struct avcodec_decoder_struct));
@@ -238,6 +238,11 @@ avcodec_decoder avcodec_decoder_create(const opencv_mat buf, const bool hevc_ena
238238
return NULL;
239239
}
240240

241+
if (codec->id == AV_CODEC_ID_AV1 && !av1_enabled) {
242+
avcodec_decoder_release(d);
243+
return NULL;
244+
}
245+
241246
d->codec = avcodec_alloc_context3(codec);
242247

243248
res = avcodec_parameters_to_context(d->codec, codec_params);

avcodec.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ const atomHeaderSize = 8
1616
// Enable by building/running with "-ldflags=-X=github.com/discord/lilliput.hevcEnabled=true"
1717
var hevcEnabled string
1818

19+
// Set AV1 decoder enablement behind a build flag, defaults to off
20+
// Enable by building/running with "-ldflags=-X=github.com/discord/lilliput.av1Enabled=true"
21+
var av1Enabled string
22+
1923
// avCodecDecoder handles decoding of various video/image formats using FFmpeg's avcodec.
2024
type avCodecDecoder struct {
2125
decoder C.avcodec_decoder
@@ -35,7 +39,7 @@ func newAVCodecDecoder(buf []byte) (*avCodecDecoder, error) {
3539
return nil, ErrBufTooSmall
3640
}
3741

38-
decoder := C.avcodec_decoder_create(mat, hevcEnabled == "true")
42+
decoder := C.avcodec_decoder_create(mat, hevcEnabled == "true", av1Enabled == "true")
3943
if decoder == nil {
4044
C.opencv_mat_release(mat)
4145
return nil, ErrInvalidImage

avcodec.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ typedef struct avcodec_decoder_struct* avcodec_decoder;
1111

1212
void avcodec_init();
1313

14-
avcodec_decoder avcodec_decoder_create(const opencv_mat buf, const bool hevc_enabled);
14+
avcodec_decoder avcodec_decoder_create(const opencv_mat buf, const bool hevc_enabled, const bool av1_enabled);
1515
void avcodec_decoder_release(avcodec_decoder d);
1616
int avcodec_decoder_get_width(const avcodec_decoder d);
1717
int avcodec_decoder_get_height(const avcodec_decoder d);

avcodec_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,65 @@ func TestICCProfile(t *testing.T) {
5959
}
6060
}
6161

62+
func TestAV1Support(t *testing.T) {
63+
// Test that AV1 variables are properly defined
64+
if av1Enabled != "true" && av1Enabled != "" {
65+
// This should be empty by default, confirming our variable is defined
66+
t.Logf("AV1 support is disabled (expected): %q", av1Enabled)
67+
}
68+
}
69+
70+
func TestAV1VideoDecoding(t *testing.T) {
71+
// Test AV1 video file
72+
av1Mp4, err := os.ReadFile("testdata/av1-mp4.mp4")
73+
if err != nil {
74+
t.Fatalf("failed to open AV1 test file: %v", err)
75+
}
76+
77+
t.Run("AV1_Disabled_By_Default", func(t *testing.T) {
78+
// Should fail when AV1 is disabled (default)
79+
_, err := newAVCodecDecoder(av1Mp4)
80+
if err == nil {
81+
t.Logf("AV1 decoder created successfully with av1Enabled=%q", av1Enabled)
82+
} else {
83+
t.Logf("AV1 decoder failed as expected when disabled: %v", err)
84+
}
85+
})
86+
87+
// Note: Testing with AV1 enabled requires building with the flag:
88+
// go test -ldflags="-X=github.com/discord/lilliput.av1Enabled=true"
89+
if av1Enabled == "true" {
90+
t.Run("AV1_Enabled_Decoding", func(t *testing.T) {
91+
decoder, err := newAVCodecDecoder(av1Mp4)
92+
if err != nil {
93+
t.Fatalf("failed to create AV1 decoder: %v", err)
94+
}
95+
defer decoder.Close()
96+
97+
// Test basic metadata
98+
header, err := decoder.Header()
99+
if err != nil {
100+
t.Fatalf("failed to get AV1 header: %v", err)
101+
}
102+
103+
t.Logf("AV1 video dimensions: %dx%d", header.Width(), header.Height())
104+
t.Logf("AV1 video duration: %v", decoder.Duration())
105+
t.Logf("AV1 video description: %s", decoder.Description())
106+
107+
// Test first frame extraction
108+
framebuffer := NewFramebuffer(header.Width(), header.Height())
109+
defer framebuffer.Close()
110+
111+
err = decoder.DecodeTo(framebuffer)
112+
if err != nil {
113+
t.Fatalf("failed to decode AV1 first frame: %v", err)
114+
}
115+
116+
t.Log("Successfully extracted first frame from AV1 video")
117+
})
118+
}
119+
}
120+
62121
func BenchmarkIsStreamableWebMp4(b *testing.B) {
63122
// Read the web-optimized streamable MP4 file
64123
webMp4, err := os.ReadFile("testdata/big_buck_bunny_480p_10s_web.mp4")

deps/build-deps-linux.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,12 @@ $BASEDIR/ffmpeg/configure $FFMPEG_CROSS_COMPILE_FLAGS \
343343
--enable-decoder=hevc \
344344
--enable-decoder=vp9 \
345345
--enable-decoder=vp8 \
346+
--enable-decoder=av1 \
346347
--enable-decoder=flac \
347348
--enable-decoder=mp3 \
348349
--enable-decoder=aac \
349350
--enable-decoder=vorbis \
351+
--enable-libaom \
350352
--disable-iconv \
351353
--disable-cuda \
352354
--disable-cuvid \

deps/build-deps-osx.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ mkdir -p $BASEDIR/ffmpeg
238238
tar -xJf $SRCDIR/ffmpeg-7.0.2.orig.tar.xz -C $BASEDIR/ffmpeg --strip-components 1
239239
mkdir -p $BUILDDIR/ffmpeg
240240
cd $BUILDDIR/ffmpeg
241-
$BASEDIR/ffmpeg/configure --prefix=$PREFIX --disable-doc --disable-programs --disable-everything --enable-demuxer=mov --enable-demuxer=matroska --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-decoder=mpeg4 --enable-decoder=h264 --enable-decoder=hevc --enable-decoder=vp9 --enable-decoder=vp8 --enable-decoder=flac --enable-decoder=mp3 --enable-decoder=aac --enable-decoder=vorbis --disable-iconv --arch=arm64 --enable-cross-compile --target-os=darwin
241+
$BASEDIR/ffmpeg/configure --prefix=$PREFIX --disable-doc --disable-programs --disable-everything --enable-demuxer=mov --enable-demuxer=matroska --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-decoder=mpeg4 --enable-decoder=h264 --enable-decoder=hevc --enable-decoder=vp9 --enable-decoder=vp8 --enable-decoder=av1 --enable-decoder=flac --enable-decoder=mp3 --enable-decoder=aac --enable-decoder=vorbis --enable-libaom --disable-iconv --arch=arm64 --enable-cross-compile --target-os=darwin
242242
make
243243
make install
244244

testdata/av1-mp4.mp4

380 KB
Binary file not shown.

0 commit comments

Comments
 (0)