commit 35c581066a748e68478359aba37bafcd42d519e3
parent d6c72403a3598531c019a54462e82c0c1775df9c
Author: Fishcake <me@fshck.com>
Date: Tue, 26 Sep 2023 16:14:18 +0900
fix video size detection, and audio track detection to work with HLS, add live stream indicator
Closes: https://github.com/damus-io/damus/pull/1560
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
2 files changed, 64 insertions(+), 14 deletions(-)
diff --git a/damus/Views/Video/DamusVideoPlayer.swift b/damus/Views/Video/DamusVideoPlayer.swift
@@ -43,6 +43,9 @@ struct DamusVideoPlayer: View {
if model.has_audio {
mute_button
}
+ if model.is_live {
+ live_indicator
+ }
}
.onChange(of: centerY) { _ in
update_is_visible(centerY: centerY)
@@ -93,6 +96,25 @@ struct DamusVideoPlayer: View {
}
}
}
+
+ private var live_indicator: some View {
+ VStack {
+ HStack {
+ Text("LIVE")
+ .bold()
+ .foregroundColor(.red)
+ .padding(.horizontal)
+ .padding(.vertical, 5)
+ .background(
+ Capsule()
+ .fill(Color.black.opacity(0.5))
+ )
+ .padding([.top, .leading])
+ Spacer()
+ }
+ Spacer()
+ }
+ }
}
struct DamusVideoPlayer_Previews: PreviewProvider {
static var previews: some View {
diff --git a/damus/Views/Video/DamusVideoPlayerViewModel.swift b/damus/Views/Video/DamusVideoPlayerViewModel.swift
@@ -10,16 +10,15 @@ import Combine
import Foundation
import SwiftUI
-func get_video_size(player: AVPlayer) async -> CGSize? {
- let res = Task.detached(priority: .background) {
- return player.currentImage?.size
- }
- return await res.value
-}
-
func video_has_audio(player: AVPlayer) async -> Bool {
- let tracks = try? await player.currentItem?.asset.load(.tracks)
- return tracks?.filter({ t in t.mediaType == .audio }).first != nil
+ do {
+ let hasAudibleTracks = ((try await player.currentItem?.asset.loadMediaSelectionGroup(for: .audible)) != nil)
+ let tracks = try? await player.currentItem?.asset.load(.tracks)
+ let hasAudioTrack = tracks?.filter({ t in t.mediaType == .audio }).first != nil // Deal with odd cases of audio only MOV
+ return hasAudibleTracks || hasAudioTrack
+ } catch {
+ return false
+ }
}
@MainActor
@@ -32,12 +31,16 @@ final class DamusVideoPlayerViewModel: ObservableObject {
let id = UUID()
@Published var has_audio = false
+ @Published var is_live = false
@Binding var video_size: CGSize?
@Published var is_muted = true
@Published var is_loading = true
private var cancellables = Set<AnyCancellable>()
+ private var videoSizeObserver: NSKeyValueObservation?
+ private var videoDurationObserver: NSKeyValueObservation?
+
private var is_scrolled_into_view = false {
didSet {
if is_scrolled_into_view && !oldValue {
@@ -78,6 +81,31 @@ final class DamusVideoPlayerViewModel: ObservableObject {
model_id == self?.id ? self?.player.play() : self?.player.pause()
}
.store(in: &cancellables)
+
+ observeVideoSize()
+ observeDuration()
+ }
+
+ private func observeVideoSize() {
+ videoSizeObserver = player.currentItem?.observe(\.presentationSize, options: [.new], changeHandler: { [weak self] (playerItem, change) in
+ guard let self else { return }
+ if let newSize = change.newValue, newSize != .zero {
+ DispatchQueue.main.async {
+ self.video_size = newSize // Update the bound value
+ }
+ }
+ })
+ }
+
+ private func observeDuration() {
+ videoDurationObserver = player.currentItem?.observe(\.duration, options: [.new], changeHandler: { [weak self] (playerItem, change) in
+ guard let self else { return }
+ if let newDuration = change.newValue, newDuration != .zero {
+ DispatchQueue.main.async {
+ self.is_live = newDuration == .indefinite
+ }
+ }
+ })
}
private func load() async {
@@ -86,11 +114,6 @@ final class DamusVideoPlayerViewModel: ObservableObject {
video_size = meta.size
} else {
has_audio = await video_has_audio(player: player)
- if let video_size = await get_video_size(player: player) {
- self.video_size = video_size
- let meta = VideoMetadata(has_audio: has_audio, size: video_size)
- controller.set_metadata(meta, url: url)
- }
}
is_loading = false
@@ -114,4 +137,9 @@ final class DamusVideoPlayerViewModel: ObservableObject {
player.seek(to: CMTime.zero)
player.play()
}
+
+ deinit {
+ videoSizeObserver?.invalidate()
+ videoDurationObserver?.invalidate()
+ }
}