2015-03-10 13 views
7

Obecnie robię małą aplikację, która zajmuje się timelapses kamery na moim mac, zapisuje przechwyconą klatkę do png, i szukam do eksportowania przechwyconych klatek jako pojedynczy film.Jak utworzyć wideo z użyciem AVAssetWriter w szybkim tempie?

Używam CGImage do obsługi oryginalnych obrazów i ustawiania ich w tablicy, ale nie jestem pewien, czy można z tego wyjść. Z moich własnych badań wynika, że ​​muszę jakoś używać AVAssetWriter i AVAssetWriterInput.

Zajrzałem tutaj, przeczytałem docs i przeszukano google. Ale wszystkie przewodniki itp. Są raczej w obj-c niż szybkim, co sprawia, że ​​jest to naprawdę trudne do zrozumienia (jak nie mam doświadczenia w Obj-C).

Każda pomoc będzie bardzo ceniona.

Wielkie dzięki, Luke.

Odpowiedz

8

Rozwiązałem ten sam problem w Swift. Zaczynając od tablicy OIImage, spróbuj tego (to trochę za długo :-) ale działa):

var choosenPhotos: [UIImage] = [] *** your array of UIImages *** 
var outputSize = CGSizeMake(1280, 720) 

func build(outputSize outputSize: CGSize) { 
    let fileManager = NSFileManager.defaultManager() 
    let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) 
    guard let documentDirectory: NSURL = urls.first else { 
     fatalError("documentDir Error") 
    } 

    let videoOutputURL = documentDirectory.URLByAppendingPathComponent("OutputVideo.mp4") 

    if NSFileManager.defaultManager().fileExistsAtPath(videoOutputURL.path!) { 
     do { 
      try NSFileManager.defaultManager().removeItemAtPath(videoOutputURL.path!) 
     } catch { 
      fatalError("Unable to delete file: \(error) : \(__FUNCTION__).") 
     } 
    } 

    guard let videoWriter = try? AVAssetWriter(URL: videoOutputURL, fileType: AVFileTypeMPEG4) else { 
     fatalError("AVAssetWriter error") 
    } 

    let outputSettings = [AVVideoCodecKey : AVVideoCodecH264, AVVideoWidthKey : NSNumber(float: Float(outputSize.width)), AVVideoHeightKey : NSNumber(float: Float(outputSize.height))] 

    guard videoWriter.canApplyOutputSettings(outputSettings, forMediaType: AVMediaTypeVideo) else { 
     fatalError("Negative : Can't apply the Output settings...") 
    } 

    let videoWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: outputSettings) 
    let sourcePixelBufferAttributesDictionary = [kCVPixelBufferPixelFormatTypeKey as String : NSNumber(unsignedInt: kCVPixelFormatType_32ARGB), kCVPixelBufferWidthKey as String: NSNumber(float: Float(outputSize.width)), kCVPixelBufferHeightKey as String: NSNumber(float: Float(outputSize.height))] 
    let pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: videoWriterInput, sourcePixelBufferAttributes: sourcePixelBufferAttributesDictionary) 

    if videoWriter.canAddInput(videoWriterInput) { 
     videoWriter.addInput(videoWriterInput) 
    } 

    if videoWriter.startWriting() { 
     videoWriter.startSessionAtSourceTime(kCMTimeZero) 
     assert(pixelBufferAdaptor.pixelBufferPool != nil) 

     let media_queue = dispatch_queue_create("mediaInputQueue", nil) 

     videoWriterInput.requestMediaDataWhenReadyOnQueue(media_queue, usingBlock: {() -> Void in 
      let fps: Int32 = 1 
      let frameDuration = CMTimeMake(1, fps) 

      var frameCount: Int64 = 0 
      var appendSucceeded = true 

      while (!self.choosenPhotos.isEmpty) { 
       if (videoWriterInput.readyForMoreMediaData) { 
        let nextPhoto = self.choosenPhotos.removeAtIndex(0) 
        let lastFrameTime = CMTimeMake(frameCount, fps) 
        let presentationTime = frameCount == 0 ? lastFrameTime : CMTimeAdd(lastFrameTime, frameDuration) 

        var pixelBuffer: CVPixelBuffer? = nil 
        let status: CVReturn = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pixelBufferAdaptor.pixelBufferPool!, &pixelBuffer) 

        if let pixelBuffer = pixelBuffer where status == 0 { 
         let managedPixelBuffer = pixelBuffer 

         CVPixelBufferLockBaseAddress(managedPixelBuffer, 0) 

         let data = CVPixelBufferGetBaseAddress(managedPixelBuffer) 
         let rgbColorSpace = CGColorSpaceCreateDeviceRGB() 
         let context = CGBitmapContextCreate(data, Int(self.outputSize.width), Int(self.outputSize.height), 8, CVPixelBufferGetBytesPerRow(managedPixelBuffer), rgbColorSpace, CGImageAlphaInfo.PremultipliedFirst.rawValue) 

         CGContextClearRect(context, CGRectMake(0, 0, CGFloat(self.outputSize.width), CGFloat(self.outputSize.height))) 

         let horizontalRatio = CGFloat(self.outputSize.width)/nextPhoto.size.width 
         let verticalRatio = CGFloat(self.outputSize.height)/nextPhoto.size.height 
         //aspectRatio = max(horizontalRatio, verticalRatio) // ScaleAspectFill 
         let aspectRatio = min(horizontalRatio, verticalRatio) // ScaleAspectFit 

         let newSize:CGSize = CGSizeMake(nextPhoto.size.width * aspectRatio, nextPhoto.size.height * aspectRatio) 

         let x = newSize.width < self.outputSize.width ? (self.outputSize.width - newSize.width)/2 : 0 
         let y = newSize.height < self.outputSize.height ? (self.outputSize.height - newSize.height)/2 : 0 

         CGContextDrawImage(context, CGRectMake(x, y, newSize.width, newSize.height), nextPhoto.CGImage) 

         CVPixelBufferUnlockBaseAddress(managedPixelBuffer, 0) 

         appendSucceeded = pixelBufferAdaptor.appendPixelBuffer(pixelBuffer, withPresentationTime: presentationTime) 
        } else { 
         print("Failed to allocate pixel buffer") 
         appendSucceeded = false 
        } 
       } 
       if !appendSucceeded { 
        break 
       } 
       frameCount++ 
      } 
      videoWriterInput.markAsFinished() 
      videoWriter.finishWritingWithCompletionHandler {() -> Void in 
       print("FINISHED!!!!!") 
      } 
     }) 
    } 
} 
+0

Mam problem z tym w budynku iOS 8.4 w Xcode 7.1. Działa dobrze na iOS 9, ale wywołanie zwrotne z videoWriter.finishWritingWithCompletionHandler nigdy nie jest wywoływane. – Lyck

+1

videoWriter.finishWritingWithCompletionHandler {() -> Pustki w let _ = videoWriter druku ("GOTOWE !!!!!") } rozwiązuje mój problem – Lyck

+0

Dlaczego "niech managedPixelBuffer = pixelBuffer"? – drewster

Powiązane problemy