將視頻文件添加到濾鏡的最佳方法是什麼? 我是否必須從視頻中提取所有幀,然後將濾鏡添加到每個幀?或者有更好的方法來解決這個問題。如何將CIFilter添加到從畫廊導入的視頻文件
遇到了這一點,但不知道如何使用它
let vidComp = AVVideoComposition(asset: self.asset, applyingCIFiltersWithHandler: {
request in
})
請幫助。
將視頻文件添加到濾鏡的最佳方法是什麼? 我是否必須從視頻中提取所有幀,然後將濾鏡添加到每個幀?或者有更好的方法來解決這個問題。如何將CIFilter添加到從畫廊導入的視頻文件
遇到了這一點,但不知道如何使用它
let vidComp = AVVideoComposition(asset: self.asset, applyingCIFiltersWithHandler: {
request in
})
請幫助。
這是一個相當漫長的過程。你坐得舒服嗎?然後我開始...
作爲我VideoEffects項目的一部分,我創建了一個名爲FilteredVideoVendor的類,它從電影文件中提取過濾後的圖像幀。
供應商類別的第一份工作是真正從「加載」按鈕,在控制面板中提供的網址打開一個電影:
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中的一個錯誤,視頻有時會無法加載而沒有明顯的錯誤。其次,爲了支持橫向和縱向視頻,我創建了視頻軌道首選變換的倒序版本。
廠商包含CADisplayLink
它調用step(_:)
:
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
}
}
隨着CADisplayLink
,我計算基於CACurrentMediaTime
爲AVPlayerItem
的時間。標準化時間(即在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)
}
}
}
之前從視頻輸出複製像素緩衝區,我需要確保有一個可用。如果這一切都很好,那麼從該像素緩衝區創建CIImage
是一個簡單的步驟。但是,如果hasNewPixelBufferForItemTime(_:)
失敗太多次(12似乎工作),我認爲AVFoundation默默失敗,我重新打開電影。
隨着人口CIImage
,我申請一個過濾器(如果有的話),並返回所呈現的結果返回給委託(這是主視圖),以顯示:
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中討論過。
Simon