예제 #1
0
        /// <summary>
        /// Captures a screenshot. Remember, you should always use this class from the same thread.
        /// </summary>
        /// <returns></returns>
        public FragmentedImage Capture(SHRDLib.NetCommand.DesktopScreen screen)
        {
            if (screen == null)
            {
                throw new NullReferenceException("screen cannot be null");
            }
            long thisMs = timing.ElapsedMilliseconds;

            // Learn about the display configuration
            if (displaySettingsChanged)
            {
                displaySettingsChanged = false;
                ClearCaptureHandle();
                DesktopManager.ShouldReassociate = true;
            }
            if (DesktopManager.ShouldReassociate || thisMs > nextDesktopCheck)
            {
                DesktopManager.ShouldReassociate = false;
                nextDesktopCheck = thisMs + desktopCheckInterval;
                if (DesktopManager.AssociateCurrentThreadWithDefaultDesktop())
                {
                    ClearCaptureHandle();                     // Desktop was changed.
                }
            }
            // Capture
            Screenshot screenshot = CaptureScreenshot(screen.X, screen.Y, screen.Width, screen.Height);

            if (screenshot == null)
            {
                return(new FragmentedImage());
            }
            FragmentedImage img = new FragmentedImage(new MovedImageFragment[0], new DirtyImageFragment[] { new DirtyImageFragment(screen.Y, screen.X + screen.Width, screen.Height + screen.Y, screen.X, screenshot) });

            return(img);
        }
        private void streamLoop_inner(object objArgs)
        {
            Stopwatch frameTimer = new Stopwatch();

            frameTimer.Start();
            long             nextFrameStart = 0;
            StreamThreadArgs args           = (StreamThreadArgs)objArgs;

            while (!args.abortFlag.abort)
            {
                try
                {
                    int sleepTime = (int)(nextFrameStart - frameTimer.ElapsedMilliseconds);
                    while (sleepTime > 0 || (Interlocked.Read(ref args.numSentFrames) >= Interlocked.Read(ref args.numAcknowledgedFrames) + maxUnacknowledgedFrames))
                    {
                        if (args.abortFlag.abort)
                        {
                            return;
                        }
                        Thread.Sleep(BPMath.Clamp(sleepTime, 1, 10));
                        sleepTime = (int)(nextFrameStart - frameTimer.ElapsedMilliseconds);
                    }
                    if (args.abortFlag.abort)
                    {
                        return;
                    }

                    nextFrameStart = frameTimer.ElapsedMilliseconds + (1000 / maxFPS);

                    if (streamerController == null)
                    {
                        return;
                    }
                    FragmentedImage fragmentedImage = streamerController.GetRawDesktopCapture(imgFlags, jpegQuality, args.abortFlag);
                    if (args.abortFlag.abort)
                    {
                        return;
                    }
                    if (fragmentedImage == null)
                    {
                        fragmentedImage = new FragmentedImage();
                    }
                    fragmentedImage.streamId = (byte)args.myStreamNumber;
                    using (MemoryDataStream mds = new MemoryDataStream(fragmentedImage.GetMaximumRequiredBufferSize()))
                    {
                        byte[] compressionBuffer = null;
                        fragmentedImage.WriteToDataStream(mds, ref compressionBuffer);
                        Interlocked.Increment(ref args.numSentFrames);
                        socket.Send(mds.ToArray());
                    }
                }
                catch (ThreadAbortException) { throw; }
                catch (Exception ex)
                {
                    Logger.Debug(ex);
                }
            }
        }
예제 #3
0
 private static void desktopCaptureThreadRunner()
 {
     try
     {
         byte[] compressToBuffer = null;
         while (!isExiting && static_sm != null)
         {
             Thread.Sleep(1);
             DesktopCaptureTask task;
             while (!isExiting && static_sm != null && desktopCaptureTasks.TryDequeue(out task))
             {
                 turbojpegCLI.SubsamplingOption subsamp = GetSubsamplingOptionFromImgFlags(task.imgFlags);
                 FragmentedImage    img = CaptureRawDesktopImage(task.imgFlags.HasFlag(ImgFlags.Refresh));
                 SharedMemoryStream sm  = static_sm;
                 if (sm == null)
                 {
                     break;
                 }
                 lock (sm)
                 {
                     img.WriteToDataStream(static_sm, ref compressToBuffer, task.jpegQuality, subsamp);
                 }
             }
         }
     }
     catch (ThreadAbortException) { }
     catch (StreamDisconnectedException ex)
     {
         Logger.Info("Exiting because: " + ex.Message);
     }
     catch (Exception ex)
     {
         Logger.Debug(ex);
         Logger.Info("Exiting due to main thread runner exception");
     }
     finally
     {
         Try.Catch(() => { dxgiDuplicator?.Dispose(); });
         Try.Catch(() => { screenCapturer?.Dispose(); });
         //Try.Catch(() => { inputEmulator?.Dispose(); });
         RobustExit();
     }
 }
