6

私のアプリケーションでは、NSData オブジェクトに保存されている MP3 ファイルをデコードする必要があります。

セキュリティ上の理由から、NSData オブジェクトをディスクに書き込み、システム URL 参照を使用して再度開くことは望ましくありません。それがローカルに一時的に保存されるだけであってもです。

これを行うために拡張オーディオ ファイル サービス (ま​​たはオーディオ ファイル サービス) を利用したいのですが、これらのオーディオ ファイル サービスで読み取ることができる、メモリ内にのみ存在する NSData の表現を取得するのに問題があります。

編集: MP3 データをデコードして、線形の PCM オーディオ サンプルにアクセスして操作できるようにしたいと考えています。NSData オブジェクトからの再生は問題ありません。

私のコードは次のとおりです。

 decryptedData; //an NSData object which has already been initialized
 const void *dataBytes   = decryptedData.bytes; //pointer to the bytes in my NSData object 

//this creates a CFURLRef from the pointer to the byte data
//I have printed out the resulting CFURL and have confirmed that it is indeed reading the bytes correctly
CFURLRef audioFileURLFromBytes = CFURLCreateWithBytes (kCFAllocatorDefault,
                                                               dataBytes,
                                                               decryptedData.length,
                                                               kCFStringEncodingASCII,
                                                               NULL);

//attempt to open the the URL using Extended Audio File Services
        ExtAudioFileRef outExtAudioFile;
        OSStatus err = 0;
        err = ExtAudioFileOpenURL(audioFileURLFromBytes, &outExtAudioFile);
        if (err != noErr) {
            NSLog(@"ExtAudioFileOpenURL failed with OSStatus Code %i \n", err);
        }

//Attempt to open the URL using Audio File Services
        AudioFileID audioFile;
        OSStatus res = 0;
        res = AudioFileOpenURL(audioFileURLFromBytes, kAudioFileReadPermission,  kAudioFileMP3Type, &audioFile);
        if (res != noErr) {
            NSLog(@"AudioFileOpenURL failed with OSStatus Code %i \n", res);
        }

どちらの URL を開こうとしても、「ファイルが見つかりません」という OSStatus コード 43 が返されます。

ポインターが NSData のメモリ内の正しいアドレスを指していること、およびバイトを正しく読み取ることができることを確認しました。

メモリに格納されたバイトへの参照を禁止する、拡張オーディオ ファイル サービスに何らかの制限はありますか?

ご協力いただきありがとうございます。

編集:Sboothの提案を使用してそれを行う方法を見つけました。以下のコード: この関数は、オーディオ ファイルの mp3 表現を含む NSData オブジェクトを受け取ります。サンプルを取得できるようにリニア PCM としてデコードし、AAC として再エンコードします。MP3 エンコーディングは、すべてのプラットフォーム (モバイル/デスクトップ) で CoreAudio で利用できるとは思いません。このコードは私の Mac でテストされ、仕事が完了しました。

