2012-10-24 12 views
8

Próbuję pobrać lokalny plik m4a lub mp3 i skompresować/pobrać próbkę tego pliku (w celu utworzenia mniejszego pliku).AVAssetWriter Jak zapisywać próbkowane/skompresowane pliki m4a/mp3?

Oryginalnie używałem AVAssetExportSession do eksportowania zestawu AVA do katalogu tymczasowego, ale nie miałem żadnej kontroli nad kompresją/próbkowaniem w dół (można używać tylko wstępnych ustawień, które z nich mają tylko formaty plików .wav obniżenie jakości wsparcia).

Następnie, po kilku przykładach tutaj na SO, próbowałem użyć AVAssetReader/AVAssetWriter do preformowania tego "eksportu".

tworzę odczytującego/zapisującego jako takie:

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

A potem zacznę pisać ...

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

Kiedy skończę pisanie, dane i jakie rzekomo napisany do exportURL ma wartość null, a program piszący informuje o pomyślnym zakończeniu. Wszelkie pomysły, co może pójść nie tak?

Aktualizacja Stan pisarz po wywołaniu appendSampleBuffer: jest AVAssetWriterStatusFailed, choć status czytelników jest udany, i wydaje się czytać przez cały plik.

+0

Czy kiedykolwiek próbuje się coś napisać? Jaki jest stan czytnika przy pierwszym próbach dołączenia bufora próbek? – BlueVoodoo

+0

Ah ha, pojawia się na każdym kroku, gdy jest wywoływane '[writerInput appendSampleBuffer:]', status pisarza wynosi 3, co patrząc na wyliczenie, wygląda jak AVAssetWriterStatusFailed. Wygląda na to, że czytnik kopiuje wszystkie przykładowe bufory z mojego zasobu - appendSampleBuffer nazywa się * wiele * razy – Dfowj

Odpowiedz

5

natknąłem Rozwiązanie:

Korzystanie NSHomeDirectory() w NSString *exportPath = [NSHomeDirectory() stringByAppendingPathComponent:@"out.m4a"] było przyczyną pisarz nie być w stanie utworzyć plik. Nie jestem do końca pewien, dlaczego tak się stało, lub co musiałbym zrobić, aby to zadziałało, ale zmiana na NSTemporaryDirectory() rozwiązała moje problemy w międzyczasie.

+1

Nie można pisać do katalogu domowego w iOS. Katalog tymczasowy jest ok, podobnie jak katalog Dokumenty –

Powiązane problemy