ra1nty / DXcam

A Python high-performance screen capture library for Windows using Desktop Duplication API
MIT License
500 stars 70 forks source link

Issue: grab() Returns None on Consecutive Calls #104

Open zzf971129 opened 1 month ago

zzf971129 commented 1 month ago

Hello,

I've encountered an issue with the dxcam library where calling camera.grab() consecutively causes the second call to return None. Here’s a minimal example that reproduces the issue:

import dxcam
import time
import cv2

# 定义截图区域
left, top, right, bottom = 1333, 94, 475, 419

# 初始化DXcam截图
dxcam_camera = dxcam.create()  # returns a DXCamera instance on primary monitor

def dx(left, top, right,bottom):
    t0 = time.perf_counter_ns()
    frame = dxcam_camera.grab(region=(left, top, left+right, top+bottom)) 
    print(f"DXcam截图耗时 {(time.perf_counter_ns() - t0) / 1_000_000:.2f} ms")
    return frame

img1 = dx(left, top, right, bottom)
img2 = dx(left, top, right, bottom)
cv2.imwrite("./img/img1.png", img1)
cv2.imwrite("./img/img2.png", img2)

Traceback (most recent call last):
  File "c:\Users\9527\Desktop\screen capture\DXcam_garb.py", line 23, in <module>
    cv2.imwrite("./img/img2.png", img2)
cv2.error: OpenCV(4.10.0) D:\a\opencv-python\opencv-python\opencv\modules\imgcodecs\src\loadsave.cpp:798: error: (-215:Assertion failed) !_img.empty() in function 'cv::imwrite'

camera = dxcam.create() camera.grab() # First call works fine camera.grab() # Second call returns None It seems that after the first call to grab(), the second call immediately returns None and fails to capture the frame. This issue prevents me from taking multiple quick successive screenshots.

Could you please advise on how to resolve this or if there is a workaround available?

Thank you!

Lonely-Dream commented 3 weeks ago

READMEScreenshot 小节已经提到了

This is the default and the only supported format (for now). It is worth noting that .grab will return None if there is no new frame since the last time you called .grab. Usually it means there's nothing new to render since last time (E.g. You are idling).

也可以参考grab的实现

class DXCamera:
    def _grab(self, region: Tuple[int, int, int, int]):
        if self._duplicator.update_frame():
            if not self._duplicator.updated:
                return None
            self._device.im_context.CopyResource(
                self._stagesurf.texture, self._duplicator.texture
            )
            self._duplicator.release_frame()
            rect = self._stagesurf.map()
            frame = self._processor.process(
                rect, self.width, self.height, region, self.rotation_angle
            )
            self._stagesurf.unmap()
            return frame
        else:
            self._on_output_change()
            return None

所以,如果你的场景需要每次截图都有内容返回,那么当grab返回None的时候,你可以将上一帧返回。 如果不需要的话,那就检查一下返回值,若为None跳过即可。