{"action":"created","issue":{"url":"https://api.github.com/repos/luca-piccioni/OpenGL.Net/issues/58","repository_url":"https://api.github.com/repos/luca-piccioni/OpenGL.Net","labels_url":"https://api.github.com/repos/luca-piccioni/OpenGL.Net/issues/58/labels{/name}","comments_url":"https://api.github.com/repos/luca-piccioni/OpenGL.Net/issues/58/comments","events_url":"https://api.github.com/repos/luca-piccioni/OpenGL.Net/issues/58/events","html_url":"https://github.com/luca-piccioni/OpenGL.Net/issues/58","id":250041985,"number":58,"title":"Encounter NullReferenceException Second Time Gl.Control Window is Opened","user":{"login":"dcb-areva","id":31008249,"avatar_url":"https://avatars3.githubusercontent.com/u/31008249?v=4","gravatar_id":"","url":"https://api.github.com/users/dcb-areva","html_url":"https://github.com/dcb-areva","followers_url":"https://api.github.com/users/dcb-areva/followers","following_url":"https://api.github.com/users/dcb-areva/following{/other_user}","gists_url":"https://api.github.com/users/dcb-areva/gists{/gist_id}","starred_url":"https://api.github.com/users/dcb-areva/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dcb-areva/subscriptions","organizations_url":"https://api.github.com/users/dcb-areva/orgs","repos_url":"https://api.github.com/users/dcb-areva/repos","events_url":"https://api.github.com/users/dcb-areva/events{/privacy}","received_events_url":"https://api.github.com/users/dcb-areva/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":3,"created_at":"2017-08-14T14:08:39Z","updated_at":"2017-08-14T16:56:47Z","closed_at":null,"body":"\r\n\r\nI am using OpenGL.Net to display a video stream using the OpenGL.Net.WinForms GlControl.  When I open the form window the first time everything works great.  However the second time I open the window I get the NullReferenceException shown in the screen capture.  I'm not sure why I am encountering the exception.  Is it a problem in my code (shown) or a bug in OpenGL.Net? Thanks!\r\n\r\n![openglnetnullreferenceexception](https://user-images.githubusercontent.com/31008249/29274642-87e639fe-80d6-11e7-922a-1091c4f3f2b8.png)\r\n\r\n`\r\nusing System;\r\nusing System.Diagnostics;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.Drawing;\r\nusing System.Drawing.Imaging;\r\nusing System.Threading;\r\nusing System.Windows.Forms;\r\nusing System.Runtime.InteropServices;\r\n\r\nusing OpenGL;\r\n\r\n    /// <summary>\r\n    /// Class:\r\n    ///     OpenGLNetWindowWriter : MediaWindow : MediaOutput : MediaAct\r\n    ///\r\n    /// </summary>\r\n    /// <remarks>\r\n    /// Thread Safe: Class executes on multiple threads. Constructor executes on calling application\r\n    ///              thread. A MediaIOThread is created and run from this class.\r\n    ///              See individual methods. \r\n    /// </remarks>\r\n    public class OpenGLNetWindowWriter : MediaWindow\r\n    {\r\n\r\n        //private static double usPerTick = (double)(1000 * 1000) / (double)Stopwatch.Frequency;\r\n\r\n        /// <summary>    \r\n        /// Writes video frames to a window using a SimpleOpenGlControl (Tao OpenGL).\r\n        /// </summary>\r\n        /// <remarks>\r\n        /// Thread Safe: Yes, designed to be called from the main application thread.\r\n        /// </remarks>\r\n        public OpenGLNetWindowWriter()\r\n        {\r\n            MediaActThread = new OpenGLNetWindowWriterMediaIOThread(\"OpenGL.Net Window Writer\", this, ThreadPriority.AboveNormal);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Open the media act (parameters must be set before opening).\r\n        /// </summary>\r\n        /// <Param Name=\"timeTicks\">Open time (in ticks).</Param>\r\n        /// <returns></returns>\r\n        /// <remarks>\r\n        /// Thead Safe - Yes\r\n        /// </remarks>\r\n        internal override void ActOpen(long timeTicks, VideoMedia video, AudioMedia audio, MediaScript.ActionEnum action)\r\n        {\r\n            if (!ActOpened)\r\n            {\r\n                videoSizeRatio = (double)video.VideoSize.Width / (double)video.VideoSize.Height;\r\n                windowSize = new Size(video.VideoSize.Width, video.VideoSize.Height);\r\n                windowLocation = new Point(0, 0);   // #### should be passed in?\r\n\r\n                base.ActOpen(timeTicks, video, audio, action);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Show the window by setting window state to normal (it starts out minimized).\r\n        /// </summary>\r\n        /// <Param Name=\"\"></Param>\r\n        /// <returns></returns>\r\n        /// <remarks>\r\n        /// Thead Safe - Yes, designed to be called from the main application thread.\r\n        /// </remarks>\r\n        private delegate void showDelegate();\r\n        public override void Show()\r\n        {\r\n            OpenGLNetWindowWriterMediaIOThread openGLNetWindowThread = MediaActThread as OpenGLNetWindowWriterMediaIOThread;\r\n            if (openGLNetWindowThread.containerForm.InvokeRequired)\r\n                openGLNetWindowThread.containerForm.BeginInvoke(new showDelegate(SetWindowState));\r\n            else\r\n                SetWindowState();\r\n        }\r\n\r\n        private void SetWindowState()\r\n        {\r\n            OpenGLNetWindowWriterMediaIOThread openGLNetWindowThread = MediaActThread as OpenGLNetWindowWriterMediaIOThread;\r\n            if (openGLNetWindowThread.containerForm != null)\r\n                openGLNetWindowThread.containerForm.WindowState = FormWindowState.Normal;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Set the size of the window, set the video frame size to fit in the window (scale to maintain aspect ratio).\r\n        /// </summary>\r\n        /// <Param Name=\"size\"> New size of window.</Param>\r\n        /// <returns></returns>\r\n        /// <remarks>\r\n        /// Thead Safe - Yes, intended to be called from the main app thread.\r\n        /// </remarks>\r\n        private delegate void setClientSizeDelegate(Size size);\r\n        public override void SetSize(Size size)\r\n        {\r\n            OpenGLNetWindowWriterMediaIOThread openGLNetWindowThread = MediaActThread as OpenGLNetWindowWriterMediaIOThread;\r\n            if (openGLNetWindowThread.containerForm != null)\r\n                if (openGLNetWindowThread.containerForm.InvokeRequired)\r\n                    openGLNetWindowThread.containerForm.BeginInvoke(new setClientSizeDelegate(SetClientSize), size);\r\n                else\r\n                    SetClientSize(size);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Set the size of the window, set the video frame size to fit in the window (scale to maintain aspect ratio).\r\n        /// </summary>\r\n        /// <Param Name=\"size\"> New size of window.</Param>\r\n        /// <returns></returns>\r\n        /// <remarks>\r\n        /// Thead Safe - No, must be called from the thread the media was opened on (i.e. MediaAct thread).\r\n        /// </remarks>\r\n        private void SetClientSize(Size size)\r\n        {\r\n            OpenGLNetWindowWriterMediaIOThread openGLNetWindowThread = MediaActThread as OpenGLNetWindowWriterMediaIOThread;\r\n\r\n            if (openGLNetWindowThread.containerForm != null)\r\n            {\r\n                Size videoSize = size;\r\n                Point videoLocation = new System.Drawing.Point(0, 0);\r\n                windowSize = size;\r\n                openGLNetWindowThread.containerForm.ClientSize = size;\r\n\r\n                // keep video size perportional to captured video size\r\n                double windowSizeRatio = (double)size.Width / (double)size.Height;\r\n                if (windowSizeRatio > videoSizeRatio)\r\n                {\r\n                    videoSize.Width = (int)((double)size.Height * videoSizeRatio);          // scale video size by height\r\n                    videoLocation = new Point((size.Width - videoSize.Width) / 2, 0);       // center video in window\r\n                }\r\n                else if (windowSizeRatio < videoSizeRatio)\r\n                {\r\n                    videoSize.Height = (int)((double)size.Width / videoSizeRatio);          // scale video size by width\r\n                    videoLocation = new Point(0, (size.Height - videoSize.Height) / 2);       // center video in window\r\n                }\r\n\r\n                OpenGL.GlControl openGlControl = openGLNetWindowThread.windowControl as OpenGL.GlControl;\r\n                openGlControl.Size = videoSize;\r\n                openGlControl.Location = videoLocation;\r\n            }\r\n\r\n        }\r\n\r\n        /// <summary>\r\n        /// Set the screen location of the window.\r\n        /// </summary>\r\n        /// <Param Name=\"location\"> New screen location of window.</Param>\r\n        /// <returns></returns>\r\n        /// <remarks>\r\n        /// Thead Safe - Yes, intended to be called from the main application thread.\r\n        /// </remarks>\r\n        private delegate void setClientLocationDelegate(Point location);\r\n        public override void SetLocation(Point location)\r\n        {\r\n            OpenGLNetWindowWriterMediaIOThread openGLNetWindowThread = MediaActThread as OpenGLNetWindowWriterMediaIOThread;\r\n\r\n            if (openGLNetWindowThread.containerForm != null)\r\n                if (openGLNetWindowThread.containerForm.InvokeRequired)\r\n                    openGLNetWindowThread.containerForm.BeginInvoke(new setClientLocationDelegate(SetClientLocation), location);\r\n                else\r\n                    SetClientLocation(location);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Set the screen location of the window.\r\n        /// </summary>\r\n        /// <Param Name=\"location\"> New screen location of window.</Param>\r\n        /// <returns></returns>\r\n        /// <remarks>\r\n        /// Thead Safe - No, must be called from the thread the media was opened on (i.e. MediaAct thread).\r\n        /// </remarks>\r\n        private void SetClientLocation(Point location)\r\n        {\r\n            OpenGLNetWindowWriterMediaIOThread openGLNetWindowThread = MediaActThread as OpenGLNetWindowWriterMediaIOThread;\r\n\r\n            if (openGLNetWindowThread.containerForm != null)\r\n            {\r\n                windowLocation = location;\r\n                openGLNetWindowThread.containerForm.Location = location;\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Set window focus.\r\n        /// </summary>\r\n        /// <Param Name=\"\"></Param>\r\n        /// <returns></returns>\r\n        /// <remarks>\r\n        /// Thead Safe - Yes, intended to be called from the main application thread.\r\n        /// </remarks>\r\n        private delegate void setWindowFocusDelegate();\r\n        public override void SetWindowFocus()\r\n        {\r\n            OpenGLNetWindowWriterMediaIOThread openGLNetWindowThread = MediaActThread as OpenGLNetWindowWriterMediaIOThread;\r\n\r\n            if (openGLNetWindowThread.containerForm != null)\r\n                if (openGLNetWindowThread.containerForm.InvokeRequired)\r\n                    openGLNetWindowThread.containerForm.BeginInvoke(new setWindowFocusDelegate(SetFocus));\r\n                else\r\n                    SetFocus();\r\n        }\r\n\r\n        /// <summary>\r\n        /// Set window focus, bring window to top of z-order.\r\n        /// </summary>\r\n        /// <Param Name=\"\"></Param>\r\n        /// <returns></returns>\r\n        /// <remarks>\r\n        /// Thead Safe - No, must be called from the thread the media was opened on (i.e. MediaAct thread).\r\n        /// </remarks>\r\n        private void SetFocus()\r\n        {\r\n            OpenGLNetWindowWriterMediaIOThread openGLNetWindowThread = MediaActThread as OpenGLNetWindowWriterMediaIOThread;\r\n            //System.Diagnostics.Debug.WriteLine(\"2) openGLNetWindowThread.SetFocus() \" + openGLNetWindowThread.containerForm.WindowState.ToString());\r\n            if (openGLNetWindowThread.containerForm != null)\r\n            {\r\n                openGLNetWindowThread.containerForm.TopMost = true;\r\n                openGLNetWindowThread.containerForm.Refresh();\r\n                openGLNetWindowThread.containerForm.TopMost = false;\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///     Class:      OpenGLNetWindowWriterMediaIOThread : MediaIOThread : MediaThread\r\n        ///     \r\n        ///     \r\n        ///     \r\n        ///     \r\n        /// </summary>\r\n\r\n        internal class OpenGLNetWindowWriterMediaIOThread : MediaIOThread, IDisposable\r\n        {\r\n            public Control windowControl;\r\n            public Form containerForm;\r\n            private DeviceContext deviceContext;\r\n            private IntPtr renderContext;\r\n            private bool disposed = false;\r\n            private bool delayedStorageCleanup = false;\r\n\r\n            public OpenGLNetWindowWriterMediaIOThread(string threadName, MediaAct parent, ThreadPriority priority)\r\n                : base(threadName, parent, priority)\r\n            {\r\n                containerForm = null;\r\n                windowControl = null;\r\n                deviceContext = null;\r\n                renderContext = IntPtr.Zero;\r\n            }\r\n\r\n            protected virtual void Dispose(bool disposing)\r\n            {\r\n                if (disposed)\r\n                    return;\r\n\r\n                if (disposing)\r\n                {\r\n                    // dispose managed resources\r\n                    StopProcessing();\r\n                }\r\n                disposed = true;\r\n            }\r\n\r\n            public void Dispose()\r\n            {\r\n                Dispose(true);\r\n                GC.SuppressFinalize(this);\r\n            }\r\n\r\n            /// <summary>\r\n            /// Windows message loop thread.\r\n            /// </summary>\r\n            /// <Param Name=\"\"></Param>\r\n            /// <returns>This method does not return until the Media is closed (Windows form is closed).</returns>\r\n            /// <remarks>\r\n            /// Thead Safe - No, designed to be called from the MediaAct thread.\r\n            /// </remarks>\r\n            protected void WindowsMessageLoop()\r\n            {\r\n                StartProcessing();\r\n            }\r\n\r\n            /// <summary>\r\n            /// Open MediaAct media, create windows form, OpenGL.Net windows control, and start Windows message loop thread.\r\n            /// </summary>\r\n            /// <Param Name=\"\"></Param>\r\n            /// <returns>This method does not return until the Media is closed (Windows form is closed).</returns>\r\n            /// <remarks>\r\n            /// Thead Safe - No, designed to be called from the MediaAct thread.\r\n            /// </remarks>\r\n            protected override bool StartProcessing()\r\n            {\r\n                bool success = false;\r\n\r\n                try\r\n                {\r\n                    OpenGLNetWindowWriter OpenGLNetWindowWriter = ParentMediaAct as OpenGLNetWindowWriter;\r\n\r\n                    Application.EnableVisualStyles();\r\n                    containerForm = new Form();                     // create form as a container for the Open Gl Window\r\n\r\n                    containerForm.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;\r\n                    containerForm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;\r\n                    containerForm.ControlBox = false;\r\n                    containerForm.StartPosition = System.Windows.Forms.FormStartPosition.Manual;\r\n                    containerForm.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;\r\n                    containerForm.Margin = new System.Windows.Forms.Padding(0);\r\n                    containerForm.ShowIcon = false;\r\n                    containerForm.ShowInTaskbar = false;\r\n                    containerForm.ClientSize = OpenGLNetWindowWriter.windowSize;\r\n                    containerForm.Location = OpenGLNetWindowWriter.windowLocation;\r\n                    containerForm.AutoScaleMode = AutoScaleMode.None;\r\n                    containerForm.Cursor = Cursors.Default;\r\n                    containerForm.WindowState = FormWindowState.Minimized;\r\n                    containerForm.Load += new EventHandler(containerForm_Load);\r\n\r\n                    // start a windows message loop \r\n                    Application.Run(containerForm);\r\n\r\n                    // Windows message loop does NOT exit until the form is closed\r\n\r\n                    success = true;\r\n                }\r\n                catch (System.Exception e)\r\n                {\r\n                    System.Diagnostics.Debug.WriteLine(\"OpenGLNetWindowWriter :\" + e.ToString());\r\n                }\r\n\r\n                return success;\r\n            }\r\n\r\n            /// <summary>\r\n            /// Form load event of the MediaAct thread, used to send MediaAct initialized event.\r\n            /// </summary>\r\n            /// <Param Name=\"\"></Param>\r\n            /// <returns></returns>\r\n            /// <remarks>\r\n            /// Thead Safe - No, must be called from the thread the media was opened on (i.e. MediaAct thread).\r\n            /// </remarks>\r\n            protected void containerForm_Load(object sender, EventArgs e)\r\n            {\r\n                OpenGLNetWindowWriter OpenGLNetWindowWriter = ParentMediaAct as OpenGLNetWindowWriter;\r\n\r\n                windowControl = new OpenGL.GlControl();\r\n                OpenGL.GlControl openGlControl = windowControl as OpenGL.GlControl;\r\n                openGlControl.BackColor = System.Drawing.Color.Black;\r\n                openGlControl.Location = new System.Drawing.Point(0, 0);\r\n                openGlControl.Name = \"MediaWindowWriter\";\r\n                openGlControl.Size = new Size(OpenGLNetWindowWriter.windowSize.Width, OpenGLNetWindowWriter.windowSize.Height);\r\n                openGlControl.AutoScaleMode = AutoScaleMode.None;\r\n                openGlControl.BorderStyle = BorderStyle.None;\r\n                openGlControl.TabStop = false;\r\n                //openGlControl.MouseDown += new System.Windows.Forms.MouseEventHandler(openGlControl_MouseDown);\r\n                //openGlControl.MouseMove += new System.Windows.Forms.MouseEventHandler(openGlControl_MouseMove);\r\n                //openGlControl.MouseUp += new System.Windows.Forms.MouseEventHandler(openGlControl_MouseUp);\r\n                //openGlControl.MouseLeave += new System.EventHandler(openGlControl_MouseLeave);\r\n                openGlControl.MouseClick += new System.Windows.Forms.MouseEventHandler(openGlControl_MouseClick);\r\n                openGlControl.MouseWheel += new System.Windows.Forms.MouseEventHandler(openGlControl_MouseWheel);\r\n                openGlControl.ContextCreated += new EventHandler<GlControlEventArgs>(containerForm_ContextCreated);\r\n\r\n                containerForm.Controls.Add(openGlControl);\r\n\r\n                OpenGLNetWindowWriter.ActOpened = true;\r\n                OpenGLNetWindowWriter.SendOpenedEvent();\r\n            }\r\n\r\n            /// <summary>\r\n            /// OpenGL context created event of the MediaAct thread.\r\n            /// </summary>\r\n            /// <Param Name=\"\"></Param>\r\n            /// <returns></returns>\r\n            /// <remarks>\r\n            /// Thead Safe - No, must be called from the thread the media was opened on (i.e. MediaAct thread).\r\n            /// </remarks>\r\n            protected void containerForm_ContextCreated(object sender, GlControlEventArgs e)\r\n            {\r\n                deviceContext = e.DeviceContext;\r\n                renderContext = e.RenderContext;\r\n                System.Diagnostics.Debug.WriteLine(\"Context created\");\r\n            }\r\n\r\n            /// <summary>\r\n            /// OpenGL.Net control mouse click event, send event (back to main application).\r\n            /// </summary>\r\n            /// <Param Name=\"\"></Param>\r\n            /// <returns></returns>\r\n            /// <remarks>\r\n            /// Thead Safe - Yes\r\n            /// </remarks>\r\n            private void openGlControl_MouseClick(object sender, MouseEventArgs e)\r\n            {\r\n                //System.Diagnostics.Debug.WriteLine(\"openGTKControl_MouseClick()\");\r\n                OpenGLNetWindowWriter OpenGLNetWindowWriter = ParentMediaAct as OpenGLNetWindowWriter;\r\n                OpenGLNetWindowWriter.SendWindowMouseClickEvent(e);\r\n            }\r\n\r\n            /// <summary>\r\n            /// OpenGL.Net control mouse wheel event, send event (back to main application).\r\n            /// </summary>\r\n            /// <Param Name=\"\"></Param>\r\n            /// <returns></returns>\r\n            /// <remarks>\r\n            /// Thead Safe - No, must be called from the thread the media was opened on (i.e. MediaAct thread).\r\n            /// </remarks>\r\n            private void openGlControl_MouseWheel(object sender, MouseEventArgs e)\r\n            {\r\n                //System.Diagnostics.Debug.WriteLine(\"openGlControl_MouseWheel()\");\r\n                OpenGLNetWindowWriter OpenGLNetWindowWriter = ParentMediaAct as OpenGLNetWindowWriter;\r\n                OpenGLNetWindowWriter.SendWindowMouseWheelEvent(e);\r\n            }\r\n\r\n            /// <summary>\r\n            /// CloseMedia\r\n            /// </summary>\r\n            /// <Param Name=\"\"></Param>\r\n            /// <returns></returns>\r\n            /// <remarks>\r\n            /// Thead Safe - No, must be called from the thread the media was opened on (i.e. MediaAct thread). Use\r\n            ///              CloseMediaDelegate() with BeginInvoke() from other threads.\r\n            /// </remarks>\r\n            protected delegate bool CloseMediaDelegate();\r\n            protected override bool StopProcessing()\r\n            {\r\n                bool success = false;\r\n\r\n                try\r\n                {\r\n                    if (containerForm != null)\r\n                    {\r\n                        containerForm.Close();\r\n                        OpenGL.GlControl openGlControl = windowControl as OpenGL.GlControl;\r\n                        openGlControl.Dispose();\r\n                        containerForm = null;\r\n                        deviceContext = null;\r\n                        renderContext = IntPtr.Zero;\r\n                    }\r\n                    success = true;\r\n                }\r\n                catch (System.Exception e)\r\n                {\r\n                    System.Diagnostics.Debug.WriteLine(\"OpenGLNetWindowWriter.CloseMedia(): \" + e.ToString());\r\n                }\r\n\r\n                return success;\r\n            }\r\n\r\n            /// <summary>\r\n            /// Handle MediaThread events (thread loop).\r\n            /// </summary>\r\n            /// <returns></returns>\r\n            /// <remarks>\r\n            /// Thead Safe - Yes\r\n            /// </remarks>\r\n            protected override void HandleEvents()\r\n            {\r\n                bool started = true;\r\n                ThreadEventsList newEventIndex;\r\n                MediaFrameEventInfo newFrameInfo = null;\r\n                VideoFrame lastOtherFrame = null;\r\n                OpenGLNetWindowWriter OpenGLNetWindowWriter = ParentMediaAct as OpenGLNetWindowWriter;\r\n\r\n                // tell anyone who is listening - initialization is complete\r\n                SendInitializedEvent();\r\n\r\n                while (started)\r\n                {\r\n                    try\r\n                    {\r\n                        newEventIndex = (ThreadEventsList)WaitHandle.WaitAny(ThreadEvents);     // ##### need a timeout here ??\r\n                        switch (newEventIndex)\r\n                        {\r\n                            case ThreadEventsList.StartProcessing:\r\n\r\n                                // start windows form message loop\r\n                                Thread windowsThread = new Thread(new ThreadStart(WindowsMessageLoop));\r\n                                windowsThread.Name = \"OpenGL.Net Window Writer MessageLoop\";\r\n                                windowsThread.Start();                                          // #### should add an error event to handle errors in this thread\r\n\r\n                                break;\r\n\r\n                            case ThreadEventsList.StopProcessing:\r\n                                if (OpenGLNetWindowWriter.ActOpened)\r\n                                {\r\n                                    if (containerForm != null)\r\n                                        containerForm.BeginInvoke(new CloseMediaDelegate(StopProcessing));\r\n                                    OpenGLNetWindowWriter.ActOpened = false;\r\n                                    OpenGLNetWindowWriter.SendClosedEvent();\r\n                                }\r\n                                break;\r\n\r\n                            case ThreadEventsList.Shutdown:\r\n                                if (OpenGLNetWindowWriter.ActOpened)\r\n                                {\r\n                                    if (containerForm != null)\r\n                                        containerForm.BeginInvoke(new CloseMediaDelegate(StopProcessing));\r\n                                    OpenGLNetWindowWriter.ActOpened = false;\r\n                                    OpenGLNetWindowWriter.SendClosedEvent();\r\n                                }\r\n                                started = false;\r\n                                break;\r\n\r\n                            case ThreadEventsList.Frame:\r\n                                int frameEventQueueCount = 0;\r\n                                lock (FrameEventQueue.SyncRoot)\r\n                                    frameEventQueueCount = FrameEventQueue.Count;\r\n\r\n                                while (frameEventQueueCount > 0)\r\n                                {\r\n                                    lock (FrameEventQueue.SyncRoot)\r\n                                    {\r\n                                        newFrameInfo = (MediaFrameEventInfo)FrameEventQueue.Dequeue();\r\n                                        frameEventQueueCount = FrameEventQueue.Count;\r\n                                    }\r\n                                    MediaScript.ActionEnum action = OpenGLNetWindowWriter.ActAction;\r\n\r\n                                    if ((OpenGLNetWindowWriter.ActOpened) && (newFrameInfo != null) && (newFrameInfo.Frame != null))\r\n                                    {\r\n                                        // see if the frame is a video frame\r\n                                        VideoFrame videoFrame = newFrameInfo.Frame as VideoFrame;\r\n\r\n                                        if (videoFrame != null)\r\n                                        {\r\n\r\n\r\n                                            MediaScript.ActionEnum otherDisplay = (action == MediaScript.ActionEnum.Display1) ? MediaScript.ActionEnum.Display2 : MediaScript.ActionEnum.Display1;\r\n\r\n                                            // Frame source and display match (Source1 and Display1 OR Source2 and Display2)\r\n                                            bool frameSourceDisplayMatch = ((videoFrame.Source == MediaScript.ActionEnum.Source1) && (action == MediaScript.ActionEnum.Display1))\r\n                                                                                                                                  ||\r\n                                                                           ((videoFrame.Source == MediaScript.ActionEnum.Source2) && (action == MediaScript.ActionEnum.Display2));\r\n\r\n                                            //Debug.WriteLine(\"WindowWriter Action \" + action.ToString() + \" VideoFrame \" + videoFrame.Source.ToString() + \" FrameNumber \" +\r\n                                            //                videoFrame.FrameNumber.ToString() + \" DisplayMatch \" + frameSourceDisplayMatch.ToString());\r\n\r\n                                            // is swap displays enabled?\r\n                                            if (videoFrame.SwapSource && videoFrame.Script.Is(action, MediaScript.ActionStateEnum.Active) &&\r\n                                                videoFrame.Script.Is(otherDisplay, MediaScript.ActionStateEnum.Active))\r\n                                            {\r\n                                                if (!frameSourceDisplayMatch)\r\n                                                    lastOtherFrame = videoFrame;\r\n                                                else if (lastOtherFrame != null)\r\n                                                    videoFrame = lastOtherFrame;\r\n                                            }\r\n                                            else if (!frameSourceDisplayMatch)\r\n                                                lastOtherFrame = null;\r\n\r\n                                            if (videoFrame.Script.Is(action, MediaScript.ActionStateEnum.Active) && frameSourceDisplayMatch)\r\n                                            {\r\n                                                // write overlay\r\n\r\n                                                //string frameTime = ((double)videoFrame.FrameCaptureTimeTicks / (double)Stopwatch.Frequency).ToString(\"0000.000 \");\r\n                                                //Debug.WriteLine(frameTime + action.ToString() + \" \" + videoFrame.Source.ToString() + \" write overlay\r\n                                                if (videoFrame.DataLock.TryEnterReadLock(videoFrame.DataLockTimeout))\r\n                                                {\r\n                                                    // write overlay to display bitmap (only for exam display)\r\n                                                    if (videoFrame.Overlay != null)\r\n                                                    {\r\n                                                        // draw on the frame bitmap - might want to use a copy here?\r\n                                                        videoFrame.Overlay.Draw(videoFrame.VideoBitmap.RGBBitmap,\r\n                                                            OpenGLNetWindowWriter.ShowSubtitles, OpenGLNetWindowWriter.ShowGraphic);\r\n                                                        if (videoFrame.FilteredVideoBitmap != null)\r\n                                                            videoFrame.Overlay.Draw(videoFrame.FilteredVideoBitmap.RGBBitmap,\r\n                                                                OpenGLNetWindowWriter.ShowSubtitles, OpenGLNetWindowWriter.ShowGraphic);\r\n                                                    }\r\n                                                    videoFrame.DataLock.ExitReadLock();\r\n                                                }\r\n\r\n                                                WriteFrame(videoFrame, OpenGLNetWindowWriter.Video);\r\n\r\n                                                // capture image requested ?\r\n                                                if (Interlocked.CompareExchange(ref OpenGLNetWindowWriter.CaptureImageFlag, 0, 1) == 1)\r\n                                                    CaptureImage(videoFrame);\r\n\r\n                                                if (videoFrame.DataLock.TryEnterWriteLock(videoFrame.DataLockTimeout))\r\n                                                {\r\n                                                    // Return video storage to global pool.\r\n                                                    if (!delayedStorageCleanup)\r\n                                                    {\r\n                                                        videoFrame.ReturnVideoStorage();\r\n                                                        videoFrame.ReturnFilteredVideoStorage();\r\n                                                    }\r\n                                                    videoFrame.DataLock.ExitWriteLock();\r\n                                                }\r\n                                            }\r\n                                        }\r\n\r\n                                        // send audio frame event (i.e. used to display audio level)\r\n                                        AudioFrame audioFrame = newFrameInfo.Frame as AudioFrame;\r\n                                        if (audioFrame != null)\r\n                                        {\r\n                                            if (audioFrame.Script.Is(action, MediaScript.ActionStateEnum.Active))\r\n                                            {\r\n                                                OpenGLNetWindowWriter.SendAudioFrameEvent(new MediaFrameEventInfo(newFrameInfo.Frame));\r\n                                            }\r\n                                        }\r\n                                    }\r\n\r\n                                    if ((newFrameInfo != null) && (newFrameInfo.Frame != null))\r\n                                        OpenGLNetWindowWriter.SendFrameEvent(new MediaFrameEventInfo(newFrameInfo.Frame));\r\n                                }\r\n                                break;\r\n                        }\r\n                    }\r\n                    catch (Exception e)\r\n                    {\r\n                        System.Diagnostics.Debug.WriteLine(\"OpenGLNetWindowWriterMediaIOThread.HandleEvents: \" + e.ToString());\r\n                    }\r\n                }\r\n            }\r\n\r\n            /// <summary>\r\n            /// Writes video frame to the openGl window.\r\n            /// </summary>\r\n            /// <Param Name=\"frame\">Video frame to be written.</Param>\r\n            /// <Param Name=\"options\">Video frame options for writing.</Param>\r\n            /// <returns>true - if no error</returns>\r\n            /// <remarks>\r\n            /// Thead Safe - Yes, intended to be called from the MediaAct thread.\r\n            /// </remarks>\r\n            private bool WriteFrame(VideoFrame frame, VideoMedia options)\r\n            {\r\n                bool result = false;\r\n                delayedStorageCleanup = false;\r\n\r\n                if (windowControl != null)\r\n                {\r\n                    try\r\n                    {\r\n                        if (windowControl.InvokeRequired)\r\n                        {\r\n                            delayedStorageCleanup = true;\r\n                            windowControl.BeginInvoke(new OpenGLNetWindowWriterMediaIOThread.RenderWindowDelegate(Render), frame, options);\r\n                        }\r\n                        else\r\n                            Render(frame, options);\r\n                        result = true;\r\n                    }\r\n                    catch (System.Exception e)\r\n                    {\r\n                        System.Diagnostics.Debug.WriteLine(\"OpenGLNetWindowWriterMediaIOThread.WriteFrame: \" + e.ToString());\r\n                    }\r\n                }\r\n\r\n                return result;\r\n            }\r\n\r\n            /// <summary>\r\n            /// Renders video frame to the openGl window.\r\n            /// </summary>\r\n            /// <Param Name=\"frame\">Video frame to be rendered.</Param>\r\n            /// <Param Name=\"options\">Video frame options for rendering.</Param>\r\n            /// <returns></returns>\r\n            /// <remarks>\r\n            /// Thead Safe - No, must be called from the thread the media was opened on (i.e. MediaAct thread).\r\n            /// </remarks>\r\n            public delegate void RenderWindowDelegate(VideoFrame frame, VideoMedia options);\r\n            public void Render(VideoFrame frame, VideoMedia options)\r\n            {\r\n                RGBStorage videoBitmap;\r\n                BitmapData bmData;\r\n                bool locked = false;\r\n\r\n                if (frame != null)\r\n                {\r\n                    try\r\n                    {\r\n                        frame.FrameDisplayTimeTicks = DateTime.UtcNow.Ticks - frame.FrameCaptureTimeTicks;\r\n\r\n                        OpenGL.GlControl openGlControl = windowControl as OpenGL.GlControl;\r\n                        if (openGlControl != null && deviceContext != null)\r\n                        {\r\n                            deviceContext.MakeCurrent(renderContext);\r\n                            Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);\r\n\r\n                            //Debug.WriteLine(\"OpenGlWriter.Render TryEnterReadLock Frame\");\r\n                            if (frame.DataLock.TryEnterReadLock(frame.DataLockTimeout))\r\n                            {\r\n                                locked = true;\r\n\r\n                                videoBitmap = frame.VideoBitmap;\r\n                                //videoBitmap = videoFrame.FilteredVideoBitmap;\r\n                                if (videoBitmap != null)\r\n                                {\r\n                                    //System.Diagnostics.Debug.WriteLine(\"Rendering\");\r\n                                    if (options.Stereo == VideoMedia.VideoStereoEnum.TopRightBottomLeft)\r\n                                    {\r\n                                        Gl.PixelZoom((float)openGlControl.Width / (float)videoBitmap.Width, (float)openGlControl.Height / ((float)videoBitmap.Height) / 2F);\r\n                                        Gl.DrawBuffer(DrawBufferMode.BackLeft);\r\n                                        bmData = videoBitmap.RGBBitmap.LockBits(new Rectangle(0, 0, (int)videoBitmap.Width, (int)videoBitmap.Height / 2),\r\n                                            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);\r\n                                        Gl.DrawPixels((int)videoBitmap.Width, (int)videoBitmap.Height, OpenGL.PixelFormat.Bgr, OpenGL.PixelType.UnsignedByte, bmData.Scan0);\r\n                                        videoBitmap.RGBBitmap.UnlockBits(bmData);\r\n\r\n                                        Gl.DrawBuffer(DrawBufferMode.BackRight);\r\n                                        bmData = videoBitmap.RGBBitmap.LockBits(new Rectangle(0, (int)videoBitmap.Height, (int)videoBitmap.Width, (int)videoBitmap.Height),\r\n                                            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);\r\n                                        Gl.DrawPixels((int)videoBitmap.Width, (int)videoBitmap.Height, OpenGL.PixelFormat.Bgr, OpenGL.PixelType.UnsignedByte, bmData.Scan0);\r\n                                        videoBitmap.RGBBitmap.UnlockBits(bmData);\r\n                                    }\r\n                                    else if (options.Stereo == VideoMedia.VideoStereoEnum.RightLeft)\r\n                                    {\r\n                                        Gl.PixelZoom((float)openGlControl.Width / ((float)videoBitmap.Width) / 2F, (float)openGlControl.Height / (float)videoBitmap.Height);\r\n                                        Gl.DrawBuffer(DrawBufferMode.BackRight);\r\n                                        bmData = videoBitmap.RGBBitmap.LockBits(new Rectangle(0, 0, (int)videoBitmap.Width / 2, (int)videoBitmap.Height),\r\n                                            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);\r\n                                        Gl.DrawPixels((int)videoBitmap.Width, (int)videoBitmap.Height, OpenGL.PixelFormat.Bgr, OpenGL.PixelType.UnsignedByte, bmData.Scan0);\r\n                                        videoBitmap.RGBBitmap.UnlockBits(bmData);\r\n\r\n                                        Gl.DrawBuffer(DrawBufferMode.BackLeft);\r\n                                        bmData = videoBitmap.RGBBitmap.LockBits(new Rectangle((int)videoBitmap.Width / 2, 0, (int)videoBitmap.Width / 2, (int)videoBitmap.Height),\r\n                                            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);\r\n                                        Gl.DrawPixels((int)videoBitmap.Width, (int)videoBitmap.Height, OpenGL.PixelFormat.Bgr, OpenGL.PixelType.UnsignedByte, bmData.Scan0);\r\n                                        videoBitmap.RGBBitmap.UnlockBits(bmData);\r\n                                    }\r\n                                    else // default to mono (no Stereo)\r\n                                    {\r\n                                        Gl.PixelZoom((float)openGlControl.Width / (float)videoBitmap.Width, (float)openGlControl.Height / (float)videoBitmap.Height);\r\n                                        bmData = videoBitmap.RGBBitmap.LockBits(new Rectangle(0, 0, (int)videoBitmap.Width, (int)videoBitmap.Height),\r\n                                            ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);\r\n                                        Gl.DrawBuffer(DrawBufferMode.BackLeft);\r\n                                        Gl.DrawPixels((int)videoBitmap.Width, (int)videoBitmap.Height, OpenGL.PixelFormat.Bgr, OpenGL.PixelType.UnsignedByte, bmData.Scan0);\r\n                                        videoBitmap.RGBBitmap.UnlockBits(bmData);\r\n                                    }\r\n\r\n                                }\r\n\r\n                                // Return video storage to global pool.\r\n                                if (delayedStorageCleanup)\r\n                                {\r\n                                    frame.ReturnVideoStorage();\r\n                                    frame.ReturnFilteredVideoStorage();\r\n                                }\r\n\r\n                                frame.DataLock.ExitReadLock();\r\n                                locked = false;\r\n\r\n                                Gl.Flush();\r\n                                deviceContext.SwapBuffers();\r\n                            }\r\n                            else\r\n                                throw (new Exception(\"OpenGLNetWindowWriter.Render(): Lock Timeout\"));\r\n\r\n                            frame.FrameDisplayCompleteTimeTicks = DateTime.UtcNow.Ticks - frame.FrameCaptureTimeTicks;\r\n                        }\r\n                    }\r\n                    catch (System.Exception e)\r\n                    {\r\n                        System.Diagnostics.Debug.WriteLine(\"OpenGLNetWindowWriter.Render(): \" + e.ToString());\r\n                    }\r\n                    finally\r\n                    {\r\n                        if (locked)\r\n                        {\r\n                            //Debug.WriteLine(\"OpenGlWriter.Render TryEnterReadLock Frame ENTER finally\");\r\n                            frame.DataLock.ExitReadLock();\r\n                        }\r\n                    }\r\n\r\n                }\r\n            }\r\n\r\n            /// <summary>\r\n            /// Capture image from video frame and send the capture image event.\r\n            /// </summary>\r\n            /// <Param Name=\"frame\">Current media video frame.</Param>\r\n            /// <returns>true - if no error</returns>\r\n            /// <remarks>\r\n            /// Thead Safe - Yes, intended to be called from the MediaAct thread.\r\n            /// </remarks>\r\n            private bool CaptureImage(VideoFrame videoFrame)\r\n            {\r\n                bool result = false;\r\n                bool locked = false;\r\n                MediaImage newImage = null;\r\n                OpenGLNetWindowWriter openGlWindowWriter = ParentMediaAct as OpenGLNetWindowWriter;\r\n\r\n                try\r\n                {\r\n                    if ((videoFrame != null) && (videoFrame.DataLock.TryEnterWriteLock(videoFrame.DataLockTimeout)))\r\n                    {\r\n                        locked = true;\r\n                        newImage = new MediaImage();\r\n                        newImage.ImageBitmap = (Bitmap)videoFrame.VideoBitmap.RGBBitmap.Clone();\r\n                        if (videoFrame.RawVideoBitmap != null)\r\n                            newImage.RawImageBitmap = (Bitmap)videoFrame.RawVideoBitmap.RGBBitmap.Clone();\r\n                        if (videoFrame.FilteredVideoBitmap != null)\r\n                            newImage.FilteredImageBitmap = (Bitmap)videoFrame.FilteredVideoBitmap.RGBBitmap.Clone();\r\n\r\n                    }\r\n                }\r\n                catch (Exception e)\r\n                {\r\n                    newImage = null;\r\n                    System.Diagnostics.Debug.WriteLine(\"openGlWindowWriterMediaThreadIO.CaptureImage(): \" + e.ToString());\r\n                }\r\n                finally\r\n                {\r\n                    if (locked)\r\n                        videoFrame.DataLock.ExitWriteLock();\r\n                }\r\n\r\n                // post image captured event to anyone who is listening\r\n                if (newImage != null)\r\n                {\r\n                    // images need to be flipped (display needs them one way and file needs them another)\r\n\r\n                    if (newImage.ImageBitmap != null)\r\n                        newImage.ImageBitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);\r\n                    if (newImage.RawImageBitmap != null)\r\n                        newImage.RawImageBitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);\r\n                    if (newImage.FilteredImageBitmap != null)\r\n                        newImage.FilteredImageBitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);\r\n\r\n                    openGlWindowWriter.SendImageEvent(new MediaImageEventInfo(videoFrame.Source, newImage));\r\n                }\r\n\r\n                return result;\r\n            }\r\n        }\r\n    }\r\n\r\n`\r\n"},"comment":{"url":"https://api.github.com/repos/luca-piccioni/OpenGL.Net/issues/comments/322245963","html_url":"https://github.com/luca-piccioni/OpenGL.Net/issues/58#issuecomment-322245963","issue_url":"https://api.github.com/repos/luca-piccioni/OpenGL.Net/issues/58","id":322245963,"user":{"login":"dcb-areva","id":31008249,"avatar_url":"https://avatars3.githubusercontent.com/u/31008249?v=4","gravatar_id":"","url":"https://api.github.com/users/dcb-areva","html_url":"https://github.com/dcb-areva","followers_url":"https://api.github.com/users/dcb-areva/followers","following_url":"https://api.github.com/users/dcb-areva/following{/other_user}","gists_url":"https://api.github.com/users/dcb-areva/gists{/gist_id}","starred_url":"https://api.github.com/users/dcb-areva/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dcb-areva/subscriptions","organizations_url":"https://api.github.com/users/dcb-areva/orgs","repos_url":"https://api.github.com/users/dcb-areva/repos","events_url":"https://api.github.com/users/dcb-areva/events{/privacy}","received_events_url":"https://api.github.com/users/dcb-areva/received_events","type":"User","site_admin":false},"created_at":"2017-08-14T16:56:47Z","updated_at":"2017-08-14T16:56:47Z","body":"I already tried calling Gl.BindApi() before creating the GlControl.  I still get the same exception.  In this case the first time the window is opened since I have to call Gl.Initialize() first in order to get the KhronosVersion and Extensions objects.  That appears to be the key to solving the issue.  I don’t understand why the OpenGL bindings are not available after calling Gl.Initialize() since Gl.Initialize() is called automatically without setting the OPENGL_NET_INIT env variable to NO.\r\n\r\nFrom: Luca Piccioni [mailto:notifications@github.com]\r\nSent: Monday, August 14, 2017 12:38 PM\r\nTo: luca-piccioni/OpenGL.Net\r\nCc: BIGLER Don (IB); Author\r\nSubject: Re: [luca-piccioni/OpenGL.Net] Encounter NullReferenceException Second Time Gl.Control Window is Opened (#58)\r\n\r\n\r\nThere's a Gl.BindAPI() method that loads function pointers based on the context current on the calling thread. Call it before creation the new window.\r\n\r\nBut it shouldn't necessary, since this is called automatically the GlControl at handle creation time. I suspect there is something wrong elsewhere.\r\n\r\n—\r\nYou are receiving this because you authored the thread.\r\nReply to this email directly, view it on GitHub<https://github.com/luca-piccioni/OpenGL.Net/issues/58#issuecomment-322241207>, or mute the thread<https://github.com/notifications/unsubscribe-auth/Adkl-YxVEBOA7a9il7-Xmbe8XdogeBbcks5sYHf_gaJpZM4O2apX>.\r\n"}}
{"actor":{"display_login":"dcb-areva"}}