Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions LibVLCSharp.DVD/App.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="LibVLCSharp.DVD.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->

<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>
23 changes: 23 additions & 0 deletions LibVLCSharp.DVD/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}
25 changes: 25 additions & 0 deletions LibVLCSharp.DVD/LibVLCSharp.DVD.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Avalonia" Version="11.3.12" />
<PackageReference Include="Avalonia.Desktop" Version="11.3.12" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.12" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.12" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.12">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="LibVLCSharp" Version="3.9.6" />
<PackageReference Include="LibVLCSharp.Avalonia" Version="3.9.6" />
<PackageReference Include="VideoLAN.LibVLC.Mac" Version="3.1.3.1" />
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.23" />
</ItemGroup>
</Project>
106 changes: 106 additions & 0 deletions LibVLCSharp.DVD/MainWindow.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vlc="clr-namespace:LibVLCSharp.Avalonia;assembly=LibVLCSharp.Avalonia"
x:Class="LibVLCSharp.DVD.MainWindow"
Title="DVD Player - LibVLCSharp"
Width="900" Height="600"
MinWidth="640" MinHeight="480"
Background="#111111"
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaChromeHints="NoChrome"
ExtendClientAreaTitleBarHeightHint="-1">

<Grid RowDefinitions="Auto,*, Auto">

<Grid Grid.Row="0"
Background="#1a1a1a"
Height="36"
ColumnDefinitions="Auto,*,Auto">

<TextBlock Grid.Column="1"
Text="DVD Player - LibVLCSharp"
Foreground="#aaaaaa"
FontSize="13"
VerticalAlignment="Center"
HorizontalAlignment="Center" />

<StackPanel Grid.Column="2"
Orientation="Horizontal">
<Button Content="─"
Click="OnMinimize"
Width="46" Height="36"
Background="Transparent"
Foreground="White"
BorderThickness="0"
FontSize="14" />
<Button Content="□"
Click="OnFullScreen"
Width="46" Height="36"
Background="Transparent"
Foreground="White"
BorderThickness="0"
FontSize="14" />
<Button Content="✕"
Click="OnClose"
Width="46" Height="36"
Background="Transparent"
Foreground="White"
BorderThickness="0"
FontSize="14" />
</StackPanel>
</Grid>


<vlc:VideoView x:Name="VideoView" Grid.Row="1" />

<!-- Bottom control bar -->
<Border Grid.Row="2"
Background="#1a1a1a"
BorderBrush="#333333"
BorderThickness="0,1,0,0"
Padding="12,4">
<Grid RowDefinitions="Auto,Auto">

<Slider Grid.Row="0"
x:Name="TimeSlider"
Minimum="0" Maximum="100" Value="0"
Margin="0,0,0,8"/>


<Grid Grid.Row="1" ColumnDefinitions="Auto,*,Auto">
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="6">
<Button Content="📂 Open ISO"
Click="OnOpenFile"
Padding="12,5"
Background="#2d2d2d"
Foreground="White"
CornerRadius="6"
ToolTip.Tip="Open ISO" />
<Button Content="▶"
Click="OnPlay"
Padding="12,5"
Background="#107c10"
Foreground="White"
CornerRadius="6"
ToolTip.Tip="Play" />
<Button Content="⏸️"
Click="OnPause"
Padding="12,5"
Background="#2d2d2d"
Foreground="White"
CornerRadius="6"
ToolTip.Tip="Pause" />
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="8" VerticalAlignment="Center">
<TextBlock Text="🔊" Foreground="White" VerticalAlignment="Center"/>
<Slider x:Name="VolumeSlider"
Minimum="0" Maximum="100" Value="100"
Width="100"
VerticalAlignment="Center"
ValueChanged="OnVolumeChanged" />
</StackPanel>
</Grid>
</Grid>
</Border>
</Grid>
</Window>
101 changes: 101 additions & 0 deletions LibVLCSharp.DVD/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}
24 changes: 24 additions & 0 deletions LibVLCSharp.DVD/Program.cs
Original file line number Diff line number Diff line change
@@ -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<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}
Loading
Loading