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
24 changes: 14 additions & 10 deletions FlyleafLib/Controls/WPF/FlyleafHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ IsStandAlone [ReadOnly]
static int idGenerator = 1;
static nint NONE_STYLE = (nint) (WindowStyles.WS_MINIMIZEBOX | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_VISIBLE); // WS_MINIMIZEBOX required for swapchain

float curResizeRatio;
float curResizeRatioIfEnabled;
double curResizeRatio;
double curResizeRatioIfEnabled;
bool surfaceClosed, surfaceClosing, overlayClosed;
int panPrevX, panPrevY;
bool isMouseBindingsSubscribedSurface;
Expand Down Expand Up @@ -599,17 +599,21 @@ private static void DropChanged(DependencyObject d, DependencyPropertyChangedEve
}
private void UpdateCurRatio()
{
/* TODO (Keep ratio on resize)
* 1) Should 'monitor' renderer's curRatio (includes rotation logic and user cropping)
* 2) Should resize based on Viewport's logic (rounding/ceiling) to avoid 1 pixel more or less for width/height
* 3) Consider default ratio (16:9) as config?
*/

if (!KeepRatioOnResize || IsFullScreen)
return;

if (Player != null && Player.Video.AspectRatio.Value > 0)
curResizeRatio = Player.Video.AspectRatio.Value;
else if (ReplicaPlayer != null && ReplicaPlayer.Video.AspectRatio.Value > 0)
curResizeRatio = ReplicaPlayer.Video.AspectRatio.Value;
else
curResizeRatio = (float)(16.0/9.0);
var player = Player ?? ReplicaPlayer;

curResizeRatioIfEnabled = curResizeRatio;
if (player != null && player.renderer != null && player.renderer.DAR.Value > 0)
curResizeRatioIfEnabled = curResizeRatio = player.renderer.DAR.Value;
else
curResizeRatioIfEnabled = curResizeRatio = 16.0 / 9.0;

Rect screen;

Expand Down Expand Up @@ -1112,7 +1116,7 @@ private void Host_LayoutUpdated(object sender, EventArgs e)
}
private void Player_Video_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (KeepRatioOnResize && e.PropertyName == nameof(Player.Video.AspectRatio) && Player.Video.AspectRatio.Value > 0)
if (KeepRatioOnResize && e.PropertyName == nameof(Player.Video.AspectRatio))
UpdateCurRatio();
}
private void ReplicaPlayer_Video_PropertyChanged(object sender, PropertyChangedEventArgs e)
Expand Down
6 changes: 3 additions & 3 deletions FlyleafLib/Engine/Engine.Audio.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public ObservableCollection<AudioEndpoint>

public event PropertyChangedEventHandler PropertyChanged;

public AudioEngine()
public AudioEngine() // We consider from UI here
{
if (Engine.Config.DisableAudio)
{
Expand All @@ -65,7 +65,7 @@ public void RefreshCapDevices()

var devices = MediaFactory.MFEnumAudioDeviceSources();
foreach (var device in devices)
try { Engine.Audio.CapDevices.Add(new AudioDevice(device.FriendlyName, device.SymbolicLink)); } catch(Exception) { }
try { Engine.Audio.CapDevices.Add(new(device.FriendlyName, device.SymbolicLink)); } catch(Exception) { }
}
}

Expand Down Expand Up @@ -166,7 +166,7 @@ private void RefreshDevices()
{
CurrentDevice.Id = defaultDevice.Id;
CurrentDevice.Name = defaultDevice.FriendlyName;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentDevice)));
PropertyChanged?.Invoke(this, new(nameof(CurrentDevice)));
}

// Fall back to DefaultDevice *Non-UI thread otherwise will freeze (not sure where and why) during xaudio.Dispose()
Expand Down
4 changes: 2 additions & 2 deletions FlyleafLib/Engine/Engine.Video.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public Dictionary<long, GPUAdapter>

private readonly object lockCapDevices = new();

