This commit is contained in:
Frank Skare
2019-03-11 06:16:39 +01:00
parent c25c605672
commit e957101268
33 changed files with 24 additions and 24 deletions

53
mpv.net/Addon.cs Normal file
View File

@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Windows.Forms;
using static mpvnet.StaticUsing;
namespace mpvnet
{
public class Addon
{
[ImportMany]
public IEnumerable<IAddon> Addons = null;
private readonly CompositionContainer CompositionContainer;
public Addon()
{
try
{
AggregateCatalog catalog = new AggregateCatalog();
string dir = Application.StartupPath + "\\Addons";
if (Directory.Exists(dir))
foreach (string i in Directory.GetDirectories(dir))
catalog.Catalogs.Add(new DirectoryCatalog(i, "*Addon.dll"));
dir = mpv.mpvConfFolderPath + "\\Addons";
if (Directory.Exists(dir))
foreach (string i in Directory.GetDirectories(dir))
catalog.Catalogs.Add(new DirectoryCatalog(i, "*Addon.dll"));
if (catalog.Catalogs.Count > 0)
{
CompositionContainer = new CompositionContainer(catalog);
CompositionContainer.ComposeParts(this);
}
}
catch (Exception e)
{
MsgError(e.ToString());
}
}
}
public interface IAddon
{
}
}

6
mpv.net/App.config Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
</configuration>

167
mpv.net/Command.cs Normal file
View File

@@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using static mpvnet.StaticUsing;
namespace mpvnet
{
public class Command
{
public string Name { get; set; }
public Action<string[]> Action { get; set; }
private static List<Command> commands;
public static List<Command> Commands
{
get
{
if (commands == null)
{
commands = new List<Command>();
var type = typeof(Command);
var methods = type.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
foreach (var i in methods)
{
var parameters = i.GetParameters();
if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != typeof(string[]))
continue;
var cmd = new Command() { Name = i.Name.Replace("_","-"), Action = (Action<string[]>)i.CreateDelegate(typeof(Action<string[]>)) };
commands.Add(cmd);
}
}
return commands;
}
}
public static void open_files(string[] args)
{
MainForm.Instance.Invoke(new Action(() => {
using (var d = new OpenFileDialog())
{
d.Multiselect = true;
d.Filter = Misc.GetFilter(Misc.FileTypes);
if (d.ShowDialog() == DialogResult.OK)
mpv.LoadFiles(d.FileNames);
}
}));
}
public static void open_config_folder(string[] args)
{
Process.Start(mpv.mpvConfFolderPath);
}
public static void show_keys(string[] args)
{
Process.Start(mpv.InputConfPath);
}
private static void CreateMpvConf()
{
if (!File.Exists(mpv.mpvConfPath))
{
if (!Directory.Exists(mpv.mpvConfFolderPath))
Directory.CreateDirectory(mpv.mpvConfFolderPath);
File.WriteAllText(mpv.mpvConfPath, "# https://mpv.io/manual/master/#configuration-files");
}
}
public static void show_prefs(string[] args)
{
CreateMpvConf();
Process.Start(mpv.mpvConfPath);
}
public static void history(string[] args)
{
var fp = mpv.mpvConfFolderPath + "history.txt";
if (File.Exists(fp))
Process.Start(fp);
else
if (MsgQuestion("Create history.txt file in config folder?\r\n\r\nmpv.net will write the date, time and filename of opened files to it.") == DialogResult.OK)
File.WriteAllText(fp, "");
}
public static void shell_execute(string[] args)
{
Process.Start(args[0]);
}
public static void set_setting(string[] args)
{
CreateMpvConf();
bool changed = false;
string fp = mpv.mpvConfPath;
var confLines = File.ReadAllLines(fp);
for (int i = 0; i < confLines.Length; i++)
{
if (confLines[i].Left("=").Trim() == args[0])
{
confLines[i] = args[0] + "=" + args[1];
changed = true;
}
}
if (changed)
{
File.WriteAllText(fp, String.Join(Environment.NewLine, confLines));
}
else
{
File.WriteAllText(fp,
File.ReadAllText(fp) + Environment.NewLine + args[0] + "=" + args[1]);
}
MsgInfo("Please restart mpv.net");
}
public static void show_info(string[] args)
{
var fi = new FileInfo(mpv.GetStringProp("path"));
using (var mi = new MediaInfo(fi.FullName))
{
var w = mi.GetInfo(MediaInfoStreamKind.Video, "Width");
var h = mi.GetInfo(MediaInfoStreamKind.Video, "Height");
var pos = TimeSpan.FromSeconds(mpv.GetIntProp("time-pos"));
var dur = TimeSpan.FromSeconds(mpv.GetIntProp("duration"));
string mibr = mi.GetInfo(MediaInfoStreamKind.Video, "BitRate");
if (mibr == "")
mibr = "0";
var br = Convert.ToInt32(mibr) / 1000.0 / 1000.0;
var vf = mpv.GetStringProp("video-format").ToUpper();
var fn = fi.Name;
if (fn.Length > 60)
fn = fn.Insert(59, "\r\n");
var info =
FormatTime(pos.TotalMinutes) + ":" +
FormatTime(pos.Seconds) + " / " +
FormatTime(dur.TotalMinutes) + ":" +
FormatTime(dur.Seconds) + "\n" +
((int)(fi.Length / 1024 / 1024)).ToString() +
$" MB - {w} x {h}\n{vf} - {br.ToString("f1")} Mb/s" + "\n" + fn;
mpv.Command("show-text", info, "5000");
string FormatTime(double value) => ((int)(Math.Floor(value))).ToString("00");
}
}
}
}

30
mpv.net/Extensions.cs Normal file
View File

@@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Linq;
namespace mpvnet
{
public static class Extensions
{
public static string Join(this IEnumerable<string> instance, string delimiter, bool removeEmpty = false)
{
if (instance == null)
return null;
bool containsEmpty = false;
foreach (var i in instance)
{
if (string.IsNullOrEmpty(i))
{
containsEmpty = true;
break;
}
}
if (containsEmpty && removeEmpty)
instance = instance.Where(arg => !string.IsNullOrEmpty(arg));
return string.Join(delimiter, instance);
}
}
}

64
mpv.net/MainForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,64 @@
namespace mpvnet
{
partial class MainForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.Timer = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// Timer
//
this.Timer.Enabled = true;
this.Timer.Interval = 1000;
this.Timer.Tick += new System.EventHandler(this.Timer_Tick);
//
// MainForm
//
this.AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(1553, 1000);
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.Name = "MainForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "mpv.net";
this.Load += new System.EventHandler(this.MainForm_Load);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Timer Timer;
}
}

302
mpv.net/MainForm.cs Normal file
View File

