2012-08-23 4 views
1

내부에 인코딩 된 PCM 오디오가있는 여러 CAF 파일을 조인 할 수 있습니다. 먼저 CAF 파일 중 하나에서 데이터 형식을 읽습니다. PCM 데이터 포맷에 대한여러 ALAC 파일을 결합합니다.

UInt32 size = sizeof(srcFormatDescription); 
     status = AudioFileGetProperty(srcAudioFile, kAudioFilePropertyDataFormat, &size, &srcFormatDescription); 

[Line 7697] mSampleRate: 44100.000000 
[Line 7698] mFormatID: 1819304813d 
[Line 7699] mFormatFlags: 12d 
[Line 7700] mBytesPerPacket: 2d 
[Line 7701] mFramesPerPacket: 1d 
[Line 7702] mBytesPerFrame: 2d 
[Line 7703] mChannelsPerFrame: 1d 
[Line 7704] mBitsPerChannel: 16d 
[Line 7705] mReserved: 0d 

그럼 내가 모든 CAF의를 포함하는, 대상 파일에 대한 데이터 형식을 설정할 것 같습니다. 다음 단계에서

destFormatDescription = srcFormatDescription; 
status = AudioFileCreateWithURL(dest, kAudioFileCAFType, &destFormatDescription, kAudioFileFlags_EraseFile, &destAudioFile); 

나는 CAF

status = AudioFileReadBytes(srcAudioFile, 
            FALSE, 
            currentStartForReading, 
            &bytesNumberToRead, 
            buffer); 

에서 데이터를 읽고는

status = AudioFileWriteBytes(destAudioFile, 
            FALSE, 
            writePosition, 
            &bytesNumberToWrite, 
            buffer); 

이 단계가 루프에서 수행된다 destAudioFile하는 물품. 그것은 위대한 작품. 그러나 큰 문제가 있습니다. 이제 ALAC 형식의 데이터가 포함 된 CAF 파일에 대해 동일한 단계를 수행하려고합니다. 작동하지 않습니다. AudioFileWriteBytes는 반환 된 오류 연산을 지원하지 않습니다. ALAC 데이터 형식

아무도 내가 내 애플 무손실 데이터와 여러 CAF 파일을 가입 할 수있는 방법을 알고 있나요이

[Line 7697] mSampleRate: 44100.000000 
[Line 7698] mFormatID: 1634492771d 
[Line 7699] mFormatFlags: 1d 
[Line 7700] mBytesPerPacket: 0d 
[Line 7701] mFramesPerPacket: 4096d 
[Line 7702] mBytesPerFrame: 0d 
[Line 7703] mChannelsPerFrame: 1d 
[Line 7704] mBitsPerChannel: 0d 
[Line 7705] mReserved: 0d 

처럼 보인다?

답변

1

인코딩 된 PCM 오디오가있는 여러 CAF 파일을 내부에서 결합 할 수 있습니다. 먼저 CAF 파일 중 하나에서 데이터 형식을 읽습니다.

ASBD가 일치하면 오디오 파일이 정확합니다. 그러나 입력 파일의 샘플 형식이 일치하지 않으면 데이터가 손상됩니다. 이는 각 CAF 파일이 정확히 하나의 샘플 데이터 청크와 하나의 오디오 설명 청크를 정의하기 때문입니다.

따라서 하나의 오디오 데이터 청크에 여러 형식의 샘플 데이터를 추가하려고하면 오류가 발생합니다. (시도하고있는 것이 든 그렇지 않던간에)

압축 된 형식에는 추가 필드 즉, 마법 쿠키가 있어야합니다. 모든 쿠키는 동일해야합니다 (이것은 불투명 한 데이터 표현, btw입니다).

마지막으로 압축 된 데이터를 쓰는 올바른 방법은 패킷 테이블 청크를 사용하는 것입니다. VBR/VFR 포맷은 정확히 하나의 패킷 테이블 청크를 지정해야합니다.

