Saving video from CMSampleBuffer while streaming using ReplayKit

前端 未结 3 959
挽巷
挽巷 2020-12-29 17:41

I\'m streaming a content of my app to my RTMP server and using RPBroadcastSampleHandler.

One of the methods is

override func processSampleBuffer(_ s         


        
相关标签:
3条回答
  • 2020-12-29 18:14

    You can try this:

    override func broadcastFinished() {
        Log(#function)
        ...
        // Need to give the end CMTime, if not set, the video cannot be used
        videoWriter.endSession(atSourceTime: ...)
        videoWriter.finishWriting {
            // Callback cannot be executed here
        }
        ...
        // The program has been executed.
    }
    
    0 讨论(0)
  • 2020-12-29 18:17

    @Marty's answer should be accepted because he pointed out the problem and its DispatchGroup solution works perfectly.
    Since he used a while loop and didn't describe how to use DispatchGroups, here's the way I implemented it.

    override func broadcastFinished() {
        let dispatchGroup = DispatchGroup()
        dispatchGroup.enter()
        self.writerInput.markAsFinished()
        self.writer.finishWriting {
            // Do your work to here to make video available
            dispatchGroup.leave()
        }
        dispatchGroup.wait() // <= blocks the thread here
    }
    
    0 讨论(0)
  • 2020-12-29 18:20

    From https://developer.apple.com/documentation/avfoundation/avassetwriter/1390432-finishwritingwithcompletionhandl

    This method returns immediately and causes its work to be performed asynchronously

    When broadcastFinished returns, your extension is killed. The only way I've been able to get this to work is by blocking the method from returning until the video processing is done. I'm not sure if this is the correct way to do it (seems weird), but it works. Something like this:

            var finishedWriting = false
            videoWriter.finishWriting {
                NSLog("DEBUG:::The videoWriter finished writing.")
                if videoWriter.status == .completed {
                    NSLog("DEBUG:::The videoWriter status is completed")
    
                    let fileManager = FileManager.default
                    if fileManager.fileExists(atPath: self.videoOutputFullFileName!) {
                        NSLog("DEBUG:::The file: \(self.videoOutputFullFileName ?? "") has been saved in documents folder, and is ready to be moved to camera roll")
    
                        let sharedFileURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.xxx.com")
                        guard let documentsPath = sharedFileURL?.path else {
                            NSLog("ERROR:::No shared file URL path")
                            finishedWriting = true
                            return
                        }
                        let finalFilename = documentsPath + "/test_capture_video.mp4"
    
                        //Check whether file exists
                        if fileManager.fileExists(atPath: finalFilename) {
                            NSLog("WARN:::The file: \(finalFilename) exists, will delete the existing file")
                            do {
                                try fileManager.removeItem(atPath: finalFilename)
                            } catch let error as NSError {
                                NSLog("WARN:::Cannot delete existing file: \(finalFilename), error: \(error.debugDescription)")
                            }
                        } else {
                            NSLog("DEBUG:::The file \(self.videoOutputFullFileName!) doesn't exist")
                        }
    
                        do {
                            try fileManager.copyItem(at: URL(fileURLWithPath: self.videoOutputFullFileName!), to: URL(fileURLWithPath: finalFilename))
                        }
                        catch let error as NSError {
                            NSLog("ERROR:::\(error.debugDescription)")
                        }
    
                        PHPhotoLibrary.shared().performChanges({
                            PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: "xxx")
                            PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: finalFilename))
                        }) { completed, error in
                            if completed {
                                NSLog("Video \(self.videoOutputFullFileName ?? "") has been moved to camera roll")
                            }
    
                            if error != nil {
                                NSLog("ERROR:::Cannot move the video \(self.videoOutputFullFileName ?? "") to camera roll, error: \(error!.localizedDescription)")
                            }
    
                            finishedWriting = true
                        }
    
                    } else {
                        NSLog("ERROR:::The file: \(self.videoOutputFullFileName ?? "") doesn't exist, so can't move this file camera roll")
                        finishedWriting = true
                    }
                } else {
                    NSLog("WARN:::The videoWriter status is not completed, status: \(videoWriter.status)")
                    finishedWriting = true
                }
            }
    
            while finishedWriting == false {
        //          NSLog("DEBUG:::Waiting to finish writing...")
            }
    

    I would think you'd have to also call extensionContext.completeRequest at some point, but mine's working fine without it shrug.

    0 讨论(0)
提交回复
热议问题