我目前正在研究應用程序,作爲我的計算機科學學士學位的一部分。該應用程序將關聯來自iPhone硬件(加速度計,gps)和正在播放的音樂的數據。如何在iOS上使用AVAssetReader正確讀取已解碼的PCM樣本 - 目前解碼不正確
該項目尚處於起步階段,僅僅進行了2個月。
我現在正在和我需要幫助的那一刻正在從itunes庫中的歌曲中讀取PCM樣本,並使用它和音頻單元播放它們。 目前我想要工作的實現如下:從iTunes中選擇隨機歌曲,並在需要時從中讀取樣本,並存儲在緩衝區中,讓我們稱其爲sampleBuffer。稍後在消費者模型中,音頻單元(具有混音器和remoteIO輸出)具有回調,我只需將sampleBuffer中所需數量的樣本複製到回調中指定的緩衝區中。然後我通過揚聲器聽到的東西並不是我所期望的;我可以認識到,它正在播放這首歌曲,但它似乎是不正確的解碼,它有很多噪音!我附上了一張圖片,其中顯示了第一〜半秒(24576個樣本@ 44.1kHz),這並不像一個正常的輸出。 在我進入清單之前,我已檢查過該文件沒有被破壞,類似地,我已經爲緩衝區編寫了測試用例(所以我知道緩衝區不會改變樣本),儘管這可能不是最好的方法它(有些人會爭辯去音頻隊列路線),我想對樣本進行各種操作,並在完成之前更改歌曲,重新排列播放什麼歌曲等。此外,也許有一些不正確的設置在音頻單元,然而,顯示樣本(顯示樣本被錯誤解碼)的圖形是直接從緩衝區中取出的,因此我現在只想着解決爲什麼磁盤讀取和解碼無法正常工作。現在我只想通過工作來獲得一部戲。 廣東話發表圖片,因爲新來的StackOverflow因此,繼承人的鏈接圖片:http://i.stack.imgur.com/RHjlv.jpg
上市:
這是我的設置將被用於AVAssetReaderAudioMixOutput
// Set the read settings
audioReadSettings = [[NSMutableDictionary alloc] init];
[audioReadSettings setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM]
forKey:AVFormatIDKey];
[audioReadSettings setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[audioReadSettings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
[audioReadSettings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
[audioReadSettings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsNonInterleaved];
[audioReadSettings setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
現在的audioReadSettigns下面的代碼清單是一種方法,接收NSString與歌曲的persistant_id:
-(BOOL)setNextSongID:(NSString*)persistand_id {
assert(persistand_id != nil);
MPMediaItem *song = [self getMediaItemForPersistantID:persistand_id];
NSURL *assetUrl = [song valueForProperty:MPMediaItemPropertyAssetURL];
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetUrl
options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
forKey:AVURLAssetPreferPreciseDurationAndTimingKey]];
NSError *assetError = nil;
assetReader = [[AVAssetReader assetReaderWithAsset:songAsset error:&assetError] retain];
if (assetError) {
NSLog(@"error: %@", assetError);
return NO;
}
CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, songAsset.duration);
[assetReader setTimeRange:timeRange];
track = [[songAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
assetReaderOutput = [AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:[NSArray arrayWithObject:track]
audioSettings:audioReadSettings];
if (![assetReader canAddOutput:assetReaderOutput]) {
NSLog(@"cant add reader output... die!");
return NO;
}
[assetReader addOutput:assetReaderOutput];
[assetReader startReading];
// just getting some basic information about the track to print
NSArray *formatDesc = ((AVAssetTrack*)[[assetReaderOutput audioTracks] objectAtIndex:0]).formatDescriptions;
for (unsigned int i = 0; i < [formatDesc count]; ++i) {
CMAudioFormatDescriptionRef item = (CMAudioFormatDescriptionRef)[formatDesc objectAtIndex:i];
const CAStreamBasicDescription *asDesc = (CAStreamBasicDescription*)CMAudioFormatDescriptionGetStreamBasicDescription(item);
if (asDesc) {
// get data
numChannels = asDesc->mChannelsPerFrame;
sampleRate = asDesc->mSampleRate;
asDesc->Print();
}
}
[self copyEnoughSamplesToBufferForLength:24000];
return YES;
}
下文介紹的功能 - (空)copyEnoughSamplesToBufferForLength:
-(void)copyEnoughSamplesToBufferForLength:(UInt32)samples_count {
[w_lock lock];
int stillToCopy = 0;
if (sampleBuffer->numSamples() < samples_count) {
stillToCopy = samples_count;
}
NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
CMSampleBufferRef sampleBufferRef;
SInt16 *dataBuffer = (SInt16*)malloc(8192 * sizeof(SInt16));
int a = 0;
while (stillToCopy > 0) {
sampleBufferRef = [assetReaderOutput copyNextSampleBuffer];
if (!sampleBufferRef) {
// end of song or no more samples
return;
}
CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBufferRef);
CMItemCount numSamplesInBuffer = CMSampleBufferGetNumSamples(sampleBufferRef);
AudioBufferList audioBufferList;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBufferRef,
NULL,
&audioBufferList,
sizeof(audioBufferList),
NULL,
NULL,
0,
&blockBuffer);
int data_length = floorf(numSamplesInBuffer * 1.0f);
int j = 0;
for (int bufferCount=0; bufferCount < audioBufferList.mNumberBuffers; bufferCount++) {
SInt16* samples = (SInt16 *)audioBufferList.mBuffers[bufferCount].mData;
for (int i=0; i < numSamplesInBuffer; i++) {
dataBuffer[j] = samples[i];
j++;
}
}
CFRelease(sampleBufferRef);
sampleBuffer->putSamples(dataBuffer, j);
stillToCopy = stillToCopy - data_length;
}
free(dataBuffer);
[w_lock unlock];
[apool release];
}
現在sampleBuffer將沒有正確解碼的樣本。任何人都可以幫助我爲什麼這是這樣嗎?這發生在我的iTunes庫上的不同文件(mp3,aac,wav等)。 任何幫助將不勝感激,此外,如果您需要我的代碼的任何其他列表,或者可能是什麼輸出聽起來像,我會附加它每個請求。在過去的一週裏,我一直在試圖調試它,並沒有在網上找到任何幫助 - 每個人似乎都以我的方式去做,但似乎只有我有這個問題。
感謝您的幫助!
彼得
非常感謝!真的有幫助! – Peter 2012-03-05 13:34:40
什麼是kUnitSize?什麼是kTotalBufferSize? – 2012-07-25 03:54:14
@smartfaceweb:就我而言,我已經使用了以下設置 '#定義kUnitSize的sizeof(AudioSampleType) 的#define kBufferUnit 655360 的#define kTotalBufferSize kBufferUnit * kUnitSize' – infiniteloop 2012-07-26 03:49:40