2012-10-24 17 views
8

Sto provando a prendere un file m4a o mp3 locale e comprimere/eseguire il down-sample di questo file (allo scopo di creare un file più piccolo).AVAssetWriter Come scrivere/campionare file m4a/mp3

Originariamente, stavo usando AVAssetExportSession per esportare un AVAsset in una directory temporanea, ma non avevo alcun controllo sulla compressione/down-sampling (è possibile utilizzare solo i preset, quali di essi, solo i formati di file .wav sostenere il degrado della qualità).

Quindi, seguendo alcuni esempi qui su SO, ho provato a utilizzare AVAssetReader/AVAssetWriter per preformare questa 'esportazione'.

Creo il mio lettore/scrittore in quanto tale:

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]; 

E poi mi metto a scrivere ...

[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; 
     } 
    } 
}]; 

Quando ho finito la scrittura, i dati che ho presumibilmente scritto exportURL è nullo e lo scrittore segnala un completamento positivo. Qualche idea su cosa potrebbe andare storto?

Aggiornamento Lo stato scrittore dopo aver chiamato appendSampleBuffer: è AVAssetWriterStatusFailed, anche se lo stato di lettori è successo, e sembra di leggere l'intero file.

+0

Si tenta mai di scrivere qualcosa? Qual è lo stato del lettore la prima volta che tenta di aggiungere il samplebuffer? – BlueVoodoo

+0

Ah ah, appare ad ogni passaggio quando viene chiamato '[writerInput appendSampleBuffer:]', lo stato del writer è 3, che guardando l'enum appare come AVAssetWriterStatusFailed. Sembra che il lettore stia copiando tutti i buffer di esempio dalla mia risorsa, tuttavia - appendSampleBuffer è chiamato * molte * volte – Dfowj

risposta

5

mi sono imbattuto la soluzione:

Utilizzando NSHomeDirectory() in NSString *exportPath = [NSHomeDirectory() stringByAppendingPathComponent:@"out.m4a"] stava causando lo scrittore di non essere in grado di creare il file. Non sono esattamente sicuro del perché o di cosa avrei bisogno per fare in modo che funzioni, ma cambiare NSHomeDirectiory() a NSTemporaryDirectory() ha risolto i miei problemi nel frattempo.

+1

Non è possibile scrivere nella directory home in iOS. La directory temporanea è ok, così come la directory Documenti –

Problemi correlati