UIImagesの配列をビデオに変換する際の黒いフレーム

リチウム

UIImageの配列をビデオに変換しようとしていますが、結果のファイルに多くの黒いフレームがあります(たとえば、最初に4つの黒いフレーム、その後に3つの良いフレーム、その後に3つの黒いフレームと2つの良いフレームなど)このパターンは、ビデオの最後まで繰り返されます)。

私のコードはこのソリューションに基づいていますが、問題の主な原因はコードのこの部分にあるはずです。

func build(progress: (NSProgress -> Void), success: (NSURL -> Void), failure: (NSError -> Void)) {
    //videosizes and path to temp output file
    let inputSize = CGSize(width: 568, height: 320)
    let outputSize = CGSize(width: 568, height: 320)
    var error: NSError?
    let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString
    let videoOutputURL = NSURL(fileURLWithPath: documentsPath.stringByAppendingPathComponent("TempVideo.mov"))!
    NSFileManager.defaultManager().removeItemAtURL(videoOutputURL, error: nil)

    videoWriter = AVAssetWriter(URL: videoOutputURL, fileType: AVFileTypeMPEG4, error: &error)

    if let videoWriter = videoWriter {
        let videoSettings: [NSObject : AnyObject] = [
            AVVideoCodecKey  : AVVideoCodecH264,
            AVVideoWidthKey  : outputSize.width,
            AVVideoHeightKey : outputSize.height,
        ]

        let videoWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: videoSettings)
        let pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(
            assetWriterInput: videoWriterInput,
            sourcePixelBufferAttributes: [
                kCVPixelBufferPixelFormatTypeKey : kCVPixelFormatType_32ARGB,
                kCVPixelBufferWidthKey : inputSize.width,
                kCVPixelBufferHeightKey : inputSize.height,
            ]
        )

        assert(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 = 30
                let frameDuration = CMTimeMake(1, fps)
                let currentProgress = NSProgress(totalUnitCount: Int64(self.photoURLs.count))

                var frameCount: Int64 = 0

                for var i = 0; i < self.photoURLs.count - 1; i++ {

                    var currentFrame = self.photoURLs[i]
                    var lastFrameTime = CMTimeMake(Int64(i), fps)                       
                    var presentationTime = CMTimeAdd(lastFrameTime, frameDuration)

                    //this one is needed because sometimes videoWriter is not ready, and we have to wait for a while
                    while videoWriterInput.readyForMoreMediaData == false {
                        var maxDate = NSDate(timeIntervalSinceNow: 0.5)
                        var currentRunLoop = NSRunLoop()
                        currentRunLoop.runUntilDate(maxDate)

                    }

                    self.appendPixelBufferForImageAtURL(currentFrame, pixelBufferAdaptor: pixelBufferAdaptor, presentationTime: presentationTime)

                    frameCount++
                    currentProgress.completedUnitCount = frameCount
                    progress(currentProgress)

                }

                videoWriterInput.markAsFinished()
                videoWriter.finishWritingWithCompletionHandler { () -> Void in
                    if error == nil {
                        success(videoOutputURL)
                    }
                }
            })
        } else {
            error = NSError(
                domain: kErrorDomain,
                code: kFailedToStartAssetWriterError,
                userInfo: ["description": "AVAssetWriter failed to start writing"]
            )
        }
    }

    if let error = error {
        failure(error)
    }
}

明らかに私は何か間違ったことをしていますが、何ですか?一部の画像は変換に問題がないため、ここにあるはずですが、pixelbufferにはさらに2つの関数があります。

func appendPixelBufferForImageAtURL(image: UIImage, pixelBufferAdaptor: AVAssetWriterInputPixelBufferAdaptor, presentationTime: CMTime) -> Bool {
    var appendSucceeded = true

    autoreleasepool {


                var pixelBuffer: Unmanaged<CVPixelBuffer>?
                let status: CVReturn = CVPixelBufferPoolCreatePixelBuffer(
                    kCFAllocatorDefault,
                    pixelBufferAdaptor.pixelBufferPool,
                    &pixelBuffer
                )

                if let pixelBuffer = pixelBuffer where status == 0 {
                    let managedPixelBuffer = pixelBuffer.takeRetainedValue()

                    fillPixelBufferFromImage(image, pixelBuffer: managedPixelBuffer)

                    appendSucceeded = pixelBufferAdaptor.appendPixelBuffer(
                        managedPixelBuffer,
                        withPresentationTime: presentationTime
                    )
                } else {
                    NSLog("error: Failed to allocate pixel buffer from pool")
                }

    }

    return appendSucceeded
}

