2016-05-16 7 views
1

ビデオファイルにフィルタを追加する最適な方法は何ですか? ビデオからすべてのフレームを抽出し、各フレームにフィルタを追加する必要がありますか?あるいはこれにはより良いアプローチがあります。 ギャラリーからインポートしたビデオファイルにCIFilterを追加する方法

はこの出くわしたが、それは

let vidComp = AVVideoComposition(asset: self.asset, applyingCIFiltersWithHandler: { 
    request in 
    }) 

助けてください使用する方法がわかりません。

答えて

1

これはかなり長いプロセスです。あなたは快適に座っていますか?その後、私は始めるでしょう...

私のVideoEffectsプロジェクトの一環として、FilteredVideoVendorという名前のクラスを作成しました。これは、ムービーファイルからフィルタリングされたイメージフレームを提供します。

ベンダークラスの最初の仕事は、実際には、コントロールパネルの「ロード」ボタンから供給されたURLから動画を開くことです。

func openMovie(url: NSURL){ 
player = AVPlayer(URL: url) 

guard let player = player, 
    currentItem = player.currentItem, 
    videoTrack = currentItem.asset.tracksWithMediaType(AVMediaTypeVideo).first else { 
    fatalError("** unable to access item **") 
} 

currentURL = url 
failedPixelBufferForItemTimeCount = 0 

currentItem.addOutput(videoOutput) 

videoTransform = CGAffineTransformInvert(videoTrack.preferredTransform) 

player.muted = true 

} 

いくつかの興味深い点がここにあります:まず、私はfailedPixelBufferForItemTimeCountという名前の変数をリセットしてください。これはAVFoundationのバグで、明らかにエラーがなくても読み込めない場合があると私は思いますが、これを回避する方法です。次に、風景と肖像画の両方のビデオをサポートするために、ビデオトラックの優先変換の逆のバージョンを作成します。私はCACurrentMediaTimeに基づいてAVPlayerItemのための時間を計算し、CADisplayLink

func step(link: CADisplayLink) { 
guard let player = player, 
    currentItem = player.currentItem else { 
    return 
} 

let itemTime = videoOutput.itemTimeForHostTime(CACurrentMediaTime()) 

displayVideoFrame(itemTime) 

let normalisedTime = Float(itemTime.seconds/currentItem.asset.duration.seconds) 

delegate?.vendorNormalisedTimeUpdated(normalisedTime) 

if normalisedTime >= 1.0 
{ 
    paused = true 
} 
} 

ベンダーはstep(_:)呼び出すCADisplayLink含まれています。正規化された時間(すなわち、0と1との間の)は、プレイヤアイテムの時間をアセット持続時間で割ることによって計算され、プレイ中のスクラブバーの位置を設定するためにUIコンポーネントによって使用される。 itemTimeでムービーのフレームからCIImageを作成するには、displayVideoFrame(_:)で行われます。

func displayVideoFrame(time: CMTime) { 
guard let player = player, 
    currentItem = player.currentItem where player.status == .ReadyToPlay && currentItem.status == .ReadyToPlay else { 
    return 
} 

if videoOutput.hasNewPixelBufferForItemTime(time) { 
    failedPixelBufferForItemTimeCount = 0 

    var presentationItemTime = kCMTimeZero 

    guard let pixelBuffer = videoOutput.copyPixelBufferForItemTime(
    time, 
    itemTimeForDisplay: &presentationItemTime) else { 
     return 
    } 

    unfilteredImage = CIImage(CVImageBuffer: pixelBuffer) 

    displayFilteredImage() 
} 
else if let currentURL = currentURL where !paused { 
    failedPixelBufferForItemTimeCount += 1 

    if failedPixelBufferForItemTimeCount > 12 { 
    openMovie(currentURL) 
    } 
} 
} 

ビデオ出力からピクセルバッファをコピーする前に、私は1つが利用可能であることを確認する必要があります。それでも問題がなければ、そのピクセルバッファーからCIImageを作成するのは簡単なステップです。しかし、hasNewPixelBufferForItemTime(_:)が何度も失敗すると(12がうまくいくと思われます)、私はAVFoundationが黙って失敗したと判断して、ムービーを再度開きます。人口CIImage

(1がある場合)、私はフィルタを適用し、表示されるように背面(メインビューである)デリゲートにレンダリングされた結果を返す:

func displayFilteredImage() { 
guard let unfilteredImage = unfilteredImage, 
    videoTransform = videoTransform else { 
    return 
} 

let ciImage: CIImage 

if let ciFilter = ciFilter { 
    ciFilter.setValue(unfilteredImage, forKey: kCIInputImageKey) 

    ciImage = ciFilter.outputImage!.imageByApplyingTransform(videoTransform) 
} 
else { 
    ciImage = unfilteredImage.imageByApplyingTransform(videoTransform) 
} 

let cgImage = ciContext.createCGImage(
    ciImage, 
    fromRect: ciImage.extent) 

delegate?.finalOutputUpdated(UIImage(CGImage: cgImage)) 
} 

あなたがしたい場合はフィルタリングされたムービーをファイルシステムに書き戻して、私はそれをthis blog postで議論します。

シモン

関連する問題