Watch
1
0
Fork
You've already forked nexus
0
forked from Nexus/nexus

use another avif library that works on aarch64-linux

This commit is contained in:
Henry Hiles 2026-10-17 11:18:23 -04:00
commit 8180338d99
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
12 changed files with 93 additions and 196 deletions

View file

@ -1,8 +1,10 @@
import "dart:async";
import "dart:io";
import "dart:isolate";
import "dart:ui" as ui;
import "package:avif_native/avif_native.dart";
import "package:flutter/widgets.dart";
import "package:flutter_avif/flutter_avif.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/client.dart";
import "package:nexus/models/requests/download_media.dart";
@ -24,13 +26,9 @@ class MxcImage(final WidgetRef ref, final DownloadMediaRequest request)
final bytes = await File(file.path).readAsBytes();
// Flutter can't decode AVIF on Linux/Windows (or older Android/iOS), so we do it ourselves
final avifType = isAvifFile(bytes.sublist(0, 16.clamp(0, bytes.length)));
if (avifType != .unknown) {
final codec = avifType == .avif
? SingleFrameAvifCodec(bytes: bytes)
: MultiFrameAvifCodec(key: hashCode, avifBytes: bytes);
await codec.ready();
return AvifCodecAdapter(codec);
if (String.fromCharCodes(bytes.skip(4).take(8))
case "ftypavif" || "ftypavis") {
return AvifCodec(await Isolate.run(() => decodeAvif(bytes)));
}
return decode(await .fromUint8List(bytes));
@ -44,21 +42,33 @@ class MxcImage(final WidgetRef ref, final DownloadMediaRequest request)
int get hashCode => request.hashCode;
}
class AvifCodecAdapter(final AvifCodec codec) implements ui.Codec {
@override
int get frameCount => codec.frameCount;
class AvifCodec(final AvifImageData data) implements ui.Codec {
var _frameIndex = 0;
@override
int get repetitionCount => frameCount > 1 ? -1 : 0;
int get frameCount => data.frames.length;
// libavif uses -2 for unknown, which we treat as infinite like browsers do
@override
int get repetitionCount =>
data.repetitionCount < 0 ? -1 : data.repetitionCount;
@override
Future<ui.FrameInfo> getNextFrame() async {
final frame = await codec.getNextFrame();
return AvifFrameInfo(frame.duration, frame.image);
Future<ui.FrameInfo> getNextFrame() {
final frame = data.frames[_frameIndex++ % frameCount];
final completer = Completer<ui.FrameInfo>();
ui.decodeImageFromPixels(
frame.rgba,
frame.width,
frame.height,
.rgba8888,
(image) => completer.complete(AvifFrameInfo(frame.duration, image)),
);
return completer.future;
}
@override
void dispose() => codec.dispose();
void dispose() {}
}
class AvifFrameInfo(