Example #1
0
        /// <summary>
        /// Disposes the resources held by the image.
        /// </summary>
        /// <param name="disposing"><c>True</c> to release both managed and unmanaged resources; <c>False</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposedValue)
            {
                lock (this)
                {
                    if (disposing)
                    {
                        // If we have a native buffer wrapper, dispose it since we
                        // are a wrapper for it's IMemoryOwner<T> interface
                        this.nativeBufferWrapper?.Dispose();

                        Allocator.Singleton.UnregisterForDisposal(this);

                        this.handle.Close();
                        this.handle = null;
                    }

                    // Return the buffer during finalization to ensure that the pool
                    // can clean up its references. If the Image was garbage collected, the pool
                    // will continue to hold a reference.
                    if (this.managedBufferCache != null)
                    {
                        unsafe
                        {
                            Allocator.Singleton.ReturnBufferCache((IntPtr)this.GetUnsafeBuffer());
                        }

                        this.managedBufferCache = null;
                    }

                    this.disposedValue = true;
                }
            }
        }
Example #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Image"/> class.
        /// </summary>
        /// <param name="handle">Handle to initialize the image from.</param>
        /// <remarks>The handle will be owned by the new image.</remarks>
        internal Image(NativeMethods.k4a_image_t handle)
        {
            // Hook the native allocator and register this object.
            // .Dispose() will be called on this object when the allocator is shut down.
            Allocator.Singleton.RegisterForDisposal(this);

            this.handle = handle;
        }
        /// <summary>
        /// Retrieves a native image handle from the native API.
        /// </summary>
        /// <param name="nativeMethod">Native method to retrieve the image.</param>
        /// <param name="cachedImage">A cached instance of the Image that we return to callers. (Callers may dispose this image, although they shouldn't).</param>
        /// <remarks>
        /// If this is the first time calling the property, we construct a new wrapper.
        /// If the handle is for an Image we have already constructed a wrapper for, we return the existing wrapper.
        /// If the handle is for a different Image, we construct a new wrapper and dispose the old one.
        /// If existing wrapper has been disposed, we throw an exception.
        /// </remarks>
        private void UpdateImageWrapperAndDisposePrevious(
            Func <NativeMethods.k4a_capture_t, NativeMethods.k4a_image_t> nativeMethod,
            ref Image cachedImage)
        {
            // Lock must be held to ensure the Image in cache is not replaced while we are inspecting it
            // It is still possible for that Image to be accessed or Disposed while this lock is held
            lock (this)
            {
                if (this.disposedValue)
                {
                    throw new ObjectDisposedException(nameof(Capture));
                }

                // Get the image object from the native SDK
                // We now own a reference on this image and must eventually release it.
                NativeMethods.k4a_image_t nativeImageHandle = nativeMethod(this.handle);

                // This try block ensures that we close image (and release our reference) if we fail
                // to create a new Image.
                try
                {
                    // If this Capture previously had an image
                    if (cachedImage != null)
                    {
                        // Get the native pointer
                        IntPtr imageHandleValue = nativeImageHandle.DangerousGetHandle();

                        // Get the handle value from the cached image. If it has been disposed, this
                        // will throw an exception, which will be passed to the caller.

                        // Take an extra reference on the cachedImage to ensure it doesn't get disposed
                        // after getting the IntPtr from the handle.
                        using (Image reference = cachedImage.Reference())
                        {
                            if (reference.DangerousGetHandle().DangerousGetHandle() != imageHandleValue)
                            {
                                // The image has changed, invalidate the current image and construct new wrappers
                                cachedImage.Dispose();
                                cachedImage = null;
                            }
                        }
                    }

                    if (cachedImage == null && !nativeImageHandle.IsInvalid)
                    {
                        // Construct a new wrapper and return it
                        // The native function may have returned
#pragma warning disable CA2000 // Dispose objects before losing scope
                        cachedImage = new Image(nativeImageHandle);
#pragma warning restore CA2000 // Dispose objects before losing scope

                        // Since we have wrapped image, it is now owned by Image and we should no longer close it
                        nativeImageHandle = null;
                    }
                }
                finally
                {
                    // Ensure the native handle is closed if we have a failure creating the Image object
                    if (nativeImageHandle != null)
                    {
                        nativeImageHandle.Close();
                    }
                }
            }
        }
        // This function retrieves a native image handle from the native API.
        //
        // If this is the first time calling the property, we construct a new wrapper
        // If the handle is for an Image we have already constructed a wrapper for, we return the existing wrapper
        // If the handle is for a different Image, or if the wrapper has already been disposed, we construct a new wrapper and dispose the old one
        private Image GetImageWrapperAndDisposePrevious(Func <NativeMethods.k4a_capture_t, NativeMethods.k4a_image_t> nativeMethod,
                                                        ref Image cache)
        {
            // Lock must be held to ensure the Image in cache is not replaced while we are inspecting it
            // It is still possible for that Image to be accessed or Disposed while this lock is held
            lock (this)
            {
                if (this.disposedValue)
                {
                    throw new ObjectDisposedException(nameof(Capture));
                }

                NativeMethods.k4a_image_t image = nativeMethod(this.handle);
                // This try block ensures that we close image
                try
                {
                    if (cache != null)
                    {
                        IntPtr imageHandle = image.DangerousGetHandle();

                        // Only attempt to access cache in this try block
                        try
                        {
                            // If cache was disposed before we called the native accessor (by the caller or another thread),
                            // the handle could have been reused and the values would incorrectly match. However, cache.DangerousGetHandle()
                            // will throw an exception, and we will correctly construct a new image wrapper.
                            if (cache.DangerousGetHandle().DangerousGetHandle() != imageHandle)
                            {
                                // The image has changed, invalidate the current image and construct a new wrapper
                                cache.Dispose();
                                cache = null;
                            }
                        }
                        catch (ObjectDisposedException)
                        {
                            // If cache has been disposed by the caller or another thread we will discard
                            // it and construct a new wrapper
                            cache = null;
                        }
                    }

                    if (cache == null && !image.IsInvalid)
                    {
                        // Construct a new wrapper and return it
                        // The native function may have returned
                        cache = new Image(image);

                        // Since we have wrapped image, it is now owned by the UnsafeImage object and we should no longer close it
                        image = null;
                    }
                }
                finally
                {
                    // Ensure the native handle is closed if we have a failure creating the Image object
                    if (image != null)
                    {
                        image.Close();
                    }
                }

                return(cache);
            }
        }