mirror of
https://github.com/dirtydishes/dreamio.git
synced 2026-06-06 13:37:24 +00:00
add native player controls and captions
This commit is contained in:
parent
75e76e14d4
commit
419ffae415
9 changed files with 1096 additions and 4 deletions
|
|
@ -16,10 +16,13 @@ final class VLCNativePlaybackBackend: NSObject, NativePlaybackBackend {
|
|||
let view = UIView()
|
||||
var onReady: (() -> Void)?
|
||||
var onFailure: ((Error) -> Void)?
|
||||
var onStateChange: (() -> Void)?
|
||||
var onSubtitleTracksChange: (() -> Void)?
|
||||
|
||||
#if canImport(MobileVLCKit)
|
||||
private let mediaPlayer = VLCMediaPlayer()
|
||||
#endif
|
||||
private var attachedSubtitleURLs = Set<URL>()
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
|
|
@ -54,11 +57,61 @@ final class VLCNativePlaybackBackend: NSObject, NativePlaybackBackend {
|
|||
print("[DreamioVLC] opening url=\(URLRedactor.redactedURLString(request.playbackURL.absoluteString))")
|
||||
#endif
|
||||
mediaPlayer.play()
|
||||
attachSubtitles(request.subtitleCandidates)
|
||||
#else
|
||||
onFailure?(NativePlaybackError.backendUnavailable)
|
||||
#endif
|
||||
}
|
||||
|
||||
func play() {
|
||||
#if canImport(MobileVLCKit)
|
||||
mediaPlayer.play()
|
||||
#endif
|
||||
}
|
||||
|
||||
func pause() {
|
||||
#if canImport(MobileVLCKit)
|
||||
mediaPlayer.pause()
|
||||
#endif
|
||||
}
|
||||
|
||||
func togglePlayPause() {
|
||||
isPlaying ? pause() : play()
|
||||
}
|
||||
|
||||
func seek(to position: Float) {
|
||||
#if canImport(MobileVLCKit)
|
||||
guard isSeekable else {
|
||||
return
|
||||
}
|
||||
mediaPlayer.position = max(0, min(1, position))
|
||||
#endif
|
||||
}
|
||||
|
||||
func jump(by seconds: TimeInterval) {
|
||||
#if canImport(MobileVLCKit)
|
||||
guard isSeekable else {
|
||||
return
|
||||
}
|
||||
let nextTime = max(0, min(duration, currentTime + seconds))
|
||||
mediaPlayer.time = VLCTime(int: Int32(nextTime * 1000))
|
||||
#endif
|
||||
}
|
||||
|
||||
func selectSubtitleTrack(id: Int32) {
|
||||
#if canImport(MobileVLCKit)
|
||||
mediaPlayer.currentVideoSubTitleIndex = id
|
||||
onSubtitleTracksChange?()
|
||||
#endif
|
||||
}
|
||||
|
||||
func adjustSubtitleDelay(by seconds: TimeInterval) {
|
||||
#if canImport(MobileVLCKit)
|
||||
mediaPlayer.currentVideoSubTitleDelay += Int(seconds * 1_000_000)
|
||||
onSubtitleTracksChange?()
|
||||
#endif
|
||||
}
|
||||
|
||||
func stop() {
|
||||
#if canImport(MobileVLCKit)
|
||||
mediaPlayer.stop()
|
||||
|
|
@ -66,6 +119,93 @@ final class VLCNativePlaybackBackend: NSObject, NativePlaybackBackend {
|
|||
mediaPlayer.media = nil
|
||||
#endif
|
||||
}
|
||||
|
||||
var isPlaying: Bool {
|
||||
#if canImport(MobileVLCKit)
|
||||
mediaPlayer.isPlaying
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
}
|
||||
|
||||
var isSeekable: Bool {
|
||||
#if canImport(MobileVLCKit)
|
||||
mediaPlayer.isSeekable
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
}
|
||||
|
||||
var duration: TimeInterval {
|
||||
#if canImport(MobileVLCKit)
|
||||
TimeInterval(max(0, mediaPlayer.media?.length.intValue ?? 0)) / 1000
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
}
|
||||
|
||||
var currentTime: TimeInterval {
|
||||
#if canImport(MobileVLCKit)
|
||||
TimeInterval(max(0, mediaPlayer.time.intValue)) / 1000
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
}
|
||||
|
||||
var remainingTime: TimeInterval {
|
||||
max(0, duration - currentTime)
|
||||
}
|
||||
|
||||
var position: Float {
|
||||
#if canImport(MobileVLCKit)
|
||||
mediaPlayer.position
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
}
|
||||
|
||||
var subtitleTracks: [SubtitleTrack] {
|
||||
#if canImport(MobileVLCKit)
|
||||
let names = mediaPlayer.videoSubTitlesNames as? [String] ?? []
|
||||
let indexes = mediaPlayer.videoSubTitlesIndexes as? [NSNumber] ?? []
|
||||
return zip(indexes, names).map { index, name in
|
||||
SubtitleTrack(id: index.int32Value, name: name)
|
||||
}
|
||||
#else
|
||||
[]
|
||||
#endif
|
||||
}
|
||||
|
||||
var selectedSubtitleTrackID: Int32 {
|
||||
#if canImport(MobileVLCKit)
|
||||
mediaPlayer.currentVideoSubTitleIndex
|
||||
#else
|
||||
-1
|
||||
#endif
|
||||
}
|
||||
|
||||
var subtitleDelay: TimeInterval {
|
||||
#if canImport(MobileVLCKit)
|
||||
TimeInterval(mediaPlayer.currentVideoSubTitleDelay) / 1_000_000
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
}
|
||||
|
||||
#if canImport(MobileVLCKit)
|
||||
private func attachSubtitles(_ candidates: [SubtitleCandidate]) {
|
||||
candidates.forEach { candidate in
|
||||
guard !attachedSubtitleURLs.contains(candidate.url) else {
|
||||
return
|
||||
}
|
||||
attachedSubtitleURLs.insert(candidate.url)
|
||||
mediaPlayer.addPlaybackSlave(candidate.url, type: .subtitle, enforce: false)
|
||||
#if DEBUG
|
||||
print("[DreamioVLC] attached subtitle=\(URLRedactor.redactedURLString(candidate.url.absoluteString))")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if canImport(MobileVLCKit)
|
||||
|
|
@ -77,8 +217,13 @@ extension VLCNativePlaybackBackend: VLCMediaPlayerDelegate {
|
|||
switch mediaPlayer.state {
|
||||
case .buffering, .playing:
|
||||
onReady?()
|
||||
onStateChange?()
|
||||
case .error:
|
||||
onFailure?(NativePlaybackError.playbackFailed)
|
||||
case .paused, .stopped, .ended:
|
||||
onStateChange?()
|
||||
case .esAdded:
|
||||
onSubtitleTracksChange?()
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue