溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

FFMPEG4.0 音頻解碼解封裝

發(fā)布時間:2020-06-28 09:38:16 來源:網(wǎng)絡(luò) 閱讀:6032 作者:liu149339750 欄目:編程語言

FFMPEG 4.0 for Android 準(zhǔ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;i<avformat_context->nb_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-&gt;codecpar-&gt;codec_id);
6.聲明解碼Context。
codec_ctx = avcodec_alloc_context3(codec);
7.把stream信息中的參數(shù)拷貝到解碼Context中。
ret = avcodec_parameters_to_context(codec_ctx,stream-&gt;codecpar);
8.打開×××
avcodec_open2(codec_ctx, codec, NULL);
三、進行數(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ù)幀,需要注意的是一個數(shù)據(jù)包可能解壓出多個數(shù)據(jù)幀,所以需要循環(huán)讀取
avcodec_receive_frame(codec_ctx,frame)//讀取一幀
一個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;i<frame->nb_samples;i++)
        {
            for(ch = 0;ch<codec_ctx->channels;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);得到的是此格式每個采樣的字節(jié)大小。
frame->linesize[0]內(nèi)存儲的是frame單聲道的字節(jié)大小,=data_size*frame->nb_samples
14.解碼得到的每幀數(shù)據(jù)都有多個樣本,每幀數(shù)據(jù)可能有多個通道
//下面的代碼針對的是planar類型格式。

        for(i = 0;i<frame->nb_samples;i++)
        {
            for(ch = 0;ch<codec_ctx->channels;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...(每個LLLLLLRRRRRR為一個音頻幀)
而不帶P的數(shù)據(jù)格式(即交錯排列)排列方式為:
LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每個LR為一個音頻樣本)

目前的音頻一般是planar格式,packed格式的數(shù)據(jù)存在一列之中,左右聲道交替存放。
planar格式聲道的數(shù)據(jù)存在各自的數(shù)組中,生成PCM文件時需要注意左右聲道加起來才是一個完整的采樣點。
對于音頻,使用extended_data,data注意是給視頻用的,雖然單純的音頻文件在聲道較少時也是能用的,但是官方不推薦用。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI