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);
        }
Exemple #2
0
        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);
        }
Exemple #6
0
        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
                    }
                }
            }
Exemple #10
0
        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;
        }
Exemple #11
0
        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;
        }
Exemple #13
0
        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.");
                        }
                    }
                }
Exemple #15
0
    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);
    }
Exemple #16
0
 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);
        }
Exemple #19
0
    /* Код взят с:
     * 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);
    }