Open Bug 2016484 Opened 1 day ago Updated 23 hours ago

High-bitrate AV1 freezes: DAV1DDecoder::InvokeDecode busy-waits on dav1d EAGAIN instead of draining frames

Categories

(Core :: Audio/Video: Playback, defect)

defect

Tracking

()

UNCONFIRMED

People

(Reporter: bran.perch-07, Unassigned)

Details

Attachments

(1 file)

Summary

High-bitrate AV1 video (30+ Mbps, 4K) freezes after a few seconds of playback when using the dav1d software decoder. The freeze timing varies with bitrate but is consistently reproducible.

Root Cause

DAV1DDecoder::InvokeDecode has a do/while loop that calls dav1d_send_data followed by a single dav1d_get_picture. When dav1d_send_data returns DAV1D_ERR(EAGAIN) (internal buffer full, no data consumed) and dav1d_get_picture also returns DAV1D_ERR(EAGAIN) (no completed frame yet), the continue statement loops back to retry dav1d_send_data immediately -- but nothing has changed. This creates a tight busy-wait spin loop with no yield that competes with dav1d's own frame decode threads for CPU time.

On high-bitrate content where software AV1 decode already needs every CPU cycle, this busy-wait starves the decode threads, preventing them from completing the frames that would unblock the pipeline. The result is a vicious cycle where decode falls further behind until playback freezes.

Two issues in the current code:

  1. Single frame drain per iteration: Only one GetPicture() call per loop iteration, even when dav1d_send_data returned EAGAIN (buffer full). When the buffer is full there may be multiple completed frames waiting -- retrieving only one means multiple outer loop iterations with failed dav1d_send_data calls before the buffer has room.

  2. No yield on double-EAGAIN: When both dav1d_send_data and dav1d_get_picture return EAGAIN, the loop spins with no yield. Frames are in-flight on dav1d's decode threads but the busy-wait contends for CPU time those threads need to finish.

Fix

Replace the single GetPicture() call with a draining loop (matching the pattern already used in DAV1DDecoder::Drain()), and add std::this_thread::yield() when dav1d_send_data returned EAGAIN and no frames were available to drain.

Steps to Reproduce

  1. Play a high-bitrate AV1 video (30+ Mbps, 4K) with hardware AV1 decode disabled (to force dav1d software path)
  2. Video freezes within a few seconds
  3. Lower bitrate content may not trigger the issue because dav1d can keep up without EAGAIN contention
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: