如何从托管字节[]缓冲区中获取字节**

本文关键字:字节 缓冲区 获取 | 更新日期: 2023-09-27 17:58:17

我一直在使用FFmpeg.AutoGenhttps://github.com/Ruslan-B/FFmpeg.AutoGen包装器解码我的H264视频有一段时间非常成功,现在必须添加AAC音频解码(以前我使用G711和NAudio)。

我使用avcodec_decode_audio4进行AAC流解码,但是输出缓冲器或帧是浮点格式FLT,我需要它在S16中。为此,我发现了使用swr_convert和FFmpeg的非托管示例。AutoGen确实具有此函数P/Invoked as;

[DllImport(SWRESAMPLE_LIBRARY, EntryPoint="swr_convert", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int swr_convert(SwrContext* s, byte** @out, int out_count, byte** @in, int in_count);

我的问题是,我找不到一种成功的方法来将托管的byte[]转换/修复/强制转换为byte**,以将其作为目标缓冲区。

以前有人这样做过吗?

我的非工作代码。。。

packet.ResetBuffer(m_avFrame->linesize[0]*2);
fixed (byte* pData = packet.Payload)
{
    byte** src = &m_avFrame->data_0;
    //byte** dst = *pData;
    IntPtr d = new IntPtr(pData);
    FFmpegInvoke.swr_convert(m_pConvertContext, (byte**)d.ToPointer(), packet.Length, src, (int)m_avFrame->linesize[0]);
}

谢谢你的帮助。

干杯

Dave

如何从托管字节[]缓冲区中获取字节**

您试图调用的函数记录在这里:http://www.ffmpeg.org/doxygen/2.0/swresample_8c.html#a81af226d8969df314222218c56396f6a

out_arg参数声明如下:

uint8_t* out_arg[SWR_CH_MAX]

这是字节数组的长度为SWR_CH_MAX的数组。您的翻译将其呈现为byte**,因此迫使您使用不安全的代码。就我个人而言,我认为我会避免这种情况。我会这样声明参数:

[MarshalAs(UnmanagedType.LPArray)]
IntPtr[] out_arg

像这样声明数组:

IntPtr[] out_arg = new IntPtr[channelCount];

我猜SWR_CH_MAX中的CH对于通道来说是人手不足的。

然后您需要为输出缓冲区分配内存。我不知道你想怎么做。您可以为每个通道分配一个字节数组,并固定这些数组以获得一个指针,从而传递给本机代码。这将是我的首选方法,因为在返回时,您的通道将位于良好的托管阵列中。另一种方式是调用Marshal.AllocHGlobal

输入缓冲区需要以相同的方式进行处理。

我不会使用你目前使用的自动拼音翻译。他似乎会强迫你使用指针和不安全的代码。没有太大帮助。我会亲手翻译。

很抱歉没有提供更多具体的细节,但这有点困难,因为您的问题没有包含任何关于代码示例中使用的类型的信息。我希望一般性的建议是有用的。

感谢@david heffernan的回答,我成功地完成了以下工作,我将作为回答发布,因为管理使用FFmpeg的例子非常罕见。

fixed (byte* pData = packet.Payload)
{
    IntPtr[] in_buffs = new IntPtr[2];
    in_buffs[0] = new IntPtr(m_avFrame->data_0);
    in_buffs[1] = new IntPtr(m_avFrame->data_1);
    IntPtr[] out_buffs = new IntPtr[1];
    out_buffs[0] = new IntPtr(pData);
    FFmpegInvoke.swr_convert(m_pConvertContext, out_buffs, m_avFrame->nb_samples, in_buffs, m_avFrame->nb_samples);
}

在解码AAC音频缓冲区的完整上下文中。。。

    protected override void DecodePacket(MediaPacket packet)
    {
        int frameFinished = 0;

        AVPacket avPacket = new AVPacket();
        FFmpegInvoke.av_init_packet(ref avPacket);
        byte[] payload = packet.Payload;
        fixed (byte* pData = payload)
        {
            avPacket.data = pData;
            avPacket.size = packet.Length;
            if (packet.KeyFrame)
            {
                avPacket.flags |= FFmpegInvoke.AV_PKT_FLAG_KEY;
            }
            int in_len = packet.Length;

            int count = FFmpegInvoke.avcodec_decode_audio4(CodecContext, m_avFrame, out frameFinished, &avPacket);
            if (count != packet.Length)
            {
            }
            if (count < 0)
            {
                throw new Exception("Can't decode frame!");
            }
        }
        FFmpegInvoke.av_free_packet(ref avPacket);
        if (frameFinished > 0)
        {
            if (!mConverstionContextInitialised)
            {
                InitialiseConverstionContext();
            }
            packet.ResetBuffer(m_avFrame->nb_samples*4); // need to find a better way of getting the out buff size
            fixed (byte* pData = packet.Payload)
            {
                IntPtr[] in_buffs = new IntPtr[2];
                in_buffs[0] = new IntPtr(m_avFrame->data_0);
                in_buffs[1] = new IntPtr(m_avFrame->data_1);
                IntPtr[] out_buffs = new IntPtr[1];
                out_buffs[0] = new IntPtr(pData);
                FFmpegInvoke.swr_convert(m_pConvertContext, out_buffs, m_avFrame->nb_samples, in_buffs, m_avFrame->nb_samples);
            }
            packet.Type = PacketType.Decoded;
            if (mFlushRequest)
            {
                //mRenderQueue.Clear();
                packet.Flush = true;
                mFlushRequest = false;
            }
            mFirstFrame = true;
        }
    }