FFMPEG 4.0 for Android 準(zhǔn)備工作
創(chuàng)新互聯(lián)公司是一家專注于成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)和成都二樞服務(wù)器租用托管的網(wǎng)絡(luò)公司,有著豐富的建站經(jīng)驗(yàn)和案例。下面的函數(shù)方法基于最新的FFMPEG 4.0(4.X):
音頻的原始數(shù)據(jù)是pcm編碼,關(guān)于PCM編碼的相關(guān)信息請看這篇文章:https://www.jianshu.com/p/cfb3d4dc3676
本文的解碼就是要把原始文件中的音頻部分提取出來解碼生成PCM文件,以下是正文,將會去除邏輯相關(guān)代碼,按照流程順序用最基礎(chǔ)的方法展現(xiàn),方便大家掌握用法:
一、獲取多媒體文件的信息
1.聲明并分配內(nèi)存格式信息的Context
avformat_context = avformat_alloc_context();
2.打開文件讀取頭信息avformat_open_input(&avformat_context,src_name,NULL,NULL);
其中avformat_context如果沒有被聲明分配內(nèi)存,此方法會給分配。
3.某些格式?jīng)]有頭信息,需要讀取數(shù)據(jù)來分析avformat_find_stream_info(avformat_context,NULL);
二、解碼設(shè)置
4.找到你想要的數(shù)據(jù)流,可用方法av_find_best_stream代替:
int audio_stream_index = 0;
//like av_find_best_stream
for(i = 0;inb_streams;i++) {
if(avformat_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_stream_index = i;
av_log(NULL,AV_LOG_ERROR,"find audio stream index = %d\n",audio_stream_index);
break;
}
}
AVStream *stream = avformat_context->streams[audio_stream_index];
5.從數(shù)據(jù)流信息中得到×××信息,生成×××codec = avcodec_find_decoder(stream->codecpar->codec_id);
6.聲明解碼Context。
codec_ctx = avcodec_alloc_context3(codec);
7.把stream信息中的參數(shù)拷貝到解碼Context中。ret = avcodec_parameters_to_context(codec_ctx,stream->codecpar);
8.打開×××avcodec_open2(codec_ctx, codec, NULL);
三、進(jìn)行數(shù)據(jù)流解封裝解碼
9.聲明數(shù)據(jù)包packet與數(shù)據(jù)幀frame
frame = av_frame_alloc();
pkt = av_packet_alloc();
10.讀取數(shù)據(jù)包av_read_frame(avformat_context,pkt)
11.發(fā)送數(shù)據(jù)包avcodec_send_packet(codec_ctx,pkt);
12.接收解碼后的數(shù)據(jù)幀,需要注意的是一個(gè)數(shù)據(jù)包可能解壓出多個(gè)數(shù)據(jù)幀,所以需要循環(huán)讀取
avcodec_receive_frame(codec_ctx,frame)//讀取一幀
一個(gè)packet的解碼范例:
while((ret = avcodec_receive_frame(codec_ctx,frame)) >= 0) {
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
int data_size = av_get_bytes_per_sample(codec_ctx->sample_fmt);
LOGV("data_size = %d,line0 = %d,codec_ctx->channels = %d\n",data_size * frame->nb_samples,frame->linesize[0],codec_ctx->channels);
int i,ch = 0;
for(i = 0;inb_samples;i++)
{
for(ch = 0;chchannels;ch++)
{
fwrite(frame->extended_data[ch] + data_size*i,1,data_size,outfile);
}
}
}
13.每種采樣格式的數(shù)據(jù)大小都是固定的
int data_size = av_get_bytes_per_sample(codec_ctx->sample_fmt);得到的是此格式每個(gè)采樣的字節(jié)大小。
frame->linesize[0]內(nèi)存儲的是frame單聲道的字節(jié)大小,=data_size*frame->nb_samples
14.解碼得到的每幀數(shù)據(jù)都有多個(gè)樣本,每幀數(shù)據(jù)可能有多個(gè)通道
//下面的代碼針對的是planar類型格式。
for(i = 0;inb_samples;i++)
{
for(ch = 0;chchannels;ch++)
{
fwrite(frame->extended_data[ch] + data_size*i,1,data_size,outfile);
}
}
音頻格式存儲分為兩種類型,分別為packed和planar,區(qū)別為格式后面是否帶p
帶P和不帶P的數(shù)據(jù)類型的區(qū)別:
P表示Planar(平面),聲道分開存放。其數(shù)據(jù)格式排列方式為 :*
LLLLLLRRRRRRLLLLLLRRRRRRLLLLLLRRRRRRL...(每個(gè)LLLLLLRRRRRR為一個(gè)音頻幀)
而不帶P的數(shù)據(jù)格式(即交錯(cuò)排列)排列方式為:
LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每個(gè)LR為一個(gè)音頻樣本)
目前的音頻一般是planar格式,packed格式的數(shù)據(jù)存在一列之中,左右聲道交替存放。
planar格式聲道的數(shù)據(jù)存在各自的數(shù)組中,生成PCM文件時(shí)需要注意左右聲道加起來才是一個(gè)完整的采樣點(diǎn)。
對于音頻,使用extended_data,data注意是給視頻用的,雖然單純的音頻文件在聲道較少時(shí)也是能用的,但是官方不推薦用。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。