代码之家  ›  专栏  ›  技术社区  ›  Duck

无法使用AVAssetWriterVideoInput将帧附加到视频文件。失败,结尾出现未记录的错误-12738

  •  1
  • Duck  · 技术社区  · 8 年前

    我正在使用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兆字节,因为没有保存缓冲区/帧。

    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 至AVCaptureSessionPresetHigh inside Processador视频。m`如果您的设备不能做到这一点。示例代码从视频流中裁剪一个矩形,并对其应用漫画效果。 谢谢

    1 回复  |  直到 8 年前
        1
  •  1
  •   manishg    8 年前

    我尝试了您的示例,但无法复制错误-12783。然而,我得到了另一个错误-12780。我使用了iPhone 6s,因此不确定是否是由于该错误。

    在任何情况下,我都可以修复错误-12780。由于旧的时间戳,您面临这个问题。我在你的应用程序中添加了一些日志以进行调试。见下文

    2017-01-26 15:00:35.809590不写[16829:3116125]从401051199680537开始 2017-01-26 15:00:35.809986不写入[16829:3116125]附加时间戳为401051199680537的视频缓冲区 2017-01-26 15:00:35.810008不写入[16829:3116125]presentationTimeStamp小于最后一帧时间戳,因此可能会失败 2017-01-26 15:00:35.815605不写入[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;