В настоящее время я работаю над приложением как частью моего бакалавра по информатике. Приложение будет сопоставлять данные с аппаратного обеспечения iPhone (акселерометр, gps) и воспроизводимой музыки.Как правильно читать декодированные образцы PCM на iOS, используя AVAssetReader - в настоящее время некорректное декодирование
Проект все еще находится в зачаточном состоянии, работая над ним всего на 2 месяца.
В тот момент, когда я сейчас, и где мне нужна помощь, читает образцы PCM из песен из библиотеки itunes и воспроизводит их с помощью и аудиоустройства. В настоящее время реализация, которую я хотел бы выполнять, делает следующее: выбирает случайную песню из iTunes и читает сэмплы из нее, когда это необходимо, и сохраняет в буфере, позволяет называть его sampleBuffer. Позже в потребительской модели звуковой блок (с микшером и выходом remoteIO) имеет обратный вызов, где я просто копирую необходимое количество выборок из SampleBuffer в буфер, указанный в обратном вызове. То, что я потом слышу через динамики, - это нечто совсем не то, что я ожидаю; Я могу понять, что он играет песню, но кажется, что она неправильно декодирована, и у нее много шума! Я прикрепил изображение, которое показывает первые полсекунды (24576 выборок @ 44.1 кГц), и это не похоже на нормальный вывод. Прежде чем попасть в список, я проверил, что файл не поврежден, аналогично, я написал тестовые примеры для буфера (поэтому я знаю, что буфер не изменяет образцы), и хотя это может быть не лучший способ сделать это (некоторые утверждают, что идут по пути аудио очереди), я хочу выполнять различные манипуляции с образцами, а также изменять песню до ее завершения, перестраивать воспроизведение какой-либо песни и т. д. Кроме того, возможно, некоторые неправильные настройки в однако, график, который отображает сэмплы (который показывает, что образцы декодируются некорректно), берется прямо из буфера, поэтому я сейчас только ищу, чтобы решить, почему чтение с диска и декодирование работает неправильно. Прямо сейчас я просто хочу получить игру через работу. Cant разместить изображения, так как новые для StackOverflow так Heres ссылку на изображение: http://i.stack.imgur.com/RHjlv.jpg
Листинг:
Это где я установка в audioReadSettigns, которые будут использоваться для 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];
теперь следующий код - метод, который получает 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
Что такое kUnitSize? и что такое kTotalBufferSize? –
@smartfaceweb: В моем случае, я использовал следующие настройки '#define kUnitSize SizeOf (AudioSampleType) #define kBufferUnit 655360 #define kTotalBufferSize kBufferUnit * kUnitSize' – infiniteloop