Skip to content

Commit 64b62ba

Browse files
committed
Updating to v3.3.9 / v1.1.13
Ensures decoders are paused on Player's pause (was causing rendering issues) Fixes Pan Zoom In/Out to respect aspect ratio Fixes and Improves Recording to start and stop more accurate and support audio only (moved from demuxers to decoders) Fixes AudioDemuxer to seek within queue Fixes a rare dead lock during seeking and re-syncing (after open/download) subtitiles Controls.WPF: Adds subtitles shadow for better visibility Controls.WPF: Fixes IsRecording bindings Plugins.BitSwarm: Updating to v2.4.2 which fixes a critical issue that sometimes it wouldn't start after pause
1 parent 9df800b commit 64b62ba

File tree

12 files changed

+151
-157
lines changed

12 files changed

+151
-157
lines changed

FlyleafLib.Controls.WPF/Flyleaf.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
<Binding Path="Player.BitRate"/>
6666
<Binding Path="VideoInfo.BitRate"/>
6767
<Binding Path="AudioInfo.BitRate"/>
68-
<Binding Path="VideoDemuxer.IsRecording"/>
68+
<Binding Path="Player.IsRecording"/>
6969
<Binding Path="VideoInfo.DroppedFrames"/>
7070
<Binding Path="GPUUsage"/>
7171
</MultiBinding>

