/// <summary> /// Updates the specified frame with the next retrieved frame. /// </summary> private void UpdateFrame(DesktopDuplicatorInternal ddupe, DesktopFrame frame) { // Try to get the latest frame; if (ddupe.TryRetrieveFrame(out var frameInfo)) { try { ddupe.RetrieveFrameMetadata(frame, frameInfo); ddupe.RetrieveCursorMetadata(frame, frameInfo); ddupe.ProcessFrame(frame); } finally { ddupe.ReleaseFrame(_logger); } } }
/// <summary> /// Duplicates the desktop yielding Desktop Frames until cancelled. /// </summary> /// <param name="token"></param> /// <returns></returns> public IEnumerable <DesktopFrame> DuplicateDesktop(CancellationToken token) { _logger.LogInformation($"Beginning Desktop Duplication"); using var duplicator = DesktopDuplicatorInternal.CreateDesktopDuplicator(_logger, _adapterIndex, _outputDeviceIndex); while (token.IsCancellationRequested == false) { var desktopFrame = new DesktopFrame(); UpdateFrame(duplicator, desktopFrame); if (token.IsCancellationRequested == false) { if (desktopFrame.IsDesktopImageBufferEmpty) { continue; } yield return(desktopFrame); } } }
public static DesktopDuplicatorInternal CreateDesktopDuplicator(ILogger logger, int adapterIndex, int outputDeviceIndex) { var dd = new DesktopDuplicatorInternal { _outputDeviceIndex = outputDeviceIndex }; var createFactoryResult = DXGI.CreateDXGIFactory1(out IDXGIFactory1 factory); if (!createFactoryResult.Success) { throw new DesktopDuplicationException("Couldn't create a DXGI Factory."); } IDXGIAdapter1 adapter = null; IDXGIOutput output = null; try { var result = factory.EnumAdapters1(adapterIndex, out adapter); if (result.Failure) { throw new DesktopDuplicationException($"An error occurred attempting to retrieve the adapter at the specified index ({adapterIndex}): {result}"); } if (adapter == null) { throw new DesktopDuplicationException($"An adapter was not found at the specified index ({adapterIndex})."); } logger.LogInformation($"Using adapter at index {adapterIndex} - {adapter.Description.Description}"); var createD3dDeviceResult = D3D11.D3D11CreateDevice(adapter, DriverType.Unknown, DeviceCreationFlags.None, null, out dd._d3dDevice, out dd._immediateContext); if (!createD3dDeviceResult.Success) { throw new DesktopDuplicationException("Couldn't create a D3D device from the specified adapter."); } using var device = dd._d3dDevice.QueryInterface <IDXGIDevice>(); var outputResult = adapter.EnumOutputs(outputDeviceIndex, out output); if (outputResult.Failure) { throw new DesktopDuplicationException($"An error occurred attempting to retrieve the output device at the specified index ({outputDeviceIndex}): {outputResult}"); } if (output == null) { throw new DesktopDuplicationException($"An output was not found at the specified index ({outputDeviceIndex})."); } logger.LogInformation($"Using output device on adapter {adapterIndex} at index {outputDeviceIndex}."); var output6 = output.QueryInterface <IDXGIOutput6>(); try { // Copy the values to a new rect. var rectTemp = output6.Description.DesktopCoordinates; dd._desktopRect = new RawRect(rectTemp.Left, rectTemp.Top, rectTemp.Right, rectTemp.Bottom); dd._outputDuplication = output6.DuplicateOutput(device); var stagingTexture = new Texture2DDescription() { CpuAccessFlags = CpuAccessFlags.Read, BindFlags = BindFlags.None, Format = dd._outputDuplication.Description.ModeDescription.Format, Width = Math.Abs(dd._desktopRect.Right - dd._desktopRect.Left), Height = Math.Abs(dd._desktopRect.Bottom - dd._desktopRect.Top), OptionFlags = ResourceOptionFlags.None, MipLevels = 1, ArraySize = 1, SampleDescription = { Count = 1, Quality = 0 }, Usage = Usage.Staging // << can be read by CPU }; // Initialize the Output Duplication -- If this isn't done occassionally an 'Unsupported' result will occur with DuplicationOutput1 dd._desktopImageTexture = dd._d3dDevice.CreateTexture2D(stagingTexture); } catch (SharpGenException ex) { if (ex.Descriptor.NativeApiCode == "DXGI_ERROR_UNSUPPORTED") { throw new DesktopDuplicationException("Unsupported desktop mode or scenario."); } else if (ex.Descriptor.NativeApiCode == "DXGI_ERROR_NOT_CURRENTLY_AVAILABLE") { throw new DesktopDuplicationException("There is already the maximum number of applications using the Desktop Duplication API running, please close one of the applications and try again."); } else { throw; } } } finally { if (output != null) { output.Dispose(); } if (adapter != null) { adapter.Dispose(); } if (factory != null) { factory.Dispose(); } } return(dd); }