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);
            }
Exemple #2
0
        private void RetrieveFrameMetadata(DesktopFrame frame)
        {
            if (_frameInfo.TotalMetadataBufferSize > 0)
            {
                // Get moved regions
                int movedRegionsLength;
                OutputDuplicateMoveRectangle[] movedRectangles = new OutputDuplicateMoveRectangle[_frameInfo.TotalMetadataBufferSize];
                _outputDuplication.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out movedRegionsLength);
                frame.MovedRegions = new MovedRegion[movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))];
                for (int i = 0; i < frame.MovedRegions.Length; i++)
                {
                    frame.MovedRegions[i] = new MovedRegion()
                    {
                        Source      = new System.Drawing.Point(movedRectangles[i].SourcePoint.X, movedRectangles[i].SourcePoint.Y),
                        Destination = new System.Drawing.Rectangle(movedRectangles[i].DestinationRect.X, movedRectangles[i].DestinationRect.Y, movedRectangles[i].DestinationRect.Width, movedRectangles[i].DestinationRect.Height)
                    };
                }

                // Get dirty regions
                int         dirtyRegionsLength;
                Rectangle[] dirtyRectangles = new Rectangle[_frameInfo.TotalMetadataBufferSize];
                _outputDuplication.GetFrameDirtyRects(dirtyRectangles.Length, dirtyRectangles, out dirtyRegionsLength);
                frame.UpdatedRegions = new System.Drawing.Rectangle[dirtyRegionsLength / Marshal.SizeOf(typeof(Rectangle))];
                for (int i = 0; i < frame.UpdatedRegions.Length; i++)
                {
                    frame.UpdatedRegions[i] = new System.Drawing.Rectangle(dirtyRectangles[i].X, dirtyRectangles[i].Y, dirtyRectangles[i].Width, dirtyRectangles[i].Height);
                }
            }
            else
            {
                frame.MovedRegions   = new MovedRegion[0];
                frame.UpdatedRegions = new System.Drawing.Rectangle[0];
            }
        }
        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);
        }
            private int GetMoveRects(int bufferSizeBytes, out OutputDuplicateMoveRectangle[] moveRects)
            {
                int moveRectsBufferSizeRequired = 0;

                moveRects = new OutputDuplicateMoveRectangle[0];
                if (bufferSizeBytes <= 0)
                {
                    return(moveRectsBufferSizeRequired);
                }

                var moveItemSize         = Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle));
                var maxMoveRectItemCount = bufferSizeBytes / moveItemSize;

                if (maxMoveRectItemCount > 0)
                {
                    var moveRectBuf = new OutputDuplicateMoveRectangle[maxMoveRectItemCount];

                    try
                    {
                        deskDupl.GetFrameMoveRects(bufferSizeBytes, moveRectBuf, out moveRectsBufferSizeRequired);
                    }
                    catch (SharpDXException ex)
                    {
                        if (ex.ResultCode == SharpDX.DXGI.ResultCode.MoreData)
                        {
                            logger.Error(ex);

                            // TODO:
                            //maxMoveRectItemCount = moveRectsBufferSizeRequired / moveItemSize;
                            //moveRectBuf = new OutputDuplicateMoveRectangle[maxMoveRectItemCount];
                            // continue...
                        }

                        throw;
                    }


                    var moveCount = moveRectsBufferSizeRequired / moveItemSize;

                    if (moveCount > 0)
                    {
                        if (maxMoveRectItemCount > moveCount)
                        {
                            moveRects = moveRectBuf.Take(moveCount).ToArray();
                        }
                        else
                        {
                            moveRects = moveRectBuf;
                        }
                    }
                }

                return(moveRectsBufferSizeRequired);
            }
