AVAssetReader 正在寻找

Posted

技术标签:

【中文标题】AVAssetReader 正在寻找【英文标题】:AVAssetReader Seeking 【发布时间】:2011-05-21 16:56:23 【问题描述】:

我需要四处寻找音频文件并提取块。我正在尝试使用 AVAssetReader。我看到的错误是,如果我在一段时间内从不同的偏移量读取音频,我得到的平均值(块)是不同的。

例如,如果我从 0.1s 到 0.5s 读取音频,我会得到不同的数据,如果我从 0.2s 读取到 0.5s,我收到的数据块也会不同

以下是演示它的代码示例

#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>

+ (void) test

    NSURL* path = [[NSBundle mainBundle] URLForResource:@"music" withExtension:@"mp3"];

    [self test:path sample:1 showChunks:5];
    [self test:path sample:2 showChunks:4];
    [self test:path sample:3 showChunks:3];


+(void) test:(NSURL*) url sample:(NSInteger) sample showChunks:(NSInteger) chunkCount

#define CHUNK 800
#define SAMPLE_RATE 8000
    AVURLAsset* asset = [AVURLAsset URLAssetWithURL:url options:nil];
    NSError *assetError = nil;
    AVAssetReader* assetReader = [AVAssetReader assetReaderWithAsset:asset error:&assetError];

    CMTime startTime = CMTimeMake(sample*CHUNK, SAMPLE_RATE);
    CMTimeShow(startTime);

    CMTimeRange timeRange = CMTimeRangeMake(startTime, kCMTimePositiveInfinity);
    assetReader.timeRange = timeRange;

    NSDictionary* dict = nil;
    dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInteger:SAMPLE_RATE], AVSampleRateKey, [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey, nil];


    AVAssetReaderAudioMixOutput* assetReaderOutput = [AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:asset.tracks audiosettings: dict];
    if (! [assetReader canAddOutput: assetReaderOutput]) 
        NSLog (@"error: Cannot add output reader");
        assetReader = nil;
        return;
    

    [assetReader addOutput: assetReaderOutput];

    [assetReader startReading];

    CMSampleBufferRef nextBuffer;

    if (!(nextBuffer = [assetReaderOutput copyNextSampleBuffer]))
    
        return;
    
    CMSampleBufferGetTotalSampleSize (nextBuffer);
    // Extract bytes from buffer
    CMBlockBufferRef dataBuffer = CMSampleBufferGetDataBuffer(nextBuffer);

    NSInteger len = CMBlockBufferGetDataLength(dataBuffer);
    if (len < chunkCount*CHUNK)
    
        printf("CHUNK is to big");
        return;
    
    UInt8* buf = malloc(len);
    CMBlockBufferCopyDataBytes(dataBuffer, 0, len, buf);

    for (int ii = 0; ii < chunkCount*CHUNK; ii+=CHUNK)
    
        CGFloat av = 0;
        for (int jj = 0; jj < CHUNK; jj++)
        
            av += (CGFloat) buf[jj+ii];
        
        printf("Time: %f av: %f\n", (CGFloat)(ii+CHUNK*sample)/(CGFloat)SAMPLE_RATE,  av/(CGFloat)CHUNK);
    
    printf("\n");

    free(buf);



这是输出

800/8000 = 0.100
Time: 0.100000 av: 149.013748
Time: 0.200000 av: 100.323753
Time: 0.300000 av: 146.991257
Time: 0.400000 av: 106.763748
Time: 0.500000 av: 145.020004

1600/8000 = 0.200
Time: 0.200000 av: 145.011246
Time: 0.300000 av: 110.718750
Time: 0.400000 av: 154.543747
Time: 0.500000 av: 112.025002

2400/8000 = 0.300
Time: 0.300000 av: 149.278748
Time: 0.400000 av: 104.477501
Time: 0.500000 av: 158.162506

请帮忙

【问题讨论】:

【参考方案1】:

在我看来,您的问题在于假设以下代码准确地寻求 startTime:

CMTimeRange timeRange = CMTimeRangeMake(startTime, kCMTimePositiveInfinity);
assetReader.timeRange = timeRange;

你可以通过调用来测试这个

CMSampleBufferGetOutputPresentationTimeStamp(nextBuffer);

从中您将能够看到缓冲区启动的确切时间(以秒为单位)。

【讨论】:

【参考方案2】:

根据我自己的经验寻找

assetReader.timeRange = CMTimeRangeMake(CMTimeMake(sample, sample_rate), kCMTimePositiveInfinity)

完美运行。搜索不存在精度问题。

您可能会遇到淡入问题:实际上 AVAssetReader 似乎在前 1024 个样本中淡入(可能更多)。 我通过在我真正想要读取的位置之前读取 1024 个样本来修复它,然后跳过这 1024 个样本。

【讨论】:

以上是关于AVAssetReader 正在寻找的主要内容,如果未能解决你的问题,请参考以下文章

使用 AVAssetReader 读取多个轨道

第五十七篇AVAssetReader和AVAssetWrite 对视频进行编码

启动 AVAssetReader 停止对远程 I/O AudioUnit 的回调

AVAssetReader 初始化失败?

获取 AVAssetReader 的样本数据

AVAssetWriter视频数据编码