Skip to content

Commit

Permalink
πŸ”§ Deprecate on_shutdown in favor of lifespan (Fixes #397) [#398]
Browse files Browse the repository at this point in the history
- πŸ—οΈ Replaced deprecated Starlette's `on_shutdown` parameter with an async context manager `lifespan` in WebGear and WebGear_RTC APIs.
- 🚚 Moved shutdown logic for VideoGear and peer RTC connections to this new `lifespan` context manager.
- πŸ“¦οΈ Added new `contextlib` import for using `asynccontextmanager`.

### NetGear_Async API:
- 🩹 Fixed event loop handling 
    - ⚑️Modified `__init__` method to handle event loop more robustly:
        - Try to get the running event loop using `asyncio.get_running_loop()`
        - If no running event loop found, create a new one with `asyncio.new_event_loop()`
        - Log if creating a new event loop
    - πŸ§‘β€πŸ’» Changed launch method to use `self.loop.create_task()` instead of `asyncio.ensure_future()`
        - Ensures the task is created using the correct event loop instance.
- πŸš‘οΈ  Fix event loop initialization on Windows platforms 
    - ⚑️ Moved the event loop initialization code to an earlier point before setting event loop policy to ensure it is set up correctly before selecting `WindowsSelectorEventLoop` policy.
      - πŸ’¬ Background: On Windows, vidgear requires the `WindowsSelectorEventLoop`, but Python 3.8 and above defaults to the `ProactorEventLoop` which is not compatible.
    - πŸ”₯ Removed redundant python version check to set `WindowsSelectorEventLoop` policy, as minimum supported version is already `3.8`.
    - πŸ’‘ Updated code comments.
- ⚑️ Move event loop setup and policy assignment to the beginning of `__init__` before zmq Context creation.

### PiGear API: 
- πŸš‘οΈ Modify PiGear class behavior when `enforce_legacy_picamera=True` on unsupported system
    - ⚑️ Instead of silently disabling `picamera2` API directly, PiGear now raises an error if `picamera` is unavailable or unsupported
    - πŸ₯… Prevented incorrect initialization of `PiGear` class on unsupported 64-bit OS systems.

### Docs: 
- πŸ“ Added workaround for 'AttributeError: 'DXCamera' object has no attribute 'is_capturing'' error on Windows.
- πŸ’„ Added new `screengear_error11.png` asset.
- πŸ“ Update README.md with changes to JPEG compression options
  - ✏️ Replaces deprecated options (`frame_jpeg_quality`, `frame_jpeg_optimize`, `frame_jpeg_progressive`) with their newer equivalents (`jpeg_compression_quality,` `jpeg_compression_fastdct`, `jpeg_compression_fastupsample`) in WebGear usage example.
- πŸ› Replaced buggy kofi widget with a button image in index.md
- πŸ—οΈ Remove script tags from main.html and use a custom hook for adding JS
- πŸ”₯ Remove site.webmanifest file
- πŸ’„ Update mkdocs.yml with new configuration settings:
    - Set edit_uri for GitHub edit links
    - Add new theme features like content actions, tooltips, etc.
    - Update palette settings for light/dark mode
    - Enable new markdown extensions
    - Add custom JS hook for adding scripts on certain pages
- ♻️ Other minor tweaks and cleanups
- πŸ§‘β€πŸ’» Refactored all APIs and bonus examples to use linenums and hl_lines
    - Makes it easier to highlight specific lines in code blocks
- πŸ“ Updated remaining code examples for picamera2 and legacy picamera backends
- πŸ› Replaced buggy kofi widget with a button image in  `help.md`
- πŸ’„ Update announcement icon in `main.html`
- πŸ’„ Change system mode toggle icon and name in `mkdocs.yml`
- πŸ“ Add failure warning in various docs about `picamera` incompatibility on 64-bit OS

### CI: 
- πŸ’š Deprecated event_loop fixture overrides. 
    - πŸ‘· Added new recommended approach of using `pytest.mark.asyncio(scope="module")` to mark all WebGear_RTC and NetGear_Async tests as asynchronous and utilize the same event loop throughout the module.
    - πŸ—‘οΈ Deprecated custom `event_loop` fixture overrides in WebGear_RTC and NetGear_Async tests.
    - πŸ”₯ Removed redundant `pytest.mark.asyncio` decorators from several test functions.
- πŸ’š Refactor event loop handling 
    - πŸ‘· Add a new event_loop_policy fixture for pytest to override the event loop policy
    - πŸ”Š Log the event loop being used for debugging
    - πŸ”§ Mark the new fixture in relevant test functions with pytest.mark.asyncio(scope="module")
    - ♻️ Remove unused imports and code cleanup
  • Loading branch information
abhiTronix authored May 20, 2024
2 parents e497ac2 + 6285688 commit 20dec0a
Show file tree
Hide file tree
Showing 51 changed files with 1,321 additions and 661 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -515,9 +515,9 @@ from vidgear.gears.asyncio import WebGear
# various performance tweaks
options = {
"frame_size_reduction": 40,
"frame_jpeg_quality": 80,
"frame_jpeg_optimize": True,
"frame_jpeg_progressive": False,
"jpeg_compression_quality": 80,
"jpeg_compression_fastdct": True,
"jpeg_compression_fastupsample": False,
}

# initialize WebGear app
Expand Down
13 changes: 7 additions & 6 deletions docs/gears/camgear/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ limitations under the License.

Following is the bare-minimum code you need to get started with CamGear API:

```python
```python linenums="1"
# import required libraries
from vidgear.gears import CamGear
import cv2
Expand Down Expand Up @@ -124,7 +124,8 @@ The complete usage example for Dailymotion and Twitch URLs are as follows:
```

=== "Dailymotion :fontawesome-brands-dailymotion:"
```python hl_lines="12-13"

```python linenums="1" hl_lines="12-13"
# import required libraries
from vidgear.gears import CamGear
import cv2
Expand Down Expand Up @@ -172,7 +173,7 @@ The complete usage example for Dailymotion and Twitch URLs are as follows:

!!! warning "If Twitch user is offline, CamGear will throw ValueError."

```python hl_lines="12-13"
```python linenums="1" hl_lines="12-13"
# import required libraries
from vidgear.gears import CamGear
import cv2
Expand Down Expand Up @@ -274,7 +275,7 @@ The complete usage example is as follows:
print(video_metadata["title"])
```

```python hl_lines="8-9"
```python linenums="1" hl_lines="8-9"
# import required libraries
from vidgear.gears import CamGear
import cv2
Expand Down Expand Up @@ -325,7 +326,7 @@ The complete usage example is as follows:

!!! tip "All the supported Source Tweak Parameters can be found [here ➢](../advanced/source_params/#source-tweak-parameters-for-camgear-api)"

```python hl_lines="8-10"
```python linenums="1" hl_lines="8-10"
# import required libraries
from vidgear.gears import CamGear
import cv2
Expand Down Expand Up @@ -383,7 +384,7 @@ In following example code, we will start with [**HSV**](https://en.wikipedia.org
!!! failure "Any incorrect or None-type value, will immediately revert the colorspace to default i.e. `BGR`."


```python hl_lines="7 30 34 38"
```python linenums="1" hl_lines="7 30 34 38"
# import required libraries
from vidgear.gears import CamGear
import cv2
Expand Down
201 changes: 145 additions & 56 deletions docs/gears/netgear/advanced/bidirectional_mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ 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 hl_lines="9 31"
```python linenums="1" hl_lines="9 31"
# import required libraries
from vidgear.gears import VideoGear
from vidgear.gears import NetGear
Expand Down Expand Up @@ -151,7 +151,7 @@ Then open another terminal on the same system and execute the following python c

!!! tip "You can terminate client anytime by pressing ++ctrl+"C"++ on your keyboard!"

```python hl_lines="6 18"
```python linenums="1" hl_lines="6 18"
# import required libraries
from vidgear.gears import NetGear
import cv2
Expand Down Expand Up @@ -219,7 +219,7 @@ Open a terminal on Client System _(where you want to display the input frames re

!!! tip "You can terminate client anytime by pressing ++ctrl+"C"++ on your keyboard!"

```python hl_lines="11-17"
```python linenums="1" hl_lines="11-17"
# import required libraries
from vidgear.gears import NetGear
import cv2
Expand Down Expand Up @@ -290,73 +290,162 @@ Now, Open the terminal on another Server System _(a Raspberry Pi with Camera Mod

!!! tip "You can terminate stream on both side anytime by pressing ++ctrl+"C"++ on your keyboard!"

```python hl_lines="25-30"
# import required libraries
from vidgear.gears import VideoGear
from vidgear.gears import NetGear
from vidgear.gears import PiGear
!!! new "Backend PiGear API now fully supports the newer [`picamera2`](https://github.com/raspberrypi/picamera2) python library under the hood for Raspberry Pi :fontawesome-brands-raspberry-pi: camera modules. Follow this [guide ➢](../../installation/pip_install/#picamera2) for its installation."

# add various Picamera tweak parameters to dictionary
options = {
"hflip": True,
"exposure_mode": "auto",
"iso": 800,
"exposure_compensation": 15,
"awb_mode": "horizon",
"sensor_mode": 0,
}
!!! warning "Make sure to [complete Raspberry Pi Camera Hardware-specific settings](https://www.raspberrypi.com/documentation/accessories/camera.html#installing-a-raspberry-pi-camera) prior using this backend, otherwise nothing will work."

# open pi video stream with defined parameters
stream = PiGear(resolution=(640, 480), framerate=60, logging=True, **options).start()

# activate Bidirectional mode
options = {"bidirectional_mode": True}
=== "New Picamera2 backend"

# Define NetGear server at given IP address and define parameters
# !!! change following IP address '192.168.x.xxx' with client's IP address !!!
server = NetGear(
address="192.168.x.xxx",
port="5454",
protocol="tcp",
pattern=1,
logging=True,
**options
)
```python linenums="1" hl_lines="25-30"
# import required libraries
from vidgear.gears import VideoGear
from vidgear.gears import NetGear
from vidgear.gears import PiGear
from libcamera import Transform

# loop over until KeyBoard Interrupted
while True:
# add various Picamera2 API tweaks
options = {
"queue": True,
"buffer_count": 4,
"controls": {"Brightness": 0.5, "ExposureValue": 2.0},
"transform": Transform(hflip=1),
"auto_align_output_config": True, # auto-align camera configuration
}

try:
# read frames from stream
frame = stream.read()
# open pi video stream with defined parameters
stream = PiGear(resolution=(640, 480), framerate=60, logging=True, **options).start()

# check for frame if Nonetype
if frame is None:
# activate Bidirectional mode
options = {"bidirectional_mode": True}

# Define NetGear server at given IP address and define parameters
# !!! change following IP address '192.168.x.xxx' with client's IP address !!!
server = NetGear(
address="192.168.x.xxx",
port="5454",
protocol="tcp",
pattern=1,
logging=True,
**options
)

# loop over until KeyBoard Interrupted
while True:

try:
# read frames from stream
frame = stream.read()

# check for frame if Nonetype
if frame is None:
break

# {do something with the frame here}

# prepare data to be sent(a simple text in our case)
target_data = "Hello, I am a Server."

# send frame & data and also receive data from Client
recv_data = server.send(frame, message=target_data) # (1)

# print data just received from Client
if not (recv_data is None):
print(recv_data)

except KeyboardInterrupt:
break

# {do something with the frame here}
# safely close video stream
stream.stop()

# prepare data to be sent(a simple text in our case)
target_data = "Hello, I am a Server."
# safely close server
server.close()
```

# send frame & data and also receive data from Client
recv_data = server.send(frame, message=target_data) # (1)
1. :warning: Everything except [numpy.ndarray](https://numpy.org/doc/1.18/reference/generated/numpy.ndarray.html#numpy-ndarray) datatype data is accepted as `target_data` in `message` parameter.

# print data just received from Client
if not (recv_data is None):
print(recv_data)

=== "Legacy Picamera backend"

except KeyboardInterrupt:
break
??? info "Under the hood, Backend PiGear API _(version `0.3.3` onwards)_ prioritizes the new [`picamera2`](https://github.com/raspberrypi/picamera2) API backend."

# safely close video stream
stream.stop()
However, the API seamlessly switches to the legacy [`picamera`](https://picamera.readthedocs.io/en/release-1.13/index.html) backend, if the `picamera2` library is unavailable or not installed.
!!! tip "It is advised to enable logging(`logging=True`) to see which backend is being used."

# safely close server
server.close()
```
!!! failure "The `picamera` library is built on the legacy camera stack that is NOT _(and never has been)_ supported on 64-bit OS builds."

!!! note "You could also enforce the legacy picamera API backend in PiGear by using the [`enforce_legacy_picamera`](../../gears/pigear/params) user-defined optional parameter boolean attribute."

```python linenums="1" hl_lines="25-30"
# 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
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()

# activate Bidirectional mode
options = {"bidirectional_mode": True}

# Define NetGear server at given IP address and define parameters
# !!! change following IP address '192.168.x.xxx' with client's IP address !!!
server = NetGear(
address="192.168.x.xxx",
port="5454",
protocol="tcp",
pattern=1,
logging=True,
**options
)

# loop over until KeyBoard Interrupted
while True:

try:
# read frames from stream
frame = stream.read()

# check for frame if Nonetype
if frame is None:
break

# {do something with the frame here}

# prepare data to be sent(a simple text in our case)
target_data = "Hello, I am a Server."

# send frame & data and also receive data from Client
recv_data = server.send(frame, message=target_data) # (1)

# print data just received from Client
if not (recv_data is None):
print(recv_data)

except KeyboardInterrupt:
break

# safely close video stream
stream.stop()

# safely close server
server.close()
```

1. :warning: Everything except [numpy.ndarray](https://numpy.org/doc/1.18/reference/generated/numpy.ndarray.html#numpy-ndarray) datatype data is accepted as `target_data` in `message` parameter.

1. :warning: Everything except [numpy.ndarray](https://numpy.org/doc/1.18/reference/generated/numpy.ndarray.html#numpy-ndarray) datatype data is accepted as `target_data` in `message` parameter.

 

Expand All @@ -380,7 +469,7 @@ Open your favorite terminal and execute the following python code:

!!! tip "You can terminate both side anytime by pressing ++ctrl+"C"++ on your keyboard!"

```python hl_lines="35-45"
```python linenums="1" hl_lines="35-45"
# import required libraries
from vidgear.gears import NetGear
from vidgear.gears.helper import reducer
Expand Down Expand Up @@ -447,7 +536,7 @@ Then open another terminal on the same system and execute the following python c

!!! tip "You can terminate client anytime by pressing ++ctrl+"C"++ on your keyboard!"

```python hl_lines="29"
```python linenums="1" hl_lines="29"
# import required libraries
from vidgear.gears import NetGear
from vidgear.gears.helper import reducer
Expand Down
16 changes: 8 additions & 8 deletions docs/gears/netgear/advanced/compression.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ 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 hl_lines="11-14"
```python linenums="1" hl_lines="11-14"
# import required libraries
from vidgear.gears import VideoGear
from vidgear.gears import NetGear
Expand Down Expand Up @@ -173,7 +173,7 @@ Then open another terminal on the same system and execute the following python c

!!! note "If compression is enabled at Server, then Client will automatically enforce Frame Compression with its performance attributes."

```python
```python linenums="1"
# import required libraries
from vidgear.gears import NetGear
import cv2
Expand Down Expand Up @@ -230,7 +230,7 @@ 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 hl_lines="7 11"
```python linenums="1" hl_lines="7 11"
# import required libraries
from vidgear.gears import VideoGear
from vidgear.gears import NetGear
Expand Down Expand Up @@ -288,7 +288,7 @@ Then open another terminal on the same system and execute the following python c

!!! info "Client's end also automatically enforces Server's colorspace, there's no need to define it again."

```python
```python linenums="1"
# import required libraries
from vidgear.gears import NetGear
import cv2
Expand Down Expand Up @@ -340,7 +340,7 @@ Open a terminal on Client System _(where you want to display the input frames re

!!! tip "You can terminate client anytime by pressing ++ctrl+"C"++ on your keyboard!"

```python hl_lines="9-15"
```python linenums="1" hl_lines="9-15"
# import required libraries
from vidgear.gears import NetGear
import cv2
Expand Down Expand Up @@ -395,7 +395,7 @@ Now, Open the terminal on another Server System _(with a webcam connected to it

!!! tip "You can terminate stream on both side anytime by pressing ++ctrl+"C"++ on your keyboard!"

```python hl_lines="20-25"
```python linenums="1" hl_lines="20-25"
# import required libraries
from vidgear.gears import VideoGear
from vidgear.gears import NetGear
Expand Down Expand Up @@ -475,7 +475,7 @@ Open your favorite terminal and execute the following python code:

!!! tip "You can terminate both side anytime by pressing ++ctrl+"C"++ on your keyboard!"

```python hl_lines="12-16 42"
```python linenums="1" hl_lines="12-16 42"
# import required libraries
from vidgear.gears import NetGear
from vidgear.gears.helper import reducer
Expand Down Expand Up @@ -548,7 +548,7 @@ Then open another terminal on the same system and execute the following python c

!!! tip "You can terminate client anytime by pressing ++ctrl+"C"++ on your keyboard!"

```python hl_lines="8-12 35"
```python linenums="1" hl_lines="8-12 35"
# import required libraries
from vidgear.gears import NetGear
from vidgear.gears.helper import reducer
Expand Down
Loading

0 comments on commit 20dec0a

Please sign in to comment.