1

J'essaie de créer un wrapper C# de base pour un encodeur h264. J'utilise Directshow.NET et un codeur H264 personnalisé. Le filtre DirectShow de codeur est une partie du projet de traitement vidéo http://sourceforge.net/projects/videoprocessing/ La classe de filtre (H264EncoderFilter) hérite d'une ISettingsInterface:Comment créer un wrapper C# pour l'encodeur DirectShow h264 personnalisé

//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; 

}; 

I créé une enveloppe pour le filtre lui-même (en Uuids.cs de Directshow.NET lib , pour l'enregistrement):

[ComImport, Guid("28D61FDF-2646-422D-834C-EFFF45884A36")] 
public class H264Encoder 
{ 
} 

Avec elle, je peux instancier la classe de filtre en C# et aussi je suis en mesure de jeter le filtre sur l'interface IBaseFilter, donc je suppose que fonctionne ce wrapper.

Ensuite, je voulais créer une enveloppe pour le ISettingsInterface (j'ai ajouté le code ci-dessous pour AxCore.cs) dont nous avons parlé:

[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 
     ); 
} 

Cela nous amène à mon problème. Lorsque j'essaie d'utiliser l'interface, tout ne fonctionne pas. Lorsque j'utilise la fonction SetParameter, il semble que tout se passe bien (Hresult retourné est 0), mais quelque chose ne va pas quand j'utilise GetParameter. S'il vous plaît jeter un oeil sur le code de test et sa sortie de la console:

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()); 
      } 
     } 

Sortie de la console: http://img707.imageshack.us/img707/3667/consolevd.png

Observations:

  • szParamValue doit être une chaîne containg "15", car il a été mis de cette façon par SetParameter. Au lieu de cela, c'est un gâchis. NLength est la longueur de chaîne contenue dans SetParameter, ce qui est correct car la longueur du "15" attendu est 2. Elle passe à 3 lorsque la qualité est définie par exemple sur "151"
  • szParamValue n'est pas toujours telle mess, parfois c'est une chaîne vide ou du code XML ... Et, ce qui est plus important, AccessViolationException est lancé en ligne avec l'appel GetParameter. Les détails de l'exception ci-dessous.
  • L'adresse od szParamValue dans la mémoire change, comme vous pouvez le voir dans la sortie de la console.

Détails de l'exception:

System.AccessViolationException était unhandled message = Tentative de lecture ou d'écriture de mémoire protégée. C'est souvent une indication que l'autre mémoire est corrompue. Source = DirectShowLib-2005 StackTrace: à DirectShowLib.ISettingsInterface.GetParameter (type String, Int32 buffersize, Valeur de chaîne &, Int32 longueur &) à ConsoleApplication4.Program.Main (String [] args) dans F: \ Documents \ System.AppDomain._nExecuteAssembly (Assembly assembly, String [] args) à System.AppDomain.ExecuteAssembly (String assemblyFile, Evidence assemblySecurity, String [] args Visual Studio 2010 \ Projects \ ConsoleApplication4 \ ConsoleApplication4 \ Program.cs: ligne 79 ) à Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() à System.Threading.ThreadHelper.ThreadStart_Context (état de l'objet) à System.Threading.ExecutionCon texte.Run (ExecutionContext ExecutionContext, rappel ContextCallback, état d'objet) à System.Threading.ThreadHelper.ThreadStart() InnerException:

Questions: Le premier est obvious- ce que je fais mal? ;) Deuxièmement, comment. Marshaler .NET ou quelque chose savoir si j'ai écrit l'interface correctement? Comment sait-il quelle fonction appeler à partir de l'interface C++ d'origine? Il ne les reconnaît pas par des noms (j'ai essayé d'incorporer un typo-SetParam au lieu de SetParameter et cela a fonctionné) mais il a échoué quand j'ai permuté l'ordre de fonction dans l'interface. PS Je peux joindre n'importe quel code que vous voulez (ou vous pouvez télécharger le télécharger aussi) parce que le projet de traitement vidéo est open source, comme directshow.net. Le code créé par moi est tout ici.

Merci d'avance.

EDIT: SetParameter fonctionne en effet, car j'ai créé une caméra graphique de filtre -> h264 -> décodeur -> renderer et joué seulement avec SetParameter ("quality", "..."); et une réaction attendue et clairement visible était présente.

+0

Avez-vous trouvé une solution? – daniel

Répondre

0

vous utilisez le mauvais type pour marshalling le paramètre de valeur (3e) dans GetParameter. au lieu de chaîne, utilisez StringBuilder. Comme ci-dessous

[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); 

Un exemple d'utilisation serait alors

StringBuilder sb = new StringBuilder(); 
int len = int.MinValue; 
((ISettingsInterface)enc).GetParameter("quality", 0, sb, ref len); 
string value = sb.ToString(); 

Je ne sais pas ce que le paramètre buffersize fait, mais je peux le mettre à 0 et la méthode renvoie toujours les valeurs attendues

Questions connexes