переключить CIFilters на видео

может ли кто-нибудь помочь мне понять, как правильно переключать CIFilters без перезапуска видеоплеера?

У меня есть локальное видео, воспроизводимое внутри представления. Если я коснусь ячейки в представлении коллекции, видео изменит CIFilter.

мой код

let filter = CIFilter(name: "CIPhotoEffectNoir")!
let asset = AVAsset(url: fooURL)
let item = AVPlayerItem(asset: asset)
item.videoComposition = AVVideoComposition(asset: asset,  applyingCIFiltersWithHandler: { request in
    let source = request.sourceImage.clampedToExtent()
    filter.setValue(source, forKey: kCIInputImageKey)

    let output = filter.outputImage

    request.finish(with: output!, context: nil)
})

player = AVPlayer(playerItem: item)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = videoViewDetail.bounds
videoViewDetail.layer.addSublayer(playerLayer)
player?.play()

код отлично работает, и эффект правильный.

но у меня есть коллекция со многими CIFilters. При нажатии на ячейку я не могу найти способ переключить фильтр, связанный с видео. Если я воссоздам новый проигрыватель с новым фильтром и добавлю его вместо текущего «добавить подслой», проигрыватель перезапустит видео.

@IBAction func tap(_ sender: UITapGestureRecognizer) {

    let location = sender.location(in: self.collectionView)
    let indexPath = self.collectionView.indexPathForItem(at: location)

    if let index = indexPath {
        // code to switch to another CIFilter like for example "CISepiaTone"
    }
}

Как лучше всего изменить CIFilters на воспроизводимое видео без перезапуска видео. Можно ли сохранить видео с новым фильтром?

Спасибо!


person Stefano Vet    schedule 20.10.2019    source источник


Ответы (1)


Блок обработчика, который вы указываете при создании AVVideoComposition, постоянно вызывается для каждого видеокадра, который показывает проигрыватель. Это означает, что вам просто нужно переключить фильтр, который используется внутри этого блока.

Самый простой способ добиться этого — ссылаться на фильтр снаружи блока, а не захватывать его. Затем вы можете просто изменить ссылку во время выполнения.

Например, предполагая, что ваш код запускается внутри некоторого метода контроллера представления, вы можете сделать следующее:

class MyViewController: UIViewController {

    var filter: CIFilter = CIFilter(name: "CIPhotoEffectNoir")!

    func createPlayer() {
        let asset = AVAsset(url: fooURL)
        let item = AVPlayerItem(asset: asset)
        item.videoComposition = AVVideoComposition(asset: asset,  applyingCIFiltersWithHandler: { [weak self] request in
            guard let self = self else {
                request.finish(with error: SomeError)
                return
            }
            let source = request.sourceImage.clampedToExtent()
            self.filter.setValue(source, forKey: kCIInputImageKey)

            let output = self.filter.outputImage

            request.finish(with: output!, context: nil)
        })

        player = AVPlayer(playerItem: item)
        let playerLayer = AVPlayerLayer(player: player)
        playerLayer.frame = videoViewDetail.bounds
        videoViewDetail.layer.addSublayer(playerLayer)
        player?.play()
    }

    // ...

}

Затем вы можете легко изменить фильтр, просто изменив self.filter.

(Возможно, вы захотите синхронизировать доступ к фильтру, чтобы избежать проблем с параллелизмом.)

person Frank Schlegel    schedule 20.10.2019
comment
Работает отлично!! Благодарность! Для сохранения результата я пытаюсь использовать AVMutableComposition в качестве актива AVPlayerItem .... это правильный способ? - person Stefano Vet; 20.10.2019
comment
Для экспорта лучше всего использовать файл AVAssetExportSession. Он также может работать с AVVideoComposition и будет записывать видео в указанный вами URL-адрес файла. - person Frank Schlegel; 20.10.2019
comment
я пытаюсь передать актив (пусть актив = AVAsset (url: fooURL)) в AVAssetExportSession. Новое видео сохраняется корректно, но без фильтров. Есть идеи? Я использую let exporter = AVAssetExportSession (актив: актив!, PresetName: AVAssetExportPresetHighestQuality). Спасибо Фрэнк!!! - person Stefano Vet; 20.10.2019
comment
Вы также должны установить videoComposition сеанса экспорта, как вы это сделали с элементом проигрывателя. - person Frank Schlegel; 20.10.2019