Beispiel #1
0
        public override void handleGETRequest(HttpProcessor p)
        {
            try
            {
                string requestedPage = Uri.UnescapeDataString(p.request_url.AbsolutePath.TrimStart('/'));

                if (requestedPage == "admin")
                {
                    p.writeRedirect("admin/main");
                    return;
                }

                if (requestedPage == "login")
                {
                    LogOutUser(p, null);
                    return;
                }

                Session s = sm.GetSession(p.requestCookies.GetValue("cps"), p.requestCookies.GetValue("auth"), p.GetParam("rawauth"));
                if (s.sid != null && s.sid.Length == 16)
                {
                    p.responseCookies.Add("cps", s.sid, TimeSpan.FromMinutes(s.sessionLengthMinutes));
                }

                if (requestedPage == "logout")
                {
                    LogOutUser(p, s);
                    return;
                }


                if (requestedPage.StartsWith("admin/"))
                {
                    string adminPage = requestedPage == "admin" ? "" : requestedPage.Substring("admin/".Length);
                    if (string.IsNullOrWhiteSpace(adminPage))
                    {
                        adminPage = "main";
                    }
                    int idxQueryStringStart = adminPage.IndexOf('?');
                    if (idxQueryStringStart == -1)
                    {
                        idxQueryStringStart = adminPage.Length;
                    }
                    adminPage = adminPage.Substring(0, idxQueryStringStart);
                    Pages.Admin.AdminPage.HandleRequest(adminPage, p, s);
                    return;
                }
                else if (requestedPage.StartsWith("image/"))
                {
                    requestedPage = requestedPage.Substring("image/".Length);
                    #region image/
                    if (requestedPage.EndsWith(".jpg") || requestedPage.EndsWith(".jpeg") || requestedPage.EndsWith(".png") || requestedPage.EndsWith(".webp"))
                    {
                        int    extensionLength = requestedPage[requestedPage.Length - 4] == '.' ? 4 : 5;
                        string format          = requestedPage.Substring(requestedPage.Length - (extensionLength - 1));
                        string cameraId        = requestedPage.Substring(0, requestedPage.Length - extensionLength);
                        cameraId = cameraId.ToLower();

                        int minPermission = cm.GetCameraMinPermission(cameraId);
                        if (minPermission == 101)
                        {
                            p.writeFailure();
                            return;
                        }
                        if ((s == null && minPermission > 0) || (s != null && s.permission < minPermission))
                        {
                            LogOutUser(p, s);
                            return;
                        }
                        int          wait        = p.GetIntParam("wait", 5000);
                        IPCameraBase cam         = cm.GetCamera(cameraId);
                        byte[]       latestImage = cm.GetLatestImage(cameraId, wait);
                        int          patience    = p.GetIntParam("patience");
                        if (patience > 0)
                        {
                            if (patience > 5000)
                            {
                                patience = 5000;
                            }

                            int timeLeft = patience;
                            System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
                            timer.Start();
                            while (s.DuplicateImageSendCheck(cameraId, latestImage) && cam != null && timeLeft > 0)
                            {
                                // The latest image was already sent to the user in a previous image request.
                                // Wait for up to 5 seconds as desired by the user to get a "new" image.
                                cam.newFrameWaitHandle.WaitOne(Math.Max(50, timeLeft));                                  // This EventWaitHandle nonsense isn't perfect, so this should prevent excessively long delays in the event of a timing error.
                                latestImage = cm.GetLatestImage(cameraId);
                                timeLeft    = patience - (int)timer.ElapsedMilliseconds;
                            }
                        }
                        if (latestImage.Length == 0)
                        {
                            p.writeFailure("502 Bad Gateway");
                            return;
                        }
                        ImageFormat imgFormat = ImageFormat.Jpeg;
                        latestImage = ImageConverter.HandleRequestedConversionIfAny(latestImage, p, ref imgFormat, format);
                        p.tcpClient.SendBufferSize = latestImage.Length + 256;
                        p.writeSuccess(Util.GetMime(imgFormat), latestImage.Length);
                        p.outputStream.Flush();
                        p.rawOutputStream.Write(latestImage, 0, latestImage.Length);
                    }
                    else if (requestedPage.EndsWith(".mjpg"))
                    {
                        string cameraId = requestedPage.Substring(0, requestedPage.Length - 5);
                        cameraId = cameraId.ToLower();
                        int minPermission = cm.GetCameraMinPermission(cameraId);
                        if (minPermission == 101)
                        {
                            p.writeFailure();
                            return;
                        }
                        if ((s == null && minPermission > 0) || (s != null && s.permission < minPermission))
                        {
                            LogOutUser(p, s);
                            return;
                        }
                        if (cm.GetLatestImage(cameraId).Length == 0)
                        {
                            return;
                        }
                        // Increasing the send buffer size here does not help streaming fluidity.
                        p.writeSuccess("multipart/x-mixed-replace;boundary=ipcamera");
                        byte[] newImage;
                        byte[] lastImage = null;
                        while (!this.stopRequested)
                        {
                            try
                            {
                                newImage = cm.GetLatestImage(cameraId);
                                while (newImage == lastImage)
                                {
                                    Thread.Sleep(1);
                                    newImage = cm.GetLatestImage(cameraId);
                                    if (this.stopRequested)
                                    {
                                        return;
                                    }
                                }
                                lastImage = newImage;

                                ImageFormat imgFormat = ImageFormat.Jpeg;
                                byte[]      sendImage = ImageConverter.HandleRequestedConversionIfAny(newImage, p, ref imgFormat);

                                p.outputStream.WriteLine("--ipcamera");
                                p.outputStream.WriteLine("Content-Type: " + Util.GetMime(imgFormat));
                                p.outputStream.WriteLine("Content-Length: " + sendImage.Length);
                                p.outputStream.WriteLine();
                                p.outputStream.Flush();
                                p.rawOutputStream.Write(sendImage, 0, sendImage.Length);
                                p.rawOutputStream.Flush();
                                p.outputStream.WriteLine();
                            }
                            catch (Exception ex)
                            {
                                if (!p.isOrdinaryDisconnectException(ex))
                                {
                                    Logger.Debug(ex);
                                }
                                break;
                            }
                        }
                    }
                    else if (requestedPage.EndsWith(".ogg"))
                    {
                        string cameraId = requestedPage.Substring(0, requestedPage.Length - 4);
                        cameraId = cameraId.ToLower();
                        int minPermission = cm.GetCameraMinPermission(cameraId);
                        if (minPermission == 101)
                        {
                            p.writeFailure();
                            return;
                        }
                        if ((s == null && minPermission > 0) || (s != null && s.permission < minPermission))
                        {
                            LogOutUser(p, s);
                            return;
                        }
                        IPCameraBase _cam = cm.GetCamera(cameraId);
                        if (_cam is Html5VideoCamera)
                        {
                            Html5VideoCamera         cam            = (Html5VideoCamera)_cam;
                            ConcurrentQueue <byte[]> myDataListener = new ConcurrentQueue <byte[]>();
                            try
                            {
                                cam.RegisterStreamListener(myDataListener);
                                p.writeSuccess("application/octet-stream");
                                p.outputStream.Flush();
                                byte[] outputBuffer;
                                int    chunkCount = 0;
                                while (!this.stopRequested)
                                {
                                    try
                                    {
                                        chunkCount = myDataListener.Count;
                                        if (chunkCount > 100)
                                        {
                                            return;                                             // This connection is falling too far behind.  End it.
                                        }
                                        else if (chunkCount > 0)
                                        {
                                            Console.Write(chunkCount + " ");
                                            if (myDataListener.TryDequeue(out outputBuffer))
                                            {
                                                p.rawOutputStream.Write(outputBuffer, 0, outputBuffer.Length);
                                                p.rawOutputStream.Flush();
                                            }
                                        }
                                        else
                                        {
                                            Thread.Sleep(1);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        if (!p.isOrdinaryDisconnectException(ex))
                                        {
                                            Logger.Debug(ex);
                                        }
                                        break;
                                    }
                                }
                            }
                            finally
                            {
                                cam.UnregisterStreamListener(myDataListener);
                            }
                        }
                        else
                        {
                            p.writeFailure("501 Not Implemented");
                        }
                    }
                    else if (requestedPage.EndsWith(".cam"))
                    {
                        string cameraId = requestedPage.Substring(0, requestedPage.Length - 4);
                        cameraId = cameraId.ToLower();
                        int minPermission = cm.GetCameraMinPermission(cameraId);
                        if (minPermission == 101)
                        {
                            p.writeFailure();
                            return;
                        }
                        if ((s == null && minPermission > 0) || (s != null && s.permission < minPermission))
                        {
                            LogOutUser(p, s);
                            return;
                        }
                        IPCameraBase cam = cm.GetCamera(cameraId);
                        if (cam != null && cam.cameraSpec.ptzType == MJpegCameraProxy.Configuration.PtzType.Dahua || cam.cameraSpec.ptzType == MJpegCameraProxy.Configuration.PtzType.Hikvision)
                        {
                            p.writeRedirect("../Camera.html?cam=" + cameraId);
                            return;
                        }

                        string userAgent = p.GetHeaderValue("User-Agent", "");
                        bool   isMobile  = userAgent.Contains("iPad") || userAgent.Contains("iPhone") || userAgent.Contains("Android") || userAgent.Contains("BlackBerry");

                        bool   isLanConnection = p == null ? false : p.IsLanConnection;
                        int    defaultRefresh  = isLanConnection && !isMobile ? -1 : 250;
                        string html            = CamPage.GetHtml(cameraId, !isMobile, p.GetIntParam("refresh", defaultRefresh), p.GetBoolParam("override") ? -1 : 600000, p);
                        if (string.IsNullOrEmpty(html) || html == "NO")
                        {
                            p.writeFailure();
                            return;
                        }
                        p.writeSuccess("text/html");
                        p.outputStream.Write(html);
                    }
                    else if (requestedPage == "PTZPRESETIMG")
                    {
                        string cameraId = p.GetParam("id");
                        cameraId = cameraId.ToLower();
                        IPCameraBase cam = cm.GetCamera(cameraId);
                        if (cam != null)
                        {
                            int index = p.GetIntParam("index", -1);
                            if (index > -1)
                            {
                                if (cam.cameraSpec.ptz_proxy)
                                {
                                    string auth = (!string.IsNullOrEmpty(cam.cameraSpec.ptz_username) && !string.IsNullOrEmpty(cam.cameraSpec.ptz_password)) ? "rawauth=" + HttpUtility.UrlEncode(cam.cameraSpec.ptz_username) + ":" + HttpUtility.UrlEncode(cam.cameraSpec.ptz_password) + "&" : "";
                                    byte[] data = SimpleProxy.GetData("http://" + cam.cameraSpec.ptz_hostName + "/PTZPRESETIMG?" + auth + "id=" + HttpUtility.UrlEncode(cam.cameraSpec.ptz_proxy_cameraId) + "&index=" + index);
                                    if (data.Length > 0)
                                    {
                                        p.writeSuccess("image/jpg", data.Length);
                                        p.outputStream.Flush();
                                        p.rawOutputStream.Write(data, 0, data.Length);
                                        return;
                                    }
                                }
                                else
                                {
                                    string fileName      = Globals.ThumbsDirectoryBase + cameraId + index + ".jpg";
                                    int    minPermission = cm.GetCameraMinPermission(cameraId);
                                    if ((s == null && minPermission > 0) || (s != null && s.permission < minPermission) || minPermission == 101)
                                    {
                                    }
                                    else
                                    {
                                        if (File.Exists(fileName))
                                        {
                                            byte[] bytes = File.ReadAllBytes(fileName);
                                            p.writeSuccess("image/jpg", bytes.Length);
                                            p.outputStream.Flush();
                                            p.rawOutputStream.Write(bytes, 0, bytes.Length);
                                            return;
                                        }
                                    }
                                }
                            }
                        }
                        {                         // Failed to get image thumbnail
                            byte[] bytes = File.ReadAllBytes(Globals.WWWPublicDirectoryBase + "Images/qmark.png");
                            p.writeSuccess("image/png", bytes.Length);
                            p.outputStream.Flush();
                            p.rawOutputStream.Write(bytes, 0, bytes.Length);
                            return;
                        }
                    }
                    else if (requestedPage.EndsWith(".wanscamstream"))
                    {
                        string       cameraId = requestedPage.Substring(0, requestedPage.Length - ".wanscamstream".Length);
                        IPCameraBase cam      = cm.GetCamera(cameraId);
                        if (cam == null)
                        {
                            return;
                        }
                        if (!cam.cameraSpec.wanscamCompatibilityMode)
                        {
                            return;
                        }
                        if (p.RemoteIPAddress != "127.0.0.1")
                        {
                            return;
                        }
                        Uri    url  = new Uri(cam.cameraSpec.imageryUrl);
                        string host = url.Host;
                        int    port = url.Port;
                        string path = url.PathAndQuery;
                        //string path = "/livestream.cgi?user=admin&pwd=nooilwell&streamid=0&audio=0&filename=";
                        //string path = "/videostream.cgi?user=admin&pwd=nooilwell&resolution=8";
                        int total = 0;
                        try
                        {
                            //Console.WriteLine("opening");
                            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                            socket.Connect(host, port);
                            byte[] buffer = new byte[4096];
                            socket.Send(UTF8Encoding.UTF8.GetBytes("GET " + path + " HTTP/1.1\r\nHost: " + host + ":" + port + "\r\nConnection: close\r\n\r\n"));
                            //Console.WriteLine("open");
                            int read = socket.Receive(buffer);
                            p.writeSuccess("video/raw");
                            p.outputStream.Flush();
                            while (read > 0 && socket.Connected && p.tcpClient.Connected)
                            {
                                p.rawOutputStream.Write(buffer, 0, read);
                                total += read;
                                //Console.WriteLine(read);
                                read = socket.Receive(buffer);
                            }
                            //Console.WriteLine("close");
                        }
                        catch (Exception ex)
                        {
                            if (!p.isOrdinaryDisconnectException(ex))
                            {
                                Logger.Debug(ex);
                            }
                        }
                    }
                    #endregion
                }
                else if (requestedPage.StartsWith("control/"))
                {
                    requestedPage = requestedPage.Substring("control/".Length);
                    #region control/
                    if (requestedPage == "keepalive")
                    {
                        string cameraId = p.GetParam("id");
                        cameraId = cameraId.ToLower();
                        int minPermission = cm.GetCameraMinPermission(cameraId);
                        if (minPermission == 101)
                        {
                            p.writeFailure();
                            return;
                        }
                        if ((s == null && minPermission > 0) || (s != null && s.permission < minPermission))
                        {
                            p.writeFailure("403 Forbidden");
                            return;
                        }
                        cm.GetRTSPUrl(cameraId, p);
                        p.writeSuccess("text/plain");
                        p.outputStream.Write("1");
                    }

                    else if (requestedPage == "PTZ")
                    {
                        string cameraId = p.GetParam("id");
                        cameraId = cameraId.ToLower();
                        int minPermission = cm.GetCameraMinPermission(cameraId);
                        if (minPermission == 101)
                        {
                            p.writeFailure();
                            return;
                        }
                        if ((s == null && minPermission > 0) || (s != null && s.permission < minPermission))
                        {
                            LogOutUser(p, s);
                            return;
                        }
                        PTZ.RunCommand(cameraId, p.GetParam("cmd"));
                        p.writeSuccess("text/plain");
                    }
                    #endregion
                }
                else
                {
                    #region www
                    int permissionRequired;
                    if (!Util.TryGetValue(requestedPage.ToLower(), MJpegWrapper.cfg.GetWwwFilesList(), out permissionRequired))
                    {
                        permissionRequired = -1;
                    }


                    string wwwDirectory = permissionRequired == -1 ? Globals.WWWPublicDirectoryBase : Globals.WWWDirectoryBase;

                    if (permissionRequired < 0)
                    {
                        permissionRequired = 0;
                    }
                    else if (permissionRequired > 100)
                    {
                        permissionRequired = 100;
                    }

                    if (permissionRequired > s.permission)
                    {
                        LogOutUser(p, s);
                        return;
                    }

                    DirectoryInfo WWWDirectory     = new DirectoryInfo(wwwDirectory);
                    string        wwwDirectoryBase = WWWDirectory.FullName.Replace('\\', '/').TrimEnd('/') + '/';
                    FileInfo      fi             = new FileInfo(wwwDirectoryBase + requestedPage);
                    string        targetFilePath = fi.FullName.Replace('\\', '/');
                    if (!targetFilePath.StartsWith(wwwDirectoryBase) || targetFilePath.Contains("../"))
                    {
                        p.writeFailure("400 Bad Request");
                        return;
                    }
                    if (!fi.Exists)
                    {
                        p.writeFailure();
                        return;
                    }

                    // && (fi.Extension == ".html" || fi.Extension == ".htm")
                    if (fi.Name.ToLower() == "camera.html" && fi.Length < 256000)
                    {
                        p.writeSuccess(Mime.GetMimeType(fi.Extension));
                        string   html = File.ReadAllText(fi.FullName);
                        CamPage2 cp   = new CamPage2(html, p);
                        html = cp.Html;
                        html = html.Replace("%ALLCAMS%", string.Join(",", MJpegServer.cm.GenerateAllCameraIdList()));
                        html = html.Replace("%ALLCAMS_IDS_NAMES_JS_ARRAY%", MJpegServer.cm.GenerateAllCameraIdNameList(s == null ? 0 : s.permission));
                        try
                        {
                            html = html.Replace("%REMOTEIP%", p.RemoteIPAddress);
                        }
                        catch (Exception ex)
                        {
                            Logger.Debug(ex);
                        }
                        p.outputStream.Write(html);
                        p.outputStream.Flush();
                    }
                    else if ((fi.Extension == ".html" || fi.Extension == ".htm") && fi.Length < 256000)
                    {
                        p.writeSuccess(Mime.GetMimeType(fi.Extension));
                        string html = File.ReadAllText(fi.FullName);
                        html = html.Replace("%ALLCAMS%", string.Join(",", MJpegServer.cm.GenerateAllCameraIdList()));
                        html = html.Replace("%ALLCAMS_IDS_NAMES_JS_ARRAY%", MJpegServer.cm.GenerateAllCameraIdNameList(s == null ? 0 : s.permission));
                        try
                        {
                            html = html.Replace("%REMOTEIP%", p.RemoteIPAddress);
                        }
                        catch (Exception ex)
                        {
                            Logger.Debug(ex);
                        }
                        p.outputStream.Write(html);
                        p.outputStream.Flush();
                    }
                    else
                    {
                        List <KeyValuePair <string, string> > additionalHeaders = new List <KeyValuePair <string, string> >();
                        additionalHeaders.Add(new KeyValuePair <string, string>("Cache-Control", "max-age=3600, public"));
                        p.writeSuccess(Mime.GetMimeType(fi.Extension), additionalHeaders: additionalHeaders);
                        p.outputStream.Flush();
                        using (FileStream fs = fi.OpenRead())
                        {
                            fs.CopyTo(p.rawOutputStream);
                        }
                        p.rawOutputStream.Flush();
                    }
                    #endregion
                }
            }
            catch (Exception ex)
            {
                if (!p.isOrdinaryDisconnectException(ex))
                {
                    Logger.Debug(ex);
                }
            }
        }
Beispiel #2
0
        public static string GetHtml(string camId, bool enableAutoResize, int refreshTime = 250, int disableRefreshAfter = 600000, HttpProcessor httpProcessor = null)
        {
            IPCameraBase cam = MJpegServer.cm.GetCameraAndGetItRunning(camId);

            if (cam == null)
            {
                return("NO");
            }
            int    width         = 0;
            int    height        = 0;
            int    patience      = (cam.cameraSpec.delayBetweenImageGrabs > 0 ? cam.cameraSpec.delayBetweenImageGrabs : 0) + 5000;
            string cameraImgLink = @"<img id=""imgFrame"" class=""CamImg"" />";
            string keepalive     = "";

            if (cam.cameraSpec.type == CameraType.h264_rtsp_proxy)
            {
                bool sizeOverridden = cam.cameraSpec.h264_video_width > 0 && cam.cameraSpec.h264_video_height > 0;
                width  = sizeOverridden ? cam.cameraSpec.h264_video_width : 640;
                height = sizeOverridden ? cam.cameraSpec.h264_video_height : 360;

                keepalive     = @"
				var keepaliveInterval;
				$(function()
				{
					sizeOverridden = "                     + (sizeOverridden ? "true" : "false") + @";
					keepaliveInterval = setInterval(keepalive, 4000);
					var vlc = document.getElementById('vlc');
					registerVLCEvent('MediaPlayerPlaying', handlePlayerPlaying);
					var url = '"                     + HttpUtility.HtmlEncode(HttpUtility.JavaScriptStringEncode(MJpegServer.cm.GetRTSPUrl(cam.cameraSpec.id, httpProcessor))) + @"';
					url = url.replace('$$$HOST$$$', location.hostname);
					vlc.playlist.add(url);
					vlc.playlist.play();
					if(sizeOverridden)
						vlc.video.aspectRatio = '"                         + width + ":" + height + @"';
				});
				function keepalive()
				{
					if(refreshDisabled)
						clearInterval(keepaliveInterval);
					else
						$.ajax('keepalive?id="                         + camId + @"');
				}
				function handlePlayerPlaying()
				{
					if(!sizeOverridden)
					{
						setTimeout(resize, 500);
						setTimeout(resize, 1000);
						setTimeout(resize, 1500);
					}
				}
				function registerVLCEvent(event, handler)
				{
					var vlc = document.getElementById('vlc');
					if (vlc)
					{
						if (vlc.attachEvent)
						{
							// Microsoft
							vlc.attachEvent(event, handler);
						} else if (vlc.addEventListener)
						{
							// Mozilla: DOM level 2
							vlc.addEventListener(event, handler, false);
						} else
						{
							// DOM level 0
							vlc['on' + event] = handler;
						}
					}
				}"                ;
                cameraImgLink = @"<div id=""vlcFrame"" style=""width:" + width + @"px;height:" + height + @"px;""><embed type=""application/x-vlc-plugin"" id=""vlc"" pluginspage=""http://www.videolan.org"" width=""" + width + @""" height=""" + height + @""" toolbar=""false"" src="""" mute=""false"" /></div>";
            }
            else
            {
                for (int i = 0; i < 50; i++)
                {
                    if (cam.ImageSize.Width != 0 && cam.ImageSize.Height != 0)
                    {
                        break;
                    }
                    Thread.Sleep(100);
                }
                if (cam.ImageSize.Width == 0 || cam.ImageSize.Height == 0)
                {
                    return(@"<!DOCTYPE HTML>
						<html>
						<head>
							<title>"                             + HttpUtility.HtmlEncode(cam.cameraSpec.name) + @"</title>
						</head>
						<body>
						This camera is starting up.<br/>
						Please <a href=""javascript:top.location.reload();"">try again in a few moments</a>.
						</body>
						</html>"                        );
                }
                width  = cam.ImageSize.Width;
                height = cam.ImageSize.Height;
            }

            string minutesLabel = disableRefreshAfter < 0 ? "a very long time" : (TimeSpan.FromMilliseconds(disableRefreshAfter).TotalMinutes + " minutes");

            return(@"<!DOCTYPE HTML>
<html>
<head>
	<title>"     + HttpUtility.HtmlEncode(cam.cameraSpec.name) + @"</title>
	<script src="""     + Globals.jQueryPath + @""" type=""text/javascript""></script>
	<script type=""text/javascript"">
		var disableRefreshAfter = "         + disableRefreshAfter + @";
		var refreshDisabled = false;
		var originwidth = parseInt("         + width + @");
		var originheight = parseInt("         + height + @");
		var lastUpdate = 0;
		var clickCausesResize = true;
		var showPTH = "         + (cam.cameraSpec.ptzType == PtzType.None ? "false" : "true") + @";
		var sizeOverridden = false;
		$(function()
		{
			if(disableRefreshAfter > -1)
				setTimeout(""disableRefresh()"", disableRefreshAfter);
		});
		"         + keepalive + @"
		function myOnLoad()
		{
			$(""#imgFrame"").load(function ()
			{
" + (refreshTime < 0 ? "" : @"
				if (!this.complete || typeof this.naturalWidth == ""undefined"" || this.naturalWidth == 0)
				{
					alert('Bad image data was received.  A data transmission error may have occurred, or this camera may be offline.  Please reload this page to try again.');
				}
				else if(!refreshDisabled)
				{
					lastUpdate = new Date().getTime();
					setTimeout(""GetNewImage();"", "                     + refreshTime + @");
				}
") + @"
			});
			$(""#imgFrame"").error(function ()
			{
				setTimeout(""GetNewImage();"", "                 + (refreshTime < 0 ? 1000 : refreshTime) + @");
			});
			GetNewImage();
		}
		function PopupMessage(msg)
		{
			var pm = $(""#popupMessage"");
			if(pm.length < 1)
				$(""#camFrame"").after('<div id=""popupFrame""><div id=""popupMessage"">' + msg + '</div><center><input type=""button"" value=""Close Message"" onclick=""CloseMessage()""/></center></div>');
			else
				pm.append(msg);
		}
		function CloseMessage()
		{
			$(""#popupFrame"").remove();
		}
		function GetNewImage()
		{
			$(""#imgFrame"").attr('src', '"             + camId + "." + (refreshTime < 0 ? "m" : "") + @"jpg?patience=" + patience + "&" + httpProcessor.GetParam("imgargs") + @"&nocache=' + new Date().getTime());
		}
		function disableRefresh()
		{
			refreshDisabled = true;
			PopupMessage('This page has been open for "             + minutesLabel + @".  To save resources, the image will no longer refresh automatically.  <a href=""javascript:top.location.reload();"">Click here</a> to reload this page.');" + (refreshTime < 0 ? @"$(""#imgFrame"").attr('src', '" + camId + @".jpg?nocache=' + new Date().getTime());" : "") + @"
		}
		"         + (enableAutoResize ? "$(window).load(resize); $(window).resize(resize);" : "") + @"
		function resize(width, height)
		{
			var newHeight;
			var newWidth;
			var currentImage = document.getElementById(""imgFrame"");
			if (currentImage == null)
			{
				currentImage = document.getElementById(""vlcFrame"");
				
				var vlc = document.getElementById('vlc')
				if(vlc && !sizeOverridden)
				{
					originwidth = parseInt(vlc.video.width);
					originheight = parseInt(vlc.video.height);
					if(originwidth == 0)
						originwidth = 640;
					if(originheight == 0)
						originheight = 360;
				}
			}
			if (currentImage == null)
				return;
			if (typeof (width) == 'undefined' || typeof (height) == 'undefined')
			{
				var imgOff = FindOffsets(currentImage);
				var screenOff = GetViewportDims();
				// Calculate available dimensions
				var availableHeight = (screenOff.height - imgOff.top) - 7 - (showPTH ? 130 : 0);
				var availableWidth = (screenOff.width - imgOff.left) - 21;
				// Take into consideration the original width and height for the image
				newHeight = originheight < availableHeight ? originheight : availableHeight;
				newWidth = originwidth < availableWidth ? originwidth : availableWidth;
				// Calculate ratios
				var originRatio = originwidth / originheight;
				var newRatio = newWidth / newHeight;
				if (newRatio < originRatio)
					newHeight = newWidth / originRatio;
				else
					newWidth = newHeight * originRatio;
				currentImage.onclick = function ()
				{
					if(clickCausesResize)
						resize(originwidth, originheight);
				}
			}
			else
			{
				var newHeight = height;
				var newWidth = width;
				currentImage.onclick = function ()
				{
					if(clickCausesResize)
						resize();
				}
			}
			$(currentImage).height(newHeight);
			$(currentImage).width(newWidth);

			$(""#vlcFrame"").width(newWidth);
			$(""#vlcFrame"").height(newHeight);
			$(""#vlc"").attr('width', newWidth + 'px');
			$(""#vlc"").attr('height', newHeight + 'px');
			
			$(""#camFrame"").width(newWidth);
		}
		function GetViewportDims()
		{
			var w;
			var h;
			if (typeof (window.innerWidth) != 'undefined')
			{
				w = window.innerWidth;
				h = window.innerHeight;
			}
			else if (typeof (document.documentElement) != 'undefined' && typeof (document.documentElement.clientWidth) != 'undefined' && document.documentElement.clientWidth != 0)
			{
				w = document.documentElement.clientWidth;
				h = document.documentElement.clientHeight;
			}
			else
			{
				w = document.getElementsByTagName('body')[0].clientWidth;
				h = document.getElementsByTagName('body')[0].clientHeight;
			}
			return { width: w, height: h };
		}
		function FindOffsets(node)
		{
			var oLeft = 0;
			var oTop = 0;
			var oWidth = node.offsetWidth;
			var oHeight = node.offsetHeight;
			if (oWidth == 0)
				oWidth += node.scrollWidth;
			oLeft = node.offsetLeft;
			oTop = node.offsetTop;
			if (oHeight == 0)
			{
				if (node.childNodes.length > 0)
				{
					oHeight += node.childNodes[0].offsetHeight;
					oTop = node.childNodes[0].offsetTop;
				}
				if (oHeight == 0)
					oHeight += node.scrollHeight;
			}
			node = node.offsetParent;
			while (node)
			{
				oLeft += node.offsetLeft;
				oTop += node.offsetTop;
				node = node.offsetParent;
			}
			return { left: oLeft, top: oTop, width: oWidth, height: oHeight };
		}
	</script>
	<style type=""text/css"">
		.CamImg
		{
			width: "             + width + @"px;
			height: "             + height + @"px;
		}
		#vlcFrame
		{
			width: "             + width + @"px;
			height: "             + height + @"px;
		}
		body
		{
			margin: 3px;
		}
		#camFrame
		{
			background-color: #666666;
			border: 1px Solid Black;
			border-radius: 5px;
			padding: 3px;
			width: "             + width + @"px;
		}
		#popupFrame
		{
			position: fixed;
			background-color: #BB0000;
			border: 1px Solid White;
			border-radius: 5px;
			padding: 5px;
			top: 15px;
			width: 300px;
			left: 20px;
		}
		#popupMessage
		{
			color: White;
			margin-bottom: 5px;
		}
		#popupMessage a
		{
			color: #DDDDFF;
		}
		#pthDiv, #camControls
		{
			margin-top: 3px;
			padding: 0px 3px 0px 3px;
			background-color: #AAAAAA;
		}
		#pthCell
		{
			vertical-align: top;
		}
		#pthTable td
		{
			text-align: center;
		}
		.nounderline, .nounderline a
		{
			text-decoration: none;
		}
		.flip-horizontal
		{
			-moz-transform: scaleX(-1);
			-webkit-transform: scaleX(-1);
			-o-transform: scaleX(-1);
			transform: scaleX(-1);
			-ms-filter: fliph; /*IE*/
			filter: fliph; /*IE*/
		}
		.flip-vertical
		{
			-moz-transform: scaleY(-1);
			-webkit-transform: scaleY(-1);
			-o-transform: scaleY(-1);
			transform: scaleY(-1);
			-ms-filter: flipv; /*IE*/
			filter: flipv; /*IE*/
		}
		.flip-both
		{
			-moz-transform: scale(-1,-1);
			-webkit-transform: scale(-1,-1);
			-o-transform: scale(-1,-1);
			transform: scale(-1,-1);
			-ms-filter: flipv fliph; /*IE*/
			filter: flipv fliph; /*IE*/
		}
		.arrow-up
		{
			width: 0px;
			height: 0px;
			border-bottom: 20px solid #00AA00;
			border-left: 20px solid transparent;
			border-right: 20px solid transparent;
		}
		.arrow-down
		{
			width: 0px;
			height: 0px;
			border-top: 20px solid #00AA00;
			border-left: 20px solid transparent;
			border-right: 20px solid transparent;
		}
		.arrow-left
		{
			width: 0px;
			height: 0px;
			border-bottom: 10px solid transparent;
			border-top: 10px solid transparent;
			border-right: 10px solid #00AA00;
		}
		.arrow-right
		{
			width: 0px;
			height: 0px;
			border-bottom: 10px solid transparent;
			border-left: 10px solid #00AA00;
			border-top: 10px solid transparent;
		}
	</style>
</head>
<body onload=""myOnLoad();"">
	<div id=""camFrame"">
		"         + cameraImgLink + @"
		<table style=""width: 100%"">
			<tbody>
				<tr>
					"                     + PTZ.GetHtml(camId, cam) + @"
				</tr>
			</tbody>
		</table>
	</div>
</body>
</html>");
        }