版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}