Files
streamyfin/docs/ks-player/KSOptions.md

9.6 KiB

KSOptions

KSOptions is the configuration class for KSPlayer. It contains both instance properties (per-player settings) and static properties (global defaults).

Creating Options

let options = KSOptions()

// Configure instance properties
options.isLoopPlay = true
options.startPlayTime = 30.0  // Start at 30 seconds

// Use with player
playerView.set(url: url, options: options)

Instance Properties

Buffering

Property Type Default Description
preferredForwardBufferDuration TimeInterval 3.0 Minimum buffer duration before playback starts
maxBufferDuration TimeInterval 30.0 Maximum buffer duration
isSecondOpen Bool false Enable fast open (instant playback)

Seeking

Property Type Default Description
isAccurateSeek Bool false Enable frame-accurate seeking
seekFlags Int32 1 FFmpeg seek flags (AVSEEK_FLAG_BACKWARD)
isSeekedAutoPlay Bool true Auto-play after seeking

Playback

Property Type Default Description
isLoopPlay Bool false Loop playback (for short videos)
startPlayTime TimeInterval 0 Initial playback position (seconds)
startPlayRate Float 1.0 Initial playback rate
registerRemoteControll Bool true Enable system remote control

Video

Property Type Default Description
display DisplayEnum .plane Display mode (.plane, .vr, .vrBox)
videoDelay Double 0.0 Video delay in seconds
autoDeInterlace Bool false Auto-detect interlacing
autoRotate Bool true Auto-rotate based on metadata
destinationDynamicRange DynamicRange? nil Target HDR mode
videoAdaptable Bool true Enable adaptive bitrate
videoFilters [String] [] FFmpeg video filters
syncDecodeVideo Bool false Synchronous video decoding
hardwareDecode Bool true Use hardware decoding
asynchronousDecompression Bool false Async hardware decompression
videoDisable Bool false Disable video track

Audio

Property Type Default Description
audioFilters [String] [] FFmpeg audio filters
syncDecodeAudio Bool false Synchronous audio decoding

Subtitles

Property Type Default Description
autoSelectEmbedSubtitle Bool true Auto-select embedded subtitles
isSeekImageSubtitle Bool false Seek for image subtitles

Picture-in-Picture

Property Type Default Description
canStartPictureInPictureAutomaticallyFromInline Bool true Auto-start PiP when app backgrounds

Window (macOS)

Property Type Default Description
automaticWindowResize Bool true Auto-resize window to video aspect ratio

Network/HTTP

Property Type Default Description
referer String? nil HTTP referer header
userAgent String? "KSPlayer" HTTP user agent
cache Bool false Enable FFmpeg HTTP caching
outputURL URL? nil URL to record/save stream

FFmpeg Options

Property Type Default Description
avOptions [String: Any] [:] AVURLAsset options
formatContextOptions [String: Any] See below FFmpeg format context options
decoderOptions [String: Any] See below FFmpeg decoder options
probesize Int64? nil FFmpeg probe size
maxAnalyzeDuration Int64? nil Max analyze duration
lowres UInt8 0 Low resolution decoding
nobuffer Bool false Disable buffering
codecLowDelay Bool false Low delay codec mode

Default formatContextOptions

[
    "user_agent": "KSPlayer",
    "scan_all_pmts": 1,
    "reconnect": 1,
    "reconnect_streamed": 1
]

Default decoderOptions

[
    "threads": "auto",
    "refcounted_frames": "1"
]

Read-Only Timing Properties

Property Type Description
formatName String Detected format name
prepareTime Double Time when prepare started
dnsStartTime Double DNS lookup start time
tcpStartTime Double TCP connection start time
tcpConnectedTime Double TCP connected time
openTime Double File open time
findTime Double Stream find time
readyTime Double Ready to play time
readAudioTime Double First audio read time
readVideoTime Double First video read time
decodeAudioTime Double First audio decode time
decodeVideoTime Double First video decode time

Static Properties (Global Defaults)

Player Types

// Primary player type (default: AVPlayer)
KSOptions.firstPlayerType: MediaPlayerProtocol.Type = KSAVPlayer.self

// Fallback player type (default: FFmpeg)
KSOptions.secondPlayerType: MediaPlayerProtocol.Type? = KSMEPlayer.self

Buffering Defaults