internal VideoEngine()
internal VideoEngine() // We consider from UI here
{
if (DXGI.CreateDXGIFactory1(out Factory).Failure)
throw new InvalidOperationException("Cannot create IDXGIFactory1");
Expand All @@ -48,7 +48,7 @@ public void RefreshCapDevices()

var devices = MediaFactory.MFEnumVideoDeviceSources();
foreach (var device in devices)
try { Engine.Video.CapDevices.Add(new VideoDevice(device.FriendlyName, device.SymbolicLink)); } catch(Exception) { }
try { Engine.Video.CapDevices.Add(new(device.FriendlyName, device.SymbolicLink)); } catch(Exception) { }
}
}

Expand Down
39 changes: 20 additions & 19 deletions FlyleafLib/Engine/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static class Engine
/// <summary>
/// List of active Players
/// </summary>
public static List<Player> Players { get; private set; }
public static List<Player> Players { get; private set; } = [];

public static event EventHandler
Loaded;
Expand Down Expand Up @@ -103,25 +103,28 @@ public static void TimeEndPeriod1()

private static void StartInternal(EngineConfig config = null, bool async = false)
{
lock (lockEngine)
{
if (isLoading)
return;
if (Application.Current == null)
_ = new Application();

isLoading = true;
UIInvokeIfRequired(() =>
{
lock (lockEngine)
{
if (isLoading)
return;

Config = config ?? new EngineConfig();
isLoading = true;

if (Application.Current == null)
_ = new Application();
Config = config ?? new EngineConfig();

StartInternalUI();
StartInternalUI();

if (async)
Task.Run(() => StartInternalNonUI());
else
StartInternalNonUI();
}
if (async)
Task.Run(() => StartInternalNonUI());
else
StartInternalNonUI();
}
});
}

private static void StartInternalUI()
Expand All @@ -138,6 +141,7 @@ private static void StartInternalUI()
SetOutput();
Log = new("[FlyleafEngine] ");
Audio = new();
Video = new();
}

private static void StartInternalNonUI()
Expand All @@ -146,13 +150,10 @@ private static void StartInternalNonUI()
Log.Info($"FlyleafLib {version.Major }.{version.Minor}.{version.Build}");

FFmpeg = new();
Video = new();
Plugins = new();
Players = [];

IsLoaded= true;

if (Config.FFmpegLoadProfile == LoadProfile.All) // Cap Devices (TBR: if UI required)
if (Config.FFmpegLoadProfile == LoadProfile.All)
{
Audio.RefreshCapDevices();
Video.RefreshCapDevices();
Expand Down
16 changes: 8 additions & 8 deletions FlyleafLib/Engine/Globals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,10 @@ public struct AspectRatio : IEquatable<AspectRatio>

public static implicit operator AspectRatio(string value) => new(value);

public float Num { get; set; }
public float Den { get; set; }
public double Num { get; set; }
public double Den { get; set; }

public float Value
public double Value
{
readonly get => Num / Den;
set { Num = value; Den = 1; }
Expand All @@ -211,8 +211,8 @@ public string ValueStr
set => FromString(value);
}

public AspectRatio(float value) : this(value, 1) { }
public AspectRatio(float num, float den) { Num = num; Den = den; }
public AspectRatio(double value) : this(value, 1) { }
public AspectRatio(double num, double den) { Num = num; Den = den; }
public AspectRatio(string value) { Num = Invalid.Num; Den = Invalid.Den; FromString(value); }

public readonly bool Equals(AspectRatio other) => Num == other.Num && Den == other.Den;
Expand Down Expand Up @@ -240,11 +240,11 @@ public void FromString(string value)
if (values.Length < 2)
values = newvalue.ToString().Split('/');

Num = float.Parse(values[0], NumberStyles.Any, CultureInfo.InvariantCulture);
Den = float.Parse(values[1], NumberStyles.Any, CultureInfo.InvariantCulture);
Num = double.Parse(values[0], NumberStyles.Any, CultureInfo.InvariantCulture);
Den = double.Parse(values[1], NumberStyles.Any, CultureInfo.InvariantCulture);
}

else if (float.TryParse(newvalue.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out float result))
else if (double.TryParse(newvalue.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out double result))
{ Num = result; Den = 1; }

