调用broadcastPaused()后的AVAssetWriter异步视频和音频

时间:2021-05-12 17:25:47

标签: ios swift avassetwriter

我正在尝试使用 ReplayKit 和 RPBroadcastSampleHandler 从设备屏幕录制带有声音的视频。

当我只使用“开始广播”和“停止”录制时,我得到的结果很棒。

但是如果我尝试暂停录制(通过使用红色状态栏),我就会遇到问题。我得到的结果是不同长度的视频和音频(音频较短,但有我需要的一切)。在录制中,我得到了在点击状态栏(ios14)后开始异步的视频和音频。音频运行良好,但点击状态栏时视频冻结,并在模式窗口关闭时继续。结果我最后得到了没有音频的视频。

这是我的代码:

1.我拥有的所有类字段:

class SampleHandler: RPBroadcastSampleHandler {
    
    private let videoService = VideoService()
    private let audioService = AudioService()
    private var isRecording = false
    
    private let lock = NSLock()
    private var finishCalled = false
    
    private var videoWriter: AVAssetWriter!
    private var videoWriterInput: AVAssetWriterInput!
    private var microphoneWriterInput: AVAssetWriterInput!
    private var sessionBeginAtSourceTime: CMTime!

2.开始捕获时的一些配置:

override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
    guard !isRecording else { return }
    isRecording = true
    BroadcastData.clear()
    BroadcastData.startVideoDate = Date()
    BroadcastData.status = .writing
    sessionBeginAtSourceTime = nil
                    
    configurateVideoWriter()
}

private func configurateVideoWriter() {
    let outputFileLocation = videoService.getVideoFileLocation()
    
    videoWriter = try? AVAssetWriter.init(outputURL: outputFileLocation,
                                          fileType: AVFileType.mov)
    
    configurateVideoWriterInput()
    configurateMicrophoneWriterInput()
    
    if videoWriter.canAdd(videoWriterInput) { videoWriter.add(videoWriterInput) }
    if videoWriter.canAdd(microphoneWriterInput) { videoWriter.add(microphoneWriterInput) }

    videoWriter.startWriting()
}

private func configurateVideoWriterInput() {
    let RESOLUTION_COEF: CGFloat = 16
    let naturalWidth = UIScreen.main.bounds.width
    let naturalHeight = UIScreen.main.bounds.height
    let width = naturalWidth - naturalWidth.truncatingRemainder(dividingBy: RESOLUTION_COEF)
    let height = naturalHeight - naturalHeight.truncatingRemainder(dividingBy: RESOLUTION_COEF)
    
    let videoSettings: [String: Any] = [
        AVVideoCodecKey: AVVideoCodecType.h264,
        AVVideoWidthKey: width,
        AVVideoHeightKey: height
    ]
    
    videoWriterInput = AVAssetWriterInput(mediaType: .video,
                                          outputSettings: videoSettings)
    videoWriterInput.expectsMediaDataInRealTime = true
}

private func configurateMicrophoneWriterInput() {
    let audioOutputSettings: [String : Any] = [
        AVFormatIDKey: kAudioFormatMPEG4AAC,
        AVNumberOfChannelsKey : 1,
        AVSampleRateKey : 44100.0,
        AVEncoderBitRateKey: 96000
    ]

    microphoneWriterInput = AVAssetWriterInput(mediaType: .audio,
                                               outputSettings: audioOutputSettings)
    microphoneWriterInput.expectsMediaDataInRealTime = true
}

3.写入过程:

override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: 
RPSampleBufferType) {
    guard isRecording && videoWriter?.status == .writing else { return }
    
    if BroadcastData.status != .writing {
        isRecording = false
        finishBroadCast()
        return
    }
    
    if sessionBeginAtSourceTime == nil {
        sessionBeginAtSourceTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
        videoWriter.startSession(atSourceTime: sessionBeginAtSourceTime!)
    }
    
    switch sampleBufferType {
    case .video:
        if videoWriterInput.isReadyForMoreMediaData {
            videoWriterInput.append(sampleBuffer)
        }
    case .audioMic:
        if microphoneWriterInput.isReadyForMoreMediaData {
            microphoneWriterInput.append(sampleBuffer)
        }
    case .audioApp:
        break
    @unknown default:
        print("unknown")
    }
}

4.暂停和恢复

override func broadcastPaused() {
    super.broadcastPaused()
}

override func broadcastResumed() {
    super.broadcastResumed()
}

1 个答案:

答案 0 :(得分:0)

暂停和恢复录制会导致视频演示时间戳和音频不连续,我相信这可以解释您的症状。

您需要做的是测量录制暂停的时间,可能使用示例缓冲区时间戳,然后从您处理的所有后续 CMSampleBuffer 的演示时间戳中减去该偏移量。 CMSampleBufferCreateCopyWithNewTiming() 可以为您提供帮助。