Skip to content
Merged
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
15 changes: 8 additions & 7 deletions TinyPlayer.Core/Extensions/TrackResolver.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System.Globalization;
using TinyPlayer.Core.Models;

namespace TinyPlayer.Core.Extensions;

public static class TrackResolver
{
public static string IsoToLanguageName(this string code, string? codec, uint bitrate, int index, string prefix)
public static string IsoToLanguageName(this string code, MetadataLanguage metadata)
{
string? name = null;

Expand All @@ -18,14 +19,14 @@ public static string IsoToLanguageName(this string code, string? codec, uint bit
return name;
}

// Fallback — кодек + битрейт
if (!string.IsNullOrEmpty(codec))
// Fallback codec + bitrate
if (!string.IsNullOrEmpty(metadata.Codec))
{
return bitrate > 0
? $"{codec} {bitrate / 1000}kbps"
: codec;
return metadata.Bitrate > 0
? $"{metadata.Codec} {metadata.Bitrate / 1000}kbps"
: metadata.Codec;
}

return $"{prefix} {index}";
return $"{metadata.Prefix} {metadata.Index}";
}
}
9 changes: 9 additions & 0 deletions TinyPlayer.Core/Models/MetadataLanguage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace TinyPlayer.Core.Models;

public class MetadataLanguage
{
public string? Codec { get; set; }
public int Index { get; set; }
public uint Bitrate { get; set; }
public string? Prefix { get; set; }
}
34 changes: 29 additions & 5 deletions TinyPlayer.Core/VideoPlayerCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ private void InitPipeline(string uri)

_playbin.SetProperty("flags", new Value((uint)AvFlagsType.EnableAllFlags));

// Waiting for the actual Paused evenе only then is the duration known
// Waiting for the actual Paused even only then is the duration known
_playbin.SetState(State.Paused);
_playbin.GetState(out _, out _, Constants.SECOND * 5);
_playbin.SetState(State.Playing);
Expand Down Expand Up @@ -286,8 +286,8 @@ private void ApplicationCb(object o, SignalArgs args)

private static void TagsCb(object sender, SignalArgs args)
{
var el = sender as Element;
el?.PostMessage(Message.NewApplication(el, new Structure("tags-changed")));
var element = sender as Element;
element?.PostMessage(Message.NewApplication(element, new Structure("tags-changed")));
}

private void AnalyseStreams()
Expand Down Expand Up @@ -328,13 +328,19 @@ private void AnalyseStreams()
}

// Title: Language (if available), otherwise codec, otherwise "Track N"
var title = lang?.IsoToLanguageName(codec, rate, i, "Track");
var title = lang?.IsoToLanguageName(new MetadataLanguage
{
Codec = codec,
Bitrate = rate,
Index = i,
Prefix = "Track"
});

metadata.AudioTracks.Add(new StreamItem { Index = i, Title = title });
sb.AppendLine($"Audio {i}: {title}");
}

// Subtitles
// Subtitles
for (var i = 0; i < metadata.NumOfSubtitles; i++)
{
var tags = (TagList)_playbin.Emit("get-text-tags", i);
Expand All @@ -353,4 +359,22 @@ private void AnalyseStreams()

StreamsAnalysed?.Invoke(this, new StreamsAnalysedEventArgs(metadata, sb.ToString()));
}

public void SetRenderSize(int w, int h)
{
if (_playbin == null)
{
return;
}

var overlay = ((Bin)_playbin)?.GetByInterface(VideoOverlayAdapter.GType);
if (overlay == null)
{
return;
}

var adapter = new VideoOverlayAdapter(overlay.Handle);
adapter.SetRenderRectangle(0, 0, w, h);
adapter.Expose();
}
}
46 changes: 28 additions & 18 deletions TinyPlayer.Desktop/Controls/VideoHost.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

namespace TinyPlayer.Desktop.Controls;
Expand All @@ -8,47 +9,56 @@ namespace TinyPlayer.Desktop.Controls;
/// </summary>
public class VideoHost : HwndHost
{
// Win32
private const int WsChild = 0x40000000;

private const int WsVisible = 0x10000000;

public new IntPtr Handle { get; private set; }

protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
Handle = CreateWindowEx(
0,
"static",
"",
0, "static", "",
WsChild | WsVisible,
0, 0, 100, 100,
hwndParent.Handle,
IntPtr.Zero,
IntPtr.Zero,
0);
IntPtr.Zero, IntPtr.Zero, 0);

return new HandleRef(this, Handle);
}

// When resizing a WPF element, resize the native window to fit the new dimensions
protected override void OnRenderSizeChanged(SizeChangedInfo info)
{
base.OnRenderSizeChanged(info);
if (Handle == IntPtr.Zero)
{
return;
}

var w = (int)info.NewSize.Width;
var h = (int)info.NewSize.Height;

if (w > 0 && h > 0)
{
MoveWindow(Handle, 0, 0, w, h, true);
}
}