FlyleafLib.Controls.WPF/Flyleaf.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ private void ToggleRecordAction(object obj = null)
623623
{
624624
if (!Player.CanPlay) return;
625625

626-
if (Player.decoder.VideoDemuxer.IsRecording)
626+
if (Player.IsRecording)
627627
Player.StopRecording();
628628
else
629629
{

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFrameworks>net5.0-windows;net472</TargetFrameworks>
55
<UseWindowsForms>true</UseWindowsForms>
66
<UseWPF>true</UseWPF>
7-
<Version>1.1.12</Version>
7+
<Version>1.1.13</Version>
88
<Authors>SuRGeoNix</Authors>
99
<Copyright>SuRGeoNix © 2021</Copyright>
1010
<PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression>
@@ -13,7 +13,10 @@
1313
<PackageIconUrl />
1414
<PackageTags>flyleaf flyleaflib video audio media player element control</PackageTags>
1515
<Description>WPF Media Player Control/Element (based on FlyleafLib)</Description>
16-
<PackageReleaseNotes>Adds Color Themes (based on MaterialDesigninXaml)</PackageReleaseNotes>
16+
<PackageReleaseNotes>
17+
Adds subtitles shadow for better visibility
18+
Fixes IsRecording bindings
19+
</PackageReleaseNotes>
1720
</PropertyGroup>
1821

1922
<ItemGroup>

FlyleafLib.Controls.WPF/MainDictionary.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@
314314
</MenuItem.ItemContainerStyle>
315315
</MenuItem>
316316
<MenuItem Header="HW Acceleration" IsCheckable="True" IsChecked="{Binding VideoConfig.VideoAcceleration}"/>
317-
<MenuItem Header="Record" IsCheckable="True" IsChecked="{Binding Player.IsRecording}" Command="{Binding ToggleRecord}"/>
317+
<MenuItem Header="Record" IsCheckable="True" IsChecked="{Binding Player.IsRecording, Mode=OneWay}" Command="{Binding ToggleRecord}"/>
318318
<MenuItem Header="{Binding PlayerConfig.Speed}" HeaderStringFormat="Speed ({0})">
319319
<MenuItem Header=" x 1" CommandParameter="1" Command="{Binding SetPlaybackSpeed}"/>
320320
<MenuItem Header=" x 2" CommandParameter="2" Command="{Binding SetPlaybackSpeed}"/>

FlyleafLib/FlyleafLib.csproj

Lines changed: 6 additions & 7 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 WPF/WinForms (based on FFmpeg/DirectX)</Description>
11-
<Version>3.3.8</Version>
11+
<Version>3.3.9</Version>
1212
<Authors>SuRGeoNix</Authors>
1313
<Copyright>SuRGeoNix © 2021</Copyright>
1414
<PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression>
@@ -17,12 +17,11 @@
1717
<IncludeSymbols>true</IncludeSymbols>
1818
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
1919
<PackageReleaseNotes>
20-
Improves interrupts implementation
21-
Adds draining support to VideoDecoder.GetNextFrame
22-
Initializes AudioPlayer early to allow changing volume/mute (before opening any input)
23-
Ensures rendering is disabled on initialization
24-
Fixes critical issues with interrupts (could stop the demuxers/decoders)
25-
Fixes critical race condition issues with RunThreadBase (could prevent demuxers/decoders from starting)
20+
Ensures decoders are paused on Player's pause (was causing rendering issues)
21+
Fixes Pan Zoom In/Out to respect aspect ratio
22+
Fixes and Improves Recording to start and stop more accurate and support audio only
23+
Fixes AudioDemuxer to seek within queue
24+
Fixes a rare dead lock during seeking and re-syncing (after open/download) subtitiles
2625
</PackageReleaseNotes>
2726
</PropertyGroup>
2827

FlyleafLib/FlyleafLib.xml

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

FlyleafLib/MediaFramework/MediaContext/DecoderContext.cs

Lines changed: 62 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ public DecoderContext(Config config = null, Control control = null, int uniqueId
8484
VideoDecoder = new VideoDecoder(Config, control, UniqueId);
8585
AudioDecoder = new AudioDecoder(Config, UniqueId, VideoDecoder);
8686
SubtitlesDecoder = new SubtitlesDecoder(Config, UniqueId);
87+
88+
VideoDecoder.recCompleted = RecordCompleted;
89+
AudioDecoder.recCompleted = RecordCompleted;
8790
}
8891
public void Initialize()
8992
{
@@ -626,6 +629,7 @@ public int Seek(long ms = -1, bool foreward = false)
626629

627630
if (ms == -1) ms = GetCurTimeMs();
628631

632+
// Review decoder locks (lockAction should be added to avoid dead locks with flush mainly before lockCodecCtx)
629633
lock (VideoDecoder.lockCodecCtx)
630634
lock (AudioDecoder.lockCodecCtx)
631635
lock (SubtitlesDecoder.lockCodecCtx)
@@ -657,7 +661,7 @@ public int Seek(long ms = -1, bool foreward = false)
657661
{
658662
AudioDecoder.Pause();
659663
AudioDecoder.Flush();
660-
AudioDemuxer.PauseOnQueueFull = true; // Pause() will cause corrupted packets which causes av_read_frame to EOF
664+
AudioDemuxer.PauseOnQueueFull = true;
661665
RequiresResync = true;
662666
}
663667

@@ -673,44 +677,55 @@ public int Seek(long ms = -1, bool foreward = false)
673677
}
674678
public int SeekAudio(long ms = -1, bool foreward = false)
675679
{
676-
int ret = -1;
680+
int ret = 0;
677681

678-
if (AudioDemuxer.Disposed || AudioDecoder.OnVideoDemuxer || !Config.Audio.Enabled) return ret;
682+
if (AudioDemuxer.Disposed || AudioDecoder.OnVideoDemuxer || !Config.Audio.Enabled) return -1;
679683

680684
if (ms == -1) ms = GetCurTimeMs();
681685

686+
long seekTimestamp = CalcSeekTimestamp(AudioDemuxer, ms, ref foreward);
687+
688+
lock (AudioDecoder.lockActions)
682689
lock (AudioDecoder.lockCodecCtx)
683690
{
684-
ret = AudioDemuxer.Seek(CalcSeekTimestamp(AudioDemuxer, ms, ref foreward), foreward);
685-
AudioDecoder.Flush();
686-
}
691+
lock (AudioDemuxer.lockActions)
692+
if (AudioDemuxer.SeekInQueue(seekTimestamp, foreward) != 0)
693+
ret = AudioDemuxer.Seek(seekTimestamp, foreward);
687694

688-
if (VideoDecoder.IsRunning)
689-
{
690-
AudioDemuxer.Start();
691-
AudioDecoder.Start();
695+
AudioDecoder.Flush();
696+
if (VideoDecoder.IsRunning)
697+
{
698+
AudioDemuxer.Start();
699+
AudioDecoder.Start();
700+
}
692701
}
693702

694703
return ret;
695704
}
696705
public int SeekSubtitles(long ms = -1, bool foreward = false)
697706
{
698-
int ret = -1;
707+
int ret = 0;
699708

700-
if (SubtitlesDemuxer.Disposed || SubtitlesDecoder.OnVideoDemuxer || !Config.Subtitles.Enabled) return ret;
709+
if (SubtitlesDemuxer.Disposed || SubtitlesDecoder.OnVideoDemuxer || !Config.Subtitles.Enabled) return -1;
701710

702711
if (ms == -1) ms = GetCurTimeMs();
703712

713+
long seekTimestamp = CalcSeekTimestamp(SubtitlesDemuxer, ms, ref foreward);
714+
715+
lock (SubtitlesDecoder.lockActions)
704716
lock (SubtitlesDecoder.lockCodecCtx)
705717
{
706-
ret = SubtitlesDemuxer.Seek(CalcSeekTimestamp(SubtitlesDemuxer, ms, ref foreward), foreward);
707-
SubtitlesDecoder.Flush();
708-
}
718+
// Currently disabled as it will fail to seek within the queue the most of the times
719+
//lock (SubtitlesDemuxer.lockActions)
720+
//if (SubtitlesDemuxer.SeekInQueue(seekTimestamp, foreward) != 0)
721+
ret = SubtitlesDemuxer.Seek(seekTimestamp, foreward);
709722

710-
if (VideoDecoder.IsRunning)
711-
{
712-
SubtitlesDemuxer.Start();
713-
SubtitlesDecoder.Start();
723+
SubtitlesDecoder.Flush();
724+
if (VideoDecoder.IsRunning)
725+
{
726+
SubtitlesDemuxer.Start();
727+
SubtitlesDecoder.Start();
728+
}
714729
}
715730

716731
return ret;
@@ -994,58 +1009,64 @@ public void PrintStats()
9941009

9951010
#region Recorder
9961011
Remuxer Recorder = new Remuxer();
1012+
public event EventHandler RecordingCompleted;
9971013
public bool IsRecording
9981014
{
999-
get => VideoDemuxer.IsRecording || AudioDemuxer.IsRecording;
1015+
get => VideoDecoder.isRecording || AudioDecoder.isRecording;
10001016
}
10011017
int oldMaxAudioFrames;
1018+
bool recHasVideo;
10021019
public void StartRecording(ref string filename, bool useRecommendedExtension = true)
10031020
{
1004-
oldMaxAudioFrames = -1;
1005-
1006-
if (AudioStream == null || AudioStream.Demuxer.Type == MediaType.Video)
1007-
{
1008-
VideoDemuxer.StartRecording(ref filename, useRecommendedExtension);
1009-
return;
1010-
}
10111021

10121022
if (IsRecording) StopRecording();
10131023

1024+
oldMaxAudioFrames = -1;
1025+
recHasVideo = false;
1026+
10141027
Log("Record Start");
1015-
VideoDemuxer.RecordingCompleted += RecordingCompleted;
1028+
1029+
recHasVideo = !VideoDecoder.Disposed && VideoDecoder.Stream != null;
10161030

10171031
if (useRecommendedExtension)
1018-
filename = $"{filename}.{VideoDemuxer.Extension}";
1032+
filename = $"{filename}.{(recHasVideo ? VideoDecoder.Stream.Demuxer.Extension : AudioDecoder.Stream.Demuxer.Extension)}";
10191033

10201034
Recorder.Open(filename);
1021-
for(int i=0; i<VideoDemuxer.EnabledStreams.Count; i++)
1022-
Log(Recorder.AddStream(VideoDemuxer.AVStreamToStream[VideoDemuxer.EnabledStreams[i]].AVStream).ToString());
1023-
1024-
for(int i=0; i<AudioDemuxer.EnabledStreams.Count; i++)
1025-
Log(Recorder.AddStream(AudioDemuxer.AVStreamToStream[AudioDemuxer.EnabledStreams[i]].AVStream, true).ToString());
1035+
if (recHasVideo)
1036+
Log(Recorder.AddStream(VideoDecoder.Stream.AVStream).ToString());
1037+
1038+
if (!AudioDecoder.Disposed && AudioDecoder.Stream != null)
1039+
Log(Recorder.AddStream(AudioDecoder.Stream.AVStream, !AudioDecoder.OnVideoDemuxer).ToString());
10261040

10271041
if (!Recorder.HasStreams || Recorder.WriteHeader() != 0) return; //throw new Exception("Invalid remuxer configuration");
10281042

10291043
// Check also buffering and possible Diff of first audio/video timestamp to remuxer to ensure sync between each other (shouldn't be more than 30-50ms)
10301044
oldMaxAudioFrames = Config.Decoder.MaxAudioFrames;
1031-
long timestamp = Math.Max(VideoDemuxer.CurTime + VideoDemuxer.BufferedDuration, AudioDemuxer.CurTime + AudioDemuxer.BufferedDuration) + 1500 * 10000;
1045+
//long timestamp = Math.Max(VideoDemuxer.CurTime + VideoDemuxer.BufferedDuration, AudioDemuxer.CurTime + AudioDemuxer.BufferedDuration) + 1500 * 10000;
10321046
Config.Decoder.MaxAudioFrames = Config.Decoder.MaxVideoFrames;
10331047

1034-
VideoDemuxer.StartRecording(Recorder, timestamp);
1035-
AudioDemuxer.StartRecording(Recorder, timestamp);
1048+
VideoDecoder.StartRecording(Recorder);
1049+
AudioDecoder.StartRecording(Recorder);
10361050
}
10371051
public void StopRecording()
10381052
{
10391053
if (oldMaxAudioFrames != -1) Config.Decoder.MaxAudioFrames = oldMaxAudioFrames;
10401054

1041-
VideoDemuxer.RecordingCompleted -= RecordingCompleted;
1042-
VideoDemuxer.StopRecording();
1043-
AudioDemuxer.StopRecording();
1055+
VideoDecoder.StopRecording();
1056+
AudioDecoder.StopRecording();
10441057
Recorder.Dispose();
10451058
oldMaxAudioFrames = -1;
10461059
Log("Record Completed");
10471060
}
1048-
private void RecordingCompleted(object sender, EventArgs e) { StopRecording(); }
1061+
1062+
internal void RecordCompleted(MediaType type)
1063+
{
1064+
if (!recHasVideo || (recHasVideo && type == MediaType.Video))
1065+
{
1066+
StopRecording();
1067+
RecordingCompleted?.Invoke(this, new EventArgs());
1068+
}
1069+
}
10491070
#endregion
10501071

10511072
private void Log(string msg) { Debug.WriteLine($"[{DateTime.Now.ToString("hh.mm.ss.fff")}] [#{UniqueId}] [DecoderContext] {msg}"); }

FlyleafLib/MediaFramework/MediaDecoder/AudioDecoder.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
using FlyleafLib.MediaFramework.MediaStream;
1313
using FlyleafLib.MediaFramework.MediaFrame;
14+
using FlyleafLib.MediaFramework.MediaRemuxer;
1415

1516
namespace FlyleafLib.MediaFramework.MediaDecoder
1617
{
@@ -168,6 +169,15 @@ protected override void RunInternal()
168169
demuxer.AudioPackets.TryDequeue(out IntPtr pktPtr);
169170
packet = (AVPacket*) pktPtr;
170171

172+
if (isRecording)
173+
{
174+
if (!recGotKeyframe && VideoDecoder.StartRecordTime != AV_NOPTS_VALUE && (long)(packet->pts * AudioStream.Timebase) - demuxer.StartTime > VideoDecoder.StartRecordTime)
175+
recGotKeyframe = true;
176+
177+
if (recGotKeyframe)
178+
curRecorder.Write(av_packet_clone(packet), !OnVideoDemuxer);
179+
}
180+
171181
ret = avcodec_send_packet(codecCtx, packet);
172182
av_packet_free(&packet);
173183

@@ -205,6 +215,8 @@ protected override void RunInternal()
205215
}
206216

207217
} while (Status == Status.Running);
218+
219+
if (isRecording) { StopRecording(); recCompleted(MediaType.Audio); }
208220
}
209221

210222
[HandleProcessCorruptedStateExceptions]
@@ -291,5 +303,24 @@ public void DisposeFrames()
291303
}
292304
Frames = new ConcurrentQueue<AudioFrame>();
293305
}
306+
307+
internal Action<MediaType> recCompleted;
308+
Remuxer curRecorder;
309+
bool recGotKeyframe;
310+
internal bool isRecording;
311+
312+
internal void StartRecording(Remuxer remuxer, long startAt = -1)
313+
{
314+
if (Disposed || isRecording) return;
315+
316+
curRecorder = remuxer;
317+
isRecording = true;
318+
recGotKeyframe = VideoDecoder.Disposed || VideoDecoder.Stream == null;
319+
}
320+
321+
internal void StopRecording()
322+
{
323+
isRecording = false;
324+
}
294325
}
295326
}

0 commit comments

Comments
 (0)