From dd7696e7c63867f202d248bba7467ce89a66fd9e Mon Sep 17 00:00:00 2001 From: pabloFuente Date: Mon, 2 Nov 2026 12:16:01 +0100 Subject: [PATCH] openvidu-test-e2e: decode AV1 recordings one frame at a time av1TrackEgressTest's L3T3 case failed in every CI run on the mediasoup engine: "Every presented packet must decode to one frame" (174 of 178, 171 of 175). The recordings are valid. The egress recorded part of the track on S1, below the top spatial layer of the sequence header. Run with frame threading (ffmpeg's default), dav1d outputs no picture for some temporal units of that part, since Matroska has no temporal delimiters to close a unit. The 4 frames missing in each file were T2 frames of the S1 part. assertHealthyVideoRecording now runs libdav1d with -max_frame_delay 1, which decodes one frame at a time, as WebRTC receivers do. Co-Authored-By: Claude Opus 5.5 --- .../openvidu/test/e2e/AbstractOpenViduTestappE2eTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/AbstractOpenViduTestappE2eTest.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/AbstractOpenViduTestappE2eTest.java index 90d0bc973..5bc4e30ab 100644 --- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/AbstractOpenViduTestappE2eTest.java +++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/AbstractOpenViduTestappE2eTest.java @@ -1233,12 +1233,16 @@ public class AbstractOpenViduTestappE2eTest extends OpenViduTestE2e { // Decode every frame: no errors, the picture moves (Chrome's fake camera changes // on every frame) and reaches the published size. VP9 goes through libvpx, the // decoder of browsers and GStreamer: FFmpeg's own shows only the base layer of a - // VP9 SVC superframe. AV1 goes through dav1d: FFmpeg's own needs hardware + // VP9 SVC superframe. AV1 goes through dav1d: FFmpeg's own needs hardware. It + // decodes one frame at a time, as WebRTC receivers do: with frame threading, a + // temporal unit of an SVC track recorded below the top spatial layer of its + // sequence header sometimes outputs no picture, since Matroska has no temporal + // delimiters to close the unit (4 T2 frames of the S1 part of an L3T3 track) List command = new ArrayList<>(List.of("ffmpeg", "-nostdin", "-loglevel", "level+info")); if ("vp9".equals(codec)) { command.addAll(List.of("-c:v", "libvpx-vp9")); } else if ("av1".equals(codec)) { - command.addAll(List.of("-c:v", "libdav1d")); + command.addAll(List.of("-c:v", "libdav1d", "-max_frame_delay", "1")); } command.addAll(List.of("-i", file.toString(), "-map", "0:v", "-vf", "showinfo", "-fps_mode", "passthrough", "-enc_time_base", "demux", "-f", "null", "-"));