7.SwrContext音频重采样使用
阅读原文时间:2023年07月09日阅读:2

头文件位于#include

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即可
//返回值:转换成功后每个通道的输出样本数,出错则为负值

音频解码并重采样示例

void debugErr(QString prefix, int err) //根据错误编号获取错误信息并打印
{
char errbuf[]={};

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!= )
{
debugErr("avformat_open_input",ret);
return ;
}
ret = avformat_find_stream_info(pFmtCtx, NULL); //初始化流信息
if (ret!= )
{
debugErr("avformat_find_stream_info",ret);
return ;
}

int audioindex=-;  
audioindex = av\_find\_best\_stream(pFmtCtx, AVMEDIA\_TYPE\_AUDIO, -, -, NULL, );

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!= )  
{  
    debugErr("avcodec\_open2",ret);  
    return ;  
}

SwrContext \*swrctx =NULL;  
swrctx=swr\_alloc\_set\_opts(swrctx, av\_get\_default\_channel\_layout(),AV\_SAMPLE\_FMT\_S16,,  
                          acodecCtx->channel\_layout, acodecCtx->sample\_fmt,acodecCtx->sample\_rate, NULL,NULL);  

      
swr_init(swrctx);

while()  
{  
  ret = av\_read\_frame(pFmtCtx, packet);  
  if (ret!= )  
  {  
     debugErr("av\_read\_frame",ret);  
     break ;  
  }  
  //解码一帧数据  
  ret = avcodec\_send\_packet(acodecCtx, packet);  
  av\_packet\_unref(packet);  
  if (ret != )  
  {  
    debugErr("avcodec\_send\_packet",ret);  
    continue ;  
  }

  if(packet->stream\_index==audioindex)    //判断是音频流  
  {  
   while( avcodec\_receive\_frame(acodecCtx, frame) == )  
   {  
     uint8\_t \*data\[\] = {  };  
     int byteCnt=frame->nb\_samples \*  \* ;  
     unsigned char \*pcm = new uint8\_t\[byteCnt\];  
          //frame->nb\_samples\*2\*2表示分配样本数据量\*两通道\*每通道2字节大小

     data\[\] = 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);  

}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器