내부의 Apple 무손실 데이터로 여러 CAF 파일을 어떻게 조인 할 수 있습니까?

모든 것 : ALAC의 경우 선택한 방법을 사용하면 높은 실패율이 발생합니다. 또한 이러한 파일과 그 청크를 관련된 모든 패킷 세부 정보와 올바르게 동기화하는 데 많은 도움이됩니다.새로운 ALAC는 귀하의 의견은 귀하의 의견은을 파일에서

  • 공통 샘플 형식을 결정하는 파일을 열 수
  • 사용 ExtAudioFileOpenURL 파일 생성

    • 사용 ExtAudioFileCreateWithURL : 그래서

      ,의 다른 각도에서이 문제를 접근하자
    • ExtAudioFileSetProperty + kExtAudioFileProperty_ClientDataFormat을 사용하여 일반적인 PCM 형식을 지정하십시오.
    • 대상/ALAC fi 르 컨버터는 당신이 선택한 일반적인 PCM 형식을 기대합니다. ,
    • 가까운 모든 파일을해야

    나머지 파일의 대상에

  • 반복을 작성, 입력 파일의 샘플 데이터를 읽을 (하지만 아마 코드의 몇 백 라인이 필요합니다 원시 AudioFile API를 다루는 경우).

  • +1

    귀하의 aproach는 괜찮아 보입니다. 사용하겠습니다. 고마워. – pawelropa

    +0

    @ user1212112 예, 불행히도,이 작업은 희망만큼 간단하지 않습니다. 그러나 ExtAudioFile 변환기는 많은 복잡성으로부터 해방시켜줍니다. 행운을 빈다. 환영 받는다. – justin

    0

    AVAssetExportSession, AVMutableComposition, AVAsset, AVMutableCompositionTrack을 사용하지 않은 이유가 궁금합니다. 다른 오디오 파일을 결합/병합하려면 아래 단계를 따르라고 제안 할 수 있습니다.

    1. URL을 사용하여 각 오디오 파일을 AVAsset에로드하십시오.
    2. 아래 코드를 사용하여 AVMutableComposition 개체를 초기화하십시오.

    3. 아래와 같이 변경 가능한 오디오 트랙을 추가하십시오.

      AVMutableCompositionTrack *AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 
      
    4. 은 다음과 AudioTrack에 자산의 시간 범위를 추가합니다.

      [AudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeAdd(firstAsset.duration, secondAsset.duration)) ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil]; 
      
    5. AVAssetExportSession를 만들고 코드를 아래의 모든 오디오 파일을 병합합니다.

      // Prepare final exporter for merging 
      AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition AVAssetExportPresetAppleM4A]; 
      exporter.outputURL = outputURL; 
      exporter.outputFileType = AVFileTypeAppleM4A; 
      exporter.videoComposition = mainCompositionInst; 
      exporter.shouldOptimizeForNetworkUse = YES; 
      
      // Notify caller that merging process is about tro start 
      [self.delegate handler:self didStartMergingAtPath:[outputURL path]]; 
      
      [exporter exportAsynchronouslyWithCompletionHandler:^ { 
          dispatch_async(dispatch_get_main_queue(), ^{ 
           [self exportDidFinishMerging:exporter]; 
          }); 
      }]; 
      
    6. 또한 내보내기 프로세스의 상태를 확인하는 방법을 구현하십시오.

      - (void)exportDidFinishMerging:(AVAssetExportSession*)session { 
      if(session.status == AVAssetExportSessionStatusCompleted){ 
      // notify the calling class that merging is finished 
      [self.delegate handler:self didFinishMergingAtPath:[session.outputURL path]]; 
          } 
      } 
      

    참고 :이 직접 코드에 사용할 수 있지만 이것은 단지 목적을 이해하기위한 샘플 코드되지 않도록 메모를 확인하시기 바랍니다. 희망이 당신을 도울 수 있습니다.

    관련 문제