func fillPixelBufferFromImage(image: UIImage, pixelBuffer: CVPixelBufferRef) {

    let imageData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage))
    let lockStatus:UInt8 = UInt8(CVPixelBufferLockBaseAddress(pixelBuffer, 0))

    let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer)
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue)
    let rgbColorSpace = CGColorSpaceCreateDeviceRGB()

    let context = CGBitmapContextCreate(
        pixelData,
        Int(568),
        Int(320),
        8,
        Int(8 * 320),
        rgbColorSpace,
        bitmapInfo
    )



    var imageDataProvider = CGDataProviderCreateWithCFData(imageData)
    var imageRef = CGImageCreateWithJPEGDataProvider(imageDataProvider, nil, true, kCGRenderingIntentDefault)

    CGContextDrawImage(context, CGRectMake(0, 0, 568, 320), imageRef)

    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0)
}
ジャスティン・レヴィ・ウィンター

したがってfillPixelBufferFromImage、ここで見つけた例を使用して書き直すことで、これを解決することができました:CVPixelBufferPool Error(kCVReturnInvalidArgument / -6661)

これが私のために働いているSwift2-Xcode 7GMソリューションです:

 public func build(progress: (NSProgress -> Void), success: (NSURL -> Void), failure: (NSError -> Void)) {
    let inputSize = CGSize(width: 600, height: 600)
    let outputSize = CGSize(width: 600, height: 600)
    var error: NSError?

    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("AssembledVideo.mov")

    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: AVFileTypeQuickTimeMovie) 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(inputSize.width)),
      kCVPixelBufferHeightKey as String: NSNumber(float: Float(inputSize.height)),
    ]

    let pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(
      assetWriterInput: videoWriterInput,
      sourcePixelBufferAttributes: sourcePixelBufferAttributesDictionary
    )

    assert(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)
        let currentProgress = NSProgress(totalUnitCount: Int64(self.photoURLs.count))

        var frameCount: Int64 = 0
        var remainingPhotoURLs = [String](self.photoURLs)

        while (videoWriterInput.readyForMoreMediaData && !remainingPhotoURLs.isEmpty) {
          let nextPhotoURL = remainingPhotoURLs.removeAtIndex(0)
          let lastFrameTime = CMTimeMake(frameCount, fps)
          let presentationTime = frameCount == 0 ? lastFrameTime : CMTimeAdd(lastFrameTime, frameDuration)


          if !self.appendPixelBufferForImageAtURL(nextPhotoURL, pixelBufferAdaptor: pixelBufferAdaptor, presentationTime: presentationTime) {
            error = NSError(domain: kErrorDomain, code: kFailedToAppendPixelBufferError,
              userInfo: [
                "description": "AVAssetWriterInputPixelBufferAdapter failed to append pixel buffer",
                "rawError": videoWriter.error ?? "(none)"
              ])

            break
          }

          frameCount++

          currentProgress.completedUnitCount = frameCount
          progress(currentProgress)
        }

        videoWriterInput.markAsFinished()
        videoWriter.finishWritingWithCompletionHandler { () -> Void in
          if error == nil {
            success(videoOutputURL)
          }
        }
      })
    } else {
      error = NSError(domain: kErrorDomain, code: kFailedToStartAssetWriterError,
        userInfo: ["description": "AVAssetWriter failed to start writing"]
      )
    }

    if let error = error {
      failure(error)
    }
  }

  public func appendPixelBufferForImageAtURL(urlString: String, pixelBufferAdaptor: AVAssetWriterInputPixelBufferAdaptor, presentationTime: CMTime) -> Bool {
    var appendSucceeded = true

    autoreleasepool {
      if let image = UIImage(contentsOfFile: urlString) {

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

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

            fillPixelBufferFromImage(image.CGImage!, pixelBuffer: managedPixelBuffer)

            appendSucceeded = pixelBufferAdaptor.appendPixelBuffer(pixelBuffer, withPresentationTime: presentationTime)

          } else {
            NSLog("error: Failed to allocate pixel buffer from pool")
          }
       }
    }

    return appendSucceeded
  }


  func fillPixelBufferFromImage(image: CGImage, pixelBuffer: CVPixelBuffer){
    let frameSize = CGSizeMake(CGFloat(CGImageGetWidth(image)), CGFloat(CGImageGetHeight(image)))
    CVPixelBufferLockBaseAddress(pixelBuffer, 0)
    let data = CVPixelBufferGetBaseAddress(pixelBuffer)
    let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
    let context = CGBitmapContextCreate(data, Int(frameSize.width), Int(frameSize.height), 8, CVPixelBufferGetBytesPerRow(pixelBuffer), rgbColorSpace, CGImageAlphaInfo.PremultipliedFirst.rawValue)
    CGContextDrawImage(context, CGRectMake(0, 0, CGFloat(CGImageGetWidth(image)), CGFloat(CGImageGetHeight(image))), image)
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0)
  }

