2011-01-07 171 views
7

我想從LPCM原始文件中提取通道音頻,即提取立體聲LPCM文件的左聲道和右聲道。 LPCM是16位深度,交錯式,2個通道,litle endian。從我收集的字節順序是{LeftChannel,RightChannel,LeftChannel,RightChannel ...}並且由於它是16位深度,每個通道會有2個字節的採樣對嗎?從線性PCM提取音頻通道

所以我的問題是,如果我想提取左通道,那麼我會採取在0,2,4,6 ... n * 2地址的字節?而右聲道將是1,3,4,...(n * 2 + 1)。

也提取音頻通道後,我應該提取通道的格式爲16位深度,1通道?

在此先感謝

這是被提取,所以我可能由格式造成的,我目前使用從AssetReader提取PCM音頻..此代碼工作正常與不寫它的渠道的音樂文件的代碼或東西...

NSURL *assetURL = [song valueForProperty:MPMediaItemPropertyAssetURL]; 
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil]; 
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
           [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey, 
           [NSNumber numberWithFloat:44100.0], AVSampleRateKey, 
           [NSNumber numberWithInt:2], AVNumberOfChannelsKey, 
          // [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey, 
           [NSNumber numberWithInt:16], AVLinearPCMBitDepthKey, 
           [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved, 
           [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey, 
           [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey, 
           nil]; 
NSError *assetError = nil; 
AVAssetReader *assetReader = [[AVAssetReader assetReaderWithAsset:songAsset 
                  error:&assetError] 
           retain]; 
if (assetError) { 
    NSLog (@"error: %@", assetError); 
    return; 
} 

AVAssetReaderOutput *assetReaderOutput = [[AVAssetReaderAudioMixOutput 
              assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks 
              audioSettings: outputSettings] 
              retain]; 
if (! [assetReader canAddOutput: assetReaderOutput]) { 
    NSLog (@"can't add reader output... die!"); 
    return; 
} 
[assetReader addOutput: assetReaderOutput]; 


NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString *documentsDirectoryPath = [dirs objectAtIndex:0]; 

//CODE TO SPLIT STEREO 
[self setupAudioWithFormatMono:kAudioFormatLinearPCM]; 
NSString *splitExportPath = [[documentsDirectoryPath stringByAppendingPathComponent:@"monoleft.caf"] retain]; 
if ([[NSFileManager defaultManager] fileExistsAtPath:splitExportPath]) { 
    [[NSFileManager defaultManager] removeItemAtPath:splitExportPath error:nil]; 
} 

AudioFileID mRecordFile; 
NSURL *splitExportURL = [NSURL fileURLWithPath:splitExportPath]; 


OSStatus status = AudioFileCreateWithURL(splitExportURL, kAudioFileCAFType, &_streamFormat, kAudioFileFlags_EraseFile, 
              &mRecordFile); 

NSLog(@"status os %d",status); 

[assetReader startReading]; 

CMSampleBufferRef sampBuffer = [assetReaderOutput copyNextSampleBuffer]; 
UInt32 countsamp= CMSampleBufferGetNumSamples(sampBuffer); 
NSLog(@"number of samples %d",countsamp); 

SInt64 countByteBuf = 0; 
SInt64 countPacketBuf = 0; 
UInt32 numBytesIO = 0; 
UInt32 numPacketsIO = 0; 
NSMutableData * bufferMono = [NSMutableData new]; 
while (sampBuffer) { 


    AudioBufferList audioBufferList; 
    CMBlockBufferRef blockBuffer; 
    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer); 
    for (int y=0; y<audioBufferList.mNumberBuffers; y++) { 
     AudioBuffer audioBuffer = audioBufferList.mBuffers[y]; 
     //frames = audioBuffer.mData; 
     NSLog(@"the number of channel for buffer number %d is %d",y,audioBuffer.mNumberChannels); 
     NSLog(@"The buffer size is %d",audioBuffer.mDataByteSize); 






     //Append mono left to buffer data 
     for (int i=0; i<audioBuffer.mDataByteSize; i= i+4) { 
      [bufferMono appendBytes:(audioBuffer.mData+i) length:2]; 
     } 

     //the number of bytes in the mutable data containing mono audio file 
     numBytesIO = [bufferMono length]; 
     numPacketsIO = numBytesIO/2; 
     NSLog(@"numpacketsIO %d",numPacketsIO); 
     status = AudioFileWritePackets(mRecordFile, NO, numBytesIO, &_packetFormat, countPacketBuf, &numPacketsIO, audioBuffer.mData); 
     NSLog(@"status for writebyte %d, packets written %d",status,numPacketsIO); 
     if(numPacketsIO != (numBytesIO/2)){ 
      NSLog(@"Something wrong"); 
      assert(0); 
     } 


     countPacketBuf = countPacketBuf + numPacketsIO; 
     [bufferMono setLength:0]; 


    } 

    sampBuffer = [assetReaderOutput copyNextSampleBuffer]; 
    countsamp= CMSampleBufferGetNumSamples(sampBuffer); 
    NSLog(@"number of samples %d",countsamp); 
} 
AudioFileClose(mRecordFile); 
[assetReader cancelReading]; 
[self performSelectorOnMainThread:@selector(updateCompletedSizeLabel:) 
         withObject:0 
        waitUntilDone:NO]; 

與audiofileservices輸出格式如下:

 _streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; 
    _streamFormat.mBitsPerChannel = 16; 
    _streamFormat.mChannelsPerFrame = 1; 
    _streamFormat.mBytesPerPacket = 2; 
    _streamFormat.mBytesPerFrame = 2;// (_streamFormat.mBitsPerChannel/8) * _streamFormat.mChannelsPerFrame; 
    _streamFormat.mFramesPerPacket = 1; 
    _streamFormat.mSampleRate = 44100.0; 

    _packetFormat.mStartOffset = 0; 
    _packetFormat.mVariableFramesInPacket = 0; 
    _packetFormat.mDataByteSize = 2; 

回答

4

聽起來差不多吧 - 你有16雙深度,這意味着每個採樣需要2個字節。這意味着左聲道數據將以字節{0,1},{4,5},{8,9}等等爲單位。交錯意味着樣本是交錯的,而不是字節。 除此之外,我會嘗試一下,看看你是否有任何問題與您的代碼。

此外提取音頻 信道之後,我應該設定的 所提取的信道作爲16位深度 ,1個頻道的格式?

提取後只剩下兩個通道中的一個通道,所以是的,這是正確的。

+0

好吧我其實已經嘗試過這一點,結果是不正確的......我用你說的提取算法,但輸出聲音失真...扭曲,因爲它聽起來「慢」... – Samuel 2011-01-09 14:19:45

1

我有一個類似的錯誤,音頻響起'慢',原因是你指定mChannelsPerFrame爲1,而你有一個雙聲道的聲音。將它設置爲2,它應該加快播放速度。也請告訴你是否在你做這個輸出'聽起來'正確... :)