superstar_v2/Services/MediaService.cs

234 lines
9.0 KiB
C#
Raw Normal View History

using DirectShowLib;
using System;
using System.Runtime.InteropServices;
namespace DualScreenDemo.Services
{
2025-08-08 16:42:15 +08:00
public class MediaService : Video
{
public IGraphBuilder graphBuilder;
private IMediaControl mediaControl;
public IBaseFilter renderer;
//private IBaseFilter audioRenderer;
private IBaseFilter lavSplitter;
private IVideoWindow videoWindow;
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 VideoPlayerForm_FormClosing()
{
if (videoWindow != null)
{
videoWindow.put_Visible(OABool.False);
videoWindow.put_Owner(IntPtr.Zero);
Marshal.ReleaseComObject(videoWindow);
videoWindow = null;
}
}
public bool IsAtEnd()
{
bool isAtEnd = false;
if (mediaControl == null) { return false; }
IMediaSeeking mediaSeeking = graphBuilder as IMediaSeeking;
if (mediaSeeking != null)
{
long currentPosition;
long duration;
if (mediaSeeking.GetCurrentPosition(out currentPosition) >= 0 &&
mediaSeeking.GetDuration(out duration) >= 0)
{
double currentSeconds = currentPosition / 10000000.0;
double durationSeconds = duration / 10000000.0;
// 添加更严格的结束条件判断
isAtEnd = durationSeconds > 0 && currentSeconds > 0 &&
Math.Abs(currentSeconds - durationSeconds) < 0.1; // 确保真的到了结尾
//Console.WriteLine($"檢測到歌曲 - 當前位置: {currentSeconds:F2}秒, 總時長: {durationSeconds:F2}秒");
if (isAtEnd)
{
Console.WriteLine($"檢測到歌曲 -結束: {currentSeconds:F2}秒, 總時長: {durationSeconds:F2}秒");
}
}
}
return isAtEnd;
}
public void RenderMediaFile(string filePath, nint Handle, int Width, int Height)
{
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();
try
{
lavSplitter = AddFilterByClsid(graphBuilder, "LAV Splitter", Clsid.LAVSplitter);
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;
}
catch (Exception ex)
{
Console.WriteLine("Error initializing graph builder with second monitor: " + ex.Message);
}
hr = graphBuilder.RenderFile(filePath, null);
if (hr == 0)
SetAudioTrackTo(1);
else
Console.WriteLine("Failed to render secondary file.");
// 绑定视频窗口到副屏幕
videoWindow = renderer 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);
}
mediaControl.Run();
}
public void SetVolume(int volume)
{
if (graphBuilder != null)
{
IBasicAudio basicAudio = graphBuilder as IBasicAudio;
if (basicAudio != null)
basicAudio.put_Volume( Math.Max(-10000, Math.Min(0, volume)));
}
}
public int GetVolume()
{
if (graphBuilder != null)
{
IBasicAudio basicAudio = graphBuilder as IBasicAudio;
if (basicAudio != null)
{
int volume;
basicAudio.get_Volume(out volume);
return volume;
}
}
return -10000;
}
private bool isVocalRemoved = false;
public bool ToggleVocalRemoval()
{
try
{
IAMStreamSelect streamSelect = lavSplitter 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;
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return isVocalRemoved;
}
public void SetAudioTrackTo(int trackIndex)
{
try
{
IAMStreamSelect streamSelect = lavSplitter 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);
}
}
}
}