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