目的:改变pcm的采样率,通道数,每个采样bit数
public unsafe class AudioResample
{
private SwrContext* m_swr_ctx = null;
private byte** m_dst_data = null;
long m_max_dst_nb_samples = 0;
int m_dst_linesize = 0;
private int m_src_channel_layout = 0;
private int m_src_sample_rate = 0;
private AVSampleFormat m_src_sample_fmt = 0;
private int m_dst_channel_layout = 0;
private int m_dst_sample_rate = 0;
private AVSampleFormat m_dst_sample_fmt;
///
/// 初始化重采样
///
public int ARInit(int src_channel_layout, int src_sample_rate, AVSampleFormat src_sample_fmt,
int dst_channel_layout, int dst_sample_rate, AVSampleFormat dst_sample_fmt,
int data_delay = 20)
{
if (m_swr_ctx != null)
return -1;
int ret = 0;
int dst_audio_channels;
long src_nb_samples = src_sample_rate / data_delay, dst_nb_samples;
m_swr_ctx = ffmpeg.swr_alloc();
ffmpeg.av_opt_set_int(m_swr_ctx, "in_channel_layout", (long)src_channel_layout, 0);
ffmpeg.av_opt_set_int(m_swr_ctx, "in_sample_rate", src_sample_rate, 0);
ffmpeg.av_opt_set_sample_fmt(m_swr_ctx, "in_sample_fmt", src_sample_fmt, 0);
ffmpeg.av_opt_set_int(m_swr_ctx, "out_channel_layout", (long)dst_channel_layout, 0);
ffmpeg.av_opt_set_int(m_swr_ctx, "out_sample_rate", dst_sample_rate, 0);
ffmpeg.av_opt_set_sample_fmt(m_swr_ctx, "out_sample_fmt", dst_sample_fmt, 0);
if (ffmpeg.swr_init(m_swr_ctx) < 0)
{
goto fail;
}
m_max_dst_nb_samples = dst_nb_samples =
ffmpeg.av_rescale_rnd(src_nb_samples, dst_sample_rate, src_sample_rate, AVRounding.AV_ROUND_UP);
dst_audio_channels = ffmpeg.av_get_channel_layout_nb_channels((ulong)dst_channel_layout);
fixed(byte*** dst_data = &m_dst_data)
fixed(int *dst_linesize = &m_dst_linesize)
ret = ffmpeg.av_samples_alloc_array_and_samples(dst_data, dst_linesize, dst_audio_channels,
(int)dst_nb_samples, dst_sample_fmt, 0);
m_src_channel_layout = src_channel_layout;
m_dst_channel_layout = dst_channel_layout;
m_src_sample_rate = src_sample_rate;
m_dst_sample_rate = dst_sample_rate;
m_src_sample_fmt = src_sample_fmt;
m_dst_sample_fmt = dst_sample_fmt;
return 0;
fail:
ARDeinit();
return -1;
}
///
/// 重采样
///
public byte[] ARConvert(byte* src_data, int src_data_len)
{
int ret = 0;
int dst_data_len = 0;
byte* out_data;
ret = ARConvert(src_data, src_data_len, &out_data, ref dst_data_len);
if (ret < 0)
return null;
byte[] convert_data = new byte[dst_data_len];
Marshal.Copy((IntPtr)(*m_dst_data), convert_data, 0, convert_data.Length);
return convert_data;
}
public int ARConvert(byte* src_data, int src_data_len, byte** out_data, ref int out_len)
{
int ret;
int dst_data_samples, src_data_sample;
int dst_audio_channels;
int dst_data_len;
int src_audio_channels = ffmpeg.av_get_channel_layout_nb_channels((ulong)m_src_channel_layout);
src_data_sample = src_data_len / src_audio_channels;
if (m_src_sample_fmt == AVSampleFormat.AV_SAMPLE_FMT_S16)
src_data_sample = src_data_sample / 2;
fixed (int* dst_linesize = &m_dst_linesize)
{
dst_data_samples = (int)ffmpeg.av_rescale_rnd(ffmpeg.swr_get_delay(m_swr_ctx, (long)m_src_sample_rate) + (long)src_data_sample,
(long)m_dst_sample_rate, (long)m_src_sample_rate, AVRounding.AV_ROUND_UP);
dst_audio_channels = ffmpeg.av_get_channel_layout_nb_channels((ulong)m_dst_channel_layout);
if (dst_data_samples > m_max_dst_nb_samples)
{
ffmpeg.av_freep(&m_dst_data[0]);
ret = ffmpeg.av_samples_alloc(m_dst_data, dst_linesize, dst_audio_channels,
(int)dst_data_samples, m_dst_sample_fmt, 1);
if (ret < 0)
{
m_max_dst_nb_samples = 0;
return -1;
}
m_max_dst_nb_samples = dst_data_samples;
}
/* convert to destination format */
ret = ffmpeg.swr_convert(m_swr_ctx, m_dst_data, (int)dst_data_samples, (byte**)&src_data, (int)src_data_sample);
if (ret < 0)
{
return -1;
}
dst_data_len = ffmpeg.av_samples_get_buffer_size(dst_linesize, dst_audio_channels,
ret, m_dst_sample_fmt, 1);
out_len = dst_data_len;
*out_data = *m_dst_data;
return 0;
}
}
public void ARDeinit()
{
if(m_swr_ctx != null)
{
fixed (SwrContext** swr_ctx = &m_swr_ctx)
ffmpeg.swr_free(swr_ctx);
m_swr_ctx = null;
}
if(m_dst_data != null)
{
ffmpeg.av_freep(&m_dst_data[0]);
m_dst_data = null;
}
}
}