我正在尝试为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
观察:
异常详情:
System.AccessViolationException未处理 Message =尝试读取或写入受保护的内存。这通常表明其他内存已损坏。 来源= DirectShowLib-2005 堆栈跟踪: at DirectShowLib.ISettingsInterface.GetParameter(String type,Int32 buffersize,String& value,Int32& length) 在F:\ Documents \ Visual Studio 2010 \ Projects \ ConsoleApplication4 \ ConsoleApplication4 \ Program.cs中的ConsoleApplication4.Program.Main(String [] args):第79行 在System.AppDomain._nExecuteAssembly(Assembly assembly,String [] args) 在System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence assemblySecurity,String [] args) 在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在System.Threading.ThreadHelper.ThreadStart_Context(对象状态) 在System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,对象状态) 在System.Threading.ThreadHelper.ThreadStart() InnerException:
问题:第一个显而易见的是 - 我做错了什么? ;)其次,如果我正确地编写了接口,.NET编组器或其他任何东西都知道了吗?它如何知道从原始c ++接口调用哪个函数?它不会通过名称识别它们(我试图合并一个拼写错误的SetParam而不是SetParameter并且它有效)但是当我在界面中交换功能顺序时失败了。
PS我可以附加你想要的任何代码(或者你也可以下载下载它),因为视频处理项目是开源的,如directshow.net。我创建的代码都在这里。
提前谢谢。
编辑: SetParameter确实有效,因为我创建了一个过滤器图形相机 - > h264 - >解码器 - >渲染器并仅使用SetParameter(“quality”,“...”)播放;并且存在预期且清晰可见的反应。
答案 0 :(得分:0)
您使用错误的类型来编组GetParameter中的value(3rd)参数。而不是字符串使用StringBuilder。如下所示
[PreserveSig]
int GetParameter(
[MarshalAs(UnmanagedType.LPStr)] String type,
[MarshalAs(UnmanagedType.I4)] int buffersize,
[In, Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder value,
[In, Out, MarshalAs(UnmanagedType.I4)] ref int length);
然后使用它的一个例子是
StringBuilder sb = new StringBuilder();
int len = int.MinValue;
((ISettingsInterface)enc).GetParameter("quality", 0, sb, ref len);
string value = sb.ToString();
不确定buffersize参数的作用,但我可以将其设置为0,方法仍返回预期值