/// <inheritdoc />
        /// <summary>
        ///   Acquires a single frame
        /// </summary>
        /// <inheritdoc />
        /// <summary>
        ///   Acquires a single frame from this provider
        /// </summary>
        public override void AcquireFrame()
        {
            for (int i = 0; i < this.sources.Length; i++)
            {
                DxgiCaptureSource source = this.sources[i];

                try {
                    OutputDuplicateFrameInformation info;
                    Resource desktopResource = null;

                    do
                    {
                        // release previous frame if last capture attempt failed
                        if (desktopResource != null)
                        {
                            desktopResource.Dispose();
                            source.Duplication.ReleaseFrame();
                        }

                        // try to capture a frame
                        source.Duplication.AcquireNextFrame(DuplicationFrameTimeout,
                                                            out info,
                                                            out desktopResource);
                    } while (info.TotalMetadataBufferSize == 0);

                    this.lastPresentTime = info.LastPresentTime;

                    using (var srcResource = desktopResource.QueryInterface <SharpDX.Direct3D11.Resource>())
                        using (var destResource = source.Texture.QueryInterface <SharpDX.Direct3D11.Resource>()) {
                            // copy the entire screen region to the target texture
                            source.Context.CopySubresourceRegion(
                                srcResource,
                                0,
                                source.Subregion,
                                destResource,
                                0);
                        }

                    // release resources
                    desktopResource.Dispose();
                    source.Duplication.ReleaseFrame();
                } catch (SharpDXException exception) when(exception.ResultCode == ResultCode.AccessLost ||
                                                          exception.ResultCode == ResultCode.DeviceHung ||
                                                          exception.ResultCode == ResultCode.DeviceRemoved)
                {
                    // device has been lost - we can't ignore this and should try to reinitialize the D3D11 device until it's
                    // available again (...)
                    // we'll be receiving black/unsynced frames beyond this point - it is OK until we restore the device
                    while (true)
                    {
                        try {
                            this.sources[i] = DxgiCaptureSource.Recreate(this.virtualRect);
                            break; // successfully restored capture source
                        } catch (SharpDXException) {
                            /* could not restore the capture source - keep trying */
                        }
                    }
                }
            }
        }
Пример #2
0
        /// <summary>
        ///   Creates a capture source with the same properties as this one
        /// </summary>
        /// <param name="bounds">Target screen bounds</param>
        /// <returns>A new <see cref="DxgiCaptureSource"/> instance</returns>
        internal static DxgiCaptureSource Recreate(Rectangle bounds)
        {
            DxgiCaptureSource source = null;

            using (var factory = new Factory1()) {
                if (factory.GetAdapterCount1() == 0)
                {
                    throw new NotSupportedException("No suitable video adapters found");
                }

                foreach (Adapter1 adapter in factory.Adapters1)
                {
                    foreach (Output output in adapter.Outputs)
                    {
                        var intersection = Rectangle.Intersect(bounds, output.Description.DesktopBounds);
                        if (intersection.Width > 0 && intersection.Height > 0)
                        {
                            source = new DxgiCaptureSource(adapter, output, new Rectangle(intersection.X,
                                                                                          intersection.Y,
                                                                                          intersection.Width,
                                                                                          intersection.Height));
                            break;
                        }

                        output.Dispose();
                    }

                    adapter.Dispose();
                    if (source != null)
                    {
                        break;
                    }
                }
            }

            return(source ?? throw new Exception("No suitable capture sources were found"));
        }