Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create supporting nuget package with latest LGPL binaries for Windows. #64

Closed
qmfrederik opened this issue Sep 22, 2017 · 24 comments
Closed
Assignees

Comments

@qmfrederik
Copy link
Contributor

The P/Invoke declarations currently link to a specific version of the FFmpeg/libav libraries, like this:

[DllImport("avcodec-57", EntryPoint = "audio_resample", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

For example, libav 11.7 includes avcode-58 instead of avcodec-57, so you can't use FFmpeg.AutoGen with libav 11.7 (although they are fairly API-compatible). And dllmap isn't an option, as .NET (Core) doesn't provide dllmap support.

You could workaround this by manually loading the functions. An example of how this is done, can be found in the .NET Core source code.

You would first:

  1. Need to manually load the library (dlopen or LoadLibrary); see https://github.com/dotnet/corefx/blob/bc9a9d7ed76053c9b7a5ffad6707002ff7a815db/src/System.Drawing.Common/src/System/Drawing/GdiplusNative.Unix.cs:L19
  2. You can then manually load a function pointer (delegate) which invokes any of the exported functions of the native libraries; see https://github.com/dotnet/corefx/blob/b587dc3d0ed68b3c37ea93e5afc472ba2e815dad/src/Common/src/System/Runtime/InteropServices/FunctionWrapper.Unix.cs
  3. Finally, you can invoke that function pointer; see https://github.com/dotnet/corefx/blob/master/src/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs

I believe you use ClangSharp to auto-generate the P/Invoke code so I assume it could be amended to use this logic, providing a bit more of flexibility to the users of this library so to which dlls are exactly loaded.

@Ruslan-B
Copy link
Owner

@qmfrederik could you please elaborate the rational need of this.
My point of view:
These bindings are generated against the specific version of API, so in case you have a different version of dll it means you have a breaking change(s) in the API of that library which means they are incompatible.
From my perspective, in case you need hack something or experiment you can grab the source code and you can adjust and compile binding yourself or just create a symlink.

@qmfrederik
Copy link
Contributor Author

@Ruslan-B Thanks for the fast response!

Well - at the root of the issue is that I'm using libav, not ffmpeg, though they are very (but not totally) compatible. I prefer libav because they publish LGPL binaries, whereas ffmpeg provides (by default) GPL binaries.

Another use case would also be upgrading to a newer version of ffmpeg - they may bump the API version if they add new functions or remove deprecated functions, but bindings for a lower API version should still work, as long as you're not using the deprecated functions.

The same may also hold true if you're developing an assembly which you want to run on different Linux distributions which may include different versions of ffmpeg. Ideally you are compatible with the different ffmpeg versions which ship out of the box on your Linux distribution, as long as you (the developer) make sure the functions you call are present on all versions of ffmpeg you want to target.

I know it's a stretch, but wanted to share the approach just in case :).

@Ruslan-B
Copy link
Owner

@qmfrederik okay, I got you point it is indeed interesting to know.

However, I see few problems which can be address I a slightly different way.

With respect to next version of ffmpeg I already have the nuget package my intention is to update it for every major/minor release it going to be sufficient.
assume). I'm convinced that having a supporting nuget package with latest LGPL binaries for Windows will beneficial and not going to be a problem any more.
I'll try to look how hard or easy it will be to organize.

Distribution on Linux should not be a problem at all as ffmpeg has packages and you can install required version or if you brave enough you just can symlink installed version to any other.

@qmfrederik
Copy link
Contributor Author

I'm convinced that having a supporting nuget package with latest LGPL binaries for Windows will beneficial and not going to be a problem any more.

That would a great idea :-).

I maintain a couple of packages that distribute binaries (mostly .dll's on Windows & .dylib's on macOS) via NuGet.

It becomes really easy when you're targetting .NET Core or newer NuGet versions. In that case, you just need to put the native files in the runtimes/{runtime}/native/ folder, where {runtime} is the runtime identifier, such as win7-x64 or win7-x86.
iMobileDevice-net.csproj has an example.

If you want to target Desktop .NET, you'll also need to provide a build/net45/{PackageName}.targets file which copies the files from the NuGet package folder to your destination folder, something like iMobileDevice-net.targets

@Ruslan-B
Copy link
Owner

Ok then I'll rename this issue, I have plans to do so during next week.

@Ruslan-B Ruslan-B changed the title Support multiple versions of FFmpeg/libav Create supporting nuget package with latest LGPL binaries for Windows. Sep 23, 2017
@qmfrederik
Copy link
Contributor Author

Awesome, thanks!

@Ruslan-B Ruslan-B self-assigned this Sep 25, 2017
@Ruslan-B
Copy link
Owner

Ruslan-B commented Oct 1, 2017

It appears it is quite a problem to build stable version of ffmpeg (3.3).

@qmfrederik
Copy link
Contributor Author

@Ruslan-B I'm experimeting with a Travis project which cross-builds ffmpeg for Windows on Ubuntu and packages that in a NuGet package - see http://github.com/qmfrederik/ffmpeg-win32

@Ruslan-B
Copy link
Owner

Ruslan-B commented Oct 3, 2017

@qmfrederik it is awesome! It appears I took quite complex route. However, I tried the package (r30) and didn't manage to open any file or uri it fails with the Protocol not found error.

