2014-01-20 44 views
2

저는 스트리밍 어플리케이션의 초보자입니다. AudioBuffer에서 NSdata를 만들고 클라이언트 (수신자)에게 nsdata를 보내고 있습니다. 하지만 NSdata를 오디오 버퍼로 변환하는 방법을 모르겠습니다.NSdata에서 AudioBuffer/Audio를 생성하는 방법

(이 잘 작동하고) 나는있는 NSData로 오디오 버퍼를 변환하려면 다음 코드를 사용하고

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{    
AudioStreamBasicDescription audioFormat; 
memset(&audioFormat, 0, sizeof(audioFormat)); 
audioFormat.mSampleRate = 8000.0; 
audioFormat.mFormatID = kAudioFormatiLBC; 
audioFormat.mFormatFlags = kAudioFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kAudioFormatFlagIsAlignedHigh; 
audioFormat.mFramesPerPacket = 1; 
audioFormat.mChannelsPerFrame = 1; 
audioFormat.mBitsPerChannel = 16; 
audioFormat.mBytesPerPacket = 2; 
audioFormat.mReserved = 0; 
audioFormat.mBytesPerFrame = audioFormat.mBytesPerPacket = audioFormat.mChannelsPerFrame* sizeof(SInt16); 

AudioBufferList audioBufferList; 
NSMutableData *data=[[NSMutableData alloc] init]; 
CMBlockBufferRef blockBuffer; 
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer); 
    for(int y=0; y<audioBufferList.mNumberBuffers; y++) 
    { 
     AudioBuffer audioBuffer = audioBufferList.mBuffers[y]; 
     Float32 *frame = (Float32*)audioBuffer.mData; 
     [data appendBytes:frame length:audioBuffer.mDataByteSize]; 
    } 
} 

이 다음 저를 도와주세요 적절한 방법이 아닌 경우 .... 감사합니다.

+0

안녕하세요, 관리 할 수 ​​있었습니까? 그렇다면 솔루션을 게시하십시오. 고마워, 나는 똑같은 문제로 고심하고있다. – moenad

+0

@Sojan - 데이터를 다시 CMSampleBufferRef로 변환 할 수 있었습니까? 또는 당신을 위해 일한 약간의 자원/접근법을 안내해주십시오. –

답변

0

이것은 오디오 데이터 (오디오 파일)를 부동 소수점 표현으로 변환하고 array.firstly로 오디오 데이터를 AudioBufferList에 저장 한 다음 오디오 데이터의 부동 소수점 값을 얻는 코드입니다. 그것이 내가있는 NSData을 변환하려면 다음 코드를 사용 (800 바이트 패킷의 제 경우에, 그러나 틀림없이 어떤 크기의 수)