@@ -0,0 +1,302 @@
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using static mpvnet.StaticUsing;
namespace mpvnet
{
public partial class MainForm : Form
{
public static MainForm Instance { get; set; }
public static IntPtr Hwnd;
private Point LastCursorPosChanged;
private int LastCursorChangedTickCount;
private bool IsCloseRequired = true;
public ContextMenuStripEx CMS;
public MainForm()
{
InitializeComponent();
try
{
Application.ThreadException += Application_ThreadException;
SetFormPosSize();
Instance = this;
Hwnd = Handle;
ChangeFullscreen((mpv.mpvConv.ContainsKey("fullscreen") && mpv.mpvConv["fullscreen"] == "yes") || (mpv.mpvConv.ContainsKey("fs") && mpv.mpvConv["fs"] == "yes"));
CMS = new ContextMenuStripEx(components);
CMS.Opened += CMS_Opened;
ContextMenuStrip = CMS;
BuildMenu();
}
catch (Exception ex)
{
HandleException(ex);
}
}
public void BuildMenu()
{
if (!File.Exists(mpv.InputConfPath))
{
if (!Directory.Exists(mpv.mpvConfFolderPath))
Directory.CreateDirectory(mpv.mpvConfFolderPath);
File.WriteAllText(mpv.InputConfPath, Properties.Resources.input_conf);
}
foreach (var i in File.ReadAllText(mpv.InputConfPath).SplitLinesNoEmpty())
{
if (!i.Contains("#menu:"))
continue;
var left = i.Left("#menu:").Trim();
if (left.StartsWith("#"))
continue;
var cmd = left.Right(" ").Trim();
var menu = i.Right("#menu:").Trim();
var key = menu.Left(";").Trim();
var path = menu.Right(";").Trim();
if (path == "" || cmd == "")
continue;
var menuItem = CMS.Add(path, () => {
try
{
mpv.CommandString(cmd, false);
}
catch (Exception e)
{
MsgError(e.ToString());
}
});
if (menuItem != null)
menuItem.ShortcutKeyDisplayString = key.Replace("_","") + " ";
}
}
private void CMS_Opened(object sender, EventArgs e)
{
CursorHelp.Show();
}
private string LastHistory;
private void mpv_PlaybackRestart()
{
var fn = mpv.GetStringProp("filename");
BeginInvoke(new Action(() => { Text = fn + " - mpv.net " + Application.ProductVersion; }));
var fp = mpv.mpvConfFolderPath + "history.txt";
if (LastHistory != fn && File.Exists(fp))
{
File.AppendAllText(fp, DateTime.Now.ToString() + " " + Path.GetFileNameWithoutExtension(fn) + "\r\n");
LastHistory = fn;
}
}
private void CM_Popup(object sender, EventArgs e)
{
CursorHelp.Show();
}
private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
HandleException(e.Exception);
}
void HandleException(Exception e)
{
MsgError(e.ToString());
}
private void Mpv_VideoSizeChanged()
{
BeginInvoke(new Action(() => SetFormPosSize()));
}
private void Mpv_AfterShutdown()
{
if (IsCloseRequired)
Invoke(new Action(() => Close()));
}
public bool IsFullscreen
{
get { return WindowState == FormWindowState.Maximized; }
}
void MpvChangeFullscreen(bool value)
{
BeginInvoke(new Action(() => ChangeFullscreen(value)));
}
void ChangeFullscreen(bool value)
{
if (value)
{
FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Maximized;
}
else
{
WindowState = FormWindowState.Normal;
FormBorderStyle = FormBorderStyle.Sizable;
SetFormPosSize();
}
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x0201: // WM_LBUTTONDOWN
case 0x0202: // WM_LBUTTONUP
case 0x0100: // WM_KEYDOWN
case 0x0101: // WM_KEYUP
case 0x020A: // WM_MOUSEWHEEL
if (mpv.MpvWindowHandle != IntPtr.Zero)
Native.SendMessage(mpv.MpvWindowHandle, m.Msg, m.WParam, m.LParam);
break;
case 0x203: // Native.WM.LBUTTONDBLCLK
if (!IsMouseInOSC())
mpv.CommandString("cycle fullscreen");
break;
case 0x0214: // WM_SIZING
var rc = Marshal.PtrToStructure<Native.RECT>(m.LParam);
var r = rc;
NativeHelp.SubtractWindowBorders(Handle, ref r);
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
float aspect = mpv.VideoSize.Width / (float)mpv.VideoSize.Height;
int d_w = (int)(c_h * aspect - c_w);
int d_h = (int)(c_w / aspect - c_h);
int[] d_corners = { d_w, d_h, -d_w, -d_h };
int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom };
int corner = NativeHelp.GetResizeBorder(m.WParam.ToInt32());
if (corner >= 0)
corners[corner] -= d_corners[corner];
Marshal.StructureToPtr<Native.RECT>(new Native.RECT(corners[0], corners[1], corners[2], corners[3]), m.LParam, false);
m.Result = new IntPtr(1);
return;
}
base.WndProc(ref m);
}
void SetFormPosSize()
{
if (IsFullscreen || mpv.VideoSize.Width == 0) return;
var wa = Screen.GetWorkingArea(this);
int h = (int)(wa.Height * 0.6);
int w = (int)(h * mpv.VideoSize.Width / (float)mpv.VideoSize.Height);
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
var r = new Native.RECT(new Rectangle(0, 0, w, h));
NativeHelp.AddWindowBorders(Handle, ref r);
int l = middlePos.X - r.Width / 2;
int t = middlePos.Y - r.Height / 2;
if (l < 0) l = 0;
if (t < 0) t = 0;
if (l + r.Width > wa.Width ) l = wa.Width - r.Width;
if (t + r.Height > wa.Height ) t = wa.Height - r.Height;
Native.SetWindowPos(Handle, IntPtr.Zero /* HWND_TOP */, l, t, r.Width, r.Height, 4 /* SWP_NOZORDER */);
}
protected override void OnDragEnter(DragEventArgs e)
{
base.OnDragEnter(e);
if (e.Data.GetDataPresent(DataFormats.FileDrop))
e.Effect = DragDropEffects.Copy;
}
protected override void OnDragDrop(DragEventArgs e)
{
base.OnDragDrop(e);
if (e.Data.GetDataPresent(DataFormats.FileDrop))
mpv.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as String[]);
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
// window-dragging
if (WindowState == FormWindowState.Normal &&
e.Button == MouseButtons.Left &&
e.Y < ClientSize.Height * 0.9)
{
var HTCAPTION = new IntPtr(2);
Native.ReleaseCapture();
Native.PostMessage(Handle, 0xA1 /* WM_NCLBUTTONDOWN */, HTCAPTION, IntPtr.Zero);
}
var sb = Screen.FromControl(this).Bounds;
var p1 = new Point(sb.Width, 0);
var p2 = PointToScreen(e.Location);
if (Math.Abs(p1.X - p2.X) < 10 && Math.Abs(p1.Y - p2.Y) < 10)
mpv.Command("quit");
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
// send mouse command to make OSC show
mpv.CommandString($"mouse {e.X} {e.Y}");
if (CursorHelp.IsPosDifferent(LastCursorPosChanged))
CursorHelp.Show();
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
IsCloseRequired = false;
mpv.Command("quit");
}
bool IsMouseInOSC()
{
return PointToClient(Control.MousePosition).Y > ClientSize.Height * 0.9;
}
private void Timer_Tick(object sender, EventArgs e)
{
if (CursorHelp.IsPosDifferent(LastCursorPosChanged))
{
LastCursorPosChanged = Control.MousePosition;
LastCursorChangedTickCount = Environment.TickCount;
}
else if (Environment.TickCount - LastCursorChangedTickCount > 1500 &&
!IsMouseInOSC() && ClientRectangle.Contains(PointToClient(MousePosition)) &&
Form.ActiveForm == this && !CMS.Visible)
{
CursorHelp.Hide();
}
}
private void MainForm_Load(object sender, EventArgs ea)
{
mpv.Init();
mpv.ObserveBoolProp("fullscreen", MpvChangeFullscreen);
mpv.AfterShutdown += Mpv_AfterShutdown;
mpv.VideoSizeChanged += Mpv_VideoSizeChanged;
mpv.PlaybackRestart += mpv_PlaybackRestart;
}
}
}

4634
mpv.net/MainForm.resx Normal file

File diff suppressed because it is too large Load Diff

84
mpv.net/MediaInfo.cs Normal file
View File

