C# 如何从托管字节[]缓冲区获取字节**
我已经使用FFmpeg.AutoGen包装器对H264视频进行了一段时间的解码,取得了巨大的成功,现在必须添加AAC音频解码(之前我使用G711和NAudio进行解码) 我有AAC流解码使用avcodec_decode_audio4,但输出缓冲区或帧是浮点格式FLT,我需要它在S16。为此,我找到了使用swr_convert和FFmpeg.AutoGen的非托管示例。AutoGen确实有此函数P/called asC# 如何从托管字节[]缓冲区获取字节**,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
[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调用进行返工。再次感谢你的帮助