1. 程式人生 > >基於ffmpeg重取樣、取樣精度轉換、通道數轉換(未測,需要修改部分變數)的例子

基於ffmpeg重取樣、取樣精度轉換、通道數轉換(未測,需要修改部分變數)的例子

#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;
}