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

Schreibe einen Kommentar