superstar_v2/VideoPlayerForm.cs

1860 lines
76 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.IO; // For StreamWriter
using System.Runtime.InteropServices;
using DirectShowLib;
using DBObj;
using OverlayFormObj;
using DualScreenDemo.Shared;
namespace DualScreenDemo
{
public class VideoPlayerForm : Form
{
#region
public SongData currentPlayingSong;
public bool IsPlayingPublicSong { get; private set; } = false;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
#endregion
// 单例实例
public static VideoPlayerForm Instance { get; private set; }
// 导入user32.dll API
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
// Windows API 函數
[DllImport("user32.dll")]
static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
[DllImport("user32.dll")]
static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
// MONITORINFO 結構
[StructLayout(LayoutKind.Sequential)]
struct MONITORINFO
{
public int cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
}
// RECT 結構
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private const int GWL_EXSTYLE = -20;
private const int WS_EX_TOPMOST = 0x00000008;
private const uint SWP_NOZORDER = 0x0004;
private IGraphBuilder graphBuilderPrimary;
private IGraphBuilder graphBuilderSecondary;
private IMediaControl mediaControlPrimary;
private IMediaControl mediaControlSecondary;
private static IBaseFilter videoRendererSecondary;
private static IBaseFilter videoRendererPrimary;
private IBaseFilter lavSplitterPrimary;
private IBaseFilter lavSplitterSecondary;
private IBaseFilter lavVideoDecoderPrimary;
private IBaseFilter lavVideoDecoderSecondary;
private static IBaseFilter lavAudioDecoderSecondary;
private IPin outputPinSecondary;
private static IBaseFilter audioRenderer;
private IVideoWindow videoWindowSecondary;
private IVideoWindow videoWindowPrimary;
private IMediaEventEx mediaEventExPrimary;
private IMediaEventEx mediaEventExSecondary;
//private int videoWidth;
//private int videoHeight;
private static bool isInitializationComplete = false;
public static OverlayForm overlayForm;
public static List<SongData> playingSongList;
public static List<SongData> publicPlaylist;
public static int currentSongIndex = 0;
private static bool isUserPlaylistPlaying = false;
public bool isMuted = false;
public int previousVolume = -1000;
public bool isPaused = false;
private bool isSyncToPrimaryMonitor = false;
public bool IsSyncToPrimaryMonitor
{
get { return isSyncToPrimaryMonitor; }
set { isSyncToPrimaryMonitor = value; }
}
private static Screen secondMonitor;
public VideoPlayerForm()
{
Instance = this;
// this.DoubleBuffered = true;
InitializeComponent();
this.Load += VideoPlayerForm_Load;
this.Shown += VideoPlayerForm_Shown;
this.FormClosing += VideoPlayerForm_FormClosing;
InitializeOverlayForm(secondMonitor);
BringOverlayToFront();
HttpServer.OnDisplayBarrage += DisplayBarrageOnOverlay;
MonitorMediaEvents();
}
private void InitializeComponent()
{
}
private void VideoPlayerForm_Load(object sender, EventArgs e)
{
secondMonitor = ScreenHelper.GetSecondMonitor();
if (secondMonitor != null)
{
this.FormBorderStyle = FormBorderStyle.None; // 设置窗体没有边框
this.StartPosition = FormStartPosition.Manual;
this.Location = secondMonitor.Bounds.Location;
this.Size = secondMonitor.Bounds.Size;
// this.DoubleBuffered = true;
}
CheckMonitor();
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
try
{
if (secondMonitor != null)
{
SetWindowPos(this.Handle, IntPtr.Zero, secondMonitor.Bounds.X, secondMonitor.Bounds.Y,
secondMonitor.Bounds.Width, secondMonitor.Bounds.Height, 0);
}
IntPtr exStyle = GetWindowLong(this.Handle, GWL_EXSTYLE);
SetWindowLong(this.Handle, GWL_EXSTYLE, (IntPtr)(exStyle.ToInt32()));
}
catch (Exception ex)
{
Console.WriteLine("An error occurred in OnShown: " + ex.Message);
}
}
private void VideoPlayerForm_Shown(object sender, EventArgs e)
{
int hr = CoInitializeEx(IntPtr.Zero, COINIT.APARTMENTTHREADED);
if (hr < 0)
{
Console.WriteLine("Failed to initialize COM library.");
return;
}
InitializeGraphBuilderPrimary();
InitializeGraphBuilderSecondary();
Task.Run(() => MonitorMediaEvents());
}
private void VideoPlayerForm_FormClosing(object sender, FormClosingEventArgs e)
{
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();
}
// COM API函数声明
[DllImport("ole32.dll")]
private static extern int CoInitializeEx(IntPtr pvReserved, COINIT dwCoInit);
[DllImport("ole32.dll")]
private static extern void CoUninitialize();
// CoInitializeEx() 可以选择的参数
private enum COINIT : int
{
APARTMENTTHREADED = 0x2,
MULTITHREADED = 0x0
}
private void InitializeGraphBuilderPrimary()
{
graphBuilderPrimary = (IGraphBuilder)new FilterGraph();
if (graphBuilderPrimary == null)
{
Console.WriteLine("Failed to create FilterGraph for primary monitor.");
throw new Exception("Failed to create FilterGraph for primary monitor.");
}
try
{
lavSplitterPrimary = AddFilterByClsid(graphBuilderPrimary, "LAV Splitter", Clsid.LAVSplitter);
lavVideoDecoderPrimary = AddFilterByClsid(graphBuilderPrimary, "LAV Video Decoder", Clsid.LAVVideoDecoder);
videoRendererPrimary = AddFilterByClsid(graphBuilderPrimary, "Primary Video Renderer", Clsid.VideoRenderer);
int hr = graphBuilderPrimary.AddFilter(videoRendererPrimary, "Primary Video Renderer");
DsError.ThrowExceptionForHR(hr);
mediaControlPrimary = (IMediaControl)graphBuilderPrimary;
if (mediaControlPrimary == null)
{
Console.WriteLine("Failed to get Media Control for primary monitor.");
return;
}
mediaEventExPrimary = (IMediaEventEx)graphBuilderPrimary;
if (mediaEventExPrimary == null)
{
Console.WriteLine("Failed to get Media Event Ex for primary monitor.");
return;
}
}
catch (Exception ex)
{
Console.WriteLine("Error initializing graph builder for primary monitor: " + ex.Message);
}
}
private void InitializeGraphBuilderSecondary()
{
graphBuilderSecondary = (IGraphBuilder)new FilterGraph();
if (graphBuilderSecondary == null)
{
Console.WriteLine("Failed to create FilterGraph");
throw new Exception("Failed to create FilterGraph");
}
try
{
lavSplitterSecondary = AddFilterByClsid(graphBuilderSecondary, "LAV Splitter", Clsid.LAVSplitter);
lavVideoDecoderSecondary = AddFilterByClsid(graphBuilderSecondary, "LAV Video Decoder", Clsid.LAVVideoDecoder);
lavAudioDecoderSecondary = AddFilterByClsid(graphBuilderSecondary, "LAV Audio Decoder", Clsid.LAVAudioDecoder);
outputPinSecondary = FindPin(lavAudioDecoderSecondary, "Output");
videoRendererSecondary = AddFilterByClsid(graphBuilderSecondary, "Secondary Video Renderer", Clsid.VideoRenderer);
if (videoRendererSecondary == null)
{
Console.WriteLine("Failed to initialize Secondary Video Renderer.");
return;
}
int hr = graphBuilderSecondary.AddFilter(videoRendererSecondary, "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 = graphBuilderSecondary.AddFilter(audioRenderer, "Default DirectSound Device");
DsError.ThrowExceptionForHR(hr);
mediaControlSecondary = (IMediaControl)graphBuilderSecondary;
if (mediaControlSecondary == null)
{
Console.WriteLine("Failed to get Media Control");
return;
}
mediaEventExSecondary = (IMediaEventEx)graphBuilderSecondary;
if (mediaEventExSecondary == null)
{
Console.WriteLine("Failed to get Media Event Ex");
return;
}
isInitializationComplete = true;
}
catch (Exception ex)
{
Console.WriteLine("Error initializing graph builder with second monitor: " + ex.Message);
}
}
private void ConfigureSampleGrabber(IBaseFilter sampleGrabberFilter)
{
ISampleGrabber sampleGrabber = (ISampleGrabber)sampleGrabberFilter;
AMMediaType mediaType = new AMMediaType
{
majorType = MediaType.Video,
subType = MediaSubType.RGB24,
formatType = FormatType.VideoInfo
};
sampleGrabber.SetMediaType(mediaType);
DsUtils.FreeAMMediaType(mediaType);
sampleGrabber.SetBufferSamples(false);
sampleGrabber.SetOneShot(false);
sampleGrabber.SetCallback(new SampleGrabberCallback(this), 1);
}
private int ConnectFilters(IGraphBuilder graphBuilder, IBaseFilter sourceFilter, string sourcePinName, IBaseFilter destFilter, string destPinName)
{
IPin outPin = FindPin(sourceFilter, sourcePinName);
IPin inPin = FindPin(destFilter, destPinName);
if (outPin == null || inPin == null)
{
Console.WriteLine(String.Format("Cannot find pins: {0} or {1}", sourcePinName, destPinName));
return -1;
}
int hr = graphBuilder.Connect(outPin, inPin);
return hr;
}
private IPin FindPin(IBaseFilter filter, string pinName)
{
IEnumPins enumPins;
IPin[] pins = new IPin[1];
filter.EnumPins(out enumPins);
enumPins.Reset();
while (enumPins.Next(1, pins, IntPtr.Zero) == 0)
{
PinInfo pinInfo;
pins[0].QueryPinInfo(out pinInfo);
Console.WriteLine(pinInfo);
if (pinInfo.name == pinName)
{
return pins[0];
}
}
return null;
}
private void CheckMonitor()
{
Screen screen = Screen.FromHandle(this.Handle);
}
private static IBaseFilter AddFilterByClsid(IGraphBuilder graphBuilder, string name, Guid clsid)
{
try
{
// 获取 CLSID 对应的类型
Type filterType = Type.GetTypeFromCLSID(clsid);
//Console.WriteLine($"Attempting to create filter of type: {filterType.FullName}");
// 创建实例
object filterObject = Activator.CreateInstance(filterType);
// 尝试转换为 IBaseFilter
IBaseFilter filter = filterObject as IBaseFilter;
if (filter == null)
{
// 如果转换失败,使用 IUnknown 获取并转换为 IBaseFilter
IntPtr comObjectPointer = Marshal.GetIUnknownForObject(filterObject);
filter = (IBaseFilter)Marshal.GetObjectForIUnknown(comObjectPointer);
// Console.WriteLine($"Successfully converted COM object to IBaseFilter via IUnknown.");
}
else
{
// Console.WriteLine($"Successfully created IBaseFilter directly.");
}
// 添加过滤器到图形构建器
int hr = graphBuilder.AddFilter(filter, name);
if (hr != 0)
{
// Console.WriteLine($"Failed to add filter {name} with CLSID {clsid}, HRESULT: {hr}");
}
DsError.ThrowExceptionForHR(hr);
// Console.WriteLine($"Successfully added filter {name} with CLSID {clsid}");
return filter;
}
catch (Exception ex)
{
Console.WriteLine($"Exception in AddFilterByClsid: {ex.Message}");
throw; // Rethrow the exception to handle it further up the call stack
}
}
// 同步畫面事件
public void SyncToPrimaryMonitor()
{
PrimaryForm.Instance.primaryScreenPanel.Visible = true;
PrimaryForm.Instance.primaryScreenPanel.BringToFront();
PrimaryForm.Instance.syncServiceBellButton.Visible = true;
PrimaryForm.Instance.syncServiceBellButton.BringToFront();
PrimaryForm.Instance.syncCutSongButton.Visible = true;
PrimaryForm.Instance.syncCutSongButton.BringToFront();
PrimaryForm.Instance.syncReplayButton.Visible = true;
PrimaryForm.Instance.syncReplayButton.BringToFront();
PrimaryForm.Instance.syncOriginalSongButton.Visible = true;
PrimaryForm.Instance.syncOriginalSongButton.BringToFront();
PrimaryForm.Instance.syncMuteButton.Visible = true;
PrimaryForm.Instance.syncMuteButton.BringToFront();
if (isPaused)
{
PrimaryForm.Instance.syncPlayButton.Visible = true;
PrimaryForm.Instance.syncPlayButton.BringToFront();
}
else
{
PrimaryForm.Instance.syncPauseButton.Visible = true;
PrimaryForm.Instance.syncPauseButton.BringToFront();
}
PrimaryForm.Instance.syncVolumeUpButton.Visible = true;
PrimaryForm.Instance.syncVolumeUpButton.BringToFront();
PrimaryForm.Instance.syncVolumeDownButton.Visible = true;
PrimaryForm.Instance.syncVolumeDownButton.BringToFront();
PrimaryForm.Instance.syncMicUpButton.Visible = true;
PrimaryForm.Instance.syncMicUpButton.BringToFront();
PrimaryForm.Instance.syncMicDownButton.Visible = true;
PrimaryForm.Instance.syncMicDownButton.BringToFront();
PrimaryForm.Instance.syncCloseButton.Visible = true;
PrimaryForm.Instance.syncCloseButton.BringToFront();
try
{
if (videoRendererPrimary == null)
{
// Console.WriteLine("VMR9 is not initialized.");
return;
}
int designWidth = 1620;
int designHeight = 1080;
int actualWidth = PrimaryForm.Instance.primaryScreenPanel.Width;
int actualHeight = PrimaryForm.Instance.primaryScreenPanel.Height;
// 等比例縮放不會超出fit
float scaleX = (float)actualWidth / designWidth;
float scaleY = (float)actualHeight / designHeight;
float scale = Math.Min(scaleX, scaleY);
// 計算縮放後的尺寸(但起點仍是 0,0
int newWidth = (int)(designWidth * scale);
int newHeight = (int)(designHeight * scale);
// trash location with trash flexible of screen size.
if (actualWidth == 1024)
{
newWidth = (int)(newWidth * 0.84f);
}
else if (actualWidth == 1440)
{
newWidth = (int)(newWidth * 0.9f);
}
videoWindowPrimary = (IVideoWindow)videoRendererPrimary;
videoWindowPrimary.put_Owner(PrimaryForm.Instance.primaryScreenPanel.Handle);
videoWindowPrimary.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren);
// ⬅ 左上角對齊(固定從 0,0 開始)
videoWindowPrimary.SetWindowPosition(0, 0, newWidth, newHeight);
videoWindowPrimary.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));
}
}
public void ClosePrimaryScreenPanel()
{
try
{
PrimaryForm.Instance.primaryScreenPanel.Visible = false;
PrimaryForm.Instance.syncServiceBellButton.Visible = false;
PrimaryForm.Instance.syncCutSongButton.Visible = false;
PrimaryForm.Instance.syncReplayButton.Visible = false;
PrimaryForm.Instance.syncOriginalSongButton.Visible = false;
PrimaryForm.Instance.syncMuteButton.Visible = false;
PrimaryForm.Instance.syncPauseButton.Visible = false;
PrimaryForm.Instance.syncPlayButton.Visible = false;
PrimaryForm.Instance.syncVolumeUpButton.Visible = false;
PrimaryForm.Instance.syncVolumeDownButton.Visible = false;
PrimaryForm.Instance.syncMicUpButton.Visible = false;
PrimaryForm.Instance.syncMicDownButton.Visible = false;
PrimaryForm.Instance.syncCloseButton.Visible = false;
if (videoWindowPrimary != null)
{
videoWindowPrimary.put_Owner(PrimaryForm.Instance.primaryScreenPanel.Handle); // 绑定到主屏幕的特定区域
videoWindowPrimary.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings);
videoWindowPrimary.put_Visible(OABool.False); // 初始化时隐藏
}
IsSyncToPrimaryMonitor = false;
}
catch (Exception ex)
{
Console.WriteLine(String.Format("Error closing primary screen panel: {0}", ex.Message));
MessageBox.Show(String.Format("Error closing primary screen panel: {0}", ex.Message));
}
}
[DllImport("gdi32.dll", ExactSpelling = true)]
public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight,
IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
public enum TernaryRasterOperations : uint
{
SRCCOPY = 0x00CC0020,
}
private void DisplayBarrageOnOverlay(string text)
{
if (overlayForm.InvokeRequired)
{
overlayForm.Invoke(new System.Action(() => overlayForm.DisplayBarrage(text)));
}
else
{
overlayForm.DisplayBarrage(text);
}
}
public async void InitializePublicPlaylist(List<SongData> initialPlaylist)
{
publicPlaylist = initialPlaylist;
await PlayPublicPlaylist(); // 开始播放公播歌单
}
public async Task SetPlayingSongList(List<SongData> songList)
{
// [1] 輸出 debug 訊息,方便開發時追蹤是否有呼叫此方法
Console.WriteLine("SetPlayingSongList called");
// [2] 停止當前播放,釋放資源(例如關閉影片播放器、清除緩衝)
StopAndReleaseResources();
// [3] 將新的播放清單指派給 `playingSongList`
playingSongList = songList;
// [4] 根據是否有歌,設定旗標為是否播放使用者點播清單
isUserPlaylistPlaying = playingSongList != null && playingSongList.Any();
// [5] 強制關閉公播狀態(意即現在進入點歌模式)
IsPlayingPublicSong = false;
// [6] 若使用者點播清單有歌,就開始播放
if (isUserPlaylistPlaying)
{
// [6.1] 設定當前歌曲索引為 -1意味著即將播放第一首從 `PlayNextSong` 開始)
currentSongIndex = -1;
// [6.2] 播放下一首歌(實際會遞增 index 為 0並播放該首歌
await PlayNextSong();
}
else
{
await InitializeAndPlayPublicPlaylist();
}
}
public async Task PlayPublicPlaylist()
{
Console.WriteLine("開始播放公播清單...");
// 在切换到公播之前,确保最后一首用户歌曲状态正确
if (PrimaryForm.currentSongIndexInHistory >= 0 &&
PrimaryForm.currentSongIndexInHistory < PrimaryForm.playStates.Count)
{
PrimaryForm.playStates[PrimaryForm.currentSongIndexInHistory] = PlayState.Played;
Console.WriteLine($"切換到公播前更新最後一首歌曲狀態為已播放,索引:{PrimaryForm.currentSongIndexInHistory}");
// 强制刷新显示
if (PrimaryForm.Instance.multiPagePanel != null)
{
PrimaryForm.Instance.multiPagePanel.LoadPlayedSongs(
PrimaryForm.playedSongsHistory,
PrimaryForm.playStates
);
}
}
isUserPlaylistPlaying = false;
IsPlayingPublicSong = true; // 设置为正在播放公播
currentSongIndex = -1;
try
{
// 重新整理公播清單
publicPlaylist = new List<SongData>();
// 首先添加 welcome.mpg
string welcomePath = @"D:\video\welcome.mpg";
if (File.Exists(welcomePath))
{
publicPlaylist.Add(new SongData(
"0", "歡迎光臨", welcomePath, 1,true
));
}
// 添加 BGM 序列
for (int i = 1; i <= 99; i++)
{
string bgmPath = $@"D:\video\BGM{i:D2}.mpg";
if (File.Exists(bgmPath))
{
publicPlaylist.Add(new SongData(
i.ToString(), $"背景音樂{i:D2}", bgmPath, 1,true
));
}
}
// 如果公播清單為空,使用原有的歌曲
if (publicPlaylist.Count == 0)
{
string videoDirectory = @"D:\video\";
string[] videoFiles = Directory.GetFiles(videoDirectory, "*.mpg");
foreach (var songPath in videoFiles)
{
string fileName = Path.GetFileNameWithoutExtension(songPath);
publicPlaylist.Add(new SongData("0", fileName,songPath,1,true));
}
}
await Task.Delay(100); // 添加短暂延迟
await PlayNextSong();
}
catch (Exception ex)
{
Console.WriteLine($"播放公播清單時發生錯誤: {ex.Message}");
// 可以在这里添加重试逻辑
await Task.Delay(1000);
await PlayNextSong();
}
}
// private static async Task UpdateMarqueeTextForCurrentSong(SongData song)
// {
// string text;
// if (string.IsNullOrEmpty(song?.Song))
// {
// text = string.Empty;
// }
// else
// {
// text = String.Format("正在播放:{0} ", song.Song);
// }
// overlayForm.UpdateSongDisplayLabel(text);
// await Task.Delay(5000);
// }
public static async Task UpdateMarqueeTextForNextSong(SongData song)
{
string nextSongText = String.Format("下一首3{0}", song.Name);
if (overlayForm.InvokeRequired)
{
overlayForm.Invoke(new MethodInvoker(() =>
{
overlayForm.UpdateMarqueeText(nextSongText, OverlayForm.MarqueeStartPosition.Middle, Color.White);
}));
}
else
{
overlayForm.UpdateMarqueeText(nextSongText, OverlayForm.MarqueeStartPosition.Middle, Color.White);
}
await Task.Delay(5000);
// 重置跑马灯文本
if (overlayForm.InvokeRequired)
{
overlayForm.Invoke(new MethodInvoker(() =>
{
overlayForm.ResetMarqueeTextToWelcomeMessage();
}));
}
else
{
overlayForm.ResetMarqueeTextToWelcomeMessage();
}
}
public void UpdateNextSongFromPlaylist()
{
List<SongData> currentPlaylist = isUserPlaylistPlaying ? playingSongList : publicPlaylist;
if (currentPlaylist == null || currentPlaylist.Count == 0)
{
overlayForm?.UpdateNextSongLabelFromPlaylist(isUserPlaylistPlaying, null);
return;
}
int currentSongIndex = currentPlaylist.IndexOf(currentPlayingSong);
if (currentSongIndex == -1 || currentSongIndex + 1 >= currentPlaylist.Count)
{
overlayForm?.UpdateNextSongLabelFromPlaylist(isUserPlaylistPlaying, null);
}
else
{
SongData nextSong = currentPlaylist[currentSongIndex + 1];
overlayForm?.UpdateNextSongLabelFromPlaylist(isUserPlaylistPlaying, currentPlayingSong);
}
}
public async Task PlayNextSong()
{
// 等待初始化完成(例如播放器、串口等資源尚未就緒時)
while (!isInitializationComplete)
{
await Task.Delay(100);
}
Console.WriteLine("開始播放下一首歌曲...");
// 根據目前播放模式(點歌 or 公播)決定要播放的清單
List<SongData> currentPlaylist = isUserPlaylistPlaying ? playingSongList : publicPlaylist;
// 若播放清單是空的,直接返回(不執行播放)
if (!currentPlaylist.Any()) return;
if (!isUserPlaylistPlaying)
{
// 公播模式下,正常循環播放(用 % 保證不會超出陣列界限)
currentSongIndex = (currentSongIndex + 1) % currentPlaylist.Count;
Console.WriteLine($"順序播放: currentSongIndex = {currentSongIndex}, currentPlaylist.Count = {currentPlaylist.Count}");
}
else
{
// 若是使用者點播模式先送出升Key的串口指令
if (SerialPortManager.mySerialPort != null && SerialPortManager.mySerialPort.IsOpen)
{
byte[] commandBytesIncreasePitch1 = new byte[] { 0xA2, 0x7F, 0xA4 };
SerialPortManager.mySerialPort.Write(commandBytesIncreasePitch1, 0, commandBytesIncreasePitch1.Length);
}
// 同樣遞增 index 來播放下一首
currentSongIndex = (currentSongIndex + 1) % currentPlaylist.Count;
}
// 可以取得 燈控/聲控 的位置
var songToPlay = currentPlaylist[currentSongIndex];
// pathToPlay 需要調整
var pathToPlay = songToPlay.getFile();
// 若兩個 host 上都找不到檔案就直接結束
if (string.IsNullOrEmpty(pathToPlay))
{
Console.WriteLine($"文件不存在:{songToPlay.Name}");
return;
}
// 更新目前正在播放的歌曲
currentPlayingSong = songToPlay;
// 更新畫面上顯示的下一首歌資訊
UpdateNextSongFromPlaylist();
// 顯示 QRCode可能是點歌頁用
overlayForm.DisplayQRCodeOnOverlay(HttpServer.randomFolderPath);
// 隱藏「暫停中」標籤
overlayForm.HidePauseLabel();
try
{
// 確保在UI線程上執行COM對象操作
if (this.InvokeRequired)
{
this.Invoke(new Action(async () =>
{
await InitializeAndPlayMedia(pathToPlay);
}));
}
else
{
await InitializeAndPlayMedia(pathToPlay);
}
}
catch (Exception ex)
{
Console.WriteLine($"播放時發生錯誤: {ex.Message}");
// 嘗試重新初始化並重播
try
{
await Task.Delay(100);
StopAndReleaseResources();
await Task.Delay(100);
// 重新初始化 COM
int hr = CoInitializeEx(IntPtr.Zero, COINIT.APARTMENTTHREADED);
if (hr >= 0)
{
InitializeGraphBuilderPrimary();
InitializeGraphBuilderSecondary();
await InitializeAndPlayMedia(pathToPlay);
}
}
catch (Exception retryEx)
{
Console.WriteLine($"重試播放時發生錯誤: {retryEx.Message}");
}
}
}
private async Task InitializeAndPlayMedia(string pathToPlay)
{
if (videoWindowPrimary != null)
{
videoWindowPrimary.put_Visible(OABool.False);
}
if (videoWindowSecondary != null)
{
videoWindowSecondary.put_Visible(OABool.False);
}
// 清理並初始化 DirectShow 圖表
RemoveAllFilters(graphBuilderPrimary);
RemoveAllFilters(graphBuilderSecondary);
InitializeGraphBuilderPrimary();
InitializeGraphBuilderSecondary();
// 渲染媒體文件
RenderMediaFilePrimary(pathToPlay);
RenderMediaFileSecondary(pathToPlay);
// 綁定視頻窗口到副屏幕
videoWindowSecondary = (IVideoWindow)videoRendererSecondary;
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);
await Task.Delay(100); // 給予視窗一些時間進行設置
videoWindowSecondary.put_Visible(OABool.True);
}
// 音量處理
if (isMuted)
{
SetVolume(-10000);
}
// 開始播放
if (mediaControlPrimary != null) mediaControlPrimary.Run();
if (mediaControlSecondary != null) mediaControlSecondary.Run();
if (isSyncToPrimaryMonitor)
{
SyncToPrimaryMonitor();
}
}
/// <summary>
/// 跳至下一首歌曲的方法,會根據目前播放清單(使用者清單或公播清單)做切換與播放邏輯控制。
/// </summary>
public async Task SkipToNextSong()
{
try
{
// 停止當前播放並釋放資源(如播放器、影片檔等)
StopAndReleaseResources();
// 稍作延遲,確保資源已被釋放
await Task.Delay(100);
// 如果目前正在播放使用者點播清單,且清單還有歌曲
if (isUserPlaylistPlaying && playingSongList != null && playingSongList.Count > 0)
{
// 移除目前播放的第一首歌(已經播放過的)
playingSongList.RemoveAt(0);
if (playingSongList.Count == 0)
{
// 使用者點播清單播完了,切換回公播清單
Console.WriteLine("用戶播放列表已清空,切換至公播清單");
isUserPlaylistPlaying = false;
lastPlayedIndex = -1;
currentSongIndex = -1;
// 初始化並開始播放公播清單
await InitializeAndPlayPublicPlaylist();
}
else
{
// 還有歌曲可播,繼續播放下一首使用者歌曲
currentSongIndex = -1;
await PlayNextSong();
}
}
else
{
// 如果不是在播放使用者清單(或清單為空),直接初始化並播放公播清單
await InitializeAndPlayPublicPlaylist();
}
// 如果目前歌曲在播放歷史列表的索引是合法的(防呆)
if (PrimaryForm.currentSongIndexInHistory >= 0 && PrimaryForm.currentSongIndexInHistory < PrimaryForm.playedSongsHistory.Count)
{
var currentSong = PrimaryForm.playedSongsHistory[PrimaryForm.currentSongIndexInHistory];
// 如果新的播放清單還有歌曲,並且當前歷史記錄中的歌曲與播放清單的第一首一致,則標記為已播畢
if (playingSongList.Count > 0 && currentSong == playingSongList[0])
{
PrimaryForm.playStates[PrimaryForm.currentSongIndexInHistory] = PlayState.Played;
}
}
/*如果當前為公播,不可以+1*/
bool isPlayingPublicList = PrimaryForm.userRequestedSongs.Count == 0 ||
(PrimaryForm.currentSongIndexInHistory >= PrimaryForm.userRequestedSongs.Count - 1 && PrimaryForm.Instance.videoPlayerForm.IsPlayingPublicSong);
if (!isPlayingPublicList)
{
PrimaryForm.currentSongIndexInHistory += 1;
}
Console.WriteLine("currentSongIndexInHistory : " + PrimaryForm.currentSongIndexInHistory);
}
catch (Exception ex)
{
// 若有例外錯誤,列印錯誤訊息並切回公播模式
Console.WriteLine($"切換歌曲時發生錯誤: {ex.Message}");
await InitializeAndPlayPublicPlaylist();
}
}
// 新增一个方法来处理公播列表的初始化和播放
private async Task InitializeAndPlayPublicPlaylist()
{
try
{
isUserPlaylistPlaying = false;
currentSongIndex = -1;
// 重新初始化公播列表
publicPlaylist = new List<SongData>();
// 添加 welcome.mpg
string welcomePath = @"D:\video\welcome.mpg";
if (File.Exists(welcomePath))
{
publicPlaylist.Add(new SongData("0", "歡迎光臨", welcomePath, 1,true));
}
// 添加 BGM 序列
for (int i = 1; i <= 99; i++)
{
string bgmPath = $@"D:\video\BGM{i:D2}.mpg";
if (File.Exists(bgmPath))
{
publicPlaylist.Add(new SongData(i.ToString(), $"背景音樂{i:D2}", bgmPath, 1,true));
}
}
if (publicPlaylist.Count > 0)
{
await PlayNextSong();
}
}
catch (Exception ex)
{
Console.WriteLine($"初始化公播清單時發生錯誤: {ex.Message}");
}
}
public void ReplayCurrentSong()
{
List<SongData> currentPlaylist = isUserPlaylistPlaying ? playingSongList : publicPlaylist;
if (!currentPlaylist.Any()) return;
var songToPlay = currentPlaylist[currentSongIndex];
var pathToPlay = songToPlay.getFile();
if (string.IsNullOrEmpty(pathToPlay))
{
MessageBox.Show("File does not exist on both hosts.");
return;
}
// UpdateMarqueeTextForCurrentSong(songToPlay);
try
{
if (mediaControlPrimary != null)
{
mediaControlPrimary.Stop();
}
if (mediaControlSecondary != null)
{
mediaControlSecondary.Stop();
}
if (videoWindowPrimary != null)
{
videoWindowPrimary.put_Visible(OABool.False); // 隐藏主屏幕窗口,避免干扰
}
if (videoWindowSecondary != null)
{
videoWindowSecondary.put_Visible(OABool.False); // 隐藏副屏幕窗口,避免闪烁
}
// 清理并初始化 DirectShow 图表
RemoveAllFilters(graphBuilderPrimary);
RemoveAllFilters(graphBuilderSecondary);
InitializeGraphBuilderPrimary();
InitializeGraphBuilderSecondary();
// 渲染媒体文件
RenderMediaFilePrimary(pathToPlay);
RenderMediaFileSecondary(pathToPlay);
// 绑定视频窗口到副屏幕
videoWindowSecondary = videoRendererSecondary 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); // 显示窗口
}
// 音量处理
if (isMuted)
{
SetVolume(-10000); // 静音
}
// 开始播放
mediaControlPrimary?.Run();
mediaControlSecondary?.Run();
if (isSyncToPrimaryMonitor)
{
SyncToPrimaryMonitor();
}
}
catch (Exception ex)
{
Console.WriteLine(String.Format("Error replaying song: {0}", ex.Message));
MessageBox.Show(String.Format("Error replaying song: {0}", ex.Message));
}
}
public void StopAndReleaseResources()
{
try
{
if (mediaControlPrimary != null)
{
mediaControlPrimary.Stop();
Marshal.ReleaseComObject(mediaControlPrimary);
mediaControlPrimary = null;
}
if (mediaControlSecondary != null)
{
mediaControlSecondary.Stop();
Marshal.ReleaseComObject(mediaControlSecondary);
mediaControlSecondary = null;
}
// 释放其他资源
if (lavSplitterPrimary != null)
{
Marshal.ReleaseComObject(lavSplitterPrimary);
lavSplitterPrimary = null;
}
if (lavSplitterSecondary != null)
{
Marshal.ReleaseComObject(lavSplitterSecondary);
lavSplitterSecondary = null;
}
if (lavVideoDecoderPrimary != null)
{
Marshal.ReleaseComObject(lavVideoDecoderPrimary);
lavVideoDecoderPrimary = null;
}
if (lavVideoDecoderSecondary != null)
{
Marshal.ReleaseComObject(lavVideoDecoderSecondary);
lavVideoDecoderSecondary = null;
}
if (lavAudioDecoderSecondary != null)
{
Marshal.ReleaseComObject(lavAudioDecoderSecondary);
lavAudioDecoderSecondary = null;
}
if (outputPinSecondary != null)
{
Marshal.ReleaseComObject(outputPinSecondary);
outputPinSecondary = null;
}
// 强制进行垃圾回收
GC.Collect();
GC.WaitForPendingFinalizers();
}
catch (Exception ex)
{
Console.WriteLine($"釋放資源時發生錯誤: {ex.Message}");
}
}
public void RenderMediaFilePrimary(string filePath)
{
int hr;
try
{
IBaseFilter sourceFilter;
hr = graphBuilderPrimary.AddSourceFilter(filePath, "Source", out sourceFilter);
DsError.ThrowExceptionForHR(hr);
videoWindowPrimary = (IVideoWindow)videoRendererPrimary;
videoWindowPrimary.put_Visible(OABool.False);
hr = ConnectFilters(graphBuilderPrimary, sourceFilter, "Output", lavSplitterPrimary, "Input");
DsError.ThrowExceptionForHR(hr);
hr = ConnectFilters(graphBuilderPrimary, lavSplitterPrimary, "Video", lavVideoDecoderPrimary, "Input");
DsError.ThrowExceptionForHR(hr);
hr = ConnectFilters(graphBuilderPrimary, lavVideoDecoderPrimary, "Output", videoRendererPrimary, "VMR Input0");
DsError.ThrowExceptionForHR(hr);
videoWindowPrimary = (IVideoWindow)videoRendererPrimary;
videoWindowPrimary.put_Owner(PrimaryForm.Instance.primaryScreenPanel.Handle); // 设置为 primaryScreenPanel 的句柄
videoWindowPrimary.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren);
videoWindowPrimary.SetWindowPosition(0, 0, 1500, 1000); // 调整视频窗口大小以填满黑色区域
//Task.Delay(100).Wait();
videoWindowPrimary.put_Visible(OABool.True);
SaveGraphFile(graphBuilderPrimary, "primary_graph.grf");
if (hr == 0)
{
Console.WriteLine("主檔案 成功");
}
else
{
Console.WriteLine("檔案失敗");
}
}
catch (Exception ex)
{
Console.WriteLine("主檔案失敗2: " + ex.Message);
}
}
public void RenderMediaFileSecondary(string filePath)
{
int hr = graphBuilderSecondary.RenderFile(filePath, null);
DsError.ThrowExceptionForHR(hr);
SaveGraphFile(graphBuilderSecondary, "secondary_graph.grf");
if (hr == 0)
{
Console.WriteLine("Secondary File rendered successfully.");
SetAudioTrackTo(1);
}
else
{
Console.WriteLine("Failed to render secondary file.");
}
}
public static void SaveGraphFile(IGraphBuilder graph, string filename)
{
var writer = new StreamWriter(filename);
IFilterGraph2 graph2 = graph as IFilterGraph2;
if (graph2 != null)
{
IEnumFilters enumFilters;
graph2.EnumFilters(out enumFilters);
enumFilters.Reset();
IBaseFilter[] filters = new IBaseFilter[1];
while (enumFilters.Next(1, filters, IntPtr.Zero) == 0)
{
FilterInfo filterInfo;
filters[0].QueryFilterInfo(out filterInfo);
writer.WriteLine("Filter: " + filterInfo.achName);
IEnumPins enumPins;
filters[0].EnumPins(out enumPins);
enumPins.Reset();
IPin[] pins = new IPin[1];
while (enumPins.Next(1, pins, IntPtr.Zero) == 0)
{
PinInfo pinInfo;
pins[0].QueryPinInfo(out pinInfo);
writer.WriteLine(" Pin: " + pinInfo.name);
Marshal.ReleaseComObject(pins[0]);
}
Marshal.ReleaseComObject(enumPins);
Marshal.ReleaseComObject(filters[0]);
}
Marshal.ReleaseComObject(enumFilters);
}
writer.Close();
}
private static void RemoveAllFilters(IGraphBuilder graph)
{
IEnumFilters enumFilters;
graph.EnumFilters(out enumFilters);
IBaseFilter[] filters = new IBaseFilter[1];
while (enumFilters.Next(1, filters, IntPtr.Zero) == 0)
{
graph.RemoveFilter(filters[0]);
Marshal.ReleaseComObject(filters[0]);
}
Marshal.ReleaseComObject(enumFilters);
}
private void InitializeOverlayForm(Screen secondaryScreen)
{
overlayForm = new OverlayForm();
Screen secondMonitor = ScreenHelper.GetSecondMonitor();
if (secondMonitor != null)
{
overlayForm.Location = secondMonitor.WorkingArea.Location;
overlayForm.StartPosition = FormStartPosition.Manual;
overlayForm.Size = new Size(secondMonitor.WorkingArea.Width, secondMonitor.WorkingArea.Height);
}
overlayForm.ShowInTaskbar = false;
overlayForm.Owner = this;
overlayForm.Show();
this.Focus();
}
private bool isPlayingNext = false;
private int lastPlayedIndex = -1; // 追蹤上一首播放的索引
public void MonitorMediaEvents()
{
Console.WriteLine("開始監聽媒體事件...");
Task.Run(async () =>
{
while (true)
{
try
{
if (mediaControlSecondary == null || isPlayingNext)
{
await Task.Delay(500);
continue;
}
// 只檢查播放進度
IMediaSeeking mediaSeekingSecondary = graphBuilderSecondary as IMediaSeeking;
if (mediaSeekingSecondary != null && !isPlayingNext)
{
long currentPosition = 0;
long duration = 0;
if (mediaSeekingSecondary.GetCurrentPosition(out currentPosition) >= 0 &&
mediaSeekingSecondary.GetDuration(out duration) >= 0)
{
double currentSeconds = currentPosition / 10000000.0;
double durationSeconds = duration / 10000000.0;
// 添加更严格的结束条件判断
bool isAtEnd = durationSeconds > 0 && currentSeconds > 0 &&
Math.Abs(currentSeconds - durationSeconds) < 0.1 && // 确保真的到了结尾
!isPaused;
if (isAtEnd && !isPlayingNext)
{
Console.WriteLine($"檢測到歌曲結束 - 當前位置: {currentSeconds:F2}秒, 總時長: {durationSeconds:F2}秒");
if (!isPlayingNext)
{
isPlayingNext = true;
// 添加额外的保护:确保在切换前停止当前播放
if (mediaControlSecondary != null)
{
mediaControlSecondary.Stop();
}
this.BeginInvoke(new Action(async () =>
{
try
{
// 在切换前释放资源
StopAndReleaseResources();
await Task.Delay(100); // 给予足够的时间释放资源
if (isUserPlaylistPlaying && playingSongList != null)
{
if (playingSongList.Count > 0)
{
try
{
// 移除當前播放的歌曲
playingSongList.RemoveAt(0);
// 更新播放状态逻辑
if (PrimaryForm.currentSongIndexInHistory >= 0)
{
// 将当前播放的歌曲标记为已播放
PrimaryForm.playStates[PrimaryForm.currentSongIndexInHistory] = PlayState.Played;
// 如果还有下一首歌
if (playingSongList.Count > 0)
{
PrimaryForm.currentSongIndexInHistory++;
// 将下一首歌标记为正在播放
if (PrimaryForm.currentSongIndexInHistory < PrimaryForm.playStates.Count)
{
PrimaryForm.playStates[PrimaryForm.currentSongIndexInHistory] = PlayState.Playing;
}
}
}
if (playingSongList.Count == 0)
{
Console.WriteLine("用戶播放列表已播放完畢,切換到公共播放列表");
// 确保当前歌曲状态更新为已播放
if (PrimaryForm.currentSongIndexInHistory >= 0 &&
PrimaryForm.currentSongIndexInHistory < PrimaryForm.playStates.Count)
{
PrimaryForm.playStates[PrimaryForm.currentSongIndexInHistory] = PlayState.Played;
Console.WriteLine($"已將最後一首歌曲狀態更新為已播放,索引:{PrimaryForm.currentSongIndexInHistory}");
// 强制刷新显示
if (PrimaryForm.Instance.multiPagePanel != null)
{
PrimaryForm.Instance.multiPagePanel.LoadPlayedSongs(
PrimaryForm.playedSongsHistory,
PrimaryForm.playStates
);
}
}
// 重置播放状态但保留历史记录
isUserPlaylistPlaying = false;
currentSongIndex = -1;
// 确保所有未播放的歌曲状态被清除
for (int i = PrimaryForm.currentSongIndexInHistory + 1;
i < PrimaryForm.playStates.Count; i++)
{
if (PrimaryForm.playStates[i] == PlayState.Playing)
{
PrimaryForm.playStates[i] = PlayState.NotPlayed;
}
}
// 添加延迟以确保状态更新完成
await Task.Delay(200);
await InitializeAndPlayPublicPlaylist();
}
else
{
currentSongIndex = -1;
await PlayNextSong();
}
}
catch (Exception ex)
{
Console.WriteLine($"處理播放列表時發生錯誤: {ex.Message}");
lastPlayedIndex = -1;
isUserPlaylistPlaying = false;
currentSongIndex = -1;
await InitializeAndPlayPublicPlaylist();
}
}
}
else if (!isUserPlaylistPlaying && publicPlaylist != null)
{
await PlayNextSong();
}
}
catch (Exception ex)
{
Console.WriteLine($"切換歌曲時發生錯誤: {ex.Message}");
// 发生错误时重置状态并切换到公播
lastPlayedIndex = -1;
isUserPlaylistPlaying = false;
currentSongIndex = -1;
await InitializeAndPlayPublicPlaylist();
}
finally
{
isPlayingNext = false;
}
}));
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"監控媒體事件時發生錯誤: {ex.Message}");
isPlayingNext = false;
// 添加重试机制
if (!isUserPlaylistPlaying && publicPlaylist != null)
{
await Task.Delay(1000);
await PlayNextSong();
}
await Task.Delay(1000);
}
await Task.Delay(500);
}
});
}
public void BringOverlayToFront()
{
if (overlayForm != null)
{
if (!overlayForm.Visible)
{
overlayForm.Show();
}
overlayForm.BringToFront();
overlayForm.TopMost = true;
}
}
public void Play()
{
if (mediaControlPrimary != null)
mediaControlPrimary.Run();
if (mediaControlSecondary != null)
mediaControlSecondary.Run();
isPaused = false;
OverlayForm.MainForm.HidePauseLabel();
}
public void Stop()
{
if (mediaControlPrimary != null)
mediaControlPrimary.Stop();
if (mediaControlSecondary != null)
mediaControlSecondary.Stop();
}
public void Pause()
{
if (mediaControlPrimary != null)
mediaControlPrimary.Pause();
if (mediaControlSecondary != null)
mediaControlSecondary.Pause();
isPaused = true;
OverlayForm.MainForm.ShowPauseLabel();
}
public void PauseOrResumeSong()
{
if (isPaused)
{
Play();
PrimaryForm.Instance.pauseButton.Visible = true;
PrimaryForm.Instance.playButton.Visible = false;
PrimaryForm.Instance.syncPauseButton.Visible = true;
PrimaryForm.Instance.syncPlayButton.Visible = false;
}
else
{
Pause();
PrimaryForm.Instance.pauseButton.Visible = false;
PrimaryForm.Instance.playButton.Visible = true;
PrimaryForm.Instance.syncPauseButton.Visible = false;
PrimaryForm.Instance.syncPlayButton.Visible = true;
OverlayForm.MainForm.ShowPauseLabel();
}
}
private void UpdateSyncButtons()
{
if (isPaused)
{
PrimaryForm.Instance.syncPlayButton.Visible = true;
PrimaryForm.Instance.syncPauseButton.Visible = false;
}
else
{
PrimaryForm.Instance.syncPlayButton.Visible = false;
PrimaryForm.Instance.syncPauseButton.Visible = true;
}
}
public void SetVolume(int volume)
{
if (audioRenderer != null)
{
IBasicAudio basicAudio = audioRenderer as IBasicAudio;
if (basicAudio != null)
{
basicAudio.put_Volume(volume);
}
}
}
public int GetVolume()
{
if (audioRenderer != null)
{
IBasicAudio basicAudio = audioRenderer as IBasicAudio;
if (basicAudio != null)
{
int volume;
basicAudio.get_Volume(out volume);
return volume;
}
}
return -10000;
}
private bool isVocalRemoved = false;
public async void ToggleVocalRemoval()
{
try
{
IAMStreamSelect streamSelect = lavSplitterSecondary as IAMStreamSelect;
if (streamSelect != null)
{
int trackCount;
if (streamSelect.Count(out trackCount) == 0 && trackCount > 0)
{
int currentTrackIndex = -1;
int audioTrack1 = -1;
int audioTrack2 = -1;
for (int i = 0; i < trackCount; i++)
{
// 獲取音軌信息
AMMediaType mediaType;
AMStreamSelectInfoFlags flags;
int lcid, dwGroup;
string name;
object pObject, pUnk;
streamSelect.Info(i, out mediaType, out flags, out lcid, out dwGroup, out name, out pObject, out pUnk);
if (mediaType.majorType == MediaType.Audio)
{
if (audioTrack1 == -1)
{
audioTrack1 = i;
} else if (audioTrack2 == -1) {
audioTrack2 = i;
}
if ((flags & AMStreamSelectInfoFlags.Enabled) != 0)
{
currentTrackIndex = i;
}
}
DsUtils.FreeAMMediaType(mediaType);
}
// 切換音軌
if (currentTrackIndex == audioTrack1 && audioTrack2 != -1)
{
streamSelect.Enable(audioTrack2, AMStreamSelectEnableFlags.Enable);
isVocalRemoved = true;
}
else if (currentTrackIndex == audioTrack2 && audioTrack1 != -1)
{
streamSelect.Enable(audioTrack1, AMStreamSelectEnableFlags.Enable);
isVocalRemoved = false;
}
//OverlayForm.MainForm.ShowOriginalSongLabel();
string labelText = isVocalRemoved ? "無人聲" : "有人聲";
// 显示标签
// 修改成新標籤
OverlayForm.MainForm.HideAllLabels();
OverlayForm.MainForm.ShowOriginalSongLabel(labelText);
//await Task.Delay(3000);
// 隐藏标签
//OverlayForm.MainForm.HideOriginalSongLabel();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void SetAudioTrackTo(int trackIndex)
{
try
{
IAMStreamSelect streamSelect = lavSplitterSecondary as IAMStreamSelect;
if (streamSelect != null)
{
int trackCount;
if (streamSelect.Count(out trackCount) == 0 && trackCount > 0)
{
int audioTrackIndex = -1;
for (int i = 0; i < trackCount; i++)
{
AMMediaType mediaType;
AMStreamSelectInfoFlags flags;
int lcid, dwGroup;
string name;
object pObject, pUnk;
streamSelect.Info(i, out mediaType, out flags, out lcid, out dwGroup, out name, out pObject, out pUnk);
if (mediaType.majorType == MediaType.Audio)
{
audioTrackIndex++;
if (audioTrackIndex == trackIndex)
{
streamSelect.Enable(i, AMStreamSelectEnableFlags.Enable);
}
else
{
streamSelect.Enable(i, AMStreamSelectEnableFlags.DisableAll);
}
}
DsUtils.FreeAMMediaType(mediaType);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void AddSongToPlaylist(SongData songData)
{
try{
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
// 查找所有相同歌曲的索引
var sameNameIndices = new List<int>();
for (int i = 0; i < PrimaryForm.playedSongsHistory.Count; i++)
{
if (PrimaryForm.playedSongsHistory[i].Name == songData.Name)
{
sameNameIndices.Add(i);
}
}
// 添加新歌到播放列表
PrimaryForm.userRequestedSongs.Add(songData);
PrimaryForm.playedSongsHistory.Add(songData);
// 更新状态
if (wasEmpty)
{
// 如果是空列表,设置为正在播放
PrimaryForm.playStates.Add(PlayState.Playing);
PrimaryForm.currentSongIndexInHistory = PrimaryForm.playedSongsHistory.Count - 1;
// 确保之前相同歌曲的状态为已播放
foreach (int index in sameNameIndices)
{
if (index < PrimaryForm.currentSongIndexInHistory)
{
PrimaryForm.playStates[index] = PlayState.Played;
}
}
VideoPlayerForm.Instance.SetPlayingSongList(PrimaryForm.userRequestedSongs);
}
else
{
// 如果不是空列表,设置为未播放
PrimaryForm.playStates.Add(PlayState.NotPlayed);
// 更新所有相同歌曲的状态
foreach (int index in sameNameIndices.Where(i => i < PrimaryForm.playedSongsHistory.Count - 1))
{
if (index < PrimaryForm.currentSongIndexInHistory)
{
// 之前的相同歌曲标记为已播放
PrimaryForm.playStates[index] = PlayState.Played;
}
else if (index == PrimaryForm.currentSongIndexInHistory)
{
// 当前播放的歌曲保持Playing状态
PrimaryForm.playStates[index] = PlayState.Playing;
}
else
{
// 后面的相同歌曲标记为未播放
PrimaryForm.playStates[index] = PlayState.NotPlayed;
}
}
}
VideoPlayerForm.Instance.UpdateNextSongFromPlaylist();
PrimaryForm.PrintPlayingSongList();
}
catch (Exception ex)
{
Console.WriteLine("Error occurred: " + ex.Message);
}
}
public void InsertSongToPlaylist(SongData songData)
{
try{
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
// 查找所有相同歌曲的索引
var sameNameIndices = new List<int>();
for (int i = 0; i < PrimaryForm.playedSongsHistory.Count; i++)
{
if (PrimaryForm.playedSongsHistory[i].Name == songData.Name)
{
sameNameIndices.Add(i);
}
}
if (wasEmpty)
{
// 如果列表为空,直接添加
PrimaryForm.userRequestedSongs.Add(songData);
PrimaryForm.playedSongsHistory.Add(songData);
PrimaryForm.playStates.Add(PlayState.Playing);
PrimaryForm.currentSongIndexInHistory = PrimaryForm.playedSongsHistory.Count - 1;
// 更新之前相同歌曲的状态
foreach (int index in sameNameIndices)
{
if (index < PrimaryForm.currentSongIndexInHistory)
{
PrimaryForm.playStates[index] = PlayState.Played;
}
}
VideoPlayerForm.Instance.SetPlayingSongList(PrimaryForm.userRequestedSongs);
}
else
{
// 插入到当前播放歌曲之后
int insertIndex = PrimaryForm.currentSongIndexInHistory + 1;
PrimaryForm.userRequestedSongs.Insert(1, songData);
PrimaryForm.playedSongsHistory.Insert(insertIndex, songData);
PrimaryForm.playStates.Insert(insertIndex, PlayState.NotPlayed);
// 更新所有相同歌曲的状态
foreach (int index in sameNameIndices)
{
if (index < PrimaryForm.currentSongIndexInHistory)
{
// 之前的相同歌曲标记为已播放
PrimaryForm.playStates[index] = PlayState.Played;
}
else if (index == PrimaryForm.currentSongIndexInHistory)
{
// 当前播放的歌曲保持Playing状态
PrimaryForm.playStates[index] = PlayState.Playing;
}
else if (index > insertIndex)
{
// 后面的相同歌曲标记为未播放
PrimaryForm.playStates[index] = PlayState.NotPlayed;
}
}
}
VideoPlayerForm.Instance.UpdateNextSongFromPlaylist();
PrimaryForm.PrintPlayingSongList();
}
catch (Exception ex)
{
Console.WriteLine("Error occurred: " + ex.Message);
}
}
public VideoStatus GetCurrentVideoStatus()
{
var status = new VideoStatus();
try
{
IMediaSeeking mediaSeekingSecondary = graphBuilderSecondary as IMediaSeeking;
if (mediaSeekingSecondary != null)
{
long position;
if (mediaSeekingSecondary.GetCurrentPosition(out position) >= 0)
{
status.PositionSeconds = position / 10000000.0;
}
else
{
status.LastError = "無法取得影片播放位置";
status.PositionSeconds = -1;
}
}
else
{
status.LastError = "mediaSeekingSecondary 物件為 null";
status.PositionSeconds = -1;
}
if (mediaControlSecondary != null)
{
FilterState stateCode;
int hr = mediaControlSecondary.GetState(100, out stateCode);
if (hr >= 0)
{
var state = (FilterState)stateCode;
status.PlayState = state.ToString();
status.LastError = state.ToString();
status.IsGraphOk = true;
}
else
{
status.PlayState = "無法取得播放狀態";
status.LastError = "無法取得播放狀態";
status.IsGraphOk = false;
}
}
else
{
status.PlayState = "mediaControlSecondary 物件為 null";
status.LastError = "mediaControlSecondary 物件為 null";
status.IsGraphOk = false;
}
}
catch (Exception ex)
{
status.LastError = "取得影片狀態時發生例外:" + ex.Message;
status.PositionSeconds = -1;
status.PlayState = "Error";
status.IsGraphOk = false;
}
return status;
}
}
}