Skip to content

Commit 13acc8f

Browse files
SuRGeoNixumlx5h
authored andcommitted
Updates to v3.8.4 (FlyleafLib) / v1.4.4 (FlyleafME) / v1.1.5 (FlyleafHost.WinUI)
- AudioDecoder: Fixes an issue with ReloadFilters() - VideoDecoder: Fixes an issue with PixelFormat (while software decoding and codec wrongly sets sw_pix_fmt, use pix_fmt instead) - Demuxer: Fixes an issue with BitmapSubtitles auto-increase of analyseduration/probesize [Fixes #502] - Engine.Config: Replaces FFmpegDevices with FFmpegLoadProfile (which by default requires/loads all FFmpeg libs) [Fixes #581] - Config.FormatOpts: Disables by default the new FFmpeg format option extension_picky which causes issues with the allowed extentions [Fixes #577] - PlaylistItem: Introduces MediaTitle for Movies/TVShows - Plugins.OpenDefault: Sets PlaylistItem's OrignalTitle/Title to filename (without removing any parts) in case of non-Movie/TVShow - Plugins.OpenSubtitles: Sets ExternalSubtitlesStream's Title to filename (without removing any parts) - Solution: Few code clean-ups and performance improvements [Breaking Changes] - Engine.Config: Deprecates FFmpegDevices - Engine.FFmpeg: Deprecates DevicesLoaded/FiltersLoaded # Conflicts: # FlyleafLib.Controls.WPF/Config.cs # FlyleafLib.Controls.WPF/FlyleafLib.Controls.WPF.csproj # FlyleafLib.Controls.WinUI/FlyleafLib.Controls.WinUI.csproj # FlyleafLib/Engine/Config.cs # FlyleafLib/Engine/Language.cs # FlyleafLib/FlyleafLib.csproj # FlyleafLib/MediaFramework/MediaPlaylist/PlaylistItem.cs # FlyleafLib/MediaFramework/MediaRenderer/Renderer.VideoProcessor.cs # FlyleafLib/Plugins/OpenSubtitles.cs # FlyleafLib/Utils/Utils.cs # Plugins/OpenSubtitlesOrg/OpenSubtitlesOrg.cs # Plugins/OpenSubtitlesOrg/OpenSubtitlesOrg.csproj # Plugins/TorrentBitSwarm/TorrentBitSwarm.cs # Samples/FlyleafPlayer (WPF Control) (WPF)/App.xaml.cs
1 parent 7b23759 commit 13acc8f

File tree

16 files changed

+249
-153
lines changed

16 files changed

+249
-153
lines changed

FlyleafLib/Engine/Config.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Text.Json.Serialization;
66
using System.Threading;
77
using System.Threading.Tasks;
8+
89
using FlyleafLib.Controls.WPF;
910
using FlyleafLib.MediaFramework.MediaDecoder;
1011
using FlyleafLib.MediaFramework.MediaFrame;
@@ -22,6 +23,8 @@ namespace FlyleafLib;
2223
/// </summary>
2324
public class Config : NotifyPropertyChanged
2425
{
26+
static JsonSerializerOptions jsonOpts = new() { WriteIndented = true };
27+
2528
public Config()
2629
{
2730
// Parse default plugin options to Config.Plugins (Creates instances until fix with statics in interfaces)
@@ -69,6 +72,9 @@ public static Config Load(string path, JsonSerializerOptions jsonOptions = null)
6972
config.Loaded = true;
7073
config.LoadedPath = path;
7174

75+
if (config.Audio.FiltersEnabled && Engine.Config.FFmpegLoadProfile == LoadProfile.Main)
76+
config.Audio.FiltersEnabled = false;
77+
7278
// TODO: L: refactor
7379
config.Player.config = config;
7480
config.Demuxer.config = config;
@@ -131,7 +137,7 @@ public void Save(string path = null, JsonSerializerOptions jsonOptions = null)
131137
path = LoadedPath;
132138
}
133139

134-
jsonOptions ??= new JsonSerializerOptions { WriteIndented = true };
140+
jsonOptions ??= jsonOpts;
135141

136142
File.WriteAllText(path, JsonSerializer.Serialize(this, jsonOptions));
137143
}
@@ -876,7 +882,7 @@ public AudioConfig Clone()
876882
/// 1. Requires FFmpeg avfilter lib<br/>
877883
/// 2. Currently SWR performs better if you dont need filters<br/>
878884
/// </summary>
879-
public bool FiltersEnabled { get => _FiltersEnabled; set { if (Set(ref _FiltersEnabled, value && Engine.FFmpeg.FiltersLoaded)) player?.AudioDecoder.SetupFiltersOrSwr(); } }
885+
public bool FiltersEnabled { get => _FiltersEnabled; set { if (Set(ref _FiltersEnabled, value && Engine.Config.FFmpegLoadProfile != LoadProfile.Main)) player?.AudioDecoder.SetupFiltersOrSwr(); } }
880886
bool _FiltersEnabled = false;
881887

882888
/// <summary>
@@ -1333,14 +1339,13 @@ public class EngineConfig
13331339
public string FFmpegPath { get; set; } = "FFmpeg";
13341340

13351341
/// <summary>
1336-
/// <para>Whether to register av devices or not (gdigrab/dshow/etc.)</para>
1337-
/// <para>When enabled you can pass urls in this format device://[device_name]?[FFmpeg_Url]</para>
1338-
/// <para>device://gdigrab?desktop</para>
1339-
/// <para>device://gdigrab?title=Command Prompt</para>
1340-
/// <para>device://dshow?video=Lenovo Camera</para>
1341-
/// <para>device://dshow?audio=Microphone (Relatek):video=Lenovo Camera</para>
1342+
/// <para>Can be used to choose which FFmpeg libs to load</para>
1343+
/// All (Devices &amp; Filters)<br/>
1344+
/// Filters<br/>
1345+
/// Main<br/>
13421346
/// </summary>
1343-
public bool FFmpegDevices { get; set; }
1347+
public LoadProfile
1348+
FFmpegLoadProfile { get; set; } = LoadProfile.All;
13441349

13451350
/// <summary>
13461351
/// Whether to allow HLS live seeking (this can cause segmentation faults in case of incompatible ffmpeg version with library's custom structures)

FlyleafLib/Engine/Engine.FFmpeg.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ public class FFmpegEngine
55
public string Folder { get; private set; }
66
public string Version { get; private set; }
77

8-
public bool FiltersLoaded { get; set; }
9-
public bool DevicesLoaded { get; set; }
10-
118
const int AV_LOG_BUFFER_SIZE = 5 * 1024;
129
internal AVRational AV_TIMEBASE_Q;
1310

@@ -17,17 +14,14 @@ internal FFmpegEngine()
1714
{
1815
Engine.Log.Info($"Loading FFmpeg libraries from '{Engine.Config.FFmpegPath}'");
1916
Folder = Utils.GetFolderPath(Engine.Config.FFmpegPath);
20-
LoadLibraries(Folder, Engine.Config.FFmpegDevices ? LoadProfile.All : LoadProfile.Filters);
21-
22-
FiltersLoaded = true; // Possible allow only main profile?
23-
DevicesLoaded = Engine.Config.FFmpegDevices;
17+
LoadLibraries(Folder, Engine.Config.FFmpegLoadProfile);
2418

2519
uint ver = avformat_version();
2620
Version = $"{ver >> 16}.{(ver >> 8) & 255}.{ver & 255}";
2721

2822
SetLogLevel();
2923
AV_TIMEBASE_Q = av_get_time_base_q();
30-
Engine.Log.Info($"FFmpeg Loaded (Location: {Folder}, Ver: {Version}) [Devices: {(DevicesLoaded ? "yes" : "no")}, Filters: {(FiltersLoaded ? "yes" : "no")}]");
24+
Engine.Log.Info($"FFmpeg Loaded (Profile: {Engine.Config.FFmpegLoadProfile}, Location: {Folder}, FmtVer: {Version})");
3125
} catch (Exception e)
3226
{
3327
Engine.Log.Error($"Loading FFmpeg libraries '{Engine.Config.FFmpegPath}' failed\r\n{e.Message}\r\n{e.StackTrace}");

FlyleafLib/Engine/Engine.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ private static void StartInternalUI()
144144
Log = new LogHandler("[FlyleafEngine] ");
145145

146146
Audio = new AudioEngine();
147-
if (Config.FFmpegDevices)
147+
if (Config.FFmpegLoadProfile == LoadProfile.All)
148148
AudioDevice.RefreshDevices();
149149
}
150150

@@ -155,7 +155,7 @@ private static void StartInternalNonUI()
155155

156156
FFmpeg = new FFmpegEngine();
157157
Video = new VideoEngine();
158-
if (Config.FFmpegDevices)
158+
if (Config.FFmpegLoadProfile == LoadProfile.All)
159159
VideoDevice.RefreshDevices();
160160
Plugins = new PluginsEngine();
161161
Players = new List<Player>();

FlyleafLib/Engine/Language.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Globalization;
33
using System.Linq;
44
using System.Text.Json.Serialization;
5-
using System.Windows;
65

76
namespace FlyleafLib;
87

FlyleafLib/FlyleafLib.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<UseWPF>true</UseWPF>
88
<RepositoryUrl></RepositoryUrl>
99
<Description>Media Player .NET Library for WinUI 3/WPF/WinForms (based on FFmpeg/DirectX)</Description>
10-
<Version>3.8.3</Version>
10+
<Version>3.8.4</Version>
1111
<Authors>SuRGeoNix</Authors>
1212
<Copyright>SuRGeoNix © 2025</Copyright>
1313
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>

FlyleafLib/MediaFramework/MediaDecoder/AudioDecoder.Filters.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ internal int SetupFiltersOrSwr()
207207
if (Disposed)
208208
return ret;
209209

210-
if (Config.Audio.FiltersEnabled && Engine.FFmpeg.FiltersLoaded)
210+
if (Config.Audio.FiltersEnabled)
211211
{
212212
ret = SetupFilters();
213213

@@ -236,9 +236,12 @@ public int UpdateFilter(string filterId, string key, string value)
236236
}
237237
public int ReloadFilters()
238238
{
239+
if (!Config.Audio.FiltersEnabled)
240+
return -1;
241+
239242
lock (lockActions)
240243
lock (lockCodecCtx)
241-
return !Engine.FFmpeg.FiltersLoaded || Config.Audio.FiltersEnabled ? -1 : SetupFilters();
244+
return SetupFilters();
242245
}
243246

244247
private void ProcessFilters()

FlyleafLib/MediaFramework/MediaDecoder/VideoDecoder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ internal int FillFromCodec(AVFrame* frame)
625625

626626
avcodec_parameters_from_context(Stream.AVStream->codecpar, codecCtx);
627627
VideoStream.AVStream->time_base = codecCtx->pkt_timebase;
628-
VideoStream.Refresh(codecCtx->sw_pix_fmt != AVPixelFormat.None ? codecCtx->sw_pix_fmt : codecCtx->pix_fmt, frame);
628+
VideoStream.Refresh(VideoAccelerated && codecCtx->sw_pix_fmt != AVPixelFormat.None ? codecCtx->sw_pix_fmt : codecCtx->pix_fmt, frame);
629629

630630
if (!(VideoStream.FPS > 0)) // NaN
631631
{

FlyleafLib/MediaFramework/MediaDemuxer/Demuxer.cs

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -587,30 +587,38 @@ public string Open(string url, Stream stream)
587587
// Find Streams Info
588588
if (Config.AllowFindStreamInfo)
589589
{
590-
// TBR: Tested and even if it requires more analyze duration it does not actually use it
591-
bool requiresMoreAnalyse = false;
592-
for (int i = 0; i < fmtCtx->nb_streams; i++)
593-
if (fmtCtx->streams[i]->codecpar->codec_id == AVCodecID.HdmvPgsSubtitle ||
594-
fmtCtx->streams[i]->codecpar->codec_id == AVCodecID.DvdSubtitle
595-
)
596-
{ requiresMoreAnalyse = true; break; }
597-
598-
if (requiresMoreAnalyse)
590+
/* For some reason HdmvPgsSubtitle requires more analysis (even when it has already all the information)
591+
*
592+
* Increases delay & memory and it will not free it after analysis (fmtctx internal buffer)
593+
* - avformat_flush will release it but messes with the initial seek position (possible seek to start to force it releasing it but still we have the delay)
594+
*
595+
* Consider
596+
* - DVD/Blu-ray/mpegts only? (possible HLS -> mpegts?*)
597+
* - Re-open in case of "Consider increasing the value for the 'analyzeduration'" (catch from ffmpeg log)
598+
*
599+
* https://github.com/SuRGeoNix/Flyleaf/issues/502
600+
*/
601+
602+
if (Utils.BytePtrToStringUTF8(fmtCtx->iformat->name) == "mpegts")
599603
{
600-
fmtCtx->probesize = Math.Max(fmtCtx->probesize, 5000 * (long)1024 * 1024); // Bytes
601-
fmtCtx->max_analyze_duration = Math.Max(fmtCtx->max_analyze_duration, 1000 * (long)1000 * 1000); // Mcs
604+
bool requiresMoreAnalyse = false;
605+
606+
for (int i = 0; i < fmtCtx->nb_streams; i++)
607+
if (fmtCtx->streams[i]->codecpar->codec_id == AVCodecID.HdmvPgsSubtitle ||
608+
fmtCtx->streams[i]->codecpar->codec_id == AVCodecID.DvdSubtitle
609+
)
610+
{ requiresMoreAnalyse = true; break; }
611+
612+
if (requiresMoreAnalyse)
613+
{
614+
fmtCtx->probesize = Math.Max(fmtCtx->probesize, 5000 * (long)1024 * 1024); // Bytes
615+
fmtCtx->max_analyze_duration = Math.Max(fmtCtx->max_analyze_duration, 1000 * (long)1000 * 1000); // Mcs
616+
}
602617
}
603618

604619
ret = avformat_find_stream_info(fmtCtx, null);
605620
if (ret == AVERROR_EXIT || Status != Status.Opening || Interrupter.ForceInterrupt == 1) return error = "Cancelled";
606621
if (ret < 0) return error = $"[avformat_find_stream_info] {FFmpegEngine.ErrorCodeToMsg(ret)} ({ret})";
607-
608-
if (requiresMoreAnalyse)
609-
{
610-
// https://github.com/SuRGeoNix/Flyleaf/issues/502
611-
// TODO: L: Fix high memory usage after avformat_find_stream_info temporality when enabling bitmap subtitles
612-
avformat_seek_file(fmtCtx, -1, 0, 0, 0, 0);
613-
}
614622
}
615623

616624
// Prevent Multiple Immediate exit requested on eof (maybe should not use avio_feof() to test for the end)

FlyleafLib/MediaFramework/MediaPlaylist/PlaylistItem.cs

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,31 @@ public class PlaylistItem : DemuxerInput
1515
/// </summary>
1616
public string DirectUrl { get; set; }
1717

18-
//public IOpen OpenPlugin { get; set; }
19-
2018
/// <summary>
2119
/// Relative folder to playlist's folder base (can be empty, not null)
2220
/// Use Path.Combine(Playlist.FolderBase, Folder) to get absolute path for saving related files with the current selection item (such as subtitles)
2321
/// </summary>
2422
public string Folder { get; set; } = "";
2523

26-
27-
//public long StoppedAt { get; set; }
28-
//public long SubtitlesDelay { get; set; }
29-
//public long AudioDelay { get; set; }
24+
public long FileSize { get; set; }
3025

3126
/// <summary>
32-
/// Item's file size
27+
/// Usually just the filename part of the provided Url
3328
/// </summary>
34-
public long FileSize { get; set; }
29+
public string OriginalTitle { get => _OriginalTitle;set => SetUI(ref _OriginalTitle, value ?? "", false); }
30+
string _OriginalTitle = "";
3531

3632
/// <summary>
37-
/// Item's title
38-
/// (can be updated from scrapers)
33+
/// Movie/TVShow Title
3934
/// </summary>
40-
public string Title { get => _Title; set { if (_Title == "") OriginalTitle = value; SetUI(ref _Title, value ?? "", false);} }
41-
string _Title = "";
35+
public string MediaTitle { get => _MediaTitle; set => SetUI(ref _MediaTitle, value ?? "", false); }
36+
string _MediaTitle = "";
4237

4338
/// <summary>
44-
/// Item's original title
45-
/// (setted by opened plugin)
39+
/// Movie/TVShow Title including Movie's Year or TVShow's Season/Episode
4640
/// </summary>
47-
public string OriginalTitle { get => _OriginalTitle; set => SetUI(ref _OriginalTitle, value ?? "", false); }
48-
string _OriginalTitle = "";
41+
public string Title { get => _Title; set { if (_Title == "") OriginalTitle = value; SetUI(ref _Title, value ?? "", false);} }
42+
string _Title = "";
4943

5044
public List<Demuxer.Chapter>
5145
Chapters { get; set; } = new();
@@ -55,17 +49,15 @@ public List<Demuxer.Chapter>
5549
public int Year { get; set; }
5650

5751
public Dictionary<string, object>
58-
Tag { get; set; } = new Dictionary<string, object>();
52+
Tag { get; set; } = [];
5953
public void AddTag(object tag, string pluginName)
6054
{
61-
if (Tag.ContainsKey(pluginName))
55+
if (!Tag.TryAdd(pluginName, tag))
6256
Tag[pluginName] = tag;
63-
else
64-
Tag.Add(pluginName, tag);
6557
}
6658

6759
public object GetTag(string pluginName)
68-
=> Tag.ContainsKey(pluginName) ? Tag[pluginName] : null;
60+
=> Tag.TryGetValue(pluginName, out object value) ? value : null;
6961

7062
public bool SearchedLocal { get; set; }
7163
public bool SearchedOnline { get; set; }
@@ -86,33 +78,60 @@ public ExternalSubtitlesStream[]
8678
{ get; set; } = new ExternalSubtitlesStream[2];
8779

8880
public ObservableCollection<ExternalVideoStream>
89-
ExternalVideoStreams { get; set; } = new ObservableCollection<ExternalVideoStream>();
81+
ExternalVideoStreams { get; set; } = [];
9082
public ObservableCollection<ExternalAudioStream>
91-
ExternalAudioStreams { get; set; } = new ObservableCollection<ExternalAudioStream>();
83+
ExternalAudioStreams { get; set; } = [];
9284
public ObservableCollection<ExternalSubtitlesStream>
93-
ExternalSubtitlesStreamsAll{ get; set; } = new ObservableCollection<ExternalSubtitlesStream>();
85+
ExternalSubtitlesStreamsAll
86+
{ get; set; } = [];
9487
internal object lockExternalStreams = new();
9588

96-
public void AddExternalStream(ExternalStream extStream, PlaylistItem item, string pluginName, object tag = null)
89+
bool filled;
90+
public void FillMediaParts() // Called during OpenScrape (if file) & Open/Search Subtitles (to be able to search online and compare tvshow/movie properly)
91+
{
92+
if (filled)
93+
return;
94+
95+
filled = true;
96+
var mp = Utils.GetMediaParts(OriginalTitle);
97+
Year = mp.Year;
98+
Season = mp.Season;
99+
Episode = mp.Episode;
100+
MediaTitle = mp.Title; // safe title to check with online subs
101+
102+
if (mp.Season > 0 && mp.Episode > 0) // tvshow
103+
{
104+
var title = "S";
105+
title += Season > 9 ? Season : $"0{Season}";
106+
title += "E";
107+
title += Episode > 9 ? Episode : $"0{Episode}";
108+
109+
Title = mp.Title == "" ? title : mp.Title + " (" + title + ")";
110+
}
111+
else if (mp.Year > 0) // movie
112+
Title = mp.Title + " (" + mp.Year + ")";
113+
}
114+
115+
public static void AddExternalStream(ExternalStream extStream, PlaylistItem item, string pluginName, object tag = null)
97116
{
98117
lock (item.lockExternalStreams)
99118
{
100119
extStream.PlaylistItem = item;
101120
extStream.PluginName = pluginName;
102121

103-
if (extStream is ExternalAudioStream)
122+
if (extStream is ExternalAudioStream astream)
104123
{
105-
item.ExternalAudioStreams.Add((ExternalAudioStream)extStream);
124+
item.ExternalAudioStreams.Add(astream);
106125
extStream.Index = item.ExternalAudioStreams.Count - 1;
107126
}
108-
else if (extStream is ExternalVideoStream)
127+
else if (extStream is ExternalVideoStream vstream)
109128
{
110-
item.ExternalVideoStreams.Add((ExternalVideoStream)extStream);
129+
item.ExternalVideoStreams.Add(vstream);
111130
extStream.Index = item.ExternalVideoStreams.Count - 1;
112131
}
113-
else if (extStream is ExternalSubtitlesStream)
132+
else if (extStream is ExternalSubtitlesStream sstream)
114133
{
115-
item.ExternalSubtitlesStreamsAll.Add((ExternalSubtitlesStream)extStream);
134+
item.ExternalSubtitlesStreamsAll.Add(sstream);
116135
extStream.Index = item.ExternalSubtitlesStreamsAll.Count - 1;
117136
}
118137

FlyleafLib/MediaFramework/MediaRenderer/Renderer.VideoProcessor.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Collections.Generic;
22
using System.Numerics;
33
using System.Text.Json.Serialization;
4-
54
using Vortice.DXGI;
65
using Vortice.Direct3D11;
76

0 commit comments

Comments
 (0)