diff --git a/docs/gears/netgear/params.md b/docs/gears/netgear/params.md
index c9562e362..949069b2f 100644
--- a/docs/gears/netgear/params.md
+++ b/docs/gears/netgear/params.md
@@ -169,7 +169,9 @@ This parameter provides the flexibility to alter various NetGear API's internal
* **`max_retries`**(_integer_): This internal attribute controls the maximum retries before Server/Client exit itself, if it's unable to get any response/reply from the socket before a certain amount of time, when synchronous messaging patterns like (`zmq.PAIR` & `zmq.REQ/zmq.REP`) are being used. It's value can anything greater than `0`, and its default value is `3`.
- * **`request_timeout`**(_integer_): This internal attribute controls the timeout value _(in seconds)_, after which the Server/Client exit itself if it's unable to get any response/reply from the socket, when synchronous messaging patterns like (`zmq.PAIR` & `zmq.REQ/zmq.REP`) are being used. It's value can anything greater than `0`, and its default value is `10` seconds.
+ * **`request_timeout`**(_integer_): This internal attribute controls the timeout value _(in seconds)_, after which the Server/Client exit itself with `Nonetype` value if it's unable to get any response/reply from the socket, when synchronous messaging patterns like (`zmq.PAIR` & `zmq.REQ/zmq.REP`) are being used. It's value can anything greater than `0`, and its default value is `10` seconds.
+
+ * **`subscriber_timeout`**(_integer_): Similar to `request_timeout`, this internal attribute also controls the timeout value _(in seconds)_ but for non-synchronous `zmq.PUB/zmq.SUB` pattern in compression mode, after which the Client(Subscriber) exit itself with `Nonetype` value if it's unable to get any response from the socket. It's value can anything greater than `0`, and its disabled by default _(meaning the client will wait forever for response)_.
* **`flag`**(_integer_): This PyZMQ attribute value can be either `0` or `zmq.NOBLOCK`_( i.e. 1)_. More information can be found [here ➶](https://pyzmq.readthedocs.io/en/latest/api/zmq.html).
diff --git a/docs/gears/screengear/params.md b/docs/gears/screengear/params.md
index 2202c912d..c12f96ad5 100644
--- a/docs/gears/screengear/params.md
+++ b/docs/gears/screengear/params.md
@@ -131,17 +131,18 @@ ScreenGear(colorspace="COLOR_BGR2HSV")
This parameter provides the flexibility to manually set the dimensions of capture screen area.
-!!! info "Supported Dimensional Parameters"
+!!! info "Supported Dimensional Attributes"
- Supported Dimensional Parameters are as follows:
+ ScreenGear API takes `left`, `top`, `width`, `height` coordinates of the bounding box of capture screen area(ROI), similar to [PIL.ImageGrab.grab](https://pillow.readthedocs.io/en/stable/reference/ImageGrab.html), defined below:
+
+
+
+
* **`left`:** the x-coordinate of the upper-left corner of the region
* **`top`:** the y-coordinate of the upper-left corner of the region
- * **`width`:** the width of the region
- * **`height`:** the height of the region
-
-!!! note "Additional Exclusive Attribute such as [`THREAD_TIMEOUT`](../../camgear/advanced/source_params/#exclusive-camgear-parameters) is also supported for this parameter."
-
+ * **`width`:** the width of the complete region from left to the bottom-right corner of the region.
+ * **`height`:** the height of the complete region from top to the bottom-right corner of the region.
**Data-Type:** Dictionary
@@ -149,15 +150,13 @@ This parameter provides the flexibility to manually set the dimensions of captur
**Usage:**
-The desired dimensional parameters can be passed to ScreenGear API by formatting them as attributes, as follows:
-
-!!! tip "More information about screen dimensioning can be found [here ➶](https://python-mss.readthedocs.io/api.html#mss.tools.mss.base.MSSMixin.monitors)"
+The desired dimensional coordinates parameters can be passed to ScreenGear API by formatting them as attributes, as follows:
```python
# formatting dimensional parameters as dictionary attributes
options = {'top': 40, 'left': 0, 'width': 100, 'height': 100}
-# assigning it w.r.t monitor=1
-ScreenGear(monitor=1, **options)
+# assigning it
+ScreenGear(**options)
```
diff --git a/docs/gears/screengear/usage.md b/docs/gears/screengear/usage.md
index 8400dddfe..52bb5f8a8 100644
--- a/docs/gears/screengear/usage.md
+++ b/docs/gears/screengear/usage.md
@@ -77,6 +77,20 @@ stream.stop()
ScreenGear API provides us the flexibility to directly set the dimensions of capturing-area of the screen. These dimensions can be easily applied to ScreenGear API through its [`options`](../params/#options) dictionary parameter by formatting them as its attributes.
+
+??? info "Supported Dimensional Attributes"
+
+ ScreenGear API takes `left`, `top`, `width`, `height` coordinates of the bounding box of capture screen area(ROI), similar to [PIL.ImageGrab.grab](https://pillow.readthedocs.io/en/stable/reference/ImageGrab.html), defined below:
+
+
+
+
+
+ * **`left`:** the x-coordinate of the upper-left corner of the region
+ * **`top`:** the y-coordinate of the upper-left corner of the region
+ * **`width`:** the width of the complete region from left to the bottom-right corner of the region.
+ * **`height`:** the height of the complete region from top to the bottom-right corner of the region.
+
The complete usage example is as follows:
diff --git a/docs/gears/writegear/compression/params.md b/docs/gears/writegear/compression/params.md
index f81393aa3..d2949d451 100644
--- a/docs/gears/writegear/compression/params.md
+++ b/docs/gears/writegear/compression/params.md
@@ -176,6 +176,17 @@ This parameter allows us to exploit almost all FFmpeg supported parameters effor
"-ffpreheaders": ["-re"], # executes as `ffmpeg -re `
}
```
+
+ * **`-disable_ffmpeg_window`** _(bool)_: sets a special flag to enable detached subprocess creation on Windows OS, and can be useful while creating an `.exe` file for a python script that uses WriteGear API. On Windows, in certain cases, even after creating the `.exe` file in windowed mode or no-console mode, the FFmpeg commandline window would pop up while its being used by WriteGear API. Its usage is as follows:
+
+ ??? new "New in v0.3.2"
+ This feature was added in `v0.3.2`.
+
+ !!! warning "`-disable_ffmpeg_window` is only available on Windows OS with logging disabled(`logging=False`) in compression mode."
+
+ ```python
+ output_params = {"-disable_ffmpeg_window": True} # disables FFmpeg creation window
+ ```
* **`-disable_force_termination`** _(bool)_: sets a special flag to manually disable the default forced-termination behaviour in WriteGear API when `-i` FFmpeg parameter is used _(For more details, see issue: #149)_. Its usage is as follows:
diff --git a/docs/gears/writegear/non_compression/params.md b/docs/gears/writegear/non_compression/params.md
index b9ae65f2a..034e7b351 100644
--- a/docs/gears/writegear/non_compression/params.md
+++ b/docs/gears/writegear/non_compression/params.md
@@ -149,7 +149,7 @@ To assign desired parameters in Non-Compression Mode, you can format it as dicti
# format parameter as dictionary attribute
output_params = {"-fps":30}
# and then, assign it
-WriteGear(output = 'output.mp4', **output_params)
+WriteGear(output = 'output.mp4', compression_mode=False, **output_params)
```
!!! example "Its usage example can be found [here ➶](../usage/#using-non-compression-mode-with-videocapture-gears)."
@@ -170,7 +170,7 @@ To select desired FOURCC codec in Non-Compression Mode, you can format it as dic
# format codec as dictionary attribute
output_params = {"-fourcc":"MJPG"}
# and then, assign it
-WriteGear(output = 'output.mp4', **output_params)
+WriteGear(output = 'output.mp4', compression_mode=False, **output_params)
```
!!! example "Its usage example can be found [here ➶](../usage/#using-non-compression-mode-with-videocapture-gears)."
@@ -188,7 +188,7 @@ This parameter enables logging _(if `True`)_, essential for debugging.
**Usage:**
```python
-WriteGear(output = 'output.mp4', logging=True)
+WriteGear(output = 'output.mp4', compression_mode=False, logging=True)
```
diff --git a/docs/overrides/assets/images/screengear_region.png b/docs/overrides/assets/images/screengear_region.png
new file mode 100644
index 000000000..a884fb261
Binary files /dev/null and b/docs/overrides/assets/images/screengear_region.png differ
diff --git a/scripts/bash/prepare_dataset.sh b/scripts/bash/prepare_dataset.sh
index e7fcdac8b..8701ef4e1 100644
--- a/scripts/bash/prepare_dataset.sh
+++ b/scripts/bash/prepare_dataset.sh
@@ -26,7 +26,7 @@ mkdir -p "$TMPFOLDER"/Downloads
mkdir -p "$TMPFOLDER"/Downloads/{FFmpeg_static,Test_videos}
# Acknowledging machine architecture
-MACHINE_BIT=$(uname -m)
+# MACHINE_BIT=$(uname -m)
#Defining alternate ffmpeg static binaries date/version
ALTBINARIES_DATE="12-07-2022"
@@ -48,12 +48,12 @@ msys*)
esac
#Download and Configure FFmpeg Static
-cd "$TMPFOLDER"/Downloads/FFmpeg_static
+cd "$TMPFOLDER"/Downloads/FFmpeg_static || exit
if [ $OS_NAME = "linux" ]; then
echo "Downloading Linux64 Static FFmpeg Binaries..."
- curl -LO https://github.com/abhiTronix/ffmpeg-static-builds/raw/master/$ALTBINARIES_DATE/linux/ffmpeg-git-amd64-static.tar.xz
+ curl -LO https://gitlab.com/abhiTronix/ffmpeg-static-builds/-/raw/master/$ALTBINARIES_DATE/linux/ffmpeg-git-amd64-static.tar.xz
tar -xJf ffmpeg-git-amd64-static.tar.xz
rm *.tar.*
mv ffmpeg* ffmpeg
@@ -61,7 +61,7 @@ if [ $OS_NAME = "linux" ]; then
elif [ $OS_NAME = "windows" ]; then
echo "Downloading Win64 Static FFmpeg Binaries..."
- curl -LO https://github.com/abhiTronix/ffmpeg-static-builds/raw/master/$ALTBINARIES_DATE/windows/ffmpeg-latest-win64-static.zip
+ curl -LO https://gitlab.com/abhiTronix/ffmpeg-static-builds/-/raw/master/$ALTBINARIES_DATE/windows/ffmpeg-latest-win64-static.zip
unzip -qq ffmpeg-latest-win64-static.zip
rm ffmpeg-latest-win64-static.zip
mv ffmpeg-latest-win64-static ffmpeg
@@ -69,7 +69,7 @@ elif [ $OS_NAME = "windows" ]; then
else
echo "Downloading MacOS64 Static FFmpeg Binary..."
- curl -LO https://github.com/abhiTronix/ffmpeg-static-builds/raw/master/$ALTBINARIES_DATE/macOS/ffmpeg-latest-macos64-static.zip
+ curl -LO https://gitlab.com/abhiTronix/ffmpeg-static-builds/-/raw/master/$ALTBINARIES_DATE/macOS/ffmpeg-latest-macos64-static.zip
unzip -qq ffmpeg-latest-macos64-static.zip
rm ffmpeg-latest-macos64-static.zip
mv ffmpeg-latest-macos64-static ffmpeg
diff --git a/vidgear/gears/netgear.py b/vidgear/gears/netgear.py
index 2765f8ba7..3ef639a84 100644
--- a/vidgear/gears/netgear.py
+++ b/vidgear/gears/netgear.py
@@ -119,7 +119,6 @@ def __init__(
logging=False,
**options
):
-
"""
This constructor method initializes the object state and attributes of the NetGear class.
@@ -241,6 +240,9 @@ def __init__(
self.__max_retries = 3
# request timeout
self.__request_timeout = 4000 # 4 secs
+ else:
+ # subscriber timeout
+ self.__subscriber_timeout = None
# Handle user-defined options dictionary values
# reformat dictionary
@@ -384,6 +386,7 @@ def __init__(
self.__max_retries = value
else:
logger.warning("Invalid `max_retries` value skipped!")
+
# assign request timeout in synchronous patterns
elif key == "request_timeout" and isinstance(value, int) and pattern < 2:
if value >= 4:
@@ -391,6 +394,15 @@ def __init__(
else:
logger.warning("Invalid `request_timeout` value skipped!")
+ # assign subscriber timeout
+ elif (
+ key == "subscriber_timeout" and isinstance(value, int) and pattern == 2
+ ):
+ if value > 0:
+ self.__subscriber_timeout = value * 1000 # covert to milliseconds
+ else:
+ logger.warning("Invalid `request_timeout` value skipped!")
+
# handle ZMQ flags
elif key == "flag" and isinstance(value, int):
self.__msg_flag = value
@@ -403,7 +415,6 @@ def __init__(
# Handle Secure mode
if self.__secure_mode:
-
# activate and log if overwriting is enabled
if overwrite_cert:
if not receive_mode:
@@ -525,7 +536,6 @@ def __init__(
# check whether `receive_mode` is enabled
if self.__receive_mode:
-
# define connection address
if address is None:
address = "*" # define address
@@ -609,9 +619,15 @@ def __init__(
# enable CURVE connection for this socket
self.__msg_socket.curve_server = True
- # define exclusive socket options for patterns
+ # define exclusive socket options for `patterns=2`
if self.__pattern == 2:
self.__msg_socket.setsockopt_string(zmq.SUBSCRIBE, "")
+ self.__subscriber_timeout and self.__msg_socket.setsockopt(
+ zmq.RCVTIMEO, self.__subscriber_timeout
+ )
+ self.__subscriber_timeout and self.__msg_socket.setsockopt(
+ zmq.LINGER, 0
+ )
# if multiserver_mode is enabled, then assign port addresses to zmq socket
if self.__multiserver_mode:
@@ -640,12 +656,17 @@ def __init__(
)
self.__msg_pattern = msg_pattern[1]
self.__poll.register(self.__msg_socket, zmq.POLLIN)
-
self.__logging and logger.debug(
"Reliable transmission is enabled for this pattern with max-retries: {} and timeout: {} secs.".format(
self.__max_retries, self.__request_timeout / 1000
)
)
+ else:
+ self.__logging and self.__subscriber_timeout and logger.debug(
+ "Timeout: {} secs is enabled for this system.".format(
+ self.__subscriber_timeout / 1000
+ )
+ )
except Exception as e:
# otherwise log and raise error
@@ -721,7 +742,6 @@ def __init__(
logger.debug("Receive Mode is now activated.")
else:
-
# otherwise default to `Send Mode`
# define connection address
@@ -931,7 +951,6 @@ def __init__(
)
def __recv_handler(self):
-
"""
A threaded receiver handler, that keep iterating data from ZMQ socket to a internally monitored deque,
until the thread is terminated, or socket disconnects.
@@ -941,7 +960,6 @@ def __recv_handler(self):
# keep looping infinitely until the thread is terminated
while not self.__terminate:
-
# check queue buffer for overflow
if len(self.__queue) >= 96:
# stop iterating if overflowing occurs
@@ -986,7 +1004,14 @@ def __recv_handler(self):
continue
else:
- msg_json = self.__msg_socket.recv_json(flags=self.__msg_flag)
+ try:
+ msg_json = self.__msg_socket.recv_json(flags=self.__msg_flag)
+ except zmq.ZMQError as e:
+ if e.errno == zmq.EAGAIN:
+ logger.critical("Connection Timeout. Exiting!")
+ self.__terminate = True
+ self.__queue.append(None)
+ break
# check if terminate_flag` received
if msg_json["terminate_flag"]:
@@ -1302,7 +1327,6 @@ def send(self, frame, message=None):
if self.__pattern < 2:
# check if Bidirectional data transmission is enabled
if self.__bi_mode or self.__multiclient_mode:
-
# handles return data
recvd_data = None
@@ -1452,9 +1476,12 @@ def send(self, frame, message=None):
# log confirmation
self.__logging and logger.debug(recv_confirmation)
- def close(self):
+ def close(self, kill=False):
"""
Safely terminates the threads, and NetGear resources.
+
+ Parameters:
+ kill (bool): Kills ZMQ context instead of graceful exiting in receive mode.
"""
# log it
self.__logging and logger.debug(
@@ -1469,20 +1496,29 @@ def close(self):
self.__queue.clear()
# call immediate termination
self.__terminate = True
- # wait until stream resources are released (producer thread might be still grabbing frame)
+ # properly close the socket
+ self.__logging and logger.debug("Terminating. Please wait...")
+ # wait until stream resources are released
+ # (producer thread might be still grabbing frame)
if self.__thread is not None:
# properly handle thread exit
- self.__thread.join()
+ if self.__thread.is_alive() and kill:
+ # force close if still alive
+ logger.warning("Thread still running...Killing it forcefully!")
+ self.__msg_context.destroy()
+ self.__thread.join()
+ else:
+ self.__thread.join()
+ self.__msg_socket.close(linger=0)
self.__thread = None
- self.__logging and logger.debug("Terminating. Please wait...")
- # properly close the socket
- self.__msg_socket.close(linger=0)
self.__logging and logger.debug("Terminated Successfully!")
-
else:
# indicate that process should be terminated
self.__terminate = True
-
+ # log if kill enabled
+ kill and logger.warning(
+ "`kill` parmeter is only available in the receive mode."
+ )
# check if all attempts of reconnecting failed, then skip to closure
if (self.__pattern < 2 and not self.__max_retries) or (
self.__multiclient_mode and not self.__port_buffer
diff --git a/vidgear/gears/screengear.py b/vidgear/gears/screengear.py
index c5aa17318..64ab630ee 100644
--- a/vidgear/gears/screengear.py
+++ b/vidgear/gears/screengear.py
@@ -106,7 +106,11 @@ def __init__(
}
# check whether user-defined dimensions are provided
if screen_dims and len(screen_dims) == 4:
- key_order = ("top", "left", "width", "height")
+ 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)
logging and logger.debug(
"Setting Capture-Area dimensions: {}".format(json.dumps(screen_dims))
@@ -165,11 +169,7 @@ def __init__(
# 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 or self.__backend == "mss"
- else self.__backend
- )
+ self.__backend = "pil" if self.__backend is None else self.__backend
# check if valid backend
assert (
self.__backend in pysct.backends()
diff --git a/vidgear/gears/stabilizer.py b/vidgear/gears/stabilizer.py
index 1bbe557e8..5bd998ab2 100644
--- a/vidgear/gears/stabilizer.py
+++ b/vidgear/gears/stabilizer.py
@@ -59,7 +59,6 @@ def __init__(
crop_n_zoom=False,
logging=False,
):
-
"""
This constructor method initializes the object state and attributes of the Stabilizer class.
@@ -67,7 +66,7 @@ def __init__(
smoothing_radius (int): alter averaging window size.
border_type (str): changes the extended border type.
border_size (int): enables and set the value for extended border size to reduce the black borders.
- crop_n_zoom (bool): enables croping and zooming of frames(to original size) to reduce the black borders.
+ crop_n_zoom (bool): enables cropping and zooming of frames(to original size) to reduce the black borders.
logging (bool): enables/disables logging.
"""
# print current version
@@ -88,9 +87,9 @@ def __init__(
# initialize global vars
self.__smoothing_radius = smoothing_radius # averaging window, handles the quality of stabilization at expense of latency and sudden panning
self.__smoothed_path = None # handles the smoothed path with box filter
- self.__path = None # handles path i.e cumulative sum of pevious_2_current transformations along a axis
- self.__transforms = [] # handles pevious_2_current transformations [dx,dy,da]
- self.__frame_transforms_smoothed = None # handles smoothed array of pevious_2_current transformations w.r.t to frames
+ self.__path = None # handles path i.e cumulative sum of previous_2_current transformations along a axis
+ self.__transforms = [] # handles previous_2_current transformations [dx,dy,da]
+ self.__frame_transforms_smoothed = None # handles smoothed array of previous_2_current transformations w.r.t to frames
self.__previous_gray = None # handles previous gray frame
self.__previous_keypoints = (
None # handles previous detect_GFTTed keypoints w.r.t previous gray frame
@@ -193,24 +192,13 @@ def stabilize(self, frame):
:
] # save gray frame clone for further processing
- elif self.__frame_queue_indexes[-1] <= self.__smoothing_radius - 1:
+ elif self.__frame_queue_indexes[-1] < self.__smoothing_radius - 1:
# for rest of frames
self.__frame_queue.append(frame) # save frame to deque
self.__frame_queue_indexes.append(
self.__frame_queue_indexes[-1] + 1
) # save frame index
self.__generate_transformations() # generate transformations
- if self.__frame_queue_indexes[-1] == self.__smoothing_radius - 1:
- # calculate smooth path once transformation capturing is completed
- for i in range(3):
- # apply normalized box filter to the path
- self.__smoothed_path[:, i] = self.__box_filter_convolve(
- (self.__path[:, i]), window_size=self.__smoothing_radius
- )
- # calculate deviation of path from smoothed path
- deviation = self.__smoothed_path - self.__path
- # save smoothed transformation
- self.__frame_transforms_smoothed = self.frame_transform + deviation
else:
# start applying transformations
self.__frame_queue.append(frame) # save frame to deque
@@ -253,7 +241,7 @@ def __generate_transformations(self):
status == 1
] # previous
- # calculate optimal affine transformation between pevious_2_current key-points
+ # calculate optimal affine transformation between previous_2_current key-points
if self.__cv2_version == 3:
# backward compatibility with OpenCV3
transformation = cv2.estimateRigidTransform(
@@ -270,11 +258,11 @@ def __generate_transformations(self):
# check if transformation is not None
if not (transformation is None):
- # pevious_2_current translation in x direction
+ # previous_2_current translation in x direction
dx = transformation[0, 2]
- # pevious_2_current translation in y direction
+ # previous_2_current translation in y direction
dy = transformation[1, 2]
- # pevious_2_current rotation in angle
+ # previous_2_current rotation in angle
da = np.arctan2(transformation[1, 0], transformation[0, 0])
else:
# otherwise zero it
diff --git a/vidgear/gears/writegear.py b/vidgear/gears/writegear.py
index 8c537d8a8..1d041d7a6 100644
--- a/vidgear/gears/writegear.py
+++ b/vidgear/gears/writegear.py
@@ -83,7 +83,6 @@ def __init__(
logging=False,
**output_params
):
-
"""
This constructor method initializes the object state and attributes of the WriteGear class.
@@ -92,6 +91,7 @@ def __init__(
compression_mode (bool): selects the WriteGear's Primary Mode of Operation.
custom_ffmpeg (str): assigns the location of custom path/directory for custom FFmpeg executables.
logging (bool): enables/disables logging.
+ ffmpeg_subprocess_creation_window:
output_params (dict): provides the flexibility to control supported internal parameters and FFmpeg properities.
"""
# print current version
@@ -122,6 +122,9 @@ def __init__(
self.__initiate_process = (
True # handles initiate one-time process for generating pipeline
)
+ self.__ffmpeg_window_disabler_patch = (
+ False # handles disabling window for ffmpeg subprocess on Windows
+ )
self.__out_file = None # handles output
gstpipeline_mode = False # handles GStreamer Pipeline Mode
@@ -244,6 +247,22 @@ def __init__(
True if ("-i" in self.__output_parameters) else False
)
+ # handles disabling window for ffmpeg subprocess on Windows OS (only for Compression mode)
+ # this patch prevents ffmpeg creation window from opening when building exe files
+ ffmpeg_window_disabler_patch = self.__output_parameters.pop(
+ "-disable_ffmpeg_window", False
+ )
+ # check if value is valid
+ if not self.__os_windows or logging:
+ logger.warning(
+ "Optional `-disable_ffmpeg_window` flag is only available on Windows OS with `logging=False`. Discarding!"
+ )
+ elif isinstance(ffmpeg_window_disabler_patch, bool):
+ self.__ffmpeg_window_disabler_patch = ffmpeg_window_disabler_patch
+ else:
+ # handle improper values
+ self.__ffmpeg_window_disabler_patch = False
+
# validate the FFmpeg path/binaries and returns valid executable FFmpeg
# location/path (also auto-downloads static binaries on Windows OS)
self.__ffmpeg = get_valid_ffmpeg_path(
@@ -352,7 +371,6 @@ def __init__(
)
def write(self, frame, rgb_mode=False):
-
"""
Pipelines `ndarray` frames to respective API _(**FFmpeg** in Compression Mode & **OpenCV's VideoWriter API** in Non-Compression Mode)_.
@@ -516,7 +534,6 @@ def __PreprocessFFParams(self, channels, dtype=None, rgb=False):
)
def __start_FFProcess(self, input_params, output_params):
-
"""
An Internal method that launches FFmpeg subprocess pipeline in Compression Mode
for pipelining frames to `stdin`.
@@ -595,7 +612,13 @@ def __start_FFProcess(self, input_params, output_params):
else:
# In silent mode
self.__process = sp.Popen(
- cmd, stdin=sp.PIPE, stdout=sp.DEVNULL, stderr=sp.STDOUT
+ cmd,
+ stdin=sp.PIPE,
+ stdout=sp.DEVNULL,
+ stderr=sp.STDOUT,
+ creationflags=( # this prevents ffmpeg creation window from opening when building exe files on Windows
+ sp.DETACHED_PROCESS if self.__ffmpeg_window_disabler_patch else 0
+ ),
)
def __enter__(self):
diff --git a/vidgear/tests/network_tests/test_netgear.py b/vidgear/tests/network_tests/test_netgear.py
index 42aecf4f1..6875dc76a 100644
--- a/vidgear/tests/network_tests/test_netgear.py
+++ b/vidgear/tests/network_tests/test_netgear.py
@@ -133,7 +133,13 @@ def test_patterns(pattern):
Testing NetGear different messaging patterns
"""
# define parameters
- options = {"flag": 0, "copy": False, "track": False, "jpeg_compression": False}
+ options = {
+ "flag": 0,
+ "copy": False,
+ "track": False,
+ "jpeg_compression": False,
+ "subscriber_timeout": 5,
+ }
# initialize
frame_server = None
stream = None
@@ -167,9 +173,9 @@ def test_patterns(pattern):
if not (stream is None):
stream.release()
if not (server is None):
- server.close()
+ server.close(kill=True)
if not (client is None):
- client.close()
+ client.close(kill=True)
@pytest.mark.parametrize(
@@ -239,9 +245,9 @@ def test_compression(options_server):
if not (stream is None):
stream.stop()
if not (server is None):
- server.close()
+ server.close(kill=True)
if not (client is None):
- client.close()
+ client.close(kill=True)
test_data_class = [
@@ -304,9 +310,9 @@ def test_secure_mode(pattern, security_mech, custom_cert_location, overwrite_cer
if not (stream is None):
stream.release()
if not (server is None):
- server.close()
+ server.close(kill=True)
if not (client is None):
- client.close()
+ client.close(kill=True)
@pytest.mark.parametrize(
@@ -418,9 +424,9 @@ def test_bidirectional_mode(pattern, target_data, options):
if not (stream is None):
stream.stop()
if not (server is None):
- server.close()
+ server.close(kill=True)
if not (client is None):
- client.close()
+ client.close(kill=True)
@pytest.mark.parametrize(
@@ -455,6 +461,7 @@ def test_bidirectional_mode(pattern, target_data, options):
{
"multiserver_mode": True,
"ssh_tunnel_mode": "new@sdf.org",
+ "subscriber_timeout": 0,
},
),
],
@@ -647,6 +654,7 @@ def test_multiclient_mode(pattern):
},
{"max_retries": 2, "request_timeout": 4, "multiclient_mode": True},
{"max_retries": 2, "request_timeout": -1, "multiserver_mode": True},
+ {"subscriber_timeout": 4},
],
)
def test_client_reliablity(options):
@@ -658,7 +666,7 @@ def test_client_reliablity(options):
try:
# define params
client = NetGear(
- pattern=1,
+ pattern=2 if "subscriber_timeout" in options.keys() else 1,
port=[5587] if "multiserver_mode" in options.keys() else 6657,
receive_mode=True,
logging=True,
@@ -747,8 +755,8 @@ def test_server_reliablity(options):
@pytest.mark.parametrize(
"server_ports, client_ports, options",
[
- (0, 5555, {"multiserver_mode": True}),
- (5555, 0, {"multiclient_mode": True}),
+ (None, 5555, {"multiserver_mode": True}),
+ (5555, None, {"multiclient_mode": True}),
],
)
@pytest.mark.xfail(raises=ValueError)
diff --git a/vidgear/tests/writer_tests/test_compression_mode.py b/vidgear/tests/writer_tests/test_compression_mode.py
index aac1fa472..262877ded 100644
--- a/vidgear/tests/writer_tests/test_compression_mode.py
+++ b/vidgear/tests/writer_tests/test_compression_mode.py
@@ -229,6 +229,7 @@ def test_output_dimensions():
output_params = {
"-output_dimensions": dimensions,
"-ffmpeg_download_path": tempfile.gettempdir(),
+ "-disable_ffmpeg_window": True,
}
else:
output_params = {"-output_dimensions": dimensions}
@@ -264,7 +265,13 @@ def test_output_dimensions():
(
"Output2.mp4",
"",
- {"-vcodec": "libx264", "-crf": 0, "-preset": "fast", "-ffpreheaders": False},
+ {
+ "-vcodec": "libx264",
+ "-crf": 0,
+ "-preset": "fast",
+ "-ffpreheaders": False,
+ "-disable_ffmpeg_window": True,
+ },
True,
),
(
@@ -276,6 +283,7 @@ def test_output_dimensions():
"-crf": 0,
"-preset": "veryfast",
"-ffpreheaders": ["-re"],
+ "-disable_ffmpeg_window": "Invalid",
},
True,
),
diff --git a/vidgear/tests/writer_tests/test_non_compression_mode.py b/vidgear/tests/writer_tests/test_non_compression_mode.py
index 69f555e60..c9c45bfd2 100644
--- a/vidgear/tests/writer_tests/test_non_compression_mode.py
+++ b/vidgear/tests/writer_tests/test_non_compression_mode.py
@@ -134,6 +134,7 @@ def test_write(conversion):
"-fourcc": "DIVX",
"-fps": 25,
"-backend": "CAP_FFMPEG",
+ "-disable_ffmpeg_window": True,
"-color": True,
"-gst_pipeline_mode": False,
},