创建静音音频CMSampleBufferRef

时间:2015-12-23 18:28:31

标签: ios swift avfoundation

如何在Swift中创建静音音频CMSampleBufferRef?我希望将无声的CMSampleBufferRef附加到AVAssetWriterInput的实例。

3 个答案:

答案 0 :(得分:7)

你没有说你想要什么格式的零(整数/浮点,单声道/立体声,采样率),但也许没关系。无论如何,这是在swift中创建静音CD音频样式CMSampleBuffer的一种方法。

func createSilentAudio(startFrm: Int64, nFrames: Int, sampleRate: Float64, numChannels: UInt32) -> CMSampleBuffer? {
    let bytesPerFrame = UInt32(2 * numChannels)
    let blockSize = nFrames*Int(bytesPerFrame)

    var block: CMBlockBuffer?
    var status = CMBlockBufferCreateWithMemoryBlock(
        kCFAllocatorDefault,
        nil,
        blockSize,  // blockLength
        nil,        // blockAllocator
        nil,        // customBlockSource
        0,          // offsetToData
        blockSize,  // dataLength
        0,          // flags
        &block
    )
    assert(status == kCMBlockBufferNoErr)

    // we seem to get zeros from the above, but I can't find it documented. so... memset:
    status = CMBlockBufferFillDataBytes(0, block!, 0, blockSize)
    assert(status == kCMBlockBufferNoErr)

    var asbd = AudioStreamBasicDescription(
        mSampleRate: sampleRate,
        mFormatID: kAudioFormatLinearPCM,
        mFormatFlags: kLinearPCMFormatFlagIsSignedInteger,
        mBytesPerPacket: bytesPerFrame,
        mFramesPerPacket: 1,
        mBytesPerFrame: bytesPerFrame,
        mChannelsPerFrame: numChannels,
        mBitsPerChannel: 16,
        mReserved: 0
    )

    var formatDesc: CMAudioFormatDescription?
    status = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &asbd, 0, nil, 0, nil, nil, &formatDesc)
    assert(status == noErr)

    var sampleBuffer: CMSampleBuffer?

    // born ready
    status = CMAudioSampleBufferCreateReadyWithPacketDescriptions(
        kCFAllocatorDefault,
        block,      // dataBuffer
        formatDesc!,
        nFrames,    // numSamples
        CMTimeMake(startFrm, Int32(sampleRate)),    // sbufPTS
        nil,        // packetDescriptions
        &sampleBuffer
    )
    assert(status == noErr)

    return sampleBuffer
}

你问这个不是很难过吗?你真的需要沉默CMSampleBuffer吗?你不能通过向前移动演示时间戳来将沉默插入AVAssetWriterInput吗?

答案 1 :(得分:1)

您需要使用CMBlockBufferCreateWithMemoryBlock()创建块缓冲区。 用一堆零填充块缓冲区,然后将其传递到CMAudioSampleBufferCreateWithPacketDescriptions()

免责声明:我实际上并没有在Swift中做到这一点,我尝试了但发现自己每次都在与编译器对抗,所以我切换到了obj-c。 Core Media Framework是一个低级别的C框架,在不使用Swifts类型系统的情况下更容易使用。我知道这不是你正在寻找的答案,希望它会指引你朝着正确的方向前进。

Example

答案 2 :(得分:0)

已针对XCode 10.3更新。斯威夫特5.0.1。 不要忘记import CoreMedia

import Foundation
import CoreMedia

class CMSampleBufferFactory
{
    static func createSilentAudio(startFrm: Int64, nFrames: Int, sampleRate: Float64, numChannels: UInt32) -> CMSampleBuffer? {
        let bytesPerFrame = UInt32(2 * numChannels)
        let blockSize = nFrames*Int(bytesPerFrame)

        var block: CMBlockBuffer?
        var status = CMBlockBufferCreateWithMemoryBlock(
            allocator: kCFAllocatorDefault,
            memoryBlock: nil,
            blockLength: blockSize,
            blockAllocator: nil,
            customBlockSource: nil,
            offsetToData: 0,
            dataLength: blockSize,
            flags: 0,
            blockBufferOut: &block
        )
        assert(status == kCMBlockBufferNoErr)

        guard var eBlock = block else { return nil }

        // we seem to get zeros from the above, but I can't find it documented. so... memset:
        status = CMBlockBufferFillDataBytes(with: 0, blockBuffer: eBlock, offsetIntoDestination: 0, dataLength: blockSize)
        assert(status == kCMBlockBufferNoErr)


        var asbd = AudioStreamBasicDescription(
            mSampleRate: sampleRate,
            mFormatID: kAudioFormatLinearPCM,
            mFormatFlags: kLinearPCMFormatFlagIsSignedInteger,
            mBytesPerPacket: bytesPerFrame,
            mFramesPerPacket: 1,
            mBytesPerFrame: bytesPerFrame,
            mChannelsPerFrame: numChannels,
            mBitsPerChannel: 16,
            mReserved: 0
        )

        var formatDesc: CMAudioFormatDescription?
        status = CMAudioFormatDescriptionCreate(allocator: kCFAllocatorDefault, asbd: &asbd, layoutSize: 0, layout: nil, magicCookieSize: 0, magicCookie: nil, extensions: nil, formatDescriptionOut: &formatDesc)
        assert(status == noErr)

        var sampleBuffer: CMSampleBuffer?

        status = CMAudioSampleBufferCreateReadyWithPacketDescriptions(
            allocator: kCFAllocatorDefault,
            dataBuffer: eBlock,
            formatDescription: formatDesc!,
            sampleCount: nFrames,
            presentationTimeStamp: CMTimeMake(value: startFrm, timescale: Int32(sampleRate)),  
            packetDescriptions: nil,
            sampleBufferOut: &sampleBuffer
        )
        assert(status == noErr)
        return sampleBuffer
    }
}