@@ -0,0 +1,84 @@
using System;
using System.Runtime.InteropServices;
public class MediaInfo : IDisposable
{
private IntPtr Handle;
private static bool Loaded;
public MediaInfo(string sourcepath)
{
if (!Loaded)
{
if (LoadLibrary("MediaInfo.dll") == IntPtr.Zero)
throw new Exception("Failed to load MediaInfo.dll.");
Loaded = true;
}
Handle = MediaInfo_New();
MediaInfo_Open(Handle, sourcepath);
}
public string GetInfo(MediaInfoStreamKind streamKind, string parameter)
{
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, streamKind, 0, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
}
private bool Disposed;
public void Dispose()
{
if (!Disposed)
{
Disposed = true;
MediaInfo_Close(Handle);
MediaInfo_Delete(Handle);
}
}
~MediaInfo()
{
Dispose();
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string path);
[DllImport("MediaInfo.dll")]
private static extern IntPtr MediaInfo_New();
[DllImport("MediaInfo.dll")]
private static extern void MediaInfo_Delete(IntPtr Handle);
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
private static extern int MediaInfo_Open(IntPtr Handle, string FileName);
[DllImport("MediaInfo.dll")]
private static extern int MediaInfo_Close(IntPtr Handle);
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr MediaInfo_Get(IntPtr Handle, MediaInfoStreamKind StreamKind, int StreamNumber, string Parameter, MediaInfoInfoKind KindOfInfo, MediaInfoInfoKind KindOfSearch);
}
public enum MediaInfoStreamKind
{
General,
Video,
Audio,
Text,
Chapters,
Image
}
public enum MediaInfoInfoKind
{
Name,
Text,
Measure,
Options,
NameText,
MeasureText,
Info,
HowTo
}

520
mpv.net/Menu.cs Normal file
View File

@@ -0,0 +1,520 @@
using System;
using System.Linq;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using Microsoft.Win32;
using System.Windows.Forms;
using System.Drawing;
public class ContextMenuStripEx : ContextMenuStrip
{
public ContextMenuStripEx()
{
}
public ContextMenuStripEx(IContainer container) : base(container)
{
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
Renderer = new ToolStripRendererEx();
}
public ActionMenuItem Add(string path)
{
return Add(path, null);
}
public ActionMenuItem Add(string path, Action action)
{
return Add(path, action, true);
}
public ActionMenuItem Add(string path, Action action, bool enabled)
{
var ret = ActionMenuItem.Add(Items, path, action);
if (ret == null)
return null;
ret.Enabled = enabled;
return ret;
}
public ActionMenuItem Add(string path, Action action, Func<bool> enabledFunc)
{
var ret = ActionMenuItem.Add(Items, path, action);
return ret;
}
}
public class ActionMenuItem : MenuItemEx
{
private Action Action;
public ActionMenuItem()
{
}
public ActionMenuItem(string text, Action action)
{
this.Text = text;
this.Action = action;
}
protected override void OnClick(EventArgs e)
{
Application.DoEvents();
if (Action != null)
Action();
base.OnClick(e);
}
public static ActionMenuItem Add<T>(ToolStripItemCollection items, string path, Action<T> action, T value)
{
return Add(items, path, () => action(value));
}
public static ActionMenuItem Add(ToolStripItemCollection items, string path, Action action)
{
var a = path.Split(new[] { " > " }, StringSplitOptions.RemoveEmptyEntries);
var l = items;
for (var x = 0; x <= a.Length - 1; x++)
{
var found = false;
foreach (var i in l.OfType<ToolStripMenuItem>())
{
if (x < a.Length - 1)
{
if (i.Text == a[x] + " ")
{
found = true;
l = i.DropDownItems;
}
}
}
if (!found)
{
if (x == a.Length - 1)
{
if (a[x] == "-")
l.Add(new ToolStripSeparator());
else
{
ActionMenuItem item = new ActionMenuItem(a[x] + " ", action);
l.Add(item);
l = item.DropDownItems;
return item;
}
}
else
{
ActionMenuItem item = new ActionMenuItem();
item.Text = a[x] + " ";
l.Add(item);
l = item.DropDownItems;
}
}
}
return null;
}
}
public class MenuItemEx : ToolStripMenuItem
{
public static bool UseTooltips { get; set; }
public MenuItemEx()
{
}
public MenuItemEx(string text) : base(text)
{
}
public override Size GetPreferredSize(Size constrainingSize)
{
var ret = base.GetPreferredSize(constrainingSize);
ret.Height = Convert.ToInt32(Font.Height * 1.4);
return ret;
}
public void CloseAll(object item)
{
if (item is ToolStripItem)
{
var d = (ToolStripItem)item;
CloseAll(d.Owner);
}
if (item is ToolStripDropDown)
{
var d = (ToolStripDropDown)item;
d.Close();
CloseAll(d.OwnerItem);
}
}
protected override void OnClick(EventArgs e)
{
Application.DoEvents();
base.OnClick(e);
}
}
public class ToolStripRendererEx : ToolStripSystemRenderer
{
public static Color ColorChecked { get; set; }
public static Color ColorBorder { get; set; }
public static Color ColorTop { get; set; }
public static Color ColorBottom { get; set; }
public static Color ColorBackground { get; set; }
public static Color ColorToolStrip1 { get; set; }
public static Color ColorToolStrip2 { get; set; }
public static Color ColorToolStrip3 { get; set; }
public static Color ColorToolStrip4 { get; set; }
private int TextOffset;
public ToolStripRendererEx()
{
var argb = Convert.ToInt32(Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", 0));
if (argb == 0)
argb = Color.LightBlue.ToArgb();
InitColors(Color.FromArgb(argb));
}
public static void InitColors(Color c)
{
ColorBorder = HSLColor.Convert(c).ToColorSetLuminosity(100);
ColorChecked = HSLColor.Convert(c).ToColorSetLuminosity(200);
ColorBottom = HSLColor.Convert(c).ToColorSetLuminosity(220);
ColorBackground = HSLColor.Convert(c).ToColorSetLuminosity(230);
ColorTop = HSLColor.Convert(c).ToColorSetLuminosity(240);
ColorToolStrip1 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 1)));
ColorToolStrip2 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.7f)));
ColorToolStrip3 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.1f)));
ColorToolStrip4 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.4f)));
}
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
{
ControlPaint.DrawBorder(e.Graphics, e.AffectedBounds, Color.FromArgb(160, 175, 195), ButtonBorderStyle.Solid);
}
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
{
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
if (e.Item is ToolStripMenuItem && !(e.Item.Owner is MenuStrip))
{
var r = e.TextRectangle;
var dropDown = e.ToolStrip as ToolStripDropDownMenu;
if (dropDown == null || dropDown.ShowImageMargin || dropDown.ShowCheckMargin)
TextOffset = Convert.ToInt32(e.Item.Height * 1.1);
else
TextOffset = Convert.ToInt32(e.Item.Height * 0.2);
e.TextRectangle = new Rectangle(TextOffset, Convert.ToInt32((e.Item.Height - r.Height) / 2.0), r.Width, r.Height);
}
base.OnRenderItemText(e);
}
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
{
if (!(e.ToolStrip is ToolStripDropDownMenu) && !(e.ToolStrip.LayoutStyle == ToolStripLayoutStyle.VerticalStackWithOverflow))
{
Rectangle r = new Rectangle(-1, -1, e.AffectedBounds.Width, e.AffectedBounds.Height);
using (SolidBrush b = new SolidBrush(ColorToolStrip2))
{
e.Graphics.FillRectangle(b, r);
}
}
}
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
{
e.Item.ForeColor = Color.Black;
var r = new Rectangle(Point.Empty, e.Item.Size);
var g = e.Graphics;
if (!(e.Item.Owner is MenuStrip))
g.Clear(ColorBackground);
if (e.Item.Selected && e.Item.Enabled)
{
if (e.Item.Owner is MenuStrip)
DrawButton(e);
else
{
g.SmoothingMode = SmoothingMode.AntiAlias;
var r2 = new Rectangle(r.X + 2, r.Y, r.Width - 4, r.Height - 1);
using (Pen pen = new Pen(ColorBorder))
{
g.DrawRectangle(pen, r2);
}
r2.Inflate(-1, -1);
using (SolidBrush b = new SolidBrush(ColorBottom))
{
g.FillRectangle(b, r2);
}
}
}
}
public void DrawButton(ToolStripItemRenderEventArgs e)
{
var g = e.Graphics;
var r = new Rectangle(Point.Empty, e.Item.Size);
var r2 = new Rectangle(r.X, r.Y, r.Width - 1, r.Height - 1);
using (Pen pen = new Pen(ColorBorder))
{
g.DrawRectangle(pen, r2);
}
r2.Inflate(-1, -1);
var tsb = e.Item as ToolStripButton;
if (!(tsb == null) && tsb.Checked)
{
using (SolidBrush brush = new SolidBrush(ColorChecked))
{
g.FillRectangle(brush, r2);
}
}
else
using (SolidBrush brush = new SolidBrush(ColorBottom))
{
g.FillRectangle(brush, r2);
}
}
protected override void OnRenderDropDownButtonBackground(ToolStripItemRenderEventArgs e)
{
if (e.Item.Selected)
DrawButton(e);
}
protected override void OnRenderButtonBackground(ToolStripItemRenderEventArgs e)
{
var button = (ToolStripButton)e.Item;
if (e.Item.Selected || button.Checked)
DrawButton(e);
}
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
{
var value = e.Direction == ArrowDirection.Down ? 0x36 : 0x34;
var s = Convert.ToChar(value).ToString();
var font = new Font("Marlett", e.Item.Font.Size - 2);
var size = e.Graphics.MeasureString(s, font);
var x = Convert.ToInt32(e.Item.Width - size.Width);
var y = Convert.ToInt32((e.Item.Height - size.Height) / 2.0) + 1;
e.Graphics.DrawString(s, font, Brushes.Black, x, y);
}
protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
{
var x = Convert.ToInt32(e.ImageRectangle.Height * 0.2);
e.Graphics.DrawImage(e.Image, new Point(x, x));
}
protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
{
if (e.Item.IsOnDropDown)
{
e.Graphics.Clear(ColorBackground);
var right = e.Item.Width - Convert.ToInt32(TextOffset / 5.0);
var top = e.Item.Height / 2;
top -= 1;
var b = e.Item.Bounds;
using (Pen p = new Pen(Color.Gray))
{
e.Graphics.DrawLine(p, new Point(TextOffset, top), new Point(right, top));
}
}
else if (e.Vertical)
{
var b = e.Item.Bounds;
using (Pen p = new Pen(SystemColors.ControlDarkDark))
{
e.Graphics.DrawLine(p,
Convert.ToInt32(b.Width / 2.0),
Convert.ToInt32(b.Height * 0.15),
Convert.ToInt32(b.Width / 2.0),
Convert.ToInt32(b.Height * 0.85));
}
}
}
}
public struct HSLColor
{
public HSLColor(Color color) : this()
{
SetRGB(color.R, color.G, color.B);
}
public HSLColor(int h, int s, int l) : this()
{
Hue = h;
Saturation = s;
Luminosity = l;
}
private double HueValue;
public int Hue {
get {
return System.Convert.ToInt32(HueValue * 240);
}
set {
HueValue = CheckRange(value / 240.0);
}
}
private double SaturationValue;
public int Saturation {
get {
return System.Convert.ToInt32(SaturationValue * 240);
}
set {
SaturationValue = CheckRange(value / (double)240);
}
}
private double LuminosityValue;
public int Luminosity {
get {
return System.Convert.ToInt32(LuminosityValue * 240);
}
set {
LuminosityValue = CheckRange(value / (double)240);
}
}
private double CheckRange(double value)
{
if (value < 0)
value = 0;
else if (value > 1)
value = 1;
return value;
}
public Color ToColorAddLuminosity(int luminosity)
{
this.Luminosity += luminosity;
return ToColor();
}
public Color ToColorSetLuminosity(int luminosity)
{
this.Luminosity = luminosity;
return ToColor();
}
public Color ToColor()
{
double r = 0, g = 0, b = 0;
if (LuminosityValue != 0)
{
if (SaturationValue == 0)
{
b = LuminosityValue;
g = LuminosityValue;
r = LuminosityValue;
}
else
{
var temp2 = GetTemp2(this);
var temp1 = 2.0 * LuminosityValue - temp2;
r = GetColorComponent(temp1, temp2, HueValue + 1.0 / 3.0);
g = GetColorComponent(temp1, temp2, HueValue);
b = GetColorComponent(temp1, temp2, HueValue - 1.0 / 3.0);
}
}
return Color.FromArgb(
System.Convert.ToInt32(255 * r),
System.Convert.ToInt32(255 * g),
System.Convert.ToInt32(255 * b));
}
private static double GetColorComponent(double temp1, double temp2, double temp3)
{
temp3 = MoveIntoRange(temp3);
if (temp3 < 1 / 6.0)
return temp1 + (temp2 - temp1) * 6.0 * temp3;
else if (temp3 < 0.5)
return temp2;
else if (temp3 < 2 / 3.0)
return temp1 + ((temp2 - temp1) * (2 / 3.0 - temp3) * 6);
else
return temp1;
}
private static double MoveIntoRange(double temp3)
{
if (temp3 < 0)
temp3 += 1;
else if (temp3 > 1)
temp3 -= 1;
return temp3;
}
private static double GetTemp2(HSLColor hslColor)
{
double temp2;
if (hslColor.LuminosityValue < 0.5)
temp2 = hslColor.LuminosityValue * (1.0 + hslColor.SaturationValue);
else
temp2 = hslColor.LuminosityValue + hslColor.SaturationValue - (hslColor.LuminosityValue * hslColor.SaturationValue);
return temp2;
}
public static HSLColor Convert(Color c)
{
HSLColor r = new HSLColor();
r.HueValue = c.GetHue() / 360.0;
r.LuminosityValue = c.GetBrightness();
r.SaturationValue = c.GetSaturation();
return r;
}
public void SetRGB(int red, int green, int blue)
{
var hc = HSLColor.Convert(Color.FromArgb(red, green, blue));
HueValue = hc.HueValue;
SaturationValue = hc.SaturationValue;
LuminosityValue = hc.LuminosityValue;
}
}

