gpt4 book ai didi

ios - 使用来自原始 PCM 流的 CMSampleTimingInfo、CMSampleBuffer 和 AudioBufferList

转载 作者:可可西里 更新时间:2023-11-01 04:33:57 27 4
gpt4 key购买 nike

我正在从 Google 的 WebRTC C++ 引用实现(一个插入到 VoEBaseImpl::GetPlayoutData 中的 Hook )接收原始 PCM 流。音频似乎是线性 PCM,符号为 int16,但在使用 AssetWriter 录制时,它会保存到音频文件中,高度失真且音调更高。

我假设这是输入参数某处的错误,最有可能是关于将 stereo-int16 转换为 AudioBufferList,然后再转换为 CMSampleBuffer。下面的代码有什么问题吗?

void RecorderImpl::RenderAudioFrame(void* audio_data, size_t number_of_frames, int sample_rate, int64_t elapsed_time_ms, int64_t ntp_time_ms) {
OSStatus status;

AudioChannelLayout acl;
bzero(&acl, sizeof(acl));
acl.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;

AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate = sample_rate;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 2;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = audioFormat.mFramesPerPacket * audioFormat.mChannelsPerFrame * audioFormat.mBitsPerChannel / 8;
audioFormat.mBytesPerFrame = audioFormat.mBytesPerPacket / audioFormat.mFramesPerPacket;

CMSampleTimingInfo timing = { CMTimeMake(1, sample_rate), CMTimeMake(elapsed_time_ms, 1000), kCMTimeInvalid };

CMFormatDescriptionRef format = NULL;
status = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &audioFormat, sizeof(acl), &acl, 0, NULL, NULL, &format);
if(status != 0) {
NSLog(@"Failed to create audio format description");
return;
}

CMSampleBufferRef buffer;
status = CMSampleBufferCreate(kCFAllocatorDefault, NULL, false, NULL, NULL, format, (CMItemCount)number_of_frames, 1, &timing, 0, NULL, &buffer);
if(status != 0) {
NSLog(@"Failed to allocate sample buffer");
return;
}

AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = audioFormat.mChannelsPerFrame;
bufferList.mBuffers[0].mDataByteSize = (UInt32)(number_of_frames * audioFormat.mBytesPerFrame);
bufferList.mBuffers[0].mData = audio_data;
status = CMSampleBufferSetDataBufferFromAudioBufferList(buffer, kCFAllocatorDefault, kCFAllocatorDefault, 0, &bufferList);
if(status != 0) {
NSLog(@"Failed to convert audio buffer list into sample buffer");
return;
}

[recorder writeAudioFrames:buffer];

CFRelease(buffer);
}

作为引用,我在 iPhone 6S+/iOS 9.2 上从 WebRTC 接收的采样率为 48kHz,每次调用此 Hook 时有 480 个样本,我每 10 毫秒接收一次数据。

最佳答案

首先,恭喜您冒昧地从头开始创建音频 CMSampleBuffer。对于大多数,它们既没有被创建也没有被销毁,而是从 CoreMediaAVFoundation 中完美而神秘地传承下来。

您的时序信息中的presentationTimeStamp是整数毫秒,不能代表您的 48kHz 样本的时间位置。

尝试使用 CMTimeMake(elapsed_frames, sample_rate) 而不是 CMTimeMake(elapsed_time_ms, 1000),其中 elapsed_frames 是您计算的帧数以前写过。

这可以解释失真,但不能解释音高,因此请确保 AudioStreamBasicDescription 与您的 AVAssetWriterInput 设置相匹配。如果没有看到您的 AVAssetWriter 代码,很难说。

p.s 注意 writeAudioFrames - 如果它是异步的,您将遇到 audio_data 所有权的问题。

p.p.s.看起来您正在泄漏 CMFormatDescriptionRef

关于ios - 使用来自原始 PCM 流的 CMSampleTimingInfo、CMSampleBuffer 和 AudioBufferList,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34398058/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com