ScreenGear API References
ScreenGear API usage examples can be found here âž¶
ScreenGear API parameters are explained here âž¶
ScreenGear is designed exclusively for targeting rapid Screencasting Capabilities, which means it can grab frames from your monitor in real-time, either by defining an area on the computer screen or full-screen, at the expense of inconsiderable latency. ScreenGear also seamlessly support frame capturing from multiple monitors as well as supports multiple backends.
ScreenGear API implements a multi-threaded wrapper around dxcam, pyscreenshot, python-mss python library, and also flexibly supports its internal parameter.
Source code in vidgear/gears/screengear.py
class ScreenGear:
"""
ScreenGear is designed exclusively for targeting rapid Screencasting Capabilities, which means it can
grab frames from your monitor in real-time, either by defining an area on the computer screen or full-screen,
at the expense of inconsiderable latency. ScreenGear also seamlessly support frame capturing from multiple
monitors as well as supports multiple backends.
ScreenGear API implements a multi-threaded wrapper around dxcam, pyscreenshot, python-mss python library,
and also flexibly supports its internal parameter.
"""
def __init__(
self, monitor=None, backend=None, colorspace=None, logging=False, **options
):
"""
This constructor method initializes the object state and attributes of the ScreenGear class.
Parameters:
monitor (int): enables `mss` backend and sets the index of the monitor screen.
backend (str): select suitable backend for extracting frames.
colorspace (str): selects the colorspace of the input stream.
logging (bool): enables/disables logging.
options (dict): provides the flexibility to easily alter backend library parameters. Such as, manually set the dimensions of capture screen area etc.
"""
# enable logging if specified
self.__logging = logging if isinstance(logging, bool) else False
# print current version
logcurr_vidgear_ver(logging=self.__logging)
# create instances for the user-defined monitor
self.__monitor_instance = None
self.__backend = None
# validate monitor instance
assert (
monitor is None or monitor and isinstance(monitor, (int, tuple))
), "[ScreenGear:ERROR] :: Invalid `monitor` value detected!"
# initialize backend
if backend and monitor is None:
self.__backend = backend.lower().strip()
else:
# enforce `dxcam` for Windows machines if undefined (or monitor is defined)
self.__backend = (
"dxcam" if platform.system() == "Windows" and dxcam else None
)
# initiate screen dimension handler
screen_dims = {}
# reformat proper mss dict and assign to screen dimension handler
screen_dims = {
k.strip(): v
for k, v in options.items()
if k.strip() in ["top", "left", "width", "height"]
}
# check whether user-defined dimensions are provided
if screen_dims and len(screen_dims) == 4:
key_order = (
("top", "left", "width", "height")
if self.__backend != "dxcam"
else ("left", "top", "width", "height")
)
screen_dims = OrderedDict((k, screen_dims[k]) for k in key_order)
self.__logging and logger.debug(
"Setting Capture-Area dimensions: {}".format(json.dumps(screen_dims))
)
else:
screen_dims.clear()
# handle backends
if self.__backend == "dxcam":
# get target fps in case of DXcam
self.__target_fps = options.pop("dxcam_target_fps", 0)
if self.__target_fps and isinstance(self.__target_fps, (int, float)):
# set values
self.__target_fps = int(self.__target_fps)
self.__logging and logger.debug(
"Setting Target FPS: {}".format(self.__target_fps)
)
else:
# defaults to 0fps
self.__target_fps = 0
# check if platform is windows
assert (
platform.system() == "Windows"
), "`dxcam` backend is only available for Windows Machines."
# verify monitor values if tuple
assert (
monitor is None
or isinstance(monitor, int)
or (
isinstance(monitor, tuple)
and len(monitor) == 2
and all(isinstance(x, int) for x in monitor)
)
), "For dxcam` backend, monitor` tuple value must be format `int` or `(int, int)` only."
# raise error(s) for critical Class imports
import_dependency_safe("dxcam" if dxcam is None else "")
if monitor is None:
self.__capture_object = dxcam.create(
region=tuple(screen_dims.values()) if screen_dims else None
)
else:
self.__capture_object = (
dxcam.create(
device_idx=monitor[0],
output_idx=monitor[1],
region=tuple(screen_dims.values()) if screen_dims else None,
)
if isinstance(monitor, tuple)
else dxcam.create(
device_idx=monitor,
region=tuple(screen_dims.values()) if screen_dims else None,
)
)
else:
if monitor is None:
# raise error(s) for critical Class imports
import_dependency_safe("pyscreenshot" if pysct is None else "")
# reset backend if not provided
self.__backend = "pil" if self.__backend is None else self.__backend
# check if valid backend
assert (
self.__backend in pysct.backends()
), "Unsupported backend {} provided!".format(backend)
# create capture object
self.__capture_object = pysct
else:
# monitor value must be integer
assert monitor and isinstance(
monitor, int
), "[ScreenGear:ERROR] :: Invalid `monitor` value must be integer with mss backend."
# raise error(s) for critical Class imports
import_dependency_safe(
"from mss import mss" if mss is None else "", pkg_name="mss"
)
# create capture object
self.__capture_object = mss()
self.__backend and logger.warning(
"Backends are disabled for Monitor Indexing(monitor>=0)!"
)
self.__monitor_instance = self.__capture_object.monitors[monitor]
# log backend
self.__backend and self.__logging and logger.debug(
"Setting Backend: {}".format(self.__backend.upper())
)
# assigns special parameter to global variable and clear
# separately handle colorspace value to int conversion
if colorspace:
self.color_space = capPropId(colorspace.strip())
self.__logging and not (self.color_space is None) and logger.debug(
"Enabling `{}` colorspace for this video stream!".format(
colorspace.strip()
)
)
else:
self.color_space = None
# initialize mss capture instance
self.__mss_capture_instance = None
try:
if self.__backend == "dxcam":
# extract global frame from instance
self.frame = self.__capture_object.grab()
else:
if self.__monitor_instance is None:
if screen_dims:
self.__mss_capture_instance = tuple(screen_dims.values())
# extract global frame from instance
self.frame = np.asanyarray(
self.__capture_object.grab(
bbox=self.__mss_capture_instance,
childprocess=False,
backend=self.__backend,
)
)
else:
if screen_dims:
self.__mss_capture_instance = {
"top": self.__monitor_instance["top"] + screen_dims["top"],
"left": self.__monitor_instance["left"]
+ screen_dims["left"],
"width": screen_dims["width"],
"height": screen_dims["height"],
"mon": monitor,
}
else:
self.__mss_capture_instance = (
self.__monitor_instance # otherwise create instance from monitor
)
# extract global frame from instance
self.frame = np.asanyarray(
self.__capture_object.grab(self.__mss_capture_instance)
)
# convert to bgr frame if applicable
self.frame = (
self.frame[:, :, ::-1]
if self.__backend == "dxcam" or not (pysct is None)
else self.frame
)
# render colorspace if defined
if not (self.frame is None) and not (self.color_space is None):
self.frame = cv2.cvtColor(self.frame, self.color_space)
except Exception as e:
if isinstance(e, ScreenShotError):
# otherwise catch and log errors
self.__logging and logger.exception(
self.__capture_object.get_error_details()
)
raise ValueError(
"[ScreenGear:ERROR] :: ScreenShotError caught, Wrong dimensions passed to python-mss, Kindly Refer Docs!"
)
else:
raise SystemError(
"[ScreenGear:ERROR] :: Unable to grab any instance on this system, Are you running headless?"
)
# thread initialization
self.__thread = None
# initialize termination flag
self.__terminate = Event()
def start(self):
"""
Launches the internal *Threaded Frames Extractor* daemon
**Returns:** A reference to the ScreenGear class object.
"""
self.__thread = Thread(target=self.__update, name="ScreenGear", args=())
self.__thread.daemon = True
self.__thread.start()
if self.__backend == "dxcam":
self.__capture_object.start(
target_fps=self.__target_fps,
video_mode=True,
)
self.__logging and self.__target_fps and logger.debug(
"Targeting FPS: {}".format(self.__target_fps)
)
return self
def __update(self):
"""
A **Threaded Frames Extractor**, that keep iterating frames from `mss` API to a internal monitored deque,
until the thread is terminated, or frames runs out.
"""
# initialize frame variable
frame = None
# keep looping infinitely until the thread is terminated
while not self.__terminate.is_set():
try:
if self.__backend == "dxcam":
# extract global frame from instance
frame = self.__capture_object.get_latest_frame()
else:
if self.__monitor_instance:
frame = np.asanyarray(
self.__capture_object.grab(self.__mss_capture_instance)
)
else:
frame = np.asanyarray(
self.__capture_object.grab(
bbox=self.__mss_capture_instance,
childprocess=False,
backend=self.__backend,
)
)
# check if valid frame
assert not (
frame is None or np.shape(frame) == ()
), "[ScreenGear:ERROR] :: Failed to retrieve valid frame!"
# convert to bgr frame if applicable
frame = (
frame[:, :, ::-1]
if self.__backend == "dxcam" or not (pysct is None)
else frame
)
except Exception as e:
if isinstance(e, ScreenShotError):
raise RuntimeError(self.__capture_object.get_error_details())
else:
logger.exception(str(e))
self.__terminate.set()
continue
if not (self.color_space is None):
# apply colorspace to frames
color_frame = None
try:
color_frame = cv2.cvtColor(frame, self.color_space)
except Exception as e:
# Catch if any error occurred
color_frame = None
self.color_space = None
self.__logging and logger.exception(str(e))
logger.warning("Assigned colorspace value is invalid. Discarding!")
self.frame = color_frame if not (color_frame is None) else frame
else:
self.frame = frame
# indicate immediate termination
self.__terminate.set()
# finally release mss resources
if self.__monitor_instance:
self.__capture_object.close()
if self.__backend == "dxcam":
self.__capture_object.stop()
del self.__capture_object
def read(self):
"""
Extracts frames synchronously from monitored deque, while maintaining a fixed-length frame buffer in the memory,
and blocks the thread if the deque is full.
**Returns:** A n-dimensional numpy array.
"""
# return the frame
return self.frame
def stop(self):
"""
Safely terminates the thread, and release the resources.
"""
self.__logging and logger.debug("Terminating ScreenGear Processes.")
# indicate that the thread should be terminate
self.__terminate.set()
# wait until stream resources are released (producer thread might be still grabbing frame)
not (self.__thread is None) and self.__thread.join()
__init__(self, monitor=None, backend=None, colorspace=None, logging=False, **options) special ¶
This constructor method initializes the object state and attributes of the ScreenGear class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
monitor | int | enables | None |
backend | str | select suitable backend for extracting frames. | None |
colorspace | str | selects the colorspace of the input stream. | None |
logging | bool | enables/disables logging. | False |
options | dict | provides the flexibility to easily alter backend library parameters. Such as, manually set the dimensions of capture screen area etc. | {} |
Source code in vidgear/gears/screengear.py
def __init__(
self, monitor=None, backend=None, colorspace=None, logging=False, **options
):
"""
This constructor method initializes the object state and attributes of the ScreenGear class.
Parameters:
monitor (int): enables `mss` backend and sets the index of the monitor screen.
backend (str): select suitable backend for extracting frames.
colorspace (str): selects the colorspace of the input stream.
logging (bool): enables/disables logging.
options (dict): provides the flexibility to easily alter backend library parameters. Such as, manually set the dimensions of capture screen area etc.
"""
# enable logging if specified
self.__logging = logging if isinstance(logging, bool) else False
# print current version
logcurr_vidgear_ver(logging=self.__logging)
# create instances for the user-defined monitor
self.__monitor_instance = None
self.__backend = None
# validate monitor instance
assert (
monitor is None or monitor and isinstance(monitor, (int, tuple))
), "[ScreenGear:ERROR] :: Invalid `monitor` value detected!"
# initialize backend
if backend and monitor is None:
self.__backend = backend.lower().strip()
else:
# enforce `dxcam` for Windows machines if undefined (or monitor is defined)
self.__backend = (
"dxcam" if platform.system() == "Windows" and dxcam else None
)
# initiate screen dimension handler
screen_dims = {}
# reformat proper mss dict and assign to screen dimension handler
screen_dims = {
k.strip(): v
for k, v in options.items()
if k.strip() in ["top", "left", "width", "height"]
}
# check whether user-defined dimensions are provided
if screen_dims and len(screen_dims) == 4:
key_order = (
("top", "left", "width", "height")
if self.__backend != "dxcam"
else ("left", "top", "width", "height")
)
screen_dims = OrderedDict((k, screen_dims[k]) for k in key_order)
self.__logging and logger.debug(
"Setting Capture-Area dimensions: {}".format(json.dumps(screen_dims))
)
else:
screen_dims.clear()
# handle backends
if self.__backend == "dxcam":
# get target fps in case of DXcam
self.__target_fps = options.pop("dxcam_target_fps", 0)
if self.__target_fps and isinstance(self.__target_fps, (int, float)):
# set values
self.__target_fps = int(self.__target_fps)
self.__logging and logger.debug(
"Setting Target FPS: {}".format(self.__target_fps)
)
else:
# defaults to 0fps
self.__target_fps = 0
# check if platform is windows
assert (
platform.system() == "Windows"
), "`dxcam` backend is only available for Windows Machines."
# verify monitor values if tuple
assert (
monitor is None
or isinstance(monitor, int)
or (
isinstance(monitor, tuple)
and len(monitor) == 2
and all(isinstance(x, int) for x in monitor)
)
), "For dxcam` backend, monitor` tuple value must be format `int` or `(int, int)` only."
# raise error(s) for critical Class imports
import_dependency_safe("dxcam" if dxcam is None else "")
if monitor is None:
self.__capture_object = dxcam.create(
region=tuple(screen_dims.values()) if screen_dims else None
)
else:
self.__capture_object = (
dxcam.create(
device_idx=monitor[0],
output_idx=monitor[1],
region=tuple(screen_dims.values()) if screen_dims else None,
)
if isinstance(monitor, tuple)
else dxcam.create(
device_idx=monitor,
region=tuple(screen_dims.values()) if screen_dims else None,
)
)
else:
if monitor is None:
# raise error(s) for critical Class imports
import_dependency_safe("pyscreenshot" if pysct is None else "")
# reset backend if not provided
self.__backend = "pil" if self.__backend is None else self.__backend
# check if valid backend
assert (
self.__backend in pysct.backends()
), "Unsupported backend {} provided!".format(backend)
# create capture object
self.__capture_object = pysct
else:
# monitor value must be integer
assert monitor and isinstance(
monitor, int
), "[ScreenGear:ERROR] :: Invalid `monitor` value must be integer with mss backend."
# raise error(s) for critical Class imports
import_dependency_safe(
"from mss import mss" if mss is None else "", pkg_name="mss"
)
# create capture object
self.__capture_object = mss()
self.__backend and logger.warning(
"Backends are disabled for Monitor Indexing(monitor>=0)!"
)
self.__monitor_instance = self.__capture_object.monitors[monitor]
# log backend
self.__backend and self.__logging and logger.debug(
"Setting Backend: {}".format(self.__backend.upper())
)
# assigns special parameter to global variable and clear
# separately handle colorspace value to int conversion
if colorspace:
self.color_space = capPropId(colorspace.strip())
self.__logging and not (self.color_space is None) and logger.debug(
"Enabling `{}` colorspace for this video stream!".format(
colorspace.strip()
)
)
else:
self.color_space = None
# initialize mss capture instance
self.__mss_capture_instance = None
try:
if self.__backend == "dxcam":
# extract global frame from instance
self.frame = self.__capture_object.grab()
else:
if self.__monitor_instance is None:
if screen_dims:
self.__mss_capture_instance = tuple(screen_dims.values())
# extract global frame from instance
self.frame = np.asanyarray(
self.__capture_object.grab(
bbox=self.__mss_capture_instance,
childprocess=False,
backend=self.__backend,
)
)
else:
if screen_dims:
self.__mss_capture_instance = {
"top": self.__monitor_instance["top"] + screen_dims["top"],
"left": self.__monitor_instance["left"]
+ screen_dims["left"],
"width": screen_dims["width"],
"height": screen_dims["height"],
"mon": monitor,
}
else:
self.__mss_capture_instance = (
self.__monitor_instance # otherwise create instance from monitor
)
# extract global frame from instance
self.frame = np.asanyarray(
self.__capture_object.grab(self.__mss_capture_instance)
)
# convert to bgr frame if applicable
self.frame = (
self.frame[:, :, ::-1]
if self.__backend == "dxcam" or not (pysct is None)
else self.frame
)
# render colorspace if defined
if not (self.frame is None) and not (self.color_space is None):
self.frame = cv2.cvtColor(self.frame, self.color_space)
except Exception as e:
if isinstance(e, ScreenShotError):
# otherwise catch and log errors
self.__logging and logger.exception(
self.__capture_object.get_error_details()
)
raise ValueError(
"[ScreenGear:ERROR] :: ScreenShotError caught, Wrong dimensions passed to python-mss, Kindly Refer Docs!"
)
else:
raise SystemError(
"[ScreenGear:ERROR] :: Unable to grab any instance on this system, Are you running headless?"
)
# thread initialization
self.__thread = None
# initialize termination flag
self.__terminate = Event()
read(self) ¶
Extracts frames synchronously from monitored deque, while maintaining a fixed-length frame buffer in the memory, and blocks the thread if the deque is full.
Returns: A n-dimensional numpy array.
Source code in vidgear/gears/screengear.py
start(self) ¶
Launches the internal Threaded Frames Extractor daemon
Returns: A reference to the ScreenGear class object.
Source code in vidgear/gears/screengear.py
def start(self):
"""
Launches the internal *Threaded Frames Extractor* daemon
**Returns:** A reference to the ScreenGear class object.
"""
self.__thread = Thread(target=self.__update, name="ScreenGear", args=())
self.__thread.daemon = True
self.__thread.start()
if self.__backend == "dxcam":
self.__capture_object.start(
target_fps=self.__target_fps,
video_mode=True,
)
self.__logging and self.__target_fps and logger.debug(
"Targeting FPS: {}".format(self.__target_fps)
)
return self
stop(self) ¶
Safely terminates the thread, and release the resources.
Source code in vidgear/gears/screengear.py
def stop(self):
"""
Safely terminates the thread, and release the resources.
"""
self.__logging and logger.debug("Terminating ScreenGear Processes.")
# indicate that the thread should be terminate
self.__terminate.set()
# wait until stream resources are released (producer thread might be still grabbing frame)
not (self.__thread is None) and self.__thread.join()