Skip to content

Commit dd70a75

Browse files
committed
Updates to v3.9.6 (FlyleafLib) / v1.5.6 (FlyleafME) / v1.2.6 (FlyleafHost.WinUI)
- Player: Fixes an issue with TaskSnapshot - Renderer.VideoProcessor: Prioritize user's VP selection instead of supported features by VPs - VideoDecoder: Reimplementation of the main decoding loop which now respects MaxVideoFrames/ExtraFrames * It could cause unexpected results with FFmpeg's HW surface pool - VideoDecoder: Handles internally the key frame validation instead of Config.Decoder.KeyFrameValidation * To be able to support both cases dynamically. Might restore config with Auto if required/requested - Samples.FlyleafPlayer: Fixes an issue with key bindings restore during Image/Video views [Breaking Changes] - Config.Decoder: Deprecates KeyFrameValidation (will be handled automatically from the decoder) - Config.Decoder: MaxErrors will be reset on the first successful decoding (instead on each Start of the decoder) * Might add MaxTotalErrors if required/requested
1 parent bb85a08 commit dd70a75

13 files changed

Lines changed: 286 additions & 276 deletions

File tree

FlyleafLib.Controls.WPF/FlyleafLib.Controls.WPF.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFrameworks>net8.0-windows;net10.0-windows</TargetFrameworks>
55
<UseWindowsForms>true</UseWindowsForms>
66
<UseWPF>true</UseWPF>
7-
<Version>1.5.5</Version>
7+
<Version>1.5.6</Version>
88
<Authors>SuRGeoNix</Authors>
99
<Copyright>SuRGeoNix © 2025</Copyright>
1010
<PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression>

FlyleafLib.Controls.WinUI/FlyleafLib.Controls.WinUI.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<UseWinUI>true</UseWinUI>
66
<Nullable>enable</Nullable>
77
<Authors>SuRGeoNix</Authors>
8-
<Version>1.2.5</Version>
8+
<Version>1.2.6</Version>
99
<Copyright>SuRGeoNix © 2025</Copyright>
1010
<PackageProjectUrl>https://github.com/SuRGeoNix/Flyleaf</PackageProjectUrl>
1111
<PackageIcon>Flyleaf.png</PackageIcon>

FlyleafLib/Engine/Config.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -565,12 +565,6 @@ public DecoderConfig Clone()
565565
public bool ShowCorrupted { get => _ShowCorrupted; set => SetUI(ref _ShowCorrupted, value); }
566566
bool _ShowCorrupted;
567567

568-
/// <summary>
569-
/// Ensures that after a key packet receives a also key frame (can create artifacts on some broken formats when disabled and seek issues when enabled)
570-
/// </summary>
571-
public bool KeyFrameValidation { get => _KeyFrameValidation; set => SetUI(ref _KeyFrameValidation, value); }
572-
internal bool _KeyFrameValidation;
573-
574568
/// <summary>
575569
/// Forces low delay (Parses AV_CODEC_FLAG2_FAST or AV_CODEC_FLAG_LOW_DELAY -based on DropFrames- to AVCodecContext) (auto-enabled with MaxLatency)
576570
/// </summary>

FlyleafLib/Engine/Globals.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ public enum VideoProcessors
6868
public enum Cropping
6969
{
7070
None,
71-
Stream,
72-
Codec,
73-
Texture
71+
Stream = 1 << 0,
72+
Codec = 1 << 1,
73+
Texture = 1 << 2
7474
}
7575
public enum ColorSpace : int
7676
{

FlyleafLib/FlyleafLib.csproj

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<PackageIconUrl />
99
<RepositoryUrl></RepositoryUrl>
1010
<Description>Media Player .NET Library for WinUI 3/WPF/WinForms (based on FFmpeg/DirectX)</Description>
11-
<Version>3.9.5</Version>
11+
<Version>3.9.6</Version>
1212
<Authors>SuRGeoNix</Authors>
1313
<Copyright>SuRGeoNix © 2025</Copyright>
1414
<PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression>
@@ -17,17 +17,14 @@
1717
<IncludeSymbols>true</IncludeSymbols>
1818
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
1919
<PackageReleaseNotes>
20-
- Engine.Logger: Adds File Rolling support
21-
- Engine.Config: Introduces LogRollMaxFileSize and LogRollMaxFiles for the new File Rolling impelementation
22-
- Demuxer: Fixes an issue with Data streams that would be falsely included as Misc/Invalid streams instead
23-
- VideoDecoder: Stability and Performance improvements for Open/Setup implementation
24-
- Renderer.VideoProcessor: Fixes an issue with cropping not refreshing the layout
25-
- Player: Introduces OpeningVideoStream event which fires during VideoDecoder's codec open
26-
- Player.Video: Codec now returns the actual codec's name in use by the decoder
27-
- FlyleafHost.Wpf: Fixes an issue with MouseWheel event for attached hosts would fire twice causing Zoom and Rotation to not work properly
20+
- Player: Fixes an issue with TaskSnapshot
21+
- Renderer.VideoProcessor: Prioritize user's VP selection instead of supported features by VPs
22+
- VideoDecoder: Reimplementation of the main decoding loop which now respects MaxVideoFrames/ExtraFrames
23+
- VideoDecoder: Handles internally the key frame validation instead of Config.Decoder.KeyFrameValidation
2824

2925
[Breaking Changes]
30-
- Config.Decoder: Defaults AllowProfileMismatch back to false as it seems that it causes more issues than it resolves
26+
- Config.Decoder: Deprecates KeyFrameValidation (will be handled automatically from the decoder)
27+
- Config.Decoder: MaxErrors will be reset on the first successful decoding (instead on each Start of the decoder)
3128
</PackageReleaseNotes>
3229
</PropertyGroup>
3330

FlyleafLib/MediaFramework/MediaContext/DecoderContext.cs

Lines changed: 22 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,7 @@ public void Flush()
487487
DataDecoder.Flush();
488488
}
489489