예제 #4
0
        private static FragmentedImage CaptureRawDesktopImage(bool fullFrame)
        {
            if (DxgiOutputDuplicator.CurrentOSSupportsThisMethod)
            {
                bool proceedWithFastMethod = true;
                if (compatibleDesktopCaptureModeClock.IsRunning)
                {
                    if (compatibleDesktopCaptureModeClock.ElapsedMilliseconds < timeToUseCompatibleDesktopCaptureMode)
                    {
                        proceedWithFastMethod = false;                         // Not enough time has passed. Keep using compatible method.
                    }
                    else
                    {
                        compatibleDesktopCaptureModeClock.Reset();                         // time is up -- we can try fast mode again
                        Logger.Info("Switching back to fast desktop capture mode");
                    }
                }

                if (proceedWithFastMethod)
                {
                    if (fullFrame)
                    {
                        dxgiDuplicator.ResetOutputDuplicator();
                    }

                    FragmentedImage imgFast = dxgiDuplicator.Capture();
                    if (imgFast != null)
                    {
                        return(imgFast);
                    }
                    // Most likely the console session is logging off, at the login screen, or just logged on and hasn't initialized the necessary directx parts yet.
                    // Switch to the compatible capture mode for a while.
                    compatibleDesktopCaptureModeClock.Start();
                    Logger.Info("Switching to compatible desktop capture mode for next " + timeToUseCompatibleDesktopCaptureMode + " ms");
                }
            }
            // If we get here, we need to use a more-compatible capture method because we are probably at the login screen.
            FragmentedImage imgCompatible = screenCapturer.Capture(desktopInfo.GetScreen(0, 0));

            return(imgCompatible);
        }
예제 #5
0
        public FragmentedImage Capture()
        {
            if (duplicatedOutput == null && !ResetOutputDuplicator())
            {
                return(null);
            }
            OutputDuplicateFrameInformation frameInfo;

            SharpDX.DXGI.Resource screenResource = null;
            bool success = false;

            try
            {
                int frameDisposeFailures = 0;
                while (true)
                {
                    try
                    {
                        screenResource = null;
                        duplicatedOutput.AcquireNextFrame(10000, out frameInfo, out screenResource);
                        if (frameInfo.AccumulatedFrames > 0)
                        {
                            if (screenResource == null)
                            {
                                Logger.Debug("screenResource was null in DxgiOutputDuplicator");
                                return(null);
                            }

                            // Copy the texture so we can access the pixel data of the copy
                            using (Texture2D screenTexture2D = screenResource.QueryInterface <Texture2D>())
                                device.ImmediateContext.CopyResource(screenTexture2D, screenTexture);


                            // Learn which rectangles moved
                            OutputDuplicateMoveRectangle[] moveRects = GetMoveRectangles();

                            // Learn which rectangles were made dirty
                            RawRectangle[] dirtyRects = GetDirtyRectangles();

                            FragmentedImage img = new FragmentedImage(new MovedImageFragment[moveRects.Length], new DirtyImageFragment[dirtyRects.Length]);
                            int             i   = 0;
                            foreach (OutputDuplicateMoveRectangle moveRect in moveRects)
                            {
                                img.movedFragments[i++] = new MovedImageFragment(
                                    moveRect.DestinationRect.Top
                                    , moveRect.DestinationRect.Right
                                    , moveRect.DestinationRect.Bottom
                                    , moveRect.DestinationRect.Left
                                    , moveRect.SourcePoint.X
                                    , moveRect.SourcePoint.Y);
                            }

                            // Get the desktop capture pixel data
                            i = 0;
                            DataBox mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, MapFlags.None);
                            foreach (RawRectangle dirtyRect in dirtyRects)
                            {
                                Screenshot screenshot = new Screenshot(dirtyRect.Right - dirtyRect.Left, dirtyRect.Bottom - dirtyRect.Top, 32);
                                IntPtr     source     = mapSource.DataPointer;
                                source += dirtyRect.Top * mapSource.RowPitch;                 // Offset source to the correct row
                                source += dirtyRect.Left * 4;                                 // Offset source to the correct column
                                int destOffset = 0;
                                for (int y = dirtyRect.Top; y < dirtyRect.Bottom; y++)
                                {
                                    Marshal.Copy(source, screenshot.Buffer, destOffset, screenshot.Stride);
                                    source     += mapSource.RowPitch;
                                    destOffset += screenshot.Stride;
                                }

                                img.dirtyFragments[i++] = new DirtyImageFragment(
                                    dirtyRect.Top
                                    , dirtyRect.Right
                                    , dirtyRect.Bottom
                                    , dirtyRect.Left
                                    , screenshot);
                            }
                            device.ImmediateContext.UnmapSubresource(screenTexture, 0);
                            //DebugDrawRects(screenshot, moveRects, dirtyRects);

                            success = true;
                            return(img);
                        }
                    }
                    catch (SharpDXException e)
                    {
                        if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
                        {
                            throw e;
                        }
                    }
                    finally
                    {
                        if (screenResource != null)
                        {
                            try
                            {
                                screenResource.Dispose();
                                duplicatedOutput.ReleaseFrame();
                            }
                            catch
                            {
                                if (++frameDisposeFailures > 2)
                                {
                                    throw;
                                }
                                ResetOutputDuplicator();
                            }
                        }
                    }
                }
            }
            finally
            {
                if (!success)
                {
                    DestroyOutputDuplicator();
                }
            }
            // TODO: Delete cursor drawing stuff.
            //{
            //	IntPtr dc = _renderSurface.GetDC(new RawBool(true));
            //	NativeMethods.SelectObject(_hdc, dc);
            //	NativeMethods.BitBlt(dc, 0, 0, bounds.Right - bounds.Left
            //		, bounds.Bottom - bounds.Top, _hdc, bounds.Left
            //		, bounds.Top, System.Drawing.CopyPixelOperation.SourceCopy);
            //	NativeMethods.CURSORINFO pci;
            //	pci.cbSize = NativeMethods.SizeOfCursorInfo;
            //	if (NativeMethods.GetCursorInfo(out pci) && pci.flags > 0)
            //		NativeMethods.DrawIcon(dc, pci.ptScreenPos.X, pci.ptScreenPos.Y, pci.hCursor);
            //	_renderSurface.ReleaseDC();
            //	return null;
            //}
        }