diff --git a/LibVLCSharp.DVD/App.axaml b/LibVLCSharp.DVD/App.axaml
new file mode 100644
index 0000000..ec7445d
--- /dev/null
+++ b/LibVLCSharp.DVD/App.axaml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/LibVLCSharp.DVD/App.axaml.cs b/LibVLCSharp.DVD/App.axaml.cs
new file mode 100644
index 0000000..41fbcc3
--- /dev/null
+++ b/LibVLCSharp.DVD/App.axaml.cs
@@ -0,0 +1,23 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+
+namespace LibVLCSharp.DVD;
+
+public partial class App : Application
+{
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = new MainWindow();
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+}
\ No newline at end of file
diff --git a/LibVLCSharp.DVD/LibVLCSharp.DVD.csproj b/LibVLCSharp.DVD/LibVLCSharp.DVD.csproj
new file mode 100644
index 0000000..bc47e91
--- /dev/null
+++ b/LibVLCSharp.DVD/LibVLCSharp.DVD.csproj
@@ -0,0 +1,25 @@
+ο»Ώ
+
+ WinExe
+ net10.0
+ enable
+ app.manifest
+ true
+
+
+
+
+
+
+
+
+
+ None
+ All
+
+
+
+
+
+
+
diff --git a/LibVLCSharp.DVD/MainWindow.axaml b/LibVLCSharp.DVD/MainWindow.axaml
new file mode 100644
index 0000000..3f67bd6
--- /dev/null
+++ b/LibVLCSharp.DVD/MainWindow.axaml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LibVLCSharp.DVD/MainWindow.axaml.cs b/LibVLCSharp.DVD/MainWindow.axaml.cs
new file mode 100644
index 0000000..08cbb96
--- /dev/null
+++ b/LibVLCSharp.DVD/MainWindow.axaml.cs
@@ -0,0 +1,101 @@
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Input;
+using Avalonia.Controls.Primitives;
+using Avalonia.Platform.Storage;
+using LibVLCSharp.Avalonia;
+using LibVLCSharp.Shared;
+
+namespace LibVLCSharp.DVD;
+
+public partial class MainWindow : Window
+{
+ private readonly LibVLC libVLC= new();
+ private MediaPlayer? mediaPlayer;
+
+ public MainWindow(){
+ InitializeComponent();
+ Closing+= OnWindowClosing;
+
+ TimeSlider.AddHandler(PointerPressedEvent, OnTimeSliderPressed, handledEventsToo: true);
+ TimeSlider.AddHandler(PointerReleasedEvent, OnTimeSliderReleased, handledEventsToo: true);
+ }
+
+ private async void OnOpenFile(object? sender, RoutedEventArgs e){
+ var files= await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
+ {
+ Title= "Select a DVD ISO file",
+ AllowMultiple= false,
+ FileTypeFilter= new[]
+ {
+ new FilePickerFileType("DVD ISO Files"){
+ Patterns= new[] { "*.iso" }
+ },
+ new FilePickerFileType("All Files"){
+ Patterns= new[] { "*" }
+ }
+ }
+ });
+
+ if(files.Count==0) return;
+
+ if(mediaPlayer==null){
+ mediaPlayer= new MediaPlayer(libVLC);
+ mediaPlayer.TimeChanged+= OnTimeChanged;
+ VideoView.MediaPlayer= mediaPlayer;
+ }
+ else{
+ mediaPlayer.Stop();
+ }
+
+ var media= new Media(libVLC, $"dvd://{files[0].Path.LocalPath}", FromType.FromLocation);
+ mediaPlayer.Play(media);
+ media.Dispose();
+ }
+
+ private void OnPlay(object? sender, RoutedEventArgs e) => mediaPlayer?.Play();
+ private void OnPause(object? sender, RoutedEventArgs e) => mediaPlayer?.Pause();
+ private void OnStop(object? sender, RoutedEventArgs e) => mediaPlayer?.Stop();
+
+ private void OnClose(object? sender, RoutedEventArgs e) => Close();
+
+ private bool userDragging=false;
+ private void OnTimeSliderPressed(object? sender, PointerPressedEventArgs e) => userDragging=true;
+ private void OnTimeSliderReleased(object? sender, PointerReleasedEventArgs e){
+ userDragging=false;
+ if(mediaPlayer is null || mediaPlayer.Length<=0) return;
+ mediaPlayer.Time= (long)(TimeSlider.Value/100 *mediaPlayer.Length);
+ }
+
+ private void OnTimeChanged(object? sender, MediaPlayerTimeChangedEventArgs e){
+ if(mediaPlayer is null || mediaPlayer.Length<=0 || userDragging) return;
+ global::Avalonia.Threading.Dispatcher.UIThread.Post(() =>
+ {
+ TimeSlider.Value= (double)e.Time/mediaPlayer.Length*100;
+ });
+ }
+
+ private void OnTimeSliderChanged(object? sender, PointerCaptureLostEventArgs e){
+ if(mediaPlayer is null || mediaPlayer.Length<=0) return;
+ mediaPlayer.Time= (long)(TimeSlider.Value/100 *mediaPlayer.Length);
+ }
+
+ private void OnVolumeChanged(object? sender, RangeBaseValueChangedEventArgs e){
+ if(mediaPlayer is not null){
+ mediaPlayer.Volume= (int)e.NewValue;
+ }
+ }
+
+ private void OnMinimize(object? sender, RoutedEventArgs e){
+ WindowState= WindowState==WindowState.Minimized ? WindowState.Normal : WindowState.Minimized;
+ this.Hide();
+ this.Show();
+ }
+ private void OnFullScreen(object? sender, RoutedEventArgs e) => WindowState= WindowState==WindowState.FullScreen ? WindowState.Normal : WindowState.FullScreen;
+
+ private void OnWindowClosing(object? sender, WindowClosingEventArgs e){
+ mediaPlayer?.Stop();
+ mediaPlayer?.Dispose();
+ libVLC.Dispose();
+ }
+}
diff --git a/LibVLCSharp.DVD/Program.cs b/LibVLCSharp.DVD/Program.cs
new file mode 100644
index 0000000..e1c3b1c
--- /dev/null
+++ b/LibVLCSharp.DVD/Program.cs
@@ -0,0 +1,24 @@
+ο»Ώusing Avalonia;
+using System;
+using LibVLCSharp.Shared;
+
+namespace LibVLCSharp.DVD;
+
+class Program
+{
+ // Initialization code. Don't use any Avalonia, third-party APIs or any
+ // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
+ // yet and stuff might break.
+ [STAThread]
+ public static void Main(string[] args){
+ Core.Initialize();
+ BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
+ }
+
+ // Avalonia configuration, don't remove; also used by visual designer.
+ public static AppBuilder BuildAvaloniaApp()
+ => AppBuilder.Configure()
+ .UsePlatformDetect()
+ .WithInterFont()
+ .LogToTrace();
+}
diff --git a/LibVLCSharp.DVD/README.md b/LibVLCSharp.DVD/README.md
new file mode 100644
index 0000000..78a33bf
--- /dev/null
+++ b/LibVLCSharp.DVD/README.md
@@ -0,0 +1,142 @@
+# LibVLCSharp DVD Player Sample
+A cross-platform DVD player sample built with LibVLCSharp and Avalonia UI.
+
+---
+
+## Requirements
+- .NET 10 SDK
+- Avalonia 11.3.12
+- LibVLCSharp 3.9.6
+- LibVLCSharp.Avalonia 3.9.6
+- VideoLAN.LibVLC.Windows 3.0.23 (Windows)
+- VideoLAN.LibVLC.Mac 3.1.3.1 (macOS)
+- **Linux only:** `vlc-plugin-dvd` and `libdvdcss` (required for DVD playback)
+```bash
+sudo pacman -S vlc-plugin-dvd libdvdcss # Arch Linux
+```
+---
+
+## Test DVD ISO (linux)
+This sample was tested using the **Big Buck Bunny NTSC DVD ISO** β a free and legal open-source film by the Blender Foundation.
+- Download: [Big-Buck-Bunny](https://ia801907.us.archive.org/13/items/BigBuckBunny/big-buck-bunny-NTSC.iso)
+- Verify ISO: ls -lh ~/big-buck-bunny-NTSC.iso
+
+### Mount and inspect
+```bash
+sudo mkdir -p /mnt/dvd
+sudo mount -o loop ~/big-buck-bunny-NTSC.iso /mnt/dvd
+ls /mnt/dvd # should contain VIDEO_TS folder
+```
+
+### Test with system VLC first
+```bash
+vlc dvd:///mnt/dvd
+vlc /mnt/dvd/VIDEO_TS/VTS_01_1.VOB # or play specific title
+```
+
+### Unmount when done
+```bash
+sudo umount /mnt/dvd
+```
+---
+
+## Test DVD ISO (windows)
+**Prerequisites**
+- [.NET 10 SDK](https://dotnet.microsoft.com/download)
+- No separate VLC installation needed, as `VideoLAN.LibVLC.Windows` NuGet package bundles the native libraries
+
+**Run**
+```bash
+cd LibVLCSharp.DVD
+dotnet run
+```
+
+**DVD Source Options**
+
+- **Physical DVD drive:** `dvd:///D:/` (replace `D` with your drive letter)
+- **ISO file:** right-click the `.iso` in File Explorer β **Mount**, then use the assigned drive letter: `dvd:///E:/`
+- **VIDEO_TS folder:** `dvd:///C:/path/to/VIDEO_TS`
+
+> **Note:** Encrypted commercial DVDs require `libdvdcss`. The NuGet package does not bundle it. Unencrypted ISOs (e.g. Big Buck Bunny) work without it.
+
+---
+
+## Testing on macOS
+
+**Prerequisites**
+- [.NET 10 SDK](https://dotnet.microsoft.com/download)
+- No separate VLC installation needed, as `VideoLAN.LibVLC.Mac` NuGet package bundles the native libraries
+
+**Run**
+```bash
+cd LibVLCSharp.DVD
+dotnet run
+```
+
+**DVD Source Options**
+
+- **Physical DVD drive** β `dvd:///dev/rdisk2` (verify disk number with `diskutil list`)
+- **ISO file** β mount via Finder (double-click) or terminal:
+```bash
+ hdiutil attach ~/your-file.iso
+```
+ Then use `dvd:///Volumes/VOLUME_NAME/` (volume name shown after mount)
+- **VIDEO_TS folder** β `dvd:///path/to/VIDEO_TS`
+
+> **Note:** Encrypted commercial DVDs require `libdvdcss`, installable via Homebrew: `brew install libdvdcss`. Unencrypted ISOs work without it.
+
+---
+
+## Project Setup
+
+### Create the project
+```bash
+dotnet new install Avalonia.Templates
+dotnet new avalonia.app -n LibVLCSharp.DVD
+```
+
+### Add packages
+```bash
+cd LibVLCSharp.DVD # go to the project directory
+dotnet add package LibVLCSharp
+dotnet add package LibVLCSharp.Avalonia
+dotnet add package VideoLAN.LibVLC.Windows
+dotnet add package VideoLAN.LibVLC.Mac
+# don't need of linux nuget package as linux uses system-installed VLC
+```
+
+### Add to solution
+```bash
+cd ~/libvlcsharp-samples # go to the root directory
+dotnet sln libvlcsharp-samples-windows.sln add LibVLCSharp.DVD/LibVLCSharp.DVD.csproj
+dotnet sln libvlcsharp-samples-mac.sln add LibVLCSharp.DVD/LibVLCSharp.DVD.csproj
+```
+
+---
+
+## Run
+```bash
+dotnet run
+```
+> Then click **π Open ISO**, select your DVD ISO file and it starts playing.
+
+---
+
+## Features
+
+- DVD ISO file picker
+- Play / Pause
+- Seek via timestamp slider
+- Volume control
+- Minimize, fullscreen and close via custom title bar
+
+---
+
+## Key Implementation Notes
+
+- `Core.Initialize()` must be called before Avalonia starts in `Program.cs`
+- DVD URI format: `dvd://`
+- `NavigationMode` in LibVLCSharp 3.9.6 has no `Menu` value, so use `Popup` instead, and cast to `(uint)` since `Navigate()` expects `uint`
+- Slider `PointerPressed`/`PointerReleased` must be registered via `AddHandler(..., handledEventsToo: true)` in the constructor β XAML event binding doesn't fire on Slider thumb interaction in Avalonia
+- `Dispatcher.UIThread.Post()` is required when updating the UI from libvlc's `TimeChanged` event since it fires on a background thread
+- On Linux, `vlc-plugin-dvd` must be installed separately β without it DVD ISO playback fails silently
diff --git a/LibVLCSharp.DVD/app.manifest b/LibVLCSharp.DVD/app.manifest
new file mode 100644
index 0000000..21de074
--- /dev/null
+++ b/LibVLCSharp.DVD/app.manifest
@@ -0,0 +1,18 @@
+ο»Ώ
+
+
+
+
+
+
+
+
+
+
+
+
+