- 透過 MMS(Microsoft Media Server) 協定來傳送音樂
- 使用 WMA(Windows Media Audio) 的格式來封裝音樂
若想要使用 MMS+FFmpeg 播放網路廣播,可參考這裡。
若想要錄音,便需要將 WMA 的音樂進行儲存,此處使用 ffmpeg 進行實作,將音樂先轉成PCM進行播放,接著將其轉為AAC後,存入MP4檔案,茲將實作時遇到的問題整理如下:
1. 使用 avcodec_decode_audio4() 將 WMA 解碼,並存至 AVFrame。
此處用法如下,並無問題。
avcodec_decode_audio4(pAudioCodecCtx, pAVFrame1, &gotFrame, &AudioPacket);
2. 使用 avcodec_encode_audio2() 將 AVFrame 進行編碼。
int avcodec_encode_audio2 (
AVCodecContext * avctx,
AVPacket * avpkt,
const AVFrame * frame,
int * got_packet_ptr
)
實作過程中,此處發生問題,出現的錯誤訊息如下:
more samples than frame size (avcodec_encode_audio2)
其原因是因為 frame->nb_samples > avctx->frame_size ,摘錄 FFmpeg 對於 avcodec_encode_audio2() 的說明如下
AVFrame containing the raw audio data to be encoded. May be NULL when flushing an encoder that has the CODEC_CAP_DELAY capability set. If CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame can have any number of samples. If it is not set, frame->nb_samples must be equal to avctx->frame_size for all frames except the last. The final frame may be smaller than avctx->frame_size.
參考程式輸出的log,此時 nb_samples=14336, framesize=1024,的確符合上述說明的情況。
vRet=-22, Err=Invalid argument
data_size=57344,framesize=1024
linesize=57344 channels=2
nb_samples=14336, sample_rate=44100
[aac @ 0xb214600] more samples than frame size (avcodec_encode_audio2)
解決方式
其原則就是要讓每次呼叫 avcodec_encode_audio2(),其帶入的參數能夠滿足 frame->nb_samples <= avctx->frame_size 的條件。 因此我們自行將一個大的 frame 拆開成多個 frame,讓每個 frame->nb_samples 接小於 avctx->frame_size 。
程式碼可參考 AudioPlayer.m 內的函數 putAVPacketsIntoAudioQueue(),這邊僅列出實作時的幾個重點
1. 不要設定 AVCodecContext extradata,若設定 extradata,VLC在解碼時會出現下列錯誤訊息,實際原因可能是 extradata 與 rate, channel 要有正確的對應關係,這部分我並不清楚,因此直接略過,細節部分可參考 faad.c,找尋關鍵字 "Failed to initialize faad using extra data"
main debug: looking for decoder module: 32 candidates2. 當拆開 AVFrame 時,只需要改變 nb_samples 與 data 欄位
faad error: Failed to initialize faad using extra data
avcodec debug: libavcodec initialized (interface 0x361e00)
avcodec error: cannot open codec (MPEG AAC Audio)
3. 可以直接使用 avcodec_fill_audio_frame() 來進行複製部分 AVFrame 的動作。
Reference:
- encode-resampled-pcm-audio-to-aac-using-ffmpeg-api
- http://stackoverflow.com/questions/2410459/encode-audio-to-aac-with-libavcodec?rq=1
- lhttp://ffmpeg.org/doxygen/0.6/output-example_8c-source.html