diff --git a/README.md b/README.md
index 38c71f46b..f4eadc415 100644
--- a/README.md
+++ b/README.md
@@ -472,7 +472,7 @@ SteamGear also creates a Manifest file _(such as MPD in-case of DASH)_ or a Mast
NetGear implements a high-level wrapper around [**PyZmQ**][pyzmq] python library that contains python bindings for [**ZeroMQ**][zmq] - a high-performance asynchronous distributed messaging library.
-NetGear seamlessly supports [**Bidirectional data transmission**][netgear_bidata_doc] along with video-frames between receiver(client) and sender(server).
+NetGear seamlessly supports additional [**bidirectional data transmission**][netgear_bidata_doc] between receiver(client) and sender(server) while transferring video-frames all in real-time.
NetGear can also robustly handle [**Multiple Server-Systems**][netgear_multi_server_doc] and [**Multiple Client-Systems**][netgear_multi_client_doc] and at once, thereby providing access to a seamless exchange of video-frames & data between multiple devices across the network at the same time.
@@ -611,11 +611,13 @@ web.shutdown()
.
-> _NetGear_Async can generate the same performance as [NetGear API](#netgear) at about one-third the memory consumption, and also provide complete server-client handling with various options to use variable protocols/patterns similar to NetGear, but it doesn't support any of [NetGear's Exclusive Modes][netgear-exm] yet._
+> _NetGear_Async can generate the same performance as [NetGear API](#netgear) at about one-third the memory consumption, and also provide complete server-client handling with various options to use variable protocols/patterns similar to NetGear, but lacks in term of flexibility as it supports only a few [NetGear's Exclusive Modes][netgear-exm]._
NetGear_Async is built on [`zmq.asyncio`][asyncio-zmq], and powered by a high-performance asyncio event loop called [**`uvloop`**][uvloop] to achieve unmatchable high-speed and lag-free video streaming over the network with minimal resource constraints. NetGear_Async can transfer thousands of frames in just a few seconds without causing any significant load on your system.
-NetGear_Async provides complete server-client handling and options to use variable protocols/patterns similar to [NetGear API](#netgear) but doesn't support any [NetGear Exclusive modes][netgear-exm] yet. Furthermore, NetGear_Async allows us to define our custom Server as source to manipulate frames easily before sending them across the network(see this [doc][netgear_Async-cs] example).
+NetGear_Async provides complete server-client handling and options to use variable protocols/patterns similar to [NetGear API](#netgear). Furthermore, NetGear_Async allows us to define our custom Server as source to manipulate frames easily before sending them across the network(see this [doc][netgear_Async-cs] example).
+
+NetGear_Async now supports additional [**bidirectional data transmission**][btm_netgear_async] between receiver(client) and sender(server) while transferring video-frames. Users can easily build complex applications such as like [Real-Time Video Chat][rtvc] in just few lines of code.
NetGear_Async as of now supports [all four ZeroMQ messaging patterns](#attributes-and-parameters-wrench):
* [**`zmq.PAIR`**][zmq-pair] _(ZMQ Pair Pattern)_
@@ -708,7 +710,7 @@ Here is a Bibtex entry you can use to cite this project in a publication:
# Copyright
-**Copyright © abhiTronix 2019-2021**
+**Copyright © abhiTronix 2019**
This library is released under the **[Apache 2.0 License][license]**.
@@ -747,6 +749,8 @@ Internal URLs
[azure-pipeline]:https://dev.azure.com/abhiuna12/public/_build?definitionId=2
[app]:https://ci.appveyor.com/project/abhiTronix/vidgear
[code]:https://codecov.io/gh/abhiTronix/vidgear
+[btm_netgear_async]: https://abhitronix.github.io/vidgear/latest/gears/netgear_async/advanced/bidirectional_mode/
+[rtvc]: https://abhitronix.github.io/vidgear/latest/gears/netgear_async/advanced/bidirectional_mode/#using-bidirectional-mode-for-video-frames-transfer
[test-4k]:https://github.com/abhiTronix/vidgear/blob/e0843720202b0921d1c26e2ce5b11fadefbec892/vidgear/tests/benchmark_tests/test_benchmark_playback.py#L65
[bs_script_dataset]:https://github.com/abhiTronix/vidgear/blob/testing/scripts/bash/prepare_dataset.sh
diff --git a/docs/bonus/reference/helper.md b/docs/bonus/reference/helper.md
index a161db312..20c94b625 100644
--- a/docs/bonus/reference/helper.md
+++ b/docs/bonus/reference/helper.md
@@ -100,4 +100,33 @@ limitations under the License.
::: vidgear.gears.helper.get_video_bitrate
-
\ No newline at end of file
+
+
+::: vidgear.gears.helper.check_WriteAccess
+
+
+
+::: vidgear.gears.helper.check_open_port
+
+
+
+::: vidgear.gears.helper.delete_file_safe
+
+
+
+::: vidgear.gears.helper.get_supported_demuxers
+
+
+
+::: vidgear.gears.helper.get_supported_vencoders
+
+
+
+::: vidgear.gears.helper.youtube_url_validator
+
+
+
+
+::: vidgear.gears.helper.validate_auth_keys
+
+
diff --git a/docs/bonus/reference/helper_async.md b/docs/bonus/reference/helper_async.md
index 79fa7ab6b..cfc329656 100644
--- a/docs/bonus/reference/helper_async.md
+++ b/docs/bonus/reference/helper_async.md
@@ -40,4 +40,8 @@ limitations under the License.
::: vidgear.gears.asyncio.helper.download_webdata
-
\ No newline at end of file
+
+
+::: vidgear.gears.asyncio.helper.validate_webdata
+
+
diff --git a/docs/gears/netgear/advanced/bidirectional_mode.md b/docs/gears/netgear/advanced/bidirectional_mode.md
index b7aef1a2a..6ea1df99a 100644
--- a/docs/gears/netgear/advanced/bidirectional_mode.md
+++ b/docs/gears/netgear/advanced/bidirectional_mode.md
@@ -291,6 +291,7 @@ Now, Open the terminal on another Server System _(a Raspberry Pi with Camera Mod
```python
# import required libraries
from vidgear.gears import VideoGear
+from vidgear.gears import NetGear
from vidgear.gears import PiGear
# add various Picamera tweak parameters to dictionary
diff --git a/docs/gears/netgear_async/advanced/bidirectional_mode.md b/docs/gears/netgear_async/advanced/bidirectional_mode.md
new file mode 100644
index 000000000..923372156
--- /dev/null
+++ b/docs/gears/netgear_async/advanced/bidirectional_mode.md
@@ -0,0 +1,726 @@
+
+
+# Bidirectional Mode for NetGear_Async API
+
+
+
+ NetGear_Async's Bidirectional Mode
+
+
+## Overview
+
+!!! new "New in v0.2.2"
+ This document was added in `v0.2.2`.
+
+Bidirectional Mode enables seamless support for Bidirectional data transmission between Client and Sender along with video-frames through its synchronous messaging patterns such as `zmq.PAIR` (ZMQ Pair Pattern) & `zmq.REQ/zmq.REP` (ZMQ Request/Reply Pattern) in NetGear_Async API.
+
+In Bidirectional Mode, we utilizes the NetGear_Async API's [`transceive_data`](../../../../bonus/reference/NetGear_Async/#vidgear.gears.asyncio.netgear_async.NetGear_Async.transceive_data) method for transmitting data _(at Client's end)_ and receiving data _(in Server's end)_ all while transferring frames in real-time.
+
+This mode can be easily activated in NetGear_Async through `bidirectional_mode` attribute of its [`options`](../../params/#options) dictionary parameter during initialization.
+
+
+
+
+!!! danger "Important"
+
+ * In Bidirectional Mode, `zmq.PAIR`(ZMQ Pair) & `zmq.REQ/zmq.REP`(ZMQ Request/Reply) are **ONLY** Supported messaging patterns. Accessing this mode with any other messaging pattern, will result in `ValueError`.
+
+ * Bidirectional Mode ==only works with [**User-defined Custom Source**](../../usage/#using-netgear_async-with-a-custom-sourceopencv) on Server end==. Otherwise, NetGear_Async API will throw `ValueError`.
+
+ * Bidirectional Mode enables you to send data of **ANY**[^1] Data-type along with frame bidirectionally.
+
+ * NetGear_Async API will throw `RuntimeError` if Bidirectional Mode is disabled at Server end or Client end but not both.
+
+ * Bidirectional Mode may lead to additional **LATENCY** depending upon the size of data being transfer bidirectionally. User discretion is advised!
+
+
+
+
+
+
+## Exclusive Method and Parameter
+
+To send data bidirectionally, NetGear_Async API provides following exclusive method and parameter:
+
+!!! alert "`transceive_data` only works when Bidirectional Mode is enabled."
+
+* [`transceive_data`](../../../../bonus/reference/NetGear_Async/#vidgear.gears.asyncio.netgear_async.NetGear_Async.transceive_data): It's a bidirectional mode exclusive method to transmit data _(in Receive mode)_ and receive data _(in Send mode)_, all while transferring frames in real-time.
+
+ * `data`: In `transceive_data` method, this parameter enables user to inputs data _(of **ANY**[^1] datatype)_ for sending back to Server at Client's end.
+
+
+
+
+
+
+## Usage Examples
+
+
+!!! warning "For Bidirectional Mode, NetGear_Async must need [User-defined Custom Source](../../usage/#using-netgear_async-with-a-custom-sourceopencv) at its Server end otherwise it will throw ValueError."
+
+
+### Bare-Minimum Usage with OpenCV
+
+Following is the bare-minimum code you need to get started with Bidirectional Mode over Custom Source Server built using OpenCV and NetGear_Async API:
+
+#### Server End
+
+Open your favorite terminal and execute the following python code:
+
+!!! tip "You can terminate both sides anytime by pressing ++ctrl+"C"++ on your keyboard!"
+
+```python
+# import library
+from vidgear.gears.asyncio import NetGear_Async
+import cv2, asyncio
+
+# activate Bidirectional mode
+options = {"bidirectional_mode": True}
+
+# initialize Server without any source
+server = NetGear_Async(source=None, logging=True, **options)
+
+# Create a async frame generator as custom source
+async def my_frame_generator():
+
+ # !!! define your own video source here !!!
+ # Open any valid video stream(for e.g `foo.mp4` file)
+ stream = cv2.VideoCapture("foo.mp4")
+
+ # loop over stream until its terminated
+ while True:
+ # read frames
+ (grabbed, frame) = stream.read()
+
+ # check for empty frame
+ if not grabbed:
+ break
+
+ # {do something with the frame to be sent here}
+
+ # prepare data to be sent(a simple text in our case)
+ target_data = "Hello, I am a Server."
+
+ # receive data from Client
+ recv_data = await server.transceive_data()
+
+ # print data just received from Client
+ if not (recv_data is None):
+ print(recv_data)
+
+ # send our frame & data
+ yield (target_data, frame)
+
+ # sleep for sometime
+ await asyncio.sleep(0)
+
+ # safely close video stream
+ stream.release()
+
+
+if __name__ == "__main__":
+ # set event loop
+ asyncio.set_event_loop(server.loop)
+ # Add your custom source generator to Server configuration
+ server.config["generator"] = my_frame_generator()
+ # Launch the Server
+ server.launch()
+ try:
+ # run your main function task until it is complete
+ server.loop.run_until_complete(server.task)
+ except (KeyboardInterrupt, SystemExit):
+ # wait for interrupts
+ pass
+ finally:
+ # finally close the server
+ server.close()
+```
+
+#### Client End
+
+Then open another terminal on the same system and execute the following python code and see the output:
+
+!!! tip "You can terminate client anytime by pressing ++ctrl+"C"++ on your keyboard!"
+
+```python
+# import libraries
+from vidgear.gears.asyncio import NetGear_Async
+import cv2, asyncio
+
+# activate Bidirectional mode
+options = {"bidirectional_mode": True}
+
+# define and launch Client with `receive_mode=True`
+client = NetGear_Async(receive_mode=True, logging=True, **options).launch()
+
+
+# Create a async function where you want to show/manipulate your received frames
+async def main():
+ # loop over Client's Asynchronous Frame Generator
+ async for (data, frame) in client.recv_generator():
+
+ # do something with receive data from server
+ if not (data is None):
+ # let's print it
+ print(data)
+
+ # {do something with received frames here}
+
+ # Show output window(comment these lines if not required)
+ cv2.imshow("Output Frame", frame)
+ cv2.waitKey(1) & 0xFF
+
+ # prepare data to be sent
+ target_data = "Hi, I am a Client here."
+ # send our data to server
+ await client.transceive_data(data=target_data)
+
+ # await before continuing
+ await asyncio.sleep(0)
+
+
+if __name__ == "__main__":
+ # Set event loop to client's
+ asyncio.set_event_loop(client.loop)
+ try:
+ # run your main function task until it is complete
+ client.loop.run_until_complete(main())
+ except (KeyboardInterrupt, SystemExit):
+ # wait for interrupts
+ pass
+
+ # close all output window
+ cv2.destroyAllWindows()
+
+ # safely close client
+ client.close()
+```
+
+
+
+
+
+
+### Bare-Minimum Usage with VideoGear
+
+Following is another comparatively faster Bidirectional Mode bare-minimum example over Custom Source Server built using multi-threaded [VideoGear](../../../videogear/overview/) _(instead of OpenCV)_ and NetGear_Async API:
+
+#### Server End
+
+Open your favorite terminal and execute the following python code:
+
+!!! tip "You can terminate both sides anytime by pressing ++ctrl+"C"++ on your keyboard!"
+
+```python
+# import library
+from vidgear.gears.asyncio import NetGear_Async
+from vidgear.gears import VideoGear
+import cv2, asyncio
+
+# activate Bidirectional mode
+options = {"bidirectional_mode": True}
+
+# initialize Server without any source
+server = NetGear_Async(source=None, logging=True, **options)
+
+# Create a async frame generator as custom source
+async def my_frame_generator():
+
+ # !!! define your own video source here !!!
+ # Open any valid video stream(for e.g `foo.mp4` file)
+ stream = VideoGear(source="foo.mp4").start()
+
+ # loop over stream until its terminated
+ while True:
+ # read frames
+ frame = stream.read()
+
+ # check for frame if Nonetype
+ if frame is None:
+ break
+
+ # {do something with the frame to be sent here}
+
+ # prepare data to be sent(a simple text in our case)
+ target_data = "Hello, I am a Server."
+
+ # receive data from Client
+ recv_data = await server.transceive_data()
+
+ # print data just received from Client
+ if not (recv_data is None):
+ print(recv_data)
+
+ # send our frame & data
+ yield (target_data, frame)
+
+ # sleep for sometime
+ await asyncio.sleep(0)
+
+ # safely close video stream
+ stream.stop()
+
+
+if __name__ == "__main__":
+ # set event loop
+ asyncio.set_event_loop(server.loop)
+ # Add your custom source generator to Server configuration
+ server.config["generator"] = my_frame_generator()
+ # Launch the Server
+ server.launch()
+ try:
+ # run your main function task until it is complete
+ server.loop.run_until_complete(server.task)
+ except (KeyboardInterrupt, SystemExit):
+ # wait for interrupts
+ pass
+ finally:
+ # finally close the server
+ server.close()
+```
+
+#### Client End
+
+Then open another terminal on the same system and execute the following python code and see the output:
+
+!!! tip "You can terminate client anytime by pressing ++ctrl+"C"++ on your keyboard!"
+
+```python
+# import libraries
+from vidgear.gears.asyncio import NetGear_Async
+import cv2, asyncio
+
+# activate Bidirectional mode
+options = {"bidirectional_mode": True}
+
+# define and launch Client with `receive_mode=True`
+client = NetGear_Async(receive_mode=True, logging=True, **options).launch()
+
+# Create a async function where you want to show/manipulate your received frames
+async def main():
+ # loop over Client's Asynchronous Frame Generator
+ async for (data, frame) in client.recv_generator():
+
+ # do something with receive data from server
+ if not (data is None):
+ # let's print it
+ print(data)
+
+ # {do something with received frames here}
+
+ # Show output window(comment these lines if not required)
+ cv2.imshow("Output Frame", frame)
+ cv2.waitKey(1) & 0xFF
+
+ # prepare data to be sent
+ target_data = "Hi, I am a Client here."
+
+ # send our data to server
+ await client.transceive_data(data=target_data)
+
+ # await before continuing
+ await asyncio.sleep(0)
+
+
+if __name__ == "__main__":
+ # Set event loop to client's
+ asyncio.set_event_loop(client.loop)
+ try:
+ # run your main function task until it is complete
+ client.loop.run_until_complete(main())
+ except (KeyboardInterrupt, SystemExit):
+ # wait for interrupts
+ pass
+
+ # close all output window
+ cv2.destroyAllWindows()
+
+ # safely close client
+ client.close()
+```
+
+
+
+
+
+
+
+### Using Bidirectional Mode with Variable Parameters
+
+
+#### Client's End
+
+Open a terminal on Client System _(where you want to display the input frames received from the Server)_ and execute the following python code:
+
+!!! info "Note down the IP-address of this system(required at Server's end) by executing the command: `hostname -I` and also replace it in the following code."
+
+!!! tip "You can terminate client anytime by pressing ++ctrl+"C"++ on your keyboard!"
+
+```python
+# import libraries
+from vidgear.gears.asyncio import NetGear_Async
+import cv2, asyncio
+
+# activate Bidirectional mode
+options = {"bidirectional_mode": True}
+
+# Define NetGear_Async Client at given IP address and define parameters
+# !!! change following IP address '192.168.x.xxx' with yours !!!
+client = NetGear_Async(
+ address="192.168.x.xxx",
+ port="5454",
+ protocol="tcp",
+ pattern=1,
+ receive_mode=True,
+ logging=True,
+ **options
+)
+
+# Create a async function where you want to show/manipulate your received frames
+async def main():
+ # loop over Client's Asynchronous Frame Generator
+ async for (data, frame) in client.recv_generator():
+
+ # do something with receive data from server
+ if not (data is None):
+ # let's print it
+ print(data)
+
+ # {do something with received frames here}
+
+ # Show output window(comment these lines if not required)
+ cv2.imshow("Output Frame", frame)
+ cv2.waitKey(1) & 0xFF
+
+ # prepare data to be sent
+ target_data = "Hi, I am a Client here."
+ # send our data to server
+ await client.transceive_data(data=target_data)
+
+ # await before continuing
+ await asyncio.sleep(0)
+
+
+if __name__ == "__main__":
+ # Set event loop to client's
+ asyncio.set_event_loop(client.loop)
+ try:
+ # run your main function task until it is complete
+ client.loop.run_until_complete(main())
+ except (KeyboardInterrupt, SystemExit):
+ # wait for interrupts
+ pass
+
+ # close all output window
+ cv2.destroyAllWindows()
+
+ # safely close client
+ client.close()
+```
+
+
+
+#### Server End
+
+Now, Open the terminal on another Server System _(a Raspberry Pi with Camera Module)_, and execute the following python code:
+
+!!! info "Replace the IP address in the following code with Client's IP address you noted earlier."
+
+!!! tip "You can terminate stream on both side anytime by pressing ++ctrl+"C"++ on your keyboard!"
+
+```python
+# import library
+from vidgear.gears.asyncio import NetGear_Async
+from vidgear.gears import VideoGear
+import cv2, asyncio
+
+# activate Bidirectional mode
+options = {"bidirectional_mode": True}
+
+# initialize Server without any source at given IP address and define parameters
+# !!! change following IP address '192.168.x.xxx' with client's IP address !!!
+server = NetGear_Async(
+ source=None,
+ address="192.168.x.xxx",
+ port="5454",
+ protocol="tcp",
+ pattern=1,
+ logging=True,
+ **options
+)
+
+# Create a async frame generator as custom source
+async def my_frame_generator():
+
+ # !!! define your own video source here !!!
+ # Open any video stream such as live webcam
+ # video stream on first index(i.e. 0) device
+ # add various Picamera tweak parameters to dictionary
+ options = {
+ "hflip": True,
+ "exposure_mode": "auto",
+ "iso": 800,
+ "exposure_compensation": 15,
+ "awb_mode": "horizon",
+ "sensor_mode": 0,
+ }
+
+ # open pi video stream with defined parameters
+ stream = PiGear(resolution=(640, 480), framerate=60, logging=True, **options).start()
+
+ # loop over stream until its terminated
+ while True:
+ # read frames
+ frame = stream.read()
+
+ # check for frame if Nonetype
+ if frame is None:
+ break
+
+ # {do something with the frame to be sent here}
+
+ # prepare data to be sent(a simple text in our case)
+ target_data = "Hello, I am a Server."
+
+ # receive data from Client
+ recv_data = await server.transceive_data()
+
+ # print data just received from Client
+ if not (recv_data is None):
+ print(recv_data)
+
+ # send our frame & data
+ yield (target_data, frame)
+
+ # sleep for sometime
+ await asyncio.sleep(0)
+
+ # safely close video stream
+ stream.stop()
+
+
+if __name__ == "__main__":
+ # set event loop
+ asyncio.set_event_loop(server.loop)
+ # Add your custom source generator to Server configuration
+ server.config["generator"] = my_frame_generator()
+ # Launch the Server
+ server.launch()
+ try:
+ # run your main function task until it is complete
+ server.loop.run_until_complete(server.task)
+ except (KeyboardInterrupt, SystemExit):
+ # wait for interrupts
+ pass
+ finally:
+ # finally close the server
+ server.close()
+```
+
+
+
+
+
+
+### Using Bidirectional Mode for Video-Frames Transfer
+
+
+In this example we are going to implement a bare-minimum example, where we will be sending video-frames _(3-Dimensional numpy arrays)_ of the same Video bidirectionally at the same time, for testing the real-time performance and synchronization between the Server and the Client using this(Bidirectional) Mode.
+
+!!! tip "This feature is great for building applications like Real-Time Video Chat."
+
+!!! info "We're also using [`reducer()`](../../../../../bonus/reference/helper/#vidgear.gears.helper.reducer--reducer) method for reducing frame-size on-the-go for additional performance."
+
+!!! warning "Remember, Sending large HQ video-frames may required more network bandwidth and packet size which may lead to video latency!"
+
+#### Server End
+
+Open your favorite terminal and execute the following python code:
+
+!!! tip "You can terminate both side anytime by pressing ++ctrl+"C"++ on your keyboard!"
+
+!!! alert "Server end can only send [numpy.ndarray](https://numpy.org/doc/1.18/reference/generated/numpy.ndarray.html#numpy-ndarray) datatype as frame but not as data."
+
+```python
+# import library
+from vidgear.gears.asyncio import NetGear_Async
+from vidgear.gears.asyncio.helper import reducer
+import cv2, asyncio
+import numpy as np
+
+# activate Bidirectional mode
+options = {"bidirectional_mode": True}
+
+# Define NetGear Server without any source and with defined parameters
+server = NetGear_Async(source=None, pattern=1, logging=True, **options)
+
+# Create a async frame generator as custom source
+async def my_frame_generator():
+ # !!! define your own video source here !!!
+ # Open any valid video stream(for e.g `foo.mp4` file)
+ stream = cv2.VideoCapture("foo.mp4")
+ # loop over stream until its terminated
+ while True:
+
+ # read frames
+ (grabbed, frame) = stream.read()
+
+ # check for empty frame
+ if not grabbed:
+ break
+
+ # reducer frames size if you want more performance, otherwise comment this line
+ frame = await reducer(frame, percentage=30) # reduce frame by 30%
+
+ # {do something with the frame to be sent here}
+
+ # send frame & data and also receive data from Client
+ recv_data = await server.transceive_data()
+
+ # receive data from Client
+ if not (recv_data is None):
+ # check data is a numpy frame
+ if isinstance(recv_data, np.ndarray):
+
+ # {do something with received numpy frame here}
+
+ # Let's show it on output window
+ cv2.imshow("Received Frame", recv_data)
+ cv2.waitKey(1) & 0xFF
+ else:
+ # otherwise just print data
+ print(recv_data)
+
+ # prepare data to be sent(a simple text in our case)
+ target_data = "Hello, I am a Server."
+
+ # send our frame & data to client
+ yield (target_data, frame)
+
+ # sleep for sometime
+ await asyncio.sleep(0)
+
+ # safely close video stream
+ stream.release()
+
+
+if __name__ == "__main__":
+ # set event loop
+ asyncio.set_event_loop(server.loop)
+ # Add your custom source generator to Server configuration
+ server.config["generator"] = my_frame_generator()
+ # Launch the Server
+ server.launch()
+ try:
+ # run your main function task until it is complete
+ server.loop.run_until_complete(server.task)
+ except (KeyboardInterrupt, SystemExit):
+ # wait for interrupts
+ pass
+ finally:
+ # finally close the server
+ server.close()
+```
+
+
+
+#### Client End
+
+Then open another terminal on the same system and execute the following python code and see the output:
+
+!!! tip "You can terminate client anytime by pressing ++ctrl+"C"++ on your keyboard!"
+
+```python
+# import libraries
+from vidgear.gears.asyncio import NetGear_Async
+from vidgear.gears.asyncio.helper import reducer
+import cv2, asyncio
+
+# activate Bidirectional mode
+options = {"bidirectional_mode": True}
+
+# define and launch Client with `receive_mode=True`
+client = NetGear_Async(pattern=1, receive_mode=True, logging=True, **options).launch()
+
+# Create a async function where you want to show/manipulate your received frames
+async def main():
+ # !!! define your own video source here !!!
+ # again open the same video stream for comparison
+ stream = cv2.VideoCapture("foo.mp4")
+ # loop over Client's Asynchronous Frame Generator
+ async for (server_data, frame) in client.recv_generator():
+
+ # check for server data
+ if not (server_data is None):
+
+ # {do something with the server data here}
+
+ # lets print extracted server data
+ print(server_data)
+
+ # {do something with received frames here}
+
+ # Show output window
+ cv2.imshow("Output Frame", frame)
+ key = cv2.waitKey(1) & 0xFF
+
+ # read frame target data from stream to be sent to server
+ (grabbed, target_data) = stream.read()
+ # check for frame
+ if grabbed:
+ # reducer frames size if you want more performance, otherwise comment this line
+ target_data = await reducer(
+ target_data, percentage=30
+ ) # reduce frame by 30%
+ # send our frame data
+ await client.transceive_data(data=target_data)
+
+ # await before continuing
+ await asyncio.sleep(0)
+
+ # safely close video stream
+ stream.release()
+
+
+if __name__ == "__main__":
+ # Set event loop to client's
+ asyncio.set_event_loop(client.loop)
+ try:
+ # run your main function task until it is complete
+ client.loop.run_until_complete(main())
+ except (KeyboardInterrupt, SystemExit):
+ # wait for interrupts
+ pass
+ # close all output window
+ cv2.destroyAllWindows()
+ # safely close client
+ client.close()
+```
+
+
+
+
+[^1]:
+
+ !!! warning "Additional data of [numpy.ndarray](https://numpy.org/doc/1.18/reference/generated/numpy.ndarray.html#numpy-ndarray) datatype is **ONLY SUPPORTED** at Client's end with [`transceive_data`](../../../../bonus/reference/NetGear_Async/#vidgear.gears.asyncio.netgear_async.NetGear_Async.transceive_data) method using its `data` parameter. Whereas Server end can only send [numpy.ndarray](https://numpy.org/doc/1.18/reference/generated/numpy.ndarray.html#numpy-ndarray) datatype as frame but not as data."
+
+
+
\ No newline at end of file
diff --git a/docs/gears/netgear_async/overview.md b/docs/gears/netgear_async/overview.md
index caf43f195..162ff784a 100644
--- a/docs/gears/netgear_async/overview.md
+++ b/docs/gears/netgear_async/overview.md
@@ -26,11 +26,13 @@ limitations under the License.
## Overview
-> _NetGear_Async can generate the same performance as [NetGear API](../../netgear/overview/) at about one-third the memory consumption, and also provide complete server-client handling with various options to use variable protocols/patterns similar to NetGear, but it doesn't support any [NetGear's Exclusive Modes](../../netgear/overview/#exclusive-modes) yet._
+> _NetGear_Async can generate the same performance as [NetGear API](../../netgear/overview/) at about one-third the memory consumption, and also provide complete server-client handling with various options to use variable protocols/patterns similar to NetGear, but lacks in term of flexibility as it supports only a few [NetGear's Exclusive Modes](../../netgear/overview/#exclusive-modes)._
NetGear_Async is built on [`zmq.asyncio`](https://pyzmq.readthedocs.io/en/latest/api/zmq.asyncio.html), and powered by a high-performance asyncio event loop called [**`uvloop`**](https://github.com/MagicStack/uvloop) to achieve unmatchable high-speed and lag-free video streaming over the network with minimal resource constraints. NetGear_Async can transfer thousands of frames in just a few seconds without causing any significant load on your system.
-NetGear_Async provides complete server-client handling and options to use variable protocols/patterns similar to [NetGear API](../../netgear/overview/) but doesn't support any [NetGear's Exclusive Modes](../../netgear/overview/#exclusive-modes) yet. Furthermore, NetGear_Async allows us to define our custom Server as source to manipulate frames easily before sending them across the network(see this [doc](../usage/#using-netgear_async-with-a-custom-sourceopencv) example).
+NetGear_Async provides complete server-client handling and options to use variable protocols/patterns similar to [NetGear API](../../netgear/overview/). Furthermore, NetGear_Async allows us to define our custom Server as source to manipulate frames easily before sending them across the network(see this [doc](../usage/#using-netgear_async-with-a-custom-sourceopencv) example).
+
+NetGear_Async now supports additional [**bidirectional data transmission**](../advanced/bidirectional_mode) between receiver(client) and sender(server) while transferring frames. Users can easily build complex applications such as like [Real-Time Video Chat](../advanced/bidirectional_mode/#using-bidirectional-mode-for-video-frames-transfer) in just few lines of code.
In addition to all this, NetGear_Async API also provides internal wrapper around [VideoGear](../../videogear/overview/), which itself provides internal access to both [CamGear](../../camgear/overview/) and [PiGear](../../pigear/overview/) APIs, thereby granting it exclusive power for transferring frames incoming from any source to the network.
diff --git a/docs/gears/netgear_async/params.md b/docs/gears/netgear_async/params.md
index 820a3ff37..4b1180ba4 100644
--- a/docs/gears/netgear_async/params.md
+++ b/docs/gears/netgear_async/params.md
@@ -150,6 +150,34 @@ In NetGear_Async, the Receiver-end keeps tracks if frames are received from Serv
NetGear_Async(timeout=5.0) # sets 5secs timeout
```
+## **`options`**
+
+This parameter provides the flexibility to alter various NetGear_Async API's internal properties and modes.
+
+**Data-Type:** Dictionary
+
+**Default Value:** Its default value is `{}`
+
+**Usage:**
+
+
+!!! abstract "Supported dictionary attributes for NetGear_Async API"
+
+ * **`bidirectional_mode`** (_boolean_) : This internal attribute activates the exclusive [**Bidirectional Mode**](../advanced/bidirectional_mode/), if enabled(`True`).
+
+
+The desired attributes can be passed to NetGear_Async API as follows:
+
+```python
+# formatting parameters as dictionary attributes
+options = {
+ "bidirectional_mode": True,
+}
+# assigning it
+NetGear_Async(logging=True, **options)
+```
+
+
diff --git a/docs/gears/netgear_async/usage.md b/docs/gears/netgear_async/usage.md
index a1102d1b7..f0a123657 100644
--- a/docs/gears/netgear_async/usage.md
+++ b/docs/gears/netgear_async/usage.md
@@ -223,7 +223,9 @@ if __name__ == "__main__":
## Using NetGear_Async with a Custom Source(OpenCV)
-NetGear_Async allows you to easily define your own custom Source at Server-end that you want to use to manipulate your frames before sending them onto the network. Let's implement a bare-minimum example with a Custom Source using NetGear_Async API and OpenCV:
+NetGear_Async allows you to easily define your own custom Source at Server-end that you want to use to manipulate your frames before sending them onto the network.
+
+Let's implement a bare-minimum example with a Custom Source using NetGear_Async API and OpenCV:
### Server's End
@@ -237,7 +239,7 @@ from vidgear.gears.asyncio import NetGear_Async
import cv2, asyncio
# initialize Server without any source
-server = NetGear_Async(logging=True)
+server = NetGear_Async(source=None, logging=True)
# Create a async frame generator as custom source
async def my_frame_generator():
diff --git a/docs/gears/streamgear/rtfm/usage.md b/docs/gears/streamgear/rtfm/usage.md
index 164a4c429..8b0d34a3f 100644
--- a/docs/gears/streamgear/rtfm/usage.md
+++ b/docs/gears/streamgear/rtfm/usage.md
@@ -1021,8 +1021,8 @@ The complete example is as follows:
{
"-resolution": "1280x720",
"-video_bitrate": "4000k",
- }, # Stream1: 1920x1080 at 4000kbs bitrate
- {"-resolution": "640x360", "-framerate": 30.0}, # Stream2: 1280x720 at 30fps
+ }, # Stream1: 1280x720 at 4000kbs bitrate
+ {"-resolution": "640x360", "-framerate": 30.0}, # Stream2: 640x360 at 30fps
],
"-input_framerate": stream.framerate, # controlled framerate for audio-video sync !!! don't forget this line !!!
"-audio": [
@@ -1086,8 +1086,8 @@ The complete example is as follows:
{
"-resolution": "1280x720",
"-video_bitrate": "4000k",
- }, # Stream1: 1920x1080 at 4000kbs bitrate
- {"-resolution": "640x360", "-framerate": 30.0}, # Stream2: 1280x720 at 30fps
+ }, # Stream1: 1280x720 at 4000kbs bitrate
+ {"-resolution": "640x360", "-framerate": 30.0}, # Stream2: 640x360 at 30fps
],
"-input_framerate": stream.framerate, # controlled framerate for audio-video sync !!! don't forget this line !!!
"-audio": [
diff --git a/docs/overrides/assets/images/bidir_async.png b/docs/overrides/assets/images/bidir_async.png
new file mode 100644
index 000000000..8f158c65b
Binary files /dev/null and b/docs/overrides/assets/images/bidir_async.png differ
diff --git a/docs/overrides/assets/stylesheets/custom.css b/docs/overrides/assets/stylesheets/custom.css
index b7310e090..62d2fbac2 100755
--- a/docs/overrides/assets/stylesheets/custom.css
+++ b/docs/overrides/assets/stylesheets/custom.css
@@ -156,11 +156,9 @@ limitations under the License.
}
-code {
- word-break: keep-all !important;
-}
td {
vertical-align: middle !important;
+ text-align: center !important;
}
th {
font-weight: bold !important;
@@ -191,7 +189,6 @@ th {
overflow: hidden;
}
.md-version__current {
- text-transform: uppercase;
font-weight: bolder;
}
.md-typeset .task-list-control .task-list-indicator::before {
diff --git a/docs/switch_from_cv.md b/docs/switch_from_cv.md
index b99c2b8ec..3bda0e224 100644
--- a/docs/switch_from_cv.md
+++ b/docs/switch_from_cv.md
@@ -43,9 +43,11 @@ Switching OpenCV with VidGear APIs is fairly painless process, and will just req
VidGear employs OpenCV at its backend and enhances its existing capabilities even further by introducing many new state-of-the-art functionalities such as:
- [x] Accelerated [Multi-Threaded](../bonus/TQM/#what-does-threaded-queue-mode-exactly-do) Performance.
-- [x] Real-time [Stabilization](../gears/stabilizer/overview/).
-- [x] Inherit support for multiple video sources and formats.
-- [x] Screen-casting, Live network-streaming, and [way much more ➶](../gears)
+- [x] Out-of-the-box support for OpenCV API.
+- [x] Real-time [Stabilization](../gears/stabilizer/overview/) ready.
+- [x] Lossless hardware enabled video [encoding](../gears/writegear/compression/usage/#using-compression-mode-with-hardware-encoders) and [transcoding](../gears/streamgear/rtfm/usage/#usage-with-hardware-video-encoder).
+- [x] Inherited multi-backend support for various video sources and devices.
+- [x] Screen-casting, Multi-bitrate network-streaming, and [way much more ➶](../gears)
Vidgear offers all this at once while maintaining the same standard OpenCV-Python _(Python API for OpenCV)_ coding syntax for all of its APIs, thereby making it even easier to implement complex real-time OpenCV applications in python code without changing things much.
diff --git a/mkdocs.yml b/mkdocs.yml
index 0f39f2102..61d467c2a 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -25,7 +25,7 @@ repo_url: https://github.com/abhiTronix/vidgear
edit_uri: ""
# Copyright
-copyright: Copyright © 2019 - 2021 Abhishek Thakur(@abhiTronix)
+copyright: Copyright © 2019 Abhishek Thakur(@abhiTronix)
# Configuration
theme:
@@ -40,6 +40,7 @@ theme:
- navigation.top
- search.suggest
- search.highlight
+ - search.share
palette:
# Light mode
- media: "(prefers-color-scheme: light)"
@@ -68,7 +69,6 @@ theme:
# Plugins
plugins:
- search
- prebuild_index: true
- git-revision-date-localized
- minify:
minify_html: true
@@ -225,7 +225,7 @@ nav:
- NetGear:
- Overview: gears/netgear/overview.md
- Usage Examples: gears/netgear/usage.md
- - Advanced Usage:
+ - Advanced Usages:
- Multi-Servers Mode: gears/netgear/advanced/multi_server.md
- Multi-Clients Mode: gears/netgear/advanced/multi_client.md
- Bidirectional Mode: gears/netgear/advanced/bidirectional_mode.md
@@ -252,6 +252,8 @@ nav:
- NetGear_Async:
- Overview: gears/netgear_async/overview.md
- Usage Examples: gears/netgear_async/usage.md
+ - Advanced Usages:
+ - Bidirectional Mode: gears/netgear_async/advanced/bidirectional_mode.md
- Parameters: gears/netgear_async/params.md
- References: bonus/reference/netgear_async.md
- FAQs: help/netgear_async_faqs.md
@@ -261,7 +263,7 @@ nav:
- Parameters: gears/stabilizer/params.md
- References: bonus/reference/stabilizer.md
- FAQs: help/stabilizer_faqs.md
- - Bonus:
+ - References:
- API References:
- vidgear.gears:
- CamGear API: bonus/reference/camgear.md
diff --git a/vidgear/gears/asyncio/helper.py b/vidgear/gears/asyncio/helper.py
index abebb9682..a88611b02 100755
--- a/vidgear/gears/asyncio/helper.py
+++ b/vidgear/gears/asyncio/helper.py
@@ -40,7 +40,7 @@
def logger_handler():
"""
- ### logger_handler
+ ## logger_handler
Returns the logger handler
@@ -115,7 +115,7 @@ def send(self, request, **kwargs):
def mkdir_safe(dir, logging=False):
"""
- ### mkdir_safe
+ ## mkdir_safe
Safely creates directory at given path.
@@ -136,7 +136,7 @@ def mkdir_safe(dir, logging=False):
def capPropId(property, logging=True):
"""
- ### capPropId
+ ## capPropId
Retrieves the OpenCV property's Integer(Actual) value from string.
@@ -159,7 +159,7 @@ def capPropId(property, logging=True):
def retrieve_best_interpolation(interpolations):
"""
- ### retrieve_best_interpolation
+ ## retrieve_best_interpolation
Retrieves best interpolation for resizing
Parameters:
@@ -176,7 +176,7 @@ def retrieve_best_interpolation(interpolations):
def create_blank_frame(frame=None, text="", logging=False):
"""
- ### create_blank_frame
+ ## create_blank_frame
Create blank frames of given frame size with text
@@ -215,7 +215,7 @@ def create_blank_frame(frame=None, text="", logging=False):
async def reducer(frame=None, percentage=0, interpolation=cv2.INTER_LANCZOS4):
"""
- ### reducer
+ ## reducer
Asynchronous method that reduces frame size by given percentage.
@@ -256,7 +256,7 @@ async def reducer(frame=None, percentage=0, interpolation=cv2.INTER_LANCZOS4):
def generate_webdata(path, c_name="webgear", overwrite_default=False, logging=False):
"""
- ### generate_webdata
+ ## generate_webdata
Auto-Generates, and Auto-validates default data for WebGear API.
@@ -330,7 +330,7 @@ def generate_webdata(path, c_name="webgear", overwrite_default=False, logging=Fa
def download_webdata(path, c_name="webgear", files=[], logging=False):
"""
- ### download_webdata
+ ## download_webdata
Downloads given list of files for WebGear API(if not available) from GitHub Server,
and also Validates them.
@@ -398,7 +398,7 @@ def download_webdata(path, c_name="webgear", files=[], logging=False):
def validate_webdata(path, files=[], logging=False):
"""
- ### validate_auth_keys
+ ## validate_auth_keys
Validates, and also maintains downloaded list of files.
diff --git a/vidgear/gears/asyncio/netgear_async.py b/vidgear/gears/asyncio/netgear_async.py
index 97684cb70..3547d3d44 100755
--- a/vidgear/gears/asyncio/netgear_async.py
+++ b/vidgear/gears/asyncio/netgear_async.py
@@ -47,14 +47,17 @@
class NetGear_Async:
"""
NetGear_Async can generate the same performance as NetGear API at about one-third the memory consumption, and also provide complete server-client handling with various
- options to use variable protocols/patterns similar to NetGear, but only support bidirectional data transmission exclusive mode.
+ options to use variable protocols/patterns similar to NetGear, but lacks in term of flexibility as it supports only a few NetGear's Exclusive Modes.
NetGear_Async is built on `zmq.asyncio`, and powered by a high-performance asyncio event loop called uvloop to achieve unwatchable high-speed and lag-free video streaming
over the network with minimal resource constraints. NetGear_Async can transfer thousands of frames in just a few seconds without causing any significant load on your
system.
- NetGear_Async provides complete server-client handling and options to use variable protocols/patterns similar to NetGear API but doesn't support any NetGear's Exclusive
- Modes yet. Furthermore, NetGear_Async allows us to define our custom Server as source to manipulate frames easily before sending them across the network.
+ NetGear_Async provides complete server-client handling and options to use variable protocols/patterns similar to NetGear API. Furthermore, NetGear_Async allows us to define
+ our custom Server as source to manipulate frames easily before sending them across the network.
+
+ NetGear_Async now supports additional [**bidirectional data transmission**](../advanced/bidirectional_mode) between receiver(client) and sender(server) while transferring frames.
+ Users can easily build complex applications such as like [Real-Time Video Chat](../advanced/bidirectional_mode/#using-bidirectional-mode-for-video-frames-transfer) in just few lines of code.
In addition to all this, NetGear_Async API also provides internal wrapper around VideoGear, which itself provides internal access to both CamGear and PiGear APIs, thereby
granting it exclusive power for transferring frames incoming from any source to the network.
@@ -171,7 +174,7 @@ def __init__(
self.__bi_mode = False # handles Bidirectional mode state
# assign timeout for Receiver end
- if timeout > 0 and isinstance(timeout, (int, float)):
+ if timeout and isinstance(timeout, (int, float)):
self.__timeout = float(timeout)
else:
self.__timeout = 15.0
@@ -662,7 +665,7 @@ async def __frame_generator(self):
async def transceive_data(self, data=None):
"""
- Bidirectional Mode exclusive method to Transmit _(in Receive mode)_ and Receive _(in Send mode)_ data in real-time.
+ Bidirectional Mode exclusive method to Transmit data _(in Receive mode)_ and Receive data _(in Send mode)_.
Parameters:
data (any): inputs data _(of any datatype)_ for sending back to Server.
@@ -672,11 +675,10 @@ async def transceive_data(self, data=None):
if self.__bi_mode:
if self.__receive_mode:
await self.__queue.put(data)
- elif not self.__receive_mode and not self.__queue.empty():
- recvd_data = await self.__queue.get()
- self.__queue.task_done()
else:
- pass
+ if not self.__queue.empty():
+ recvd_data = await self.__queue.get()
+ self.__queue.task_done()
else:
logger.error(
"`transceive_data()` function cannot be used when Bidirectional Mode is disabled."
@@ -754,4 +756,6 @@ def close(self, skip_loop=False):
self.loop.close()
else:
# otherwise create a task
- asyncio.ensure_future(self.__terminate_connection(disable_confirmation=True))
+ asyncio.ensure_future(
+ self.__terminate_connection(disable_confirmation=True)
+ )
diff --git a/vidgear/gears/helper.py b/vidgear/gears/helper.py
index a52cdb220..1e18dd2f2 100755
--- a/vidgear/gears/helper.py
+++ b/vidgear/gears/helper.py
@@ -57,7 +57,7 @@
def logger_handler():
"""
- ### logger_handler
+ ## logger_handler
Returns the logger handler
@@ -131,7 +131,7 @@ def send(self, request, **kwargs):
def restore_levelnames():
"""
- ### restore_levelnames
+ ## restore_levelnames
Auxiliary method to restore logger levelnames.
"""
@@ -148,7 +148,7 @@ def restore_levelnames():
def check_CV_version():
"""
- ### check_CV_version
+ ## check_CV_version
**Returns:** OpenCV's version first bit
"""
@@ -160,7 +160,7 @@ def check_CV_version():
def check_open_port(address, port=22):
"""
- ### check_open_port
+ ## check_open_port
Checks whether specified port open at given IP address.
@@ -181,7 +181,7 @@ def check_open_port(address, port=22):
def check_WriteAccess(path, is_windows=False):
"""
- ### check_WriteAccess
+ ## check_WriteAccess
Checks whether given path directory has Write-Access.
@@ -212,7 +212,7 @@ def check_WriteAccess(path, is_windows=False):
def check_gstreamer_support(logging=False):
"""
- ### check_gstreamer_support
+ ## check_gstreamer_support
Checks whether OpenCV is compiled with Gstreamer(`>=1.0.0`) support.
@@ -239,7 +239,7 @@ def check_gstreamer_support(logging=False):
def get_supported_resolution(value, logging=False):
"""
- ### get_supported_resolution
+ ## get_supported_resolution
Parameters:
value (string): value to be validated
@@ -285,7 +285,7 @@ def get_supported_resolution(value, logging=False):
def dimensions_to_resolutions(value):
"""
- ### dimensions_to_resolutions
+ ## dimensions_to_resolutions
Parameters:
value (list): list of dimensions (e.g. `640x360`)
@@ -312,7 +312,7 @@ def dimensions_to_resolutions(value):
def get_supported_vencoders(path):
"""
- ### get_supported_vencoders
+ ## get_supported_vencoders
Find and returns FFmpeg's supported video encoders
@@ -339,7 +339,7 @@ def get_supported_vencoders(path):
def get_supported_demuxers(path):
"""
- ### get_supported_demuxers
+ ## get_supported_demuxers
Find and returns FFmpeg's supported demuxers
@@ -361,7 +361,7 @@ def get_supported_demuxers(path):
def is_valid_url(path, url=None, logging=False):
"""
- ### is_valid_url
+ ## is_valid_url
Checks URL validity by testing its scheme against
FFmpeg's supported protocols
@@ -400,7 +400,7 @@ def is_valid_url(path, url=None, logging=False):
def validate_video(path, video_path=None, logging=False):
"""
- ### validate_video
+ ## validate_video
Validates video by retrieving resolution/size and framerate from file.
@@ -439,7 +439,7 @@ def validate_video(path, video_path=None, logging=False):
def create_blank_frame(frame=None, text="", logging=False):
"""
- ### create_blank_frame
+ ## create_blank_frame
Create blank frames of given frame size with text
@@ -478,7 +478,7 @@ def create_blank_frame(frame=None, text="", logging=False):
def extract_time(value):
"""
- ### extract_time
+ ## extract_time
Extract time from give string value.
@@ -507,7 +507,7 @@ def extract_time(value):
def validate_audio(path, source=None):
"""
- ### validate_audio
+ ## validate_audio
Validates audio by retrieving audio-bitrate from file.
@@ -556,7 +556,7 @@ def validate_audio(path, source=None):
def get_video_bitrate(width, height, fps, bpp):
"""
- ### get_video_bitrate
+ ## get_video_bitrate
Calculate optimum Bitrate from resolution, framerate, bits-per-pixels values
@@ -573,7 +573,7 @@ def get_video_bitrate(width, height, fps, bpp):
def delete_file_safe(file_path):
"""
- ### delete_ext_safe
+ ## delete_ext_safe
Safely deletes files at given path.
@@ -593,7 +593,7 @@ def delete_file_safe(file_path):
def mkdir_safe(dir_path, logging=False):
"""
- ### mkdir_safe
+ ## mkdir_safe
Safely creates directory at given path.
@@ -615,7 +615,7 @@ def mkdir_safe(dir_path, logging=False):
def delete_ext_safe(dir_path, extensions=[], logging=False):
"""
- ### delete_ext_safe
+ ## delete_ext_safe
Safely deletes files with given extensions at given path.
@@ -652,7 +652,7 @@ def delete_ext_safe(dir_path, extensions=[], logging=False):
def capPropId(property, logging=True):
"""
- ### capPropId
+ ## capPropId
Retrieves the OpenCV property's Integer(Actual) value from string.
@@ -675,7 +675,7 @@ def capPropId(property, logging=True):
def retrieve_best_interpolation(interpolations):
"""
- ### retrieve_best_interpolation
+ ## retrieve_best_interpolation
Retrieves best interpolation for resizing
Parameters:
@@ -692,7 +692,7 @@ def retrieve_best_interpolation(interpolations):
def youtube_url_validator(url):
"""
- ### youtube_url_validator
+ ## youtube_url_validator
Validates & extracts Youtube video ID from URL.
@@ -715,7 +715,7 @@ def youtube_url_validator(url):
def reducer(frame=None, percentage=0, interpolation=cv2.INTER_LANCZOS4):
"""
- ### reducer
+ ## reducer
Reduces frame size by given percentage
@@ -756,7 +756,7 @@ def reducer(frame=None, percentage=0, interpolation=cv2.INTER_LANCZOS4):
def dict2Args(param_dict):
"""
- ### dict2Args
+ ## dict2Args
Converts dictionary attributes to list(args)
@@ -787,7 +787,7 @@ def get_valid_ffmpeg_path(
custom_ffmpeg="", is_windows=False, ffmpeg_download_path="", logging=False
):
"""
- ### get_valid_ffmpeg_path
+ ## get_valid_ffmpeg_path
Validate the given FFmpeg path/binaries, and returns a valid FFmpeg executable path.
@@ -880,7 +880,7 @@ def get_valid_ffmpeg_path(
def download_ffmpeg_binaries(path, os_windows=False, os_bit=""):
"""
- ### download_ffmpeg_binaries
+ ## download_ffmpeg_binaries
Generates FFmpeg Static Binaries for windows(if not available)
@@ -963,7 +963,7 @@ def download_ffmpeg_binaries(path, os_windows=False, os_bit=""):
def validate_ffmpeg(path, logging=False):
"""
- ### validate_ffmpeg
+ ## validate_ffmpeg
Validate FFmeg Binaries. returns `True` if tests are passed.
@@ -997,7 +997,7 @@ def validate_ffmpeg(path, logging=False):
def check_output(*args, **kwargs):
"""
- ### check_output
+ ## check_output
Returns stdin output from subprocess module
"""
@@ -1036,7 +1036,7 @@ def check_output(*args, **kwargs):
def generate_auth_certificates(path, overwrite=False, logging=False):
"""
- ### generate_auth_certificates
+ ## generate_auth_certificates
Auto-Generates, and Auto-validates CURVE ZMQ key-pairs for NetGear API's Secure Mode.
@@ -1148,7 +1148,7 @@ def generate_auth_certificates(path, overwrite=False, logging=False):
def validate_auth_keys(path, extension):
"""
- ### validate_auth_keys
+ ## validate_auth_keys
Validates, and also maintains generated ZMQ CURVE Key-pairs.
diff --git a/vidgear/tests/network_tests/asyncio_tests/test_netgear_async.py b/vidgear/tests/network_tests/asyncio_tests/test_netgear_async.py
index 3d0e77d68..0a8b2c311 100644
--- a/vidgear/tests/network_tests/asyncio_tests/test_netgear_async.py
+++ b/vidgear/tests/network_tests/asyncio_tests/test_netgear_async.py
@@ -122,11 +122,14 @@ async def custom_dataframe_generator(self):
# Create a async function where you want to show/manipulate your received frames
-async def client_iterator(client):
+async def client_iterator(client, data=False):
# loop over Client's Asynchronous Frame Generator
async for frame in client.recv_generator():
# test frame validity
assert not (frame is None or np.shape(frame) == ()), "Failed Test"
+ if data:
+ # send data
+ await client.transceive_data(data="invalid")
# await before continuing
await asyncio.sleep(0)
@@ -152,7 +155,7 @@ async def client_dataframe_iterator(client, data=""):
@pytest.mark.asyncio
@pytest.mark.parametrize(
"pattern",
- [0, 2, 3, 4],
+ [1, 2, 3, 4],
)
async def test_netgear_async_playback(pattern):
try:
@@ -164,12 +167,15 @@ async def test_netgear_async_playback(pattern):
server = NetGear_Async(
source=return_testvideo_path(),
pattern=pattern,
- timeout=7.0,
+ timeout=7.0 if pattern == 4 else 0,
logging=True,
**options_gear
).launch()
# gather and run tasks
- input_coroutines = [server.task, client_iterator(client)]
+ input_coroutines = [
+ server.task,
+ client_iterator(client, data=True if pattern == 4 else False),
+ ]
res = await asyncio.gather(*input_coroutines, return_exceptions=True)
except Exception as e:
if isinstance(e, queue.Empty):
@@ -275,15 +281,19 @@ async def test_netgear_async_bidirectionalmode(
@pytest.mark.asyncio
-@pytest.mark.parametrize("address, port", [("172.31.11.15.77", "5555"), (None, "5555")])
+@pytest.mark.parametrize(
+ "address, port",
+ [("172.31.11.15.77", "5555"), ("172.31.11.33.44", "5555"), (None, "5555")],
+)
async def test_netgear_async_addresses(address, port):
+ server = None
try:
# define and launch Client with `receive_mode = True`
client = NetGear_Async(
address=address, port=port, logging=True, timeout=5.0, receive_mode=True
).launch()
+ options_gear = {"THREAD_TIMEOUT": 60}
if address is None:
- options_gear = {"THREAD_TIMEOUT": 60}
server = NetGear_Async(
source=return_testvideo_path(),
address=address,
@@ -295,15 +305,28 @@ async def test_netgear_async_addresses(address, port):
# gather and run tasks
input_coroutines = [server.task, client_iterator(client)]
await asyncio.gather(*input_coroutines, return_exceptions=True)
+ elif address == "172.31.11.33.44":
+ options_gear["bidirectional_mode"] = True
+ server = NetGear_Async(
+ source=return_testvideo_path(),
+ address=address,
+ port=port,
+ logging=True,
+ timeout=5.0,
+ **options_gear
+ ).launch()
+ await asyncio.ensure_future(server.task)
else:
await asyncio.ensure_future(client_iterator(client))
except Exception as e:
- if address == "172.31.11.15.77" or isinstance(e, queue.Empty):
+ if address in ["172.31.11.15.77", "172.31.11.33.44"] or isinstance(
+ e, queue.Empty
+ ):
logger.exception(str(e))
else:
pytest.fail(str(e))
finally:
- if address is None:
+ if (address is None or address == "172.31.11.33.44") and not (server is None):
server.close(skip_loop=True)
client.close(skip_loop=True)