2222using System . Threading ;
2323using System . Threading . Tasks ;
2424using System . Threading . Tasks . Dataflow ;
25+ using Windows . Foundation ;
2526using Windows . Media . Playback ;
2627using Windows . Storage ;
2728using Windows . Storage . FileProperties ;
2829using Windows . UI ;
2930using ImageUI = Microsoft . UI . Xaml . Controls . Image ;
3031using static Hi3Helper . Logger ;
3132// ReSharper disable PartialTypeWithSinglePart
33+ // ReSharper disable StringLiteralTypo
3234
3335#nullable enable
3436namespace CollapseLauncher . Helper . Background . Loaders
@@ -39,32 +41,36 @@ namespace CollapseLauncher.Helper.Background.Loaders
3941 internal sealed partial class MediaPlayerLoader : IBackgroundMediaLoader
4042 {
4143 private readonly Color _currentDefaultColor = Color . FromArgb ( 0 , 0 , 0 , 0 ) ;
42- private bool _isCanvasCurrentlyDrawing ;
44+ private int _isCanvasCurrentlyDrawing ;
4345
4446 private FrameworkElement ParentUI { get ; }
4547 private Compositor CurrentCompositor { get ; }
4648 private DispatcherQueue CurrentDispatcherQueue { get ; }
47- private static bool IsUseVideoBgDynamicColorUpdate { get => LauncherConfig . IsUseVideoBGDynamicColorUpdate && LauncherConfig . EnableAcrylicEffect ; }
49+ private static bool IsUseVideoBgDynamicColorUpdate
50+ {
51+ get => LauncherConfig . IsUseVideoBGDynamicColorUpdate && LauncherConfig . EnableAcrylicEffect ;
52+ }
4853
4954 private Grid AcrylicMask { get ; }
5055 private Grid OverlayTitleBar { get ; }
5156 public bool IsBackgroundDimm { get ; set ; }
5257
5358 private FileStream ? _currentMediaStream ;
5459 private MediaPlayer ? _currentMediaPlayer ;
55- #if USEFFMPEGFORVIDEOBG
60+ #if USEFFMPEGFORVIDEOBG
5661 private FFmpegMediaSource ? _currentFFmpegMediaSource ;
5762#endif
5863
59- private CanvasImageSource ? _currentCanvasImageSource ;
60- private CanvasBitmap ? _currentCanvasBitmap ;
61- private CanvasDevice ? _currentCanvasDevice ;
62- private readonly int _currentCanvasWidth ;
63- private readonly int _currentCanvasHeight ;
64- private readonly float _currentCanvasDpi ;
65- private readonly MediaPlayerElement ? _currentMediaPlayerFrame ;
66- private readonly Grid _currentMediaPlayerFrameParentGrid ;
67- private readonly ImageUI _currentImage ;
64+ private CanvasVirtualImageSource ? _currentCanvasVirtualImageSource ;
65+ private CanvasBitmap ? _currentCanvasBitmap ;
66+ private CanvasDevice ? _currentCanvasDevice ;
67+ private readonly int _currentCanvasWidth ;
68+ private readonly int _currentCanvasHeight ;
69+ private readonly float _currentCanvasDpi ;
70+ private readonly Rect _currentCanvasDrawArea ;
71+ private readonly MediaPlayerElement ? _currentMediaPlayerFrame ;
72+ private readonly Grid _currentMediaPlayerFrameParentGrid ;
73+ private readonly ImageUI _currentImage ;
6874
6975 internal MediaPlayerLoader (
7076 FrameworkElement parentUI ,
@@ -81,9 +87,11 @@ internal MediaPlayerLoader(
8187 _currentMediaPlayerFrameParentGrid = mediaPlayerParentGrid ;
8288 _currentMediaPlayerFrame = mediaPlayerCurrent ;
8389
84- _currentCanvasWidth = ( int ) _currentMediaPlayerFrameParentGrid . ActualWidth ;
85- _currentCanvasHeight = ( int ) _currentMediaPlayerFrameParentGrid . ActualHeight ;
86- _currentCanvasDpi = 96f ;
90+ _currentCanvasWidth = ( int ) _currentMediaPlayerFrameParentGrid . ActualWidth ;
91+ _currentCanvasHeight = ( int ) _currentMediaPlayerFrameParentGrid . ActualHeight ;
92+ _currentCanvasDpi = 96f ;
93+
94+ _currentCanvasDrawArea = new Rect ( 0 , 0 , _currentCanvasWidth , _currentCanvasHeight ) ;
8795
8896 _currentImage = mediaPlayerParentGrid . AddElementToGridRowColumn ( new ImageUI
8997 {
@@ -125,12 +133,13 @@ public async Task LoadAsync(string filePath, bool isImageLoadF
125133 if ( IsUseVideoBgDynamicColorUpdate )
126134 {
127135 _currentCanvasDevice ??= CanvasDevice . GetSharedDevice ( ) ;
128- _currentCanvasImageSource ??= new CanvasImageSource ( _currentCanvasDevice ,
129- _currentCanvasWidth ,
130- _currentCanvasHeight ,
131- _currentCanvasDpi ,
132- CanvasAlphaMode . Premultiplied ) ;
133- _currentImage . Source = _currentCanvasImageSource ;
136+ _currentCanvasVirtualImageSource ??= new CanvasVirtualImageSource ( _currentCanvasDevice ,
137+ _currentCanvasWidth ,
138+ _currentCanvasHeight ,
139+ _currentCanvasDpi ,
140+ CanvasAlphaMode . Ignore ) ;
141+
142+ _currentImage . Source = _currentCanvasVirtualImageSource . Source ;
134143
135144 byte [ ] temporaryBuffer = ArrayPool < byte > . Shared . Rent ( _currentCanvasWidth * _currentCanvasHeight * 4 ) ;
136145 try
@@ -141,7 +150,7 @@ public async Task LoadAsync(string filePath, bool isImageLoadF
141150 _currentCanvasHeight ,
142151 Windows . Graphics . DirectX . DirectXPixelFormat . B8G8R8A8UIntNormalized ,
143152 _currentCanvasDpi ,
144- CanvasAlphaMode . Premultiplied ) ;
153+ CanvasAlphaMode . Ignore ) ;
145154 }
146155 finally
147156 {
@@ -162,9 +171,8 @@ public async Task LoadAsync(string filePath, bool isImageLoadF
162171
163172#if ! USEFFMPEGFORVIDEOBG
164173 EnsureIfFormatIsDashOrUnsupported ( _currentMediaStream ) ;
165- #endif
166-
167174 _currentMediaPlayer ??= new MediaPlayer ( ) ;
175+ #endif
168176
169177 if ( WindowUtility . IsCurrentWindowInFocus ( ) )
170178 {
@@ -181,26 +189,26 @@ public async Task LoadAsync(string filePath, bool isImageLoadF
181189#if ! USEFFMPEGFORVIDEOBG
182190 _currentMediaPlayer . SetStreamSource ( _currentMediaStream . AsRandomAccessStream ( ) ) ;
183191#else
184-
185- _currentFFmpegMediaSource ??= await FFmpegMediaSource . CreateFromStreamAsync ( CurrentMediaStream . AsRandomAccessStream ( ) ) ;
186-
187- await _currentFFmpegMediaSource . OpenWithMediaPlayerAsync ( CurrentMediaPlayer ) ;
188- const string MediaInfoStrFormat = @" Playing background video with FFmpeg!
189- Media Duration: {0}
190- Video Resolution: {9}x{10} px
191- Video Codec: {1}
192- Video Codec Decoding Method: {3}
193- Video Decoder Engine: {11}
194- Video Bitrate: {2} bps
195- Video Bitdepth: {11} Bits
196- Audio Codec: {4}
197- Audio Bitrate: {5} bps
198- Audio Channel: {6}
199- Audio Sample: {7}Hz
200- Audio Bitwide: {8} Bits
201- " ;
202- Logger . LogWriteLine (
203- string . Format ( MediaInfoStrFormat ,
192+ _currentFFmpegMediaSource ??= await FFmpegMediaSource . CreateFromStreamAsync ( _currentMediaStream . AsRandomAccessStream ( ) ) ;
193+
194+ await _currentFFmpegMediaSource . OpenWithMediaPlayerAsync ( _currentMediaPlayer ) ;
195+ const string mediaInfoStrFormat = """
196+ Playing background video with FFmpeg!
197+ Media Duration: {0}
198+ Video Resolution: {9}x{10} px
199+ Video Codec: {1}
200+ Video Codec Decoding Method: {3}
201+ Video Decoder Engine: {11}
202+ Video Bitrate: {2} bps
203+ Video Bitdepth: {11} Bits
204+ Audio Codec: {4}
205+ Audio Bitrate: {5} bps
206+ Audio Channel: {6}
207+ Audio Sample: {7}Hz
208+ Audio Bitwide: {8} Bits
209+ "" ";
210+ LogWriteLine (
211+ string . Format ( mediaInfoStrFormat ,
204212 _currentFFmpegMediaSource . Duration . ToString ( "c" ) , // 0
205213 _currentFFmpegMediaSource . CurrentVideoStream ? . CodecName ?? "No Video Stream" , // 1
206214 _currentFFmpegMediaSource . CurrentVideoStream ? . Bitrate ?? 0 , // 2
@@ -213,8 +221,7 @@ public async Task LoadAsync(string filePath, bool isImageLoadF
213221 _currentFFmpegMediaSource . CurrentAudioStream ? . BitsPerSample ?? 0 , // 8
214222 _currentFFmpegMediaSource . CurrentVideoStream ? . PixelWidth ?? 0 , // 9
215223 _currentFFmpegMediaSource . CurrentVideoStream ? . PixelHeight ?? 0 , // 10
216- _currentFFmpegMediaSource . CurrentVideoStream ? . BitsPerSample ?? 0 , // 11
217- _currentFFmpegMediaSource . CurrentVideoStream ? . DecoderEngine ?? 0 // 12
224+ _currentFFmpegMediaSource . CurrentVideoStream ? . BitsPerSample ?? 0 // 11
218225 ) , LogType . Debug , true ) ;
219226#endif
220227 _currentMediaPlayer . IsVideoFrameServerEnabled = IsUseVideoBgDynamicColorUpdate ;
@@ -241,24 +248,26 @@ public async Task LoadAsync(string filePath, bool isImageLoadF
241248
242249 public void DisposeMediaModules ( )
243250 {
251+ #if ! USEFFMPEGFORVIDEOBG
244252 if ( _currentMediaPlayer != null )
245253 {
246254 _currentMediaPlayer . VideoFrameAvailable -= FrameGrabberEvent ;
247255 _currentMediaPlayer . Dispose ( ) ;
248256 Interlocked . Exchange ( ref _currentMediaPlayer , null ) ;
249257 }
258+ #endif
250259
251260 if ( IsUseVideoBgDynamicColorUpdate )
252261 {
253- while ( _isCanvasCurrentlyDrawing )
262+ while ( _isCanvasCurrentlyDrawing == 1 )
254263 {
255264 Thread . Sleep ( 100 ) ;
256265 }
257266 }
258267
259- if ( _currentCanvasImageSource != null )
268+ if ( _currentCanvasVirtualImageSource != null )
260269 {
261- Interlocked . Exchange ( ref _currentCanvasImageSource , null ) ;
270+ Interlocked . Exchange ( ref _currentCanvasVirtualImageSource , null ) ;
262271 }
263272
264273 if ( _currentCanvasBitmap != null )
@@ -313,37 +322,34 @@ await ColorPaletteUtility.ApplyAccentColor(ParentUI,
313322 true ) ;
314323 }
315324
316- private static async ValueTask < StorageFile > GetFileAsStorageFile ( string filePath )
325+ private static async Task < StorageFile > GetFileAsStorageFile ( string filePath )
317326 => await StorageFile . GetFileFromPathAsync ( filePath ) ;
318327
319328 private void FrameGrabberEvent ( MediaPlayer mediaPlayer , object args )
320329 {
321- if ( _isCanvasCurrentlyDrawing )
322- {
323- return ;
324- }
325-
326- Interlocked . Exchange ( ref _isCanvasCurrentlyDrawing , true ) ;
330+ CanvasDrawingSession ? drawingSession = null ;
327331 try
328332 {
329- CurrentDispatcherQueue . TryEnqueue ( DispatcherQueuePriority . High , RunImpl ) ;
333+ Interlocked . Exchange ( ref _isCanvasCurrentlyDrawing , 1 ) ;
334+ mediaPlayer . CopyFrameToVideoSurface ( _currentCanvasBitmap ) ;
335+ drawingSession = _currentCanvasVirtualImageSource ? . CreateDrawingSession ( _currentDefaultColor , _currentCanvasDrawArea ) ;
336+ drawingSession ? . DrawImage ( _currentCanvasBitmap ) ;
330337 }
331- catch ( Exception e )
338+ catch
339+ #if DEBUG
340+ ( Exception e )
332341 {
333- LogWriteLine ( $ "[FrameGrabberEvent] Error drawing frame to canvas .\r \n { e } ", LogType . Error , true ) ;
342+ LogWriteLine ( $ "[FrameGrabberEvent] Error while drawing frame to bitmap .\r \n { e } ", LogType . Warning , true ) ;
334343 }
335- finally
344+ #else
336345 {
337- Interlocked . Exchange ( ref _isCanvasCurrentlyDrawing , false ) ;
346+ // ignored
338347 }
339-
340- return ;
341-
342- void RunImpl ( )
348+ #endif
349+ finally
343350 {
344- using CanvasDrawingSession canvasDrawingSession = _currentCanvasImageSource ! . CreateDrawingSession ( _currentDefaultColor ) ;
345- mediaPlayer . CopyFrameToVideoSurface ( _currentCanvasBitmap ) ;
346- canvasDrawingSession . DrawImage ( _currentCanvasBitmap ) ;
351+ CurrentDispatcherQueue . TryEnqueue ( ( ) => drawingSession ? . Dispose ( ) ) ;
352+ Interlocked . Exchange ( ref _isCanvasCurrentlyDrawing , 0 ) ;
347353 }
348354 }
349355
@@ -485,18 +491,18 @@ public void Unmute()
485491 LauncherConfig . SetAndSaveConfigValue ( "BackgroundAudioIsMute" , false ) ;
486492 }
487493
488- private async ValueTask InterpolateVolumeChange ( float from , float to , bool isMute )
494+ private async Task InterpolateVolumeChange ( float from , float to , bool isMute )
489495 {
490- if ( _currentMediaPlayer == null ) return ;
491-
492496 double tFrom = from ;
493497 double tTo = to ;
494498
495499 double current = tFrom ;
496500 double inc = isMute ? - 0.05 : 0.05 ;
497501
498502 Loops :
499- current += inc ;
503+ if ( _currentMediaPlayer == null ) return ;
504+
505+ current += inc ;
500506 _currentMediaPlayer . Volume = current ;
501507
502508 await Task . Delay ( 10 ) ;
0 commit comments