@qmfrederik
Copy link
Contributor Author

@Ruslan-B DId you use the FFmpeg.Native.H264 package? That one is built from the h264-only package and only contains the h264 decoder (because that's the part of ffmpeg we're using in our software).

I'm building a FFmpeg.Native package as well, I'll try to upload that later today so you can give it a try.

As a note, I've noticed that the GPL build of FFmpeg for Windows links with all possible dependencies. If you want to do that, you'll need to compile each of them and include it in the NuGet package. So I kind of took a shortcut by not linking with any external FFmpeg dependency.

The gnutls dependency is a dependency which caused quite some trouble for me (because it has a lot of other dependencies); in the end it turns out that you don't really need to use gnutls on Windows because FFmpeg can use the standard Windows cryptography APIs. So if you ever want to build a FFmpeg package which is more complete than mine - just remember that gnutls isn't really required.

I'll keep you updated in this thread. If you want to publish a package with the runtime dependencies (or take ownership of FFmpeg.Native), that'd be fine with me, too.

@Ruslan-B
Copy link
Owner

Ruslan-B commented Oct 3, 2017

@qmfrederik thank for the update! Yes, used the FFmpeg.Native.H264 package so it explains.
Indeed, It would be nice to try out new package.
With respect to ownership I'm not insisting on any, as long we have up-to-date binaries. Especially, right now I do realize it is quite en effort to build and maintain it in future.
Beside, I saw few post on internet - some folks bought lgpl build from zeranoe for 500$ in 2013.

@qmfrederik
Copy link
Contributor Author

@Ruslan-B I pushed a package with x64 LGPL binaries here (free of charge 😄 ): https://www.nuget.org/packages/FFmpeg.Native. It may take a couple of minutes for NuGet to index it but it should be there soon.

I also updated the README file with a list of all options which are included.

Let me know if it works for you!

@Ruslan-B
Copy link
Owner

Ruslan-B commented Oct 4, 2017

@qmfrederik works like a charm! I think some minor twinks can be done like put semantic version and throw a way binaries from this repo and update read me but this package is really big step forward.

@hey-red
Copy link
Contributor

hey-red commented Feb 13, 2018

I got strange error while starting NET Core 2.0 console application:

Unable to load DLL 'avformat.57': The specified module could not be found.

but why library is trying to load avformat.57 instead avformat-57?

csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="FFmpeg.AutoGen" Version="3.4.0.5" />
    <PackageReference Include="FFmpeg.Native" Version="1.0.0-r31" />
  </ItemGroup>

</Project>

@Ruslan-B
Copy link
Owner

@hey-red what platform are you running on?

@hey-red
Copy link
Contributor

hey-red commented Feb 13, 2018

@Ruslan-B
Win10 x64, NET Core SDK 2.1.4

My apologies, I thought this library doesn't use LoadLibrary and works out of box with FFmpeg.Native.

@Ruslan-B
Copy link
Owner

Ruslan-B commented Feb 13, 2018

It appreas to be true they are not working out of box. I wonder how @qmfrederik uses FFmpeg.Native package. As .NET Core host does not extract native dlls from the package.

@qmfrederik
Copy link
Contributor Author

I currently use the FFmpeg.Native package which only includes the H264 codecs.
That one includes a FFmpegBinaries.FindFFmpegLibrary method which does the library loading.

That said, native library loading is being improved in .NET Core. dotnet/corefx#17135 describes a new API which has been approved today and will land soon. It's probably best to wait for this to land & build on that one.

@hey-red
Copy link
Contributor

hey-red commented Feb 13, 2018

Thanks for clarifying.

@grill2010
Copy link

grill2010 commented Mar 29, 2018

In case someone is also struggling to build a valid LGPL ffmpeg build for Windows x64/x86, there is this fantastic piece of work on github which is called media-autobuild_suite. These scripts do basically all the work for you and provide many customization features for all kind of ffmpeg features like openh264 and many more.
At first I tried to build ffmpeg on Ubuntu by myself which was more ore less working but as soon as I wanted to include some 3rd Party libraries things got complicated.

@grill2010
Copy link

grill2010 commented Apr 1, 2018

If you want to build a specific version of FFmpeg to use it in FFmpeg autogen you can do this by editing the media-suite_compile.sh script.

Example

@popcatalin81
Copy link

popcatalin81 commented May 7, 2018

For using FFmpeg.Native in a .Net standard style class library the following can be added to the .csproj to copy the runtime files to bin

  <ItemGroup>
    <None Include="$(NuGetPackageRoot)ffmpeg.native\1.0.0-r31\runtimes\win7-x64\native\*.*">
      <Link>runtime\%(Filename)%(Extension)</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

Edit the paths if other versions of FFmpeg.Native are used.

@Ruslan-B
Copy link
Owner

Ruslan-B commented May 7, 2018

Looks like a good workaround. Nevertheless, we have and issue here quamotion/ffmpeg-win32#2 to automate the process. I had a plan to add an extra target file to package to do this automatically.

@Ruslan-B
Copy link
Owner

Ruslan-B commented Mar 5, 2019

Closing this issue as irrelevant to project as seems supporting package never going to meet all users requirements. So if you don't like GPL binaries you need to build your own very special version of FFMPEG any way.

@Ruslan-B Ruslan-B closed this as completed Mar 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants