4

Based on this other question from here Using OpenH264 DLL in C# Project I'm basically trying to use the library https://github.com/secile/OpenH264Lib.NET in unity to encode H264 video files in real time, using unity's JINT native library for use in JavaScript interperting

I am having quite a bit of difficulty referencing the DLL in unity though.

I follow the instructions from the GitHub site and manage to compile to OPenH264Lib.dll (as well as the sample project, and get the sample project to work with visual studio 2019, on windows x64 fine, and it encodes everything etc), but when I simply drag the compiled OpenH264Lib.dll to the Plugins folder in the Assets folder of a Unity project, I am not able to access the namespace OpenH264Lib, which is used in the standard C# sample there to access the DLL managed functions, it just says in the unity console the namespace isn't found.

OK fine so I decided to build a C# DLL with visual studio, which itself loads in OpenH264Lib.dll and then call its functions from there, then use the C# DLL in unity, so here's my C# code in visuaal studio (after having put the compiled (with .NET version 4.6.1) OpenH264Lib.dll in the Debug folder, just like in the sample, and I'm not getting any reference errors in Visual Studio 2019):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sayfir
{
    public class Class1
    {
        public static OpenH264Lib.Encoder ok(string path)
        {
            var code = new OpenH264Lib.Encoder(path);
            return code;
        }
    }
}

OK fine so this builds perfectly with no errors and it seems to be doing the same as the sample folder (in Assets/Plugins).

Then when I take the DLL files generated in the x64/Debug folder of my solution (both the OpenH264Lib.dll and the Sayfir.dll) and copy them to the Plugins folder in Unity, then try to access it in unity like so

public class Yetzirah {
        public static void Wellz() {
            var k = Sayfir.Class1.ok("2");
            Debug.Log(k);
        }
}

I get an error in the Unity console

Assets\scripts\Yetzirah.cs(45,12): error CS0012: The type 'Encoder' is defined in an assembly that is not referenced. You must add a reference to assembly 'OpenH264Lib, Version=1.0.7598.38705, Culture=neutral, PublicKeyToken=null'.

so it seems it recognizes the Sayfir.dll file compiled from the source above, but just not the OpenH264Lib.dll that it depends on, even though both are in the same folder (in Assets/Plugins)

I've heard about .rsp files but I tried making one with the name csc.rsp and adding it to Assets with the content -r:OpenH264Lib

still nothing

Also I've heard of .asmdef files but when I made one with the contents

{
    "references":  "OpenH264Lib" 
}

But still nothing, I don't really know much about asmdef files, I also don't know much about this error or in general how to use managed C++ DLLs in unity at all.

I've also seen an article that mentions referencing external DLL files in unity, but it says to go to

Project > Edit References > .NET Assembly

Thing is, I don't know how to get to that screen in the UnityEditor 2020, or if there is even a way to get there or accomplish the same thing, if so I don't know how and wasn't able to find it searching

I tried making another DLL using standard dllexports, with the header file contents of

extern "C" __declspec(dllexport) int well();

then in the .cpp file

#include "deeall.h"
__declspec(dllexport) int well() {
    return 634;
}

then in unity C#

DllImport("deeall.dll", EntryPoint="well")]
public static extern int well();

then it works, but when I include in the dll extern int any kinds of managed libraries i get an error __declspec(dllexport) cannot be applied to a function with the __clrcall calling convention.

which is what is necessary if I want to use __declspec exports for the C# wrapper

As a hack I tried adding to the Encoder.cpp file itself (from the source of the OpenH264Lib .dll) the following

    __declspec(dllexport) int well() {
        String ^h = "ok";
        Encoder
        ^enc = 
        gcnew Encoder(
            h
        );
        return 4;
    }