46
mpv.net/Misc.cs Normal file
View File

@@ -0,0 +1,46 @@
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace mpvnet
{
public class Misc
{
public static readonly string[] FileTypes = "264 265 3gp aac ac3 avc avi avs bmp divx dts dtshd dtshr dtsma eac3 evo flac flv h264 h265 hevc hvc jpg jpeg m2t m2ts m2v m4a m4v mka mkv mlp mov mp2 mp3 mp4 mpa mpeg mpg mpv mts ogg ogm opus pcm png pva raw rmvb thd thd+ac3 true-hd truehd ts vdr vob vpy w64 wav webm wmv y4m".Split(' ');
public static string GetFilter(IEnumerable<string> values)
{
return "*." + values.Join(";*.") + "|*." + values.Join(";*.") + "|All Files|*.*";
}
}
public class StringLogicalComparer : IComparer, IComparer<string>
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogical(string x, string y);
int IComparer_Compare(object x, object y) => StrCmpLogical(x.ToString(), y.ToString());
int IComparer.Compare(object x, object y) => IComparer_Compare(x, y);
int IComparerOfString_Compare(string x, string y) => StrCmpLogical(x, y);
int IComparer<string>.Compare(string x, string y) => IComparerOfString_Compare(x, y);
}
public class StaticUsing
{
public static void MsgInfo(string message)
{
MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
public static void MsgError(string message)
{
MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
public static DialogResult MsgQuestion(string message)
{
return MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
}
}
}

78
mpv.net/Native.cs Normal file
View File

@@ -0,0 +1,78 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace mpvnet
{
public class Native
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern string SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern void ReleaseCapture();
[DllImport("user32.dll")]
public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowLongPtrW(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(Rectangle r)
{
Left = r.Left;
Top = r.Top;
Right = r.Right;
Bottom = r.Bottom;
}
public RECT(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public Rectangle ToRectangle()
{
return Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
public Size Size
{
get { return new Size(Right - Left, Bottom - Top); }
}
public int Width
{
get { return Right - Left; }
}
public int Height
{
get { return Bottom - Top; }
}
}
}
}

38
mpv.net/NativeHelp.cs Normal file
View File

@@ -0,0 +1,38 @@
using System;
namespace mpvnet
{
public static class NativeHelp
{
public static int GetResizeBorder(int v)
{
switch (v)
{
case 1 /* WMSZ_LEFT */ : return 3;
case 3 /* WMSZ_TOP */ : return 2;
case 2 /* WMSZ_RIGHT */ : return 3;
case 6 /* WMSZ_BOTTOM */ : return 2;
case 4 /* WMSZ_TOPLEFT */ : return 1;
case 5 /* WMSZ_TOPRIGHT */ : return 1;
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
case 8 /* WMSZ_BOTTOMRIGHT */: return 3;
default: return -1;
}
}
public static void SubtractWindowBorders(IntPtr hwnd, ref Native.RECT rc)
{
var b = new Native.RECT(0, 0, 0, 0);
AddWindowBorders(hwnd, ref b);
rc.Left -= b.Left;
rc.Top -= b.Top;
rc.Right -= b.Right;
rc.Bottom -= b.Bottom;
}
public static void AddWindowBorders(IntPtr hwnd, ref Native.RECT rc)
{
Native.AdjustWindowRect(ref rc, (uint)Native.GetWindowLongPtrW(hwnd, -16 /* GWL_STYLE */), false);
}
}
}

16
mpv.net/Program.cs Normal file
View File

@@ -0,0 +1,16 @@
using System;
using System.Windows.Forms;
namespace mpvnet
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("mpv.net")]
[assembly: AssemblyDescription("mpv/libmpv based player with pure mpv experience")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("mpv.net")]
[assembly: AssemblyCopyright("Copyright © 2019 stax76")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("1751f378-8edf-4b62-be6d-304c7c287089")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.2.6.0")]
[assembly: AssemblyFileVersion("0.2.6.0")]

84
mpv.net/Properties/Resources.Designer.cs generated Normal file
View File

@@ -0,0 +1,84 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace mpvnet.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("mpvnet.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to
///#key command key caption menu path/caption
///
///o script-message mpv.net open-files #menu: O; Open Files
///
///Space cycle pause #menu: Space ; Play/Pause
///s stop #menu: S ; Stop
///
///F11 playlist-prev #menu: F11 ; Navigate | Previous
///F12 playlist-next #menu: F12 ; Navigate | Next
///
///Ctrl++ add video-zoom 0.1 #menu: Ctrl++ ; Pan &amp;&amp; Scan | Increase Size
///Ctrl+- add video-zoom -0.1 #menu: Ct [rest of string was truncated]&quot;;.
/// </summary>
internal static string input_conf {
get {
return ResourceManager.GetString("input_conf", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="input_conf" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\input_conf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
</root>

26
mpv.net/Properties/Settings.Designer.cs generated Normal file
View File

@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace mpvnet.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,161 @@
# mpv.net key bindings, mouse bindings and context menu configuration
o script-message mpv.net open-files #menu: O ; Open Files...
_ ignore #menu: _ ; -
Space cycle pause #menu: Space, Enter ; Play/Pause
Enter cycle pause
s stop #menu: S ; Stop
_ ignore #menu: _ ; -
f cycle fullscreen #menu: F ; Toggle Fullscreen
F11 playlist-prev #menu: F11 ; Navigate > Previous
F12 playlist-next #menu: F12 ; Navigate > Next
_ ignore #menu: _ ; Navigate > -
PGUP add chapter 1 #menu: Page Up ; Navigate > Next Chapter
PGDWN add chapter -1 #menu: Page Down ; Navigate > Previous Chapter
. frame-step #menu: . ; Seek > Next Frame
, frame-back-step #menu: , ; Seek > Previous Frame
_ ignore #menu: _ ; Seek > -
Right no-osd seek 7 #menu: Right ; Seek > 7 sec forward
Left no-osd seek -7 #menu: Left ; Seek > 7 sec backward
_ ignore #menu: _ ; Seek > -
Up no-osd seek 40 #menu: Up ; Seek > 40 sec forward
Down no-osd seek -40 #menu: Down ; Seek > 40 sec backward
_ ignore #menu: _ ; Seek > -
Ctrl+Right no-osd seek 300 #menu: Ctrl+Right ; Seek > 5 min forward
Ctrl+Left no-osd seek -300 #menu: Ctrl+Left ; Seek > 5 min backward
Ctrl++ add video-zoom 0.1 #menu: Ctrl++ ; Pan && Scan > Increase Size
Ctrl+- add video-zoom -0.1 #menu: Ctrl+- ; Pan && Scan > Decrease Size
_ ignore #menu: _ ; Pan && Scan > -
Shift+Left add video-pan-x -0.01 #menu: Shift+Left ; Pan && Scan > Move Left
Shift+Right add video-pan-x 0.01 #menu: Shift+Right ; Pan && Scan > Move Right
_ ignore #menu: _ ; Pan && Scan > -
Shift+Up add video-pan-y -0.01 #menu: Shift+Up ; Pan && Scan > Move Up
Shift+Down add video-pan-y 0.01 #menu: Shift+Down ; Pan && Scan > Move Down
_ ignore #menu: _ ; Pan && Scan > -
Shift+BS set video-zoom 0 ; set video-pan-x 0 ; set video-pan-y 0 #menu: Alt+Backspace ; Pan && Scan > Reset
KP7 cycle audio #menu: Keypad 7 ; Audio > Cycle/Next
_ ignore #menu: _ ; Audio > -
KP6 add audio-delay 0.100 #menu: Keypad 6 ; Audio > Delay +0.1
KP9 add audio-delay -0.100 #menu: Keypad 9 ; Audio > Delay -0.1
KP8 cycle sub #menu: Keypad 8 ; Subtitle > Cycle/Next
_ ignore #menu: _ ; Subtitle > -
z add sub-delay -0.1 #menu: Z ; Subtitle > Delay -0.1
Z add sub-delay +0.1 #menu: Shift+Z ; Subtitle > Delay +0.1
+ add volume 10 #menu: + ; Volume > Up
- add volume -10 #menu: - ; Volume > Down
WHEEL_UP add volume 10
WHEEL_DOWN add volume -10
_ ignore #menu: _ ; Volume > -
m cycle mute #menu: M ; Volume > Mute
[ multiply speed 0.9 #menu: [ ; Speed > -10%
] multiply speed 1.1 #menu: ] ; Speed > +10%
_ ignore #menu: _ ; Speed > -
{ multiply speed 0.5 #menu: { ; Speed > Half
} multiply speed 2.0 #menu: } ; Speed > Double
_ ignore #menu: _ ; Speed > -
BS set speed 1 #menu: Backspace ; Speed > Reset
KP0 script-message rate-file 0 #menu: Keypad 0 ; Addons > Rating > 0stars
KP1 script-message rate-file 1 #menu: Keypad 1 ; Addons > Rating > 1stars
KP2 script-message rate-file 2 #menu: Keypad 2 ; Addons > Rating > 2stars
KP3 script-message rate-file 3 #menu: Keypad 3 ; Addons > Rating > 3stars
KP4 script-message rate-file 4 #menu: Keypad 4 ; Addons > Rating > 4stars
KP5 script-message rate-file 5 #menu: Keypad 5 ; Addons > Rating > 5stars
_ script-message mpv.net set-setting hwdec yes #menu: _ ; Settings > Hardware Decoding > Enable
_ script-message mpv.net set-setting hwdec no #menu: _ ; Settings > Hardware Decoding > Disable
p script-message mpv.net show-prefs #menu: P ; Settings > Show Preferences
k script-message mpv.net show-keys #menu: K ; Settings > Show Keys
c script-message mpv.net open-config-folder #menu: C ; Settings > Open Config Folder
i show-progress ; script-message mpv.net show-info #menu: I ; Tools > Info
t script-binding stats/display-stats #menu: T ; Tools > Show Statistics
T script-binding stats/display-stats-toggle #menu: Shift+T ; Tools > Toggle Statistics
_ ignore #menu: _ ; Tools > -
h script-message mpv.net history #menu: H ; Tools > Show History
l ab-loop #menu: L ; Tools > Set/clear A-B loop points
_ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: _ ; Tools > Web > Show mpv manual
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/blob/master/etc/input.conf #menu: _ ; Tools > Web > Show mpv default keys
_ script-message mpv.net shell-execute https://github.com/stax76/mpvnet #menu: _ ; Tools > Web > Show mpv.net web site
_ ignore #menu: _ ; -
Esc quit #menu: Escape ; Exit
Q quit-watch-later #menu: Shift+Q ; Exit Watch Later
# Adjust timing to previous/next subtitle
Ctrl+Shift+LEFT sub-step -1
Ctrl+Shift+RIGHT sub-step 1
> playlist-next # skip to next file
< playlist-prev # skip to previous file
O no-osd cycle-values osd-level 3 1 # cycle through OSD mode
#1 add contrast -1
#2 add contrast 1
#3 add brightness -1
#4 add brightness 1
#5 add gamma -1
#6 add gamma 1
#7 add saturation -1
#8 add saturation 1
# toggle deinterlacer (automatically inserts or removes required filter)
#d cycle deinterlace
#r add sub-pos -1 # move subtitles up
#R add sub-pos +1 # down
#t add sub-pos +1 # same as previous binding (discouraged)
#v cycle sub-visibility
# stretch SSA/ASS subtitles with anamorphic videos to match historical
#V cycle sub-ass-vsfilter-aspect-compat
# switch between applying no style overrides to SSA/ASS subtitles, and
# overriding them almost completely with the normal subtitle style
#u cycle-values sub-ass-override "force" "no"
#j cycle sub # cycle through subtitles
#J cycle sub down # ...backwards
#SHARP cycle audio # switch audio streams
#_ cycle video
#T cycle ontop # toggle video window ontop of other windows
#s async screenshot # take a screenshot
#S async screenshot video # ...without subtitles
#Ctrl+s async screenshot window # ...with subtitles and OSD, and scaled
#Alt+s screenshot each-frame # automatically screenshot every frame
#w add panscan -0.1 # zoom out with -panscan 0 -fs
#W add panscan +0.1 # in
#e add panscan +0.1 # same as previous binding (discouraged)
# cycle video aspect ratios; "-1" is the container aspect
#A cycle-values video-aspect "16:9" "4:3" "2.35:1" "-1"
#POWER quit
#PLAY cycle pause
#PAUSE cycle pause
#PLAYPAUSE cycle pause
#STOP quit
#FORWARD seek 60
#REWIND seek -60
#NEXT playlist-next
#PREV playlist-prev
#VOLUME_UP add volume 2
#VOLUME_DOWN add volume -2
#MUTE cycle mute
#CLOSE_WIN quit
#CLOSE_WIN {encode} quit 4
#E cycle edition # next edition
#L cycle-values loop-file "inf" "no" # toggle infinite looping
#ctrl+c quit 4
#DEL script-binding osc/visibility # cycle OSC display
#ctrl+h cycle-values hwdec "auto" "no" # cycle hardware decoding
#F8 show_text ${playlist} # show playlist
#F9 show_text ${track-list} # show list of audio/sub streams
# ? add sub-scale +0.1 # increase subtitle font size
# ? add sub-scale -0.1 # decrease subtitle font size
# ? cycle angle # switch DVD/Bluray angle
# ? cycle sub-forced-only # toggle DVD forced subs
# ? cycle program # cycle transport stream programs
# ? stop # stop playback (quit or enter idle mode)

120
mpv.net/StringExtensions.cs Normal file
View File

@@ -0,0 +1,120 @@
using System;
using System.Linq;
using System.IO;
public static class StringExtensions
{
public static string ExtFull(this string filepath)
{
return Ext(filepath, true);
}
public static string Ext(this string filepath)
{
return Ext(filepath, false);
}
public static string Ext(this string filepath, bool dot)
{
if (string.IsNullOrEmpty(filepath))
return "";
var chars = filepath.ToCharArray();
for (var x = filepath.Length - 1; x >= 0; x += -1)
{
if (chars[x] == Path.DirectorySeparatorChar)
return "";
if (chars[x] == '.')
return filepath.Substring(x + (dot ? 0 : 1)).ToLower();
}
return "";
}
public static string Left(this string value, int index)
{
if (string.IsNullOrEmpty(value) || index < 0)
return "";
if (index > value.Length)
return value;
return value.Substring(0, index);
}
public static string Left(this string value, string start)
{
if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(start))
return "";
if (!value.Contains(start))
return "";
return value.Substring(0, value.IndexOf(start));
}
public static string LeftLast(this string value, string start)
{
if (!value.Contains(start))
return "";
return value.Substring(0, value.LastIndexOf(start));
}
public static string Right(this string value, string start)
{
if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(start))
return "";
if (!value.Contains(start))
return "";
return value.Substring(value.IndexOf(start) + start.Length);
}
public static string RightLast(this string value, string start)
{
if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(start))
return "";
if (!value.Contains(start))
return "";
return value.Substring(value.LastIndexOf(start) + start.Length);
}
public static string[] SplitNoEmpty(this string value, params string[] delimiters)
{
return value.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
}
public static string[] SplitKeepEmpty(this string value, params string[] delimiters)
{
return value.Split(delimiters, StringSplitOptions.None);
}
public static string[] SplitNoEmptyAndWhiteSpace(this string value, params string[] delimiters)
{
if (string.IsNullOrEmpty(value))
return null;
var a = SplitNoEmpty(value, delimiters);
for (var i = 0; i <= a.Length - 1; i++)
a[i] = a[i].Trim();
var l = a.ToList();
while (l.Contains(""))
l.Remove("");
return l.ToArray();
}
public static string[] SplitLinesNoEmpty(this string value)
{
return SplitNoEmpty(value, Environment.NewLine);
}
}

36
mpv.net/UI.cs Normal file
View File

@@ -0,0 +1,36 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace mpvnet
{
public class CursorHelp
{
static bool IsVisible = true;
public static void Show()
{
if (!IsVisible)
{
Cursor.Show();
IsVisible = true;
}
}
public static void Hide()
{
if (IsVisible)
{
Cursor.Hide();
IsVisible = false;
}
}
public static bool IsPosDifferent(Point screenPos)
{
return
Math.Abs(screenPos.X - Control.MousePosition.X) > 10 ||
Math.Abs(screenPos.Y - Control.MousePosition.Y) > 10;
}
}
}

43
mpv.net/app.manifest Normal file
View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly
manifestVersion="1.0"
xmlns="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application>
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

167
mpv.net/libmpv.cs Normal file
View File

@@ -0,0 +1,167 @@
using System;
using System.Runtime.InteropServices;
namespace mpvnet
{
public class libmpv
{
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mpv_create();
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_initialize(IntPtr mpvHandle);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_command(IntPtr mpvHandle, IntPtr strings);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_command_string(IntPtr mpvHandle, [MarshalAs(UnmanagedType.LPUTF8Str)] string command);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_terminate_destroy(IntPtr mpvHandle);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_set_option(IntPtr mpvHandle, byte[] name, mpv_format format, ref long data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_set_option_string(IntPtr mpvHandle, byte[] name, byte[] value);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_get_property(IntPtr mpvHandle, byte[] name, mpv_format format, ref IntPtr data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_set_property(IntPtr mpvHandle, byte[] name, mpv_format format, ref byte[] data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_set_property(IntPtr mpvHandle, byte[] name, mpv_format format, ref Int64 data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_observe_property(
IntPtr mpvHandle,
UInt64 reply_userdata,
[MarshalAs(UnmanagedType.LPUTF8Str)] string name,
mpv_format format);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_unobserve_property(IntPtr mpvHandle, UInt64 registered_reply_userdata);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void mpv_free(IntPtr data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mpv_wait_event(IntPtr mpvHandle, double timeout);
public enum mpv_error
{
MPV_ERROR_SUCCESS = 0,
MPV_ERROR_EVENT_QUEUE_FULL = -1,
MPV_ERROR_NOMEM = -2,
MPV_ERROR_UNINITIALIZED = -3,
MPV_ERROR_INVALID_PARAMETER = -4,
MPV_ERROR_OPTION_NOT_FOUND = -5,
MPV_ERROR_OPTION_FORMAT = -6,
MPV_ERROR_OPTION_ERROR = -7,
MPV_ERROR_PROPERTY_NOT_FOUND = -8,
MPV_ERROR_PROPERTY_FORMAT = -9,
MPV_ERROR_PROPERTY_UNAVAILABLE = -10,
MPV_ERROR_PROPERTY_ERROR = -11,
MPV_ERROR_COMMAND = -12,
MPV_ERROR_LOADING_FAILED = -13,
MPV_ERROR_AO_INIT_FAILED = -14,
MPV_ERROR_VO_INIT_FAILED = -15,
MPV_ERROR_NOTHING_TO_PLAY = -16,
MPV_ERROR_UNKNOWN_FORMAT = -17,
MPV_ERROR_UNSUPPORTED = -18,
MPV_ERROR_NOT_IMPLEMENTED = -19,
MPV_ERROR_GENERIC = -20
}
public enum mpv_event_id
{
MPV_EVENT_NONE = 0,
MPV_EVENT_SHUTDOWN = 1,
MPV_EVENT_LOG_MESSAGE = 2,
MPV_EVENT_GET_PROPERTY_REPLY = 3,
MPV_EVENT_SET_PROPERTY_REPLY = 4,
MPV_EVENT_COMMAND_REPLY = 5,
MPV_EVENT_START_FILE = 6,
MPV_EVENT_END_FILE = 7,
MPV_EVENT_FILE_LOADED = 8,
MPV_EVENT_TRACKS_CHANGED = 9,
MPV_EVENT_TRACK_SWITCHED = 10,
MPV_EVENT_IDLE = 11,
MPV_EVENT_PAUSE = 12,
MPV_EVENT_UNPAUSE = 13,
MPV_EVENT_TICK = 14,
MPV_EVENT_SCRIPT_INPUT_DISPATCH = 15,
MPV_EVENT_CLIENT_MESSAGE = 16,
MPV_EVENT_VIDEO_RECONFIG = 17,
MPV_EVENT_AUDIO_RECONFIG = 18,
MPV_EVENT_METADATA_UPDATE = 19,
MPV_EVENT_SEEK = 20,
MPV_EVENT_PLAYBACK_RESTART = 21,
MPV_EVENT_PROPERTY_CHANGE = 22,
MPV_EVENT_CHAPTER_CHANGE = 23,
MPV_EVENT_QUEUE_OVERFLOW = 24
}
public enum mpv_format
{
MPV_FORMAT_NONE = 0,
MPV_FORMAT_STRING = 1,
MPV_FORMAT_OSD_STRING = 2,
MPV_FORMAT_FLAG = 3,
MPV_FORMAT_INT64 = 4,
MPV_FORMAT_DOUBLE = 5,
MPV_FORMAT_NODE = 6,
MPV_FORMAT_NODE_ARRAY = 7,
MPV_FORMAT_NODE_MAP = 8,
MPV_FORMAT_BYTE_ARRAY = 9
}
public enum mpv_log_level
{
MPV_LOG_LEVEL_NONE = 0,
MPV_LOG_LEVEL_FATAL = 10,
MPV_LOG_LEVEL_ERROR = 20,
MPV_LOG_LEVEL_WARN = 30,
MPV_LOG_LEVEL_INFO = 40,
MPV_LOG_LEVEL_V = 50,
MPV_LOG_LEVEL_DEBUG = 60,
MPV_LOG_LEVEL_TRACE = 70,
}
[StructLayout(LayoutKind.Sequential)]
public struct mpv_event_log_message
{
public string prefix;
public string level;
public string text;
public mpv_log_level log_level;
}
[StructLayout(LayoutKind.Sequential)]
public struct mpv_event
{
public mpv_event_id event_id;
public int error;
public UInt64 reply_userdata;
public IntPtr data;
}
[StructLayout(LayoutKind.Sequential)]
public struct mpv_event_client_message
{
public int num_args;
public IntPtr args;
}
[StructLayout(LayoutKind.Sequential)]
public struct mpv_event_property
{
[MarshalAs(UnmanagedType.LPUTF8Str)] public string name;
public mpv_format format;
public IntPtr data;
}
}
}

347
mpv.net/mpv.cs Normal file
View File

@@ -0,0 +1,347 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static mpvnet.libmpv;
using static mpvnet.Native;
using static mpvnet.StaticUsing;
namespace mpvnet
{
public delegate void MpvBoolPropChangeHandler(string propName, bool value);
public class mpv
{
public static event Action<string[]> ClientMessage;
public static event Action Shutdown;
public static event Action AfterShutdown;
public static event Action PlaybackRestart;
public static event Action VideoSizeChanged;
public static IntPtr MpvHandle;
public static IntPtr MpvWindowHandle;
public static Addon Addon;
public static List<Action<bool>> BoolPropChangeActions = new List<Action<bool>>();
public static Size VideoSize = new Size(1920, 1080);
public static string mpvConfFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
public static string InputConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\input.conf";
public static string mpvConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf";
private static Dictionary<string, string> _mpvConv;
public static Dictionary<string, string> mpvConv {
get {
if (_mpvConv == null)
{
_mpvConv = new Dictionary<string, string>();
if (File.Exists(mpvConfPath))
{
foreach (var i in File.ReadAllLines(mpvConfPath))
{
if (i.Contains("=") && ! i.StartsWith("#"))
{
_mpvConv[i.Left("=").Trim()] = i.Right("=").Trim();
}
}
}
}
return _mpvConv;
}
}
public static void Init()
{
LoadLibrary("mpv-1.dll");
MpvHandle = mpv_create();
SetIntProp("input-ar-delay", 500);
SetIntProp("input-ar-rate", 20);
SetIntProp("volume", 50);
SetStringProp("hwdec", "yes");
SetStringProp("vo", "direct3d");
SetStringProp("input-default-bindings", "yes");
SetStringProp("osd-playing-msg", "'${filename}'");
SetStringProp("screenshot-directory", "~~desktop/");
SetStringProp("keep-open", "yes");
SetStringProp("keep-open-pause", "no");
SetStringProp("osc", "yes");
SetStringProp("config", "yes");
SetStringProp("wid", MainForm.Hwnd.ToString());
SetStringProp("force-window", "yes");
mpv_initialize(MpvHandle);
ProcessCommandLine();
Task.Run(() => { Addon = new Addon(); });
Task.Run(() => { EventLoop(); });
}
public static void EventLoop()
{
while (true)
{
IntPtr ptr = mpv_wait_event(MpvHandle, -1);
mpv_event evt = (mpv_event)Marshal.PtrToStructure(ptr, typeof(mpv_event));
Debug.WriteLine(evt.event_id);
if (MpvWindowHandle == IntPtr.Zero)
MpvWindowHandle = FindWindowEx(MainForm.Hwnd, IntPtr.Zero, "mpv", null);
switch (evt.event_id)
{
case mpv_event_id.MPV_EVENT_SHUTDOWN:
Shutdown?.Invoke();
AfterShutdown?.Invoke();
return;
case mpv_event_id.MPV_EVENT_FILE_LOADED:
LoadFolder();
break;
case mpv_event_id.MPV_EVENT_PLAYBACK_RESTART:
PlaybackRestart?.Invoke();
Size s = new Size(GetIntProp("dwidth", false), GetIntProp("dheight", false));
if (VideoSize != s && s != Size.Empty)
{
VideoSize = s;
VideoSizeChanged?.Invoke();
}
break;
case mpv_event_id.MPV_EVENT_CLIENT_MESSAGE:
if (ClientMessage != null)
{
var client_messageData = (mpv_event_client_message)Marshal.PtrToStructure(evt.data, typeof(mpv_event_client_message));
var args = NativeUtf8StrArray2ManagedStrArray(client_messageData.args, client_messageData.num_args);
if (args != null && args.Length > 1 && args[0] == "mpv.net")
foreach (var i in mpvnet.Command.Commands)
if (args[1] == i.Name)
try
{
i.Action(args.Skip(2).ToArray());
}
catch (Exception ex)
{
MsgError(ex.GetType().Name + "\r\n\r\n" + ex.ToString());
}
ClientMessage?.Invoke(args);
}
break;
case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE:
var eventData = (mpv_event_property)Marshal.PtrToStructure(evt.data, typeof(mpv_event_property));
if (eventData.format == mpv_format.MPV_FORMAT_FLAG)
foreach (var action in BoolPropChangeActions)
action.Invoke(Marshal.PtrToStructure<int>(eventData.data) == 1);
break;
}
}
}
public static void Command(params string[] args)
{
if (MpvHandle == IntPtr.Zero)
return;
IntPtr[] byteArrayPointers;
var mainPtr = AllocateUtf8IntPtrArrayWithSentinel(args, out byteArrayPointers);
int err = mpv_command(MpvHandle, mainPtr);
if (err < 0)
throw new Exception($"{(mpv_error)err}");
foreach (var ptr in byteArrayPointers)
Marshal.FreeHGlobal(ptr);
Marshal.FreeHGlobal(mainPtr);
}
public static void CommandString(string command, bool throwException = true)
{
if (MpvHandle == IntPtr.Zero)
return;
int err = mpv_command_string(MpvHandle, command);
if (err < 0 && throwException)
throw new Exception($"{(mpv_error)err}\r\n\r\n" + command);
}
public static void SetStringProp(string name, string value, bool throwException = true)
{
var bytes = GetUtf8Bytes(value);
int err = mpv_set_property(MpvHandle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, ref bytes);
if (err < 0 && throwException)
throw new Exception($"{name}: {(mpv_error)err}");
}
public static string GetStringProp(string name)
{
var lpBuffer = IntPtr.Zero;
int err = mpv_get_property(MpvHandle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, ref lpBuffer);
if (err < 0)
throw new Exception($"{name}: {(mpv_error)err}");
var ret = StringFromNativeUtf8(lpBuffer);
mpv_free(lpBuffer);
return ret;
}
public static int GetIntProp(string name, bool throwException = true)
{
var lpBuffer = IntPtr.Zero;
int err = mpv_get_property(MpvHandle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_INT64, ref lpBuffer);
if (err < 0 && throwException)
throw new Exception($"{name}: {(mpv_error)err}");
else
return lpBuffer.ToInt32();
}
public static void SetIntProp(string name, int value)
{
Int64 val = value;
int err = mpv_set_property(MpvHandle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_INT64, ref val);
if (err < 0)
throw new Exception($"{name}: {(mpv_error)err}");
}
public static void ObserveBoolProp(string name, Action<bool> action)
{
BoolPropChangeActions.Add(action);
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_FLAG);
if (err < 0)
throw new Exception($"{name}: {(mpv_error)err}");
}
public static void UnobserveBoolProp(string name, Action<bool> action)
{
BoolPropChangeActions.Remove(action);
int err = mpv_unobserve_property(MpvHandle, (ulong)action.GetHashCode());
if (err < 0)
throw new Exception($"{name}: {(mpv_error)err}");
}
public static void ProcessCommandLine()
{
var args = Environment.GetCommandLineArgs().Skip(1);
foreach (string i in args)
if (!i.StartsWith("--") && File.Exists(i))
mpv.Command("loadfile", i, "append");
mpv.SetStringProp("playlist-pos", "0", false);
foreach (string i in args)
{
if (i.StartsWith("--"))
{
if (i.Contains("="))
{
string left = i.Substring(2, i.IndexOf("=") - 2);
string right = i.Substring(left.Length + 3);
mpv.SetStringProp(left, right);
}
else
mpv.SetStringProp(i.Substring(2), "yes");
}
}
}
public static void LoadFiles(string[] files)
{
int count = mpv.GetIntProp("playlist-count");
foreach (string file in files)
mpv.Command("loadfile", file, "append");
mpv.SetIntProp("playlist-pos", count);
for (int i = 0; i < count; i++)
mpv.Command("playlist-remove", "0");
mpv.LoadFolder();
}
private static bool WasFolderLoaded;
public static void LoadFolder()
{
if (WasFolderLoaded)
return;
if (GetIntProp("playlist-count") == 1)
{
string[] types = "264 265 3gp aac ac3 avc avi avs bmp divx dts dtshd dtshr dtsma eac3 evo flac flv h264 h265 hevc hvc jpg jpeg m2t m2ts m2v m4a m4v mka mkv mlp mov mp2 mp3 mp4 mpa mpeg mpg mpv mts ogg ogm opus pcm png pva raw rmvb thd thd+ac3 true-hd truehd ts vdr vob vpy w64 wav webm wmv y4m".Split(' ');
string path = GetStringProp("path");
List<string> files = Directory.GetFiles(Path.GetDirectoryName(path)).ToList();
files = files.Where((file) => types.Contains(file.Ext())).ToList();
files.Sort(new StringLogicalComparer());
int index = files.IndexOf(path);
files.Remove(path);
foreach (string i in files)
Command("loadfile", i, "append");
if (index > 0)
Command("playlist-move", "0", (index + 1).ToString());
}
WasFolderLoaded = true;
}
public static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers)
{
int numberOfStrings = arr.Length + 1; // add extra element for extra null pointer last (sentinel)
byteArrayPointers = new IntPtr[numberOfStrings];
IntPtr rootPointer = Marshal.AllocCoTaskMem(IntPtr.Size * numberOfStrings);
for (int index = 0; index < arr.Length; index++)
{
var bytes = GetUtf8Bytes(arr[index]);
IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytes.Length);
Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
byteArrayPointers[index] = unmanagedPointer;
}
Marshal.Copy(byteArrayPointers, 0, rootPointer, numberOfStrings);
return rootPointer;
}
public static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr pUnmanagedStringArray, int StringCount)
{
IntPtr[] pIntPtrArray = new IntPtr[StringCount];
string[] ManagedStringArray = new string[StringCount];
Marshal.Copy(pUnmanagedStringArray, pIntPtrArray, 0, StringCount);
for (int i = 0; i < StringCount; i++)
ManagedStringArray[i] = StringFromNativeUtf8(pIntPtrArray[i]);
return ManagedStringArray;
}
public static string StringFromNativeUtf8(IntPtr nativeUtf8)
{
int len = 0;
while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len;
byte[] buffer = new byte[len];
Marshal.Copy(nativeUtf8, buffer, 0, buffer.Length);
return Encoding.UTF8.GetString(buffer);
}
public static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0");
}
}

BIN
mpv.net/mpv.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

169
mpv.net/mpv.net.csproj Normal file
View File

@@ -0,0 +1,169 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1751F378-8EDF-4B62-BE6D-304C7C287089}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>mpvnet</RootNamespace>
<AssemblyName>mpvnet</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup />
<PropertyGroup />
<PropertyGroup>
<StartupObject>mpvnet.Program</StartupObject>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup />
<PropertyGroup />
<PropertyGroup />
<PropertyGroup />
<PropertyGroup />
<PropertyGroup />
<PropertyGroup />
<PropertyGroup />
<PropertyGroup>
<ApplicationIcon>mpv.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Addon.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="MediaInfo.cs" />
<Compile Include="Menu.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="StringExtensions.cs" />
<Compile Include="libmpv.cs" />
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Misc.cs" />
<Compile Include="mpv.cs" />
<Compile Include="Command.cs" />
<Compile Include="Native.cs" />
<Compile Include="NativeHelp.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UI.cs" />
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="mpv.ico" />
<Content Include="screenshot.jpg" />
<None Include="Resources\input_conf.txt" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

BIN
mpv.net/screenshot.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 KiB