简体   繁体   中英

WPF: LibVLCSharp integration in setup project/release version

So I have been against a wall for this one for a while now.

My requirement is to play .mp4 video file in a wpf application. Sounds simple enough, right?

At first, I used built-in MediaElement class and everything worked.

But it turns out, MediaElement is based on Windows Media Player , and for people (myself included) who are using Windows 10 Pro N (or KN) versions, which are basically stripped-down versions of Windows 10, videos are not playing, because Windows Media Player is not included.

That is also reported by attaching an error callback to MediaElement , resulting in message:

"Windows Media Player version 10 or later is required"

Of course, one option is to show user a message and a link to download the feature pack ( https://www.microsoft.com/en-us/software-download/mediafeaturepack ), which includes Windows Media Player , but in all my years using Windows apps, I have NEVER seen any app do/ask that. It is also wrong - the feature pack comes with alot more than just WMP and user might not want to bloat their system with unnecessary apps. That's why user chose Windows 10 Pro N (or KN) in the first place.

But then - how do other apps do it? How are videos on Slack, Discord apps played on my Windows 10 Pro N ?

A bit of googling and general solution is to use VideoLAN.LibVLC.Windows framework, because it is open-sourced, well maintained and has proven itself over the years on multiple platforms.

Ok, I get it's nuget package, and since it is native code, I also download a wrapper libraries to use it in WPF - LibVLCSharp and LibVLCSharp.WPF .

I have successfully integrated video playback, everything works in Debug version.

Now it's time to test it in Release version. I create a new Setup project , build it, install it.

So here's the problem:

My app runs just fine, but when I get to the section where video is supposed to play, I get an exception error:

Failed to load required native libraries. 
Have you installed the latest LibVLC package from nuget for your target platform?
Search paths include 
C:\Program Files (x86)\My app\libvlc\win-x64\libvlc.dll,
C:\Program Files (x86)\My app\libvlc\win-x64\libvlccore.dll; 
C:\Program Files (x86)\My app\libvlc\win-x64\libvlc.dll,
C:\Program Files (x86)\My app\libvlc\win-x64\libvlccore.dll; 
C:\Program Files (x86)\My app\libvlc.dll,

So, in my install directory C:\Program Files (x86)\My app\ , I find these 2 dlls:

LibVLCSharp.dll
LibVLCSharp.WPF.dll

I check the Debug version's folder (because it was working just fine there) and I see that I also have a libvlc folder being generater there, with contents:

libvlc
- win-x64
-- hrtfs
-- locale
-- lua
-- plugins
-- libvlc.dll
-- libvlc.lib
-- libvlccore.dll
-- libvlccore.lib
- win-x86
-- hrtfs
-- locale
-- lua
-- plugins
-- libvlc.dll
-- libvlc.lib
-- libvlccore.dll
-- libvlccore.lib

I copy that folder to my install directory and videos are now playing. Ok, I can automate that folder copy during installation.

But now the problem is size .

My app is 10 MB in size. That libvlc folder is 324 MB in size. It is quite unacceptable for a small 10 MB app to suddenly grow to be 334 MB large. I would understand 10-20 MB increase, but not by this much.

I understand, that I can create two seperate installations - one for x64 and one for x86 systems. Great, that splits size in half.

Then by trial and error, I removed things from those folders that my app can live without and still play the videos.

I am left with this structure, which runs fine:

libvlc
- win-x64
-- plugins
-- libvlc.dll
-- libvlccore.dll

But it still weighs 125 MB. If I delete anything from plugins folder, app crashes.

Is there a better/correct way of including this "libvlc" folder to my Release version, without it blowing up my installer size?

Perhaps there is another, more lightweight framework that can play .mp4 files?

Did I jump into the wrong rabbit hole?

====================== Update ======================

Solved, thanks to @cube45 suggestion.

Indeed, I can delete plugins that I don't need, thus saving space (I initially deleted a required one, so I assumed all were mandatory, simply unlucky).

So again, by trial and error I only left those files that were needed for successfully displaying video.

The resulting list:

libvlc
- win-x64
-- libvlc.dll
-- libvlccore.dll
-- plugins
--- access
---- libimem_plugin.dll
--- codec
---- libavcodec_plugin.dll
---- libd3d11va_plugin.dll
--- video_output
---- libdirect3d9_plugin.dll
---- libdirect3d11_plugin.dll
---- libdrawable_plugin.dll
---- libvmem_plugin.dll

Same for x86 configuration.

The main problem, why the libvlc folder wasn't being generated in the install directory, was because I needed to explicitly add a content output for that directory.

I did so by:

1. Right clicked on **my setup project -> View -> File System**
2. Right clicked on **Application Folder -> Add -> Project Output**
3. Selected **Content Files -> Ok**

And voila - now libvlc folder with it's contents are included in the installer file and placed in install directory.

However, even compressed, the installer file now is 140 MB large, because it included whole libvlc folder. We need to include only those files we need and skip the rest.

So that's where the link @cube45 provided came in handy. Process, where we select only those files/folders that we need, is called Cherry picking . So I added following to *.csproj file:

  <ItemGroup>
    <VlcWindowsX64IncludeFiles Include="libvlc.dll" />
    <VlcWindowsX64IncludeFiles Include="libvlccore.dll" />
    <VlcWindowsX64IncludeFiles Include="plugins\access\libimem_plugin.dll" />
    <VlcWindowsX64IncludeFiles Include="plugins\codec\libavcodec_plugin.dll" />
    <VlcWindowsX64IncludeFiles Include="plugins\codec\libd3d11va_plugin.dll" />
    <VlcWindowsX64IncludeFiles Include="plugins\video_output\libdirect3d9_plugin.dll" />
    <VlcWindowsX64IncludeFiles Include="plugins\video_output\libdirect3d11_plugin.dll" />
    <VlcWindowsX64IncludeFiles Include="plugins\video_output\libdrawable_plugin.dll" />
    <VlcWindowsX64IncludeFiles Include="plugins\video_output\libvmem_plugin.dll" />
    <VlcWindowsX86IncludeFiles Include="libvlc.dll" />
    <VlcWindowsX86IncludeFiles Include="libvlccore.dll" />
    <VlcWindowsX86IncludeFiles Include="plugins\access\libimem_plugin.dll" />
    <VlcWindowsX86IncludeFiles Include="plugins\codec\libavcodec_plugin.dll" />
    <VlcWindowsX86IncludeFiles Include="plugins\codec\libd3d11va_plugin.dll" />
    <VlcWindowsX86IncludeFiles Include="plugins\video_output\libdirect3d9_plugin.dll" />
    <VlcWindowsX86IncludeFiles Include="plugins\video_output\libdirect3d11_plugin.dll" />
    <VlcWindowsX86IncludeFiles Include="plugins\video_output\libdrawable_plugin.dll" />
    <VlcWindowsX86IncludeFiles Include="plugins\video_output\libvmem_plugin.dll" />
  </ItemGroup>

And voila - now my installation file weighs only 23 MB, which is completely acceptable!

Oh and that size can be cut down by half, because this was built for Any CPU configuration. So if I split this installation into two seperate ones, the weight would be ~11.5 MB (but then a whole new set of problems would occur, so I'm not gona delve into that).

Long story short - success!

So a few things:

Ok, I get it's nuget package, and since it is native code, I also download a wrapper libraries to use it in WPF - LibVLCSharp and LibVLCSharp.WPF.

You only need to reference LibVLCSharp.WPF and VideoLAN.LibVLC.Windows , LibVLCSharp is a dependency of the .WPF project

I check the Debug version's folder (because it was working just fine there) and I see that I also have a libvlc folder being generater there, with contents:

You should also have that in the Release folder too. If not, something might be wrong with VideoLAN.LibVLC.Windows or the way you're using it.

I understand, that I can create two seperate installations - one for x64 and one for x86 systems.

Yes, that would avoid embedding libvlc twice, that's what I'd recommend

If I delete anything from plugins folder, app crashes.

That's the way you should customize it, but you would need to figure out by yourself what you really need (you'll likely only need the "file" access plugin, no gui plugin, no mux...). I'd recommend taking a look at this documentation: https://code.videolan.org/videolan/libvlc-nuget/-/blob/master/cherry-picking.md

If that's not slim enough for you (for example, codec/libavcodec_plugin.dll is still too heavy for you), I'm afraid you'll have to build libvlc by yourself. Warning: it's not a nice walk in the park.

Perhaps there is another, more lightweight framework that can play.mp4 files?

I only know about FFMediaElement and other ffmpeg-based projects, but I'm unsure about the ffmpeg licensing, and I did not test them myself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM