/// <summary>
            /// This acquires a new CameraFrame from the pool and copies the pixel data through the internal IBuffer.
            /// </summary>
            /// <param name="bmpFrame">The software bitmap from the camera</param>
            /// <returns>The camera frame (with the pixel data copied already)</returns>
            public CameraFrameInternal AcquireFrame(SoftwareBitmap bmpFrame, PixelFormat desiredPixelFormat)
            {
                lock (frameLock)
                {
                    CameraFrameInternal frame = null;

                    // convert the data format and get the data size -
                    PixelFormat pixelFormat = PixelHelpers.ConvertFormat(bmpFrame.BitmapPixelFormat);
                    if (pixelFormat != desiredPixelFormat)
                    {
                        BitmapPixelFormat bitmapPixelFormat = PixelHelpers.ConvertFormat(desiredPixelFormat);
                        bmpFrame = SoftwareBitmap.Convert(bmpFrame, PixelHelpers.ConvertFormat(desiredPixelFormat));
                    }

                    int dataSize = PixelHelpers.GetDataSize(bmpFrame.PixelWidth, bmpFrame.PixelHeight, desiredPixelFormat);

                    if (freeCameraFrames.Count > 0)
                    {
                        // find a frame with the required size buffer
                        for (LinkedListNode <CameraFrameInternal> node = freeCameraFrames.First; node != null; node = node.Next)
                        {
                            // check if the pixel data array is the correct length
                            if (node.Value != null && node.Value?.PixelData?.Length == dataSize)
                            {
                                // remove the frame from the free list
                                freeCameraFrames.Remove(node);

                                // add the frame to the used list (need to create a new node)
                                frame = node.Value;
                                usedCameraFrames.AddFirst(frame);
                            }
                        }
                    }

                    // if there were no free frames, create a new one
                    if (frame == null)
                    {
                        frame                 = new CameraFrameInternal(this);
                        frame.PixelData       = new byte[dataSize];
                        frame.PixelDataBuffer = frame.PixelData.AsBuffer();

                        // add the new frame to the used camera frames list
                        usedCameraFrames.AddFirst(frame);
                    }

                    // copy the pixel data to the frame through the internal IBuffer
                    bmpFrame.CopyToBuffer(frame.PixelDataBuffer);

                    return(frame);
                }
            }
        private void OnMediaFrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
        {
            bool getFrame = false;

            lock (stateLock)
            {
                getFrame = (State == CameraState.CapturingContinuous || State == CameraState.CapturingSingle);

                // quickly handle state changes here (only changes if we're capturing a single image)
                if (State == CameraState.CapturingSingle)
                {
                    State = CameraState.Ready;
                }
            }

            CameraFrameInternal frame = null;

            if (getFrame)
            {
                frame = GetFrameFromMediaFrameReader(sender);
            }

            if (frame != null)
            {
                // clean up state after frame
                if (CaptureMode == CaptureMode.SingleLowLatency)
                {
                    // release previous frame and addref current frame
                    if (latestFrame != null)
                    {
                        latestFrame.Release();
                    }

                    // add ref for the camera
                    frame.AddRef();
                    latestFrame = frame;
                }

                // callback any registered listeners
                OnFrameCaptured?.Invoke(this, frame);
            }
        }
            public void ReleaseFrame(CameraFrameInternal frame)
            {
                lock (frameLock)
                {
                    // remove the frame from the used list and add to the free list
                    if (frame != null)
                    {
                        LinkedListNode <CameraFrameInternal> frameNode = usedCameraFrames.Find(frame);

                        // if the frame was found, add to the free pile and remove from the used list
                        if (frameNode != null)
                        {
                            // need to create a new node as nodes don't swap between linked lists
                            freeCameraFrames.AddFirst(frameNode.Value);

                            // remove from the current list
                            usedCameraFrames.Remove(frameNode);
                        }
                    }
                }
            }
        private CameraFrameInternal GetFrameFromMediaFrameReader(MediaFrameReader frameReader)
        {
            // get the latest frame
            MediaFrameReference frameReference = frameReader?.TryAcquireLatestFrame();
            VideoMediaFrame     videoFrame     = frameReference?.VideoMediaFrame;
            SoftwareBitmap      frameBmp       = videoFrame?.SoftwareBitmap;

            CameraFrameInternal frame = null;

            if (frameBmp != null)
            {
                // get a camera frame and populate with the correct data for this frame - acquire copies the bitmap to the frame
                frame             = framePool.AcquireFrame(frameBmp, desiredPixelFormat);
                frame.PixelFormat = desiredPixelFormat;
                frame.Resolution  = Resolution;
                frame.FrameTime   = frameReference.SystemRelativeTime.HasValue ? frameReference.SystemRelativeTime.Value.TotalSeconds : 0.0;
                frame.Exposure    = frameReference.Duration.TotalSeconds;
                frame.Gain        = Gain;

                if (KeepSoftwareBitmap)
                {
                    frame.SoftwareBitmap = frameBmp;
                }
                else
                {
                    frameBmp.Dispose();
                }

                // extrinsics and intrinsics
                frame.Extrinsics = GetExtrinsics(frameReference.CoordinateSystem);
                frame.Intrinsics = ConvertIntrinsics(frameReference.VideoMediaFrame.CameraIntrinsics);
            }

            frameReference?.Dispose();

            return(frame);
        }