else
Expand Down
2 changes: 1 addition & 1 deletion FlyleafLib/FlyleafLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<UseWPF>true</UseWPF>
<RepositoryUrl></RepositoryUrl>
<Description>Media Player .NET Library for WinUI 3/WPF/WinForms (based on FFmpeg/DirectX)</Description>
<Version>3.8.10</Version>
<Version>3.8.11</Version>
<Authors>SuRGeoNix</Authors>
<Copyright>SuRGeoNix © 2025</Copyright>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
Expand Down
2 changes: 1 addition & 1 deletion FlyleafLib/MediaFramework/MediaDecoder/DecoderBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ protected string Open2(StreamBase stream, StreamBase prevStream, bool openStream
stream.Demuxer.EnableStream(stream);

Status = Status.Stopped;
CodecChanged?.Invoke(this);
//CodecChanged?.Invoke(this); // We call this when we successfully decode one frame
}

return null;
Expand Down
26 changes: 10 additions & 16 deletions FlyleafLib/MediaFramework/MediaDecoder/VideoDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public ConcurrentQueue<VideoFrame>
Frames { get; protected set; } = [];
public Renderer Renderer { get; private set; }
public bool VideoAccelerated { get; internal set; }
public bool ZeroCopy { get; internal set; }

public VideoStream VideoStream => (VideoStream) Stream;

Expand Down Expand Up @@ -293,36 +292,30 @@ protected override int Setup(AVCodec* codec)
else
Log.Debug("VA Disabled");

// Can't get data from here?
//var t1 = av_stream_get_side_data(VideoStream.AVStream, AVPacketSideDataType.AV_PKT_DATA_MASTERING_DISPLAY_METADATA, null);
//var t2 = av_stream_get_side_data(VideoStream.AVStream, AVPacketSideDataType.AV_PKT_DATA_CONTENT_LIGHT_LEVEL, null);

// TBR: during swFallback (keyFrameRequiredPacket should not reset, currenlty saved in SWFallback)
keyPacketRequired = false; // allow no key packet after open (lot of videos missing this)
ZeroCopy = false;
filledFromCodec = false;

lastFixedPts = 0; // TBR: might need to set this to first known pts/dts
lastFixedPts = 0; // TBR: might need to set this to first known pts/dts
startPts = VideoStream.StartTimePts;
codecCtx->apply_cropping
= 0;

if (VideoAccelerated)
{
codecCtx->thread_count = 1;
codecCtx->hwaccel_flags |= HWAccelFlags.IgnoreLevel;
if (Config.Decoder.AllowProfileMismatch)
codecCtx->hwaccel_flags|= HWAccelFlags.AllowProfileMismatch;

codecCtx->get_format = getHWformat;
codecCtx->extra_hw_frames = Config.Decoder.MaxVideoFrames;

// D3D11/AV1 Issue: https://trac.ffmpeg.org/ticket/10608 "Static surface pool size exceeded" | Workaround: we use +X margin for the initial_pool_size (not for us/extra frames)
codecCtx->extra_hw_frames = codecCtx->codec_id == AVCodecID.Av1 ? Config.Decoder.MaxVideoFrames + 3 : Config.Decoder.MaxVideoFrames;
}
else
codecCtx->thread_count = Math.Min(Config.Decoder.VideoThreads, codecCtx->codec_id == AVCodecID.Hevc ? 32 : 16);

if (codecCtx->codec_descriptor != null)
isIntraOnly = codecCtx->codec_descriptor->props.HasFlag(CodecPropFlags.IntraOnly);

startPts = VideoStream.StartTimePts;
CodecCtx->apply_cropping = 0;

return 0;
}
internal bool SetupSws()
Expand Down Expand Up @@ -621,15 +614,16 @@ internal int FillFromCodec(AVFrame* frame)
codecChanged = false;
startPts = VideoStream.StartTimePts;
skipSpeedFrames = speed * VideoStream.FPS / Config.Video.MaxOutputFps;
CodecChanged?.Invoke(this);


DisposeFrame(Renderer.LastFrame);
if (VideoStream.PixelFormat == AVPixelFormat.None || !Renderer.ConfigPlanes(frame))
{
Log.Error("[Pixel Format] Unknown");
CodecChanged?.Invoke(this);
return -1234;
}

CodecChanged?.Invoke(this);
return ret;
}
}
Expand Down
Loading