PrismCore / API reference / Previews and cached media

Actor

SeekPreviewService

actor SeekPreviewService

Declared in Sources/PrismCore/Preview/SeekPreviewService.swift · PrismCore 3.5.4

Scrub-bar thumbnails for any source libavformat can open — the floating frame a player HUD shows while the user drags the seek bar.

This is deliberately its own small pipeline, not a reuse of the playback paths, and independent of which engine is actually playing the title:

  • It opens its own context. An AVFormatContext is not safe for concurrent use, and the producer's is busy producing — a thumbnail request must never stall playback, only itself.
  • It decodes on the CPU only. A thumbnail is one keyframe scaled to ~300 px: VideoToolbox would win milliseconds and cost a hardware session per preview strip, plus the fallback complexity playback genuinely needs and this doesn't. sws_scale also IS the delivery format step — the decode and the downscale are one pipeline stage here.
  • The image comes back as a CGImage, because the only consumer is a HUD about to draw it. No CVPixelBuffer, no CMSampleBuffer — those exist for renderers.

A request decodes the keyframe at-or-before the timestamp (av_seek_frame BACKWARD lands there; keyframes decode standalone, so one packet usually suffices) and the result is cached by the keyframe's PTS: scrubbing within one GOP is a dictionary hit, not a decode. When the source has a harvested keyframe map (KeyframeIndexCache, issue #34), requests resolve to their keyframe before seeking, so even the first touch of a GOP that is already cached skips the demuxer entirely.

Known caveats, accepted for v1: HDR (PQ/HLG) sources are converted by matrix, not tone-mapped — previews look flatter than the picture. Dolby Vision Profile 5 (IPT-PQc2) has no honest RGB conversion here at all; the host should not offer engine previews for P5 (SourceInfo says).

Initializers

init(url: URL, httpHeaders: [String : String] = [:], maxDimension: Int = 320, keyframeIndexCacheDirectory: URL? = nil, keyframeIndexCacheIdentity: SourceCacheIdentity? = nil, coordinatedHTTP: Bool = false, input: PrismCoreInputFactory? = nil)

No documentation comment in the source.

Instance methods

func close()

Tear the demuxer and decoder down now. Idempotent; later requests throw .closed.

func thumbnail(at seconds: Double) async throws -> CGImage

The thumbnail for the keyframe at-or-before seconds.

Serial by actor design: a scrub sweep queues its requests, and each is one keyframe's decode. Callers that only want the newest position should cancel superseded tasks — cancellation is honoured between the seek and the decode.

Enumeration

SeekPreviewService.Failure

enum Failure

No documentation comment in the source.

Cases

case closed

The service was closed; requests after close() are a caller bug.

case undecodable(String)

The source has no video stream, or its codec has no decoder in this FFmpeg build.

case noFrame

The demuxer delivered no decodable keyframe near the timestamp — a truncated tail, or a seek the transport couldn't do.

Generated from the public symbols of PrismCore 3.5.4. All types