trying to call the Encoder function directly, (along with the following header file modification to Encoder.h:

namespace OpenH264Lib {
    extern "C" __declspec(dllexport) int well();
    //etc.. rest of code in namespace.....

) then in unity

[DllImport("OpenH264Lib6.dll", EntryPoint="well")]
public static extern int well();

but when I called well(), unity hung for a while then crashed, without any errors

So how can I get the OpenH264Lib.dll working in unity, or other similar managed compiled C++ DLLs in unity? If this is not possible is there any other way I can use OpenH264 in general in Unity? If not are there any others solutions for encoding H264 videos in real time in unity (from byte[]s)?

  • Please consider editing your question and adding the code fragment, with no code you might get only some guesses and no actual solution – Cleptus Oct 14 '20 at 06:13
  • @cleptus I added the relevant code sections before, what else should I add – B''H Bi'ezras -- Boruch Hashem Oct 14 '20 at 06:20
  • You very likely are leaving some unmanaged resource used and that would not allow disposing the classes. You could use the [using statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement) instead `Dispose` but it would not solve your problem (it is only an exception safe `Dispose` statement) – Cleptus Oct 14 '20 at 06:20
  • You have exposed a problem, but only added one line of code, check the [mcve](https://stackoverflow.com/help/minimal-reproducible-example) help page – Cleptus Oct 14 '20 at 06:22
  • @cleptus basically I am using JINT native and I call a c# function that returns the native array, as well as calls the AsyncGPUReadback function to read into the array, with a callback, then in the callback I make a new wrapper class to hold the native array, to manipulate it within JINT s JavaScript, then in JavaScripts I set a timer to call .Dispose of the native array from the wrapper class.. just not sure why dispose itself would crash it – B''H Bi'ezras -- Boruch Hashem Oct 14 '20 at 06:23
  • @cleptus I am not able to make a new example because it's all too complicated to reproduce, just wondering why dispose would make an error – B''H Bi'ezras -- Boruch Hashem Oct 14 '20 at 06:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/223003/discussion-between-cleptus-and-bluejayke). – Cleptus Oct 14 '20 at 06:24

1 Answers1

1

This is written from memory and not tested but I'd assume it would work.

  • Make sure the OpenH264Lib.dll is loaded correctly, otherwise load it manually, e.g. in your Wrapper using Assembly.Load/Assembly.LoadFrom
  • Make sure the openh264-1.7.0-win32.dll is located next to your executable or specify a full path
  • Make sure you don't mix 32Bit and 64Bit
  • Build your Sayfir wrapper Assembly like you did but do not expose the Encoder class itself instead wrap the methods you want to use. This way Unity does not need to know anything about the OpenH264Lib.dll

For example


public class Wrapper 
{
  private Encoder _encoder;
  public Wrapper() 
  {
    // Be sure the openh264-1.7.0-win32.dll can be found! 
    // Native dlls should be located next to the actual executable if you call it without a full path!
    _encoder = new OpenH264Lib.Encoder("openh264-1.7.0-win32.dll");
  }

  public void Setup(/* ... */)
  {
    //_encoder.Setup(...)
  }
}

If it still does not work, try to redirect the DLL lookup path using this method before you try to load OpenH264Lib.dll. In the source of the encoder class we see the call to LoadLibrary which will then use the path that you give here to search for the DLL. Restore normal search order after loading by calling the function again with null as argument.

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetDllDirectory(string lpPathName);

https://www.pinvoke.net/default.aspx/kernel32.LoadLibrary

sneusse
  • 1,422
  • 1
  • 10
  • 18
  • interesdting thanks for the answer, do you know if its possible to call native DLL functions at runtime, it may simplify things – B''H Bi'ezras -- Boruch Hashem Oct 23 '20 at 02:05
  • Yes, using the `DllImport` as you already wrote. Look at https://github.com/secile/OpenH264Lib.NET/blob/master/OpenH264Lib/Encoder.h. You have to match the signature exactly or do the marshalling yourself. – sneusse Oct 23 '20 at 07:05
  • Thanks although i think dllimport only works if compiled in the c# code, but what if I want a to select a dll file from their computer to load it in runtime – B''H Bi'ezras -- Boruch Hashem Oct 23 '20 at 18:36
  • Ok then you would use the standard WinAPI GetProcAddress https://www.pinvoke.net/default.aspx/kernel32.getprocaddress and convert it using GetDelegateForFunctionPointer https://learn.microsoft.com/de-de/dotnet/api/system.runtime.interopservices.marshal.getdelegateforfunctionpointer?view=netcore-3.1 – sneusse Oct 26 '20 at 07:35
  • ok I tried that but #1 is that a cross platform solution and #2 how do I automatically generated Delegate for each type of function loaded – B''H Bi'ezras -- Boruch Hashem Oct 27 '20 at 06:41
  • Well if cross plattform means Win7/Win10 then yeah. Otherwise obviously now as you are loading native object files. You'd have to implement this for every platform you want to support. The delegates you'll have to write yourself. – sneusse Oct 27 '20 at 11:33
  • I mean mac and Linux and Android how can I load dll functions from them – B''H Bi'ezras -- Boruch Hashem Oct 27 '20 at 18:26