Exemple #5
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 #6
0
        public OutputDuplicateMoveRectangle[] GetMoveRectangles()
        {
            OutputDuplicateMoveRectangle[] moveRectBuffer = moveRectHelper.GetExistingBuffer();
            // First, try with our existing buffer. It may fail and make us increase the buffer size.
            int requiredMoveRectSize = -1;

            try
            {
                duplicatedOutput.GetFrameMoveRects(moveRectHelper.bufferSizeBytes, moveRectBuffer, out requiredMoveRectSize);
            }
            catch (SharpDXException e)
            {
                if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.MoreData.Result.Code)
                {
                    throw e;
                }
            }
            if (requiredMoveRectSize == -1)
            {
                throw new Exception("GetFrameMoveRects did not tell us the required buffer size");
            }

            if (requiredMoveRectSize > moveRectHelper.bufferSizeBytes)
            {
                if (requiredMoveRectSize % moveRectHelper.itemSize != 0)
                {
                    throw new Exception("requiredMoveRectSize " + requiredMoveRectSize + " is not divisible by " + moveRectHelper.itemSize);
                }

                // Increase buffer size and try again
                moveRectBuffer = moveRectHelper.GetLargerBuffer(requiredMoveRectSize / moveRectHelper.itemSize);
                duplicatedOutput.GetFrameMoveRects(moveRectHelper.bufferSizeBytes, moveRectBuffer, out requiredMoveRectSize);

                if (requiredMoveRectSize % moveRectHelper.itemSize != 0)
                {
                    throw new Exception("requiredMoveRectSize " + requiredMoveRectSize + " is not divisible by " + moveRectHelper.itemSize);
                }
            }
            int numMoveRects = requiredMoveRectSize / moveRectHelper.itemSize;

            OutputDuplicateMoveRectangle[] retVal = new OutputDuplicateMoveRectangle[numMoveRects];
            for (int i = 0; i < numMoveRects; i++)
            {
                retVal[i] = moveRectBuffer[i];
                //Logger.Info("MoveRect [" + moveRectBuffer[i].SourcePoint.X
                //	+ "," + +moveRectBuffer[i].SourcePoint.Y + "] -> ["
                //	+ moveRectBuffer[i].DestinationRect.Left + ","
                //	+ moveRectBuffer[i].DestinationRect.Top + ","
                //	+ moveRectBuffer[i].DestinationRect.Right + ","
                //	+ moveRectBuffer[i].DestinationRect.Bottom + "]");
            }
            return(retVal);
        }
        private void RetrieveFrameMetadata(DesktopFrame frame)
        {
            if (_frameInfo.TotalMetadataBufferSize > 0)
            {
                // Get moved regions
                var movedRegionsLength = 0;
                var movedRectangles    = new OutputDuplicateMoveRectangle[_frameInfo.TotalMetadataBufferSize];
                _mDeskDupl.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out movedRegionsLength);
                frame.MovedRegions =
                    new MovedRegion[movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))];
                for (var i = 0; i < frame.MovedRegions.Length; i++)
                {
                    var destRect = (Rectangle)movedRectangles[i].DestinationRect;
                    frame.MovedRegions[i] = new MovedRegion
                    {
                        Source      = new Point(movedRectangles[i].SourcePoint.X, movedRectangles[i].SourcePoint.Y),
                        Destination =
                            new global::System.Drawing.Rectangle(destRect.X, destRect.Y, destRect.Width, destRect.Height)
                    };
                }

                // Get dirty regions
                var dirtyRegionsLength = 0;
                var dirtyRectangles    = new RawRectangle[_frameInfo.TotalMetadataBufferSize];
                _mDeskDupl.GetFrameDirtyRects(dirtyRectangles.Length, dirtyRectangles, out dirtyRegionsLength);
                frame.UpdatedRegions =
                    new global::System.Drawing.Rectangle[dirtyRegionsLength / Marshal.SizeOf(typeof(Rectangle))];
                frame.FinishedRegions = new FinishedRegions[frame.UpdatedRegions.Length];
                for (var i = 0; i < frame.UpdatedRegions.Length; i++)
                {
                    var dirtyRect = (Rectangle)dirtyRectangles[i];
                    var rect      = new global::System.Drawing.Rectangle(dirtyRect.X, dirtyRect.Y, dirtyRect.Width,
                                                                         dirtyRect.Height);


                    frame.FinishedRegions[i] = new FinishedRegions
                    {
                        Destination = rect,
                        Frame       = ExtractRect(rect.X, rect.Y, rect.Width, rect.Height)
                    };
                }
            }
            else
            {
                frame.MovedRegions   = new MovedRegion[0];
                frame.UpdatedRegions = new global::System.Drawing.Rectangle[0];
            }
        }
