头文件位于 #include <libswresample/swresample.h>
SwrContext经常使用函数以下所示
SwrContext *swr_alloc(void); //建立一个SwrContext,并设置为默认参数
struct SwrContext *swr_alloc_set_opts(struct SwrContext *s, int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,nt64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, int log_offset, void *log_ctx);
//若是第一个参数指向为NULL,则建立一个新的SwrContext,不然对其进行参数配置。
//@param s 要建立的SwrContext ,若是指向NULL,则分配一个新的SwrContext
//@param out_ch_layout output channel layout (AV_CH_LAYOUT_*)
//@param out_sample_fmt output sample format (AV_SAMPLE_FMT_*).
//@param out_sample_rate output sample rate (frequency in Hz)
//@param in_ch_layout input channel layout (AV_CH_LAYOUT_*)
//@param in_sample_fmt input sample format (AV_SAMPLE_FMT_*).
//@param in_sample_rate input sample rate (frequency in Hz)
//@param log_offset logging level offset(日志相关,为NULL便可)
//@param log_ctx parent logging context(日志相关,为NULL便可)
int64_t av_get_default_channel_layout(int nb_channels);
//经过当前通道数返回对应AV_CH_LAYOUT_*枚举值,好比参数为2(2通道),那么返回AV_CH_LAYOUT_STEREO(立体声)
int av_get_channel_layout_nb_channels(uint64_t channel_layout);
//经过AV_CH_LAYOUT_*获取当前有多少通道
int swr_init(struct SwrContext *s);
// 初始化上下文,初始化以前须要配置好SwrContext
//若是初始化好后,还须要修改转换的参数,则调用swr_alloc_set_opts(),而后swr_init()从新初始化
void swr_free(struct SwrContext **s); // 释放上下文空间,而且设置*s为NULL
int swr_convert(struct SwrContext *s, uint8_t **out, int out_count, const uint8_t **in , int in_count);
//音频重采样转换
// s : 初始化好的SwrContext
//out : 输出缓冲区,对于packet,都存在out[0]中,对于planar,好比AV_CH_LAYOUT_STEREO,那么out[0]存L,out[1]存R
//out_count : 输出缓冲区每通道样本数据数量(对于音频,每一个通道数据长度都相同),注意这里不是以字节为单位.
//in :输入缓冲区,这里填入frame->data便可
//in_count :输入缓冲区每通道数据数量,这里填入frame->nb_samples便可
//返回值:转换成功后每一个通道的输出样本数,出错则为负值
音频解码并重采样示例html
void debugErr(QString prefix, int err) //根据错误编号获取错误信息并打印
{
char errbuf[512]={0};
av_strerror(err,errbuf,sizeof(errbuf));
cout<<prefix<<":"<<errbuf<<endl;
}
void runAudioPlay()
{
int ret;
avformat_network_init(); //初始化网络库 (能够打开rtsp rtmp http 协议的流媒体视频)
AVFormatContext *pFmtCtx=NULL;
ret = avformat_open_input(&pFmtCtx,filePath,NULL, NULL) ; //打开音视频文件并建立AVFormatContext结构体以及初始化.
if (ret!= 0)
{
debugErr("avformat_open_input",ret);
return ;
}
ret = avformat_find_stream_info(pFmtCtx, NULL); //初始化流信息
if (ret!= 0)
{
debugErr("avformat_find_stream_info",ret);
return ;
}
int audioindex=-1;
audioindex = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
qDebug()<<"audioindex:"<<audioindex;
AVCodec *acodec = avcodec_find_decoder(pFmtCtx->streams[audioindex]->codecpar->codec_id);//获取codec
AVCodecContext *acodecCtx = avcodec_alloc_context3(acodec); //构造AVCodecContext ,并将vcodec填入AVCodecContext中
avcodec_parameters_to_context(acodecCtx, pFmtCtx->streams[audioindex]->codecpar); //初始化AVCodecContext
ret = avcodec_open2(acodecCtx, NULL,NULL);
//打开解码器,因为以前调用avcodec_alloc_context3(acodec)初始化了解码器,那么codec(第2个参数)能够填NULL
if (ret!= 0)
{
debugErr("avcodec_open2",ret);
return ;
}
SwrContext *swrctx =NULL;
swrctx=swr_alloc_set_opts(swrctx, av_get_default_channel_layout(2),AV_SAMPLE_FMT_S16,44100,
acodecCtx->channel_layout, acodecCtx->sample_fmt,acodecCtx->sample_rate, NULL,NULL);
swr_init(swrctx);
while(1)
{
ret = av_read_frame(pFmtCtx, packet);
if (ret!= 0)
{
debugErr("av_read_frame",ret);
break ;
}
//解码一帧数据
ret = avcodec_send_packet(acodecCtx, packet);
av_packet_unref(packet);
if (ret != 0)
{
debugErr("avcodec_send_packet",ret);
continue ;
}
if(packet->stream_index==audioindex) //判断是音频流
{
while( avcodec_receive_frame(acodecCtx, frame) == 0)
{
uint8_t *data[2] = { 0 };
int byteCnt=frame->nb_samples * 2 * 2;
unsigned char *pcm = new uint8_t[byteCnt];
//frame->nb_samples*2*2表示分配样本数据量*两通道*每通道2字节大小
data[0] = pcm; //输出格式为AV_SAMPLE_FMT_S16(packet类型),因此转换后的LR两通道都存在data[0]中
ret = swr_convert(swrctx,
data, frame->nb_samples, //输出
(const uint8_t**)frame->data,frame->nb_samples ); //输入
//将重采样后的data数据发送到输出设备,进行播放
... ...
delete[] pcm; //最后delete pcm
}
}
}
//释放
av_frame_free(&frame);
av_packet_free(&packet);
swr_free(&swrctx);
avcodec_free_context(&acodecCtx);
avformat_close_input(&pFmtCtx);
}