ffmpeg 声音的重采样

目的:改变pcm的采样率,通道数,每一个采样bit数code

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;
        
    /// <summary>
    /// 初始化重采样
    /// </summary>
    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;
    }
    /// <summary>
    /// 重采样
    /// </summary>
    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;
        }
    }
}