202508111732
調整開包廂計算關包廂時間 調整寫法
This commit is contained in:
parent
be19d8bcf7
commit
fdd8cf047d
@ -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}";
|
||||
}
|
||||
}
|
||||
}
|
@ -119,53 +119,22 @@ 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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -21,12 +21,7 @@ namespace DBObj
|
||||
{
|
||||
basic=new(songNumber,song,songSimplified,filename,humanVoice);
|
||||
A = new Artist(artistA, artistASimplified);
|
||||
if(!artistB.Equals("")){
|
||||
B = new Artist(artistB, artistBSimplified);
|
||||
} else
|
||||
{
|
||||
B = null;
|
||||
}
|
||||
B = !artistB.Equals("") ? new Artist(artistB, artistBSimplified) : null;
|
||||
isPublicSong = false;
|
||||
}
|
||||
public SongData(SongData value,PlayState s){
|
||||
@ -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 PlayState GetState() => state;
|
||||
|
||||
public int getHumanVoice() { return basic.getHumanVoice(); }
|
||||
public int getHumanVoice() => basic.getHumanVoice();
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0} {1}", basic.getName(),state.GetDescription() );
|
||||
|
@ -162,7 +162,6 @@ namespace DBObj
|
||||
}
|
||||
public static void clearSong()
|
||||
{
|
||||
|
||||
isWelcome = true;
|
||||
not_played.Clear();
|
||||
played.Clear();
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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()
|
||||
|
19
Room.cs
19
Room.cs
@ -13,7 +13,6 @@ namespace DualScreenDemo
|
||||
private string State = "error";
|
||||
private DateTime? startedAt;
|
||||
private DateTime? endedAt;
|
||||
public TimeSpan timePeriod;
|
||||
|
||||
public Room()
|
||||
{
|
||||
@ -47,14 +46,13 @@ namespace DualScreenDemo
|
||||
var Statedb = db.Field<string>("status");
|
||||
startedAt = ParseTime(db.Field<string>("started_at"));
|
||||
endedAt = ParseTime(db.Field<string>("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");
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user