4.基于FFMPEG将音频解码为PCM

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011003120/article/details/81735139

继续FFMPEG学习之路,前面了解了将PCM编码为AAC文件,接下来则需要了解一下解码方面,将MP3/AAC等音频格式解码为PCM数据,记录一下过程。。。

1)解码流程
整个解码流程采用伪代码大致如下:
初始化复用器和解复用器—>获取输入文件的一些信息—->查找解码器并打开—->读出音频数据并解码—>将解码后的数据写入文件中—>结束,做去初始化工作

2)其他
其中,需要注意的是要根据音源的格式来确定是否要做重采样工作。即使用SwrContext进行重采样。

3)代码
代码参考雷博的代码,在一些地方做了些修改。

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>

#define debug_msg(fmt, args ...) printf("--->[%s,%d]  " fmt "\n\n", __FUNCTION__, __LINE__, ##args)

#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio  
                                     //48000 * (32/8)
int test_audio_2_PCM()
{
    AVFormatContext *pFortCtx = NULL;
    AVCodecContext *pCodecCtx = NULL;
    AVCodec *pCodec = NULL;
    AVPacket *pPkt = NULL;
    AVFrame*pFrame = NULL;
    struct SwrContext *pSwrCtx = NULL;

    FILE* outFile = fopen("output.pcm", "wb");
    char inFile[] = "skycity1.mp3";

    int ret = -1;
    int audioIndex = -1;
    int i = 0;
    int got_picture = -1;

    uint64_t out_chn_layout = AV_CH_LAYOUT_STEREO;  //通道布局 输出双声道
    enum AVSampleFormat out_sample_fmt=AV_SAMPLE_FMT_S16; //声音格式
    int out_sample_rate=44100;   //采样率
    int out_nb_samples = -1;   
    int out_channels = -1;        //通道数
    int out_buffer_size = -1;   //输出buff
    unsigned char *outBuff = NULL;

    uint64_t in_chn_layout = -1;  //通道布局 

    struct SwrContext *au_convert_ctx;

    av_register_all();

    pFortCtx = avformat_alloc_context();  

    if (avformat_open_input(&pFortCtx, inFile, NULL, NULL) != 0)   //open input file and read data into buf
    {
        debug_msg("avformat_open_input error!\n");
        ret = -1;
        goto ERR_1;
    }

    if (avformat_find_stream_info(pFortCtx, NULL) < 0)   //find stream some info
    {
        debug_msg("avformat_find_stream_info error!\n");
        ret = -1;
        goto ERR_1;
    }

    /* find audio index */
    for (i = 0; i < pFortCtx->nb_streams; i++)
    {
        if (pFortCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            audioIndex = i;
            break;
        }
    }

    if (-1 == audioIndex)
    {
        debug_msg("can not find audio index!\n");
        ret = -1;
        goto ERR_1;
    }

    debug_msg("------>audioIndex is %d\n", audioIndex);

    pCodecCtx = pFortCtx->streams[audioIndex]->codec;
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if (NULL == pCodec)
    {
        debug_msg("can not find decoder!\n");
        ret = -1;
        goto ERR_1;
    }
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        debug_msg("Could not open codec.\n");
        ret = -1;
        goto ERR_1;
    }

    if (NULL == (pPkt = (AVPacket *)av_malloc(sizeof(AVPacket))))
    {
        debug_msg("AV malloc failure.\n");
        ret = -1;
        goto ERR_2;
    }

    //out parameter
    out_nb_samples = pCodecCtx->frame_size;
    out_channels = av_get_channel_layout_nb_channels(out_chn_layout);
    out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples,  out_sample_fmt, 1);
    outBuff = (unsigned char *)av_malloc(MAX_AUDIO_FRAME_SIZE*2); //双声道
    printf("-------->out_buffer_size is %d\n",out_buffer_size);
    in_chn_layout = av_get_default_channel_layout(pCodecCtx->channels);

    pFrame = av_frame_alloc();

    //Swr
    au_convert_ctx=swr_alloc_set_opts(NULL,
    out_chn_layout,                                /*out*/
    out_sample_fmt,                              /*out*/
    out_sample_rate,                             /*out*/
    in_chn_layout,                                  /*in*/
    pCodecCtx->sample_fmt ,               /*in*/
    pCodecCtx->sample_rate,               /*in*/
    0, 
    NULL);

    swr_init(au_convert_ctx);

    while(av_read_frame(pFortCtx, pPkt) >= 0)
    {
        if (pPkt->stream_index == audioIndex)
        {
            if (avcodec_decode_audio4(pCodecCtx, pFrame, &got_picture, pPkt) < 0)
            {
                debug_msg("Error in decoding audio frame.\n");
                ret = -1;
                goto  ERR_3;
            }

            if (got_picture > 0)
            {
                swr_convert(au_convert_ctx,&outBuff, MAX_AUDIO_FRAME_SIZE,(const uint8_t **)pFrame->data , pFrame->nb_samples);
                fwrite(outBuff, 1, out_buffer_size, outFile);               
            }
        }
        av_free_packet(pPkt);
    }

    ERR_3:
    av_free(outBuff);
    swr_free(&au_convert_ctx);
    ERR_2:
    avformat_close_input(&pFortCtx);
    avcodec_close(pCodecCtx);
    ERR_1:
    avformat_free_context(pFortCtx);
    fclose(outFile);
    return ret;
}

猜你喜欢

转载自blog.csdn.net/u011003120/article/details/81735139