2016-12-19 4 views
2

Я разместил вопрос раньше, но не получил правильное решение. Может быть, я был не очень ясен по поводу вопроса Frame Duration time - UIImage array to movie Вот почему я повторяю этоДлина видео - массив изображений до видео

Я работаю над проектом, где мне нужно экспортировать видео из массива UIImage. Мой массив содержит 4 изображения, и я хочу, чтобы каждое изображение показывалось в течение 5 секунд, что означает, что длина видео будет 20 секунд. Но моя экспортируемая длина видео составляет 25 секунд, а первое изображение отображается в течение 10 секунд. и последние 3 изображения отображаются в течение 15 секунд (по 5 секунд). Итак, последние 3 изображения работают отлично. я пытался этот код ...

var outputSize = CGSize(width: 1920, height: 1280) 

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.startSession(atSourceTime: kCMTimeZero) 
     assert(pixelBufferAdaptor.pixelBufferPool != nil) 
     let media_queue = DispatchQueue(label: "mediaInputQueue") 
     videoWriterInput.requestMediaDataWhenReady(on: media_queue, using: {() -> Void in 
      let fps: Int32 = 1 
      let framePerSecond: Int64 = 5 
      let frameDuration = CMTimeMake(framePerSecond, fps) 
      var frameCount: Int64 = 0 
      var appendSucceeded = true 
      while (!self.choosenPhotos.isEmpty) { //choosenPhotos is image array 
       if (videoWriterInput.isReadyForMoreMediaData) { 
        let nextPhoto = self.choosenPhotos.remove(at: 0) 
        let lastFrameTime = CMTimeMake(frameCount * framePerSecond, fps) 
        let presentationTime = frameCount == 0 ? lastFrameTime : CMTimeAdd(lastFrameTime, frameDuration) 
        print("presentationTime-------------\(presentationTime)") 
        var pixelBuffer: CVPixelBuffer? = nil 
        let status: CVReturn = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pixelBufferAdaptor.pixelBufferPool!, &pixelBuffer) 
        if let pixelBuffer = pixelBuffer, status == 0 { 
         let managedPixelBuffer = pixelBuffer 
         CVPixelBufferLockBaseAddress(managedPixelBuffer, CVPixelBufferLockFlags(rawValue: CVOptionFlags(0))) 
         let data = CVPixelBufferGetBaseAddress(managedPixelBuffer) 
         let rgbColorSpace = CGColorSpaceCreateDeviceRGB() 
         let context = CGContext(data: data, width: Int(self.outputSize.width), height: Int(self.outputSize.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(managedPixelBuffer), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue) 
         context!.clear(CGRect(x: 0, y: 0, width: CGFloat(self.outputSize.width), height: 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 = CGSize(width: nextPhoto.size.width * aspectRatio, height: 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 
         context?.draw(nextPhoto.cgImage!, in: CGRect(x: x, y: y, width: newSize.width, height: newSize.height)) 
         CVPixelBufferUnlockBaseAddress(managedPixelBuffer, CVPixelBufferLockFlags(rawValue: CVOptionFlags(0))) 
         appendSucceeded = pixelBufferAdaptor.append(pixelBuffer, withPresentationTime: presentationTime) 
        } else { 
         print("Failed to allocate pixel buffer") 
         appendSucceeded = false 
        } 
       } 
       if !appendSucceeded { 
        break 
       } 
       frameCount += 1 
      } 
      videoWriterInput.markAsFinished() 
      videoWriter.finishWriting {() -> Void in 
       self.imageArrayToVideoComplete = true 
       print("Image array to mutable video complete :)") 
      } 
     }) 
    } 
} 

На самом деле я немного запутался о переменной presentationTime. По этой причине я напечатал, что и в Xcode, журнал выход был как этот

presentationTime-------------CMTime(value: 0, timescale: 1, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0) 
presentationTime-------------CMTime(value: 10, timescale: 1, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0) 
presentationTime-------------CMTime(value: 15, timescale: 1, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0) 
presentationTime-------------CMTime(value: 20, timescale: 1, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0) 

здесь первое значение равно 0, а второе значение равно 10 - разница составляет 10. Но от второго presentationTime, он работает прекрасно (значение увеличивается на 5). Думаю, это проблема. Какое минимальное изменение мне нужно сделать?

+0

отправьте проект, если возможно, на [email protected] –

+0

отправил проект @Md. Ibrahim Hassan –

+0

На нем приятель .... –

ответ

1

Просто раскомментируйте в этой линии в buildVideoFromImageArray функции после

//   videoWriter.startSession(atSourceTime: kCMTimeZero) 

и добавьте следующие строки в месте

 let zeroTime = CMTimeMake(Int64(self.reloadDurationFromSlideShow),Int32(1)) 
     videoWriter.startSession(atSourceTime: zeroTime) 

Испытано его. Вы также проверяете это и даете мне знать.

+0

это сработало man :) спасибо большое. –

+0

Было довольно весело работать над этим. :) –

+0

это был отличный помощник :) –