Mpc-hc detection fixes

This commit is contained in:
niksedk 2014-10-14 13:52:14 +02:00
parent 5978fe473b
commit e733860ff9
3 changed files with 615 additions and 594 deletions

File diff suppressed because it is too large Load Diff

View File

@ -138,6 +138,8 @@ namespace Nikse.SubtitleEdit.Forms
radioButtonVideoPlayerMPlayer.Enabled = false; radioButtonVideoPlayerMPlayer.Enabled = false;
if (!Utilities.IsQuartsDllInstalled) if (!Utilities.IsQuartsDllInstalled)
radioButtonVideoPlayerDirectShow.Enabled = false; radioButtonVideoPlayerDirectShow.Enabled = false;
if (Nikse.SubtitleEdit.Logic.VideoPlayers.MpcHC.MpcHc.GetMpcHcFileName() == null)
radioButtonVideoPlayerMpcHc.Enabled = false;
textBoxVlcPath.Text = Configuration.Settings.General.VlcLocation; textBoxVlcPath.Text = Configuration.Settings.General.VlcLocation;
textBoxVlcPath.Left = labelVideoPlayerVLC.Left + labelVideoPlayerVLC.Width + 5; textBoxVlcPath.Left = labelVideoPlayerVLC.Left + labelVideoPlayerVLC.Width + 5;

View File

