2

我正在使用将通过以下方式捕获的AudioConverter未压缩转换为:CMSampleBufferAVCaptureSessionAudioBufferList

let status: OSStatus = AudioConverterFillComplexBuffer(
            converter,
            inputDataProc,
            Unmanaged.passUnretained(self).toOpaque(),
            &ioOutputDataPacketSize,
            outOutputData.unsafeMutablePointer,
            nil
        )

我的输出 asbd 设置如下:

AudioStreamBasicDescription
- mSampleRate : 44100.0
- mFormatID : 1633772320
- mFormatFlags : 2
- mBytesPerPacket : 0
- mFramesPerPacket : 1024
- mBytesPerFrame : 0
- mChannelsPerFrame : 1
- mBitsPerChannel : 0
- mReserved : 0

我想转换AudioBufferListCMSampleBuffer包含压缩数据,以便我可以将其写入 mp4 文件使用AVAssetWriter(我已经想出如何用视频来做到这一点),但到目前为止很少。我试过咨询这个答案,但在那种情况下有 PCM 数据,它似乎在这里不可用。

我可以访问AudioBufferList以及原始样本的presentationTimeStamp。我尝试了以下方法,但我不太确定如何计算 numSamples 以及这种方法是否有意义:

 func createCMSampleBuffer(_ data: UnsafeMutableAudioBufferListPointer, presentationTimeStamp: CMTime) -> CMSampleBuffer? {
    let numSamples = // not sure how to get this

    var status: OSStatus = noErr
    var sampleBuffer: CMSampleBuffer?
    var timing: CMSampleTimingInfo = CMSampleTimingInfo(
        duration: CMTime(value: CMTimeValue(numSamples), timescale: presentationTimeStamp.timescale),
        presentationTimeStamp: presentationTimeStamp,
        decodeTimeStamp: CMTime.invalid
    )

    status = CMSampleBufferCreate(
        allocator: kCFAllocatorDefault,
        dataBuffer: nil,
        dataReady: false,
        makeDataReadyCallback: nil,
        refcon: nil,
        formatDescription: formatDescription,
        sampleCount: CMItemCount(numSamples),
        sampleTimingEntryCount: 1,
        sampleTimingArray: &timing,
        sampleSizeEntryCount: 0,
        sampleSizeArray: nil,
        sampleBufferOut: &sampleBuffer
    )

    guard status == noErr else {
        return nil
    }

    status = CMSampleBufferSetDataBufferFromAudioBufferList(
        sampleBuffer!,
        blockBufferAllocator: kCFAllocatorDefault,
        blockBufferMemoryAllocator: kCFAllocatorDefault,
        flags: 0,
        bufferList: data.unsafePointer
    )

    guard status == noErr else {
        return nil
    }

    return sampleBuffer
}

最后我确实设法创建了一个CMSampleBuffer,但是当我尝试完成写作时,我收到以下错误:

Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSUnderlyingError=0x174442ac0 {Error Domain=NSOSStatusErrorDomain Code=-12735 "(null)"}, NSLocalizedFailureReason=An unknown error occurred (-12735), NSLocalizedDescription=The operation could not be completed}
4

2 回答 2

1

所以,我已经设法取得了一些进展(但离让一切正常工作还有很长的路要走)。我没有像上面那样构建 CMSampleBuffer ,而是设法使以下(有点)工作:

CMAudioSampleBufferCreateWithPacketDescriptions(
        allocator: kCFAllocatorDefault,
        dataBuffer: nil,
        dataReady: false,
        makeDataReadyCallback: nil,
        refcon: nil,
        formatDescription: formatDescription!,
        sampleCount: Int(data.unsafePointer.pointee.mNumberBuffers),
        presentationTimeStamp: presentationTimeStamp,
        packetDescriptions: &packetDescriptions,
        sampleBufferOut: &sampleBuffer)

这里的关键是从压缩过程中获取packetDescriptions:

let packetDescriptionsPtr = UnsafeMutablePointer<AudioStreamPacketDescription>.allocate(capacity: 1)

AudioConverterFillComplexBuffer(
                converter,
                inputDataProc,
                Unmanaged.passUnretained(self).toOpaque(),
                &ioOutputDataPacketSize,
                outOutputData.unsafeMutablePointer,
                packetDescriptionsPtr
            )

音频 CMSampleBuffer 现在似乎已正确创建,但是当我附加它时,音频不会播放,并且会在视频中产生奇怪的时序故障。

于 2019-12-30T13:05:40.067 回答
1

我可以分享一些这方面的研究工作,可能会对你有所帮助......

CMSampleBufferSetDataBufferFromAudioBufferList returned error: -12731

解决方案:- https://lists.apple.com/archives/coreaudio-api/2014/Mar/msg00008.html

或者也使用准确的 CMTime 将 AudioBuffer 转换为 CMSampleBuffer

可能会帮助你... :)

于 2019-12-28T11:54:47.703 回答