如何使用AVPlayer镜像(翻转)视频播放



我想使用 AVPlayer 镜像(翻转)视频播放。喜欢 : 镜管 :- https://chrome.google.com/webstore/detail/mirrortube/olomckflnlligkboahmaihmeaffjdbfm/related?hl=en

我想实现相同的功能。

我试图更改CGAffineTransform,但它的工作方式不同。

提前感谢!

下面是如何使用CGAffineTransform垂直和水平翻转播放器的示例:

玩家视图

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
    }
}

使用播放器的视图控制器在 xib/情节提要中定义的视图:

@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))
           }
}

注意:对于 Mac Catalyst 中的 iOS 应用(带有 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
}

最新更新