基于ffmpeg重采样、采样精度转换、通道数转换(未测,需要修改部分变量)的例子

论坛 期权论坛 脚本     
匿名网站用户   2020-12-20 10:39   30   0
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
using namespace std;
extern "C"
{
#include "libavformat/avformat.h"  
#include "libavutil/avutil.h"  
#include "libavcodec/avcodec.h"  
#include "libswresample/swresample.h"  
#include "libavutil/frame.h"  
#include "libavutil/samplefmt.h"  
#include "libavformat/avformat.h"  
#include "libavcodec/avcodec.h"  
}

#pragma comment(lib, "avcodec.lib")  
#pragma comment(lib, "avdevice.lib")  
#pragma comment(lib, "avformat.lib")  
#pragma comment(lib, "avutil.lib")  
#pragma comment(lib, "swscale.lib")  
#pragma comment(lib, "swresample.lib")  

uint8_t * out_buf = nullptr;

int AudioResampling(int in_sample_fmt, int in_channels, int in_sample_rate, AVFrame * pAudioDecodeFrame,
 int out_sample_fmt, int out_channels, int out_sample_rate )
{
 //////////////////////////////////////////////////////////////////////////  
 SwrContext * swr_ctx = NULL;
 int data_size = 0;
 int ret = 0;
 int64_t src_ch_layout = AV_CH_LAYOUT_STEREO; //初始化这样根据不同文件做调整  
 int64_t dst_ch_layout = AV_CH_LAYOUT_STEREO; //这里设定ok  
 int dst_nb_channels = 0;
 int dst_linesize = 0;
 int src_nb_samples = 0;
 int dst_nb_samples = 0;
 int max_dst_nb_samples = 0;
 uint8_t **dst_data = NULL;
 int resampled_data_size = 0;

 //重新采样  
 if (swr_ctx)
 {
  swr_free(&swr_ctx);
 }
 swr_ctx = swr_alloc();
 if (!swr_ctx)
 {
  printf("swr_alloc error \n");
  return -1;
 }

 src_ch_layout = AV_CH_LAYOUT_STEREO;
 if (out_channels == 1)
 {
  dst_ch_layout = AV_CH_LAYOUT_MONO;
 }
 else if (out_channels == 2)
 {
  dst_ch_layout = AV_CH_LAYOUT_STEREO;
 }
 else
 {
  //可扩展  
 }

 if (src_ch_layout <= 0)
 {
  printf("src_ch_layout error \n");
  return -1;
 }

 src_nb_samples = pAudioDecodeFrame->nb_samples;
 if (src_nb_samples <= 0)
 {
  printf("src_nb_samples error \n");
  return -1;
 }

 swr_ctx = swr_alloc_set_opts(
  NULL,
  dst_ch_layout,
  (AVSampleFormat)out_sample_fmt,                   //在编码前,我希望的采样格式  
  out_sample_rate,
  src_ch_layout,
  (AVSampleFormat)in_sample_fmt,                      //PCM源文件的采样格式  
  in_sample_rate,
  0, NULL);

 swr_init(swr_ctx);

 max_dst_nb_samples = dst_nb_samples =
  av_rescale_rnd(src_nb_samples, out_sample_rate, in_sample_rate, AV_ROUND_UP);
 if (max_dst_nb_samples <= 0)
 {
  printf("av_rescale_rnd error \n");
  return -1;
 }

 dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
 ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels,
  dst_nb_samples, (AVSampleFormat)out_sample_fmt, 0);
 if (ret < 0)
 {
  printf("av_samples_alloc_array_and_samples error \n");
  return -1;
 }


 dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, in_sample_rate) +
  src_nb_samples, out_sample_rate, in_sample_rate, AV_ROUND_UP);
 if (dst_nb_samples <= 0)
 {
  printf("av_rescale_rnd error \n");
  return -1;
 }
 if (dst_nb_samples > max_dst_nb_samples)
 {
  av_free(dst_data[0]);
  ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels,
   dst_nb_samples, (AVSampleFormat)out_sample_fmt, 1);
  max_dst_nb_samples = dst_nb_samples;
 }

 data_size = av_samples_get_buffer_size(NULL, in_channels,
  pAudioDecodeFrame->nb_samples,
  (AVSampleFormat)in_sample_fmt, 1);
 if (data_size <= 0)
 {
  printf("av_samples_get_buffer_size error \n");
  return -1;
 }
 resampled_data_size = data_size;

 if (swr_ctx)
 {
  ret = swr_convert(swr_ctx, dst_data, dst_nb_samples,
   (const uint8_t **)pAudioDecodeFrame->data, pAudioDecodeFrame->nb_samples);
  if (ret <= 0)
  {
   printf("swr_convert error \n");
   return -1;
  }

  resampled_data_size = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels,
   ret, (AVSampleFormat)out_sample_fmt, 1);
  if (resampled_data_size <= 0)
  {
   printf("av_samples_get_buffer_size error \n");
   return -1;
  }
 }
 else
 {
  printf("swr_ctx null error \n");
  return -1;
 }
 if (!out_buf) {
  out_buf = (uint8_t *)av_malloc(resampled_data_size * sizeof(uint8_t));
 }
 //将值返回去  
 memcpy(out_buf, dst_data[0], resampled_data_size);

 if (dst_data)
 {
  av_freep(&dst_data[0]);
 }
 av_freep(&dst_data);
 dst_data = NULL;

 if (swr_ctx)
 {
  swr_free(&swr_ctx);
 }
 return resampled_data_size;
}


int main() {
 FILE *fp_in;
 FILE *fp_out;
 char filename_in[] = "tdjm.pcm";
 char filename_out[] = "out.pcm";

 AVFrame *pFrame;
 fp_in = fopen(filename_in, "rb");
 if (!fp_in) {
  printf("Could not open %s\n", filename_in);
  return -1;
 }
 
 fp_out = fopen(filename_out, "wb");
 if (!fp_out) {
  printf("Could not open %s\n", filename_out);
  return -1;
 }
 pFrame = av_frame_alloc();
 pFrame->nb_samples = 1024;   //1024  
 pFrame->format = AV_SAMPLE_FMT_S16;
 pFrame->channels = 2;
 int size = av_samples_get_buffer_size(NULL, 2, 1024, AV_SAMPLE_FMT_S16, 0);

 uint8_t*frame_buf = (uint8_t *)av_malloc(size);
 int ret = avcodec_fill_audio_frame(pFrame, 2, AV_SAMPLE_FMT_S16, (const uint8_t*)frame_buf, size, 0);
 for (auto i = 0; i < 5000; i++) 
 {
  if (fread(frame_buf, 1, 4096, fp_in) <= 0) {
   printf("Failed to read raw data! %d \n", i);
   getchar();
   return -1;
  }
  //采样率 44100->8000
  //int out_size = AudioResampling(1, 2, 44100, pFrame, 1, 2, 8000);
  //采样精度 AV_SAMPLE_FMT_S16->AV_SAMPLE_FMT_FLTP
  int out_size = AudioResampling(1, 2, 44100, pFrame, 1, 2, 8000);
  fwrite(out_buf, 1, out_size, fp_out);
 }
 fclose(fp_out);
 fclose(fp_in);
 av_free(out_buf);
 getchar();
 return 0;
}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP