使用 AVAssetWriterVideoInput 无法将帧附加到视频文件。最后失败并出现未记录的错误 -12738
Failure to append frames to video file using AVAssetWriterVideoInput. Fails with undocumented error -12738 at the end
我正在使用 AVAssetWriterVideoInput 将缓冲区附加到文件。我有这个代码:
if ( _assetWriter.status == AVAssetWriterStatusWriting ) {
// If the asset writer status is writing, append sample buffer to its corresponding asset writer input
if (mediaType == AVMediaTypeVideo) {
if (_assetWriterVideoInput.readyForMoreMediaData) {
if (![_assetWriterVideoInput appendSampleBuffer:sampleBuffer]) {
NSLog(@"error: %@", [_assetWriter.error localizedFailureReason]);
NSLog(@"error: %@", [_assetWriter.error localizedRecoveryOptions]);
NSLog(@"error: %@", [_assetWriter.error localizedDescription]);
NSLog(@"error: %@", [_assetWriter.error domain]);
NSLog(@"error: %@", [_assetWriter.error userInfo]);
} else
NSLog(@"frame saved");
}
}
这一行
if (![_assetWriterVideoInput appendSampleBuffer:sampleBuffer]) {
因 unknown error
和代码 -12738
而失败,显然在任何 documentation 上都找不到,正如所有苹果文档所预期的那样。
此外,我怀疑这是一个未知错误,原因很简单,因为 AVFoundation 中有很多未知错误的代码,如果系统正在选择代码 -12738
它显然知道的不仅仅是说它是未知。
查看正在保存的文件,它保持 0 兆字节,因为没有 buffer/frame 被保存。
这个 AVAssetWriterVideoInput
是这样创建的:
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(currentFormatDescription);
NSUInteger numPixels = dimensions.width * dimensions.height;
NSUInteger bitsPerSecond;
// Assume that lower-than-SD resolutions are intended for streaming, and use a lower bitrate
NSUInteger bitsPerPixel = 11.4; // This bitrate matches the quality produced by AVCaptureSessionPresetHigh.
bitsPerSecond = numPixels * bitsPerPixel;
NSDictionary *videoCompressionSettings = @{AVVideoCodecKey : AVVideoCodecH264,
AVVideoWidthKey : @(dimensions.width),
AVVideoHeightKey : @(dimensions.height),
AVVideoCompressionPropertiesKey : @{ AVVideoAverageBitRateKey : @(bitsPerSecond),
AVVideoMaxKeyFrameIntervalKey : @(30)} };
if ([_assetWriter canApplyOutputSettings:videoCompressionSettings forMediaType:AVMediaTypeVideo])
{
// Intialize asset writer video input with the above created settings dictionary
_assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoCompressionSettings];
_assetWriterVideoInput.expectsMediaDataInRealTime = YES;
并且缓冲区在附加时具有以下特征:
CMSampleBuffer 0x1009e12a0 retainCount: 1 allocator: 0x1b762cbb8
invalid = NO
dataReady = YES
makeDataReadyCallback = 0x0
makeDataReadyRefcon = 0x0
formatDescription = <CMVideoFormatDescription 0x170443210 [0x1b762cbb8]> {
mediaType:'vide'
mediaSubType:'BGRA'
mediaSpecific: {
codecType: 'BGRA' dimensions: 1920 x 1080
}
extensions: {<CFBasicHash 0x17087c2c0 [0x1b762cbb8]>{type = immutable dict, count = 2,
entries =>
0 : <CFString 0x1b1c6d460 [0x1b762cbb8]>{contents = "Version"} = <CFNumber 0xb000000000000022 [0x1b762cbb8]>{value = +2, type = kCFNumberSInt32Type}
2 : <CFString 0x1b1c6d3e0 [0x1b762cbb8]>{contents = "CVBytesPerRow"} = <CFNumber 0xb00000000001e002 [0x1b762cbb8]>{value = +7680, type = kCFNumberSInt32Type}
}
}
}
sbufToTrackReadiness = 0x0
numSamples = 1
sampleTimingArray[1] = {
{PTS = {290309939228910/1000000000 = 290309.939}, DTS = {INVALID}, duration = {INVALID}},
}
imageBuffer = 0x170321180
I have a sample code here如果你想检查问题。该代码已准备好拍摄 4K 视频。如果您的设备无法做到这一点,请将行 AVCaptureSessionPreset3840x2160
更改为 AVCaptureSessionPresetHighinside
ProcessadorVideo.m`。示例代码从视频流中裁剪出一个矩形并对其应用漫画效果。
谢谢
我尝试了您的示例,但无法重现错误 -12783。但是我得到了另一个错误-12780。我用了 iPhone 6s 所以不确定是不是因为这个。
无论如何,我可以修复错误 -12780。由于旧时间戳,您正面临此问题。为了调试目的,我在你的应用程序中添加了一些日志。见下文
2017-01-26 15:00:35.809590 NotWriting[16829:3116125] 从 401051199680537 开始
2017-01-26 15:00:35.809986 NotWriting[16829:3116125] 添加时间戳为 401051199680537 的视频缓冲区
2017-01-26 15:00:35.810008 NotWriting[16829:3116125] presentationTimeStamp 小于最后一帧时间戳,所以可能会失败
2017-01-26 15:00:35.815605 NotWriting[16829:3116125] 错误:发生未知错误 (-12780)
写入缓冲区时,必须确保呈现时间戳大于写入的最后一帧,否则写入将失败。您可以使用以下逻辑添加检查:
CMTime presentationTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
if(CMTIME_COMPARE_INLINE(presentationTimeStamp, <=, lastpresentationTimeStamp))
{
NSLog(@"presentationTimeStamp is less than last frame timestamp, So rejecting frame");
return;
}
lastpresentationTimeStamp = presentationTimeStamp;
我正在使用 AVAssetWriterVideoInput 将缓冲区附加到文件。我有这个代码:
if ( _assetWriter.status == AVAssetWriterStatusWriting ) {
// If the asset writer status is writing, append sample buffer to its corresponding asset writer input
if (mediaType == AVMediaTypeVideo) {
if (_assetWriterVideoInput.readyForMoreMediaData) {
if (![_assetWriterVideoInput appendSampleBuffer:sampleBuffer]) {
NSLog(@"error: %@", [_assetWriter.error localizedFailureReason]);
NSLog(@"error: %@", [_assetWriter.error localizedRecoveryOptions]);
NSLog(@"error: %@", [_assetWriter.error localizedDescription]);
NSLog(@"error: %@", [_assetWriter.error domain]);
NSLog(@"error: %@", [_assetWriter.error userInfo]);
} else
NSLog(@"frame saved");
}
}
这一行
if (![_assetWriterVideoInput appendSampleBuffer:sampleBuffer]) {
因 unknown error
和代码 -12738
而失败,显然在任何 documentation 上都找不到,正如所有苹果文档所预期的那样。
此外,我怀疑这是一个未知错误,原因很简单,因为 AVFoundation 中有很多未知错误的代码,如果系统正在选择代码 -12738
它显然知道的不仅仅是说它是未知。
查看正在保存的文件,它保持 0 兆字节,因为没有 buffer/frame 被保存。
这个 AVAssetWriterVideoInput
是这样创建的:
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(currentFormatDescription);
NSUInteger numPixels = dimensions.width * dimensions.height;
NSUInteger bitsPerSecond;
// Assume that lower-than-SD resolutions are intended for streaming, and use a lower bitrate
NSUInteger bitsPerPixel = 11.4; // This bitrate matches the quality produced by AVCaptureSessionPresetHigh.
bitsPerSecond = numPixels * bitsPerPixel;
NSDictionary *videoCompressionSettings = @{AVVideoCodecKey : AVVideoCodecH264,
AVVideoWidthKey : @(dimensions.width),
AVVideoHeightKey : @(dimensions.height),
AVVideoCompressionPropertiesKey : @{ AVVideoAverageBitRateKey : @(bitsPerSecond),
AVVideoMaxKeyFrameIntervalKey : @(30)} };
if ([_assetWriter canApplyOutputSettings:videoCompressionSettings forMediaType:AVMediaTypeVideo])
{
// Intialize asset writer video input with the above created settings dictionary
_assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoCompressionSettings];
_assetWriterVideoInput.expectsMediaDataInRealTime = YES;
并且缓冲区在附加时具有以下特征:
CMSampleBuffer 0x1009e12a0 retainCount: 1 allocator: 0x1b762cbb8
invalid = NO
dataReady = YES
makeDataReadyCallback = 0x0
makeDataReadyRefcon = 0x0
formatDescription = <CMVideoFormatDescription 0x170443210 [0x1b762cbb8]> {
mediaType:'vide'
mediaSubType:'BGRA'
mediaSpecific: {
codecType: 'BGRA' dimensions: 1920 x 1080
}
extensions: {<CFBasicHash 0x17087c2c0 [0x1b762cbb8]>{type = immutable dict, count = 2,
entries =>
0 : <CFString 0x1b1c6d460 [0x1b762cbb8]>{contents = "Version"} = <CFNumber 0xb000000000000022 [0x1b762cbb8]>{value = +2, type = kCFNumberSInt32Type}
2 : <CFString 0x1b1c6d3e0 [0x1b762cbb8]>{contents = "CVBytesPerRow"} = <CFNumber 0xb00000000001e002 [0x1b762cbb8]>{value = +7680, type = kCFNumberSInt32Type}
}
}
}
sbufToTrackReadiness = 0x0
numSamples = 1
sampleTimingArray[1] = {
{PTS = {290309939228910/1000000000 = 290309.939}, DTS = {INVALID}, duration = {INVALID}},
}
imageBuffer = 0x170321180
I have a sample code here如果你想检查问题。该代码已准备好拍摄 4K 视频。如果您的设备无法做到这一点,请将行 AVCaptureSessionPreset3840x2160
更改为 AVCaptureSessionPresetHighinside
ProcessadorVideo.m`。示例代码从视频流中裁剪出一个矩形并对其应用漫画效果。
谢谢
我尝试了您的示例,但无法重现错误 -12783。但是我得到了另一个错误-12780。我用了 iPhone 6s 所以不确定是不是因为这个。
无论如何,我可以修复错误 -12780。由于旧时间戳,您正面临此问题。为了调试目的,我在你的应用程序中添加了一些日志。见下文
2017-01-26 15:00:35.809590 NotWriting[16829:3116125] 从 401051199680537 开始 2017-01-26 15:00:35.809986 NotWriting[16829:3116125] 添加时间戳为 401051199680537 的视频缓冲区 2017-01-26 15:00:35.810008 NotWriting[16829:3116125] presentationTimeStamp 小于最后一帧时间戳,所以可能会失败 2017-01-26 15:00:35.815605 NotWriting[16829:3116125] 错误:发生未知错误 (-12780)
写入缓冲区时,必须确保呈现时间戳大于写入的最后一帧,否则写入将失败。您可以使用以下逻辑添加检查:
CMTime presentationTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
if(CMTIME_COMPARE_INLINE(presentationTimeStamp, <=, lastpresentationTimeStamp))
{
NSLog(@"presentationTimeStamp is less than last frame timestamp, So rejecting frame");
return;
}
lastpresentationTimeStamp = presentationTimeStamp;