ここで作業中のプロジェクトファイル:https//github.com/justinlevi/imagesToVideo

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Python-jsonオブジェクトの配列をデータフレームに変換する方法は?

分類Dev

OHLCVという名前のデータ配列をnumpyデータフレームに変換する方法は?

分類Dev

パンダのデータフレームを配列に変換する

分類Dev

Uint8Arrayビデオをnodejsのフレームに変換する方法

分類Dev

データフレーム列の値を新しい列に変換する

分類Dev

配列をデータフレーム列に変換する

分類Dev

配列の配列をフラット化されたデータフレームに変換する

分類Dev

リストのリストをデータフレーム内の配列の列に変換する

分類Dev

AVAssetWriterでビデオを録画する:最初のフレームは黒です

分類Dev

配列をScalaの列とインデックスを持つデータフレームに変換する

分類Dev

文字列の配列をデータフレーム列の整数の配列に変換します

分類Dev

Pythonでデータフレームの1つの列を2D配列に変換する方法

分類Dev

pyspark | numpy配列のリストをデータフレームの列に変換する

分類Dev

png画像データの配列をビデオファイルに変換する方法

分類Dev

ビデオを連結し、ffmpegでそれらの間に黒いフレームを追加します

分類Dev

配列のPythondictをデータフレームに変換します

分類Dev

データフレームをフィーチャとラベルの配列に変換する

分類Dev

pandasデータフレームを使用するときにExcelに文字列として格納されている行列をnumpy配列に変換する際の問題

分類Dev

PNGフレームをフレームが欠落しているビデオに変換する

分類Dev

200列のnumpy配列をデータフレームに変換する方法は?

分類Dev

doubleの配列のデータフレームをVectorに変換する方法は?

分類Dev

異なる長さのデータフレームのリストを配列に変換します

分類Dev

データフレームを列名と値の構造体の配列に変換する

分類Dev

データフレーム列のデータを独自のデータフレームに変換する

分類Dev

AVMutableComposition 作成後のビデオ終了時の黒いフレーム

分類Dev

データフレームセルのコンマ区切り値をJuliaの配列に変換するにはどうすればよいですか?

分類Dev

dataFrameの配列を単一のデータフレームに変換するにはどうすればよいですか?

分類Dev

パンダのデータフレームをNumPy配列に変換する方法は?

分類Dev

配列のリストをSparkデータフレームに変換する方法

Related 関連記事

  1. 1

    Python-jsonオブジェクトの配列をデータフレームに変換する方法は?

  2. 2

    OHLCVという名前のデータ配列をnumpyデータフレームに変換する方法は?

  3. 3

    パンダのデータフレームを配列に変換する

  4. 4

    Uint8Arrayビデオをnodejsのフレームに変換する方法

  5. 5

    データフレーム列の値を新しい列に変換する

  6. 6

    配列をデータフレーム列に変換する

  7. 7

    配列の配列をフラット化されたデータフレームに変換する

  8. 8

    リストのリストをデータフレーム内の配列の列に変換する

  9. 9

    AVAssetWriterでビデオを録画する:最初のフレームは黒です

  10. 10

    配列をScalaの列とインデックスを持つデータフレームに変換する

  11. 11

    文字列の配列をデータフレーム列の整数の配列に変換します

  12. 12

    Pythonでデータフレームの1つの列を2D配列に変換する方法

  13. 13

    pyspark | numpy配列のリストをデータフレームの列に変換する

  14. 14

    png画像データの配列をビデオファイルに変換する方法

  15. 15

    ビデオを連結し、ffmpegでそれらの間に黒いフレームを追加します

  16. 16

    配列のPythondictをデータフレームに変換します

  17. 17

    データフレームをフィーチャとラベルの配列に変換する

  18. 18

    pandasデータフレームを使用するときにExcelに文字列として格納されている行列をnumpy配列に変換する際の問題

  19. 19

    PNGフレームをフレームが欠落しているビデオに変換する

  20. 20

    200列のnumpy配列をデータフレームに変換する方法は?

  21. 21

    doubleの配列のデータフレームをVectorに変換する方法は?

  22. 22

    異なる長さのデータフレームのリストを配列に変換します

  23. 23

    データフレームを列名と値の構造体の配列に変換する

  24. 24

    データフレーム列のデータを独自のデータフレームに変換する

  25. 25

    AVMutableComposition 作成後のビデオ終了時の黒いフレーム

  26. 26

    データフレームセルのコンマ区切り値をJuliaの配列に変換するにはどうすればよいですか?

  27. 27

    dataFrameの配列を単一のデータフレームに変換するにはどうすればよいですか?

  28. 28

    パンダのデータフレームをNumPy配列に変換する方法は?

  29. 29

    配列のリストをSparkデータフレームに変換する方法

ホットタグ

アーカイブ