2016-05-16 4 views
1

Was ist der beste Ansatz Filter, um Video-Dateien hinzufügen? Muss ich alle Bilder aus dem Video extrahieren und dann Filter auf jeden Rahmen hinzufügen? Oder gibt es einen besseren Ansatz dafür?Wie füge ich CIFilter um Video-Datei aus der Galerie importiert

über das kam, aber nicht sicher, wie es helfen

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

Bitte verwenden.

Antwort

1

Es ist ein ziemlich langer Prozess. Sitzst du gemütlich? Dann beginne ich ...

Als Teil meiner VideoEffects Projekt habe ich eine Klasse namens FilteredVideoVendor erstellt, die gefilterte Bilderframes aus einer Filmdatei verkauft.

Die erste Aufgabe der Herstellerklasse ist eigentlich von einer URL durch die Schaltfläche „Ladens“ in der Systemsteuerung geliefert, einen Film zu öffnen:

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 

} 

Es gibt ein paar interessanten hier Punkte: Erstens, ich zurücksetzen, um eine Variable mit dem Namen failedPixelBufferForItemTimeCount - das ist eine Abhilfe für das, was ich denke, um ein Fehler in AVFoundation mit Videos, die gelegentlich ohne offensichtliche Fehler laden fehlschlagen würden. Zweitens, um Landscape- und Portrait-Videos zu unterstützen, erstelle ich eine invertierte Version der bevorzugten Transformation der Videospur.

Der Verkäufer enthält ein CADisplayLink die step(_:) ruft:

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 
} 
} 

Mit dem CADisplayLink, berechne ich die Zeit für die AVPlayerItem basierend auf CACurrentMediaTime. Die normalisierte Zeit (d. H. Zwischen 0 und 1) wird berechnet, indem die Zeit des Spielerelements durch die Aktivitätsdauer dividiert wird, dies wird von den UI-Komponenten verwendet, um die Position der Scrub-Leiste während der Wiedergabe einzustellen. Erstellen ein CIImage aus dem Rahmen des Films bei itemTime in displayVideoFrame(_:) getan:

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) 
    } 
} 
} 

Bevor einen Pixelpuffer aus dem Videoausgang kopieren, ich brauche verfügbar ist zu gewährleisten. Wenn das alles gut ist, ist es ein einfacher Schritt, aus diesem Pixelpuffer einen CIImage zu erstellen. Wenn jedoch hasNewPixelBufferForItemTime(_:) zu oft versagt (12 scheint zu funktionieren), gehe ich davon aus AVFoundation hat leise ausgefallen und ich den Film wieder zu öffnen.

Mit dem bevölkerten CIImage, wende ich einen Filter und Rück das gerenderte Ergebnis zurück an den Delegaten (falls vorhanden) (die die Hauptansicht ist) angezeigt werden:

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)) 
} 

Wenn Sie möchten, schreibe einen gefilterten Film zurück in das Dateisystem, ich bespreche das in this blog post.

Simon

Verwandte Themen