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

C# 如何从托管字节[]缓冲区获取字节**,c#,ffmpeg,pinvoke,C#,Ffmpeg,Pinvoke,我已经使用FFmpeg.AutoGen包装器对H264视频进行了一段时间的解码,取得了巨大的成功,现在必须添加AAC音频解码(之前我使用G711和NAudio进行解码) 我有AAC流解码使用avcodec_decode_audio4,但输出缓冲区或帧是浮点格式FLT,我需要它在S16。为此,我找到了使用swr_convert和FFmpeg.AutoGen的非托管示例。AutoGen确实有此函数P/called as [DllImport(SWRESAMPLE_LIBRARY, EntryPoin

我已经使用FFmpeg.AutoGen包装器对H264视频进行了一段时间的解码,取得了巨大的成功,现在必须添加AAC音频解码(之前我使用G711和NAudio进行解码)

我有AAC流解码使用avcodec_decode_audio4,但输出缓冲区或帧是浮点格式FLT,我需要它在S16。为此,我找到了使用swr_convert和FFmpeg.AutoGen的非托管示例。AutoGen确实有此函数P/called 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);
我的问题是,我找不到一种成功的方法将我的托管字节[]转换/修复/强制转换为字节**以将其作为目标缓冲区

以前有人这样做过吗

我的非工作代码

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

此处记录了您尝试调用的函数:

out\u arg
参数如下所示:

uint8_t* out_arg[SWR_CH_MAX]
[MarshalAs(UnmanagedType.LPArray)]
IntPtr[] out_arg
IntPtr[] out_arg = new IntPtr[channelCount];
这是一个字节数组的长度
SWR\u CH\u MAX
数组。您的翻译将其呈现为
字节**
,因此强制您使用不安全的代码。我个人认为我会避免这样做。我将这样声明参数:

uint8_t* out_arg[SWR_CH_MAX]
[MarshalAs(UnmanagedType.LPArray)]
IntPtr[] out_arg
IntPtr[] out_arg = new IntPtr[channelCount];
按如下方式声明数组:

uint8_t* out_arg[SWR_CH_MAX]
[MarshalAs(UnmanagedType.LPArray)]
IntPtr[] out_arg
IntPtr[] out_arg = new IntPtr[channelCount];
我猜
SWR\u CH_MAX
中的
CH
是频道的缩写

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

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

我不会使用您当前使用的自动pinvoke翻译。看来他会强迫你使用指针和不安全的代码。没有多大帮助。我会手工翻译


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

多亏了@david heffernan answer,我成功地完成了以下工作,并且我将此作为一个答案发布,因为管理使用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;
        }
    }
受保护覆盖无效解码数据包(MediaPacket数据包)
{
int frameFinished=0;
AVPacket AVPacket=新的AVPacket();
FFmpegInvoke.av_init_包(ref avPacket);
字节[]有效载荷=数据包有效载荷;
固定(字节*pData=有效负载)
{
avPacket.data=pData;
avPacket.size=packet.Length;
if(数据包关键帧)
{
avPacket.flags |=FFmpegInvoke.AV_PKT_FLAG_键;
}
int in_len=数据包长度;
int count=FFmpegInvoke.avcodec\u decode\u audio4(CodecContext、m\u avFrame、out frameFinished和avPacket);
if(计数!=数据包长度)
{
}
如果(计数<0)
{
抛出新异常(“无法解码帧!”);
}
}
FFmpegInvoke.av_free_包(ref avPacket);
如果(frameFinished>0)
{
如果(!mconversationcontextInitialized)
{
InitialiseConversationContext();
}
packet.ResetBuffer(m_avFrame->nb_samples*4);//需要找到一种更好的方法来获得buff大小
固定(字节*pData=packet.Payload)
{
IntPtr[]in_buffs=新的IntPtr[2];
in_buff[0]=新的IntPtr(m_avFrame->data_0);
in_buff[1]=新的IntPtr(m_avFrame->data_1);
IntPtr[]out_buffs=新的IntPtr[1];
out_buff[0]=新的IntPtr(pData);
swr_convertContext,out_buff,m_avFrame->nb_samples,in_buff,m_avFrame->nb_samples;
}
packet.Type=PacketType.Decoded;
如果(请求)
{
//mRenderQueue.Clear();
packet.Flush=true;
mFlushRequest=false;
}
mFirstFrame=true;
}
}

供参考:在.NET Interop中处理双指针,以防有人发现。嘿,感谢这次更新,它确实帮助了我取得了进展。我同意使用指针并不是最好的方法,一旦一切正常,可能会对我使用的P/Invoke调用进行返工。再次感谢你的帮助