2012-10-24 8 views
8

Ich versuche, eine lokale M4A oder MP3-Datei und komprimieren/down-Sample diese Datei (für die Zwecke der Erstellung einer kleineren Datei).AVAssetWriter Wie schreibe ich downsampled/komprimierte M4A/MP3-Dateien

Ursprünglich benutzte ich die AVAssetExportSession, um ein AVAsset in ein temporäres Verzeichnis zu exportieren, aber ich hatte keine Kontrolle über Komprimierung/Downsampling (Sie können nur Presets verwenden, die nur .wav Dateiformate Unterstützung der Qualitätsminderung).

Dann, nach einigen Beispielen hier auf SO, habe ich versucht, mit AVAssetReader/AVAssetWriter diesen "Export" zu präformieren.

Ich eröffne mein Leser/Schreiber als solche:

NSString *exportPath = [NSHomeDirectory() stringByAppendingPathComponent:@"out.m4a"]; 

NSURL *exportURL = [NSURL fileURLWithPath:outPath]; 

// reader 
NSError *readerError = nil; 
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:asset 
                 error:&readerError]; 

AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];  
AVAssetReaderTrackOutput *readerOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:track 
                      outputSettings:nil]; 
[reader addOutput:readerOutput]; 

// writer 
NSError *writerError = nil; 
AVAssetWriter *writer = [[AVAssetWriter alloc] initWithURL:exportURL 
                fileType:AVFileTypeAppleM4A 
                error:&writerError]; 

AudioChannelLayout channelLayout; 
memset(&channelLayout, 0, sizeof(AudioChannelLayout)); 
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; 

// use different values to affect the downsampling/compression 
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
           [NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey, 
           [NSNumber numberWithFloat:44100.0], AVSampleRateKey, 
           [NSNumber numberWithInt:2], AVNumberOfChannelsKey, 
           [NSNumber numberWithInt:128000], AVEncoderBitRateKey, 
           [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey, 
           nil]; 

AVAssetWriterInput *writerInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio 
                   outputSettings:outputSettings]; 
[writerInput setExpectsMediaDataInRealTime:NO]; 
[writer addInput:writerInput]; 

Und dann fange ich an zu schreiben ...

[writer startWriting]; 
[writer startSessionAtSourceTime:kCMTimeZero]; 

[reader startReading]; 
dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL); 
[writerInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^{ 

    NSLog(@"Asset Writer ready : %d", writerInput.readyForMoreMediaData); 
    while (writerInput.readyForMoreMediaData) { 
     CMSampleBufferRef nextBuffer; 
     if ([reader status] == AVAssetReaderStatusReading && (nextBuffer = [readerOutput copyNextSampleBuffer])) { 
      if (nextBuffer) { 
       NSLog(@"Adding buffer"); 
       [writerInput appendSampleBuffer:nextBuffer]; 
      } 
     } else { 
      [writerInput markAsFinished]; 

      switch ([reader status]) { 
       case AVAssetReaderStatusReading: 
        break; 
       case AVAssetReaderStatusFailed: 
        [writer cancelWriting]; 
        break; 
       case AVAssetReaderStatusCompleted: 
        NSLog(@"Writer completed"); 
        [writer endSessionAtSourceTime:asset.duration]; 
        [writer finishWriting]; 

        NSData *data = [NSData dataWithContentsOfFile:exportPath]; 
        NSLog(@"Data: %@", data); 
        break; 
      } 
      break; 
     } 
    } 
}]; 

Wenn ich mit dem Schreiben fertig bin, habe die Daten i angeblich geschrieben Die exportURL ist null und der Writer meldet einen erfolgreichen Abschluss. Irgendwelche Ideen, was könnte schief gehen?

aktualisieren Der Schriftsteller Status nach appendSampleBuffer: Aufruf wird AVAssetWriterStatusFailed, obwohl der Leser Status erfolgreich ist, und scheint durch die gesamte Datei zu lesen.

+0

Hat es jemals versucht, etwas zu schreiben? Wie lautet der Leserstatus beim ersten Versuch, den Sample-Puffer anzufügen? – BlueVoodoo

+0

Ah ha, es erscheint bei jedem Schritt, wenn '[WriterInput appendSampleBuffer:]' aufgerufen wird, der Writer-Status ist 3, was durch Betrachten der Enumeration aussieht wie AVAssetWriterStatusFailed. Es sieht so aus, als ob der Reader alle Beispielpuffer aus meinem Asset kopiert - appendSampleBuffer heißt * many * mal – Dfowj

Antwort

5

stieß ich auf die Lösung:

Mit NSHomeDirectory() in NSString *exportPath = [NSHomeDirectory() stringByAppendingPathComponent:@"out.m4a"] an den Schriftsteller verursacht wurde nicht in der Lage sein, um die Datei zu erstellen. Nicht genau, warum oder was ich tun müsste, damit dies funktioniert, aber die Änderung NSHomeDirectiory() zu NSTemporaryDirectory() hat meine Probleme in der Zwischenzeit gelöst.

+1

Sie können nicht in das Home-Verzeichnis in iOS schreiben. Temporäres Verzeichnis ist in Ordnung, ebenso wie Dokumente Verzeichnis –