2014-01-20 2 views
2

Я новичок в потоковом приложении, я создал NSdata из AudioBuffer, и я отправляю nsdata на клиент (получатель). Но я не знаю, как преобразовать NSdata в Audio Buffer.Как создать AudioBuffer/Audio из NSdata

Я использую следующий код для преобразования AudioBuffer в 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

Это код, который я использовал для преобразования моих аудиоданных (аудиофайлов) в представление с плавающей запятой и сохраненных в массиве. Сначала я получаю аудиоданные в AudioBufferList, а затем получаю значение поплавка аудиоданных. Проверьте код, приведенный ниже, если это поможет

-(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

thx ваш ответ –

+0

AudioBuffer для NSdata работает правильно. Но мой вопрос заключается в том, как преобразовать NSdata в аудио/воспроизвести аудио –

0

Я использовал следующий фрагмент кода для преобразования NSData (в моем случае пакета 800 байт, но, вероятно, может быть любого размера) в 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

Вы можете создать NSData с CMSampleBufferRef, используя следующий код, а затем воспроизвести его с помощью 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 Code = 1954115647 «(null)» при попытке запустить плеер. Иногда он может запустить плеер, но я не слышу никакого звука. У вас есть намек? – Vincenzo

2

Вот как я это сделал, на случай, если кто-то еще попал в эту же проблему. Вам не нужно получать данные из AudioBufferList и вместо этого использовать их как есть. Чтобы снова воссоздать AudioBufferList из NSData, мне также нужно количество информации об образцах, поэтому я добавил его непосредственно перед фактическими данными.

Вот как получить данные из 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

Почему «размер + 4'? Почему вы добавляете 4? –

+0

Я думаю, что я использовал первые 4 байта буфера для передачи int, который я использовал для получения дополнительной информации. –

+0

Можете ли вы посмотреть на моего родственника [вопрос] (https://stackoverflow.com/questions/46908485/deep-copy-of-audio-cmsamplebuffer) с включенной функцией баунти? –