Как отразить (перевернуть) воспроизведение видео с помощью AVPlayer?
Я хочу отразить (Flip) воспроизведение видео с помощью AVPlayer. Как: MirrorTube: - https://chrome.google.com/webstore/detail/mirrortube/olomckflnlligkboahmaihmeaffjdbfm/related?hl=en
Я хочу достичь той же функциональности.
Я попытался изменить CGAffineTransform, но он не работает так же.
Заранее спасибо!
2 ответа
Вот пример того, как перевернуть плеер по вертикали и горизонтали, используя CGAffineTransform
:
PlayerView:
import AVKit
class PlayerView: UIView {
var player: AVPlayer? {
get {
return playerLayer.player
}
set {
playerLayer.player = newValue
}
}
var playerLayer: AVPlayerLayer {
return layer as! AVPlayerLayer
}
// Override UIView property
override static var layerClass: AnyClass {
return AVPlayerLayer.self
}
}
ViewController, использующий playerView, определенный в xib / storyboard:
@IBOutlet var playerView: PlayerView!
@IBAction func flipVerticallyBarButtonItemTouched(_ sender: UIBarButtonItem) {
UIView.animate(withDuration: 0.2) { [unowned self] in
self.playerView.transform = self.playerView.transform.concatenating(CGAffineTransform(scaleX: 1, y: -1))
}
}
@IBAction func flipHorizontallyBarButtonItemTouched(_ sender: UIBarButtonItem) {
UIView.animate(withDuration: 0.2) { [unowned self] in
self.playerView.transform = self.playerView.transform.concatenating(CGAffineTransform(scaleX: -1, y: 1))
}
}
Видео примера в действии.
Примечание. Для приложения iOS в Mac Catalyst (с подклассом AVPlayerController) корневым представлением является AVPlayerView. Но, как ни странно, AVPlayerView не является общедоступным на iOS> Mac Catalyst, поэтому self.playerView не будет работать, поэтому вы не можете его использовать. Вы получаете класс, не найденный для «AVPlayerView»
Но когда вы запускаете приложение в Mac Catalyst и проверяете его, self.view представляет собой AVPlayerView.
обходной путь: просто переверните корневой вид без приведения - self.view
`class MyAVPlayerController: AVPlayerController`
to flip horizontal etc
self.view.transform = self.view.transform.concatenating(CGAffineTransform(scaleX: -1, y: 1))
to flip vertical etc
self.view.transform = self.view.transform.concatenating(CGAffineTransform(scaleX: 1, y: -1))
KNOWN ISSUE this flips the whole AVPlayerView including controls. in iOS 16 the actual player is a view where Swift.type(of:view) is "__AVPlayerLayerView" so you can walk the hierarchy and find the UIView return it then apply the transform to only that subview
func flipHorizontal(){
print("TradAVPlayerViewController.swift flipHorizontal")
if self.player != nil{
//------------------------------------------------------------------
//v1 - flips VC.view which is AVPlayerView
//but also flips TOAST and CONTROLS
//https://developer.apple.com/documentation/uikit/uiview/1622459-transform
//------------------------------------------------------------------
//OK ROTATES VIEW
//self.view.transform = CGAffineTransform(rotationAngle: CGFloat((90 * Double.pi)/180))
//OK FLIP VERTICAL
//self.view.transform = self.view.transform.concatenating(CGAffineTransform(scaleX: 1, y: -1))
//OK FLIPS HORIZONTAL
// self.view.transform = self.view.transform.concatenating(CGAffineTransform(scaleX: -1, y: 1))
//note the flip remains in place as long as self.player isnt recreated so PREV/NEXT will stay flipped
//------------------------------------------------------------------
//ISSUE flipping the whole view also flips the TOAST and SCRUBBER
//------------------------------------------------------------------
//in iOS 15 the player is a class with name "__AVPlayerLayerView"
//find it in the hierarchy and only apply transform to that on
if let rootView = self.view{
let className = "__AVPlayerLayerView"
if let subViewFound
= findSubViewByName(name: className,
view: rootView)
{
print("FOUND className:'\(className)' flipping it")
subViewFound.transform = subViewFound.transform.concatenating(CGAffineTransform(scaleX: -1, y: 1))
}else{
print("NOT FOUND className:'\(className)' CANT FLIP IT - debug hierarchy in 3d and get class name for the AVPlayerLayerView")
}
}else{
logger.error("self.view is nil")
}
print()
}else{
logger.error("self.player is nil")
}
}
func findSubViewByName(name: String, view: UIView) -> UIView?{
var viewFound: UIView? = nil
for subView in view.subviews{
//MUST WRAP IN STRING else types wont match
let typeName = "\(Swift.type(of: subView))"
//print("typeName:\(typeName)")
if typeName == name {
print("SUB VIEW - typeName:\(typeName) - MATCH!!")
viewFound = subView
break
}else{
print("SUB VIEW - typeName:\(typeName) - NO MATCH")
}
//recurse depth first
if let subViewFound = findSubViewByName(name: name, view: subView){
viewFound = subViewFound
break
}else{
//no match in subviewsf
}
}
return viewFound
}