490-
// !!! NEEDS RECODING
491-
public long GetVideoFrame(long timestamp = -1)
490+
public void GetVideoFrame(long timestamp = -1)
492491
{
493492
// TBR: Between seek and GetVideoFrame lockCodecCtx is lost and if VideoDecoder is running will already have decoded some frames (Currently ensure you pause VideDecoder before seek)
494493

@@ -508,11 +507,11 @@ public long GetVideoFrame(long timestamp = -1)
508507
if (ret != 0)
509508
{
510509
av_packet_free(&packet);
511-
return -1;
510+
return;
512511
}
513512
}
514513
else
515-
packet = VideoDemuxer.VideoPackets.Dequeue();
514+
packet = VideoDemuxer.VideoPackets.Dequeue(); // TBR: This comes after seek, we shouldn't have packets here?*
516515

517516
if (!VideoDemuxer.EnabledStreams.Contains(packet->stream_index)) { av_packet_free(&packet); continue; }
518517

@@ -526,21 +525,6 @@ public long GetVideoFrame(long timestamp = -1)
526525

527526
var codecType = VideoDemuxer.FormatContext->streams[packet->stream_index]->codecpar->codec_type;
528527

529-
if (codecType == AVMediaType.Video && VideoDecoder.keyPacketRequired)
530-
{
531-
if (packet->flags.HasFlag(PktFlags.Key) || packet->pts == VideoDecoder.startPts)
532-
{
533-
VideoDecoder.keyPacketRequired = false;
534-
VideoDecoder.keyFrameRequired = Config.Decoder._KeyFrameValidation;
535-
}
536-
else
537-
{
538-
if (CanWarn) Log.Warn("Ignoring non-key packet");
539-
av_packet_free(&packet);
540-
continue;
541-
}
542-
}
543-
544528
if (VideoDemuxer.IsHLSLive)
545529
VideoDemuxer.UpdateHLSTime();
546530

@@ -571,102 +555,45 @@ public long GetVideoFrame(long timestamp = -1)
571555
continue;
572556

573557
case AVMediaType.Video:
574-
ret = avcodec_send_packet(VideoDecoder.CodecCtx, packet);
575-
576-
if (VideoDecoder.swFallback)
577-
{
578-
VideoDecoder.SWFallback();
579-
ret = avcodec_send_packet(VideoDecoder.CodecCtx, packet);
580-
}
581-
582-
av_packet_free(&packet);
583558

