zoukankan      html  css  js  c++  java
  • 7.SwrContext音频重采样使用

    头文件位于 #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);
    }
  • 相关阅读:
    微信公众平台回复音乐
    Else is very important
    Generate source code from wsdl
    PHP Simple HTML DOM Parser: check elements with multiple classes
    Get Version is the first function is called?
    Remote debug GWT UI
    Remote Debug For Java Application On Tomcat
    SetStyleName引起的Regression Issue
    做乘法运算的时候需要考虑越界问题
    MySQL Uniall All
  • 原文地址:https://www.cnblogs.com/lidabo/p/15825784.html
Copyright © 2011-2022 走看看