我正在尝试为 h264 编码器创建一些基本的 C# 包装器。我正在使用 Directshow.NET 和一些自定义 H264 编码器。编码器 directshow 过滤器是视频处理项目http://sourceforge.net/projects/videoprocessing/ 的一部分 过滤器类 (H264EncoderFilter) 继承了 ISettingsInterface:
//For Smart pointers
DEFINE_GUID( IID_ISettingsInterface, /* 388EEF20-40CC-4752-A0FF-66AA5C4AF8FA */
0x388eef20,
0x40cc,
0x4752,
0xa0, 0xff, 0x66, 0xaa, 0x5c, 0x4a, 0xf8, 0xfa
);
#undef INTERFACE
#define INTERFACE ISettingsInterface
DECLARE_INTERFACE_( ISettingsInterface, IUnknown )
{
// *** methods ***
/// Method to retrieve parameters named type. The result will be stored in value and the length of the result in length
STDMETHOD(GetParameter)( const char* type, int buffersize, char* value, int* length ) = 0;
/// Method to set parameter named type to value
STDMETHOD(SetParameter)( const char* type, const char* value) = 0;
/// Method to retrieve ALL parameters in szResult. nSize should contain the size of the buffer passed in
STDMETHOD(GetParameterSettings)(char* szResult, int nSize) = 0;
};
我为过滤器本身创建了一个包装器(在 Directshow.NET lib 的 Uuids.cs 中,作为记录):
[ComImport, Guid("28D61FDF-2646-422D-834C-EFFF45884A36")]
public class H264Encoder
{
}
有了它,我可以在 C# 中实例化过滤器类,并且我可以在 IBaseFilter 接口上强制转换过滤器,所以我猜这个包装器可以工作。
接下来,我想为前面提到的 ISettingsInterface 创建一个包装器(我将以下代码添加到 AxCore.cs):
[ComImport, System.Security.SuppressUnmanagedCodeSecurity,
Guid("388EEF20-40CC-4752-A0FF-66AA5C4AF8FA"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ISettingsInterface
{
[PreserveSig]
int GetParameter(
[MarshalAs(UnmanagedType.LPStr)] String type,
[MarshalAs(UnmanagedType.I4)] int buffersize,
[In, Out, MarshalAs(UnmanagedType.LPStr)] String value,
[In, Out, MarshalAs(UnmanagedType.I4)] ref int length
);
[PreserveSig]
int SetParameter(
[MarshalAs(UnmanagedType.LPStr)] String type,
[MarshalAs(UnmanagedType.LPStr)] String value
);
[PreserveSig]
int GetParameterSettings(
[MarshalAs(UnmanagedType.LPStr)] ref String szResult,
[In] int nSize
);
}
这给我们带来了我的问题。当我尝试使用该界面时,并非一切正常。当我使用 SetParameter 函数时,它似乎表现得很好(返回的 Hresult 为 0),但是当我使用 GetParameter 时发生了错误。请查看测试代码及其控制台输出:
object enc = new H264Encoder();
ISettingsInterface enc_settings = enc as ISettingsInterface;
String szParamValue= "initinitinitinit";
unsafe //Write address od szParamValue
{
fixed (char* wsk = szParamValue)
{
IntPtr ptr = (IntPtr)wsk;
Console.WriteLine("adres: " + ptr.ToInt64());
}
}
int nLength=0;
int hr = enc_settings.SetParameter("quality", "15"); //set quality to some arbitrary value
hr = enc_settings.GetParameter("quality", 16, ref szParamValue, ref nLength);
Console.WriteLine("szParamValue: " + szParamValue);
Console.WriteLine("nLength: " + nLength);
Console.WriteLine("HRESULT: " + hr);
Console.WriteLine(DsError.GetErrorText(hr));
Marshal.ReleaseComObject(enc_settings);
Marshal.ReleaseComObject(enc);
unsafe //Write address od szParamValue
{
fixed (char* wsk = szParamValue)
{
IntPtr ptr = (IntPtr)wsk;
Console.WriteLine("adres: " + ptr.ToInt64());
}
}
控制台输出:http: //img707.imageshack.us/img707/3667/consolevd.png
观察:
- szParamValue 应该是一个包含“15”的字符串,因为它是由 SetParameter 设置的。相反,这是一团糟。
- nLength 是 SetParameter 中包含的字符串的长度,这是正确的,因为预期的“15”长度为 2。当质量设置为例如“151”时,它变为 3
- szParamValue 并不总是如此混乱,有时它是一个空字符串或一些 XML 代码......而且,更重要的是,AccessViolationException 与 GetParameter 调用一致。下面附上异常详情。
- 内存更改中的地址 od szParamValue,如您在控制台输出中所见。
异常详情:
System.AccessViolationException 未处理 Message=尝试读取或写入受保护的内存。这通常表明其他内存已损坏。Source=DirectShowLib-2005 StackTrace:在 F:\Documents\Visual Studio 2010\Projects\ 中 ConsoleApplication4.Program.Main(String[] args) 的 DirectShowLib.ISettingsInterface.GetParameter(String type, Int32 buffersize, String& value, Int32& length) ConsoleApplication4\ConsoleApplication4\Program.cs:位于 Microsoft.VisualStudio.HostingProcess 的 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 中 System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) 的第 79 行。 System.Threading 的 System.Threading.ThreadHelper.ThreadStart_Context(Object state) 的 HostProc.RunUsersAssembly()。
问题:第一个很明显——我做错了什么?;) 其次,.NET marshaler 或任何东西如何知道我是否正确编写了接口?它如何知道从原始 c++ 接口调用哪个函数?它不能通过名称识别它们(我尝试使用拼写错误 SetParam 而不是 SetParameter 并且它有效)但是当我在界面中交换函数顺序时它失败了。
PS我可以附上你想要的任何代码(或者你可以下载也可以下载它)因为视频处理项目是开源的,如directshow.net。我创建的代码都在这里。
先感谢您。
编辑: SetParameter 确实有效,因为我创建了一个过滤器图形相机 -> h264 -> 解码器 -> 渲染器并且只使用 SetParameter("quality", "..."); 并且出现了预期的和清晰可见的反应。