KSOptions.preferredForwardBufferDuration: TimeInterval = 3.0
KSOptions.maxBufferDuration: TimeInterval = 30.0
KSOptions.isSecondOpen: Bool = false

Playback Defaults

KSOptions.isAccurateSeek: Bool = false
KSOptions.isLoopPlay: Bool = false
KSOptions.isAutoPlay: Bool = true
KSOptions.isSeekedAutoPlay: Bool = true

Decoding

KSOptions.hardwareDecode: Bool = true
KSOptions.asynchronousDecompression: Bool = false
KSOptions.canStartPictureInPictureAutomaticallyFromInline: Bool = true

UI Options

// Top bar visibility: .always, .horizantalOnly, .none
KSOptions.topBarShowInCase: KSPlayerTopBarShowCase = .always

// Auto-hide controls delay
KSOptions.animateDelayTimeInterval: TimeInterval = 5.0

// Gesture controls
KSOptions.enableBrightnessGestures: Bool = true
KSOptions.enableVolumeGestures: Bool = true
KSOptions.enablePlaytimeGestures: Bool = true

// Background playback
KSOptions.canBackgroundPlay: Bool = false

PiP

KSOptions.isPipPopViewController: Bool = false

Logging

// Log levels: .panic, .fatal, .error, .warning, .info, .verbose, .debug, .trace
KSOptions.logLevel: LogLevel = .warning
KSOptions.logger: LogHandler = OSLog(lable: "KSPlayer")

System

KSOptions.useSystemHTTPProxy: Bool = true
KSOptions.preferredFrame: Bool = true

Subtitle Data Sources

KSOptions.subtitleDataSouces: [SubtitleDataSouce] = [DirectorySubtitleDataSouce()]

Methods

HTTP Headers

let options = KSOptions()
options.appendHeader(["Referer": "https://example.com"])
options.appendHeader(["Authorization": "Bearer token123"])

Cookies

let cookies = [HTTPCookie(properties: [
    .name: "session",
    .value: "abc123",
    .domain: "example.com",
    .path: "/"
])!]
options.setCookie(cookies)

Overridable Methods

Subclass KSOptions to customize behavior:

Buffering Algorithm

class CustomOptions: KSOptions {
    override func playable(capacitys: [CapacityProtocol], isFirst: Bool, isSeek: Bool) -> LoadingState {
        // Custom buffering logic
        super.playable(capacitys: capacitys, isFirst: isFirst, isSeek: isSeek)
    }
}

Adaptive Bitrate

override func adaptable(state: VideoAdaptationState?) -> (Int64, Int64)? {
    // Return (currentBitrate, targetBitrate) or nil
    super.adaptable(state: state)
}

Track Selection

// Select preferred video track
override func wantedVideo(tracks: [MediaPlayerTrack]) -> Int? {
    // Return index of preferred track or nil for auto
    return tracks.firstIndex { $0.bitRate > 5_000_000 }
}

// Select preferred audio track  
override func wantedAudio(tracks: [MediaPlayerTrack]) -> Int? {
    // Return index of preferred track or nil for auto
    return tracks.firstIndex { $0.languageCode == "en" }
}

Display Layer

override func isUseDisplayLayer() -> Bool {
    // Return true to use AVSampleBufferDisplayLayer (supports HDR10+)
    // Return false for other display modes
    display == .plane
}

Track Processing

override func process(assetTrack: some MediaPlayerTrack) {
    super.process(assetTrack: assetTrack)
    // Custom processing before decoder creation
}

Live Playback Rate

override func liveAdaptivePlaybackRate(loadingState: LoadingState) -> Float? {
    // Return adjusted playback rate for live streams
    // Return nil to keep current rate
    if loadingState.loadedTime > preferredForwardBufferDuration + 5 {
        return 1.2  // Speed up if too far behind
    }
    return nil
}

Example: Custom Options

class StreamingOptions: KSOptions {
    override init() {
        super.init()
        
        // Low latency settings
        preferredForwardBufferDuration = 1.0
        isSecondOpen = true
        nobuffer = true
        codecLowDelay = true
        
        // Custom headers
        appendHeader(["X-Custom-Header": "value"])
    }
    
    override func wantedAudio(tracks: [MediaPlayerTrack]) -> Int? {
        // Prefer English audio
        return tracks.firstIndex { $0.languageCode == "en" }
    }
}

// Usage
let options = StreamingOptions()
playerView.set(url: streamURL, options: options)