使用 AVAssetWriter 录制视频:第一帧为黑色
Record video with AVAssetWriter: first frames are black
我正在用 AVAssetWriter
录制视频(用户也可以只切换到音频)。我在应用程序启动时开始录制。
但是第一帧是黑色(或非常暗)。当我从音频切换到视频时也会发生这种情况。
感觉AVAssetWriter
and/orAVAssetWriterInput
还没准备好录制。我怎样才能避免这种情况?
我不知道这是否有用,但我也使用 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")
}
}
}
好吧,愚蠢的错误...
启动应用程序时,我初始化了我的 AVCaptureSession
,添加了输入、输出等。我只是在调用 commitConfiguration
之前调用 start_new_record
有点太早了在我的捕获会话中。
至少我的代码可能对某些人有用。
SWIFT 4
解决方案 #1:
我通过在启动应用程序时尽快调用 file_writer?.startWriting() 解决了这个问题。然后当你想开始录制时,执行 file_writer?.startSession(atSourceTime:...).
当您完成录制并调用 finishRecording 时,当您收到表示完成的回调时,设置一个新的写入会话再次.
解决方案 #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)
这是为了未来的用户...
None 以上对我有用,然后我尝试将相机预设更改为中等效果很好
我正在用 AVAssetWriter
录制视频(用户也可以只切换到音频)。我在应用程序启动时开始录制。
但是第一帧是黑色(或非常暗)。当我从音频切换到视频时也会发生这种情况。
感觉AVAssetWriter
and/orAVAssetWriterInput
还没准备好录制。我怎样才能避免这种情况?
我不知道这是否有用,但我也使用 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")
}
}
}
好吧,愚蠢的错误...
启动应用程序时,我初始化了我的 AVCaptureSession
,添加了输入、输出等。我只是在调用 commitConfiguration
之前调用 start_new_record
有点太早了在我的捕获会话中。
至少我的代码可能对某些人有用。
SWIFT 4
解决方案 #1:
我通过在启动应用程序时尽快调用 file_writer?.startWriting() 解决了这个问题。然后当你想开始录制时,执行 file_writer?.startSession(atSourceTime:...).
当您完成录制并调用 finishRecording 时,当您收到表示完成的回调时,设置一个新的写入会话再次.
解决方案 #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)
这是为了未来的用户...
None 以上对我有用,然后我尝试将相机预设更改为中等效果很好