簡體   English   中英

AVAssetReader和AudioFileReadPackets如何讀取音頻之間的差異

[英]difference between how AVAssetReader and AudioFileReadPackets reads Audio

考慮這兩種場景,用於從音頻文件讀取/寫入數據(用於通過網絡發送):

場景1:音頻文件服務:
使用音頻文件服務中的 AudioFileReadPackets 這會生成您可以通過網絡輕松發送的音頻數據包。 在接收端,您使用AudioFileStreamOpenAudioFileStreamParseBytes來解析數據。

然后AudioFileStreamParseBytes有兩個回調函數: AudioFileStream_PropertyListenerProcAudioFileStream_PacketsProc 當在流中發現新屬性並且分別從流接收到分組時,將調用這些人。 收到數據包后,您可以使用音頻隊列服務將其提供給音頻隊列,該服務可以正常播放文件。

注意:此方法不適用於存儲在iPod庫中的音樂文件,這使我們進入第二種情況:

場景2:AVAssetReader:
使用AVAssetReader,您可以從iPod音樂庫中讀取並通過網絡發送數據包。 通常,您可以直接在類似於上面的音頻隊列上加載數據包。 但是,在這種情況下,您必須創建一個線程以確保在隊列已滿時阻止接收數據包,並在隊列緩沖區可用時取消阻止(請參閱示例)。

題:
是否可以使用AVAssetReader發送數據包,只是讓它被AudioFileStreamParseBytes讀取? (動機是AudioFileStreamParseBytes的回調將處理線程/阻塞業務並為您節省痛苦)。 我嘗試這樣做:
1.首先使用AVAssetReader讀取音頻文件

//NSURL *assetURL = [NSURL URLWithString:@"ipod-library://item/item.m4a?id=1053020204400037178"]; 
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];

NSError * error = nil;
AVAssetReader* reader = [[AVAssetReader alloc] initWithAsset:songAsset error:&error];

AVAssetTrack* track = [songAsset.tracks objectAtIndex:0]; 

// Note: I don't supply an audio format description here, rather I pass on nil to keep the original
// file format. In another piece of code (see here: http://stackoverflow.com/questions/12264799/why-is-audio-coming-up-garbled-when-using-avassetreader-with-audio-queue?answertab=active#tab-top) I can extract the audio format from the track, let's say it's an AAC format.
AVAssetReaderTrackOutput* readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track
                                                                                    outputSettings:nil];


[reader addOutput:readerOutput];
[reader startReading];

2.設置流光

// notice how i manually add the audio file type (for the file hint parameter) 
// using the info from step one.. If i leave it as 0, this call fails and returns
// the typ? error, which is :The specified file type is not supported.  
streamer->err = AudioFileStreamOpen((__bridge void*)streamer, 
                                     ASPropertyListenerProc, ASPacketsProc, 
                                     kAudioFileAAC_ADTSType, &(streamer->audioFileStream)); 

3.一旦我收到數據,我解析字節:

streamer->err = AudioFileStreamParseBytes(streamer->audioFileStream, inDataByteSize, inData, 0);

問題:當我做這種方式。我發送的字節數和AudioFileStreamParseBytes 不會失敗。 但是,永遠不會調用回調* AudioFileStream_PropertyListenerProc *和* AudioFileStream_PacketsProc *。 這讓我覺得解析器無法解析字節並從中提取任何有用的信息..在AudioStreamParseBytes的文檔中它指出:*你應該提供至少不止一個數據包的音頻文件數據,但它最好一次提供一些數據包到幾秒數據。*我發送超過900字節,這低於GKSession的數據限制 我非常確定900字節就足夠了(在方案1下測試時,每次總字節數為417,並且工作正常)。

有任何想法嗎?

簡短的回答是,音頻數據包被AudioFileStreamParseBytes解析是沒有意義的。在文檔中 AudioFileStreamParseBytes是一個依賴於音頻文件存在的函數(因此參數inAudioFileStream ..定義為您希望傳遞數據的解析器的ID。解析器ID由AudioFileStreamOpen函數返回。

所以吸取了教訓:不要嘗試使用iOS功能來適應你的情況..它應該是另一種方式。

我最終做的是直接將數據提供給音頻隊列..而不經過所有這些不必要的中間函數..更深入的方式是將數據饋送到音頻單元..但我的應用程序不需要那個級別控制

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM