6.6.3 - A software session that decodes into nothing says so
One diagnostic addition and one hardening on the software playback path, from a field report on 6.6.0. No API change.
Added
-
A software session says when its frames are decoding into nothing. The software path renders into an
AVSampleBufferDisplayLayerthe engine owns, and that layer reaches the screen only once the host binds a surface, eitherbind(view:)with anAetherPlayerVieworAetherPlayerSurfacein SwiftUI. A host that presents anAVPlayerViewControllerfor a software-routed source instead gets audio, a completely healthy engine log, and no picture, because this path has noAVPlayerItemfor AVKit to show; a layer bound to a view that never got a layout looks identical from the outside. Neither left a trace. Both are now named once per session, about two seconds after frames start flowing, with the count of frames that went nowhere:[SWHost] 50 frames decoded into a display layer that is in no view hierarchy: the host never bound a render surface (AetherEngine.bind(view:) / AetherPlayerSurface). The software path renders into that layer, not through AVPlayerViewController, so audio plays and no picture can appear [SWHost] display layer is bound but sized 0x0 after 50 frames: the bound view has no layout, so no frame can be visibleReported by @akacores as a renderer that stops accepting frames (#298). Worth stating for anyone reading a similar log, because the quoted signature is what a healthy session prints:
[Renderer] enqueue #1: status=rendering ready=true error=nil [Renderer] enqueue #30: status=rendering ready=false error=nil (t+1.37s) [Renderer] enqueue #100: status=rendering ready=false error=nil (t+4.74s)isReadyForMoreMediaDatais the demux loop's back-pressure gate, which parks before feeding a video packet, so a full queue immediately after an enqueue is the gate working. #100 at t+4.74s on a 23.976 fps source is real-time pacing, and audio and video are fed by the same loop: a queue that had stopped draining would have parked that loop within one queue depth and stopped the audio with it.
Changed
-
A frame whose presentation timestamp is not numeric no longer reaches the display queue.
AV_NOPTS_VALUEarrives at the renderer asCMTime.invalid, and CoreMedia builds a sample buffer from it without complaint (CMSampleBufferCreateReadyWithImageBufferreturnsnoErr, the sample's PTS reads back as NaN seconds), so the render synchronizer was the first thing in the chain that could not schedule it. The deinterlace path has dropped its own untimestamped output for that reason since it was added; this is the same rule one layer lower, before the B-frame reorder buffer, where such a frame additionally reordered its neighbours because every comparison against NaN is false. Drops are counted and named:[Renderer] dropped N frame(s) with no usable timestamp (unschedulable)Hardening rather than a fix for the report above: the demuxer opens with
fflags +genpts, so a container that carries no presentation timestamps of its own (AVI with B-frames, the reported case) has them regenerated before the decoder sees them (#298).
Verifying it
aetherctl play --sw <url> on any software-routed source prints the new line at about t+2s, because the CLI binds no render surface at all. aetherctl pktdump <url> answers the timestamp half: NOPTS_pts counts what actually reaches the decoder, which is not what ffprobe reports on the same file unless it is given -fflags +genpts too.