Skip to content

Commit

Permalink
List available ffmpeg decoders in settings, better error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
exelix11 committed Jan 14, 2024
1 parent 4f06f27 commit a39f5c0
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 35 deletions.
11 changes: 6 additions & 5 deletions Client/Core/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,13 @@ public class Options
[JsonIgnore]
public UsbLogLevel UsbLogging = UsbLogLevel.Error;

// Ffmpeg options
public bool HardwareAccel;

// Mark as json ignore the ones that can only be set via command line
[JsonIgnore]
// Ffmpeg options
public string? DecoderName;

// This option is plain bad, it means "pick the first decoder from ffmpeg" which is most likely not what the user wants
// Right now it is only available from the command line, it's always best to manually pick a decoder from its name
[JsonIgnore]
public bool HardwareAccel;

// SDL options
public bool ForceSoftwareRenderer;
Expand Down
9 changes: 3 additions & 6 deletions Client/GUI/ConnectingView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal class ConnectingView : View
readonly DeviceInfo info;
readonly DeviceConnector conn;

CancellationTokenSource src = new();
CancellationTokenSource? src = new();

bool connected;
bool isError;
Expand Down Expand Up @@ -56,10 +56,10 @@ public override async void Created()
}
catch (Exception e)
{
if (src.IsCancellationRequested)
if (src!.IsCancellationRequested)
return;

Console.WriteLine("Player connection failed");
Console.WriteLine($"Player connection failed: {e}");
Conn_OnMessage(e.ToString());
isError = true;
return;
Expand All @@ -70,12 +70,9 @@ public override async void Created()
// if the connection failed it's not needed anymore
// otherwise it's now owned by the player
src = null;

conn.OnMessage -= Conn_OnMessage;
}

Console.WriteLine("Connected");

