diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs new file mode 100644 index 0000000..150ae0a --- /dev/null +++ b/MainForm.Designer.cs @@ -0,0 +1,61 @@ +namespace robospot_camera_finder +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + lbMain = new ListBox(); + SuspendLayout(); + // + // lbMain + // + lbMain.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + lbMain.FormattingEnabled = true; + lbMain.ItemHeight = 15; + lbMain.Location = new Point(12, 23); + lbMain.Name = "lbMain"; + lbMain.Size = new Size(776, 409); + lbMain.TabIndex = 0; + lbMain.MouseDoubleClick += lbMain_MouseDoubleClick; + // + // MainForm + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(800, 450); + Controls.Add(lbMain); + Name = "MainForm"; + Text = "RoboSpot MotionCamera finder"; + FormClosing += MainForm_FormClosing; + ResumeLayout(false); + } + + #endregion + + private ListBox lbMain; + } +} \ No newline at end of file diff --git a/MainForm.cs b/MainForm.cs new file mode 100644 index 0000000..f732e85 --- /dev/null +++ b/MainForm.cs @@ -0,0 +1,95 @@ +using System.ComponentModel; +using System.Net; +using System.Runtime.CompilerServices; +using System.Web; +using Tmds.MDns; + +namespace robospot_camera_finder +{ + public partial class MainForm : Form + { + private readonly ServiceBrowser browser = new(); + + private BindingList all_cameras = new(); + + class Camera + { + private IPAddress ip; + private string name; + + public Camera(string name, IPAddress ip) + { + this.name = name; + this.ip = ip; + } + + public string camera_name + { + get + { + return name; + } + } + + public IPAddress camera_ip + { + get + { + return ip; + } + } + } + + public MainForm() + { + InitializeComponent(); + + browser.StartBrowse("_rtsp._tcp"); + + lbMain.DataSource = all_cameras; + lbMain.DisplayMember = "camera_name"; + lbMain.ValueMember = "camera_ip"; + + browser.ServiceAdded += (sender, args) => + { + foreach (var cam_addr in args.Announcement.Addresses) + { + if (cam_addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + { + Camera camera = new Camera("Camera " + cam_addr.ToString(), cam_addr); + all_cameras.Add(camera); + } + } + }; + + browser.ServiceRemoved += (sender, args) => + { + foreach (var cam_ip in args.Announcement.Addresses) + { + if (cam_ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + { + foreach (var camera in all_cameras) + { + if (cam_ip == camera.camera_ip) + { + all_cameras.Remove(camera); + return; + } + } + } + } + }; + } + + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + browser.StopBrowse(); + } + + private void lbMain_MouseDoubleClick(object sender, MouseEventArgs e) + { + Form viewer = new StreamViewer(lbMain.GetItemText(lbMain.SelectedItem), lbMain.SelectedValue.ToString()); + viewer.Show(); + } + } +} \ No newline at end of file diff --git a/MainForm.resx b/MainForm.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/MainForm.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..df11ca6 --- /dev/null +++ b/Program.cs @@ -0,0 +1,17 @@ +namespace robospot_camera_finder +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new MainForm()); + } + } +} \ No newline at end of file diff --git a/StreamViewer.Designer.cs b/StreamViewer.Designer.cs new file mode 100644 index 0000000..1196d83 --- /dev/null +++ b/StreamViewer.Designer.cs @@ -0,0 +1,124 @@ +using LibVLCSharp.Forms.Shared; + +namespace robospot_camera_finder +{ + partial class StreamViewer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + videoView = new LibVLCSharp.WinForms.VideoView(); + tbZoom = new TrackBar(); + lblMinZoom = new Label(); + lblMaxZoom = new Label(); + timerUpdateZoom = new System.Windows.Forms.Timer(components); + ((System.ComponentModel.ISupportInitialize)videoView).BeginInit(); + ((System.ComponentModel.ISupportInitialize)tbZoom).BeginInit(); + SuspendLayout(); + // + // videoView + // + videoView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + videoView.BackColor = Color.Black; + videoView.Location = new Point(12, 12); + videoView.MediaPlayer = null; + videoView.Name = "videoView"; + videoView.Size = new Size(870, 495); + videoView.TabIndex = 0; + videoView.Text = "videoView"; + // + // tbZoom + // + tbZoom.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right; + tbZoom.LargeChange = 20; + tbZoom.Location = new Point(889, 30); + tbZoom.Maximum = 9999; + tbZoom.Name = "tbZoom"; + tbZoom.Orientation = Orientation.Vertical; + tbZoom.Size = new Size(45, 459); + tbZoom.SmallChange = 10; + tbZoom.TabIndex = 1; + tbZoom.TickFrequency = 300; + tbZoom.TickStyle = TickStyle.TopLeft; + tbZoom.Value = 10; + tbZoom.KeyUp += tbZoom_KeyUp; + tbZoom.MouseUp += tbZoom_MouseUp; + // + // lblMinZoom + // + lblMinZoom.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + lblMinZoom.AutoSize = true; + lblMinZoom.Location = new Point(902, 492); + lblMinZoom.Name = "lblMinZoom"; + lblMinZoom.Size = new Size(19, 15); + lblMinZoom.TabIndex = 2; + lblMinZoom.Text = "1x"; + // + // lblMaxZoom + // + lblMaxZoom.Anchor = AnchorStyles.Top | AnchorStyles.Right; + lblMaxZoom.AutoSize = true; + lblMaxZoom.Location = new Point(902, 12); + lblMaxZoom.Name = "lblMaxZoom"; + lblMaxZoom.Size = new Size(25, 15); + lblMaxZoom.TabIndex = 3; + lblMaxZoom.Text = "32x"; + // + // timerUpdateZoom + // + timerUpdateZoom.Enabled = true; + timerUpdateZoom.Interval = 10000; + timerUpdateZoom.Tick += timerUpdateZoom_Tick; + // + // StreamViewer + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(933, 519); + Controls.Add(lblMaxZoom); + Controls.Add(lblMinZoom); + Controls.Add(tbZoom); + Controls.Add(videoView); + Margin = new Padding(4, 3, 4, 3); + Name = "StreamViewer"; + Text = "LibVLCSharp.WinForms"; + FormClosed += StreamViewer_FormClosed; + ((System.ComponentModel.ISupportInitialize)videoView).EndInit(); + ((System.ComponentModel.ISupportInitialize)tbZoom).EndInit(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private LibVLCSharp.WinForms.VideoView videoView; + private TrackBar tbZoom; + private Label lblMinZoom; + private Label lblMaxZoom; + private System.Windows.Forms.Timer timerUpdateZoom; + } +} \ No newline at end of file diff --git a/StreamViewer.cs b/StreamViewer.cs new file mode 100644 index 0000000..7256259 --- /dev/null +++ b/StreamViewer.cs @@ -0,0 +1,95 @@ +using LibVLCSharp.Shared; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.DirectoryServices.ActiveDirectory; +using System.Drawing; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace robospot_camera_finder +{ + public partial class StreamViewer : Form + { + public LibVLC _libVLC; + public MediaPlayer _mp; + + string username = "admin"; + string password = "RoboSpot10"; + string cam_ip = ""; + + public StreamViewer(string name, string ip) + { + InitializeComponent(); + _libVLC = new LibVLC(); + _mp = new MediaPlayer(_libVLC); + cam_ip = ip; + + timerUpdateZoom.Start(); + updateZoomSlider(); + + videoView.MediaPlayer = _mp; + var media = new Media(_libVLC, new Uri("rtsp://" + ip + "/profile2/media.smp")); + media.AddOption(":network-caching=25"); + _mp.Play(media); + media.Dispose(); + this.Text = name; + } + + private void updateZoomSlider() + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://" + cam_ip + "/stw-cgi/ptzcontrol.cgi?msubmenu=query&action=view&Query=Zoom"); + request.Credentials = new NetworkCredential(username, password); + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + string text; + using (var sr = new StreamReader(response.GetResponseStream())) { text = sr.ReadToEnd(); } + string[] resp_lines = text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + string zoom_value = resp_lines[1].Substring(resp_lines[1].LastIndexOf('=') + 1); + tbZoom.Value = int.Parse(zoom_value); + + } + + private void sendZoomValue(string zoom_pulse) + { + // clamp values to allowed range + if (int.Parse(zoom_pulse) < 10) + { + zoom_pulse = "10"; + } + if (int.Parse(zoom_pulse) > 9999) + { + zoom_pulse = "9999"; + } + + HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://" + cam_ip + "/stw-cgi/ptzcontrol.cgi?msubmenu=absolute&action=control&ZoomPulse=" + zoom_pulse); + request.Credentials = new NetworkCredential(username, password); + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + } + + private void StreamViewer_FormClosed(object sender, FormClosedEventArgs e) + { + _mp.Stop(); + _mp.Dispose(); + _libVLC.Dispose(); + } + + private void tbZoom_KeyUp(object sender, KeyEventArgs e) + { + sendZoomValue(tbZoom.Value.ToString()); + } + + private void tbZoom_MouseUp(object sender, MouseEventArgs e) + { + sendZoomValue(tbZoom.Value.ToString()); + } + + private void timerUpdateZoom_Tick(object sender, EventArgs e) + { + updateZoomSlider(); + } + } +} diff --git a/StreamViewer.resx b/StreamViewer.resx new file mode 100644 index 0000000..ce0bc94 --- /dev/null +++ b/StreamViewer.resx @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/robospot-camera-finder.csproj b/robospot-camera-finder.csproj new file mode 100644 index 0000000..75708d6 --- /dev/null +++ b/robospot-camera-finder.csproj @@ -0,0 +1,20 @@ + + + + WinExe + net7.0-windows + robospot_camera_finder + enable + true + enable + + + + + + + + + + + \ No newline at end of file diff --git a/robospot-camera-finder.sln b/robospot-camera-finder.sln new file mode 100644 index 0000000..4b1bb17 --- /dev/null +++ b/robospot-camera-finder.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33516.290 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "robospot-camera-finder", "robospot-camera-finder.csproj", "{D68CD277-4F05-4BEC-879C-E2097CC4BEDC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D68CD277-4F05-4BEC-879C-E2097CC4BEDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D68CD277-4F05-4BEC-879C-E2097CC4BEDC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D68CD277-4F05-4BEC-879C-E2097CC4BEDC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D68CD277-4F05-4BEC-879C-E2097CC4BEDC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {23A9FE53-49F6-4D0C-951F-CF3CA11F091C} + EndGlobalSection +EndGlobal