fabulous-dev/Fabulous

Rudimentary Video Player Example

jinyus opened this issue · 9 comments

jinyus commented

Hey, I quite new to fsharp and dotnet as a whole and I'd like to build a media manager with fabulous and wondering if video playback is even possible based on upstream issues: AvaloniaUI/Avalonia#2571

I see a simple sample with LibVLCSharp at https://code.videolan.org/videolan/LibVLCSharp/-/blob/3.x/samples/LibVLCSharp.FSharp.Sample/Program.fs?ref_type=heads
but I am not sure how to wire it up with fabulous...is it possible to provide an example on how to use libVLCSharp with fabulous?

Hi @jinyus !

Which platforms are you targeting? iOS, Android, Windows?
I see the Avalonia issue and the LibVLC sample code you shared are both targeting Windows only.

First thing you'll need is a media player control that works with Avalonia if you are using Fabulous.Avalonia.

jinyus commented

My main target is linux, I plan to support windows and macos at a later date. Thanks for pointing me in the right direction.

Seems like this package would work on Linux, Windows and macOS: https://www.nuget.org/packages/LibVLCSharp.Avalonia
They provide a VideoView control you can add to your interface.

To be able to use the VideoView control in Fabulous, you'll need to create a widget that will wrap this control.

// Tells Fabulous that VideoView inherits all the same modifiers than Control
// eg. BackgroundColor, Width, Height, etc.
type IFabVideoView = inherit IFabControl

module VideoView =
    // Register the new widget with Fabulous
    // This tells Fabulous that if you use the this VideoView widget, it needs to instantiate a LibVLCSharp.Avalonia.VideoView control
    let WidgetKey = Widgets.register<LibVLCSharp.Avalonia.VideoView>()

    // Declare the properties you will set on the widget
    // Here VideoView has only one: MediaPlayer
    let MediaPlayer = Attributes.defineAvaloniaPropertyWithEquality VideoView.MediaPlayerProperty

// Define the available constructors for the widget we are creating
// Here VideoView only makes sense if we provide the MediaPlayer so let's make it mandatory in the constructor
[<AutoOpen>]
module VideoViewBuilders =
    type Fabulous.Avalonia.View with
        static member inline VideoView<'msg>(mediaPlayer: MediaPlayer) =
            WidgetBuilder<'msg, IFabVideoView>(
                VideoView.WidgetKey,
                VideoView.MediaPlayer.WithValue(mediaPlayer)
            )

That's it. Now you can use this new VideoView widget in your Fabulous.Avalonia project.

module App =
    // Initialize the media player with the media source
    // Note that all objects are disposable but here for brevity I don't dispose them
    let mediaPlayer =
        let libVLC = new LibVLC()
        let media = new Media(libVLC, new Uri(@"C:\tmp\big_buck_bunny.mp4"))
        new MediaPlayer(media)

    type Model =
        { IsPlaying: bool }

    type Msg =
        | Play
        | Stop

    let init () = { IsPlaying = false }

    let update msg model =
        match msg with
        | Play ->
            mediaPlayer.Play()
            { model with IsPlaying = true }
    
        | Stop ->
            mediaPlayer.Stop()
            { model with IsPlaying = false }

    let view model =
        VStack() {
            Button("Play", Play)
            Button("Stop", Stop)
            VideoView(mediaPlayer)
        }
jinyus commented

Did you get this to build? Just installing LibVLCSharp.Avalonia makes the demo template unbuildable with this error:

FSC : error FS0193: The module/namespace 'Avalonia.Input.GestureRecognizers' from compilation 
unit 'Avalonia.Base' did not contain the namespace, module or type 'IGestureRecognizer'

edit:

I installed v3.7.0 and it builds now. I'm guessing there was a breaking change and Avalonia doesn't follow semver.

jinyus commented

In another stalemate, it looks like LibVLCSharp.Avalonia 3.7.0 doesn't support Avalonia 11 but 3.8.1 fails to build with the stacktrace in the video:

stacktrace
FSC : error FS0193: The module/namespace 'Avalonia.Input.GestureRecognizers' from compilation unit 'Avalonia.Base' did not contain the namespace, module or type 'IGestureRecognizer' [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
/home/dev/projects/fs/demo/player.fs(15,21): error FS0039: The value, namespace, type or module 'Widgets' is not defined. Maybe you want one of the following:   Widget   WidgetKey   WidgetDiff   WidgetChanges   WidgetChange [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
/home/dev/projects/fs/demo/player.fs(19,34): error FS0039: The value, constructor, namespace or type 'defineAvaloniaPropertyWithEquality' is not defined. Maybe you want one of the following:   defineSimpleScalarWithEquality [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
/home/dev/projects/fs/demo/player.fs(31,17): error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
/home/dev/projects/fs/demo/player.fs(29,13): error FS0041: A unique overload for method 'WidgetBuilder`2' could not be determined based on type information prior to this program point. A type annotation may be needed.Known types of arguments: 'a * 'bCandidates: - new: key: WidgetKey * attributes: AttributesBundle -> WidgetBuilder<'msg,'marker> - new: key: WidgetKey * scalar: ScalarAttribute -> WidgetBuilder<'msg,'marker> [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
FSC : error FS0193: The module/namespace 'Avalonia.Input.GestureRecognizers' from compilation unit 'Avalonia.Base' did not contain the namespace, module or type 'IGestureRecognizer' [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
/home/dev/projects/fs/demo/App.fs(31,13): warning FS3560: This copy-and-update record expression changes all fields of record type 'demo.App.Model'. Consider using the record construction syntax instead. [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
/home/dev/projects/fs/demo/App.fs(35,13): warning FS3560: This copy-and-update record expression changes all fields of record type 'demo.App.Model'. Consider using the record construction syntax instead. [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
/home/dev/projects/fs/demo/App.fs(38,9): error FS0039: The value or constructor 'VStack' is not defined. [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
/home/dev/projects/fs/demo/App.fs(45,21): error FS0039: The value or constructor 'DesktopApplication' is not defined. [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
/home/dev/projects/fs/demo/App.fs(48,27): error FS0039: The type 'Program<_,_,_,_>' does not define the field, constructor or member 'statefulWithCmd'. [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
FSC : error FS0193: The module/namespace 'Avalonia.Input.GestureRecognizers' from compilation unit 'Avalonia.Base' did not contain the namespace, module or type 'IGestureRecognizer' [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]
/home/dev/projects/fs/demo/Platform/Desktop/Program.fs(14,34): error FS0039: The value, namespace, type or module 'Program' is not defined. Maybe you want one of the following:   Progress [/home/dev/projects/fs/demo/demo.fsproj::TargetFramework=net7.0]

The build failed. Fix the build errors and run again.

Here's the repo if you want to take a look: https://github.com/jinyus/fabulous_video_player_demo

@edgarfgp Could this be a breaking change in Avalonia between the preview versions and the latest stable one?
Fabulous.Avalonia 2.0.0-pre9 is built against Avalonia 11.0.0-preview8.
LibVLCSharp.Avalonia 3.8.1 is built against 11.0.4

Ah, just noticed there is a Fabulous.Avalonia version 2.0.0-pre14 that is more recent but NuGet considers it a lower version...
https://www.nuget.org/packages/Fabulous.Avalonia/2.0.0-pre14

This should work better

@jinyus Opened a PR to attempt making it run on Linux: jinyus/fabulous_video_player_demo#1

jinyus commented

Thanks for the assistance, your PR solved all issues. I will close this issue now.