使用AVAssetWriter录制视频:前几帧视频出现黑屏问题

8
我正在使用AVAssetWriter记录视频(用户也可以切换到仅音频)。我在应用程序启动时开始录制。但是第一帧是黑色的(或非常暗)。当我从音频切换到视频时也会发生这种情况。感觉AVAssetWriter和/或AVAssetWriterInput还没有准备好进行录制。如何避免这种情况?我不知道这是否有用,但我还使用GLKView来显示视频。
func start_new_record(){
    do{
        try self.file_writer=AVAssetWriter(url: self.file_url!, fileType: AVFileTypeMPEG4)
        if video_on{
            if file_writer.canAdd(video_writer){
                file_writer.add(video_writer)
            }
        }
        if file_writer.canAdd(audio_writer){
            file_writer.add(audio_writer)
        }
    }catch let e as NSError{
        print(e)
    }
}

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!){
    guard is_recording else{
        return
    }

    guard CMSampleBufferDataIsReady(sampleBuffer) else{
        print("data not ready")
        return
    }

    guard let w=file_writer else{
        print("video writer nil")
        return
    }

    if w.status == .unknown && start_recording_time==nil{
        if (video_on && captureOutput==video_output) || (!video_on && captureOutput==audio_output){
            print("START RECORDING")
            file_writer?.startWriting()
            start_recording_time=CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
            file_writer?.startSession(atSourceTime: start_recording_time!)
        }else{
            return
        }
    }

    if w.status == .failed{
        print("failed /", w.error ?? "")
        return
    }

    if captureOutput==audio_output{
        if audio_writer.isReadyForMoreMediaData{
            if !video_on || (video_on && video_written){
                audio_writer.append(sampleBuffer)
                //print("write audio")
            }
        }else{
            print("audio writer not ready")
        }
    }else if video_output != nil && captureOutput==video_output{
        if video_writer.isReadyForMoreMediaData{
            video_writer.append(sampleBuffer)
            if !video_written{
                print("added 1st video frame")
                video_written=true
            }
        }else{
            print("video writer not ready")
        }
    }
}

对我来说,解决方案是调用 file_writer?.startWriting(),然后在下一个 runloop 中调用 file_writer?.startSession(atSourceTime: start_recording_time!)。自那以后就再也没有出现过问题。 - zumzum
3个回答

11

SWIFT 4

SOLUTION #1:

我通过在应用程序启动时尽快调用 file_writer?.startWriting() 来解决此问题。然后,在您想要开始录制时,执行file_writer?.startSession(atSourceTime:...)

当您完成录制并调用finishRecording时,在获得说已完成的回调时,再次设置新的写入会话。

SOLUTION #2:

我通过在调用AVAssetWriter.startSession时将起始时间增加半秒来解决此问题,像这样:

start_recording_time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
let startingTimeDelay = CMTimeMakeWithSeconds(0.5, 1000000000)
let startTimeToUse = CMTimeAdd(start_recording_time!, startingTimeDelay)

file_writer?.startSession(atSourceTime: startTimeToUse)

解决方案#3:

更好的解决方案是记录收到的第一帧的时间戳并决定何时开始写入,然后以此开始您的会话。这样,您就不需要任何延迟:

//Initialization, elsewhere:

var is_session_started = false
var videoStartingTimestamp = CMTime.invalid

// In code where you receive frames that you plan to write:

if (!is_session_started) {
    // Start writing at the timestamp of our earliest sample
    videoStartingTimestamp = currentTimestamp
    print ("First video sample received: Starting avAssetWriter Session: \(videoStartingTimestamp)")
    avAssetWriter?.startSession(atSourceTime: videoStartingTimestamp)

    is_session_started = true
}

// add the current frame
pixelBufferAdapter?.append(myPixelBuffer, withPresentationTime: currentTimestamp)

1
我使用了以下1/10秒的延迟。让startingTimeDelay = CMTimeMakeWithSeconds(1, 10) - Hope
我将第一种和第三种解决方案结合起来,但仍然存在延迟和开头的黑帧。 - Chewie The Chorkie
我尝试了所有的解决方案,但仍然在开头得到黑色帧。有人找到了解决办法吗? - Shree Ranga Raju

3

好的,一个愚蠢的错误...

当启动应用程序时,我初始化了我的AVCaptureSession,添加了输入、输出等。我只是在我的捕捉会话上调用commitConfiguration之前有点太快地调用了start_new_record

至少我的代码对某些人可能有用。


我尝试了这个,但仍然得到黑色帧。还有什么可以尝试的? - Kartick Vaddadi
@VaddadiKartick 对不起,我不知道。我建议你检查一下你的配置,就像我一样。你是否在同一个队列上初始化了所有内容?你是否尝试过像我一样不在应用程序启动时开始录制,而是手动开始录制? - Marie Dm

0

这是给未来用户的...

以上的方法都没有对我奏效,后来我尝试将摄像头预设更改为中等,就可以正常工作了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接