-(void) PrintFloatDataFromAudioFile { 

NSString * name = @"Filename"; //YOUR FILE NAME 
NSString * source = [[NSBundle mainBundle] pathForResource:name ofType:@"m4a"]; // SPECIFY YOUR FILE FORMAT 

const char *cString = [source cStringUsingEncoding:NSASCIIStringEncoding]; 

CFStringRef str = CFStringCreateWithCString(
              NULL, 
              cString, 
              kCFStringEncodingMacRoman 
              ); 
CFURLRef inputFileURL = CFURLCreateWithFileSystemPath(
                 kCFAllocatorDefault, 
                 str, 
                 kCFURLPOSIXPathStyle, 
                 false 
                ); 

ExtAudioFileRef fileRef; 
ExtAudioFileOpenURL(inputFileURL, &fileRef); 


    AudioStreamBasicDescription audioFormat; 
audioFormat.mSampleRate = 44100; // GIVE YOUR SAMPLING RATE 
audioFormat.mFormatID = kAudioFormatLinearPCM; 
audioFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; 
audioFormat.mBitsPerChannel = sizeof(Float32) * 8; 
audioFormat.mChannelsPerFrame = 1; // Mono 
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * sizeof(Float32); // == sizeof(Float32) 
audioFormat.mFramesPerPacket = 1; 
audioFormat.mBytesPerPacket = audioFormat.mFramesPerPacket * audioFormat.mBytesPerFrame; // = sizeof(Float32) 

// 3) Apply audio format to the Extended Audio File 
ExtAudioFileSetProperty(
         fileRef, 
         kExtAudioFileProperty_ClientDataFormat, 
         sizeof (AudioStreamBasicDescription), //= audioFormat 
         &audioFormat); 

int numSamples = 1024; //How many samples to read in at a time 
UInt32 sizePerPacket = audioFormat.mBytesPerPacket; // = sizeof(Float32) = 32bytes 
UInt32 packetsPerBuffer = numSamples; 
UInt32 outputBufferSize = packetsPerBuffer * sizePerPacket; 

// So the lvalue of outputBuffer is the memory location where we have reserved space 
UInt8 *outputBuffer = (UInt8 *)malloc(sizeof(UInt8 *) * outputBufferSize); 



AudioBufferList convertedData ;//= malloc(sizeof(convertedData)); 

convertedData.mNumberBuffers = 1; // Set this to 1 for mono 
convertedData.mBuffers[0].mNumberChannels = audioFormat.mChannelsPerFrame; //also = 1 
convertedData.mBuffers[0].mDataByteSize = outputBufferSize; 
convertedData.mBuffers[0].mData = outputBuffer; // 

UInt32 frameCount = numSamples; 
float *samplesAsCArray; 
int j =0; 
    double floatDataArray[882000] ; // SPECIFY YOUR DATA LIMIT MINE WAS 882000 , SHOULD BE EQUAL TO OR MORE THAN DATA LIMIT 

while (frameCount > 0) { 
    ExtAudioFileRead(
        fileRef, 
        &frameCount, 
        &convertedData 
        ); 
    if (frameCount > 0) { 
     AudioBuffer audioBuffer = convertedData.mBuffers[0]; 
     samplesAsCArray = (float *)audioBuffer.mData; // CAST YOUR mData INTO FLOAT 

     for (int i =0; i<1024 /*numSamples */; i++) { //YOU CAN PUT numSamples INTEAD OF 1024 

      floatDataArray[j] = (double)samplesAsCArray[i] ; //PUT YOUR DATA INTO FLOAT ARRAY 
       printf("\n%f",floatDataArray[j]); //PRINT YOUR ARRAY'S DATA IN FLOAT FORM RANGING -1 TO +1 
      j++; 


     } 
    } 
}} 
+0

답변을 –

+0

NSBata에 AudioBuffer 제대로 작동합니다. 하지만 내 질문에 NSdata 오디오 변환/오디오 재생 방법 –

0

을 도와 주면 AudioBufferList에 아래의 코드를 확인 :

-(AudioBufferList *) getBufferListFromData: (NSData *) data 
{ 
     if (data.length > 0) 
     { 
      NSUInteger len = [data length]; 
      //I guess you can use Byte*, void* or Float32*. I am not sure if that makes any difference. 
      Byte * byteData = (Byte*) malloc (len); 
      memcpy (byteData, [data bytes], len); 
      if (byteData) 
      { 
       AudioBufferList * theDataBuffer =(AudioBufferList*)malloc(sizeof(AudioBufferList) * 1); 
       theDataBuffer->mNumberBuffers = 1; 
       theDataBuffer->mBuffers[0].mDataByteSize = len; 
       theDataBuffer->mBuffers[0].mNumberChannels = 1; 
       theDataBuffer->mBuffers[0].mData = byteData; 
       // Read the data into an AudioBufferList 
       return theDataBuffer; 
      } 
     } 
     return nil; 
} 
+0

그럼 어떻게 AudioBufferList 재생합니까? 또는 다시 오디오 버퍼로 변환할까요? –

+0

오디오를 재생했지만 음성을 지우지 못하는데 어떻게 관리 할 수 ​​있습니까? –

4

다음 코드를 사용하여 CMSampleBufferRef에서 NSData을 만들고 AVAudioPlayer로 재생할 수 있습니다.

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { 

    AudioBufferList audioBufferList; 
    NSMutableData *data= [NSMutableData data]; 
    CMBlockBufferRef blockBuffer; 
    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer); 

    for(int y=0; y< audioBufferList.mNumberBuffers; y++){ 

     AudioBuffer audioBuffer = audioBufferList.mBuffers[y]; 
     Float32 *frame = (Float32*)audioBuffer.mData; 

     [data appendBytes:frame length:audioBuffer.mDataByteSize]; 

    } 

    CFRelease(blockBuffer); 
    CFRelease(ref); 

    AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:data error:nil]; 
    [player play]; 
} 
+0

어떻게 다른 사람에게 효과가 있었습니까? 위의 데이터가있는 AVAudioPlayer는이 오류와 함께 nil을 반환합니다. 'Error = Error Domain = NSOSStatusErrorDomain Code = 1954115647 "작업을 완료 할 수 없습니다 (OSStatus 오류 1954115647)." 수정 사항이 있습니까? –

