Skip to content

Software-decoded video renderer silently stops accepting frames (ready=false) on a packed-bitstream XviD/MPEG-4 AVI — audio keeps playing, video freezes on the loading spinner #298

Description

@akacores

What happened?

Playing an .avi file with codec=mpeg4 (XviD, "packed bitstream" variant) starts audio playback normally, but no video frame after the first one ever reaches the screen. The host app is left showing its loading spinner indefinitely while audio continues. No error is ever surfaced — AetherEngine's $state publisher never transitions to .error, so the host app has no way to detect or recover from this.

  • AetherEngine version: 6.6.0 (Swift Package, https://github.com/superuser404notfound/AetherEngine)
  • tvOS 26.0, Apple TV 4K (3rd generation) Simulator, 1080p
  • Swift 6.2, Xcode (tvOS 26.5 SDK)
  • Host app integration: AetherEngine() created per-playback, load(url:options:), $state observed via Combine — see reproduction context below.

Source file

Demuxer opened: 2 streams, duration=1292482883 us
  stream[0] type=video codec=mpeg4 544x400
  stream[1] type=audio codec=mp2

Delivered over HTTP (range requests, AVIOReader pump), .avi container, video track is MPEG-4 Part 2 (XviD) at 544×400, audio is MP2 at 44.1kHz/2ch. Filename: Sabrina, cosas de brujas 1x01 - El cumpleaños de Sabrina.avi.

Steps to reproduce

  1. Load and play an AVI file whose video track is a "packed" XviD/MPEG-4 bitstream (B-frames stored in the older "packed" layout).
  2. Playback starts: audio is audible immediately.
  3. Exactly one video frame is decoded, enqueued, and rendered.
  4. Within ~1.3s, the renderer's ready flag flips to false and never recovers — no further frames are displayed, though decode/enqueue calls keep being logged.
  5. The host app (which shows a loading spinner until it receives a non-nil player/engine reference and an actual rendered frame) is stuck on that spinner for the rest of the file's duration, while audio plays normally.

Expected behavior

Either:

  • Frames continue to be decoded and rendered normally (packed XviD is an old but well-documented format — FFmpeg's own mpeg4 decoder has explicit (if imperfect) handling for it), or
  • If the stream is genuinely unrecoverable, AetherEngine's state publisher should transition to .error so the host app can show an error instead of hanging forever on "loading."

Actual behavior

Video rendering silently stalls with no error signaled anywhere. Audio pipeline is completely unaffected and keeps playing to completion.

Relevant logs (verbatim, de.superuser404.AetherEngine + related CoreMedia/AVKit subsystems, log stream --predicate 'process == "coreshub"' --style compact --level debug)

Session start — dispatched to the software decode path (expected, since AVFoundation has no native XviD/MPEG-4-in-AVI decoder):

[AetherEngine] load url=https://.../Sabrina%2C%20cosas%20de%20brujas%201x01%20-%20El%20cumplea%C3%B1os%20de%20Sabrina.avi?api_key=... source-format=sdr effective-format=sdr rate=23.976
[AetherEngine] dispatch: codec=12 → software
[AetherEngine] renderer audio session active: sourceCh=2 maxChannels=2 preferred=2 output=2
[SWHost] session start: videoCodecID=12 audioCodecID=86016 duration=1292.5s
[SWDecoder] Opened: 544x400, codec=mpeg4, threads=8, 8-bit
[AudioDecoder] Opened: 44100Hz, 2ch, codec=mp2
[AudioDecoder] Resampler ready: 44100Hz, 2ch, inFmt=6

Audio starts fine and keeps going (no further issues logged for this path for the rest of the session):

[AudioOutput] first enqueue: 44100.0Hz 2ch, 1152 samples, renderer.error=nil
[AudioOutput] seekClock to=0.000 rate=1.0

First video frame is decoded and rendered successfully:

[SWHost] first video frame enqueued: pixfmt=0x34323076 size=544x400 pts=0.042s
<<<< AVSampleBufferVideoRenderer >>>> -[AVSampleBufferVideoRenderer _setStatus:error:]_block_invoke: <VR/PEK|0x11670d2a0> Change status from Unknown to Rendering with success
[Renderer] enqueue #1: status=rendering ready=true error=nil

~1.3s later, ready flips to false and never recovers — this is the actual bug, reproduced identically at two later checkpoints ~3.5s apart, with no error ever attached:

[Renderer] enqueue #30: status=rendering ready=false error=nil       (t≈+1.37s)
[Renderer] enqueue #100: status=rendering ready=false error=nil      (t≈+4.74s)

FFmpeg's own decoder logs three warnings during this window, strongly suggesting the packed-bitstream handling is where this goes wrong:

[de.superuser404.AetherEngine:ffmpeg] [mpeg4 @ 0x11c712710] [warning] Discarding excessive bitstream in packed xvid
[de.superuser404.AetherEngine:ffmpeg] [mpeg4 @ 0x122006270] [warning] Discarding excessive bitstream in packed xvid
[de.superuser404.AetherEngine:ffmpeg] [mpeg4 @ 0x12200c380] [warning] Discarding excessive bitstream in packed xvid

For context, AVKit's own now-playing controls logic confirms the host is stuck in a perpetual "loading" state from the very start of this session (playerItem.status=0 = unknown, never progresses):

-[AVNowPlayingPlaybackControlsViewController _updateLoadingAndErrorIndicators_NoTimeline] spinner: playerItem.status=0, timeControlStatus=0, loading=YES, isSeeking=NO, isEffectiveRateNonZero=false

(There are also several -[AVPlayerViewController _becomeNowPlaying] denied: Error Domain=AVFoundationErrorDomain Code=-11862 "no player item" lines in the same window — these look like benign timing noise during the load transition, not the root cause, since they all cluster within milliseconds of session start and audio playback proceeds normally afterward. Flagging them only for completeness.)

Hypothesis

The software decode path's handling of packed XviD bitstreams (mpeg4 codec, B-frames stored in the pre-DivX-5/legacy "packed" layout) appears to desynchronize the renderer after the first frame — the FFmpeg decoder itself logs Discarding excessive bitstream in packed xvid, and immediately after, the Renderer's ready flag gets stuck at false for the rest of playback, even though decode/enqueue calls keep happening (audio is unaffected, confirming the demux/read/audio-decode pipeline is healthy — this is isolated to the video renderer's frame acceptance after the packed-bitstream discard).

Suggested improvements regardless of root cause

  1. Surface an .error state (or at least a distinct "stalled"/"no video" state) when the renderer's ready flag stays false for an extended period after having previously been true — right now the host app has no signal at all and can only detect this via a user-visible symptom (audio with no video).
  2. Consider routing AetherEngine's internal logging through os_log/Logger with a stable subsystem name if not already fully doing so — the de.superuser404.AetherEngine:* subsystems captured here were the only reason this was diagnosable at all; a plain print()-only path would leave zero trace for a downstream integrator.

Additional info available on request

  • Full log stream capture (33k+ lines, this excerpt is a small slice) for this exact repro if useful.
  • Happy to test a patched build/branch against this same file.

AetherEngine version or commit SHA

6.6.0

Host app

Custom / my own integration

Platform

tvOS

OS version

tvOS 26.0

Device / chip

Apple TV 4K (3rd generation)

Playback path

Software (dav1d) host

Source media (for playback bugs)

AVI, MPEG-4 Part 2 (XviD, packed bitstream), 544x400, SDR, MP2 audio 44.1kHz 2ch

Error codes / log lines

[Renderer] enqueue #1: status=rendering ready=true error=nil
[Renderer] enqueue #30: status=rendering ready=false error=nil
[Renderer] enqueue #100: status=rendering ready=false error=nil

[mpeg4 @ 0x11c712710] [warning] Discarding excessive bitstream in packed xvid
[mpeg4 @ 0x122006270] [warning] Discarding excessive bitstream in packed xvid
[mpeg4 @ 0x12200c380] [warning] Discarding excessive bitstream in packed xvid

-[AVNowPlayingPlaybackControlsViewController _updateLoadingAndErrorIndicators_NoTimeline] spinner: playerItem.status=0, timeControlStatus=0, loading=YES, isSeeking=NO, isEffectiveRateNonZero=false

Anything else

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions