How to display a cutout/portion of a video in AVFoundation

133 Views Asked by At

I'm trying to crop a video / display a portion of a video in AVFoundation. So far my code looks right to me but the output is not what I wanted. I don't see what is wrong. Any ideas?

let item = AVPlayerItem(url: nextVideoItem.url)
let cropRect = CGRect(x: 200, y: 200, width: 300, height: 300)
let cropComposition = AVMutableVideoComposition(asset: item.asset, applyingCIFiltersWithHandler: { request in    
    let cropFilter = CIFilter(name: "CICrop")!
    cropFilter.setValue(request.sourceImage, forKey: kCIInputImageKey)
    cropFilter.setValue(CIVector(cgRect: cropRect), forKey: "inputRectangle")
    
    let imageAtOrigin = cropFilter.outputImage!.transformed(by: CGAffineTransform(translationX: -cropRect.origin.x, y: -cropRect.origin.y))
    request.finish(with: imageAtOrigin, context: nil)
})
cropComposition.renderSize = cropRect.size
item.videoComposition = cropComposition
self.player.replaceCurrentItem(with: item)
self.player.play()
1

There are 1 best solutions below

1
On BEST ANSWER

The above code runs fine in itself, the reason you can't see it is you're probably not setting the frame of the AVPlayerViewController's view or AVPlayerLayer correctly in your surrounding UI code. Here is a Swift Playground code snippet that plays a video asset with the crop you specified above:

import UIKit
import AVKit
import PlaygroundSupport

class MyViewController : UIViewController {
    var player: AVPlayer!
    var avLayer: AVPlayerLayer!
    
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        player = AVPlayer()
        
        let item = AVPlayerItem(url: #fileLiteral(resourceName: "logos.mov"))
        
        let cropRect = CGRect(x: 500, y: 250, width: 480, height: 320)
        let cropComposition = AVMutableVideoComposition(asset: item.asset, applyingCIFiltersWithHandler: { request in
            let cropFilter = CIFilter(name: "CICrop")!
            cropFilter.setValue(request.sourceImage, forKey: kCIInputImageKey)
            cropFilter.setValue(CIVector(cgRect: cropRect), forKey: "inputRectangle")
            
            let imageAtOrigin = cropFilter.outputImage!.transformed(by: CGAffineTransform(translationX: -cropRect.origin.x, y: -cropRect.origin.y))
            request.finish(with: imageAtOrigin, context: nil)
        })
        cropComposition.renderSize = cropRect.size
        item.videoComposition = cropComposition
        self.player.replaceCurrentItem(with: item)
        self.player.play()
        
        avLayer = AVPlayerLayer()
        avLayer.player = self.player
        view.layer.addSublayer(avLayer)
        self.view = view
    }
    
    override func viewDidAppear(_ animated: Bool) {
        // this is the important bit
        avLayer.frame = view.bounds
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()