如何从托管字节[]缓冲区中获取字节**
本文关键字:字节 缓冲区 获取 | 更新日期: 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;
}
}