// This must execute on the main thread
Program.Instance.PostAction(() =>
{
Expand Down
10 changes: 7 additions & 3 deletions Client/GUI/MainView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,15 @@ public MainView()

if (DynamicLibraryLoader.CriticalWarning != null)
Popups.Open(initErrorPopup);

StreamMode = Program.Options.Streaming.Kind;
}

void UpdateDiskPermissionStatus()
public override void EnterForeground()
{
base.EnterForeground();
StreamMode = Program.Options.Streaming.Kind;
}

void UpdateDiskPermissionStatus()
{
HasDiskPermission = Resources.HasDiskAccessPermission();
if (!HasDiskPermission)
Expand Down
81 changes: 77 additions & 4 deletions Client/GUI/OptionsView.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using ImGuiNET;
using LibUsbDotNet;
using SysDVR.Client.Core;
using SysDVR.Client.Platform;
using SysDVR.Client.Targets.Player;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;

Expand Down Expand Up @@ -154,10 +158,24 @@ public void Draw()
string SettingsErrorMessage = "";
Gui.CenterGroup SaveCenter = new();

readonly Gui.Popup PickDecoderPopup = new("Select video decoder");
string DecoderButtonText;
List<LibavUtils.Codec> PickDecoderList = new();

void UpdateDecoderButtonText()
{
if (Program.Options.DecoderName is not null)
DecoderButtonText = $"Disable hardware decoder ({Program.Options.DecoderName})";
else
DecoderButtonText = "Configure hardware-accelerated decoder";
}

public OptionsView()
{
Popups.Add(PathInput.Popup);
Popups.Add(ErrorPopup);
Popups.Add(PickDecoderPopup);
UpdateDecoderButtonText();
}

public void OpenSelectPath(string message, string currentValue, Action<string> setvalue)
Expand Down Expand Up @@ -249,6 +267,7 @@ public override void Draw()
ImGui.Checkbox("Uncap streaming framerate", ref Program.Options.UncapStreaming);
ImGui.Checkbox("Uncap GUI framerate", ref Program.Options.UncapGUI);

ImGui.NewLine();
ImGui.TextWrapped("These options affect the straming quality of SysDVR, the defaults are usually fine");

ImGui.Text("Audio batching"); ImGui.SameLine();
Expand All @@ -266,9 +285,6 @@ public override void Draw()
ImGui.Indent();

ImGui.Checkbox("Force SDL software rendering", ref Program.Options.ForceSoftwareRenderer);
ImGui.Checkbox("Use hardware-accelerated FFMPEG decoder", ref Program.Options.HardwareAccel);
ImGui.NewLine();

ImGui.Checkbox("Print real-time streaming information", ref Program.Options.Debug.Stats);
ImGui.Checkbox("Enable verbose logging", ref Program.Options.Debug.Log);
ImGui.Checkbox("Disable Audio/Video synchronization", ref Program.Options.Debug.NoSync);
Expand All @@ -280,8 +296,21 @@ public override void Draw()
ImGui.Text("GUI scale"); ImGui.SameLine();
ImGui.SliderFloat("##sliderGuiScale", ref Program.Options.GuiFontScale, 0.1f, 4);

ImGui.NewLine();
if (ImGui.Button(DecoderButtonText))
{
if (Program.Options.DecoderName is not null)
{
Program.Options.DecoderName = null;
UpdateDecoderButtonText();
}
else
{
ShowDecoderPickPopup();
}
}

// TODO:
// ffmpeg decoder name
// Usb log level
// other debug options

Expand All @@ -291,10 +320,54 @@ public override void Draw()

PathInput.Draw();
DrawErrorPopup();
DrawDecoderPickerPopup();

Gui.EndWindow();
}

void ShowDecoderPickPopup()
{
Popups.Open(PickDecoderPopup);
PickDecoderList.Clear();
PickDecoderList.AddRange(LibavUtils.GetH264Decoders());
}

void DrawDecoderPickerPopup()
{
if (PickDecoderPopup.Begin(ImGui.GetWindowSize()))
{
Gui.CenterText("Select a decoder to use");
ImGui.TextWrapped("Note that not all decoders may be compatible with your system, revert this option in case of issues.\n" +
"You can get more decoders by obtaining a custom build of ffmpeg libraries (libavcodec) and replacing the one included in SysDVR-Client.\n\n" +
"This feature is intended for mini-PCs like Raspberry pi where software decoding might not be enough. On desktop PCs and smartphones this option should not be used.");

ImGui.NewLine();

var sz = ImGui.GetContentRegionMax() - new Vector2(10, ImGui.GetCursorPosY() + 100);

if (sz.Y < 100)
sz.Y = 100;

ImGui.BeginChildFrame(ImGui.GetID("##CodecList"), sz, ImGuiWindowFlags.NavFlattened);
foreach (var c in PickDecoderList)
{
if (ImGui.Button($"{c.Name}: {c.Description}", new Vector2(sz.X - 10, 0)))
{
Program.Options.DecoderName = c.Name;
UpdateDecoderButtonText();
PickDecoderPopup.RequestClose();
}
}
Gui.MakeWindowScrollable();
ImGui.EndChildFrame();

ImGui.NewLine();

if (Gui.CenterButton("Cancel"))
PickDecoderPopup.RequestClose();
}
}

void DrawErrorPopup()
{
if (ErrorPopup.Begin())
Expand Down
26 changes: 12 additions & 14 deletions Client/Sources/DeviceConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace SysDVR.Client.Sources
{
internal class DeviceConnector
{
public event Action<string> OnMessage;
public event Action<string>? OnMessage;

readonly DeviceInfo Info;
readonly CancellationTokenSource Token;
Expand All @@ -38,16 +38,18 @@ public DeviceConnector(DeviceInfo info, CancellationTokenSource token, Streaming

async Task<StreamingSource> ConnectInternal()
{
StreamingSource source = null;
StreamingSource source;

if (Info.Source == ConnectionType.Net)
source = new TCPBridgeSource(Info, Token.Token, Options);
else if (Info.Source == ConnectionType.Usb)
source = new UsbStreamingSource(
Info.ConnectionHandle as DvrUsbDevice ?? throw new Exception("Invalid device handle"),
Options, Token.Token);
else if (Info.Source == ConnectionType.Stub)
source = new StubSource(Options, Token.Token, 10000);
if (Info.Source == ConnectionType.Net)
source = new TCPBridgeSource(Info, Token.Token, Options);
else if (Info.Source == ConnectionType.Usb)
source = new UsbStreamingSource(
Info.ConnectionHandle as DvrUsbDevice ?? throw new Exception("Invalid device handle"),
Options, Token.Token);
else if (Info.Source == ConnectionType.Stub)
source = new StubSource(Options, Token.Token, 10000);
else
throw new Exception($"Connection source not implemented: {Info.Source}");

source.OnMessage += MessageReceived;
try
Expand Down Expand Up @@ -79,11 +81,7 @@ public async Task<PlayerManager> ConnectForPlayer()
}
catch
{
if (Token.IsCancellationRequested)
return null;

Info?.Dispose();

throw;
}
}
Expand Down
6 changes: 3 additions & 3 deletions Client/Targets/Player/LibavUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace SysDVR.Client.Targets.Player
{
public static class LibavUtils
{
public record Codec(string Name, string Description, AVPixelFormat[] Formats);
public record Codec(string Name, string Description, AVPixelFormat[] Formats, AVCodecID CodecID);

public static unsafe Codec[] GetAllDecoders()
{
Expand All @@ -34,15 +34,15 @@ public static unsafe Codec[] GetAllDecoders()
fmt++;
}

codecs.Add(new Codec(name, desc, formats.ToArray()));
codecs.Add(new Codec(name, desc, formats.ToArray(), c->id));
}
}

return codecs.ToArray();
}

public static IEnumerable<Codec> GetH264Decoders() =>
GetAllDecoders().Where(x => x.Name.Contains("264") || x.Description.Contains("264"));
GetAllDecoders().Where(x => x.CodecID == AVCodecID.AV_CODEC_ID_H264);

public static void PrintAllCodecs()
{
Expand Down

0 comments on commit a39f5c0

Please sign in to comment.