-(void) audioFileReaderWithData: (NSData *) audioData {

        AudioFileID         refAudioFileID;
        ExtAudioFileRef     inputFileID;
        ExtAudioFileRef     outputFileID;

        OSStatus result = AudioFileOpenWithCallbacks(audioData, readProc, 0, getSizeProc, 0, kAudioFileMP3Type, &refAudioFileID);
        if(result != noErr){
            NSLog(@"problem in theAudioFileReaderWithData function: result code %i \n", result);
        }

        result = ExtAudioFileWrapAudioFileID(refAudioFileID, false, &inputFileID);
        if (result != noErr){
            NSLog(@"problem in theAudioFileReaderWithData function Wraping the audio FileID: result code %i \n", result);
        }

        // Client Audio Format Description
    AudioStreamBasicDescription clientFormat;
    memset(&clientFormat, 0, sizeof(clientFormat));
    clientFormat.mFormatID          = kAudioFormatLinearPCM;
    clientFormat.mFramesPerPacket   = 1;
    clientFormat.mChannelsPerFrame  = 2;
    clientFormat.mBitsPerChannel    = 32;
    clientFormat.mBytesPerPacket    = clientFormat.mBytesPerFrame = 4 *   clientFormat.mChannelsPerFrame;
    clientFormat.mFormatFlags       = kAudioFormatFlagsNativeFloatPacked;
    clientFormat.mSampleRate        = 44100;

     //Output Audio Format Description
     AudioStreamBasicDescription outputFormat;
     memset(&outputFormat, 0, sizeof(outputFormat));
     outputFormat.mChannelsPerFrame  = 2;
     outputFormat.mSampleRate        = 44100;
     outputFormat.mFormatID          = kAudioFormatMPEG4AAC;
     outputFormat.mFormatFlags       = kMPEG4Object_AAC_Main;
     outputFormat.mBitsPerChannel    = 0;
     outputFormat.mBytesPerFrame     = 0;
     outputFormat.mBytesPerPacket    = 0;
     outputFormat.mFramesPerPacket   = 1024;

     // create the outputFile that we're writing to here....
     UInt32 outputFormatSize = sizeof(outputFormat);
     result = 0;
     result = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &outputFormatSize, &outputFormat);
     if(result != noErr)
            NSLog(@"could not set the output format with status code %i \n",result);

     NSMutableString *outputFilePath = [NSMutableString stringWithCapacity: 100];
     [outputFilePath setString:@"/Users/You/Desktop/testAudio.m4a"];
     NSURL *sourceURL = [NSURL fileURLWithPath:outputFilePath];

     result      =  0;
     result      =  ExtAudioFileCreateWithURL((CFURLRef)sourceURL, kAudioFileM4AType, &outputFormat, NULL, kAudioFileFlags_EraseFile, &outputFileID);
     if(result != noErr){
           NSLog(@"ExtAudioFileCreateWithURL failed for outputFileID with status %i \n", result);
      }

     int size = sizeof(clientFormat);
     result = 0;
     result = ExtAudioFileSetProperty(inputFileID, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);

     if(result != noErr)
        NSLog(@"error on ExtAudioFileSetProperty for input File with result code %i \n", result);

     size = sizeof(clientFormat);
     result = 0;
     result = ExtAudioFileSetProperty(outputFileID, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
     if(result != noErr)
         NSLog(@"error on ExtAudioFileSetProperty for output File with result code %i \n", result);

     int totalFrames = 0;
     UInt32 outputFilePacketPosition = 0; //in bytes  
     UInt32 encodedBytes = 0;

     while (1) {
        UInt32 bufferByteSize       = 22050 * 4 * 2;
        char srcBuffer[bufferByteSize];
        UInt32 numFrames            = (bufferByteSize/clientFormat.mBytesPerFrame);

        AudioBufferList fillBufList;
        fillBufList.mNumberBuffers  = 1;
        fillBufList.mBuffers[0].mNumberChannels     = clientFormat.mChannelsPerFrame;
        fillBufList.mBuffers[0].mDataByteSize       = bufferByteSize;
        fillBufList.mBuffers[0].mData               = srcBuffer;
        result = 0;
        result = ExtAudioFileRead(inputFileID, &numFrames, &fillBufList);

        if (result != noErr) {
            NSLog(@"Error on ExtAudioFileRead with result code %i \n", result);
                totalFrames = 0;
            break;
        }
        if (!numFrames)
            break;

        totalFrames = totalFrames + numFrames;

        result = 0;
        result = ExtAudioFileWrite(outputFileID,
                                   numFrames,
                                   &fillBufList);

        if(result!= noErr){
            NSLog(@"ExtAudioFileWrite failed with code %i \n", result);
        }

        encodedBytes += numFrames  * clientFormat.mBytesPerFrame;
    }

    //Clean up

    ExtAudioFileDispose(inputFileID);
    ExtAudioFileDispose(outputFileID);
    AudioFileClose(refAudioFileID);

}

そして、これらの機能も必要になります...

static OSStatus readProc(void* clientData,
                         SInt64 position,
                         UInt32 requestCount,
                         void* buffer,
                         UInt32* actualCount)
{

    NSData *inAudioData = (NSData *) clientData;

    size_t dataSize = inAudioData.length;
    size_t bytesToRead = 0;

    if(position < dataSize) {
        size_t bytesAvailable = dataSize - position;
        bytesToRead = requestCount <= bytesAvailable ? requestCount : bytesAvailable;

        [inAudioData getBytes: buffer range:NSMakeRange(position, bytesToRead)];
    } else {
        NSLog(@"data was not read \n");
        bytesToRead = 0;
    }

    if(actualCount)
        *actualCount = bytesToRead;

    return noErr;
}

static SInt64 getSizeProc(void* clientData) {
    NSData *inAudioData = (NSData *) clientData;
    size_t dataSize = inAudioData.length;
    return dataSize;
}
4

2 に答える 2

3

CFURLRef問題は、ASCII エンコーディングを使用してオーディオ バイト (MP3 フレーム) からオブジェクト を作成しようとしていることです。CFURLCreateWithBytesバイナリデータではなく、バイト文字列で使用することを意図しています (つまり、" http://www.apple.com " としてchar *)。use を使用して目的を達成するAudioFileOpenWithCallbacksには、NSDataオブジェクトを refcon として渡し、渡したNSDataで動作するカスタム コールバックで生の読み取り/シークを処理します。

于 2013-06-27T00:14:31.470 に答える
-1

ストリームまたはメモリからオーディオを再生するには、Audio Queue ServicesまたはAVPlayerを使用します。

于 2013-06-26T20:57:51.910 に答える