Как создать оболочку C# для пользовательского кодировщика DirectShow h264

Я пытаюсь создать базовую оболочку С# для кодировщика h264. Я использую Directshow.NET и какой-то пользовательский кодировщик H264. Фильтр прямого показа кодировщика является частью проекта обработки видео 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;

};

Я создал оболочку для самого фильтра (в Uuids.cs библиотеки Directshow.NET, для записи):

[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. Она изменяется на 3, когда качество установлено, например, на «151».
  • szParamValue не всегда такая каша, иногда это пустая строка или какой-то XML-код... И, что более важно, AccessViolationException выбрасывается в линию с вызовом GetParameter. Детали исключения приложены ниже.
  • Адрес od szParamValue в памяти изменяется, как видно из вывода консоли.

Детали исключения:

System.AccessViolationException не было обработано. Сообщение = Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена. Source=DirectShowLib-2005 StackTrace: в DirectShowLib.ISettingsInterface.GetParameter(тип строки, размер буфера Int32, строка и значение, Int32& длина) в ConsoleApplication4.Program.Main(String[] args) в F:\Documents\Visual Studio 2010\Projects\ ConsoleApplication4\ConsoleApplication4\Program.cs:строка 79 в System.AppDomain._nExecuteAssembly(сборка сборки, 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 executeContext, обратный вызов ContextCallback, состояние объекта) в System.Threading.ThreadHelper.ThreadStart() InnerException:

Вопросы: Первый очевиден - что я делаю не так? ;) Во-вторых, как маршалер .NET или что-то еще узнает, правильно ли я написал интерфейс? Как он узнает, какую функцию вызывать из исходного интерфейса С++? Он не распознает их по именам (я попытался ввести опечатку — SetParam вместо SetParameter, и это сработало), но это не удалось, когда я поменял местами порядок функций в интерфейсе.

PS Я могу прикрепить любой код, который вы хотите (или вы можете скачать и скачать его), потому что проект видеообработки является открытым исходным кодом, как directshow.net. Код, созданный мной, находится здесь.

Заранее спасибо.

РЕДАКТИРОВАТЬ: SetParameter действительно работает, так как я создал камеру графика фильтра -> h264 -> декодер -> средство визуализации и играл только с SetParameter ("качество", "..."); и ожидаемая и ясно видимая реакция присутствовала.


person Marcin Pietrzycki    schedule 17.05.2013    source источник
comment
Вы нашли какое-нибудь решение?   -  person daniel    schedule 24.04.2014


Ответы (1)


вы используете неправильный тип для сортировки параметра значения (3-го) в GetParameter. вместо строки используйте 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();

Не уверен, что делает параметр размера буфера, но я могу установить его в 0, и метод все равно возвращает ожидаемые значения.

person Steve Medley    schedule 20.02.2015