kingslay
KSPlayer
Swift

A video player for iOS、macOS、tvOS、visionOS , based on AVPlayer and FFmpeg, support HLG、HDR10、 HDR10+、Dolby Vision、Dolby Atmos、Text/Image subtitle.

Last updated Jul 7, 2026
1.6k
Stars
307
Forks
10
Issues
+9
Stars/day
Attention Score
92
Language breakdown
No language data available.
Files click to expand
README

Build Status Platform License

KSPlayer

KSPlayer is a powerful media play framework for iOS, tvOS, macOS, xrOS, visionOS, Mac Catalyst. based on AVPlayer and FFmpeg, support HLG、HDR10、 HDR10+、Dolby Vision、Dolby Atmos、Text/Image subtitle.

English | 简体中文

Communication

If you have a commercial project that requires a custom player, or would like to receive a paid consultation, please email me.

  • Email : kingslay@icloud.com

License

KSPlayer defaults to the GPL license (requires open-sourcing your own project code), and we hope everyone will consciously respect the licensing agreement of the KSPlayer project. Additionally, there is a paid version that adopts the LGPL license (contact us).

If due to commercial reasons, you prefer not to adhere to the GPL license or the LGPL license, you can contact us. Through our authorization, you can obtain a more flexible licensing agreement.

Features

Functional differences between GPL version and LGPL version. Some features of the LGPL version require a one-time payment, which I have used 💰 to mark them out.

To experience the powerful features of the LGPL version, you can download the app from the App Store. App Store Link

| Feature | LGPL | GPL | | ----------- | --------- | ------ | |Video upscaling |💰|❌| |ProgressBar Preview |💰|❌| |Precache data to Hard Drive|💰|❌| |Video output to another screen|💰|❌| |Video switching with zero delay|💰|❌| |Audio Passthrough Output by Wi-Fi|💰|❌| |Live streaming supports rewind viewing|💰|❌| |Blu-ray disc(ISO、DVD) playback on all Apple platforms|💰|❌| |Simultaneous playback of separate audio and video URLs|💰|❌| |Offline AI real-time subtitle generation and translation|💰|❌| |ProAVPlayer supports MKV, native Dolby Vision and Dolby Atmos.|💰|❌| |Native Dolby Vision dynamic metadata. P5、P8、P7(show single-layer)|💰|❌| |Play videos in a small window in the App (resumable, supports iOS and tvOS)|💰|❌| |Dolby AC-4|✅|❌| |Swift Concurrency|✅|❌| |Hardware De-interlace|✅|❌| |AV1 hardware decoding|✅|❌| |Word-by-word subtitles|✅|❌| |HDR10+(dynamic metadata)|✅|❌| |Text subtitle translation|✅|❌| |Use System Caption Appearance|✅|❌| |Record video clips at any time|✅|❌| |Smoothly Play 8K or 120 FPS Video|✅|❌| |Display Subtitles with HDR Effects|✅|❌| |Video download and format conversion|✅|❌| |External image subtitles, such as SUP|✅|❌| |Main subtitles and Secondary subtitles|✅|❌| |Adjust Saturation, Brightness, and Contrast|✅|❌| |Picture in Picture supports subtitle display|✅|❌| |Annex-B async hardware decoding(Live Stream)|✅|❌| |Use the fonts in the video to render subtitles|✅|❌| |Use memory cache for fast seek in short time range|✅|❌| |KSMEPlayer supports all demuxing and decoding formats|✅|❌| |Full display of ass subtitles effect(Render as image using libass)|✅|❌| |FFmpeg version|8.1.1|6.1.0| |Record video|✅|✅| |4k/HDR/HDR10|✅|✅| |360° panorama video|✅|✅| |Picture in Picture|✅|✅| |Hardware accelerator|✅|✅| |Seamless loop playback|✅|✅| |De-interlace auto detect|✅|✅| |Multichannel Audio/Spatial Audio|✅|✅| |Custom url protocols such as nfs/smb/UPnP |✅|✅| |Text subtitle/Image subtitle/Closed Captions|✅|✅| |Search Online Subtitles(shooter/assrt/opensubtitles)|✅|✅| |Low latency 4K live video streaming (less than 200ms on LAN)|✅|✅| |Automatically switch to multi-bitrate streams based on network|✅|✅|

Requirements

  • iOS 13+, macOS 10.15+, tvOS 13+, xrOS 1+

List of Apps Licensed to Use this SDK

