Compare commits

..

3 Commits

2 changed files with 68 additions and 22 deletions

View File

@ -9,16 +9,19 @@
import UIKit import UIKit
import GalleryVC import GalleryVC
import AVFoundation import AVFoundation
import CoreImage
class VideoGalleryContentViewController: UIViewController, GalleryContentViewController { class VideoGalleryContentViewController: UIViewController, GalleryContentViewController {
private let url: URL private let url: URL
let caption: String? let caption: String?
private let item: AVPlayerItem private var item: AVPlayerItem
let player: AVPlayer let player: AVPlayer
@available(iOS, obsoleted: 16.0, message: "Use AVPlayer.defaultRate") @available(iOS, obsoleted: 16.0, message: "Use AVPlayer.defaultRate")
@Box private var playbackSpeed: Float = 1 @Box private var playbackSpeed: Float = 1
private var isGrayscale: Bool
private var presentationSizeObservation: NSKeyValueObservation? private var presentationSizeObservation: NSKeyValueObservation?
private var statusObservation: NSKeyValueObservation? private var statusObservation: NSKeyValueObservation?
private var rateObservation: NSKeyValueObservation? private var rateObservation: NSKeyValueObservation?
@ -29,8 +32,10 @@ class VideoGalleryContentViewController: UIViewController, GalleryContentViewCon
self.url = url self.url = url
self.caption = caption self.caption = caption
self.isGrayscale = Preferences.shared.grayscaleImages
let asset = AVAsset(url: url) let asset = AVAsset(url: url)
self.item = AVPlayerItem(asset: asset) self.item = VideoGalleryContentViewController.createItem(asset: asset)
self.player = AVPlayer(playerItem: item) self.player = AVPlayer(playerItem: item)
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
@ -40,6 +45,25 @@ class VideoGalleryContentViewController: UIViewController, GalleryContentViewCon
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
private static func createItem(asset: AVAsset) -> AVPlayerItem {
let item = AVPlayerItem(asset: asset)
if Preferences.shared.grayscaleImages {
#if os(visionOS)
#warning("Use async AVVideoComposition CIFilter initializer")
#else
let filter = CIFilter(name: "CIColorMonochrome")!
filter.setValue(CIColor(red: 0.85, green: 0.85, blue: 0.85), forKey: "inputColor")
filter.setValue(1.0, forKey: "inputIntensity")
item.videoComposition = AVVideoComposition(asset: asset, applyingCIFiltersWithHandler: { request in
filter.setValue(request.sourceImage, forKey: "inputImage")
request.finish(with: filter.outputImage!, context: nil)
})
#endif
}
return item
}
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
@ -55,20 +79,9 @@ class VideoGalleryContentViewController: UIViewController, GalleryContentViewCon
playerView.bottomAnchor.constraint(equalTo: view.bottomAnchor), playerView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
]) ])
presentationSizeObservation = item.observe(\.presentationSize, changeHandler: { [unowned self] item, _ in preferredContentSize = item.presentationSize
MainActor.runUnsafely {
self.preferredContentSize = item.presentationSize updateItemObservations()
self.container?.galleryContentChanged()
}
})
statusObservation = item.observe(\.status, changeHandler: { [unowned self] item, _ in
MainActor.runUnsafely {
if item.status == .readyToPlay {
self.container?.setGalleryContentLoading(false)
statusObservation = nil
}
}
})
rateObservation = player.observe(\.rate, options: .old, changeHandler: { [unowned self] player, info in rateObservation = player.observe(\.rate, options: .old, changeHandler: { [unowned self] player, info in
hideControlsWorkItem?.cancel() hideControlsWorkItem?.cancel()
if player.rate > 0 && info.oldValue == 0 { if player.rate > 0 && info.oldValue == 0 {
@ -84,7 +97,37 @@ class VideoGalleryContentViewController: UIViewController, GalleryContentViewCon
} }
}) })
preferredContentSize = item.presentationSize NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil)
}
private func updateItemObservations() {
presentationSizeObservation = item.observe(\.presentationSize, changeHandler: { [unowned self] item, _ in
MainActor.runUnsafely {
self.preferredContentSize = item.presentationSize
self.container?.galleryContentChanged()
}
})
statusObservation = item.observe(\.status, changeHandler: { [unowned self] item, _ in
MainActor.runUnsafely {
if item.status == .readyToPlay {
self.container?.setGalleryContentLoading(false)
statusObservation = nil
}
}
})
}
@objc private func preferencesChanged() {
if isGrayscale != Preferences.shared.grayscaleImages {
let isPlaying = player.rate > 0
isGrayscale = Preferences.shared.grayscaleImages
item = VideoGalleryContentViewController.createItem(asset: item.asset)
player.replaceCurrentItem(with: item)
updateItemObservations()
if isPlaying {
player.rate = playbackSpeed
}
}
} }
// MARK: GalleryContentViewController // MARK: GalleryContentViewController

View File

@ -62,10 +62,14 @@ class GifvController {
@objc private func preferencesChanged() { @objc private func preferencesChanged() {
if isGrayscale != Preferences.shared.grayscaleImages { if isGrayscale != Preferences.shared.grayscaleImages {
isGrayscale = Preferences.shared.grayscaleImages isGrayscale = Preferences.shared.grayscaleImages
let oldItem = item
item = GifvController.createItem(asset: asset) item = GifvController.createItem(asset: asset)
player.replaceCurrentItem(with: item) player.replaceCurrentItem(with: item)
self.updatePresentationSizeObservation() self.updatePresentationSizeObservation()
player.play() player.play()
NotificationCenter.default.removeObserver(self, name: AVPlayerItem.didPlayToEndTimeNotification, object: oldItem)
NotificationCenter.default.addObserver(self, selector: #selector(restartItem), name: AVPlayerItem.didPlayToEndTimeNotification, object: item)
} }
} }
@ -75,13 +79,12 @@ class GifvController {
#if os(visionOS) #if os(visionOS)
#warning("Use async AVVideoComposition CIFilter initializer") #warning("Use async AVVideoComposition CIFilter initializer")
#else #else
let filter = CIFilter(name: "CIColorMonochrome")!
filter.setValue(CIColor(red: 0.85, green: 0.85, blue: 0.85), forKey: "inputColor")
filter.setValue(1.0, forKey: "inputIntensity")
item.videoComposition = AVVideoComposition(asset: asset, applyingCIFiltersWithHandler: { (request) in item.videoComposition = AVVideoComposition(asset: asset, applyingCIFiltersWithHandler: { (request) in
let filter = CIFilter(name: "CIColorMonochrome")!
filter.setValue(request.sourceImage, forKey: "inputImage") filter.setValue(request.sourceImage, forKey: "inputImage")
filter.setValue(CIColor(red: 0.85, green: 0.85, blue: 0.85), forKey: "inputColor")
filter.setValue(1.0, forKey: "inputIntensity")
request.finish(with: filter.outputImage!, context: nil) request.finish(with: filter.outputImage!, context: nil)
}) })
#endif #endif