2

I want to Mirror (Flip) video playing using AVPlayer. Like : MirrorTube :- https://chrome.google.com/webstore/detail/mirrortube/olomckflnlligkboahmaihmeaffjdbfm/related?hl=en

i want to achieve same functionality.

I have tried to change CGAffineTransform but it does not work same.

Thanks in advance!

Ravi
  • 93
  • 11
  • 1
    Can you share how did you tried with CGAffineTransform? You just want to flip the `avPlayer` or you want to flip the actual video ready to export it in flipped mode? Flip should be vertical or horizontal? Providing the images would be more helpful then just a link to some extension that doesn't even have screenshots of what it does. – manikal Jan 12 '19 at 12:04
  • If you tried something then show your code. – Fogmeister Jan 12 '19 at 12:17

2 Answers2

5

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))
           }
}
manikal
  • 953
  • 7
  • 30
0

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




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
}
brian.clear
  • 5,277
  • 2
  • 41
  • 62
  • hey @brian.clear could you help explain bit more on "the actual player is a view where Swift.type(of:view) is "__AVPlayerLayerView"". type(of: controller.view) print "UIView" for me, and it doesn't heave subviews which I can walk through... Thanks! – Tieda Wei Dec 25 '22 at 02:39
  • edited code to add method to walk through hierarchy to find inner avplayer – brian.clear Jan 19 '23 at 15:08