用AVAssetReader和timeRange实时读取样本
以前,我使用CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer
从完整的audio文件中读取audio样本。 现在我想要做同样的使用范围(即我指定的时间范围..按时间读一小块audio,然后回去再读)。 我想使用时间范围的原因是B / C我想控制每个读取的大小(以适应一个最大大小的数据包)。
出于某种原因,每次读取之间总会有一个碰撞。 在我的代码中,您会注意到我启动了AVAssetReader并每次设置时间范围就结束它,这是b / c在阅读器启动之后,我无法dynamic调整时间范围(请参阅此处了解更多详细信息)。
难道这是开始和结束一个读者是太昂贵,不能产生连续的实时体验? 或者还有其他方法可以做到这一点,我不知道?
还要注意,这个抖动或滞后发生在我设置时间间隔的任何点上。这使得我相信以我的方式开始和结束阅读器对于实时audio播放来说太昂贵了。
- (void) setupReader { NSURL *assetURL = [NSURL URLWithString:@"ipod-library://item/item.m4a?id=1053020204400037178"]; songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil]; track = [songAsset.tracks objectAtIndex:0]; nativeTrackASBD = [self getTrackNativeSettings:track]; // set CM time parameters assetCMTime = songAsset.duration; CMTimeReadDurationInSeconds = CMTimeMakeWithSeconds(1, assetCMTime.timescale); currentCMTime = CMTimeMake(0,assetCMTime.timescale); } -(void)readVBRPackets { // make sure assetCMTime is greater than currentCMTime while (CMTimeCompare(assetCMTime,currentCMTime) == 1 ) { NSError * error = nil; reader = [[AVAssetReader alloc] initWithAsset:songAsset error:&error]; readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track outputSettings:nil]; [reader addOutput:readerOutput]; reader.timeRange = CMTimeRangeMake(currentCMTime, CMTimeReadDurationInSeconds); [reader startReading]; while ((sample = [readerOutput copyNextSampleBuffer])) { CMItemCount numSamples = CMSampleBufferGetNumSamples(sample); if (numSamples == 0) { continue; } NSLog(@"reading sample"); CMBlockBufferRef CMBuffer = CMSampleBufferGetDataBuffer( sample ); AudioBufferList audioBufferList; OSStatus err = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( sample, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &CMBuffer ); const AudioStreamPacketDescription * inPacketDescriptions; size_t packetDescriptionsSizeOut; size_t inNumberPackets; CheckError(CMSampleBufferGetAudioStreamPacketDescriptionsPtr(sample, &inPacketDescriptions, &packetDescriptionsSizeOut), "could not read sample packet descriptions"); inNumberPackets = packetDescriptionsSizeOut/sizeof(AudioStreamPacketDescription); AudioBuffer audioBuffer = audioBufferList.mBuffers[0]; for (int i = 0; i < inNumberPackets; ++i) { SInt64 dataOffset = inPacketDescriptions[i].mStartOffset; UInt32 packetSize = inPacketDescriptions[i].mDataByteSize; size_t packetSpaceRemaining; packetSpaceRemaining = bufferByteSize - bytesFilled; // if the space remaining in the buffer is not // enough for the data contained in this packet // then just write it if (packetSpaceRemaining < packetSize) { [self enqueueBuffer]; } // copy data to the audio queue buffer AudioQueueBufferRef fillBuf = audioQueueBuffers[fillBufferIndex]; memcpy((char*)fillBuf->mAudioData + bytesFilled, (const char*)(audioBuffer.mData + dataOffset), packetSize); // fill out packet description packetDescs[packetsFilled] = inPacketDescriptions[i]; packetDescs[packetsFilled].mStartOffset = bytesFilled; bytesFilled += packetSize; packetsFilled += 1; // if this is the last packet, then ship it size_t packetsDescsRemaining = kAQMaxPacketDescs - packetsFilled; if (packetsDescsRemaining == 0) { [self enqueueBuffer]; } } CFRelease(CMBuffer); CMSampleBufferInvalidate(sample); CFRelease(sample); } [reader cancelReading]; reader = NULL; readerOutput = NULL; currentCMTime = CMTimeAdd(currentCMTime, CMTimeReadDurationInSeconds); } }
我知道会发生什么事情–D我花了整整一天的时间才弄明白。
实际上,AVAssetReader会将前1024个样本(也许会稍微多一点)淡入。这就是您听到抖动效果的原因。
我通过在我真正想要读取的位置之前读取1024个样本来固定它,然后跳过这1024个样本。
我希望它也适用于你。