ffmpeg实现音频resample(重采样)

AVFifoBuffer和音频样本是av_sample_fmt_is_planar的样式采样率讲解,下面上代码

[cpp] view plain copy

  1. AVFifoBuffer * m_fifo = NULL;  
  2.   
  3.   
  4.   
  5. SwrContext * init_pcm_resample(AVFrame *in_frame, AVFrame *out_frame)  
  6. {  
  7.     SwrContext * swr_ctx = NULL;  
  8.     swr_ctx = swr_alloc();  
  9.     if (!swr_ctx)  
  10.     {  
  11.         printf("swr_alloc error \n");  
  12.         return NULL;  
  13.     }  
  14.     AVCodecContext * audio_dec_ctx = icodec->streams[audio_stream_idx]->codec;  
  15.     AVSampleFormat sample_fmt;  
  16.     sample_fmt = (AVSampleFormat)m_dwBitsPerSample; //样本  
  17.     if (audio_dec_ctx->channel_layout == 0)  
  18.     {  
  19.         audio_dec_ctx->channel_layout = av_get_default_channel_layout(icodec->streams[audio_stream_idx]->codec->channels);  
  20.     }  
  21.     /* set options */  
  22.     av_opt_set_int(swr_ctx, "in_channel_layout",    audio_dec_ctx->channel_layout, 0);  
  23.     av_opt_set_int(swr_ctx, "in_sample_rate",       audio_dec_ctx->sample_rate, 0);  
  24.     av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", audio_dec_ctx->sample_fmt, 0);  
  25.   
  26.     av_opt_set_int(swr_ctx, "out_channel_layout",    audio_dec_ctx->channel_layout, 0);  
  27.     av_opt_set_int(swr_ctx, "out_sample_rate",       audio_dec_ctx->sample_rate, 0);  
  28.     av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", sample_fmt, 0);  
  29.     swr_init(swr_ctx);  
  30.   
  31.     int64_t src_nb_samples = in_frame->nb_samples;  
  32.     out_frame->nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx,oaudio_st->codec->sample_rate) + src_nb_samples,  
  33.         oaudio_st->codec->sample_rate, oaudio_st->codec->sample_rate, AV_ROUND_UP);  
  34.   
  35.     int ret = av_samples_alloc(out_frame->data, &out_frame->linesize[0],   
  36.         icodec->streams[audio_stream_idx]->codec->channels, out_frame->nb_samples,oaudio_st->codec->sample_fmt,1);  
  37.     if (ret < 0)  
  38.     {  
  39.         return NULL;  
  40.     }  
  41.   
  42.     //pcm分包初始化  
  43.     int buffersize = av_samples_get_buffer_size(NULL, oaudio_st->codec->channels,  
  44.         2048, oaudio_st->codec->sample_fmt, 1);  
  45.     m_fifo = av_fifo_alloc(buffersize);  
  46.     return swr_ctx;  
  47. }  
  48.   
  49. int preform_pcm_resample(SwrContext * pSwrCtx,AVFrame *in_frame, AVFrame *out_frame)  
  50. {  
  51.     int ret = 0;  
  52.     if (pSwrCtx != NULL)   
  53.     {  
  54.         ret = swr_convert(pSwrCtx, out_frame->data, out_frame->nb_samples,   
  55.             (const uint8_t**)in_frame->data, in_frame->nb_samples);  
  56.         if (ret < 0)  
  57.         {  
  58.             return -1;  
  59.         }  
  60.         //修改分包内存  
  61.         int buffersize = av_samples_get_buffer_size(&out_frame->linesize[0], oaudio_st->codec->channels,  
  62.             ret, oaudio_st->codec->sample_fmt, 1);  
  63.         int sss = av_fifo_size(m_fifo);  
  64.         sss = av_fifo_realloc2(m_fifo, av_fifo_size(m_fifo) + out_frame->linesize[0]);  
  65.         sss = av_fifo_size(m_fifo);  
  66.         av_fifo_generic_write(m_fifo, out_frame->data[0], out_frame->linesize[0], NULL);  
  67.   
  68.         out_frame->pkt_pts = in_frame->pkt_pts;  
  69.         out_frame->pkt_dts = in_frame->pkt_dts;  
  70.         //有时pkt_pts和pkt_dts不同,并且pkt_pts是编码前的dts,这里要给avframe传入pkt_dts而不能用pkt_pts  
  71.         //out_frame->pts = out_frame->pkt_pts;  
  72.         out_frame->pts = in_frame->pkt_dts;  
  73.     }  
  74.     return 0;  
  75. }  
  76. void uinit_pcm_resample(AVFrame * poutframe,SwrContext * swr_ctx)  
  77. {  
  78.     if (poutframe)  
  79.     {  
  80.         avcodec_free_frame(&poutframe);  
  81.         poutframe = NULL;  
  82.     }  
  83.     if (swr_ctx)  
  84.     {  
  85.         swr_free(&swr_ctx);  
  86.         swr_ctx = NULL;  
  87.     }  
  88.     //析构pcm分包结构  
  89.     if(m_fifo)  
  90.     {  
  91.         av_fifo_free(m_fifo);  
  92.         m_fifo = NULL;  
  93.     }  
  94. }  
  95. int perform_code(int stream_type,AVFrame * picture)  
  96. {  
  97.     AVCodecContext *cctext = NULL;  
  98.     AVPacket pkt_t;  
  99.     av_init_packet(&pkt_t);  
  100.     pkt_t.data = NULL; // packet data will be allocated by the encoder  
  101.     pkt_t.size = 0;  
  102.     int frameFinished = 0 ;  
  103.   
  104.     if (stream_type == AUDIO_ID)  
  105.     {  
  106.         cctext = oaudio_st->codec;  
  107.         //如果进和出的的声道,样本,采样率不同,需要重采样  
  108.         if(icodec->streams[audio_stream_idx]->codec->sample_fmt != (AVSampleFormat)m_dwBitsPerSample ||  
  109.             icodec->streams[audio_stream_idx]->codec->channels != m_dwChannelCount ||  
  110.             icodec->streams[audio_stream_idx]->codec->sample_rate != m_dwFrequency)  
  111.         {  
  112.             int64_t pts_t = picture->pts;  
  113.             int duration_t = (double)cctext->frame_size * (icodec->streams[audio_stream_idx]->time_base.den /icodec->streams[audio_stream_idx]->time_base.num)/   
  114.                 icodec->streams[audio_stream_idx]->codec->sample_rate;  
  115.   
  116.             int frame_bytes = cctext->frame_size * av_get_bytes_per_sample(cctext->sample_fmt)* cctext->channels;  
  117.             AVFrame * pFrameResample = avcodec_alloc_frame();  
  118.             uint8_t * readbuff = new uint8_t[frame_bytes];  
  119.   
  120.             if(av_sample_fmt_is_planar(cctext->sample_fmt))  
  121.             {  
  122.                 frame_bytes /= cctext->channels;  
  123.             }  
  124.   
  125.             while (av_fifo_size(m_fifo) >= frame_bytes) //取出写入的未读的包  
  126.             {  
  127.                 pFrameResample->nb_samples = cctext->frame_size;  
  128.                 av_fifo_generic_read(m_fifo, readbuff, frame_bytes, NULL);  
  129.   
  130.                 //这里一定要考虑音频分片的问题  
  131.                 //如果是分片的avcodec_fill_audio_frame传入的buf是单声道的,但是buf_size 是两个声道加一起的数据量  
  132.                 //如果不是分片的avcodec_fill_audio_frame传入的buf是双声道的,buf_size 是两个声道加一起的数据量  
  133.                 if(av_sample_fmt_is_planar(cctext->sample_fmt))  
  134.                 {  
  135.                     avcodec_fill_audio_frame(pFrameResample,cctext->channels,cctext->sample_fmt,readbuff,frame_bytes * cctext->channels,1);  
  136.                 }  
  137.                 else  
  138.                 {                     
  139.                     avcodec_fill_audio_frame(pFrameResample,cctext->channels,cctext->sample_fmt,readbuff,frame_bytes,0);  
  140.                 }  
  141.   
  142.                 if(m_is_first_audio_pts == 0)  
  143.                 {  
  144.                     m_first_audio_pts = pts_t;  
  145.                     m_is_first_audio_pts = 1;  
  146.                 }  
  147.                 pFrameResample->pts = m_first_audio_pts;  
  148.                 m_first_audio_pts += duration_t;  
  149.   
  150.   
  151.                 pFrameResample->pts = av_rescale_q_rnd(pFrameResample->pts, icodec->streams[audio_stream_idx]->codec->time_base, oaudio_st->codec->time_base, AV_ROUND_NEAR_INF);  
  152.                 nRet = avcodec_encode_audio2(cctext,&pkt_t,pFrameResample,&frameFinished);  
  153.                 if (nRet>=0 && frameFinished)  
  154.                 {  
  155.                     write_frame(ocodec,AUDIO_ID,pkt_t);  
  156.                     av_free_packet(&pkt_t);  
  157.                 }  
  158.             }  
  159.             if (readbuff)  
  160.             {  
  161.                 delete []readbuff;  
  162.             }  
  163.             if (pFrameResample)  
  164.             {  
  165.                 av_free(pFrameResample);  
  166.                 pFrameResample = NULL;  
  167.             }  
  168.         }  
  169.         else  
  170.         {  
  171.             nRet = avcodec_encode_audio2(cctext,&pkt_t,picture,&frameFinished);  
  172.             if (nRet>=0 && frameFinished)  
  173.             {  
  174.                 write_frame(ocodec,AUDIO_ID,pkt_t);  
  175.                 av_free_packet(&pkt_t);  
  176.             }  
  177.         }  
  178.     }  
  179.     else if (stream_type == VIDEO_ID)  
  180.     {  
  181.         cctext = ovideo_st->codec;  
  182.         if(icodec->streams[video_stream_idx]->codec->ticks_per_frame != 1)  
  183.         {  
  184.             AVRational time_base_video_t;  
  185.             time_base_video_t.num = icodec->streams[video_stream_idx]->codec->time_base.num;  
  186.             time_base_video_t.den = icodec->streams[video_stream_idx]->codec->time_base.den /icodec->streams[video_stream_idx]->codec->ticks_per_frame;  
  187.             picture->pts = av_rescale_q_rnd(picture->pts, time_base_video_t, ovideo_st->codec->time_base, AV_ROUND_NEAR_INF);  
  188.         }  
  189.         else  
  190.         {  
  191.             picture->pts = av_rescale_q_rnd(picture->pts, icodec->streams[video_stream_idx]->codec->time_base, ovideo_st->codec->time_base, AV_ROUND_NEAR_INF);  
  192.         }  
  193.         avcodec_encode_video2(cctext,&pkt_t,picture,&frameFinished);  
  194.         picture->pts++;  
  195.         if (frameFinished)  
  196.         {  
  197.             write_frame(ocodec,VIDEO_ID,pkt_t);  
  198.             av_free_packet(&pkt_t);  
  199.         }  
  200.     }  
  201.     return 1;  
  202. }  

1:由于mp3的sample是1152 aac是1024 有时候将解码的mp3编码成aac时如果不做AVFifoBuffer操作,编码的aac音频sample会比原来的少很多,生成的音频会一卡一卡的明显少声音。

2:当要编码的音频样本是av_sample_fmt_is_planar分片的时候需要将解码后的视频添加到AVFrame结构体中:但是如图

猜你喜欢

转载自blog.csdn.net/qq_21743659/article/details/107856846