This table does not list all licensed apps. If you would like to have your app listed above, please send me an email. | App Store Link | Logo | | -------------- | ---- | |APTV|| |homeTV IPTV Player|| |IPTV +|| |LillyPlayer Video Player|| |SenPlayer|| |Smart IPTV|| |Snappier IPTV|| |Spatial Video Studio|| |SWIPTV - IPTV Smart Player|| |TracyPlayer|| |UHF - Love your IPTV|| |Zen IPTV||

Demo

cd Demo
pod install
  • Open Demo/Demo.xcworkspace with Xcode.

Quick Start

CocoaPods

Make sure to use the latest version cocoapods 1.10.1+, which can be installed using the command brew install cocoapods

target 'ProjectName' do
    use_frameworks!
    pod 'KSPlayer',:git => 'https://github.com/kingslay/KSPlayer.git', :branch => 'main'
    pod 'DisplayCriteria',:git => 'https://github.com/kingslay/KSPlayer.git', :branch => 'main'
    pod 'FFmpegKit',:git => 'https://github.com/kingslay/FFmpegKit.git', :branch => 'main'
    pod 'Libass',:git => 'https://github.com/kingslay/FFmpegKit.git', :branch => 'main'
end

Swift Package Manager

dependencies: [
    .package(url: "https://github.com/kingslay/KSPlayer.git", .branch("main"))
]

Usage

Initialization

KSOptions.secondPlayerType = KSMEPlayer.self
playerView = IOSVideoPlayerView()
view.addSubview(playerView)
playerView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    playerView.topAnchor.constraint(equalTo: view.readableContentGuide.topAnchor),
    playerView.leftAnchor.constraint(equalTo: view.leftAnchor),
    playerView.rightAnchor.constraint(equalTo: view.rightAnchor),
    playerView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
playerView.backBlock = { [unowned self] in
    if UIApplication.shared.statusBarOrientation.isLandscape {
        self.playerView.updateUI(isLandscape: false)
    } else {
        self.navigationController?.popViewController(animated: true)
    }
}

Setting up a regular video

playerView.set(url:URL(string: "http://baobab.wdjcdn.com/14525705791193.mp4")!)
playerView.set(resource: KSPlayerResource(url: url, name: name!, cover: URL(string: "http://img.wdjimg.com/image/video/447f973848167ee5e44b67c8d4df983900.jpeg"), subtitleURL: URL(string: "http://example.ksplay.subtitle")))

Multi-definition, with cover video

let res0 = KSPlayerResourceDefinition(url: URL(string: "http://clips.vorwaerts-gmbh.de/bigbuckbunny.mp4")!,
                                      definition: "高清")
let res1 = KSPlayerResourceDefinition(url: URL(string: "http://clips.vorwaerts-gmbh.de/bigbuckbunny.mp4")!,
                                      definition: "标清")

let asset = KSPlayerResource(name: "Big Buck Bunny", definitions: [res0, res1], cover: URL(string: "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Bigbuckbunnyposterbig.jpg/848px-Bigbuckbunnyposterbig.jpg")) playerView.set(resource: asset)

Setting up an HTTP header

let options = KSOptions()
options.appendHeader(["Referer":"https:www.xxx.com"])
let definition = KSPlayerResourceDefinition(url: URL(string: "http://clips.vorwaerts-gmbh.de/bigbuckbunny.mp4")!,
                                            definition: "高清",
                                            options: options)
let asset = KSPlayerResource(name: "Video Name",
                             definitions: [definition])
playerView.set(resource: asset)

Listening status change

// Listen to play time change
playerView.playTimeDidChange = { (currentTime: TimeInterval, totalTime: TimeInterval) in
    print("playTimeDidChange currentTime: \(currentTime) totalTime: \(totalTime)")
}

// Delegates public protocol PlayerControllerDelegate: class { func playerController(state: KSPlayerState) func playerController(currentTime: TimeInterval, totalTime: TimeInterval) func playerController(finish error: Error?) func playerController(maskShow: Bool) func playerController(action: PlayerButtonType) // bufferedCount: 0 indicates first time loading func playerController(bufferedCount: Int, consumeTime: TimeInterval) }

Advanced Usage

  • ### Inherits PlayerView's custom play logic and UI.