559+
ret = VideoDecoder.SendAVPacket(packet);
584560
if (ret != 0)
585561
{
586-
allowedErrors--;
587-
if (CanWarn) Log.Warn($"{FFmpegEngine.ErrorCodeToMsg(ret)} ({ret})");
588-
589-
if (allowedErrors == 0) { Log.Error("Too many errors!"); return -1; }
562+
if (ret == AVERROR_EAGAIN)
563+
continue;
590564

591-
continue;
565+
return; // Critical
592566
}
593-
594-
//VideoDemuxer.UpdateCurTime();
595-
596-
var frame = av_frame_alloc();
567+
597568
while (VideoDemuxer.VideoStream != null && !Interrupt)
598569
{
599-
ret = avcodec_receive_frame(VideoDecoder.CodecCtx, frame);
600-
if (ret != 0) { av_frame_unref(frame); break; }
601-
602-
if (VideoDecoder.keyFrameRequired)
603-
{
604-
if (!frame->flags.HasFlag(FrameFlags.Key)) { av_frame_unref(frame); continue; }
605-
VideoDecoder.keyFrameRequired = false;
606-
}
607-
608-
if (frame->best_effort_timestamp != AV_NOPTS_VALUE)
609-
frame->pts = frame->best_effort_timestamp;
610-
else if (frame->pts == AV_NOPTS_VALUE)
611-
{
612-
if (!VideoStream.FixTimestamps)
613-
{
614-
av_frame_unref(frame);
615-
continue;
616-
}
617-
618-
frame->pts = VideoDecoder.lastFixedPts + VideoStream.StartTimePts;
619-
VideoDecoder.lastFixedPts += av_rescale_q(VideoStream.FrameDuration / 10, Engine.FFmpeg.AV_TIMEBASE_Q, VideoStream.AVStream->time_base);
620-
}
621-
622-
if (!VideoDecoder.filledFromCodec)
570+
ret = VideoDecoder.RecvAVFrame();
571+
if (ret != 0)
623572
{
624-
ret = VideoDecoder.FillFromCodec(frame);
573+
if (ret == AVERROR_EAGAIN)
574+
break;
625575

626-
if (ret == -1234)
627-
{
628-
av_frame_free(&frame);
629-
return -1;
630-
}
576+
return; // EOF | Critical
631577
}
632578

633579
// Accurate seek with +- half frame distance
634580
// TBR: Live streams should never been seeked at first place (maybe allow HLSLive?) * can cause infinite loop
635-
if (timestamp != -1 && !VideoDemuxer.IsLive && (long)(frame->pts * VideoStream.Timebase) - VideoDemuxer.StartTime + (VideoStream.FrameDuration / 2) < timestamp)
581+
if (timestamp != -1 && !VideoDemuxer.IsLive && (long)(VideoDecoder.frame->pts * VideoStream.Timebase) - VideoDemuxer.StartTime + (VideoStream.FrameDuration / 2) < timestamp)
636582
{
637-
av_frame_unref(frame);
583+
av_frame_unref(VideoDecoder.frame);
638584
continue;
639585
}
640586

641-
//if (CanInfo) Info($"Asked for {TicksToTime(timestamp)} and got {TicksToTime((long)(frame->pts * VideoStream.Timebase) - VideoDemuxer.StartTime)} | Diff {TicksToTime(timestamp - ((long)(frame->pts * VideoStream.Timebase) - VideoDemuxer.StartTime))}");
642-
VideoDecoder.StartTime = (long)(frame->pts * VideoStream.Timebase) - VideoDemuxer.StartTime;
587+
ret = VideoDecoder.FillAVFrame();
588+
if (ret == 0)
589+
return; // Success
643590

644-
var mFrame = VideoDecoder.Renderer.FillPlanes(frame);
645-
if (mFrame != null)
646-
VideoDecoder.Frames.Enqueue(mFrame);
647-
else if (VideoDecoder.handleDeviceReset)
648-
{
649-
VideoDecoder.HandleDeviceReset();
650-
continue;
651-
}
591+
if (ret == -1234)
592+
return; // Critical
652593

653-
do
654-
{
655-
ret = avcodec_receive_frame(VideoDecoder.CodecCtx, frame);
656-
if (ret != 0) break;
657-
mFrame = VideoDecoder.Renderer.FillPlanes(frame);
658-
if (mFrame != null)
659-
VideoDecoder.Frames.Enqueue(mFrame);
660-
else if (VideoDecoder.handleDeviceReset)
661-
VideoDecoder.HandleDeviceReset();
662-
} while (!VideoDemuxer.Disposed && !Interrupt);
663-
664-
av_frame_free(&frame);
665-
return mFrame.timestamp;
594+
continue;
666595
}
667596

668-
av_frame_free(&frame);
669-
670597
break; // Switch break
671598

672599
default:
@@ -677,7 +604,7 @@ public long GetVideoFrame(long timestamp = -1)
677604

678605
} // While
679606

680-
return -1;
607+
return;
681608
}
682609
public new void Dispose()
683610
{

FlyleafLib/MediaFramework/MediaDecoder/DecoderBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ protected virtual void OnSpeedChanged(double value) { }
1919

2020
internal bool codecChanged;
2121
internal bool filledFromCodec;
22-
protected AVFrame* frame;
22+
internal AVFrame* frame;
2323
protected AVCodecContext* codecCtx;
2424
internal object lockCodecCtx = new();
2525

0 commit comments

Comments
 (0)