+0

동일한 오류가 발생했습니다. 오류 도메인 = NSOSStatusErrorDomain 코드 = 1954115647 "(null)"플레이어를 초기화하려고 할 때. 때로는 플레이어를 초기화 할 수 있지만 소리가 들리지 않습니다. 당신은 힌트를 가지고 있습니까? – Vincenzo

2

다른 사람이 같은 문제에 걸린 경우를 대비하여이 작업을 수행했습니다. AudioBufferList에서 데이터를 가져 와서 대신 사용할 필요는 없습니다. NSData에서 AudioBufferList를 다시 만들려면 샘플 정보도 필요합니다. 그래서 실제 데이터 바로 앞에 추가했습니다.

여기 CMSampleBufferRef에서 데이터를 가져 오는 방법은 다음과 같습니다

AudioBufferList audioBufferList; 
CMBlockBufferRef blockBuffer; 
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer); 
CMItemCount numSamples = CMSampleBufferGetNumSamples(sampleBuffer);   
NSUInteger size = sizeof(audioBufferList); 
char buffer[size + 4]; 
((int*)buffer)[0] = (int)numSamples; 
memcpy(buffer +4, &audioBufferList, size); 
//This is the Audio data. 
NSData *bufferData = [NSData dataWithBytes:buffer length:size + 4]; 

이이 데이터 밖으로 AudioSampleBufferRef를 만드는 방법은 다음과 같습니다

const void *buffer = [bufferData bytes]; 
buffer = (char *)buffer; 

CMSampleBufferRef sampleBuffer = NULL; 
OSStatus status = -1; 

/* Format Description */ 
AudioStreamBasicDescription audioFormat; 
audioFormat.mSampleRate = 44100.00; 
audioFormat.mFormatID = kAudioFormatLinearPCM; 
audioFormat.mFormatFlags = 0xc; 
audioFormat.mBytesPerPacket= 2; 
audioFormat.mFramesPerPacket= 1; 
audioFormat.mBytesPerFrame= 2; 
audioFormat.mChannelsPerFrame= 1; 
audioFormat.mBitsPerChannel= 16; 
audioFormat.mReserved= 0; 

CMFormatDescriptionRef format = NULL; 
status = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &audioFormat, 0, nil, 0, nil, nil, &format); 

CMFormatDescriptionRef formatdes = NULL; 
status = CMFormatDescriptionCreate(NULL, kCMMediaType_Audio, 'lpcm', NULL, &formatdes); 
if (status != noErr) 
{ 
    NSLog(@"Error in CMAudioFormatDescriptionCreater"); 
    return; 
} 

/* Create sample Buffer */ 
CMSampleTimingInfo timing = {.duration= CMTimeMake(1, 44100), .presentationTimeStamp= kCMTimeZero, .decodeTimeStamp= kCMTimeInvalid}; 
CMItemCount framesCount  = ((int*)buffer)[0]; 

status = CMSampleBufferCreate(kCFAllocatorDefault, nil , NO,nil,nil,format, framesCount, 1, &timing, 0, nil, &sampleBuffer); 

if(status != noErr) 
{ 
    NSLog(@"Error in CMSampleBufferCreate"); 
    return; 
} 

/* Copy BufferList to Sample Buffer */ 
AudioBufferList receivedAudioBufferList; 
memcpy(&receivedAudioBufferList, buffer + 4, sizeof(receivedAudioBufferList)); 

status = CMSampleBufferSetDataBufferFromAudioBufferList(sampleBuffer, kCFAllocatorDefault , kCFAllocatorDefault, 0, &receivedAudioBufferList); 
if (status != noErr) { 
    NSLog(@"Error in CMSampleBufferSetDataBufferFromAudioBufferList"); 
    return; 
} 
//Use your sampleBuffer. 

나에게 질문을 알고합시다.

+0

왜'size + 4'입니까? 너 왜 4를 추가하는거야? –

+0

내가 int를 전송하기 위해 버퍼의 처음 4 바이트를 사용하고 있다고 생각하는데, 이는 몇 가지 추가 정보를 위해 사용했다. –

+0

현상금을 사용할 수있는 나의 친척 [질문] (https://stackoverflow.com/questions/46908485/deep-copy-of-audio-cmsamplebuffer)을 볼 수 있습니까? –