From fdd8cf047d0be00c571a9865f1e11f4e70709e6d Mon Sep 17 00:00:00 2001 From: jasonchenwork Date: Mon, 11 Aug 2025 17:36:01 +0800 Subject: [PATCH] =?UTF-8?q?202508111732=20=E8=AA=BF=E6=95=B4=E9=96=8B?= =?UTF-8?q?=E5=8C=85=E5=BB=82=E8=A8=88=E7=AE=97=E9=97=9C=E5=8C=85=E5=BB=82?= =?UTF-8?q?=E6=99=82=E9=96=93=20=E8=AA=BF=E6=95=B4=E5=AF=AB=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DBObj/Artist.cs | 9 +-- DBObj/MyDB.cs | 53 +++----------- DBObj/Song.cs | 10 +-- DBObj/SongData.cs | 60 +++++++-------- DBObj/SongList.cs | 1 - OverlayFormObj/OverlayForm.cs | 36 --------- PrimaryFormParts/PrimaryForm.cs | 15 +--- Program.cs | 2 +- Room.cs | 21 ++---- Services/MediaService.cs | 126 +++++--------------------------- Services/MediaServicePrimary.cs | 71 ++---------------- Services/Video.cs | 2 +- VideoPlayerForm.cs | 76 +++++++++++++------ 13 files changed, 133 insertions(+), 349 deletions(-) diff --git a/DBObj/Artist.cs b/DBObj/Artist.cs index bc7f5f9..d94ea5b 100644 --- a/DBObj/Artist.cs +++ b/DBObj/Artist.cs @@ -15,12 +15,9 @@ namespace DBObj NameSimplified=nameSimplified; } public string getName(bool IsSimplified=false) { return IsSimplified ? NameSimplified : Name; } - public string getName() {return Name;} + public string getName() => Name; + + public override string ToString() => $"Name: {Name}"; - public override string ToString() - { - //return $"Name: {Name}, Phonetic: {Phonetic}, Category: {Category}, Strokes: {Strokes}"; - return $"Name: {Name}"; - } } } \ No newline at end of file diff --git a/DBObj/MyDB.cs b/DBObj/MyDB.cs index 49dc846..30c5295 100644 --- a/DBObj/MyDB.cs +++ b/DBObj/MyDB.cs @@ -119,54 +119,23 @@ namespace DBObj } return dict; } - public void moveNext() - { - cursor++; - } - public void movePrevious() - { - cursor--; - } - public void move(int index) - { - cursor = index; - } - public void moveFirst() - { - cursor = 0; - } - public void moveEnd() - { - cursor = table.Rows.Count - 1; - } - public bool bof() - { - return (cursor < 0) || (table.Rows.Count == 0); - } - public bool eof() - { - return cursor > table.Rows.Count - 1; - } + public void moveNext() => cursor++; + public void movePrevious() => cursor--; + public void move(int index) => cursor = index; + public void moveFirst() => cursor = 0; + public void moveEnd() => cursor = table.Rows.Count - 1; + public bool bof() => (cursor < 0) || (table.Rows.Count == 0); + public bool eof() => cursor > table.Rows.Count - 1; public bool Read() { if (eof()) return false; moveNext(); return !eof(); } - public int recordCount() - { - return table.Rows.Count; - } - public bool found() - { - return table.Rows.Count > 0; - } - public void clear() - { - table.Clear(); - } - - + public int recordCount() => table.Rows.Count; + public bool found() => table.Rows.Count > 0; + public void clear() => table.Clear(); + // INSERT / UPDATE / DELETE 方法 public int ExecuteNonQuery(string query, MySqlParameter[] parameters) { diff --git a/DBObj/Song.cs b/DBObj/Song.cs index 507666e..39dd45e 100644 --- a/DBObj/Song.cs +++ b/DBObj/Song.cs @@ -17,10 +17,10 @@ namespace DBObj FileName=filename; HumanVoice =humanVoice; } - public string getNumber() {return Number;} - public string getName(bool IsSimplified) {return IsSimplified ? Name_Simplified : Name;} - public string getName() { return Name;} - public string getFileName() { return FileName;} - public int getHumanVoice() { return HumanVoice;} + public string getNumber() => Number; + public string getName(bool IsSimplified) => IsSimplified ? Name_Simplified : Name; + public string getName() =>Name; + public string getFileName() => FileName; + public int getHumanVoice() => HumanVoice; } } \ No newline at end of file diff --git a/DBObj/SongData.cs b/DBObj/SongData.cs index 5225671..8f5112e 100644 --- a/DBObj/SongData.cs +++ b/DBObj/SongData.cs @@ -20,14 +20,9 @@ namespace DBObj public SongData(string songNumber, string song, string artistA, string artistB, string filename, string artistASimplified, string artistBSimplified, string songSimplified, int humanVoice) { basic=new(songNumber,song,songSimplified,filename,humanVoice); - A= new Artist(artistA, artistASimplified); - if(!artistB.Equals("")){ - B = new Artist(artistB, artistBSimplified); - } else - { - B = null; - } - isPublicSong = false; + A = new Artist(artistA, artistASimplified); + B = !artistB.Equals("") ? new Artist(artistB, artistBSimplified) : null; + isPublicSong = false; } public SongData(SongData value,PlayState s){ basic = value.getBasic(); @@ -39,15 +34,15 @@ namespace DBObj public Artist getA() => A; public Artist getB() => B; - public string getNumber() {return basic.getNumber();} - public string getName(bool IsSimplified=false) { return basic.getName(IsSimplified); } - public string getName() { return basic.getName();} - public string getArtist_A(bool IsSimplified) { return A.getName(IsSimplified); } - public string getArtist_A() { return A.getName();} - public string getArtist_B(bool IsSimplified) { return B.getName(IsSimplified); } - public string getArtist_B() { return B.getName();} - public int getNameLength() { return basic.getName().Length; } - public string getFileName() {return basic.getFileName();} + public string getNumber() => basic.getNumber(); + public string getName(bool IsSimplified=false) => basic.getName(IsSimplified); + public string getName() => basic.getName(); + public string getArtist_A(bool IsSimplified) => A.getName(IsSimplified); + public string getArtist_A() => A.getName(); + public string getArtist_B(bool IsSimplified) => B.getName(IsSimplified); + public string getArtist_B() => B.getName(); + public int getNameLength() =>basic.getName().Length; + public string getFileName() => basic.getFileName(); public string next_song_text() { var str = (state == PlayState.InsertPlayback) ? GetStateTxt(false) : ""; @@ -101,26 +96,21 @@ namespace DBObj } return null; // 找不到就回原本的 filename,不加路徑 } - public Color GetStateColor(){ - Color c = Color.White; - if (state == PlayState.Played) c = Color.Gray;//Color.FromArgb(200, 75, 125); // 播畢顏色:紫紅色 - else if (state == PlayState.Skipped)c = Color.Gray; - else if (state == PlayState.NoFile)c = Color.Gray; - else if (state == PlayState.Playing)c = Color.LimeGreen; - else if (state == PlayState.InsertPlayback)c = Color.Gold; - return c; - } - public string GetStateTxt(bool IsSimplified){ - return (state==PlayState.NotPlayed)?"":$"({state.GetDescription(IsSimplified)})"; - } + public Color GetStateColor() => state switch + { + PlayState.Played => Color.Gray, + PlayState.Skipped => Color.Gray, + PlayState.NoFile => Color.Gray, + PlayState.Playing => Color.LimeGreen, + PlayState.InsertPlayback => Color.Gold, + _ => Color.White + }; + public string GetStateTxt(bool IsSimplified) => (state==PlayState.NotPlayed)?"":$"({state.GetDescription(IsSimplified)})"; public void SetState(PlayState s) => state = s; - public PlayState GetState() - { - return state; - } - - public int getHumanVoice() { return basic.getHumanVoice(); } + public PlayState GetState() => state; + + public int getHumanVoice() => basic.getHumanVoice(); public override string ToString() { return String.Format("{0} {1}", basic.getName(),state.GetDescription() ); diff --git a/DBObj/SongList.cs b/DBObj/SongList.cs index 02542ea..08e41fb 100644 --- a/DBObj/SongList.cs +++ b/DBObj/SongList.cs @@ -162,7 +162,6 @@ namespace DBObj } public static void clearSong() { - isWelcome = true; not_played.Clear(); played.Clear(); diff --git a/OverlayFormObj/OverlayForm.cs b/OverlayFormObj/OverlayForm.cs index fcee082..7aa6633 100644 --- a/OverlayFormObj/OverlayForm.cs +++ b/OverlayFormObj/OverlayForm.cs @@ -38,7 +38,6 @@ namespace OverlayFormObj private int topMargin; private int bottomMargin; public static System.Windows.Forms.Timer displayTimer = new System.Windows.Forms.Timer(); - public static System.Timers.Timer songDisplayTimer = new System.Timers.Timer(); public static System.Timers.Timer unifiedTimer; private System.Windows.Forms.Timer stickerTimer1 = new System.Windows.Forms.Timer(); private System.Windows.Forms.Timer stickerTimer2 = new System.Windows.Forms.Timer(); @@ -360,12 +359,6 @@ namespace OverlayFormObj displayTimer.Interval = 15000; displayTimer.Tick += DisplayTimer_Tick; - songDisplayTimer = new System.Timers.Timer(30000); - songDisplayTimer.Elapsed += new ElapsedEventHandler(SongDisplayTimer_Elapsed); - songDisplayTimer.AutoReset = true; - songDisplayTimer.Enabled = true; - - unifiedTimer = new System.Timers.Timer(15000); unifiedTimer.Elapsed += new ElapsedEventHandler(UnifiedTimer_Elapsed); @@ -416,35 +409,6 @@ namespace OverlayFormObj displayTimer.Stop(); // 停止计时器 } - // 當 songDisplayTimer 計時完成時會呼叫此函式 - private static void SongDisplayTimer_Elapsed(object sender, EventArgs e) - { - // 檢查是否需要跨執行緒操作 UI 控制項 - if (MainForm.InvokeRequired) - { - // 如果目前不在 UI 執行緒上,必須透過 Invoke 安全執行 UI 更新邏輯 - Console.WriteLine("SongDisplayTimer_Tick invoked on UI thread."); - - MainForm.BeginInvoke(new Action(() => - { - if (MainForm.topLeftLabel != null) - MainForm.topLeftLabel.Visible = true; - })); - } - else - { - // 如果已經在 UI 執行緒,就直接更新 UI 控制項 - Console.WriteLine("SongDisplayTimer_Tick invoked on background thread."); - //MainForm.songDisplayLabel.Text = ""; - MainForm.topLeftLabel.Visible = true; - } - - // 停止計時器,避免重複觸發 - songDisplayTimer.Stop(); - } - - - private readonly object _lockObject = new object(); private bool _handlingTimeout = false; private async void UnifiedTimer_Elapsed(object sender, EventArgs e) diff --git a/PrimaryFormParts/PrimaryForm.cs b/PrimaryFormParts/PrimaryForm.cs index 8a1c05e..ea8e945 100644 --- a/PrimaryFormParts/PrimaryForm.cs +++ b/PrimaryFormParts/PrimaryForm.cs @@ -175,7 +175,6 @@ namespace DualScreenDemo private PictureBox serviceBellPictureBox; // 添加为类成员变量 private Timer autoRefreshTimer; - private TimeSpan remainingTime; private Timer timerCountdown; string Rtime; @@ -232,7 +231,7 @@ namespace DualScreenDemo timerCountdown = new Timer(); timerCountdown.Interval = 1000; // 1 second timerCountdown.Tick += TimerCountdown_Tick; - + timerCountdown.Start(); } // 添加 DPI 感知支持 @@ -252,18 +251,10 @@ namespace DualScreenDemo } } - - public void RoomTimeStart() - { - //DateTime now = DateTime.Now; - //DateTime tenMinutesLater = now.AddMinutes(120); - //remainingTime = tenMinutesLater - now; - remainingTime = Program.room.timePeriod; - timerCountdown.Start(); - } - private async void TimerCountdown_Tick(object sender, EventArgs e) { + TimeSpan remainingTime = Program.room.getTimeSpan(); + if (remainingTime.TotalSeconds > 0) { remainingTime = remainingTime.Subtract(TimeSpan.FromSeconds(1)); diff --git a/Program.cs b/Program.cs index f813674..a0f9168 100644 --- a/Program.cs +++ b/Program.cs @@ -13,7 +13,7 @@ namespace DualScreenDemo private static PrimaryForm primaryForm; // 儲存實例的參考 public static Room room = new Room(); - public static string verSion = "Server V2.8 202508081823"; + public static string verSion = "Server V2.8 202508111732"; [STAThread] static void Main() diff --git a/Room.cs b/Room.cs index bfaf56c..e0fee8c 100644 --- a/Room.cs +++ b/Room.cs @@ -13,8 +13,7 @@ namespace DualScreenDemo private string State = "error"; private DateTime? startedAt; private DateTime? endedAt; - public TimeSpan timePeriod; - + public Room() { hostName = System.Net.Dns.GetHostName(); @@ -47,14 +46,13 @@ namespace DualScreenDemo var Statedb = db.Field("status"); startedAt = ParseTime(db.Field("started_at")); endedAt = ParseTime(db.Field("ended_at")); - timePeriod = (TimeSpan)(endedAt - DateTime.Now); - PrimaryForm.Instance.RoomTimeStart(); if (Statedb.Equals("maintain")) { Statedb = "active"; } return Statedb; } } return "error"; } + public TimeSpan getTimeSpan() => (endedAt!=null && endedAt.HasValue) ?(TimeSpan)(endedAt.Value - DateTime.Now):TimeSpan.Zero; public void setDB(string value) { using (var db = new MyDB()) @@ -72,13 +70,9 @@ namespace DualScreenDemo { string StateDB=getDB(); if (!StateDB.Equals(State)) - { State = StateDB; - } else - { return; - } string marqueeMessage = "歡迎使用超級巨星歡唱,與你共度美好時光。"; Color c = Color.White; @@ -119,14 +113,9 @@ namespace DualScreenDemo return dt; return null; } - public bool IsClose() - { - return State.Equals("closed"); - } - public bool IsOpen() - { - return State.Equals("active"); - } + public bool IsClose() => State.Equals("closed"); + + public bool IsOpen() => State.Equals("active"); } diff --git a/Services/MediaService.cs b/Services/MediaService.cs index 56ef7c5..cc30384 100644 --- a/Services/MediaService.cs +++ b/Services/MediaService.cs @@ -8,63 +8,12 @@ namespace DualScreenDemo.Services { public IGraphBuilder graphBuilder; private IMediaControl mediaControl; - private IBaseFilter videoRenderer; + public IBaseFilter renderer; + //private IBaseFilter audioRenderer; private IBaseFilter lavSplitter; - private IBaseFilter lavVideoDecoder; - private IBaseFilter lavAudioDecoder; - private IPin outputPin; - private IBaseFilter audioRenderer; - private IVideoWindow videoWindow; - - - public int Run() - { - if (mediaControl != null) - return mediaControl.Run(); - else - return 0; - } - public int Stop() - { - if (mediaControl != null) - return mediaControl.Stop(); - else - return 0; - - } - public int Pause() - { - if (mediaControl != null) - return mediaControl.Pause(); - else - return 0; - } - public void VideoPlayerFormClosing() - { - if (videoWindow != null) - { - videoWindow.put_Visible(OABool.False); - videoWindow.put_Owner(IntPtr.Zero); - Marshal.ReleaseComObject(videoWindow); - videoWindow = null; - } - } - public void StopAndReleaseResources() - { - if (mediaControl != null) - { - mediaControl.Stop(); - SafeRelease(ref mediaControl); - } - SafeRelease(ref videoWindow); - SafeRelease(ref videoRenderer); - SafeRelease(ref lavAudioDecoder); - SafeRelease(ref outputPin); - SafeRelease(ref lavVideoDecoder); - SafeRelease(ref lavSplitter); - SafeRelease(ref graphBuilder); - - } + public int Run() => (mediaControl != null) ? mediaControl.Run() : 0; + public int Stop() => (mediaControl != null) ? mediaControl.Stop() : 0; + public int Pause() => (mediaControl != null) ? mediaControl.Pause() : 0; public bool isAtEnd() { bool isAtEnd = false; @@ -92,42 +41,22 @@ namespace DualScreenDemo.Services } return isAtEnd; } - public void RenderMediaFile(string filePath, nint Handle, int Width, int Height) + public void RenderMediaFile(string filePath) { - StopAndReleaseResources(); - if (videoWindow != null) videoWindow.put_Visible(OABool.False); + Stop(); + SafeRelease(ref renderer); + SafeRelease(ref lavSplitter); + SafeRelease(ref graphBuilder); + int hr = 0; graphBuilder = (IGraphBuilder)new FilterGraph(); - if (graphBuilder == null) - { - Console.WriteLine("Failed to create FilterGraph"); - throw new Exception("Failed to create FilterGraph"); - } try { lavSplitter = AddFilterByClsid(graphBuilder, "LAV Splitter", Clsid.LAVSplitter); - lavVideoDecoder = AddFilterByClsid(graphBuilder, "LAV Video Decoder", Clsid.LAVVideoDecoder); - lavAudioDecoder = AddFilterByClsid(graphBuilder, "LAV Audio Decoder", Clsid.LAVAudioDecoder); - outputPin = FindPin(lavAudioDecoder, "Output"); - videoRenderer = AddFilterByClsid(graphBuilder, "Secondary Video Renderer", Clsid.VideoRenderer); - if (videoRenderer == null) - { - Console.WriteLine("Failed to initialize Secondary Video Renderer."); - return; - } - hr = graphBuilder.AddFilter(videoRenderer, "Secondary Video Renderer"); - DsError.ThrowExceptionForHR(hr); - var clsidAudioRenderer = new Guid("79376820-07D0-11CF-A24D-0020AFD79767"); // CLSID for DirectSound Renderer - audioRenderer = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(clsidAudioRenderer)); - hr = graphBuilder.AddFilter(audioRenderer, "Default DirectSound Device"); - DsError.ThrowExceptionForHR(hr); - + AddFilterByClsid(graphBuilder, "LAV Video Decoder", Clsid.LAVVideoDecoder); + renderer = AddFilterByClsid(graphBuilder, "Secondary Video Renderer", Clsid.VideoRenderer); + //audioRenderer = AddFilterByClsid(graphBuilder, "Default DirectSound Device", Clsid.AudioRenderer); mediaControl = (IMediaControl)graphBuilder; - if (mediaControl == null) - { - Console.WriteLine("Failed to get Media Control"); - return; - } } catch (Exception ex) { @@ -135,40 +64,25 @@ namespace DualScreenDemo.Services } hr = graphBuilder.RenderFile(filePath, null); if (hr == 0) - { - Console.WriteLine("Secondary File rendered successfully."); SetAudioTrackTo(1); - } else - { Console.WriteLine("Failed to render secondary file."); - } - // 绑定视频窗口到副屏幕 - videoWindow = videoRenderer as IVideoWindow; - if (videoWindow != null) - { - videoWindow.put_Owner(Handle); // 副屏幕窗口句柄 - videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings); - videoWindow.SetWindowPosition(0, 0, Width, Height); - videoWindow.put_Visible(OABool.True); // 显示窗口 - } + } public void SetVolume(int volume) { - if (audioRenderer != null) + if (graphBuilder != null) { - IBasicAudio basicAudio = audioRenderer as IBasicAudio; + IBasicAudio basicAudio = graphBuilder as IBasicAudio; if (basicAudio != null) - { - basicAudio.put_Volume(volume); - } + basicAudio.put_Volume( Math.Max(-10000, Math.Min(0, volume))); } } public int GetVolume() { - if (audioRenderer != null) + if (graphBuilder != null) { - IBasicAudio basicAudio = audioRenderer as IBasicAudio; + IBasicAudio basicAudio = graphBuilder as IBasicAudio; if (basicAudio != null) { int volume; diff --git a/Services/MediaServicePrimary.cs b/Services/MediaServicePrimary.cs index 78a769b..cd9f62e 100644 --- a/Services/MediaServicePrimary.cs +++ b/Services/MediaServicePrimary.cs @@ -9,46 +9,14 @@ namespace DualScreenDemo.Services IGraphBuilder graphBuilder; IBaseFilter lavSplitter; IBaseFilter lavVideoDecoder; - IBaseFilter videoRenderer; - IVideoWindow videoWindow; + public IBaseFilter videoRenderer; IMediaControl mediaControl; IBaseFilter sourceFilter; - - public MediaServicePrimary() { } - public int Run() - { - if (mediaControl != null) - return mediaControl.Run(); - else - return 0; - } - public int Stop() - { - if (mediaControl != null) - return mediaControl.Stop(); - else - return 0; - - } - public int Pause() - { - if (mediaControl != null) - return mediaControl.Pause(); - else - return 0; - } - public void VideoPlayerFormClosing() - { - if (videoWindow != null) - { - videoWindow.put_Visible(OABool.False); - videoWindow.put_Owner(IntPtr.Zero); - Marshal.ReleaseComObject(videoWindow); - videoWindow = null; - } - } + public int Run() => (mediaControl != null) ? mediaControl.Run() : 0; + public int Stop() => (mediaControl != null)? mediaControl.Stop() : 0; + public int Pause() => (mediaControl != null) ? mediaControl.Pause() : 0; public void StopAndReleaseResources() { @@ -57,7 +25,6 @@ namespace DualScreenDemo.Services mediaControl.Stop(); SafeRelease(ref mediaControl); } - SafeRelease(ref videoWindow); SafeRelease(ref videoRenderer); SafeRelease(ref sourceFilter); SafeRelease(ref lavVideoDecoder); @@ -65,10 +32,10 @@ namespace DualScreenDemo.Services SafeRelease(ref graphBuilder); } - public void RenderMediaFile(string filePath, nint Handle, int Width, int Height) + public void RenderMediaFile(string filePath) { StopAndReleaseResources(); - if (videoWindow != null) videoWindow.put_Visible(OABool.False); + int hr; graphBuilder = (IGraphBuilder)new FilterGraph(); @@ -84,38 +51,12 @@ namespace DualScreenDemo.Services hr = graphBuilder.AddFilter(videoRenderer, "Primary Video Renderer"); DsError.ThrowExceptionForHR(hr); - mediaControl = (IMediaControl)graphBuilder; - if (mediaControl == null) - { - Console.WriteLine("Failed to get Media Control for primary monitor."); - return; - } hr = ConnectFilters(graphBuilder, sourceFilter, "Output", lavSplitter, "Input"); DsError.ThrowExceptionForHR(hr); hr = ConnectFilters(graphBuilder, lavSplitter, "Video", lavVideoDecoder, "Input"); DsError.ThrowExceptionForHR(hr); hr = ConnectFilters(graphBuilder, lavVideoDecoder, "Output", videoRenderer, "VMR Input0"); DsError.ThrowExceptionForHR(hr); - - try - { - - IVideoWindow videoWindow = (IVideoWindow)videoRenderer; - videoWindow.put_Owner(Handle); - videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren); - - // ⬅ 左上角對齊(固定從 0,0 開始) - videoWindow.SetWindowPosition(0, 0, Width, Height); - - videoWindow.put_Visible(OABool.True); - - // Console.WriteLine("Video window configured successfully."); - } - catch (Exception ex) - { - Console.WriteLine(String.Format("Error syncing to primary monitor: {0}", ex.Message)); - MessageBox.Show(String.Format("Error syncing to primary monitor: {0}", ex.Message)); - } } catch (Exception ex) { diff --git a/Services/Video.cs b/Services/Video.cs index 6572a49..5ffe153 100644 --- a/Services/Video.cs +++ b/Services/Video.cs @@ -54,7 +54,7 @@ namespace DualScreenDemo.Services { PinInfo pinInfo; pins[0].QueryPinInfo(out pinInfo); - Console.WriteLine(pinInfo); + //Console.WriteLine(pinInfo+":"+pinInfo.name); if (pinInfo.name == pinName) { diff --git a/VideoPlayerForm.cs b/VideoPlayerForm.cs index d6d4f40..7c51b42 100644 --- a/VideoPlayerForm.cs +++ b/VideoPlayerForm.cs @@ -71,6 +71,8 @@ namespace DualScreenDemo private const uint SWP_NOZORDER = 0x0004; private MediaServicePrimary primary = new MediaServicePrimary(); private MediaService secondary = new MediaService(); + private IVideoWindow videoWindowPrimary; + private IVideoWindow videoWindowSecondary; public static OverlayForm overlayForm; public bool isMuted = false; @@ -158,8 +160,20 @@ namespace DualScreenDemo private void VideoPlayerForm_FormClosing(object sender, FormClosingEventArgs e) { - primary.VideoPlayerFormClosing(); - secondary.VideoPlayerFormClosing(); + if (videoWindowPrimary != null) + { + videoWindowPrimary.put_Visible(OABool.False); + videoWindowPrimary.put_Owner(IntPtr.Zero); + Marshal.ReleaseComObject(videoWindowPrimary); + videoWindowPrimary = null; + } + if (videoWindowSecondary != null) + { + videoWindowSecondary.put_Visible(OABool.False); + videoWindowSecondary.put_Owner(IntPtr.Zero); + Marshal.ReleaseComObject(videoWindowSecondary); + videoWindowSecondary = null; + } // 清理COM CoUninitialize(); } @@ -273,10 +287,6 @@ namespace DualScreenDemo SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch1, 0, commandBytesIncreasePitch1.Length); } } - - // pathToPlay 需要調整 - var pathToPlay = songToPlay.getFile(); - // 更新畫面上顯示的下一首歌資訊 SongList.UpdateNextSongLabel(); @@ -286,45 +296,40 @@ namespace DualScreenDemo // 隱藏「暫停中」標籤 overlayForm.HidePauseLabel(); - await _InitializeAndPlayMedia(pathToPlay); + await _InitializeAndPlayMedia(songToPlay); } - public async Task ReplayCurrentSong() - { - var songToPlay = SongList.Current(); - var pathToPlay = songToPlay.getFile(); - // UpdateMarqueeTextForCurrentSong(songToPlay); - await _InitializeAndPlayMedia(pathToPlay); - } - private async Task _InitializeAndPlayMedia(string pathToPlay) + public async Task ReplayCurrentSong() =>await _InitializeAndPlayMedia(SongList.Current()); + + private async Task _InitializeAndPlayMedia(SongData song) { try { if (InvokeRequired) { - await InvokeAsync(() => InitializeAndPlayMedia(pathToPlay)); + await InvokeAsync(() => InitializeAndPlayMedia(song)); } else { - await InitializeAndPlayMedia(pathToPlay); + await InitializeAndPlayMedia(song); } } catch (Exception ex) { Console.WriteLine($"播放時發生錯誤: {ex.Message}"); - await RetryInitializeAndPlayMedia(pathToPlay); + await RetryInitializeAndPlayMedia(song); } } - private async Task RetryInitializeAndPlayMedia(string path) + private async Task RetryInitializeAndPlayMedia(SongData song) { try { int hr = CoInitializeEx(IntPtr.Zero, COINIT.APARTMENTTHREADED); if (hr >= 0) { - await InitializeAndPlayMedia(path); + await InitializeAndPlayMedia(song); } else { @@ -356,11 +361,35 @@ namespace DualScreenDemo return tcs.Task; } - private Task InitializeAndPlayMedia(string pathToPlay) + private Task InitializeAndPlayMedia(SongData song) { + string pathToPlay = song.getFile(); + if (videoWindowPrimary != null) videoWindowPrimary.put_Visible(OABool.False); + if (videoWindowSecondary != null) videoWindowSecondary.put_Visible(OABool.False); + // 渲染媒體文件 - primary.RenderMediaFile(pathToPlay,PrimaryForm.Instance.primaryScreenPanel.Handle,newWidth,newHeight); - secondary.RenderMediaFile(pathToPlay,this.Handle,secondMonitor.Bounds.Width,secondMonitor.Bounds.Height); + primary.RenderMediaFile(pathToPlay); + secondary.RenderMediaFile(pathToPlay); + + + videoWindowPrimary = primary.videoRenderer as IVideoWindow; + if (videoWindowPrimary != null) + { + videoWindowPrimary.put_Owner(PrimaryForm.Instance.primaryScreenPanel.Handle); + videoWindowPrimary.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren); + videoWindowPrimary.SetWindowPosition(0, 0, newWidth, newHeight); + videoWindowPrimary.put_Visible(OABool.True); + } + // 绑定视频窗口到副屏幕 + videoWindowSecondary = secondary.renderer as IVideoWindow; + if (videoWindowSecondary != null) + { + videoWindowSecondary.put_Owner(this.Handle); + videoWindowSecondary.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings); + videoWindowSecondary.SetWindowPosition(0, 0, secondMonitor.Bounds.Width, secondMonitor.Bounds.Height); + videoWindowSecondary.put_Visible(OABool.True); + } + // 音量處理 SetVolume(isMuted ? -10000 : previousVolume); @@ -392,6 +421,7 @@ namespace DualScreenDemo { Task.Run(async () => { + await Task.Delay(10000); Console.WriteLine("開始監聽媒體事件..."); while (true) {