web-dev-qa-db-ja.com

Swift)でAVAssetWriterを使用してAVCaptureVideoDataOutputをムービーファイルに保存します

私はウェブ全体を探していましたが、必要なチュートリアルやヘルプが見つからないようです。

AVFoundationとDlibライブラリを使用して、電話のフロントカメラを使用してリアルタイムビデオから顔を検出できるアプリを作成しました。私はShape Predictor 68 Face Landmarksを使用してこれを行っています。これが機能するためには、AVMovieFileOutputではなくAVCaptureVideoDataOutputを使用して、各フレームを分析できるようにする必要があると確信しています。

ビデオをファイルに保存できるようにしたいので、収集したものからAVAssetWriterを使用してこれを行う必要があります。私はこれを始める方法についてどこにも多くの情報を見つけることができません。私はSwiftとiOSプログラミングに完全に慣れていないので、Appleのドキュメントを見てもあまり理解できません。

誰かが私を助けることができれば大歓迎です!

7
Hardy143

AVAssetWriterの使い方を知ることができました。他の誰かが助けを必要とする場合に備えて、私が使用したコードは次のとおりです。

func setUpWriter() {

    do {
        outputFileLocation = videoFileLocation()
        videoWriter = try AVAssetWriter(outputURL: outputFileLocation!, fileType: AVFileType.mov)

        // add video input
        videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: [
            AVVideoCodecKey : AVVideoCodecType.h264,
            AVVideoWidthKey : 720,
            AVVideoHeightKey : 1280,
            AVVideoCompressionPropertiesKey : [
                AVVideoAverageBitRateKey : 2300000,
                ],
            ])

        videoWriterInput.expectsMediaDataInRealTime = true

        if videoWriter.canAdd(videoWriterInput) {
            videoWriter.add(videoWriterInput)
            print("video input added")
        } else {
            print("no input added")
        }

        // add audio input
        audioWriterInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)

        audioWriterInput.expectsMediaDataInRealTime = true

        if videoWriter.canAdd(audioWriterInput!) {
            videoWriter.add(audioWriterInput!)
            print("audio input added")
        }


        videoWriter.startWriting()
    } catch let error {
        debugPrint(error.localizedDescription)
    }


}

func canWrite() -> Bool {
    return isRecording && videoWriter != nil && videoWriter?.status == .writing
}


 //video file location method
func videoFileLocation() -> URL {
    let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
    let videoOutputUrl = URL(fileURLWithPath: documentsPath.appendingPathComponent("videoFile")).appendingPathExtension("mov")
    do {
    if FileManager.default.fileExists(atPath: videoOutputUrl.path) {
        try FileManager.default.removeItem(at: videoOutputUrl)
        print("file removed")
    }
    } catch {
        print(error)
    }

    return videoOutputUrl
}

// MARK: AVCaptureVideoDataOutputSampleBufferDelegate
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {

    let writable = canWrite()

    if writable,
        sessionAtSourceTime == nil {
        // start writing
        sessionAtSourceTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
        videoWriter.startSession(atSourceTime: sessionAtSourceTime!)
        //print("Writing")
    }

    if output == videoDataOutput {
        connection.videoOrientation = .portrait

        if connection.isVideoMirroringSupported {
            connection.isVideoMirrored = true
        }
    }

    if writable,
        output == videoDataOutput,
        (videoWriterInput.isReadyForMoreMediaData) {
        // write video buffer
        videoWriterInput.append(sampleBuffer)
        //print("video buffering")
    } else if writable,
        output == audioDataOutput,
        (audioWriterInput.isReadyForMoreMediaData) {
        // write audio buffer
        audioWriterInput?.append(sampleBuffer)
        //print("audio buffering")
    }

}

// MARK: Start recording
func start() {
    guard !isRecording else { return }
    isRecording = true
    sessionAtSourceTime = nil
    setUpWriter()
    print(isRecording)
    print(videoWriter)
    if videoWriter.status == .writing {
        print("status writing")
    } else if videoWriter.status == .failed {
        print("status failed")
    } else if videoWriter.status == .cancelled {
        print("status cancelled")
    } else if videoWriter.status == .unknown {
        print("status unknown")
    } else {
        print("status completed")
    }

}

// MARK: Stop recording
func stop() {
    guard isRecording else { return }
    isRecording = false
    videoWriterInput.markAsFinished()
    print("marked as finished")
    videoWriter.finishWriting { [weak self] in
        self?.sessionAtSourceTime = nil
    }
    //print("finished writing \(self.outputFileLocation)")
    captureSession.stopRunning()
    performSegue(withIdentifier: "videoPreview", sender: nil)
}

AVCaptureMetadataOutput、AVCaptureVideoDataOutput、およびAVCaptureAudioDataOutputを一緒に使用しているときに、このソリューションが機能しないという別の問題が発生しました。 AVCaptureAudioDataOutputを追加すると、アプリがクラッシュします。

12
Hardy143