protected override void DestroyWindowCore(HandleRef hwnd)
{
DestroyWindow(hwnd.Handle);
}

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr CreateWindowEx(
int exStyle,
string className,
string windowName,
int style,
int x, int y,
int width, int height,
IntPtr parentHandle,
IntPtr menu,
IntPtr instance,
object param);
int exStyle, string className, string windowName, int style,
int x, int y, int width, int height,
IntPtr parentHandle, IntPtr menu, IntPtr instance, object param);

[DllImport("user32.dll")]
private static extern bool DestroyWindow(IntPtr hwnd);

[DllImport("user32.dll")]
private static extern bool MoveWindow(
IntPtr hwnd, int x, int y, int width, int height, bool repaint);
}
21 changes: 17 additions & 4 deletions TinyPlayer.Desktop/View/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@
WindowBackdropType="Mica"
WindowCornerPreference="Round"
WindowStartupLocation="CenterScreen"
WindowState="{Binding WindowState, Mode=TwoWay}"
WindowStyle="{Binding WindowStyle, Mode=TwoWay}"
mc:Ignorable="d">

<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
Expand All @@ -27,7 +34,8 @@
<ui:TitleBar
Title="TinyPlayer"
Grid.Row="0"
Margin="0,0,0,0">
Margin="0,0,0,0"
Visibility="{Binding TitleBarVisibility}">
<ui:TitleBar.Header>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
<ui:Button
Expand Down Expand Up @@ -55,15 +63,20 @@
</ui:TitleBar.Header>
</ui:TitleBar>

<Grid Grid.Row="1" Background="Black">
<Grid
Grid.Row="1"
Background="Black"
MouseLeftButtonDown="VideoGrid_MouseLeftButtonDown"
MouseMove="VideoGrid_MouseMove">
<controls:VideoHost x:Name="VideoSurface" />
</Grid>

<Border
Grid.Row="2"
Margin="12,0,12,12"
Background="{DynamicResource ControlFillColorSecondaryBrush}"
CornerRadius="12,12,0,0">
CornerRadius="12,12,0,0"
Visibility="{Binding IsControlsVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid Margin="12,0" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
Expand Down Expand Up @@ -162,4 +175,4 @@
</Border>

</Grid>
</ui:FluentWindow>
</ui:FluentWindow>
68 changes: 47 additions & 21 deletions TinyPlayer.Desktop/View/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,39 +1,65 @@
using System.Windows.Input;
using TinyPlayer.Desktop.ViewModel;
using Wpf.Ui.Controls;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;

namespace TinyPlayer.Desktop.View
namespace TinyPlayer.Desktop.View;

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : FluentWindow
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : FluentWindow
public MainWindow(MainViewModel viewModel)
{
public MainViewModel Vm { get; }
InitializeComponent();

public MainWindow(MainViewModel viewModel)
{
InitializeComponent();
Vm = viewModel;
DataContext = Vm;

Vm = viewModel;
DataContext = Vm;
Loaded += (_, _) => { Vm.SetVideoHandle(VideoSurface.Handle); };
}

Loaded += (_, _) =>
{
Vm.SetVideoHandle(VideoSurface.Handle);
};
}
public MainViewModel Vm { get; }

private void OnSeekStarted(object sender, MouseButtonEventArgs e)
{
Vm.BeginSeek();
}

private void OnSeekCompleted(object sender, MouseButtonEventArgs e)
{
Vm.EndSeek();
}

private void OnSeekStarted(object sender, MouseButtonEventArgs e)
private void Window_Closed(object sender, EventArgs e)
{
Vm.Dispose();
}

private void VideoGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Vm.OnVideoClick();

if (e.ClickCount == 2)
{
Vm.BeginSeek();
Vm.ToggleFullscreenCommand.Execute(null);
}
}

private void OnSeekCompleted(object sender, MouseButtonEventArgs e)
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
Vm.EndSeek();
Vm.ToggleFullscreenCommand.Execute(null);
}

private void Window_Closed(object sender, EventArgs e) => Vm.Dispose();
base.OnKeyDown(e);
}

private void VideoGrid_MouseMove(object sender, MouseEventArgs e)
{
Vm.OnVideoClick();
}
}
2 changes: 2 additions & 0 deletions TinyPlayer.Desktop/ViewModel/BaseViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public abstract class BaseViewModel : ObservableObject, IDisposable
public ObservableCollection<StreamItem> AudioTracks { get; } = [];
public ObservableCollection<StreamItem> SubtitleTracks { get; } = [];

public readonly List<StreamItem> AllSubtitleTracks = [];

public void Dispose()
{
Core?.Dispose();
Expand Down
Loading