2015-02-04 8 views
0

내 응용 프로그램은 AVAssetReader를 사용하여 iPOD 라이브러리의 노래를 재생합니다. 이제 오디오 녹음 기능을 추가하고 싶습니다.AVAssetWriter 및 AVAssetReader를 사용하여 오디오 녹음 및 재생

AVAssetWriter를 사용하여 오디오를 녹음했습니다. 결과 오디오 파일 (MPEG4AAC 형식)을 AVAudioPlayer를 사용하여 성공적으로 재생하여 확인했습니다. 내 목표는 AVAssetReader를 사용하여 오디오를 재생하는 것입니다. 그러나 파일에 대한 AVURLAsset을 만들면 트랙이 없으므로 AVAssetReader가 실패합니다 (오류 코드 : -11828 File Format Not Recognized).

AVAsset에서 파일 형식을 인식하도록하려면 어떻게해야합니까? AVAsset에 필요한 특별한 파일 형식이 있습니까?

여기에 녹화 코드입니다 :

void setup_ASBD(void *f, double fs, int sel, int numChannels); 
static AVAssetWriter *assetWriter = NULL; 
static AVAssetWriterInput *assetWriterInput = NULL; 
static CMAudioFormatDescriptionRef formatDesc; 
AVAssetWriter *newAssetWriter(NSURL *url) { 
    NSError *outError; 
    assetWriter = [AVAssetWriter assetWriterWithURL:url fileType:AVFileTypeAppleM4A error:&outError]; 

    if(assetWriter == nil) { 
     NSLog(@"%s: asset=%x, %@\n", __FUNCTION__, (int)assetWriter, outError); 
     return assetWriter; 
    } 

    AudioChannelLayout audioChannelLayout = { 
     .mChannelLayoutTag = kAudioChannelLayoutTag_Mono, 
     .mChannelBitmap = 0, 
     .mNumberChannelDescriptions = 0 
    }; 

    // Convert the channel layout object to an NSData object. 
    NSData *channelLayoutAsData = [NSData dataWithBytes:&audioChannelLayout length:offsetof(AudioChannelLayout, mChannelDescriptions)]; 

    // Get the compression settings for 128 kbps AAC. 
    NSDictionary *compressionAudioSettings = @{ 
               AVFormatIDKey   : [NSNumber numberWithUnsignedInt:kAudioFormatMPEG4AAC], 
               AVEncoderBitRateKey : [NSNumber numberWithInteger:128000], 
               AVSampleRateKey  : [NSNumber numberWithInteger:44100], 
               AVChannelLayoutKey : channelLayoutAsData, 
               AVNumberOfChannelsKey : [NSNumber numberWithUnsignedInteger:1] 
               }; 

    // Create the asset writer input with the compression settings and specify the media type as audio. 
    assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:compressionAudioSettings]; 
    assetWriterInput.expectsMediaDataInRealTime = YES; 

    // Add the input to the writer if possible. 
    if (assetWriterInput != NULL && [assetWriter canAddInput:assetWriterInput]) { 
     [assetWriter addInput:assetWriterInput]; 
    } 
    else { 
     NSLog(@"%s:assetWriteInput problem: %x\n", __FUNCTION__, (int)assetWriterInput); 
     return NULL; 
    } 

    [assetWriter startWriting]; 
    // Start a sample-writing session. 
    [assetWriter startSessionAtSourceTime:kCMTimeZero]; 

    if(assetWriter.status != AVAssetWriterStatusWriting) { 
     NSLog(@"%s: Bad writer status=%d\n", __FUNCTION__, (int)assetWriter.status); 
     return NULL; 
    } 

    AudioStreamBasicDescription ASBD; 
    setup_ASBD(&ASBD, 44100, 2, 1); 
    CMAudioFormatDescriptionCreate (NULL, &ASBD, sizeof(audioChannelLayout), &audioChannelLayout, 0, NULL, NULL, &formatDesc); 
    //CMAudioFormatDescriptionCreate (NULL, &ASBD, 0, NULL, 0, NULL, NULL, &formatDesc); 

    return assetWriter; 

} 

static int sampleCnt = 0; 
void writeNewSamples(void *buffer, int len) { 
    if(assetWriterInput == NULL) return; 
    if([assetWriterInput isReadyForMoreMediaData]) { 
     OSStatus result; 
     CMBlockBufferRef blockBuffer = NULL; 
     result = CMBlockBufferCreateWithMemoryBlock (NULL, buffer, len, NULL, NULL, 0, len, 0, &blockBuffer); 
     if(result == noErr) { 
      CMItemCount numSamples = len >> 1; 

      const CMSampleTimingInfo sampleTiming = {CMTimeMake(1, 44100), CMTimeMake(sampleCnt, 44100), kCMTimeInvalid}; 
      CMItemCount numSampleTimingEntries = 1; 

      const size_t sampleSize = 2; 
      CMItemCount numSampleSizeEntries = 1; 

      CMSampleBufferRef sampleBuffer; 
      result = CMSampleBufferCreate(NULL, blockBuffer, true, NULL, NULL, formatDesc, numSamples, numSampleTimingEntries, &sampleTiming, numSampleSizeEntries, &sampleSize, &sampleBuffer); 

      if(result == noErr) { 
       if([assetWriterInput appendSampleBuffer:sampleBuffer] == YES) sampleCnt += numSamples; 
       else { 
        NSLog(@"%s: ERROR\n", __FUNCTION__); 
       } 
       printf("sampleCnt = %d\n", sampleCnt); 
       CFRelease(sampleBuffer); 

      } 
     } 
    } 
    else { 
     NSLog(@"%s: AVAssetWriterInput not taking input data: status=%ld\n", __FUNCTION__, assetWriter.status); 
    } 
} 

void stopAssetWriter(AVAssetWriter *assetWriter) { 
    [assetWriterInput markAsFinished]; 
    [assetWriter finishWritingWithCompletionHandler:^{ 
     NSLog(@"%s: Done: %ld: %d samples\n", __FUNCTION__, assetWriter.status, sampleCnt); 
     sampleCnt = 0; 
    }]; 
    assetWriterInput = NULL; 
} 

답변

1

그것은 AVAsset은 "유효"파일 확장자 예상 것으로 나타났다. 따라서 파일 이름에 * .mp3, * .caf, * .m4a 등과 같은 일반적인 확장자가 없으면 AVAsset은 파일 헤더를보고 미디어 형식을 찾습니다. 반면 AVAudioPlay는 파일 이름을 완전히 무시하고 파일 헤더를보고 미디어 형식을 파악합니다.

이 차이는 Apple doc에 표시되지 않습니다. 나는 이것에 대해 일주일 이상을 낭비했다. 한숨 ...