@ -1,398 +1,414 @@
using Nikse.SubtitleEdit.Core; using Nikse.SubtitleEdit.Core;
using System; using System;
using System.Collections; using System.Collections;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
namespace Nikse.SubtitleEdit.Logic.VideoPlayers.MpcHC namespace Nikse.SubtitleEdit.Logic.VideoPlayers.MpcHC
{ {
public class MpcHc : VideoPlayer, IDisposable public class MpcHc : VideoPlayer, IDisposable
{ {
private const string ModePlay = "0"; private const string ModePlay = "0";
private const string ModePause = "1"; private const string ModePause = "1";
private string _playMode = string.Empty; private string _playMode = string.Empty;
private const string StateLoaded = "2"; private const string StateLoaded = "2";
private int _loaded = 0; private int _loaded = 0;
private IntPtr _mpcHandle = IntPtr.Zero; private IntPtr _mpcHandle = IntPtr.Zero;
private IntPtr _videoHandle = IntPtr.Zero; private IntPtr _videoHandle = IntPtr.Zero;
private IntPtr _videoPanelHandle = IntPtr.Zero; private IntPtr _videoPanelHandle = IntPtr.Zero;
private ProcessStartInfo _startInfo; private ProcessStartInfo _startInfo;
private Process _process; private Process _process;
private IntPtr _messageHandlerHandle = IntPtr.Zero; private IntPtr _messageHandlerHandle = IntPtr.Zero;
private string _videoFileName; private string _videoFileName;
private System.Windows.Forms.Timer _positionTimer; private System.Windows.Forms.Timer _positionTimer;
private double _positionInSeconds = 0; private double _positionInSeconds = 0;
private double _durationInSeconds = 0; private double _durationInSeconds = 0;
private MessageHandlerWindow _form; private MessageHandlerWindow _form;
private int _initialWidth; private int _initialWidth;
private int _initialHeight; private int _initialHeight;
public override string PlayerName public override string PlayerName
{ {
get { return "MPC-HC"; } get { return "MPC-HC"; }
} }
private int _volume = 75; private int _volume = 75;
public override int Volume public override int Volume
{ {
get get
{ {
return _volume; return _volume;
} }
set set
{ {
// MPC-HC moves from 0-100 in steps of 5 // MPC-HC moves from 0-100 in steps of 5
for (int i = 0; i < 100; i += 5) for (int i = 0; i < 100; i += 5)
SendMpcMessage(MpcHcCommand.DecreaseVolume); SendMpcMessage(MpcHcCommand.DecreaseVolume);
for (int _volume = 0; _volume < value; _volume += 5) for (int _volume = 0; _volume < value; _volume += 5)
SendMpcMessage(MpcHcCommand.IncreaseVolume); SendMpcMessage(MpcHcCommand.IncreaseVolume);
} }
} }
public override double Duration public override double Duration
{ {
get get
{ {
return _durationInSeconds; return _durationInSeconds;
} }
} }
public override double CurrentPosition public override double CurrentPosition
{ {
get get
{ {
return _positionInSeconds; return _positionInSeconds;
} }
set set
{ {
SendMpcMessage(MpcHcCommand.SetPosition, string.Format(CultureInfo.InvariantCulture, "{0:0.000}", value)); SendMpcMessage(MpcHcCommand.SetPosition, string.Format(CultureInfo.InvariantCulture, "{0:0.000}", value));
} }
} }
public override void Play() public override void Play()
{ {
_playMode = ModePlay; _playMode = ModePlay;
SendMpcMessage(MpcHcCommand.Play); SendMpcMessage(MpcHcCommand.Play);
} }
public override void Pause() public override void Pause()
{ {
_playMode = ModePause; _playMode = ModePause;
SendMpcMessage(MpcHcCommand.Pause); SendMpcMessage(MpcHcCommand.Pause);
} }
public override void Stop() public override void Stop()
{ {
SendMpcMessage(MpcHcCommand.Stop); SendMpcMessage(MpcHcCommand.Stop);
} }
public override bool IsPaused public override bool IsPaused
{ {
get { return _playMode == ModePause; } get { return _playMode == ModePause; }
} }
public override bool IsPlaying public override bool IsPlaying
{ {
get { return _playMode == ModePlay; } get { return _playMode == ModePlay; }
} }
public override void Initialize(System.Windows.Forms.Control ownerControl, string videoFileName, EventHandler onVideoLoaded, EventHandler onVideoEnded) public override void Initialize(System.Windows.Forms.Control ownerControl, string videoFileName, EventHandler onVideoLoaded, EventHandler onVideoEnded)
{ {
if (ownerControl == null) if (ownerControl == null)
return; return;
VideoFileName = videoFileName; VideoFileName = videoFileName;
OnVideoLoaded = onVideoLoaded; OnVideoLoaded = onVideoLoaded;
OnVideoEnded = onVideoEnded; OnVideoEnded = onVideoEnded;
_initialWidth = ownerControl.Width; _initialWidth = ownerControl.Width;
_initialHeight = ownerControl.Height; _initialHeight = ownerControl.Height;
_form = new MessageHandlerWindow(); _form = new MessageHandlerWindow();
_form.OnCopyData += OnCopyData; _form.OnCopyData += OnCopyData;
_form.Show(); _form.Show();
_form.Hide(); _form.Hide();
_videoPanelHandle = ownerControl.Handle; _videoPanelHandle = ownerControl.Handle;
_messageHandlerHandle = _form.Handle; _messageHandlerHandle = _form.Handle;
_videoFileName = videoFileName; _videoFileName = videoFileName;
_startInfo = new ProcessStartInfo(); _startInfo = new ProcessStartInfo();
_startInfo.FileName = GetMpcHcFileName(); _startInfo.FileName = GetMpcHcFileName();
_startInfo.Arguments = "/new /minimized /slave " + _messageHandlerHandle; _startInfo.Arguments = "/new /minimized /slave " + _messageHandlerHandle;
_process = Process.Start(_startInfo); _process = Process.Start(_startInfo);
_process.WaitForInputIdle(); _process.WaitForInputIdle();
_positionTimer = new Timer(); _positionTimer = new Timer();
_positionTimer.Interval = 100; _positionTimer.Interval = 100;
_positionTimer.Tick += PositionTimerTick; _positionTimer.Tick += PositionTimerTick;
} }
private void PositionTimerTick(object sender, EventArgs e) private void PositionTimerTick(object sender, EventArgs e)
{ {
SendMpcMessage(MpcHcCommand.GetCurrentPosition); SendMpcMessage(MpcHcCommand.GetCurrentPosition);
} }
private void OnCopyData(object sender, EventArgs e) private void OnCopyData(object sender, EventArgs e)
{ {
var message = (Message)sender; var message = (Message)sender;
var cds = (NativeMethods.CopyDataStruct)Marshal.PtrToStructure(message.LParam, typeof(NativeMethods.CopyDataStruct)); var cds = (NativeMethods.CopyDataStruct)Marshal.PtrToStructure(message.LParam, typeof(NativeMethods.CopyDataStruct));
var command = cds.dwData.ToUInt32(); var command = cds.dwData.ToUInt32();
var param = Marshal.PtrToStringAuto(cds.lpData); var param = Marshal.PtrToStringAuto(cds.lpData);
var multiParam = param.Split('|'); var multiParam = param.Split('|');
switch (cds.dwData.ToUInt32()) switch (cds.dwData.ToUInt32())
{ {
case MpcHcCommand.Connect: case MpcHcCommand.Connect:
_positionTimer.Stop(); _positionTimer.Stop();
_mpcHandle = (IntPtr)Convert.ToInt64(Marshal.PtrToStringAuto(cds.lpData)); _mpcHandle = (IntPtr)Convert.ToInt64(Marshal.PtrToStringAuto(cds.lpData));
SendMpcMessage(MpcHcCommand.OpenFile, _videoFileName); SendMpcMessage(MpcHcCommand.OpenFile, _videoFileName);
_positionTimer.Start(); _positionTimer.Start();
break; break;
case MpcHcCommand.PlayMode: case MpcHcCommand.PlayMode:
_playMode = param; _playMode = param;
if (param == ModePlay && _loaded == 0) if (param == ModePlay && _loaded == 0)
{ {
_loaded = 1; _loaded = 1;
if (!HijackMpcHc()) if (!HijackMpcHc())
{ {
Application.DoEvents(); Application.DoEvents();
HijackMpcHc(); HijackMpcHc();
} }
} }
break; break;
case MpcHcCommand.NowPlaying: case MpcHcCommand.NowPlaying:
if (_loaded == 1) if (_loaded == 1)
{ {
_loaded = 2; _loaded = 2;
_durationInSeconds = double.Parse(multiParam[4], CultureInfo.InvariantCulture); _durationInSeconds = double.Parse(multiParam[4], CultureInfo.InvariantCulture);
Pause(); Pause();
Resize(_initialWidth, _initialHeight); Resize(_initialWidth, _initialHeight);
if (OnVideoLoaded != null) if (OnVideoLoaded != null)
OnVideoLoaded.Invoke(this, new EventArgs()); OnVideoLoaded.Invoke(this, new EventArgs());
SendMpcMessage(MpcHcCommand.SetSubtitleTrack, "-1"); SendMpcMessage(MpcHcCommand.SetSubtitleTrack, "-1");
} }
break; break;
case MpcHcCommand.NotifyEndOfStream: case MpcHcCommand.NotifyEndOfStream:
if (OnVideoEnded != null) if (OnVideoEnded != null)
OnVideoEnded.Invoke(this, new EventArgs()); OnVideoEnded.Invoke(this, new EventArgs());
break; break;
case MpcHcCommand.CurrentPosition: case MpcHcCommand.CurrentPosition:
_positionInSeconds = double.Parse(param, CultureInfo.InvariantCulture); _positionInSeconds = double.Parse(param, CultureInfo.InvariantCulture);
break; break;
} }
} }
internal static bool GetWindowHandle(IntPtr windowHandle, ArrayList windowHandles) internal static bool GetWindowHandle(IntPtr windowHandle, ArrayList windowHandles)
{ {
windowHandles.Add(windowHandle); windowHandles.Add(windowHandle);
return true; return true;
} }
private ArrayList GetChildWindows() private ArrayList GetChildWindows()
{ {
var windowHandles = new ArrayList(); var windowHandles = new ArrayList();
NativeMethods.EnumedWindow callBackPtr = GetWindowHandle; NativeMethods.EnumedWindow callBackPtr = GetWindowHandle;
NativeMethods.EnumChildWindows(_process.MainWindowHandle, callBackPtr, windowHandles); NativeMethods.EnumChildWindows(_process.MainWindowHandle, callBackPtr, windowHandles);
return windowHandles; return windowHandles;
} }
private static bool IsWindowMpcHcVideo(IntPtr hWnd) private static bool IsWindowMpcHcVideo(IntPtr hWnd)
{ {
var className = new StringBuilder(256); var className = new StringBuilder(256);
int returnCode = NativeMethods.GetClassName(hWnd, className, className.Capacity); // Get the window class name int returnCode = NativeMethods.GetClassName(hWnd, className, className.Capacity); // Get the window class name
if (returnCode != 0) if (returnCode != 0)
return (className.ToString().EndsWith(":b:0000000000010003:0000000000000006:0000000000000000")); // MPC-HC video class??? return (className.ToString().EndsWith(":b:0000000000010003:0000000000000006:0000000000000000")); // MPC-HC video class???
return false; return false;
} }
private bool HijackMpcHc() private bool HijackMpcHc()
{ {
IntPtr handle = _process.MainWindowHandle; IntPtr handle = _process.MainWindowHandle;
var handles = GetChildWindows(); var handles = GetChildWindows();
foreach (var h in handles) foreach (var h in handles)
{ {
if (IsWindowMpcHcVideo((IntPtr)h)) if (IsWindowMpcHcVideo((IntPtr)h))
{ {
_videoHandle = (IntPtr)h; _videoHandle = (IntPtr)h;
NativeMethods.SetParent((IntPtr)h, _videoPanelHandle); NativeMethods.SetParent((IntPtr)h, _videoPanelHandle);
NativeMethods.SetWindowPos(handle, (IntPtr)NativeMethods.SpecialWindowHandles.HWND_TOP, -9999, -9999, 0, 0, NativeMethods.SetWindowPosFlags.SWP_NOACTIVATE); NativeMethods.SetWindowPos(handle, (IntPtr)NativeMethods.SpecialWindowHandles.HWND_TOP, -9999, -9999, 0, 0, NativeMethods.SetWindowPosFlags.SWP_NOACTIVATE);
return true; return true;
} }
} }
return false; return false;
} }
public override void Resize(int width, int height) public override void Resize(int width, int height)
{ {
NativeMethods.ShowWindow(_process.MainWindowHandle, NativeMethods.ShowWindowCommands.ShowNoActivate); NativeMethods.ShowWindow(_process.MainWindowHandle, NativeMethods.ShowWindowCommands.ShowNoActivate);
NativeMethods.SetWindowPos(_videoHandle, (IntPtr)NativeMethods.SpecialWindowHandles.HWND_TOP, 0, 0, width, height, NativeMethods.SetWindowPosFlags.SWP_NOREPOSITION); NativeMethods.SetWindowPos(_videoHandle, (IntPtr)NativeMethods.SpecialWindowHandles.HWND_TOP, 0, 0, width, height, NativeMethods.SetWindowPosFlags.SWP_NOREPOSITION);
NativeMethods.ShowWindow(_process.MainWindowHandle, NativeMethods.ShowWindowCommands.Hide); NativeMethods.ShowWindow(_process.MainWindowHandle, NativeMethods.ShowWindowCommands.Hide);
} }
public static string GetMpcHcFileName() public static string GetMpcHcFileName()
{ {
string path; string path;
if (IntPtr.Size == 8) // 64-bit if (IntPtr.Size == 8) // 64-bit
{ {
path = Path.Combine(Configuration.BaseDirectory, @"MPC-HC\mpc-hc64.exe"); path = Path.Combine(Configuration.BaseDirectory, @"MPC-HC\mpc-hc64.exe");
if (File.Exists(path)) if (File.Exists(path))
return path; return path;
if (!string.IsNullOrEmpty(Configuration.Settings.General.MpcHcLocation)) if (!string.IsNullOrEmpty(Configuration.Settings.General.MpcHcLocation))
{ {
path = Path.GetDirectoryName(Configuration.Settings.General.MpcHcLocation); path = Path.GetDirectoryName(Configuration.Settings.General.MpcHcLocation);
if (File.Exists(path) && path.EndsWith("mpc-hc64.exe", StringComparison.OrdinalIgnoreCase)) if (File.Exists(path) && path.EndsWith("mpc-hc64.exe", StringComparison.OrdinalIgnoreCase))
return path; return path;
} }
path = RegistryUtil.GetValue(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{2ACBF1FA-F5C3-4B19-A774-B22A31F231B9}_is1", "InstallLocation"); path = RegistryUtil.GetValue(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{2ACBF1FA-F5C3-4B19-A774-B22A31F231B9}_is1", "InstallLocation");
if (path != null) if (path != null)
{ {
path = Path.Combine(path, "mpc-hc64.exe"); path = Path.Combine(path, "mpc-hc64.exe");
if (File.Exists(path)) if (File.Exists(path))
return path; return path;
} }
path = @"C:\Program Files\MPC-HC\mpc-hc64.exe"; path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"MPC-HC\mpc-hc64.exe");
if (File.Exists(path)) if (File.Exists(path))
return path; return path;
path = @"C:\Program Files (x86)\MPC-HC\mpc-hc64.exe"; path = @"C:\Program Files\MPC-HC\mpc-hc64.exe";
if (File.Exists(path)) if (File.Exists(path))
return path; return path;
}
else path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"K-Lite Codec Pack\MPC-HC\mpc-hc64.exe");
{ if (File.Exists(path))
path = Path.Combine(Configuration.BaseDirectory, @"MPC-HC\mpc-hc.exe"); return path;
if (File.Exists(path))
return path; path = @"C:\Program Files (x86)\MPC-HC\mpc-hc64.exe";
if (File.Exists(path))
if (!string.IsNullOrEmpty(Configuration.Settings.General.MpcHcLocation)) return path;
{ }
path = Path.GetDirectoryName(Configuration.Settings.General.MpcHcLocation); else
if (File.Exists(path) && path.EndsWith("mpc-hc.exe", StringComparison.OrdinalIgnoreCase)) {
return path; path = Path.Combine(Configuration.BaseDirectory, @"MPC-HC\mpc-hc.exe");
} if (File.Exists(path))
return path;
path = RegistryUtil.GetValue(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{2624B969-7135-4EB1-B0F6-2D8C397B45F7}_is1", "InstallLocation");
if (path != null) if (!string.IsNullOrEmpty(Configuration.Settings.General.MpcHcLocation))
{ {
path = Path.Combine(path, "mpc-hc.exe"); path = Path.GetDirectoryName(Configuration.Settings.General.MpcHcLocation);
if (File.Exists(path)) if (File.Exists(path) && path.EndsWith("mpc-hc.exe", StringComparison.OrdinalIgnoreCase))
return path; return path;
} }
path = @"C:\Program Files (x86)\MPC-HC\mpc-hc.exe"; path = RegistryUtil.GetValue(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{2624B969-7135-4EB1-B0F6-2D8C397B45F7}_is1", "InstallLocation");
if (File.Exists(path)) if (path != null)
return path; {
path = Path.Combine(path, "mpc-hc.exe");
path = @"C:\Program Files\MPC-HC\mpc-hc.exe"; if (File.Exists(path))
if (File.Exists(path)) return path;
return path; }
}
path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"MPC-HC\mpc-hc.exe");
return null; if (File.Exists(path))
} return path;
public static bool IsInstalled path = @"C:\Program Files (x86)\MPC-HC\mpc-hc.exe";
{ if (File.Exists(path))
get { return true; } return path;
}
path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"K-Lite Codec Pack\MPC-HC\mpc-hc.exe");
public override void DisposeVideoPlayer() if (File.Exists(path))
{ return path;
Dispose();
} path = @"C:\Program Files\MPC-HC\mpc-hc.exe";
if (File.Exists(path))
public override event EventHandler OnVideoLoaded; return path;
}
public override event EventHandler OnVideoEnded;
return null;
private void ReleaseUnmangedResources() }
{
try public static bool IsInstalled
{ {
lock (this) get { return true; }
{ }
if (_mpcHandle != IntPtr.Zero)
{ public override void DisposeVideoPlayer()
SendMpcMessage(MpcHcCommand.CloseApplication); {
_mpcHandle = IntPtr.Zero; Dispose();
} }
}
} public override event EventHandler OnVideoLoaded;
catch
{ public override event EventHandler OnVideoEnded;
}
} private void ReleaseUnmangedResources()
{
~MpcHc() try
{ {
Dispose(false); lock (this)
} {
if (_mpcHandle != IntPtr.Zero)
public void Dispose() {
{ SendMpcMessage(MpcHcCommand.CloseApplication);
Dispose(true); _mpcHandle = IntPtr.Zero;
GC.SuppressFinalize(this); }
} }
}
protected virtual void Dispose(bool disposing) catch
{ {
try }
{ }
if (disposing)
{ ~MpcHc()
// release managed resources {
if (_positionTimer != null) Dispose(false);
{ }
_positionTimer.Stop();
_positionTimer.Dispose(); public void Dispose()
_positionTimer = null; {
} Dispose(true);
GC.SuppressFinalize(this);
if (_form != null) }
{
_form.OnCopyData -= OnCopyData; protected virtual void Dispose(bool disposing)
//_form.Dispose(); this gives an error when doing File -> Exit... {
_form = null; try
} {
if (disposing)
if (_process != null) {
{ // release managed resources
_process.Dispose(); if (_positionTimer != null)
_process = null; {
} _positionTimer.Stop();
_startInfo = null; _positionTimer.Dispose();
} _positionTimer = null;
ReleaseUnmangedResources(); }
}
catch (Exception exception) if (_form != null)
{ {
MessageBox.Show(exception.Message); _form.OnCopyData -= OnCopyData;
} //_form.Dispose(); this gives an error when doing File -> Exit...
} _form = null;
}
private void SendMpcMessage(uint command)
{ if (_process != null)
SendMpcMessage(command, string.Empty); {
} _process.Dispose();
_process = null;
private void SendMpcMessage(uint command, string parameter) }
{ _startInfo = null;
if (_mpcHandle == IntPtr.Zero || _messageHandlerHandle == IntPtr.Zero) }
return; ReleaseUnmangedResources();
}
parameter += (char)0; catch (Exception exception)
NativeMethods.CopyDataStruct cds; {
cds.dwData = (UIntPtr)command; MessageBox.Show(exception.Message);
cds.cbData = parameter.Length * Marshal.SystemDefaultCharSize; }
cds.lpData = Marshal.StringToCoTaskMemAuto(parameter); }
NativeMethods.SendMessage(_mpcHandle, NativeMethods.WindowsMessageCopyData, _messageHandlerHandle, ref cds);
} private void SendMpcMessage(uint command)
{
} SendMpcMessage(command, string.Empty);
} }
private void SendMpcMessage(uint command, string parameter)
{
if (_mpcHandle == IntPtr.Zero || _messageHandlerHandle == IntPtr.Zero)
return;
parameter += (char)0;
NativeMethods.CopyDataStruct cds;
cds.dwData = (UIntPtr)command;
cds.cbData = parameter.Length * Marshal.SystemDefaultCharSize;
cds.lpData = Marshal.StringToCoTaskMemAuto(parameter);
NativeMethods.SendMessage(_mpcHandle, NativeMethods.WindowsMessageCopyData, _messageHandlerHandle, ref cds);
}
}
}