diff --git a/src/main/java/org/dpsoftware/config/Constants.java b/src/main/java/org/dpsoftware/config/Constants.java index 078212a1..6a3a58c5 100644 --- a/src/main/java/org/dpsoftware/config/Constants.java +++ b/src/main/java/org/dpsoftware/config/Constants.java @@ -480,11 +480,6 @@ public class Constants { public static final String INTERNAL_SCALING_Y = "INTERNAL_SCALING_Y"; public static final int RESAMPLING_FACTOR = 4; public static final String EMIT_SIGNALS = "emit-signals"; - public static final String GSTREAMER_PIPELINE_DDUPL_SM = "video/x-raw(memory:SystemMemory),width=INTERNAL_SCALING_X,height=INTERNAL_SCALING_Y,sync=false,"; - public static final String GSTREAMER_PIPELINE_DDUPL = "video/x-raw(memory:D3D11Memory),width=INTERNAL_SCALING_X,height=INTERNAL_SCALING_Y,sync=false,"; - public static final String GSTREAMER_PIPELINE = "video/x-raw,width=INTERNAL_SCALING_X,height=INTERNAL_SCALING_Y,sync=false,"; - public static final String BYTE_ORDER_BGR = "format=BGRx"; - public static final String BYTE_ORDER_RGB = "format=xRGB"; public static final String WIDTH = "width"; public static final String HEIGHT = "height"; public static final String GSTREAMER_PATH = "/gstreamer/1.0/mingw_x86_64/bin"; @@ -497,13 +492,18 @@ public class Constants { // ./gst-launch-1.0 d3d11screencapturesrc ! d3d11convert ! "video/x-raw(memory:D3D11Memory),width=800,height=600,sync=false" ! autovideosink // ./gst-launch-1.0 d3d11screencapturesrc ! d3d11convert ! d3d11download ! "video/x-raw(memory:SystemMemory),width=480,height=270,sync=false" ! autovideosink // ./gst-launch-1.0 ximagesrc startx=0 endx=3839 starty=0 endy=2159 use-damage=0 ! videoscale ! videoconvert ! autovideosink - public static final String GSTREAMER_PIPELINE_WINDOWS_HARDWARE_HANDLE_SM = "d3d11screencapturesrc monitor-handle={0} ! d3d11convert ! d3d11download"; + // public static final String GSTREAMER_PIPELINE_WINDOWS_HARDWARE_HANDLE_CPU_SCALING = "d3d11screencapturesrc monitor-handle={0} ! d3d11convert ! d3d11download"; public static final String GSTREAMER_PIPELINE_WINDOWS_HARDWARE_HANDLE = "d3d11screencapturesrc monitor-handle={0} ! d3d11convert"; public static final String GSTREAMER_PIPELINE_XIMAGESRC = "ximagesrc startx={0} endx={1} starty={2} endy={3} use-damage=0 ! videoscale ! videoconvert"; public static final String GSTREAMER_PIPELINE_XIMAGESRC_CUDA = "ximagesrc startx={0} endx={1} starty={2} endy={3} use-damage=0 ! cudaupload ! cudascale ! cudaconvert ! cudadownload"; public static final String GSTREAMER_PIPELINE_PIPEWIREXDG = "pipewiresrc fd={1} path={2} ! videorate ! videoscale ! videoconvert"; public static final String GSTREAMER_PIPELINE_PIPEWIREXDG_CUDA = "pipewiresrc fd={1} path={2} ! videorate ! cudaupload ! cudascale ! cudaconvert ! cudadownload"; public static final String GSTREAMER_PIPELINE_MAC = "avfvideosrc capture-screen=true ! videoscale ! videoconvert"; + // public static final String GSTREAMER_PIPELINE_DDUPL_CPU_SCALING = "video/x-raw(memory:SystemMemory),width=INTERNAL_SCALING_X,height=INTERNAL_SCALING_Y,sync=false,"; + public static final String GSTREAMER_PIPELINE_DDUPL = "video/x-raw(memory:D3D11Memory),width=INTERNAL_SCALING_X,height=INTERNAL_SCALING_Y,sync=false,"; + public static final String GSTREAMER_PIPELINE = "video/x-raw,width=INTERNAL_SCALING_X,height=INTERNAL_SCALING_Y,sync=false,"; + public static final String BYTE_ORDER_BGR = "format=BGRx"; + public static final String BYTE_ORDER_RGB = "format=xRGB"; public static final String FRAMERATE_PLACEHOLDER = "framerate=FRAMERATE_PLACEHOLDER/1,"; public static final String FPS_PLACEHOLDER = "FRAMERATE_PLACEHOLDER"; public static final String GSTREAMER_SCREENSHOT = "gstreamer_screenshot.bmp"; diff --git a/src/main/java/org/dpsoftware/grabber/GStreamerGrabber.java b/src/main/java/org/dpsoftware/grabber/GStreamerGrabber.java index 9d8a0cb8..b4ad8f98 100644 --- a/src/main/java/org/dpsoftware/grabber/GStreamerGrabber.java +++ b/src/main/java/org/dpsoftware/grabber/GStreamerGrabber.java @@ -84,16 +84,10 @@ public GStreamerGrabber(AppSink appsink) { videosink.connect(listener); String gstreamerPipeline; if (MainSingleton.getInstance().config.getCaptureMethod().equals(Configuration.CaptureMethod.DDUPL.name())) { - // Scale image inside the GPU by RESAMPLING_FACTOR, Constants.GSTREAMER_MEMORY_DIVIDER tells if resolution is compatible with D3D11Memory with no padding. - if (!GrabberSingleton.getInstance().isFallbackPipeline()) { - gstreamerPipeline = Constants.GSTREAMER_PIPELINE_DDUPL - .replace(Constants.INTERNAL_SCALING_X, String.valueOf(MainSingleton.getInstance().config.getScreenResX() / Constants.RESAMPLING_FACTOR)) - .replace(Constants.INTERNAL_SCALING_Y, String.valueOf(MainSingleton.getInstance().config.getScreenResY() / Constants.RESAMPLING_FACTOR)); - } else { - gstreamerPipeline = Constants.GSTREAMER_PIPELINE_DDUPL_SM - .replace(Constants.INTERNAL_SCALING_X, String.valueOf(MainSingleton.getInstance().config.getScreenResX() / Constants.RESAMPLING_FACTOR)) - .replace(Constants.INTERNAL_SCALING_Y, String.valueOf(MainSingleton.getInstance().config.getScreenResY() / Constants.RESAMPLING_FACTOR)); - } + // Scale image inside the GPU by RESAMPLING_FACTOR + gstreamerPipeline = Constants.GSTREAMER_PIPELINE_DDUPL + .replace(Constants.INTERNAL_SCALING_X, String.valueOf(MainSingleton.getInstance().config.getScreenResX() / Constants.RESAMPLING_FACTOR)) + .replace(Constants.INTERNAL_SCALING_Y, String.valueOf(MainSingleton.getInstance().config.getScreenResY() / Constants.RESAMPLING_FACTOR)); } else { gstreamerPipeline = Constants.GSTREAMER_PIPELINE .replace(Constants.INTERNAL_SCALING_X, String.valueOf(MainSingleton.getInstance().config.getScreenResX() / Constants.RESAMPLING_FACTOR)) @@ -167,6 +161,26 @@ private void intBufferRgbToImage(IntBuffer rgbBuffer) { } } + /** + * Return the stride + * + * @param width captured image width (includes rescaling) + * @param height captured image height (includes rescaling) + * @param rgbBuffer captured image IntBuffer + * @return width that contains stride for some resolutions that needs it like: 3440x1440 on NVIDIA or 1920x1080 on AMD + */ + private int getWidthPlusStride(int width, int height, IntBuffer rgbBuffer) { + int widthPlusStride = width; + final int exectedCapacityWithoutStride = width * height; + if ((rgbBuffer.capacity()) != exectedCapacityWithoutStride) { + int capacity = rgbBuffer.capacity(); + int difference = capacity - exectedCapacityWithoutStride; + int stride = difference / height; + widthPlusStride = width + stride; + } + return widthPlusStride; + } + /** * Listener callback triggered every frame */ @@ -178,13 +192,6 @@ public void rgbFrame(int width, int height, IntBuffer rgbBuffer) { if (!bufferLock.tryLock()) { return; } - int intBufferSize = (width * height) - 1; - if (((rgbBuffer.capacity() - 1) != intBufferSize) && !GrabberSingleton.getInstance().isFallbackPipeline()) { - log.debug("Received buffer is different from the expected, using fallback pipeline."); - GrabberSingleton.getInstance().setFallbackPipeline(true); - PipelineManager.restartCapture(() -> { - }, true); - } // CHECK_ASPECT_RATIO is true 10 times per second, if true and black bars auto detection is on, auto detect black bars if (MainSingleton.getInstance().config.isAutoDetectBlackBars()) { if (GrabberSingleton.getInstance().CHECK_ASPECT_RATIO) { @@ -197,6 +204,7 @@ public void rgbFrame(int width, int height, IntBuffer rgbBuffer) { if (MainSingleton.getInstance().config.getRuntimeLogLevel().equals(Level.TRACE.levelStr)) { intBufferRgbToImage(rgbBuffer); } + int widthPlusStride = getWidthPlusStride(width, height, rgbBuffer); // We need an ordered collection so no parallelStream here ledMatrix.forEach((key, value) -> { int r = 0, g = 0, b = 0; @@ -213,9 +221,9 @@ public void rgbFrame(int width, int height, IntBuffer rgbBuffer) { for (int x = 0; x < pixelInUseX; x++) { int offsetX = (xCoordinate + (skipPixel * x)); int offsetY = (yCoordinate + (skipPixel * y)); - int bufferOffset = (Math.min(offsetX, width)) - + ((offsetY < height) ? (offsetY * width) : (height * width)); - int rgb = rgbBuffer.get(Math.min(intBufferSize, bufferOffset)); + int bufferOffset = (Math.min(offsetX, widthPlusStride)) + + ((offsetY < height) ? (offsetY * widthPlusStride) : (height * widthPlusStride)); + int rgb = rgbBuffer.get(Math.min(rgbBuffer.capacity() - 1, bufferOffset)); r += rgb >> 16 & 0xFF; g += rgb >> 8 & 0xFF; b += rgb & 0xFF; diff --git a/src/main/java/org/dpsoftware/grabber/GrabberManager.java b/src/main/java/org/dpsoftware/grabber/GrabberManager.java index 9ebaacfa..c0bd1e64 100644 --- a/src/main/java/org/dpsoftware/grabber/GrabberManager.java +++ b/src/main/java/org/dpsoftware/grabber/GrabberManager.java @@ -86,12 +86,7 @@ public void launchAdvancedGrabber(ImageProcessor imageProcessor) { if (NativeExecutor.isWindows()) { DisplayManager displayManager = new DisplayManager(); String monitorNativePeer = String.valueOf(displayManager.getDisplayInfo(MainSingleton.getInstance().config.getMonitorNumber()).getNativePeer()); - // Constants.GSTREAMER_MEMORY_DIVIDER tells if resolution is compatible with D3D11Memory with no padding. - if (!GrabberSingleton.getInstance().isFallbackPipeline()) { - bin = Gst.parseBinFromDescription(Constants.GSTREAMER_PIPELINE_WINDOWS_HARDWARE_HANDLE.replace("{0}", monitorNativePeer), true); - } else { - bin = Gst.parseBinFromDescription(Constants.GSTREAMER_PIPELINE_WINDOWS_HARDWARE_HANDLE_SM.replace("{0}", monitorNativePeer), true); - } + bin = Gst.parseBinFromDescription(Constants.GSTREAMER_PIPELINE_WINDOWS_HARDWARE_HANDLE.replace("{0}", monitorNativePeer), true); } else if (NativeExecutor.isLinux()) { bin = Gst.parseBinFromDescription(finalLinuxParams, true); } else { diff --git a/src/main/java/org/dpsoftware/grabber/GrabberSingleton.java b/src/main/java/org/dpsoftware/grabber/GrabberSingleton.java index c93f9650..2ef570f9 100644 --- a/src/main/java/org/dpsoftware/grabber/GrabberSingleton.java +++ b/src/main/java/org/dpsoftware/grabber/GrabberSingleton.java @@ -62,9 +62,6 @@ public class GrabberSingleton { public Rectangle rect; // GStreamer Rendering pipeline public Pipeline pipe; - // There is a known issue that prevents to correcly scale the captured image with some resolutions/GPUs. - // for example 3440x1440 on NVIDIA, 1920x1080 on AMD. Scale the image on the CPU if this is the case. - public boolean fallbackPipeline; float maxPeak, maxRms = 0; float maxPeakLeft, maxRmsLeft = 0; float maxPeakRight, maxRmsRight = 0;