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 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); }
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 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]; } }
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; } } }
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(); } }