private bool RetrieveFrame() { if (_desktopImageTexture == null) { _desktopImageTexture = new Texture2D(_mDevice, _mTextureDesc); } Resource desktopResource = null; _frameInfo = new OutputDuplicateFrameInformation(); try { _mDeskDupl.AcquireNextFrame(500, out _frameInfo, out desktopResource); } catch (SharpDXException ex) { if (ex.ResultCode.Code == ResultCode.WaitTimeout.Result.Code) { return(true); } if (ex.ResultCode.Failure) { //return true; desktopResource?.Dispose(); throw new DesktopDuplicationException("Failed to acquire next frame."); } } using (var tempTexture = desktopResource?.QueryInterface <Texture2D>()) { _mDevice.ImmediateContext.CopyResource(tempTexture, _desktopImageTexture); } desktopResource?.Dispose(); return(false); }
private bool RetrieveFrame() { if (_desktopImageTexture == null) { _desktopImageTexture = new Texture2D(_captureDevice, _textureDesc); } SharpDX.DXGI.Resource desktopResource; _frameInfo = new OutputDuplicateFrameInformation(); try { _deskDupl.AcquireNextFrame(500, out _frameInfo, out desktopResource); } catch (SharpDXException ex) when(ex.ResultCode.Code == ResultCode.WaitTimeout.Result.Code) { return(false); } using (desktopResource) using (var tempTexture = desktopResource.QueryInterface <Texture2D>()) { _captureDevice.ImmediateContext.CopyResource(tempTexture, _desktopImageTexture); } return(true); }
private bool RetrieveFrame() { try { _frameInfo = new OutputDuplicateFrameInformation(); SharpDX.DXGI.Resource desktopResource; _deskDupl.AcquireNextFrame(500, out _frameInfo, out desktopResource); using (desktopResource) { if (_desktopImageTexture == null) { _desktopImageTexture = new Texture2D(_device, _textureDescription); } using (var tempTexture = desktopResource.QueryInterface <Texture2D>()) _device.ImmediateContext.CopyResource(tempTexture, _desktopImageTexture); } return(false); } catch (SharpDXException ex) { if (ex.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code) { return(true); } if (ex.ResultCode.Failure) { throw new DesktopDuplicationException("Failed to acquire next frame."); } return(false); } }
private FramePars GetFrameParams(OutputDuplicateFrameInformation frameInfo) { FramePars frameParams = new FramePars(); OutputDuplicateMoveRectangle[] moveRects = new OutputDuplicateMoveRectangle[0]; RawRectangle[] dirtyRects = new RawRectangle[0]; if (frameInfo.TotalMetadataBufferSize > 0) //if (frameInfo.AccumulatedFrames > 0) { var bufferSizeBytes = frameInfo.TotalMetadataBufferSize; int moveRectSizeBytes = GetMoveRects(bufferSizeBytes, out moveRects); bufferSizeBytes -= moveRectSizeBytes; int dirtyRectSizeBytes = GetDirtyRects(bufferSizeBytes, out dirtyRects); bufferSizeBytes -= dirtyRectSizeBytes; frameParams.DirtyRects = dirtyRects; frameParams.MoveRects = moveRects; frameParams.FrameInfo = frameInfo; } return(frameParams); }
private FrameMetadata GetMetadata(Capture capture, OutputDuplicateFrameInformation frameInformation) { int totalBufferSize = frameInformation.TotalMetadataBufferSize; if (totalBufferSize == 0) { return(null); } var toReturn = new FrameMetadata(); int actualLength; var moveBuffer = new OutputDuplicateMoveRectangle[totalBufferSize]; capture.OutputDuplication.GetFrameMoveRects(moveBuffer.Length, moveBuffer, out actualLength); Array.Resize(ref moveBuffer, actualLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))); toReturn.MoveRectangles = moveBuffer; var dirtyBuffer = new RawRectangle[totalBufferSize]; capture.OutputDuplication.GetFrameDirtyRects(dirtyBuffer.Length, dirtyBuffer, out actualLength); Array.Resize(ref dirtyBuffer, actualLength / Marshal.SizeOf(typeof(RawRectangle))); toReturn.DirtyRectangles = dirtyBuffer; return(toReturn); }
Bitmap ProcessFrame(IntPtr SourcePtr, int SourceRowPitch, OutputDuplicateFrameInformation FrameInfo) { var frame = new Bitmap(_rect.Width, _rect.Height, PixelFormat.Format32bppRgb); // Copy pixels from screen capture Texture to GDI bitmap var mapDest = frame.LockBits(new Rectangle(0, 0, _rect.Width, _rect.Height), ImageLockMode.WriteOnly, frame.PixelFormat); Parallel.For(0, _rect.Height, Y => { Utilities.CopyMemory(mapDest.Scan0 + Y * mapDest.Stride, SourcePtr + Y * SourceRowPitch, _rect.Width * 4); }); // Release source and dest locks frame.UnlockBits(mapDest); if (_includeCursor && (FrameInfo.LastMouseUpdateTime == 0 || FrameInfo.PointerPosition.Visible)) { using (var g = Graphics.FromImage(frame)) MouseCursor.Draw(g, P => new Point(P.X - _rect.X, P.Y - _rect.Y)); } return(frame); }
private bool RetrieveFrame() { if (desktopImageTexture == null) { desktopImageTexture = new Texture2D(mDevice, mTextureDesc); } SharpDX.DXGI.Resource desktopResource = null; frameInfo = new OutputDuplicateFrameInformation(); try { if (mDeskDupl == null) { return(true); } mDeskDupl.AcquireNextFrame(-1, out frameInfo, out desktopResource); } catch (SharpDXException ex) { if (ex.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code) { return(true); } if (ex.ResultCode.Failure) { throw new DesktopDuplicationException("Failed to acquire next frame."); } } using (var tempTexture = desktopResource.QueryInterface <Texture2D>()) mDevice.ImmediateContext.CopyResource(tempTexture, desktopImageTexture); desktopResource.Dispose(); return(false); }
private bool RetrieveFrame() { if (_desktopImageTexture == null) { _desktopImageTexture = new Texture2D(_device, new Texture2DDescription() { CpuAccessFlags = CpuAccessFlags.Read, BindFlags = BindFlags.None, Format = Format.B8G8R8A8_UNorm, Width = _outputDescription.DesktopBounds.GetWidth(), Height = _outputDescription.DesktopBounds.GetHeight(), OptionFlags = ResourceOptionFlags.None, MipLevels = 1, ArraySize = 1, SampleDescription = { Count = 1, Quality = 0 }, Usage = ResourceUsage.Staging }); } SharpDX.DXGI.Resource desktopResource; _frameInfo = new OutputDuplicateFrameInformation(); try { if (_outputDuplication == null) { throw new Exception("_outputDuplication is null"); } _outputDuplication.AcquireNextFrame(500, out _frameInfo, out desktopResource); } catch (SharpDXException ex) { if (ex.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code) { return(false); } throw new DesktopDuplicationException("Failed to acquire next frame.", ex); } if (desktopResource == null) { throw new Exception("desktopResource is null"); } using (var tempTexture = desktopResource.QueryInterface <Texture2D>()) { if (_device == null) { throw new Exception("_device is null"); } if (_device.ImmediateContext == null) { throw new Exception("_device.ImmediateContext is null"); } _device.ImmediateContext.CopyResource(tempTexture, _desktopImageTexture); } desktopResource.Dispose(); return(true); }
private void UpdateMouseInfo(OutputDuplicateFrameInformation frameInfo) { if (frameInfo.LastMouseUpdateTime > 0) {// A non-zero mouse update timestamp indicates that there is a mouse position update and optionally a shape change var pointerPosition = frameInfo.PointerPosition; cursorInfo.LastTimeStamp = frameInfo.LastMouseUpdateTime; cursorInfo.Position = pointerPosition.Position; cursorInfo.Visible = pointerPosition.Visible; // logger.Debug("mouseInfo " + mouseInfo.Position.X + " " + mouseInfo.Position.Y); if (frameInfo.PointerShapeBufferSize > 0) { var bufSize = frameInfo.PointerShapeBufferSize; if (bufSize > cursorInfo.BufferSize) { var ptr = cursorInfo.PtrShapeBuffer; if (ptr != IntPtr.Zero) { Marshal.FreeHGlobal(ptr); } cursorInfo.BufferSize = bufSize; cursorInfo.PtrShapeBuffer = Marshal.AllocHGlobal(cursorInfo.BufferSize); } try { deskDupl.GetFramePointerShape(cursorInfo.BufferSize, cursorInfo.PtrShapeBuffer, out int pointerShapeBufferSizeRequired, out OutputDuplicatePointerShapeInformation pointerShapeInfo); cursorInfo.ShapeInfo = pointerShapeInfo; //logger.Debug("pointerShapeInfo " + pointerShapeInfo.Type); } catch (SharpDXException ex) { if (ex.ResultCode == SharpDX.DXGI.ResultCode.MoreData) { // TODO: //... logger.Error(ex); } throw; } } else {// No new shape } } }
private void GetDirtyAndMoveRects(ref FrameData data, Resource screenResource, OutputDuplicateFrameInformation duplicateFrameInformation) { //copy resource into memory that can be accessed by the CPU using (var screenTexture2D = screenResource.QueryInterface <Texture2D>()) device.ImmediateContext.CopyResource(screenTexture2D, screenTexture); screenResource.Dispose(); int bufSize = duplicateFrameInformation.TotalMetadataBufferSize; if (bufSize <= 0) { return; } var moveRectangles = new OutputDuplicateMoveRectangle [ (int) Math.Ceiling((double)bufSize / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))) ]; Console.WriteLine("Move : {0} {1} {2} {3}", moveRectangles.Length, bufSize, Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle)), bufSize / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))); //get move rects if (moveRectangles.Length > 0) { duplicatedOutput.GetFrameMoveRects(bufSize, moveRectangles, out bufSize); } data.MoveRectangles = moveRectangles; data.MoveCount = bufSize; bufSize = duplicateFrameInformation.TotalMetadataBufferSize - bufSize; var dirtyRectangles = new Rectangle[bufSize / Marshal.SizeOf(typeof(Rectangle))]; Console.WriteLine("Dirty : {0} {1} {2} {3}", dirtyRectangles.Length, bufSize, Marshal.SizeOf(typeof(Rectangle)), bufSize / Marshal.SizeOf(typeof(Rectangle))); //get dirty rects if (dirtyRectangles.Length > 0) { duplicatedOutput.GetFrameDirtyRects(bufSize, dirtyRectangles, out bufSize); } data.DirtyRectangles = dirtyRectangles; data.DirtyCount = bufSize; data.Frame = screenTexture; data.FrameInfo = duplicateFrameInformation; }
public void Update(Texture2D DesktopTexture, OutputDuplicateFrameInformation FrameInfo, OutputDuplication DeskDupl) { // No update if (FrameInfo.LastMouseUpdateTime == 0) { _pointerShape?.Update(DesktopTexture, _pointerPosition); return; } _pointerPosition = FrameInfo.PointerPosition; if (FrameInfo.PointerShapeBufferSize != 0) { if (FrameInfo.PointerShapeBufferSize > _ptrShapeBufferSize) { _ptrShapeBufferSize = FrameInfo.PointerShapeBufferSize; _ptrShapeBuffer = _ptrShapeBuffer != IntPtr.Zero ? Marshal.ReAllocCoTaskMem(_ptrShapeBuffer, _ptrShapeBufferSize) : Marshal.AllocCoTaskMem(_ptrShapeBufferSize); } DeskDupl.GetFramePointerShape(_ptrShapeBufferSize, _ptrShapeBuffer, out _, out _ptrShapeInfo); _pointerShape?.Dispose(); switch (_ptrShapeInfo.Type) { case PtrShapeMonochrome: _pointerShape = new MonochromePointerShape(_ptrShapeBuffer, _ptrShapeInfo, _editorSession); break; case PtrShapeMaskedColor: _pointerShape = new MaskedColorPointerShape(_ptrShapeBuffer, _ptrShapeInfo, _editorSession); break; case PtrShapeColor: _pointerShape = new ColorPointerShape(_ptrShapeBuffer, _ptrShapeInfo, _editorSession.RenderTarget); break; } } _pointerShape?.Update(DesktopTexture, _pointerPosition); }
private void CaptureFrameIfAvailable(Capture capture, int timeoutMilliseconds) { OutputDuplicateFrameInformation frameInformation = default(OutputDuplicateFrameInformation); bool frameAvailable; if (!capture.Initialized || !capture.ScreenFound) { capture.ReInitialize(); if (!capture.Initialized || !capture.ScreenFound) { capture.LastFrameInfo = null; return; } } try { Resource desktopResource; capture.OutputDuplication.AcquireNextFrame(timeoutMilliseconds, out frameInformation, out desktopResource); frameAvailable = true; using (var tempTexture = desktopResource.QueryInterface <Texture2D>()) { capture.Device.ImmediateContext.CopyResource(tempTexture, capture.Texture); } desktopResource.Dispose(); } catch (SharpDXException ex) { if (ex.ResultCode.Code == ResultCode.WaitTimeout.Result.Code) { frameAvailable = false; } else if (ex.ResultCode.Code == ResultCode.AccessLost.Code) { capture.Dispose(); frameAvailable = false; } else { throw; } } capture.LastFrameInfo = frameAvailable ? frameInformation : (OutputDuplicateFrameInformation?)null; }
internal DxgiScreenCapture( [NotNull] IScreen screen, [NotNull] IServiceProvider serviceProvider, DateTime time, int width, int height, [NotNull] DxgiScreenCaptureSharedResources resources, [NotNull] Resource screenResource, [NotNull] OutputDuplicateFrameInformation frameInformation) : base(screen, serviceProvider, time, width, height) { SharedResources = resources; ScreenResource = screenResource; FrameInformation = frameInformation; _disposable = Disposable.Create(() => { ScreenResource.Dispose(); OutputDuplication.ReleaseFrame(); SharedResources.RemoveReference(); }); SharedResources.AddReference(); }
private void RetrieveCursorMetadata(ref OutputDuplicateFrameInformation frameInfo, OutputDuplication duplication, int outputDevice, ref PointerInfo pointerInfo) { // A non-zero mouse update timestamp indicates that there is a mouse position update and optionally a shape change if (frameInfo.LastMouseUpdateTime == 0) { return; } var updatePosition = true; // Make sure we don't update pointer position wrongly // If pointer is invisible, make sure we did not get an update from another output that the last time that said pointer // was visible, if so, don't set it to invisible or update. if (!frameInfo.PointerPosition.Visible && (pointerInfo.WhoUpdatedPositionLast != outputDevice)) { updatePosition = false; } // If two outputs both say they have a visible, only update if new update has newer timestamp if (frameInfo.PointerPosition.Visible && pointerInfo.Visible && (pointerInfo.WhoUpdatedPositionLast != outputDevice) && (pointerInfo.LastTimeStamp > frameInfo.LastMouseUpdateTime)) { updatePosition = false; } // Update position if (updatePosition) { pointerInfo.Position = new Point(frameInfo.PointerPosition.Position.X, frameInfo.PointerPosition.Position.Y); pointerInfo.WhoUpdatedPositionLast = outputDevice; pointerInfo.LastTimeStamp = frameInfo.LastMouseUpdateTime; pointerInfo.Visible = frameInfo.PointerPosition.Visible; } // No new shape if (frameInfo.PointerShapeBufferSize == 0) { return; } if (frameInfo.PointerShapeBufferSize > pointerInfo.BufferSize) { pointerInfo.PtrShapeBuffer = new byte[frameInfo.PointerShapeBufferSize]; pointerInfo.BufferSize = frameInfo.PointerShapeBufferSize; } try { unsafe { fixed(byte *ptrShapeBufferPtr = pointerInfo.PtrShapeBuffer) { duplication.GetFramePointerShape(frameInfo.PointerShapeBufferSize, (IntPtr)ptrShapeBufferPtr, out pointerInfo.BufferSize, out var info); if (info.Type != 0) { pointerInfo.ShapeInfo = info; } } } } catch (SharpDXException ex) { if (ex.ResultCode.Failure) { throw new HelixToolkitException("Failed to get frame pointer shape."); } } }
protected internal bool GetCursor(Texture2D screenTexture, OutputDuplicateFrameInformation info, FrameInfo frame) { //Prepare buffer array to hold the cursor shape. if (CursorShapeBuffer == null || info.PointerShapeBufferSize > CursorShapeBuffer.Length) { CursorShapeBuffer = new byte[info.PointerShapeBufferSize]; } //If there's a cursor shape available to be captured. if (info.PointerShapeBufferSize > 0) { //Pin the buffer in order to pass the address as parameter later. var pinnedBuffer = GCHandle.Alloc(CursorShapeBuffer, GCHandleType.Pinned); var cursorBufferAddress = pinnedBuffer.AddrOfPinnedObject(); //Load the cursor shape into the buffer. DuplicatedOutput.GetFramePointerShape(info.PointerShapeBufferSize, cursorBufferAddress, out _, out CursorShapeInfo); //If the cursor is monochrome, it will return the cursor shape twice, one is the mask. if (CursorShapeInfo.Type == 1) { CursorShapeInfo.Height /= 2; } //The buffer must be unpinned, to free resources. pinnedBuffer.Free(); } //Store the current cursor position, if it was moved. if (info.LastMouseUpdateTime != 0) { PreviousPosition = info.PointerPosition; } //TODO: In a future version, don't merge the cursor image in here, let the editor do that. //Saves the position of the cursor, so the editor can add the mouse clicks overlay later. frame.CursorX = PreviousPosition.Position.X - (Left - OffsetLeft); frame.CursorY = PreviousPosition.Position.Y - (Top - OffsetTop); //If the method is supposed to simply the get the cursor shape no shape was loaded before, there's nothing else to do. //if (CursorShapeBuffer?.Length == 0 || (info.LastPresentTime == 0 && info.LastMouseUpdateTime == 0) || !info.PointerPosition.Visible) if (screenTexture == null || CursorShapeBuffer?.Length == 0)// || !info.PointerPosition.Visible) { //FallbackCursorCapture(frame); //if (CursorShapeBuffer != null) return(false); } //Don't let it bleed beyond the top-left corner, calculate the dimensions of the portion of the cursor that will appear. var leftCut = frame.CursorX; var topCut = frame.CursorY; var rightCut = screenTexture.Description.Width - (frame.CursorX + CursorShapeInfo.Width); var bottomCut = screenTexture.Description.Height - (frame.CursorY + CursorShapeInfo.Height); //Adjust to the hotspot offset, so it's possible to add the highlight correctly later. frame.CursorX += CursorShapeInfo.HotSpot.X; frame.CursorY += CursorShapeInfo.HotSpot.Y; //Don't try merging the textures if the cursor is out of bounds. if (leftCut + CursorShapeInfo.Width < 1 || topCut + CursorShapeInfo.Height < 1 || rightCut + CursorShapeInfo.Width < 1 || bottomCut + CursorShapeInfo.Height < 1) { return(false); } var cursorLeft = Math.Max(leftCut, 0); var cursorTop = Math.Max(topCut, 0); var cursorWidth = leftCut < 0 ? CursorShapeInfo.Width + leftCut : rightCut < 0 ? CursorShapeInfo.Width + rightCut : CursorShapeInfo.Width; var cursorHeight = topCut < 0 ? CursorShapeInfo.Height + topCut : bottomCut < 0 ? CursorShapeInfo.Height + bottomCut : CursorShapeInfo.Height; //The staging texture must be able to hold all pixels. if (CursorStagingTexture == null || CursorStagingTexture.Description.Width != cursorWidth || CursorStagingTexture.Description.Height != cursorHeight) { //In order to change the size of the texture, I need to instantiate it again with the new size. CursorStagingTexture?.Dispose(); CursorStagingTexture = new Texture2D(Device, new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.None, CpuAccessFlags = CpuAccessFlags.Write, Height = cursorHeight, Format = Format.B8G8R8A8_UNorm, Width = cursorWidth, MipLevels = 1, OptionFlags = ResourceOptionFlags.None, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Staging }); } //The region where the cursor is located is copied to the staging texture to act as the background when dealing with masks and transparency. //The cutout must be the exact region needed and it can't overflow. It's not allowed to try to cut outside of the screenTexture region. var region = new ResourceRegion { Left = cursorLeft, Top = cursorTop, Front = 0, Right = cursorLeft + cursorWidth, Bottom = cursorTop + cursorHeight, Back = 1 }; //Copy from the screen the region in which the cursor is located. Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0, region, CursorStagingTexture, 0); //Get cursor details and draw it to the staging texture. DrawCursorShape(CursorStagingTexture, CursorShapeInfo, CursorShapeBuffer, leftCut < 0 ? leftCut * -1 : 0, topCut < 0 ? topCut * -1 : 0, cursorWidth, cursorHeight); //Copy back the cursor texture to the screen texture. Device.ImmediateContext.CopySubresourceRegion(CursorStagingTexture, 0, null, screenTexture, 0, cursorLeft, cursorTop); return(true); }
public AcquireResult(Result Result, OutputDuplicateFrameInformation FrameInfo, Resource DesktopResource) { this.Result = Result; this.FrameInfo = FrameInfo; this.DesktopResource = DesktopResource; }
private bool RetrieveFrame() { if (desktopImageTexture == null) desktopImageTexture = new Texture2D(mDevice, mTextureDesc); SharpDX.DXGI.Resource desktopResource = null; frameInfo = new OutputDuplicateFrameInformation(); try { mDeskDupl.AcquireNextFrame(5000, out frameInfo, out desktopResource); } catch (SharpDXException ex) { if (ex.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code) { return true; } if (ex.ResultCode.Failure) { //return true; desktopResource.Dispose(); throw new DesktopDuplicationException("Failed to acquire next frame."); } } using (var tempTexture = desktopResource.QueryInterface<Texture2D>()) mDevice.ImmediateContext.CopyResource(tempTexture, desktopImageTexture); desktopResource.Dispose(); return false; }
protected internal void GetCursor(Texture2D screenTexture, OutputDuplicateFrameInformation info, FrameInfo frame) { //Prepare buffer array to hold the cursor shape. if (CursorShapeBuffer == null || info.PointerShapeBufferSize > CursorShapeBuffer.Length) { CursorShapeBuffer = new byte[info.PointerShapeBufferSize]; } //If there's a cursor shape available to be captured. if (info.PointerShapeBufferSize > 0) { //Pin the buffer in order to pass the address as parameter later. var pinnedBuffer = GCHandle.Alloc(CursorShapeBuffer, GCHandleType.Pinned); var cursorBufferAddress = pinnedBuffer.AddrOfPinnedObject(); //Load the cursor shape into the buffer. DuplicatedOutput.GetFramePointerShape(info.PointerShapeBufferSize, cursorBufferAddress, out _, out CursorShapeInfo); //If the cursor is monochrome, it will return the cursor shape twice, one is the mask. if (CursorShapeInfo.Type == 1) { CursorShapeInfo.Height /= 2; } //The buffer must be unpinned, to free resources. pinnedBuffer.Free(); } //Store the current cursor position, if it was moved. if (info.LastMouseUpdateTime != 0) { PreviousPosition = info.PointerPosition; } //TODO: In a future version, don't merge the cursor image in here, let the editor do that. //Saves the position of the cursor, so the editor can add the mouse clicks overlay later. frame.CursorX = PreviousPosition.Position.X - Left; frame.CursorY = PreviousPosition.Position.Y - Top; //If the method is supposed to simply the get the cursor shape no shape was loaded before, there's nothing else to do. //if (CursorShapeBuffer?.Length == 0 || (info.LastPresentTime == 0 && info.LastMouseUpdateTime == 0) || !info.PointerPosition.Visible) if (screenTexture == null || CursorShapeBuffer?.Length == 0)// || !info.PointerPosition.Visible) { return; } //Don't let it bleed beyond the top-left corner. var left = Math.Max(frame.CursorX, 0); var top = Math.Max(frame.CursorY, 0); var offsetX = Math.Abs(Math.Min(0, frame.CursorX)); var offsetY = Math.Abs(Math.Min(0, frame.CursorY)); //Adjust the offset, so it's possible to add the highlight correctly later. frame.CursorX += CursorShapeInfo.HotSpot.X; frame.CursorY += CursorShapeInfo.HotSpot.Y; if (CursorShapeInfo.Width - offsetX < 0 || CursorShapeInfo.Height - offsetY < 0) { return; } //The staging texture must be able to hold all pixels. if (CursorStagingTexture == null || CursorStagingTexture.Description.Width < CursorShapeInfo.Width - offsetX || CursorStagingTexture.Description.Height < CursorShapeInfo.Height - offsetY) { //In order to change the size of the texture, I need to instantiate it again with the new size. CursorStagingTexture?.Dispose(); CursorStagingTexture = new Texture2D(Device, new Texture2DDescription { ArraySize = 1, BindFlags = BindFlags.None, CpuAccessFlags = CpuAccessFlags.Write, Height = CursorShapeInfo.Height - offsetY, Format = Format.B8G8R8A8_UNorm, Width = CursorShapeInfo.Width - offsetX, MipLevels = 1, OptionFlags = ResourceOptionFlags.None, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Staging }); } //The region where the cursor is located is copied to the staging texture to act as the background when dealing with masks and transparency. var region = new ResourceRegion { Left = left, Top = top, Front = 0, Right = left + CursorStagingTexture.Description.Width, Bottom = top + CursorStagingTexture.Description.Height, Back = 1 }; //Copy from the screen the region in which the cursor is located. Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0, region, CursorStagingTexture, 0); //Get cursor details and draw it to the staging texture. DrawCursorShape(CursorStagingTexture, CursorShapeInfo, CursorShapeBuffer, offsetX, offsetY); //Copy back the cursor texture to the screen texture. Device.ImmediateContext.CopySubresourceRegion(CursorStagingTexture, 0, null, screenTexture, 0, left, top); }
/* Код взят с: * https://github.com/sharpdx/SharpDX-Samples/blob/master/Desktop/Direct3D11.1/ScreenCapture/Program.cs * https://github.com/fabsenet/adrilight/blob/master/adrilight/DesktopDuplication/DesktopDuplicator.cs метод ProcessFrame */ public Bitmap GetFrame() { SharpDX.DXGI.Resource desktopResource = null; var frameInfo = new OutputDuplicateFrameInformation(); // Try to get duplicated frame within given time try { outputDuplication.AcquireNextFrame(500, out frameInfo, out desktopResource); } catch (SharpDXException ex) { if (ex.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code) { return(null); } MessageBox.Show("Невозможно обработать SharpDXException", "Ошибка"); return(null); } // copy resource into memory that can be accessed by the CPU using (var tempTexture = desktopResource.QueryInterface <Texture2D>()) { device.ImmediateContext.CopyResource(tempTexture, desktopImageTexture); } desktopResource.Dispose(); // Get the desktop capture texture var mapSource = device.ImmediateContext.MapSubresource(desktopImageTexture, 0, MapMode.Read, MapFlags.None); // Copy pixels from screen capture Texture to GDI bitmap BitmapData mapDest = image.LockBits(boundsRect, ImageLockMode.WriteOnly, image.PixelFormat); var sourcePtr = mapSource.DataPointer; var destPtr = mapDest.Scan0; if (mapSource.RowPitch == mapDest.Stride) { // Fast copy Utilities.CopyMemory(destPtr, sourcePtr, height * mapDest.Stride); } else { // Safe copy for (int y = 0; y < height; y++) { // Copy a single line Utilities.CopyMemory(destPtr, sourcePtr, width * 4); // Advance pointers sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch); destPtr = IntPtr.Add(destPtr, mapDest.Stride); } } // Release source and dest locks image.UnlockBits(mapDest); device.ImmediateContext.UnmapSubresource(desktopImageTexture, 0); desktopResource.Dispose(); outputDuplication.ReleaseFrame(); return(image); }