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
109 changes: 107 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,109 @@
# TinyPlayer

## A simple video player based on GStreamer.
## Player Under development
A lightweight video player built with WPF, GStreamer, and the [WPF-UI](https://github.com/lepoco/wpfui) framework featuring a modern Fluent Design interface.

![TinyPlayer Screenshot](Screenshot_en.png)

![TinyPlayer Screenshot](Screenshot_de.png)

## Features

- Video playback via GStreamer pipeline
- Multiple audio track switching
- Subtitle support with track selection
- Volume control with mute toggle
- Seek with progress bar
- Fullscreen mode (hides taskbar)
- Fluent Design with Mica backdrop (Windows 11)
- Auto-hide controls during playback

## Supported Formats

All formats supported by GStreamer - including `mp4`, `mkv`, `avi`, `mov`, `wmv`, `flv`, `webm` and more.

## Requirements

- Windows 10/11
- [.NET 10](https://dotnet.microsoft.com/download)
- [GStreamer 1.x](https://gstreamer.freedesktop.org/download/) (with `d3dvideosink` plugin)

### GStreamer Installation

1. Download and install **GStreamer runtime** [from the official site](https://gstreamer.freedesktop.org/documentation/installing/on-windows.html?gi-language=c)
2. Make sure to select **Complete** installation - not Typical
3. Add GStreamer to your `PATH`:
```
C:\gstreamer\1.0\msvc_x86_64\bin
```

## Getting Started

```bash
git clone https://github.com/Ledrunning/TinyPlayer
cd TinyPlayer
dotnet restore
dotnet build
dotnet run --project TinyPlayer.Desktop
```

## Project Structure

```
TinyPlayer/
├── TinyPlayer.Core/ # GStreamer core library (framework-agnostic)
│ ├── VideoPlayerCore.cs # Pipeline management
│ ├── VideoSinkFactory.cs # Video sink setup & HWND overlay
│ ├── Enums/
│ │ └── AvFlagsType.cs
│ └── Models/
│ ├── MetadataModel.cs
│ └── StreamItem.cs
│
└── TinyPlayer.Desktop/ # WPF UI application
├── View/
│ └── MainWindow.xaml
├── ViewModel/
│ └── MainViewModel.cs
└── Controls/
└── VideoHost.cs # HwndHost for GStreamer overlay
```

## Architecture

TinyPlayer follows **MVVM** pattern using [CommunityToolkit.Mvvm](https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/).

The core library (`TinyPlayer.Core`) has no UI dependencies - it communicates with the ViewModel through events:

| Event | Description |
| ----------------- | --------------------------------------- |
| `PositionChanged` | Current playback position & duration |
| `StreamsAnalysed` | Audio/subtitle track metadata |
| `StateChanged` | Pipeline state (Playing, Paused, Ready) |
| `ErrorOccurred` | Playback errors |
| `EndOfStream` | Playback finished |

## Keyboard Shortcuts

| Key | Action |
| -------------- | ----------------- |
| `Double Click` | Toggle fullscreen |
| `Escape` | Exit fullscreen |

## Dependencies

| Package | Purpose |
| ------------------------------------------------------------------------------------ | -------------------------- |
| [WPF-UI](https://github.com/lepoco/wpfui) | Fluent Design UI framework |
| [CommunityToolkit.Mvvm](https://github.com/CommunityToolkit/dotnet) | MVVM source generators |
| [GtkSharp / GstreamerSharp](https://www.nuget.org/packages/gstreamer-sharp-netcore/) | GStreamer .NET bindings |

## Test Videos

Good sources for testing multiple audio tracks and subtitles:

- [Sintel](https://download.blender.org/demo/movies/Sintel.2010.720p.mkv) - Blender Open Movie, multiple subtitle languages
- [Tears of Steel](https://download.blender.org/demo/movies/ToS/tears_of_steel_1080p.mov) - Blender Open Movie

## License

MIT
Binary file added Screenshot_de.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshot_en.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions TinyPlayer.Core/Events/StreamsAnalysedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using TinyPlayer.Core.Models;

namespace TinyPlayer.Core.Events;

public class StreamsAnalysedEventArgs(MetadataModel metadata, string info) : EventArgs
{
public MetadataModel Metadata { get; } = metadata;
public string StreamInfo { get; } = info;
}
32 changes: 32 additions & 0 deletions TinyPlayer.Core/Extensions/TrackResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Globalization;
using TinyPlayer.Core.Models;

namespace TinyPlayer.Core.Extensions;

public static class TrackResolver
{
public static string IsoToLanguageName(this string code, MetadataLanguage metadata)
{
string? name = null;

if (!string.IsNullOrEmpty(code) && code != "und")
{
name = new CultureInfo(code).EnglishName;
}

if (name != null)
{
return name;
}

// Fallback codec + bitrate
if (!string.IsNullOrEmpty(metadata.Codec))
{
return metadata.Bitrate > 0
? $"{metadata.Codec} {metadata.Bitrate / 1000}kbps"
: metadata.Codec;
}

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; }
}
10 changes: 9 additions & 1 deletion TinyPlayer.Core/Models/MetadataModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@ public class MetadataModel
public int NumOfVideoStreams { get; set; }
public int NumOfAudioStreams { get; set; }
public int NumOfSubtitles { get; set; }
}

// Currently active tracks (from the playbin at the time of analysis)
public int CurrentAudioIndex { get; set; } = 0;
public int CurrentSubtitleIndex { get; set; } = -1; // -1 = no subs

// Pre-defined lists with names — create combo boxes directly from here
public List<StreamItem> AudioTracks { get; } = [];
public List<StreamItem> SubtitleTracks { get; } = [];
}
7 changes: 7 additions & 0 deletions TinyPlayer.Core/Models/StreamItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TinyPlayer.Core.Models;

public class StreamItem
{
public int Index { get; set; }
public string? Title { get; set; } = string.Empty;
}
2 changes: 1 addition & 1 deletion TinyPlayer.Core/TinyPlayer.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<TargetFramework>net10.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand Down
Loading
Loading