Saltar al contenido
Ricardo RetamalSoftware y cosas que vale la pena construir
/
Conversemos
← Ver todos los escritos
Software3 min read

How to Integrate LibVLCSharp into .NET MAUI for IP Camera Streaming

In other articles, I have reviewed how to integrate some RTSP libraries for camera visualization in mobile applications. Today we will…

Publicado originalmente en Medium ↗

In other articles, I have reviewed how to integrate some RTSP libraries for camera visualization in mobile applications. Today we will review how to integrate the LibVLCSharp library into .NET MAUI, which will help us both to play IP camera streams and any other multimedia content.

In this project, we will cover the following:

  • Project creation
  • Library installation
  • Creation of a view to play the content
  • Creation of handlers to manage the content on Android and iOS

The first thing we will have to do is create a new project in Visual Studio 2022:

Next, we will have to assign it a name; in my case, I named it MauiVlc:

And then the framework we want to use in the project:

Once that step is completed, our project should look as follows:

What do we have to do now? Install the libraries! To do this, you will right-click on the project and go to NuGet to search for the VideoLAN.LibVLC.Android and VideoLAN.LibVLC.iOS libraries, and yes, you have to install them in the same project.

Once we have the libraries, we will create a ‘Controls’ folder in our project and add a MediaViewer class to it. The project should now look as follows:

And the MediaViewer class should look as follows:

public class MediaViewer : View
	{
        public static BindableProperty VideoUrlProperty = BindableProperty.Create(nameof(VideoUrl)
           , typeof(string)
           , typeof(MediaViewer)
           , ""
           , defaultBindingMode: BindingMode.TwoWay);


        public string VideoUrl
        {
            get => (string)GetValue(VideoUrlProperty);
            set => SetValue(VideoUrlProperty, value);
        }


    public MediaViewer()
		{
		}
	}

GitHub Gist ↗

The class, as you can see, inherits from View and implements a VideoUrl property to specify the path of the video we want to display.

The next step is to create the Handlers folder where we will store the respective handlers for using the VLC library:

The MediaViewerHandler will look as follows:

public partial class MediaViewerHandler
	{
        public static IPropertyMapper<MediaViewer, MediaViewerHandler> PropertyMapper = 
                                new PropertyMapper<MediaViewer, MediaViewerHandler>()
        {
        };


        public static CommandMapper<MediaViewer, MediaViewerHandler> CommandMapper = new(ViewCommandMapper)
        {
        };


        public MediaViewerHandler() : base(PropertyMapper, CommandMapper)
        {
		}
	}

GitHub Gist ↗

The implementation for Android will look like this:

public partial class MediaViewerHandler: ViewHandler<MediaViewer, VideoView>
    {
        VideoView _videoView;
        LibVLC _libVLC;
        LibVLCSharp.Shared.MediaPlayer _mediaPlayer;


        protected override VideoView CreatePlatformView() => new VideoView(Context);


        protected override void ConnectHandler(VideoView nativeView)
        {
            base.ConnectHandler(nativeView);


            _libVLC = new LibVLC(enableDebugLogs: true);
            _mediaPlayer = new LibVLCSharp.Shared.MediaPlayer(_libVLC)
            {
                EnableHardwareDecoding = true
            };


            _videoView = nativeView ?? new VideoView(Context);
            _videoView.MediaPlayer = _mediaPlayer;


            HandleUrl(VirtualView.VideoUrl);


            base.ConnectHandler(nativeView);
        }


        protected override void DisconnectHandler(VideoView nativeView)
        {
            nativeView.Dispose();
            base.DisconnectHandler(nativeView);
        }


        private void HandleUrl(string url)
        {
            try
            {


                if (url.EndsWith("/"))
                {
                    url = url.TrimEnd('/');
                }


                //url = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";


                if (!string.IsNullOrEmpty(url))
                {
                    var media = new Media(_libVLC, url, FromType.FromLocation);


                    _mediaPlayer.NetworkCaching = 1500;


                    if (_mediaPlayer.Media != null)
                    {
                        _mediaPlayer.Stop();
                        _mediaPlayer.Media.Dispose();
                    }


                    _mediaPlayer.Media = media;
                    _mediaPlayer.Mute = true;


                    _videoView.MediaPlayer.Play();
                }
            }
            catch (Exception ex)
            {
            }
        }


    }

GitHub Gist ↗

public partial class MediaViewerHandler : ViewHandler<MediaViewer, VideoView>
    {
        VideoView _videoView;
        LibVLC _libVLC;
        LibVLCSharp.Shared.MediaPlayer _mediaPlayer;


        protected override VideoView CreatePlatformView()
        {
            return new VideoView();
        }


        protected override void ConnectHandler(VideoView nativeView)
        {
            base.ConnectHandler(nativeView);


            Core.Initialize();


            _libVLC = new LibVLC(enableDebugLogs: true);
            _mediaPlayer = new LibVLCSharp.Shared.MediaPlayer(_libVLC)
            {
                EnableHardwareDecoding = true
            };


            _videoView = nativeView ?? new VideoView();
            _videoView.MediaPlayer = _mediaPlayer;


            HandleUrl(VirtualView.VideoUrl);
        }


        protected override void DisconnectHandler(VideoView nativeView)
        {
            nativeView.Dispose();
            base.DisconnectHandler(nativeView);
        }


        public void HandleUrl(string url)
        {
            try
            {
                if (url.EndsWith("/"))
                {
                    url = url.TrimEnd('/');
                }


                if (!string.IsNullOrEmpty(url))
                {
                    var media = new Media(_libVLC, url, FromType.FromLocation);


                    _mediaPlayer.NetworkCaching = 1500;


                    if (_mediaPlayer.Media != null)
                    {
                        _mediaPlayer.Stop();
                        _mediaPlayer.Media.Dispose();
                    }


                    _mediaPlayer.Media = media;
                    _mediaPlayer.Mute = true;


                    _videoView.MediaPlayer.Play();
                }
            }
            catch (Exception ex)
            {
                // Handle exception
            }
        }
    }

GitHub Gist ↗

Once those steps are completed, what remains is to register the handler in the MauiProgram.cs file:

public static class MauiProgram
    {
        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                             .ConfigureMauiHandlers((handlers) => {
                                 handlers.AddHandler(typeof(MediaViewer), typeof(MauiVlc.Handlers.MediaViewerHandler));
                             })
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                });


#if DEBUG
    		builder.Logging.AddDebug();
#endif


            return builder.Build();
        }
    }

GitHub Gist ↗

If you want to see the code, you can find it on the GitHub repository:

rretamal/MauiVLC (github.com)

If you want to see a working example, you can download the sample app here:

Android:

ReCam Viewer — Apps on Google Play

Happy Coding!

https://www.buymeacoffee.com/2hepU6W