class CustomVideoPlayerView: IOSVideoPlayerView {
      override func updateUI(isLandscape: Bool) {
          super.updateUI(isLandscape: isLandscape)
          toolBar.playbackRateButton.isHidden = true
      }

override func onButtonPressed(type: PlayerButtonType, button: UIButton) { if type == .landscape { // Your own button press behaviour here } else { super.onButtonPressed(type: type, button: button) } } }

  • ### Selecting Tracks
override open func player(layer: KSPlayerLayer, state: KSPlayerState) {
          super.player(layer: layer, state: state)
          if state == .readyToPlay, let player = layer.player {
              let tracks = player.tracks(mediaType: .audio)
              let track = tracks[1]
              /// the name of the track
              let name = track.name
              /// the language of the track
              let language = track.language
              /// selecting the one
              player.select(track: track)
          }
     }
  • ### Set the properties in KSOptions
open class KSOptions {
    /// 最低缓存视频时间
    @Published
    public var preferredForwardBufferDuration = KSOptions.preferredForwardBufferDuration
    /// 最大缓存视频时间
    public var maxBufferDuration = KSOptions.maxBufferDuration
    /// 是否开启秒开
    public var isSecondOpen = KSOptions.isSecondOpen
    /// 开启精确seek
    public var isAccurateSeek = KSOptions.isAccurateSeek
    /// Applies to short videos only
    public var isLoopPlay = KSOptions.isLoopPlay
    /// 是否自动播放,默认false
    public var isAutoPlay = KSOptions.isAutoPlay
    /// seek完是否自动播放
    public var isSeekedAutoPlay = KSOptions.isSeekedAutoPlay
    /*
     AVSEEKFLAGBACKWARD: 1
     AVSEEKFLAGBYTE: 2
     AVSEEKFLAGANY: 4
     AVSEEKFLAGFRAME: 8
     */
    public var seekFlags = Int32(0)
    // ffmpeg only cache http
    public var cache = false
    public var outputURL: URL?
    public var display = DisplayEnum.plane
    public var avOptions = [String: Any]()
    public var formatContextOptions = [String: Any]()
    public var decoderOptions = [String: Any]()
    public var probesize: Int64?
    public var maxAnalyzeDuration: Int64?
    public var lowres = UInt8(0)
    public var startPlayTime: TimeInterval = 0
    public var startPlayRate: Float = 1.0
    public var registerRemoteControll: Bool = true // 默认支持来自系统控制中心的控制
    public var referer: String?
    public var userAgent: String?
      // audio
    public var audioFilters = [String]()
    public var syncDecodeAudio = false
    // sutile
    public var autoSelectEmbedSubtitle = true
    public var subtitleDisable = false
    public var isSeekImageSubtitle = false
    // video
    public var videoDelay = 0.0 // s
    public var autoDeInterlace = false
    public var autoRotate = true
    public var destinationDynamicRange: DynamicRange?
    public var videoAdaptable = true
    public var videoFilters = [String]()
    public var syncDecodeVideo = false
    public var hardwareDecode = KSOptions.hardwareDecode
    public var asynchronousDecompression = true
    public var videoDisable = false
    public var canStartPictureInPictureAutomaticallyFromInline = true
  }

Effect

gif

Developments and Tests

Any contributing and pull requests are warmly welcome. However, before you plan to implement some features or try to fix an uncertain issue, it is recommended to open a discussion first. It would be appreciated if your pull requests could build and with all tests green. :)

Backers & Sponsors

Open-source projects cannot live long without your help. If you find KSPlayer to be useful, please consider supporting this project by becoming a sponsor.

Become a sponsor through GitHub Sponsors. :heart:

Your user icon or company logo shows up this with a link to your home page. |Name| App name | App Logo | | ----------- | ----------- |----------- | |UnknownCoder807|Snappier|| |skrew|| |Kimentanm|| |nakiostudio|UHF|| |CodingByJerez|| |andrefmsilva|| |romaingyh|Zen IPTV|| |FantasyKingdom|Senplayer|| |aart-rainey|| |nihalahmed|| |johnil|| |MeloDreek|| |nsplay1990|| |AppleChillVibez|| |stekc|| |AstroChivs|| |bmob222|| |pateltejas|| |ewanl2001|| |themisterholliday|| |JulienDev|| |Sheinices|| |Etheirystech|| |loicleser||

Thanks to nightfall708 for sponsoring a mac mini

Thanks to cdguy UnknownCoder807 skrew and LillyPlayer community for sponsoring a LG S95QR Sound Bar

Thanks to skrew and LillyPlayer community for sponsoring a 2022 Apple TV 4K

Thanks to bgoncal for sponsoring a HomePod mini

1

© 2026 GitRepoTrend · kingslay/KSPlayer · Updated daily from GitHub