Exemple #8
0
    public override int CaptureWithCursor(FrameInfo frame)
    {
        var res = new Result(-1);

        try
        {
            //Try to get the duplicated output frame within given time.
            res = DuplicatedOutput.TryAcquireNextFrame(0, out var info, out var resource);

            //Checks how to proceed with the capture. It could have failed, or the screen, cursor or both could have been captured.
            if (FrameCount == 0 && info.LastMouseUpdateTime == 0 && (res.Failure || resource == null))
            {
                //Somehow, it was not possible to retrieve the resource, frame or metadata.
                resource?.Dispose();
                return(FrameCount);
            }
            else if (FrameCount == 0 && info.TotalMetadataBufferSize == 0 && info.LastMouseUpdateTime > 0)
            {
                //Sometimes, the first frame has cursor info, but no screen changes.
                GetCursor(null, info, frame);
                resource?.Dispose();
                return(FrameCount);
            }

            #region Process changes

            //Something on screen was moved or changed.
            if (info.TotalMetadataBufferSize > 0)
            {
                //Copies the screen data into memory that can be accessed by the CPU.
                using (var screenTexture = resource.QueryInterface <Texture2D>())
                {
                    #region Moved rectangles

                    var movedRectangles = new OutputDuplicateMoveRectangle[info.TotalMetadataBufferSize];
                    DuplicatedOutput.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out var movedRegionsLength);

                    for (var movedIndex = 0; movedIndex < movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle)); movedIndex++)
                    {
                        //Crop the destination rectangle to the screen area rectangle.
                        var left   = Math.Max(movedRectangles[movedIndex].DestinationRect.Left, Left - OffsetLeft);
                        var right  = Math.Min(movedRectangles[movedIndex].DestinationRect.Right, Left + Width - OffsetLeft);
                        var top    = Math.Max(movedRectangles[movedIndex].DestinationRect.Top, Top - OffsetTop);
                        var bottom = Math.Min(movedRectangles[movedIndex].DestinationRect.Bottom, Top + Height - OffsetTop);

                        //Copies from the screen texture only the area which the user wants to capture.
                        if (right > left && bottom > top)
                        {
                            //Limit the source rectangle to the available size within the destination rectangle.
                            var sourceWidth  = movedRectangles[movedIndex].SourcePoint.X + (right - left);
                            var sourceHeight = movedRectangles[movedIndex].SourcePoint.Y + (bottom - top);

                            Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0,
                                                                          new ResourceRegion(movedRectangles[movedIndex].SourcePoint.X, movedRectangles[movedIndex].SourcePoint.Y, 0, sourceWidth, sourceHeight, 1),
                                                                          BackingTexture, 0, left - (Left - OffsetLeft), top - (Top - OffsetTop));
                        }
                    }

                    #endregion

                    #region Dirty rectangles

                    var dirtyRectangles = new RawRectangle[info.TotalMetadataBufferSize];
                    DuplicatedOutput.GetFrameDirtyRects(dirtyRectangles.Length, dirtyRectangles, out var dirtyRegionsLength);

                    for (var dirtyIndex = 0; dirtyIndex < dirtyRegionsLength / Marshal.SizeOf(typeof(RawRectangle)); dirtyIndex++)
                    {
                        //Crop screen positions and size to frame sizes.
                        var left   = Math.Max(dirtyRectangles[dirtyIndex].Left, Left - OffsetLeft);
                        var right  = Math.Min(dirtyRectangles[dirtyIndex].Right, Left + Width - OffsetLeft);
                        var top    = Math.Max(dirtyRectangles[dirtyIndex].Top, Top - OffsetTop);
                        var bottom = Math.Min(dirtyRectangles[dirtyIndex].Bottom, Top + Height - OffsetTop);

                        //Copies from the screen texture only the area which the user wants to capture.
                        if (right > left && bottom > top)
                        {
                            Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0, new ResourceRegion(left, top, 0, right, bottom, 1), BackingTexture, 0, left - (Left - OffsetLeft), top - (Top - OffsetTop));
                        }
                    }

                    #endregion
                }
            }

            if (info.TotalMetadataBufferSize > 0 || info.LastMouseUpdateTime > 0)
            {
                //Copy the captured desktop texture into a staging texture, in order to show the mouse cursor and not make the captured texture dirty with it.
                Device.ImmediateContext.CopyResource(BackingTexture, StagingTexture);

                //Gets the cursor image and merges with the staging texture.
                GetCursor(StagingTexture, info, frame);
            }

            //Saves the most recent capture time.
            LastProcessTime = Math.Max(info.LastPresentTime, info.LastMouseUpdateTime);

            #endregion

            #region Gets the image data

            //Get the desktop capture texture.
            var data = Device.ImmediateContext.MapSubresource(StagingTexture, 0, MapMode.Read, MapFlags.None);

            if (data.IsEmpty)
            {
                Device.ImmediateContext.UnmapSubresource(StagingTexture, 0);
                resource?.Dispose();
                return(FrameCount);
            }

            var bitmap     = new System.Drawing.Bitmap(Width, Height, PixelFormat.Format32bppArgb);
            var boundsRect = new System.Drawing.Rectangle(0, 0, Width, Height);

            //Copy pixels from screen capture Texture to the GDI bitmap.
            var mapDest   = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
            var sourcePtr = data.DataPointer;
            var destPtr   = mapDest.Scan0;

            for (var y = 0; y < Height; y++)
            {
                //Copy a single line.
                Utilities.CopyMemory(destPtr, sourcePtr, Width * 4);

                //Advance pointers.
                sourcePtr = IntPtr.Add(sourcePtr, data.RowPitch);
                destPtr   = IntPtr.Add(destPtr, mapDest.Stride);
            }

            //Releases the source and dest locks.
            bitmap.UnlockBits(mapDest);

            //Set frame details.
            FrameCount++;
            frame.Path  = $"{Project.FullPath}{FrameCount}.png";
            frame.Delay = FrameRate.GetMilliseconds();
            frame.Image = bitmap;

            if (IsAcceptingFrames)
            {
                BlockingCollection.Add(frame);
            }

            #endregion

            Device.ImmediateContext?.UnmapSubresource(StagingTexture, 0);

            resource?.Dispose();
            return(FrameCount);
        }
        catch (SharpDXException se) when(se.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
        {
            return(FrameCount);
        }
        catch (SharpDXException se) when(se.ResultCode.Code == SharpDX.DXGI.ResultCode.DeviceRemoved.Result.Code || se.ResultCode.Code == SharpDX.DXGI.ResultCode.DeviceReset.Result.Code)
        {
            //When the device gets lost or reset, the resources should be instantiated again.
            DisposeInternal();
            Initialize();

            return(FrameCount);
        }
        catch (Exception ex)
        {
            LogWriter.Log(ex, "It was not possible to finish capturing the frame with DirectX.");

            MajorCrashHappened = true;

            if (IsAcceptingFrames)
            {
                Application.Current.Dispatcher.Invoke(() => OnError.Invoke(ex));
            }

            return(FrameCount);
        }
        finally
        {
            try
            {
                //Only release the frame if there was a success in capturing it.
                if (res.Success)
                {
                    DuplicatedOutput.ReleaseFrame();
                }
            }
            catch (Exception e)
            {
                LogWriter.Log(e, "It was not possible to release the frame.");
            }
        }
    }
    public override int Capture(FrameInfo frame)
    {
        var res = new Result(-1);

        try
        {
            //Try to get the duplicated output frame within given time.
            res = DuplicatedOutput.TryAcquireNextFrame(0, out var info, out var resource);

            if (FrameCount == 0 && (res.Failure || resource == null))
            {
                //Somehow, it was not possible to retrieve the resource, frame or metadata.
                resource?.Dispose();
                return(FrameCount);
            }

            #region Process changes

            //Something on screen was moved or changed.
            if (info.TotalMetadataBufferSize > 0)
            {
                //Copy resource into memory that can be accessed by the CPU.
                using (var screenTexture = resource.QueryInterface <Texture2D>())
                {
                    #region Moved rectangles

                    var movedRectangles = new OutputDuplicateMoveRectangle[info.TotalMetadataBufferSize];
                    DuplicatedOutput.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out var movedRegionsLength);

                    for (var movedIndex = 0; movedIndex < movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle)); movedIndex++)
                    {
                        //Crop the destination rectangle to the screen area rectangle.
                        var left   = Math.Max(movedRectangles[movedIndex].DestinationRect.Left, Left - OffsetLeft);
                        var right  = Math.Min(movedRectangles[movedIndex].DestinationRect.Right, Left + Width - OffsetLeft);
                        var top    = Math.Max(movedRectangles[movedIndex].DestinationRect.Top, Top - OffsetTop);
                        var bottom = Math.Min(movedRectangles[movedIndex].DestinationRect.Bottom, Top + Height - OffsetTop);

                        //Copies from the screen texture only the area which the user wants to capture.
                        if (right > left && bottom > top)
                        {
                            //Limit the source rectangle to the available size within the destination rectangle.
                            var sourceWidth  = movedRectangles[movedIndex].SourcePoint.X + (right - left);
                            var sourceHeight = movedRectangles[movedIndex].SourcePoint.Y + (bottom - top);

                            Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0,
                                                                          new ResourceRegion(movedRectangles[movedIndex].SourcePoint.X, movedRectangles[movedIndex].SourcePoint.Y, 0, sourceWidth, sourceHeight, 1),
                                                                          StagingTexture, 0, left - (Left - OffsetLeft), top - (Top - OffsetTop));
                        }
                    }

                    #endregion

                    #region Dirty rectangles

                    var dirtyRectangles = new RawRectangle[info.TotalMetadataBufferSize];
                    DuplicatedOutput.GetFrameDirtyRects(dirtyRectangles.Length, dirtyRectangles, out var dirtyRegionsLength);

                    for (var dirtyIndex = 0; dirtyIndex < dirtyRegionsLength / Marshal.SizeOf(typeof(RawRectangle)); dirtyIndex++)
                    {
                        //Crop screen positions and size to frame sizes.
                        var left   = Math.Max(dirtyRectangles[dirtyIndex].Left, Left - OffsetLeft);
                        var right  = Math.Min(dirtyRectangles[dirtyIndex].Right, Left + Width - OffsetLeft);
                        var top    = Math.Max(dirtyRectangles[dirtyIndex].Top, Top - OffsetTop);
                        var bottom = Math.Min(dirtyRectangles[dirtyIndex].Bottom, Top + Height - OffsetTop);

                        //Copies from the screen texture only the area which the user wants to capture.
                        if (right > left && bottom > top)
                        {
                            Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0, new ResourceRegion(left, top, 0, right, bottom, 1), StagingTexture, 0, left - (Left - OffsetLeft), top - (Top - OffsetTop));
                        }
                    }

                    #endregion
                }
            }

            #endregion

            #region Gets the image data

            //Gets the staging texture as a stream.
            var data = Device.ImmediateContext.MapSubresource(StagingTexture, 0, MapMode.Read, MapFlags.None, out var stream);

            if (data.IsEmpty)
            {
                Device.ImmediateContext.UnmapSubresource(StagingTexture, 0);
                stream?.Dispose();
                resource?.Dispose();
                return(FrameCount);
            }

            //Set frame details.
            FrameCount++;
            frame.Path       = $"{Project.FullPath}{FrameCount}.png";
            frame.Delay      = FrameRate.GetMilliseconds();
            frame.DataLength = stream.Length;
            frame.Data       = new byte[stream.Length];

            //BGRA32 is 4 bytes.
            for (var height = 0; height < Height; height++)
            {
                stream.Position = height * data.RowPitch;
                Marshal.Copy(new IntPtr(stream.DataPointer.ToInt64() + height * data.RowPitch), frame.Data, height * Width * 4, Width * 4);
            }

            if (IsAcceptingFrames)
            {
                BlockingCollection.Add(frame);
            }

            #endregion

            Device.ImmediateContext?.UnmapSubresource(StagingTexture, 0);

            resource?.Dispose();
            return(FrameCount);
        }
        catch (SharpDXException se) when(se.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
        {
            return(FrameCount);
        }
        catch (SharpDXException se) when(se.ResultCode.Code == SharpDX.DXGI.ResultCode.DeviceRemoved.Result.Code || se.ResultCode.Code == SharpDX.DXGI.ResultCode.DeviceReset.Result.Code)
        {
            //When the device gets lost or reset, the resources should be instantiated again.
            DisposeInternal();
            Initialize();

            return(FrameCount);
        }
        catch (Exception ex)
        {
            LogWriter.Log(ex, "It was not possible to finish capturing the frame with DirectX.");

            MajorCrashHappened = true;

            if (IsAcceptingFrames)
            {
                Application.Current.Dispatcher.Invoke(() => OnError.Invoke(ex));
            }

            return(FrameCount);
        }
        finally
        {
            try
            {
                //Only release the frame if there was a sucess in capturing it.
                if (res.Success)
                {
                    DuplicatedOutput.ReleaseFrame();
                }
            }
            catch (Exception e)
            {
                LogWriter.Log(e, "It was not possible to release the frame.");
            }
        }
    }
        private void ProcessMoveRegions()
        {
            var numberOfBytes = 0;
            var rectangles = new OutputDuplicateMoveRectangle[_frameInfo.TotalMetadataBufferSize];

            if (_frameInfo.TotalMetadataBufferSize > 0)
            {
                _outputDuplication.GetFrameMoveRects(rectangles.Length, rectangles, out numberOfBytes);
            }

            _frame.MovedRegions = new ScreenFrameRegion[numberOfBytes / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))];

            for (var i = 0; i < _frame.MovedRegions.Length; i++)
            {
                _frame.MovedRegions[i].Destination.Bottom = rectangles[i].DestinationRect.Bottom;
                _frame.MovedRegions[i].Destination.Left = rectangles[i].DestinationRect.Left;
                _frame.MovedRegions[i].Destination.Right = rectangles[i].DestinationRect.Right;
                _frame.MovedRegions[i].Destination.Top = rectangles[i].DestinationRect.Top;
                _frame.MovedRegions[i].X = rectangles[i].SourcePoint.X;
                _frame.MovedRegions[i].Y = rectangles[i].SourcePoint.Y;
            }
        }
        private void RetrieveFrameMetadata(DesktopFrame frame)
        {

            if (frameInfo.TotalMetadataBufferSize > 0)
            {
                // Get moved regions
                int movedRegionsLength = 0;
                OutputDuplicateMoveRectangle[] movedRectangles = new OutputDuplicateMoveRectangle[frameInfo.TotalMetadataBufferSize];
                mDeskDupl.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out movedRegionsLength);
                frame.MovedRegions = new MovedRegion[movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))];
                for (int i = 0; i < frame.MovedRegions.Length; i++)
                {
                    frame.MovedRegions[i] = new MovedRegion()
                    {
                        Source = new System.Drawing.Point(movedRectangles[i].SourcePoint.X, movedRectangles[i].SourcePoint.Y),
                        Destination = new System.Drawing.Rectangle(movedRectangles[i].DestinationRect.X, movedRectangles[i].DestinationRect.Y, movedRectangles[i].DestinationRect.Width, movedRectangles[i].DestinationRect.Height)
                    };
                }

                // Get dirty regions
                int dirtyRegionsLength = 0;
                Rectangle[] dirtyRectangles = new Rectangle[frameInfo.TotalMetadataBufferSize];
                mDeskDupl.GetFrameDirtyRects(dirtyRectangles.Length, dirtyRectangles, out dirtyRegionsLength);
                frame.UpdatedRegions = new System.Drawing.Rectangle[dirtyRegionsLength / Marshal.SizeOf(typeof(Rectangle))];
                for (int i = 0; i < frame.UpdatedRegions.Length; i++)
                {
                    frame.UpdatedRegions[i] = new System.Drawing.Rectangle(dirtyRectangles[i].X, dirtyRectangles[i].Y, dirtyRectangles[i].Width, dirtyRectangles[i].Height);
                }
            }
            else
            {
                frame.MovedRegions = new MovedRegion[0];
                frame.UpdatedRegions = new System.Drawing.Rectangle[0];
            }
        }
        //set appropriate source and destination rects for move rects
        private void SetMoveRect(ref Rectangle srcRect, ref Rectangle destRect, OutputDescription desktopDescription,
                                 OutputDuplicateMoveRectangle moveRect, int texWidth, int texHeight)
        {
            switch (desktopDescription.Rotation)
            {
            case DisplayModeRotation.Unspecified:
            case DisplayModeRotation.Identity:
            {
                srcRect.Left  = moveRect.SourcePoint.X;
                srcRect.Top   = moveRect.SourcePoint.Y;
                srcRect.Right = moveRect.SourcePoint.X + moveRect.DestinationRect.Right -
                                moveRect.DestinationRect.Left;
                srcRect.Bottom = moveRect.SourcePoint.Y + moveRect.DestinationRect.Bottom -
                                 moveRect.DestinationRect.Top;

                destRect = moveRect.DestinationRect;
                break;
            }

            case DisplayModeRotation.Rotate90:
            {
                srcRect.Left =
                    texHeight -
                    (moveRect.SourcePoint.Y + moveRect.DestinationRect.Bottom - moveRect.DestinationRect.Top);
                srcRect.Top    = moveRect.SourcePoint.X;
                srcRect.Right  = texHeight - moveRect.SourcePoint.Y;
                srcRect.Bottom =
                    moveRect.SourcePoint.X + moveRect.DestinationRect.Right - moveRect.DestinationRect.Left;

                destRect.Left   = texHeight - moveRect.DestinationRect.Bottom;
                destRect.Top    = moveRect.DestinationRect.Left;
                destRect.Right  = texHeight - moveRect.DestinationRect.Top;
                destRect.Bottom = moveRect.DestinationRect.Right;

                break;
            }

            case DisplayModeRotation.Rotate180:
            {
                srcRect.Left = texHeight -
                               (moveRect.SourcePoint.X + moveRect.DestinationRect.Right -
                                moveRect.DestinationRect.Left);
                srcRect.Top = texHeight -
                              (moveRect.SourcePoint.Y + moveRect.DestinationRect.Bottom -
                               moveRect.DestinationRect.Top);
                srcRect.Right  = texWidth - moveRect.SourcePoint.X;
                srcRect.Bottom = texHeight - moveRect.SourcePoint.Y;

                destRect.Left   = texWidth - moveRect.DestinationRect.Right;
                destRect.Top    = texHeight - moveRect.DestinationRect.Bottom;
                destRect.Right  = texWidth - moveRect.DestinationRect.Left;
                destRect.Bottom = texHeight - moveRect.DestinationRect.Top;
                break;
            }

            case DisplayModeRotation.Rotate270:
            {
                srcRect.Left = moveRect.SourcePoint.X;
                srcRect.Top  = texWidth -
                               (moveRect.SourcePoint.X + moveRect.DestinationRect.Right -
                                moveRect.DestinationRect.Left);
                srcRect.Right = moveRect.SourcePoint.Y + moveRect.DestinationRect.Bottom -
                                moveRect.DestinationRect.Top;
                srcRect.Bottom = texWidth - moveRect.SourcePoint.X;

                destRect.Left   = moveRect.DestinationRect.Top;
                destRect.Top    = texWidth - moveRect.DestinationRect.Right;
                destRect.Right  = moveRect.DestinationRect.Bottom;
                destRect.Bottom = texWidth - moveRect.DestinationRect.Left;
                break;
            }

            default:
            {
                destRect = new Rectangle();
                srcRect  = new Rectangle();
                break;
            }
            }
        }
