AVAssetWriterInput not generating entire video when appending CMSampleBuffer

Viewed 448

I'm trying to record video via AVAssetWriter. NSData is successfully written to the file path that I specify and extracted as an AVAsset, but it seems to be data representing only 1 frame of the recording, not multiple frames appended together as a video. When I try to play the video in the UI, it immediately completes. And the size of the NSData object is much smaller than expected for a video. That's what makes me think it's only appending 1 frame. Here's my code:

func setupCaptureSession() {
    self.session = AVCaptureSession()
    session!.sessionPreset = AVCaptureSessionPresetMedium
    let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    do {
        let input = try AVCaptureDeviceInput(device: device)
        session!.addInput(input)
    } catch {

    }

    let captureLayer = AVCaptureVideoPreviewLayer(session: session)
    captureLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
    let window = UIApplication.sharedApplication().keyWindow!
    let layerRect = window.layer.bounds
    captureLayer.bounds = layerRect
    captureLayer.position = CGPointMake(CGRectGetMidX(layerRect), CGRectGetMidY(layerRect))
    self.cameraView = NSBundle.mainBundle().loadNibNamed("CameraView", owner: self, options: nil)[0] as? CameraView
    cameraView!.frame = layerRect
    cameraView!.layer.insertSublayer(captureLayer, atIndex: 0)
    window.addSubview(cameraView!)

    let output = AVCaptureVideoDataOutput()
    session!.addOutput(output)

    let queue = dispatch_queue_create("myQueue", nil)
    output.setSampleBufferDelegate(self, queue: queue)

    output.videoSettings = [kCVPixelBufferPixelFormatTypeKey: NSNumber(unsignedInt: kCVPixelFormatType_32BGRA)]
    output.connectionWithMediaType(AVMediaTypeVideo).videoOrientation = .Portrait

    session!.startRunning()
}

Sample buffer delegate:

func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {
    if self.recording == true {
        let window = UIApplication.sharedApplication().keyWindow!
        if let path = Utils.documentDirectory().URLByAppendingPathComponent("temp_video").path {
            print("recording")
            self.videoFromBuffer(sampleBuffer, path: path, size: window.frame.size, duration: self.duration)
        }
    }
}

And the AVAssetWriter:

private func videoFromBuffer(buffer: CMSampleBuffer, path: String, size: CGSize, duration: Int64) {
    do {
        let writer = try AVAssetWriter(URL: NSURL(fileURLWithPath: path), fileType: AVFileTypeMPEG4)
        let settings = [AVVideoCodecKey: AVVideoCodecH264,
            AVVideoWidthKey: NSNumber(integer: Int(size.width)),
            AVVideoHeightKey: NSNumber(integer: Int(size.height))]
        let writerInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: settings)
        writerInput.expectsMediaDataInRealTime = true

        writer.addInput(writerInput)
        writer.startWriting()
        writer.startSessionAtSourceTime(kCMTimeZero)

        writerInput.appendSampleBuffer(buffer)

        writerInput.markAsFinished()
        writer.endSessionAtSourceTime(CMTimeMake(duration, 1))
        writer.finishWritingWithCompletionHandler({ () -> Void in

        })

    } catch {
        print(error)
    }
}

Why is the resulting data not a full video?

0 Answers
Related