gpt4 book ai didi

audio - 使用 AVFoundation 准确提取音频 block 的示例

转载 作者:行者123 更新时间:2023-12-04 02:24:12 33 4
gpt4 key购买 nike

问题
我希望从视频文件中的音轨中提取样本准确范围的 LPCM 音频。目前,我希望使用 AVAssetReaderTrackOutput 来实现这一目标。反对 AVAssetTrack来自阅读 AVURLAsset .
尽管准备并确保使用 AVURLAssetPreferPreciseDurationAndTimingKey 初始化 Assets 设置为 YES ,寻求 Assets 中的样本准确位置似乎不准确。

NSDictionary *options = @{ AVURLAssetPreferPreciseDurationAndTimingKey : @(YES) };
_asset = [[AVURLAsset alloc] initWithURL:fileURL options:options];
这体现在例如可变比特率编码的 AAC 流。虽然我知道 VBR 音频流在准确搜索方面会带来性能开销,但如果我提供准确的样本,我愿意为此付出代价。
当使用例如扩展音频文件服务和 ExtAudioFileRef API,我可以实现样本准确的音频搜索和提取。同样与 AVAudioFile ,因为它建立在 ExtAudioFileRef 之上.
然而,问题是我还想从仅音频文件 API 拒绝但在 AVFoundation 中通过 AVURLAsset 支持的媒体容器中提取音频。 .
方法
使用 CMTime 定义用于提取的样本准确时间范围和 CMTimeRange ,并设置在 AVAssetReaderTrackOutput .然后迭代地提取样本。
-(NSData *)readFromFrame:(SInt64)startFrame
requestedFrameCount:(UInt32)frameCount
{
NSUInteger expectedByteCount = frameCount * _bytesPerFrame;
NSMutableData *data = [NSMutableData dataWithCapacity:expectedByteCount];

//
// Configure Output
//

NSDictionary *settings = @{ AVFormatIDKey : @( kAudioFormatLinearPCM ),
AVLinearPCMIsNonInterleaved : @( NO ),
AVLinearPCMIsBigEndianKey : @( NO ),
AVLinearPCMIsFloatKey : @( YES ),
AVLinearPCMBitDepthKey : @( 32 ),
AVNumberOfChannelsKey : @( 2 ) };

AVAssetReaderOutput *output = [[AVAssetReaderTrackOutput alloc] initWithTrack:_track outputSettings:settings];

CMTime startTime = CMTimeMake( startFrame, _sampleRate );
CMTime durationTime = CMTimeMake( frameCount, _sampleRate );
CMTimeRange range = CMTimeRangeMake( startTime, durationTime );

//
// Configure Reader
//

NSError *error = nil;
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:_asset error:&error];

if( !reader )
{
fprintf( stderr, "avf : failed to initialize reader\n" );
fprintf( stderr, "avf : %s\n%s\n", error.localizedDescription.UTF8String, error.localizedFailureReason.UTF8String );
exit( EXIT_FAILURE );
}

[reader addOutput:output];
[reader setTimeRange:range];
BOOL startOK = [reader startReading];

NSAssert( startOK && reader.status == AVAssetReaderStatusReading, @"Ensure we've started reading." );

NSAssert( _asset.providesPreciseDurationAndTiming, @"We expect the asset to provide accurate timing." );

//
// Start reading samples
//

CMSampleBufferRef sample = NULL;
while(( sample = [output copyNextSampleBuffer] ))
{
CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp( sample );
if( data.length == 0 )
{
// First read - we should be at the expected presentation time requested.
int32_t comparisonResult = CMTimeCompare( presentationTime, startTime );
NSAssert( comparisonResult == 0, @"We expect sample accurate seeking" );
}

CMBlockBufferRef buffer = CMSampleBufferGetDataBuffer( sample );

if( !buffer )
{
fprintf( stderr, "avf : failed to obtain buffer" );
exit( EXIT_FAILURE );
}

size_t lengthAtOffset = 0;
size_t totalLength = 0;
char *bufferData = NULL;

if( CMBlockBufferGetDataPointer( buffer, 0, &lengthAtOffset, &totalLength, &bufferData ) != kCMBlockBufferNoErr )
{
fprintf( stderr, "avf : failed to get sample\n" );
exit( EXIT_FAILURE );
}

if( bufferData && lengthAtOffset )
{
[data appendBytes:bufferData length:lengthAtOffset];
}

CFRelease( sample );
}

NSAssert( reader.status == AVAssetReaderStatusCompleted, @"Completed reading" );

[output release];
[reader release];

return [NSData dataWithData:data];
}
笔记 CMSampleBufferGetPresentationTimeStamp的演示时间给了我似乎符合我所追求的 - 但由于它似乎不准确,所以我没有机会纠正和对齐我检索的样本。
关于如何做到这一点的任何想法?
或者,有没有办法适应 AVAssetTrackAVAudioFile 使用或 ExtAudioFile ?
是否可以通过 AudioFileOpenWithCallbacks 访问音轨?
是否可以在 macOS 中以不同的方式从视频容器获取音频流?

最佳答案

一种有效的方法是使用 AVAssetReader 读取压缩的 AV 文件,并结合 AVAssetWriter 写入音频样本的新原始 LPCM 文件。然后可以快速索引这个新的 PCM 文件(或内存映射数组,如有必要)以提取精确的样本准确范围,而不会导致 VBR 每数据包解码大小异常或依赖于不受控制的 iOS CMTimeStamp 算法。

这可能不是时间或内存效率最高的过程,但它有效。

关于audio - 使用 AVFoundation 准确提取音频 block 的示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47129043/

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