Exemple #13
0
        public RemoteDesktopDataInfo CaptureScreen(IStreamCodec streamCodec, ICursorStreamCodec cursorStreamCodec, bool updateCursor)
        {
            //Debug.Print("_desktopDupl == null: " + (_deskDupl == null));
            if (!RetrieveFrame())
            {
                return(null);
            }

            // Get the desktop capture texture
            var mapSource = _device.ImmediateContext.MapSubresource(_desktopImageTexture, 0, MapMode.Read,
                                                                    MapFlags.None);

            try
            {
                if (updateCursor)
                {
                    _screenHelper.UpdateCursor(cursorStreamCodec, _currentMonitor);
                }
#if FALSE
                if (updateCursor)
                {
                    cursorStreamCodec.UpdateCursorInfo(_frameInfo.PointerPosition.Position.X,
                                                       _frameInfo.PointerPosition.Position.Y, _frameInfo.PointerPosition.Visible);

                    if (_frameInfo.LastMouseUpdateTime != 0 && _frameInfo.PointerShapeBufferSize > 0)
                    {
                        var buffer = new byte[_frameInfo.PointerShapeBufferSize];

                        unsafe
                        {
                            fixed(byte *ptrShapeBufferPtr = buffer)
                            {
                                int bufferSize;
                                OutputDuplicatePointerShapeInformation shapeInfo;

                                _deskDupl.GetFramePointerShape(_frameInfo.PointerShapeBufferSize,
                                                               (IntPtr)ptrShapeBufferPtr, out bufferSize, out shapeInfo);

                                switch (shapeInfo.Type)
                                {
                                case 0x1:     //DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME
                                    var size = Image.GetPixelFormatSize(PixelFormat.Format1bppIndexed);
                                    //var bitmap = new Bitmap(32, 32, 4, PixelFormat.Format1bppIndexed, (IntPtr)ptrShapeBufferPtr);
                                    cursorStreamCodec.UpdateCursorImage((IntPtr)ptrShapeBufferPtr,
                                                                        shapeInfo.Pitch, 32, 32,
                                                                        PixelFormat.Format1bppIndexed);
                                    Debug.Print("DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME");
                                    break;

                                case 0x2:     //DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR
                                    cursorStreamCodec.UpdateCursorImage((IntPtr)ptrShapeBufferPtr,
                                                                        shapeInfo.Pitch, shapeInfo.Width, shapeInfo.Height,
                                                                        PixelFormat.Format32bppArgb);
                                    Debug.Print("DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR");
                                    break;

                                case 0x4:     //DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR
                                    Debug.Print("DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR");
                                    break;
                                }
                            }
                        }
                    }
                }
#endif

                if (_frameInfo.TotalMetadataBufferSize > 0)
                {
                    int movedRegionsLength;
                    OutputDuplicateMoveRectangle[] movedRectangles =
                        new OutputDuplicateMoveRectangle[_frameInfo.TotalMetadataBufferSize];
                    _deskDupl.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out movedRegionsLength);
                    var movedRegions =
                        new MovedRegion[movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))];

                    for (int i = 0; i < movedRegions.Length; i++)
                    {
                        var moveRectangle = movedRectangles[i];
                        movedRegions[i] = new MovedRegion
                        {
                            Source      = new Point(moveRectangle.SourcePoint.X, moveRectangle.SourcePoint.Y),
                            Destination =
                                new Rectangle(moveRectangle.DestinationRect.Left,
                                              moveRectangle.DestinationRect.Top,
                                              moveRectangle.DestinationRect.GetWidth(),
                                              moveRectangle.DestinationRect.GetHeight())
                        };
                    }

                    int dirtyRegionsLength;
                    var dirtyRectangles = new RawRectangle[_frameInfo.TotalMetadataBufferSize - movedRegionsLength];
                    _deskDupl.GetFrameDirtyRects(dirtyRectangles.Length, dirtyRectangles, out dirtyRegionsLength);
                    var updatedAreas = new Rectangle[dirtyRegionsLength / Marshal.SizeOf(typeof(Rectangle))];

                    for (int i = 0; i < updatedAreas.Length; i++)
                    {
                        var dirtyRectangle = dirtyRectangles[i];
                        updatedAreas[i] = new Rectangle(dirtyRectangle.Left, dirtyRectangle.Top,
                                                        dirtyRectangle.GetWidth(), dirtyRectangle.GetHeight());
                    }

                    return(streamCodec.CodeImage(mapSource.DataPointer, updatedAreas, movedRegions,
                                                 new Size(_outputDesc.DesktopBounds.GetWidth(), _outputDesc.DesktopBounds.GetHeight()),
                                                 PixelFormat.Format32bppArgb));
                }
                else
                {
                    return(streamCodec.CodeImage(mapSource.DataPointer,
                                                 new Rectangle(0, 0, _outputDesc.DesktopBounds.GetWidth(), _outputDesc.DesktopBounds.GetHeight()),
                                                 new Size(_outputDesc.DesktopBounds.GetWidth(), _outputDesc.DesktopBounds.GetHeight()),
                                                 PixelFormat.Format32bppArgb));
                }
            }
            finally
            {
                _device.ImmediateContext.UnmapSubresource(_desktopImageTexture, 0);
                ReleaseFrame();
            }
        }