How to Mirror(Flip) Video playing using AVPlayer?

Viewed 1163
2 Answers

Here's an example how to flip the player vertically and horizontally by using 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 using the playerView defined in 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))
           }
}

Note: For an iOS app in Mac Catalyst (with a AVPlayerController subclass) the root view is AVPlayerView. But oddly AVPlayerView isn't public on iOS > Mac Catalyst so self.playerView wont work so you cant cast it. You get class not found for 'AVPlayerView'

But when you run the app in Mac Catalyst and inspect it the self.view is an AVPlayerView

workaround just flip the root view itself without casting - 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

Related