dxcam 0.1.0.dev2__tar.gz → 0.2.0.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/LICENSE +21 -21
  2. dxcam-0.2.0.dev1/MANIFEST.in +1 -0
  3. {dxcam-0.1.0.dev2/dxcam.egg-info → dxcam-0.2.0.dev1}/PKG-INFO +334 -238
  4. dxcam-0.1.0.dev2/PKG-INFO → dxcam-0.2.0.dev1/README.md +289 -238
  5. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/__init__.py +288 -197
  6. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/_libs/d3d11.py +280 -270
  7. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/_libs/dxgi.py +267 -256
  8. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/_libs/user32.py +28 -28
  9. dxcam-0.2.0.dev1/dxcam/core/__init__.py +10 -0
  10. dxcam-0.2.0.dev1/dxcam/core/backend.py +49 -0
  11. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/core/device.py +100 -100
  12. dxcam-0.2.0.dev1/dxcam/core/duplicator.py +22 -0
  13. dxcam-0.1.0.dev2/dxcam/core/duplicator.py → dxcam-0.2.0.dev1/dxcam/core/dxgi_duplicator.py +223 -219
  14. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/core/output.py +69 -69
  15. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/core/stagesurf.py +94 -94
  16. dxcam-0.2.0.dev1/dxcam/core/winrt_duplicator.py +549 -0
  17. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/dxcam.py +854 -665
  18. dxcam-0.2.0.dev1/dxcam/processor/__init__.py +7 -0
  19. dxcam-0.2.0.dev1/dxcam/processor/_numpy_kernels.c +39123 -0
  20. dxcam-0.2.0.dev1/dxcam/processor/_numpy_kernels.pyx +725 -0
  21. dxcam-0.2.0.dev1/dxcam/processor/base.py +90 -0
  22. dxcam-0.2.0.dev1/dxcam/processor/cv2_processor.py +356 -0
  23. dxcam-0.2.0.dev1/dxcam/processor/numpy_processor.py +128 -0
  24. dxcam-0.2.0.dev1/dxcam/types.py +47 -0
  25. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/util/io.py +96 -96
  26. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/util/timer.py +119 -119
  27. dxcam-0.2.0.dev1/dxcam.egg-info/PKG-INFO +334 -0
  28. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam.egg-info/SOURCES.txt +10 -1
  29. dxcam-0.2.0.dev1/dxcam.egg-info/requires.txt +19 -0
  30. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/pyproject.toml +89 -61
  31. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/setup.cfg +4 -4
  32. dxcam-0.2.0.dev1/setup.py +46 -0
  33. dxcam-0.2.0.dev1/tests/test_bgra_conversion_parity.py +88 -0
  34. dxcam-0.1.0.dev2/README.md +0 -207
  35. dxcam-0.1.0.dev2/dxcam/core/__init__.py +0 -7
  36. dxcam-0.1.0.dev2/dxcam/processor/__init__.py +0 -1
  37. dxcam-0.1.0.dev2/dxcam/processor/base.py +0 -53
  38. dxcam-0.1.0.dev2/dxcam/processor/numpy_processor.py +0 -171
  39. dxcam-0.1.0.dev2/dxcam/types.py +0 -10
  40. dxcam-0.1.0.dev2/dxcam.egg-info/requires.txt +0 -5
  41. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/_libs/__init__.py +0 -0
  42. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam/util/__init__.py +0 -0
  43. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam.egg-info/dependency_links.txt +0 -0
  44. {dxcam-0.1.0.dev2 → dxcam-0.2.0.dev1}/dxcam.egg-info/top_level.txt +0 -0
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2022 Rain
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Rain
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ recursive-include dxcam/processor *.pyx
@@ -1,238 +1,334 @@
1
- Metadata-Version: 2.4
2
- Name: dxcam
3
- Version: 0.1.0.dev2
4
- Summary: A Python high-performance screenshot library for Windows using Desktop Duplication API
5
- Author: ra1nty
6
- License-Expression: MIT
7
- Project-URL: Source, https://github.com/ra1nty/DXcam
8
- Project-URL: Tracker, https://github.com/ra1nty/DXcam/issues
9
- Keywords: screen,screenshot,screencapture,screengrab,windows
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Intended Audience :: Developers
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3 :: Only
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Classifier: Programming Language :: Python :: 3.13
17
- Classifier: Operating System :: Microsoft :: Windows
18
- Classifier: Operating System :: Microsoft :: Windows :: Windows 10
19
- Classifier: Operating System :: Microsoft :: Windows :: Windows 11
20
- Classifier: Topic :: Multimedia :: Graphics
21
- Classifier: Topic :: Multimedia :: Graphics :: Capture
22
- Classifier: Topic :: Multimedia :: Graphics :: Capture :: Screen Capture
23
- Requires-Python: >=3.10
24
- Description-Content-Type: text/markdown
25
- License-File: LICENSE
26
- Requires-Dist: comtypes
27
- Requires-Dist: numpy
28
- Provides-Extra: cv2
29
- Requires-Dist: opencv-python; extra == "cv2"
30
- Dynamic: license-file
31
-
32
- # **DXcam**
33
- > ***Fast Python Screen Capture for Windows - Updated 2026***
34
-
35
- ```python
36
- import dxcam
37
-
38
- camera = dxcam.create()
39
- frame = camera.grab()
40
- ```
41
-
42
- ## Introduction
43
- DXcam is a high-performance python screenshot and capture library for Windows based on the Desktop Duplication API.
44
- It is designed for low-latency, high-FPS capture pipelines (including full-screen Direct3D applications).
45
-
46
- Compared with common Python alternatives, DXcam focuses on:
47
- - Higher capture throughput
48
- - Stable capture for full-screen exclusive Direct3D apps
49
- - Correct handling of scaled/stretched outputs
50
- - Better FPS pacing for continuous/video capture
51
-
52
- ## Installation
53
- ### From PyPI (pip)
54
- Recommended (with OpenCV):
55
- ```bash
56
- pip install "dxcam[cv2]"
57
- ```
58
-
59
- Minimal install:
60
- ```bash
61
- pip install dxcam
62
- ```
63
-
64
- ### From source (uv)
65
- ```bash
66
- uv sync
67
- # include OpenCV
68
- uv sync --extra cv2
69
- ```
70
-
71
- ### Dev environment (uv + ruff + ty)
72
- ```bash
73
- uv venv --python 3.11 .venv
74
- uv sync --dev
75
- uv run ruff check dxcam
76
- uv run ty check dxcam
77
- ```
78
-
79
- ## Usage
80
- Each output (monitor) is associated with one `DXCamera` instance.
81
-
82
- ```python
83
- import dxcam
84
- camera = dxcam.create() # primary output on device 0
85
- ```
86
-
87
- ### Screenshot
88
- ```python
89
- frame = camera.grab()
90
- ```
91
- `grab()` returns a `numpy.ndarray`. `None` if no new frame is available since the last capture, mainly for backward compatibility. You can use `new_frame_only=False` to change this behavior.
92
-
93
- Use `copy=False` (or `camera.grab_view()`) for a zero-copy view.
94
-
95
- To capture a region:
96
- ```python
97
- left, top = (1920 - 640) // 2, (1080 - 640) // 2
98
- right, bottom = left + 640, top + 640
99
- frame = camera.grab(region=(left, top, right, bottom)) # numpy.ndarray of size (640x640x3) -> (HXWXC)
100
- ```
101
-
102
- ### Screen Capture
103
- ```python
104
- camera.start(region=(left, top, right, bottom), target_fps=60)
105
- camera.is_capturing # True
106
- # ...
107
- camera.stop()
108
- camera.is_capturing # False
109
- ```
110
-
111
- #### Consume the Screen Capture Data
112
- ```python
113
- for _ in range(1000):
114
- frame = camera.get_latest_frame() # blocks until a frame is available
115
- ```
116
- >The screen capture mode spins up a thread polling the rendered new frames and store in an in-memory frame buffer. The blocking / video_mode behavior is designed with downstream video recording / machine learning applications in mind.
117
-
118
- Useful variants:
119
- - `camera.get_latest_frame(with_timestamp=True)` -> `(frame, frame_timestamp)` -> return frame timestamp
120
- - `camera.get_latest_frame_view()` -> zero-copy view into the frame buffer
121
- - `camera.grab(copy=False)` / `camera.grab_view()` -> zero-copy latest-frame snapshot
122
-
123
- ** When `start()` capture is running, calling `grab()` reads from the in-memory ring buffer instead of directly polling DXGI.
124
-
125
- ## Advanced Usage and Remarks
126
- ### Multiple monitors / GPUs
127
- ```python
128
- cam1 = dxcam.create(device_idx=0, output_idx=0)
129
- cam2 = dxcam.create(device_idx=0, output_idx=1)
130
- cam3 = dxcam.create(device_idx=1, output_idx=1)
131
-
132
- img1 = cam1.grab()
133
- img2 = cam2.grab()
134
- img3 = cam3.grab()
135
- ```
136
-
137
- Inspect available devices/outputs:
138
- ```pycon
139
- >>> import dxcam
140
- >>> print(dxcam.device_info())
141
- 'Device[0]:<Device Name:NVIDIA GeForce RTX 3090 Dedicated VRAM:24348Mb VendorId:4318>\n'
142
- >>> print(dxcam.output_info())
143
- 'Device[0] Output[0]: Res:(1920, 1080) Rot:0 Primary:True\nDevice[0] Output[1]: Res:(1920, 1080) Rot:0 Primary:False\n'
144
- ```
145
-
146
- ### Output Format
147
- Set output color mode when creating the camera:
148
- ```python
149
- dxcam.create(output_color="BGRA")
150
- ```
151
-
152
- Supported modes: `"RGB"`, `"RGBA"`, `"BGR"`, `"BGRA"`, `"GRAY"`.
153
-
154
- Notes:
155
- - Data is returned as `numpy.ndarray`.
156
- - `BGRA` does not require OpenCV.
157
- - Other color modes conversion require OpenCV (`dxcam[cv2]`).
158
-
159
- ### Frame Buffer
160
- DXcam uses a fixed-size ring buffer in-memory. New frames overwrite old frames when full.
161
-
162
- ```python
163
- camera = dxcam.create(max_buffer_len=120) # default is 8
164
- ```
165
-
166
- ### Target FPS
167
- DXcam uses high-resolution pacing with drift correction to run near `target_fps`.
168
-
169
- ```python
170
- camera.start(target_fps=120) # default to 60, greater than 120 is resource heavy
171
- ```
172
-
173
- On Python 3.11+, DXcam relies on Windows high-resolution timer behavior used by `time.sleep()`.
174
- On older versions, DXcam uses WinAPI waitable timers directly.
175
-
176
- ### Frame Timestamp
177
- Read the most recent frame timestamp (seconds):
178
- ```python
179
- camera.start(target_fps=60)
180
- frame, ts = camera.get_latest_frame(with_timestamp=True)
181
- camera.stop()
182
- ```
183
-
184
- This value is directly from `DXGI_OUTDUPL_FRAME_INFO.LastPresentTime`, which can be used to calculate PTS / achieve VFR in video capture.
185
-
186
- ### Video Mode
187
- With `video_mode=True`, DXcam fills the buffer at target FPS, reusing the previous frame if needed, even if no new frame is rendered.
188
-
189
- ```python
190
- import cv2
191
- import dxcam
192
-
193
- target_fps = 30
194
- camera = dxcam.create(output_color="BGR")
195
- camera.start(target_fps=target_fps, video_mode=True)
196
-
197
- writer = cv2.VideoWriter(
198
- "video.mp4", cv2.VideoWriter_fourcc(*"mp4v"), target_fps, (1920, 1080)
199
- )
200
- for _ in range(600):
201
- writer.write(camera.get_latest_frame())
202
-
203
- camera.stop()
204
- writer.release()
205
- ```
206
-
207
- ### Safely Releasing Resources
208
- `release()` stops capture, frees buffers, and releases DXGI resources.
209
- After `release()`, the same instance cannot be reused.
210
-
211
- ```python
212
- camera = dxcam.create(output_idx=0, output_color="BGR")
213
- camera.release()
214
- # camera.start() # raises RuntimeError
215
- ```
216
-
217
- ## Benchmarks
218
- When using a similar logic (only capture newly rendered frames) running on a 240fps output, ```DXCam, python-mss, D3DShot``` benchmarked as follow:
219
-
220
- | | DXcam | python-mss | D3DShot |
221
- |-------------|--------|------------|---------|
222
- | Average FPS | 239.19 :checkered_flag: | 75.87 | 118.36 |
223
- | Std Dev | 1.25 | 0.5447 | 0.3224 |
224
-
225
- The benchmark is across 5 runs, with a light-moderate usage on my PC (5900X + 3090; Chrome ~30tabs, VS Code opened, etc.), I used the [Blur Buster UFO test](https://www.testufo.com/framerates#count=5&background=stars&pps=960) to constantly render 240 fps on my monitor. DXcam captured almost every frame rendered. You will see some benchmarks online claiming 1000+fps capture while most of them is busy-spinning a for loop on a staled frame (no new frame rendered on screen in test scenario).
226
-
227
- ### For Targeting FPS:
228
- | (Target)\\(mean,std) | DXcam | python-mss | D3DShot |
229
- |------------- |-------- |------------|---------|
230
- | 60fps | 61.71, 0.26 :checkered_flag: | N/A | 47.11, 1.33 |
231
- | 30fps | 30.08, 0.02 :checkered_flag: | N/A | 21.24, 0.17 |
232
-
233
-
234
- ## Work Referenced
235
-
236
- [OBS Studio](https://github.com/obsproject/obs-studio) - implementation ideas and references.
237
-
238
- [D3DShot](https://github.com/SerpentAI/D3DShot/) : DXcam borrows the ctypes header directly from the no-longer maintained D3DShot.
1
+ Metadata-Version: 2.4
2
+ Name: dxcam
3
+ Version: 0.2.0.dev1
4
+ Summary: A Python high-performance screenshot library for Windows using Desktop Duplication API
5
+ Author: ra1nty
6
+ License-Expression: MIT
7
+ Project-URL: Source, https://github.com/ra1nty/DXcam
8
+ Project-URL: Tracker, https://github.com/ra1nty/DXcam/issues
9
+ Keywords: screen,screenshot,screencapture,screengrab,windows
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Operating System :: Microsoft :: Windows
20
+ Classifier: Operating System :: Microsoft :: Windows :: Windows 10
21
+ Classifier: Operating System :: Microsoft :: Windows :: Windows 11
22
+ Classifier: Topic :: Multimedia :: Graphics
23
+ Classifier: Topic :: Multimedia :: Graphics :: Capture
24
+ Classifier: Topic :: Multimedia :: Graphics :: Capture :: Screen Capture
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: comtypes
29
+ Requires-Dist: numpy
30
+ Provides-Extra: cv2
31
+ Requires-Dist: opencv-python; extra == "cv2"
32
+ Provides-Extra: cython
33
+ Requires-Dist: Cython==3.1.1; extra == "cython"
34
+ Provides-Extra: winrt
35
+ Requires-Dist: winrt-runtime>=3.2.1; extra == "winrt"
36
+ Requires-Dist: winrt-Windows.Foundation>=3.2.1; extra == "winrt"
37
+ Requires-Dist: winrt-Windows.Foundation.Collections>=3.2.1; extra == "winrt"
38
+ Requires-Dist: winrt-Windows.Graphics>=3.2.1; extra == "winrt"
39
+ Requires-Dist: winrt-Windows.Graphics.Capture>=3.2.1; extra == "winrt"
40
+ Requires-Dist: winrt-Windows.Graphics.Capture.Interop>=3.2.1; extra == "winrt"
41
+ Requires-Dist: winrt-Windows.Graphics.DirectX>=3.2.1; extra == "winrt"
42
+ Requires-Dist: winrt-Windows.Graphics.DirectX.Direct3D11>=3.2.1; extra == "winrt"
43
+ Requires-Dist: winrt-Windows.Graphics.DirectX.Direct3D11.Interop>=3.2.1; extra == "winrt"
44
+ Dynamic: license-file
45
+
46
+ # **DXcam**
47
+ > ***Fast Python Screen Capture for Windows - Updated 2026***
48
+
49
+ ```python
50
+ import dxcam
51
+
52
+ camera = dxcam.create()
53
+ frame = camera.grab()
54
+ ```
55
+
56
+ ## Introduction
57
+ DXcam is a high-performance python screenshot and capture library for Windows based on the Desktop Duplication API.
58
+ It is designed for low-latency, high-FPS capture pipelines (including full-screen Direct3D applications).
59
+
60
+ Compared with common Python alternatives, DXcam focuses on:
61
+ - Higher capture throughput
62
+ - Stable capture for full-screen exclusive Direct3D apps
63
+ - Correct handling of scaled/stretched outputs
64
+ - Better FPS pacing for continuous/video capture
65
+
66
+ ## Installation
67
+ ### From PyPI (pip)
68
+ Minimal install:
69
+ ```bash
70
+ pip install dxcam
71
+ ```
72
+
73
+ Full feature: (includes OpenCV-based color conversion, WinRT capture backend support:):
74
+ ```bash
75
+ pip install "dxcam[cv2,winrt]"
76
+ ```
77
+
78
+ Notes:
79
+ - Official Windows wheels are built for CPython `3.10` to `3.14`.
80
+ - Binary wheels include the Cython kernels used by processor backends.
81
+
82
+ ### From source (uv)
83
+ ```bash
84
+ uv sync
85
+ # include OpenCV conversion backend
86
+ uv sync --extra cv2
87
+ # include optional Cython tooling
88
+ uv sync --extra cython
89
+ # include WinRT backend
90
+ uv sync --extra winrt
91
+ ```
92
+
93
+ Build local Cython kernels from source:
94
+ ```bash
95
+ set DXCAM_BUILD_CYTHON=1
96
+ uv pip install -e .[cython] --no-build-isolation
97
+ ```
98
+
99
+ ### Dev environment (uv + ruff + ty)
100
+ ```bash
101
+ uv venv --python 3.11 .venv
102
+ uv sync --dev
103
+ uv run ruff check dxcam
104
+ uv run ty check dxcam
105
+ ```
106
+
107
+ ### API docs (pdoc)
108
+ Generate autodocs for the public API surface:
109
+ ```bash
110
+ uv run pdoc -d google -o site dxcam dxcam.dxcam dxcam.types
111
+ ```
112
+
113
+ Preview locally by opening `site/index.html`.
114
+ CI builds docs on pull requests, and docs are deployed from `main` via GitHub Pages.
115
+
116
+ ## Usage
117
+ Each output (monitor) is associated with one `DXCamera` instance.
118
+
119
+ ```python
120
+ import dxcam
121
+ camera = dxcam.create() # primary output on device 0
122
+ ```
123
+
124
+ To specify backend:
125
+ ```python
126
+ camera = dxcam.create(
127
+ backend="dxgi", # default Desktop Duplication backend
128
+ processor_backend="cv2" # default OpenCV processor
129
+ )
130
+ ```
131
+
132
+ ### Screenshot
133
+ ```python
134
+ frame = camera.grab()
135
+ ```
136
+ `grab()` returns a `numpy.ndarray`. `None` if no new frame is available since the last capture (for backward compatibility); use `new_frame_only=False` to reuse the latest cached one-shot frame.
137
+
138
+ Use `copy=False` (or `camera.grab_view()`) for a zero-copy view. This is faster, but the returned buffer can be overwritten by later captures.
139
+
140
+ To capture a region:
141
+ ```python
142
+ left, top = (1920 - 640) // 2, (1080 - 640) // 2
143
+ right, bottom = left + 640, top + 640
144
+ frame = camera.grab(region=(left, top, right, bottom)) # numpy.ndarray of size (640x640x3) -> (HXWXC)
145
+ ```
146
+
147
+ ### Screen Capture
148
+ ```python
149
+ camera.start(region=(left, top, right, bottom), target_fps=60)
150
+ camera.is_capturing # True
151
+ # ...
152
+ camera.stop()
153
+ camera.is_capturing # False
154
+ ```
155
+
156
+ #### Consume the Screen Capture Data
157
+ ```python
158
+ for _ in range(1000):
159
+ frame = camera.get_latest_frame() # blocks until a frame is available
160
+ ```
161
+ >The screen capture mode spins up a thread that polls newly rendered frames and stores them in an in-memory ring buffer. The blocking and `video_mode` behavior is designed for downstream video recording and machine learning workloads.
162
+
163
+ Useful variants:
164
+ - `camera.get_latest_frame(with_timestamp=True)` -> `(frame, frame_timestamp)` -> return frame timestamp
165
+ - `camera.get_latest_frame_view()` -> zero-copy view into the frame buffer
166
+ - `camera.grab(copy=False)` / `camera.grab_view()` -> zero-copy latest-frame snapshot
167
+
168
+ > When `start()` capture is running, calling `grab()` reads from the in-memory ring buffer instead of directly polling DXGI.
169
+
170
+ ## Advanced Usage and Remarks
171
+ ### Multiple monitors / GPUs
172
+ ```python
173
+ cam1 = dxcam.create(device_idx=0, output_idx=0)
174
+ cam2 = dxcam.create(device_idx=0, output_idx=1)
175
+ cam3 = dxcam.create(device_idx=1, output_idx=1)
176
+
177
+ img1 = cam1.grab()
178
+ img2 = cam2.grab()
179
+ img3 = cam3.grab()
180
+ ```
181
+
182
+ Inspect available devices/outputs:
183
+ ```pycon
184
+ >>> import dxcam
185
+ >>> print(dxcam.device_info())
186
+ 'Device[0]:<Device Name:NVIDIA GeForce RTX 3090 Dedicated VRAM:24348Mb VendorId:4318>\n'
187
+ >>> print(dxcam.output_info())
188
+ 'Device[0] Output[0]: Res:(1920, 1080) Rot:0 Primary:True\nDevice[0] Output[1]: Res:(1920, 1080) Rot:0 Primary:False\n'
189
+ ```
190
+
191
+ ### Output Format
192
+ Set output color mode when creating the camera:
193
+ ```python
194
+ dxcam.create(output_color="BGRA")
195
+ ```
196
+
197
+ Supported modes: `"RGB"`, `"RGBA"`, `"BGR"`, `"BGRA"`, `"GRAY"`.
198
+
199
+ Notes:
200
+ - Data is returned as `numpy.ndarray`.
201
+ - `BGRA` does not require OpenCV and is the leanest dependency path.
202
+ - `RGB`, `BGR`, `RGBA`, `GRAY` require conversion (`cv2` or compiled `numpy` backend).
203
+
204
+ ### Frame Buffer
205
+ DXcam uses a fixed-size ring buffer in-memory. New frames overwrite old frames when full.
206
+
207
+ ```python
208
+ camera = dxcam.create(max_buffer_len=120) # default is 8
209
+ ```
210
+
211
+ ### Target FPS
212
+ DXcam uses high-resolution pacing with drift correction to run near `target_fps`.
213
+
214
+ ```python
215
+ camera.start(target_fps=120) # default to 60, greater than 120 is resource heavy
216
+ ```
217
+
218
+ On Python 3.11+, DXcam relies on Windows high-resolution timer behavior used by `time.sleep()`.
219
+ On older versions, DXcam uses WinAPI waitable timers directly.
220
+
221
+ ### Frame Timestamp
222
+ Read the most recent frame timestamp (seconds):
223
+ ```python
224
+ camera.start(target_fps=60)
225
+ frame, ts = camera.get_latest_frame(with_timestamp=True)
226
+ camera.stop()
227
+ ```
228
+
229
+ For `backend="dxgi"`, this value comes from `DXGI_OUTDUPL_FRAME_INFO.LastPresentTime`.
230
+ For `backend="winrt"`, this value is derived from WinRT `SystemRelativeTime`.
231
+
232
+ ### Video Mode
233
+ With `video_mode=True`, DXcam fills the buffer at target FPS, reusing the previous frame if needed, even if no new frame is rendered.
234
+
235
+ ```python
236
+ import cv2
237
+ import dxcam
238
+
239
+ target_fps = 30
240
+ camera = dxcam.create(output_color="BGR")
241
+ camera.start(target_fps=target_fps, video_mode=True)
242
+
243
+ writer = cv2.VideoWriter(
244
+ "video.mp4", cv2.VideoWriter_fourcc(*"mp4v"), target_fps, (1920, 1080)
245
+ )
246
+ for _ in range(600):
247
+ writer.write(camera.get_latest_frame())
248
+
249
+ camera.stop()
250
+ writer.release()
251
+ ```
252
+
253
+ ### Capture Backend
254
+ DXcam supports two capture backends:
255
+ - `dxgi` (default): Desktop Duplication API path with broad compatibility.
256
+ - `winrt`: Windows Graphics Capture path.
257
+
258
+ Use it like this:
259
+ ```python
260
+ camera = dxcam.create(backend="dxgi") # default
261
+ camera = dxcam.create(backend="winrt")
262
+ ```
263
+
264
+ Guideline:
265
+ - Start with `dxgi` for most workloads.
266
+ - Try `winrt` if it performs better on your machine or fits your app constraints.
267
+
268
+ ### Processor Backend
269
+ DXcam capture backends (`dxgi`/`winrt`) first acquire a BGRA frame.
270
+ The processor backend then handles post-processing:
271
+ - optional rotation/cropping preparation
272
+ - color conversion to your `output_color`
273
+
274
+ Recommended backend choice:
275
+ - OpenCV installed: use `cv2` (default)
276
+ - No OpenCV installed: use `numpy` (Cython kernels)
277
+
278
+ Use it like this:
279
+ ```python
280
+ camera = dxcam.create(processor_backend="cv2")
281
+ camera = dxcam.create(processor_backend="numpy")
282
+ ```
283
+
284
+ Official Windows wheels already include the compiled NumPy kernels.
285
+
286
+ Only for source installs:
287
+ ```bash
288
+ set DXCAM_BUILD_CYTHON=1
289
+ pip install -e .[cython] --no-build-isolation
290
+ ```
291
+
292
+ If `processor_backend="numpy"` is selected but compiled kernels are unavailable,
293
+ DXcam logs a warning and falls back to `cv2` behavior. In that fallback path,
294
+ install OpenCV for non-`BGRA` output modes.
295
+
296
+ ### Safely Releasing Resources
297
+ `release()` stops capture, frees buffers, and releases capture resources.
298
+ After `release()`, the same instance cannot be reused.
299
+
300
+ ```python
301
+ camera = dxcam.create(output_idx=0, output_color="BGR")
302
+ camera.release()
303
+ # camera.start() # raises RuntimeError
304
+ ```
305
+
306
+ ## Benchmarks
307
+ When using a similar logic (only capture newly rendered frames) running on a 240fps output, ```DXCam, python-mss, D3DShot``` benchmarked as follow:
308
+
309
+ | | DXcam | python-mss | D3DShot |
310
+ |-------------|--------|------------|---------|
311
+ | Average FPS | 239.19 :checkered_flag: | 75.87 | 118.36 |
312
+ | Std Dev | 1.25 | 0.5447 | 0.3224 |
313
+
314
+ The benchmark is across 5 runs, with a light-moderate usage on my PC (5900X + 3090; Chrome ~30tabs, VS Code opened, etc.), I used the [Blur Buster UFO test](https://www.testufo.com/framerates#count=5&background=stars&pps=960) to constantly render 240 fps on my monitor. DXcam captured almost every frame rendered. You will see some benchmarks online claiming 1000+fps capture while most of them is busy-spinning a for loop on a staled frame (no new frame rendered on screen in test scenario).
315
+
316
+ ### For Targeting FPS:
317
+ | (Target)\\(mean,std) | DXcam | python-mss | D3DShot |
318
+ |------------- |-------- |------------|---------|
319
+ | 60fps | 61.71, 0.26 :checkered_flag: | N/A | 47.11, 1.33 |
320
+ | 30fps | 30.08, 0.02 :checkered_flag: | N/A | 21.24, 0.17 |
321
+
322
+ Processor backend comparison helper:
323
+ ```bash
324
+ python benchmarks/dxcam_processor_compare.py --backend dxgi --target-fps 120 --target-frames 1000
325
+ python benchmarks/dxcam_capture.py --backend dxgi --processor-backend numpy
326
+ python benchmarks/numpy_processor_micro.py --width 3840 --height 2160 --modes RGB --variants process into --processor-backends cv2 numpy
327
+ ```
328
+
329
+
330
+ ## Work Referenced
331
+
332
+ [OBS Studio](https://github.com/obsproject/obs-studio) - implementation ideas and references.
333
+
334
+ [D3DShot](https://github.com/SerpentAI/D3DShot/) : DXcam borrows the ctypes header directly from the no-longer maintained D3DShot.