直播流程
一次直播中主播端采集音視頻編碼上傳數據到服務器捣卤,觀眾端不斷的拉取數據四瘫,數據解碼音視頻渲染到手機耕肩。
音頻數據流格式的變化
音頻采集上來的數據格式是pcm因妇,pcm格式的數據非常龐大问潭,不適合在網絡上傳播,所以我們用編碼器把pcm數據格式處理為aac或者mp3格式婚被,編碼后的數據再加個殼封裝成flv或者mp4多媒體文件狡忙。在觀眾端音頻的數據格式走向相反。一般直播過程中不需要再把編碼后的aac數據封裝成多媒體文件址芯,而是直接在網絡中傳輸aac格式的音頻數據灾茁。
音頻采集三要素
采樣大小:一個采樣由多少bit存放,一般是16bit谷炸。
采樣率:采樣頻率8k北专、16k、32k旬陡、44.1k拓颓。
聲道數:單聲道、雙聲道描孟、多聲道驶睦。
采樣大小越大,聲音的強度越高匿醒,采樣率越大场航,聲音的還原度越高。
音頻編碼
有損壓縮
人類聽覺范圍在20Hz~20kHz廉羔,低于20Hz的是次聲波溉痢,高于20Hz的是超聲波。
根據頻域遮蔽效應蜜另,音頻中去除人類聽不到的音頻數據适室。
根據時域遮蔽效應,去除音頻中嘈雜的低音举瑰。
無損壓縮
對音頻數據熵編碼捣辆,熵編碼包括哈夫曼編碼、香農編碼此迅、算數編碼汽畴。
音頻編碼過程
編碼的代碼
?創(chuàng)建編碼器
? ? //avcodec_find_encoder(AV_CODEC_ID_AAC);
? ? AVCodec *codec = avcodec_find_encoder_by_name("libfdk_aac");
? ? //創(chuàng)建 codec 上下文
? ? AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
? ? codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16;? ? ? ? ? //輸入音頻的采樣大小
? ? codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;? ? //輸入音頻的channel layout
? ? codec_ctx->channels =2;? ? ? ? ? ? ? ? ? ? ? ? ? ? //輸入音頻 channel 個數
? ? codec_ctx->sample_rate =44100;? ? ? ? ? ? ? ? ? ? //輸入音頻的采樣率
? ? codec_ctx->bit_rate =0; //AAC_LC: 128K, AAC HE: 64K, AAC HE V2: 32K
? ? codec_ctx->profile = FF_PROFILE_AAC_HE_V2;//閱讀 ffmpeg 代碼
? ? //打開編碼器
? ? ?ret = avcodec_open2(codec_ctx, codec,NULL)
?//將數據送編碼器
? ? ret = avcodec_send_frame(ctx, frame);
?//獲取編碼后的音頻數據
? ? ? ? ret = avcodec_receive_packet(ctx, pkt);
音頻采樣和重采樣
音頻采集命令行:
ffmpeg -f avfoundation -i :0 out.wav
音頻播放命令行:
ffplay out.wav
wav是音頻原始數據的一種格式,它實質上就是pcm數據包加上一個頭部耸序。這個頭部包含了很多的信息忍些,包括音頻的采樣率、采樣大小和聲道數坎怪。如果在音頻采集的時候罢坝,采集的數據格式為pcm格式
ffmpeg -f avfoundation -i :0 out.pcm
音頻播放命令就要指定音頻三要素的參數
ffplay -ar 44100 -ac 2 -f s16le out.pcm
ffmpeg代碼采集音頻流程
打開輸入設備
? ? avdevice_register_all();?//register audio device?
? ? //ctx
? ? AVFormatContext *fmt_ctx =NULL;
? ? AVDictionary *options =NULL;
? ? //[[video device]:[audio device]]
? ? char*devicename =":0";
? ? //get format
? ? AVInputFormat *iformat = av_find_input_format("avfoundation");
? ? //open device
ret = avformat_open_input(&fmt_ctx, devicename, iformat, &options)
數據包
FILE *outfile = fopen(path,'wb');
AVPacket ?pkt;
while(ret = av_read_frame(fmt_ctx,&pkt)== 0){
fwrite(pkt.data,pkt.size,1,outfile);
av_packet_unref(&pkt);
}
音頻重采樣是將音頻三元組采樣率、采樣大小搅窿、和通道數的值轉成另外一組值嘁酿。
例如:將441000/16/2轉成48000/16/2
為什么需要重新采樣
1 從設備采集的音頻數據和編碼器要求的數據不一致隙券。
2 揚聲器要求的音頻數據和要播放的音頻數據不一致。
采樣的代碼
?SwrContext* swr_ctx =NULL;
?swr_ctx = swr_alloc_set_opts(NULL,? ? ? ? ? ? ? ? //ctx
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AV_CH_LAYOUT_STEREO,//輸出channel布局
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AV_SAMPLE_FMT_S16,? //輸出的采樣格式
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 44100,? ? ? ? ? ? ? //采樣率
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AV_CH_LAYOUT_STEREO,//輸入channel布局
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AV_SAMPLE_FMT_FLT,? //輸入的采樣格式
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 44100,? ? ? ? ? ? ? //輸入的采樣率
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0,NULL);
?//重采樣
? ? ? ? swr_convert(swr_ctx,? ? ? ? ? ? ? ? ? ? //重采樣的上下文
? ? ? ? ? ? ? ? ? ? dst_data,? ? ? ? ? ? ? ? ? //輸出結果緩沖區(qū)
? ? ? ? ? ? ? ? ? ? 512,? ? ? ? ? ? ? ? ? ? ? ? //每個通道的采樣數
? ? ? ? ? ? ? ? ? ? (constuint8_t **)src_data,//輸入緩沖區(qū)
? ? ? ? ? ? ? ? ? ? 512);? ? ? ? ? ? ? ? ? ? ? //輸入單個通道的采樣數
注:本文代碼只是簡單示范闹司,實際操作中需要注意內存泄漏娱仔,設備狀態(tài)還有api返回值結果做些判斷。