簡體   English   中英

如何為自定義DirectShow h264編碼器創建C#包裝器

[英]How to create a C# wrapper for custom DirectShow h264 encoder

我正在嘗試為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:位於DirectShowLib.ISettingsInterface.GetParameter(字符串類型,Int32緩沖區大小,字符串和值,整數32和長度),位於F:\\ Documents \\ Visual Studio 2010 \\ Projects \\中的ConsoleApplication4.Program.Main(String [] args)中。 ConsoleApplication4 \\ ConsoleApplication4 \\ Program.cs:System.AppDomain._nExecuteAssembly(裝配體,String [] args)位於System.AppDomain.ExecuteAssembly(字符串assemblyFile,證據AssemblySecurity,String [] args)位於Microsoft.VisualStudio.HostingProcess。 System.Threading.ThreadHelper.ThreadStart_Context(對象狀態)處於System.Threading.ExecutionContext.Run(System.Threading.ThreadHelper.ThreadStart()處的HostProc.RunUsersAssembly()狀態)

問題:第一個很明顯-我在做什么錯? ;)其次,.NET封送處理程序或任何其他內容如何知道我是否正確編寫了接口? 它如何知道從原始c ++接口調用哪個函數? 它不能按名稱識別它們(我試圖用一個錯字SetParam代替SetParameter並起作用),但是當我在接口中交換功能順序時它失敗了。

PS我可以附加您想要的任何代碼(或者也可以下載也可以下載它),因為videoprocessing項目是開源的,如directshow.net。 我創建的代碼就在這里。

先感謝您。

編輯:SetParameter確實有效,因為我創建了一個濾鏡攝影機-> h264->解碼器->渲染器,並且僅使用SetParameter(“ quality”,“ ...”)播放; 並且出現了預期的清晰可見的反應。

您使用錯誤的類型來整理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,並且該方法仍返回預期值

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM