Wie man richtig Lesen dekodierten PCM-samples auf iOS mit AVAssetReader — derzeit falsche Dekodierung
Derzeit arbeite ich an einer Anwendung, die als Teil meines Bachelor in Computer Science. Die Anwendung wird die Korrelation von Daten aus der iPhone-hardware (Beschleunigungssensor, gps) und die Musik, die gespielt wird.
Sich das Projekt noch in den Kinderschuhen, nachdem arbeitete Sie für nur 2 Monate.
Dem moment, in dem ich jetzt bin, und wo ich Hilfe brauche, ist das Lesen der PCM-samples von songs aus der itunes-Bibliothek und spielen Sie wieder mit und audio unit.
Derzeit wird die Umsetzung ich möchte macht Folgendes: wählt einen zufälligen song aus iTunes, und liest samples aus, wenn erforderlich, und speichert Sie in einem Puffer, nennen wir es sampleBuffer. Später in der consumer-Modell das audio-Gerät (das ist ein mixer und ein remoteIO Ausgabe) hat einen Rückruf, wo ich einfach kopieren Sie die erforderliche Anzahl von Proben aus den sampleBuffer in den Puffer angegeben, die in den Rückruf. Was ich dann zu hören über die Lautsprecher ist etwas nicht ganz das, was ich erwarte; ich kann erkennen, dass es den song doch wie es scheint, ist es nicht korrekt dekodiert, und es hat eine Menge Lärm! Ich beigefügt ein Bild, das zeigt die erste ~halbe Sekunde (24576 samples @ 44.1 kHz), und diese gleicht nicht einem normall suchen Ausgang.
Bevor ich in der Liste habe ich überprüft, dass die Datei nicht beschädigt ist, ebenfalls habe ich geschrieben Testfälle für die Puffer (also ich weiß, der Puffer nicht verändert, die Beispiele), und obwohl dies möglicherweise nicht der beste Weg, es zu tun (einige würden argumentieren, zu gehen die audio-Warteschlange route), will ich führen verschiedene Manipulationen an den Proben sowie das ändern der song, bevor es fertig ist, die Neuordnung, welches Lied gespielt wird, etc. Außerdem, vielleicht gibt es einige falsche Einstellungen in der audio-Gerät, jedoch das Diagramm zeigt das Muster (das zeigt die Proben werden dekodiert falsch), ist gerade aus dem Puffer, somit bin ich nur auf der Suche, nun zu lösen, warum das Lesen von der Festplatte und Entschlüsselung funktioniert nicht richtig. Jetzt habe ich einfach wollen, Holen Sie sich einen Spiel durch zu arbeiten.
Kann nicht nach Bildern, weil neue zu stackoverflow so hier ist der link zu dem Bild: http://i.stack.imgur.com/RHjlv.jpg
Auflistung:
Dies ist, wo ich setup die audioReadSettigns die verwendet werden, für die 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];
Nun das folgende Codebeispiel ist eine Methode, erhält ein NSString mit dem persistant_id der song:
-(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;
}
Im folgenden werden die Funktion -(void)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];
}
Nun die sampleBuffer wird falsch decodiert Proben. Kann mir jemand helfen, warum dies so ist? Dies geschieht für verschiedene Dateien auf meine iTunes-Bibliothek (mp3, aac, wav, etc).
Jegliche Hilfe würde sehr geschätzt werden, wenn Sie überdies alle anderen Auflistung von meinem code, oder vielleicht das, was der output klingt, ich fügen Sie es per Anfrage. Ich habe gesessen, auf das in der vergangenen Woche versucht zu Debuggen, die es schon gefunden haben und Sie keine Hilfe von online -- jeder scheint zu sein, doign es in meinem Weg, doch es scheint, dass nur ich dieses Problem haben.
Vielen Dank für jede Hilfe überhaupt!
Peter
InformationsquelleAutor Peter | 2012-02-20
Du musst angemeldet sein, um einen Kommentar abzugeben.
Derzeit, ich arbeite auch an einem Projekt, das beinhaltet das extrahieren von audio-samples aus iTunes-Bibliothek in die Virtuelle.
Den Audio-Unit-render-Rückruf enthalten ist, für Ihre Referenz. Das input-format eingestellt ist, als SInt16StereoStreamFormat.
Habe ich Gebrauch gemacht von Michael Tyson ' s Ringpuffer - implementation- TPCircularBuffer als Pufferspeicher. Sehr einfach zu bedienen und zu verstehen!!! Vielen Dank Michael!
Was ist kUnitSize? und was ist kTotalBufferSize?
In meinem Fall habe ich die folgende Einstellung
#define kUnitSize sizeof(AudioSampleType) #define kBufferUnit 655360 #define kTotalBufferSize kBufferUnit * kUnitSize
können Sie bitte lassen Sie uns wissen, ob dieser code funktioniert mit iOS auch? basierend auf meiner begrenzten Forschung bislang auf audio-Geräte, es scheint, dass iOS hat weit weniger audio-unit-features als seine OSX-Pendant
Überprüfen Sie, dass Ringpuffer hat mindestens 32768 zur Verfügung vor dem Befüllen, und das ist die gleiche Anzahl CMSampleBufferGetTotalSampleSize gibt, aber ich Frage mich, ob diese Größe haben könnte überhaupt anders sein, aus welchem Grund auch immer. Irgendeine bestimmte Bedeutung für Sie sein, was es ist?
InformationsquelleAutor infiniteloop
Ich denke, es ist ziemlich spät, aber Sie könnten versuchen, diese Bibliothek:
https://bitbucket.org/artgillespie/tslibraryimport
Nachdem Sie diesen zum speichern der Audiodaten in einer Datei, die Sie verarbeiten könnten die Daten mit render-callbacks aus MixerHost.
InformationsquelleAutor Totoro
Wenn ich du wäre würde ich entweder kAudioUnitSubType_AudioFilePlayer um die Datei zu spielen und Zugriff auf Ihre Proben mit den Einheiten render callback.
Oder
Verwenden ExtAudioFileRef zu extrahieren, die Proben direkt in einen Puffer.
Ich dont haben viel Erfahrung mit der iTunes Bibliothek, die ich fürchte. Bedeutet das aber? subfurther.com/blog/2010/12/13/...
InformationsquelleAutor dubbeat