diff --git a/docs/gears/webgear_rtc/advanced.md b/docs/gears/webgear_rtc/advanced.md
index 159a084ca..175c0b676 100644
--- a/docs/gears/webgear_rtc/advanced.md
+++ b/docs/gears/webgear_rtc/advanced.md
@@ -64,87 +64,85 @@ web.shutdown()
## Using WebGear_RTC with a Custom Source(OpenCV)
-WebGear_RTC allows you to easily define your own Custom Media Server with a custom source that you want to use to transform your frames before sending them onto the browser.
+WebGear_RTC provides [`custom_stream`](../params/#webgear_rtc-specific-attributes) attribute with its `options` parameter that allows you to easily define your own Custom Streaming Class with suitable source that you want to use to transform your frames before sending them onto the browser.
Let's implement a bare-minimum example with a Custom Source using WebGear_RTC API and OpenCV:
+??? new "New in v0.2.4"
+ This implementation was added in `v0.2.4`.
-!!! warning "Auto-Reconnection will NOT work with Custom Source(OpenCV)"
+!!! success "Auto-Reconnection or Auto-Refresh works out-of-the-box with this implementation."
- - The WebGear_RTC's inbuilt auto-reconnection feature only available with its internal [**RTC_VideoServer**](https://github.com/abhiTronix/vidgear/blob/38a7f54eb911218e1fd6a95e243da2fba51a6991/vidgear/gears/asyncio/webgear_rtc.py#L77) which can seamlessly handle restarting of source/server any number of times, and therefore will fail to work with your user-defined Custom Source(OpenCV).
- - This means that once the browser tab with WebGear_RTC stream is closed, it will require you to manually close and restart the WebGear_RTC server, in order to refresh or reopen it in a new browser/tab successfully.
+!!! danger "Make sure your Custom Streaming Class at-least implements `read()` and `stop()` methods as shown in following example, otherwise WebGear_RTC will throw ValueError!"
-!!! danger "Make sure your Custom Media Server Class is inherited from aiortc's [VideoStreamTrack](https://github.com/aiortc/aiortc/blob/a270cd887fba4ce9ccb680d267d7d0a897de3d75/src/aiortc/mediastreams.py#L109) only and at-least implements `recv()` and `terminate()` methods as shown in following example, otherwise WebGear_RTC will throw ValueError!"
+???+ tip "Using Vidgear's VideoCapture APIs instead of OpenCV"
+ You can directly replace Custom Streaming Class(`Custom_Stream_Class` in following example) with any [VideoCapture APIs](../../#a-videocapture-gears). These APIs implements `read()` and `stop()` methods by-default, so they're also supported out-of-the-box.
+ See this [example ➶](../../../help/screengear_ex/#using-screengear-with-webgear_rtc) for more information.
-```python hl_lines="13-63 67"
+
+```python hl_lines="6-54 58"
# import necessary libs
-import uvicorn, asyncio, cv2
-from av import VideoFrame
-from aiortc import VideoStreamTrack
-from aiortc.mediastreams import MediaStreamError
+import uvicorn, cv2
from vidgear.gears.asyncio import WebGear_RTC
-from vidgear.gears.asyncio.helper import reducer
-
-# initialize WebGear_RTC app without any source
-web = WebGear_RTC(logging=True)
-# create your own Bare-Minimum Custom Media Server
-class Custom_RTCServer(VideoStreamTrack):
+# create your own custom streaming class
+class Custom_Stream_Class:
"""
- Custom Media Server using OpenCV, an inherit-class
- to aiortc's VideoStreamTrack.
+ Custom Streaming using OpenCV
"""
- def __init__(self, source=None):
+ def __init__(self, source=0):
- # don't forget this line!
- super().__init__()
+ # !!! define your own video source here !!!
+ self.source = cv2.VideoCapture(source)
- # initialize global params
- self.stream = cv2.VideoCapture(source)
+ # define running flag
+ self.running = True
- async def recv(self):
- """
- A coroutine function that yields `av.frame.Frame`.
- """
- # don't forget this function!!!
+ def read(self):
- # get next timestamp
- pts, time_base = await self.next_timestamp()
+ # don't forget this function!!!
- # read video frame
- (grabbed, frame) = self.stream.read()
+ # check if source was initialized or not
+ if self.source is None:
+ return None
+ # check if we're still running
+ if self.running:
+ # read frame from provided source
+ (grabbed, frame) = self.source.read()
+ # check if frame is available
+ if grabbed:
- # if NoneType
- if not grabbed:
- return MediaStreamError
+ # do something with your OpenCV frame here
- # reducer frames size if you want more performance otherwise comment this line
- frame = await reducer(frame, percentage=30) # reduce frame by 30%
+ # lets convert frame to gray for this example
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
- # contruct `av.frame.Frame` from `numpy.nd.array`
- av_frame = VideoFrame.from_ndarray(frame, format="bgr24")
- av_frame.pts = pts
- av_frame.time_base = time_base
+ # return our gray frame
+ return gray
+ else:
+ # signal we're not running now
+ self.running = False
+ # return None-type
+ return None
- # return `av.frame.Frame`
- return av_frame
+ def stop(self):
- def terminate(self):
- """
- Gracefully terminates VideoGear stream
- """
# don't forget this function!!!
- # terminate
- if not (self.stream is None):
- self.stream.release()
- self.stream = None
+ # flag that we're not running
+ self.running = False
+ # close stream
+ if not self.source is None:
+ self.source.release()
+# assign your Custom Streaming Class with adequate source (for e.g. foo.mp4)
+# to `custom_stream` attribute in options parameter
+options = {"custom_stream": Custom_Stream_Class(source="foo.mp4")}
-# assign your custom media server to config with adequate source (for e.g. foo.mp4)
-web.config["server"] = Custom_RTCServer(source="foo.mp4")
+# initialize WebGear_RTC app without any source
+web = WebGear_RTC(logging=True, **options)
# run this app on Uvicorn server at address http://localhost:8000/
uvicorn.run(web(), host="localhost", port=8000)
@@ -155,6 +153,7 @@ web.shutdown()
**And that's all, Now you can see output at [`http://localhost:8000/`](http://localhost:8000/) address.**
+
diff --git a/docs/gears/webgear_rtc/params.md b/docs/gears/webgear_rtc/params.md
index ab598c1e0..3fc6911a3 100644
--- a/docs/gears/webgear_rtc/params.md
+++ b/docs/gears/webgear_rtc/params.md
@@ -55,6 +55,28 @@ This parameter can be used to pass user-defined parameter to WebGear_RTC API by
### WebGear_RTC Specific attributes
+* **`custom_stream`** _(class)_ : Can be used to easily define your own Custom Streaming Class with suitable custom source(such as OpenCV) that you want to use to transform your frames before sending them onto the browser.
+
+ !!! danger "Make sure your Custom Streaming Class at-least implements `read()` and `stop()` methods, otherwise WebGear_RTC will throw ValueError!"
+
+ ??? new "New in v0.2.4"
+ This attribute was added in `v0.2.4`.
+
+ ??? tip "Using Vidgear's VideoCapture APIs instead of OpenCV"
+ You can directly replace Custom Streaming Class with any [VideoCapture APIs](../../#a-videocapture-gears). These APIs implements `read()` and `stop()` methods by-default, so they're also supported out-of-the-box.
+
+ See this [example ➶](../../../help/screengear_ex/#using-screengear-with-webgear_rtc) for more information.
+
+ !!! example "Its complete usage example is given [here ➶](../advanced/#using-webgear_rtc-with-a-custom-sourceopencv)."
+
+ ```python
+ # set CamGear as custom streaming class with adequate parameters
+ options = {"custom_stream": CamGear(source="foo.mp4", logging=True)}
+ # assign it
+ WebGear_RTC(logging=True, **options)
+ ```
+
+
* **`custom_data_location`** _(string)_ : Can be used to change/alter [*default location*](../overview/#default-location) path to somewhere else. Its usage is as follows:
```python
diff --git a/docs/help/netgear_ex.md b/docs/help/netgear_ex.md
index 2af3512f3..3c4dc3330 100644
--- a/docs/help/netgear_ex.md
+++ b/docs/help/netgear_ex.md
@@ -178,8 +178,8 @@ server.close()
The complete usage example is as follows:
-??? new "New in v0.2.2"
- This example was added in `v0.2.2`.
+??? new "New in v0.2.4"
+ This example was added in `v0.2.4`.
### Client + WebGear_RTC Server
@@ -193,33 +193,19 @@ Open a terminal on Client System where you want to display the input frames _(an
!!! info "Note down the local IP-address of this system(required at Server's end) and also replace it in the following code. You can follow [this FAQ](../netgear_faqs/#how-to-find-local-ip-address-on-different-os-platforms) for this purpose."
-```python
-# import required libraries
-import uvicorn, asyncio, cv2
-from av import VideoFrame
-from aiortc import VideoStreamTrack
-from aiortc.mediastreams import MediaStreamError
+!!! fail "For VideoCapture APIs you also need to implement `start()` in addition to `read()` and `stop()` methods in your Custom Streaming Class as shown in following example, otherwise WebGear_RTC will fail to work!"
+
+```python hl_lines="8-79 92-101"
+# import necessary libs
+import uvicorn, cv2
from vidgear.gears import NetGear
+from vidgear.gears.helper import reducer
from vidgear.gears.asyncio import WebGear_RTC
-from vidgear.gears.asyncio.helper import reducer
-
-# initialize WebGear_RTC app without any source
-web = WebGear_RTC(logging=True)
-
-# activate jpeg encoding and specify other related parameters
-options = {
- "jpeg_compression": True,
- "jpeg_compression_quality": 90,
- "jpeg_compression_fastdct": True,
- "jpeg_compression_fastupsample": True,
-}
-
-# create your own Bare-Minimum Custom Media Server
-class Custom_RTCServer(VideoStreamTrack):
+# create your own custom streaming class
+class Custom_Stream_Class:
"""
- Custom Media Server using OpenCV, an inherit-class
- to aiortc's VideoStreamTrack.
+ Custom Streaming using NetGear Receiver
"""
def __init__(
@@ -229,72 +215,91 @@ class Custom_RTCServer(VideoStreamTrack):
protocol="tcp",
pattern=1,
logging=True,
- options={},
+ **options,
):
- # don't forget this line!
- super().__init__()
-
# initialize global params
# Define NetGear Client at given IP address and define parameters
self.client = NetGear(
receive_mode=True,
address=address,
- port=protocol,
+ port=port,
+ protocol=protocol,
pattern=pattern,
- receive_mode=True,
logging=logging,
**options
)
+ self.running = False
- async def recv(self):
- """
- A coroutine function that yields `av.frame.Frame`.
- """
+ def start(self):
+
# don't forget this function!!!
+ # This function is specific to VideoCapture APIs only
- # get next timestamp
- pts, time_base = await self.next_timestamp()
+ if not self.source is None:
+ self.source.start()
- # receive frames from network
- frame = self.client.recv()
+ def read(self):
- # if NoneType
- if frame is None:
- raise MediaStreamError
+ # don't forget this function!!!
- # reducer frames size if you want more performance otherwise comment this line
- frame = await reducer(frame, percentage=30) # reduce frame by 30%
+ # check if source was initialized or not
+ if self.source is None:
+ return None
+ # check if we're still running
+ if self.running:
+ # receive frames from network
+ frame = self.client.recv()
+ # check if frame is available
+ if not (frame is None):
+
+ # do something with your OpenCV frame here
- # contruct `av.frame.Frame` from `numpy.nd.array`
- av_frame = VideoFrame.from_ndarray(frame, format="bgr24")
- av_frame.pts = pts
- av_frame.time_base = time_base
+ # reducer frames size if you want more performance otherwise comment this line
+ frame = reducer(frame, percentage=20) # reduce frame by 20%
- # return `av.frame.Frame`
- return av_frame
+ # return our gray frame
+ return frame
+ else:
+ # signal we're not running now
+ self.running = False
+ # return None-type
+ return None
+
+ def stop(self):
- def terminate(self):
- """
- Gracefully terminates VideoGear stream
- """
# don't forget this function!!!
- # terminate
+ # flag that we're not running
+ self.running = False
+ # close stream
if not (self.client is None):
self.client.close()
self.client = None
-# assign your custom media server to config with adequate IP address
-# !!! change following IP address '192.168.x.xxx' with yours !!!
-web.config["server"] = Custom_RTCServer(
- address="192.168.x.xxx",
- port="5454",
- protocol="tcp",
- pattern=1,
- logging=True,
- **options
-)
+# activate jpeg encoding and specify NetGear related parameters
+options = {
+ "jpeg_compression": True,
+ "jpeg_compression_quality": 90,
+ "jpeg_compression_fastdct": True,
+ "jpeg_compression_fastupsample": True,
+}
+
+# assign your Custom Streaming Class with adequate NetGear parameters
+# to `custom_stream` attribute in options parameter of WebGear_RTC.
+options = {
+ "custom_stream": Custom_Stream_Class(
+ address="192.168.x.xxx",
+ port="5454",
+ protocol="tcp",
+ pattern=1,
+ logging=True,
+ **options
+ )
+}
+
+# initialize WebGear_RTC app without any source
+web = WebGear_RTC(logging=True, **options)
# run this app on Uvicorn server at address http://localhost:8000/
uvicorn.run(web(), host="localhost", port=8000)
diff --git a/docs/help/screengear_ex.md b/docs/help/screengear_ex.md
index d4875ea40..b32eed4f1 100644
--- a/docs/help/screengear_ex.md
+++ b/docs/help/screengear_ex.md
@@ -96,7 +96,7 @@ Now, Open the terminal on another Server System _(with a montior/display attache
```python
# import required libraries
-from vidgear.gears import VideoGear
+from vidgear.gears import ScreenGear
from vidgear.gears import NetGear
# define dimensions of screen w.r.t to given monitor to be captured
@@ -151,88 +151,114 @@ server.close()
The complete usage example is as follows:
-??? new "New in v0.2.3"
- This example was added in `v0.2.3`.
+??? new "New in v0.2.4"
+ This example was added in `v0.2.4`.
-```python
-# import necessary libs
-import uvicorn, asyncio, cv2
-from av import VideoFrame
-from aiortc import VideoStreamTrack
-from aiortc.mediastreams import MediaStreamError
-from vidgear.gears import ScreenGear
-from vidgear.gears.asyncio import WebGear_RTC
-from vidgear.gears.asyncio.helper import reducer
+=== "Bare-Minimum"
+
+ ```python hl_lines="8"
+ # import necessary libs
+ import uvicorn, cv2
+ from vidgear.gears import ScreenGear
+ from vidgear.gears.asyncio import WebGear_RTC
+
+ # assign your ScreenGear class with adequate parameters
+ # to `custom_stream` attribute in options parameter
+ options = {"custom_stream": ScreenGear(logging=True)}
-# initialize WebGear_RTC app without any source
-web = WebGear_RTC(logging=True)
+ # initialize WebGear_RTC app without any source
+ web = WebGear_RTC(logging=True, **options)
-# create your own Bare-Minimum Custom Media Server with ScreenGear source
-class Custom_RTCScreenGearServer(VideoStreamTrack):
- """
- Custom Media Server using OpenCV, an inherit-class
- to aiortc's VideoStreamTrack.
- """
+ # run this app on Uvicorn server at address http://localhost:8000/
+ uvicorn.run(web(), host="localhost", port=8000)
- def __init__(self, monitor=None, logging=False):
+ # close app safely
+ web.shutdown()
+ ```
- # don't forget this line!
- super().__init__()
+=== "Advanced"
- # initialize global params
- self.stream = ScreenGear(monitor=monitor, logging=logging).start()
+ !!! fail "For VideoCapture APIs you also need to implement `start()` in addition to `read()` and `stop()` methods in your Custom Streaming Class as shown in following example, otherwise WebGear_RTC will fail to work!"
- async def recv(self):
+ ```python hl_lines="8-64 69"
+ # import necessary libs
+ import uvicorn, cv2
+ from vidgear.gears import ScreenGear
+ from vidgear.gears.helper import reducer
+ from vidgear.gears.asyncio import WebGear_RTC
+
+ # create your own custom streaming class
+ class Custom_Stream_Class:
"""
- A coroutine function that yields `av.frame.Frame`.
+ Custom Streaming using ScreenGear
"""
- # don't forget this function!!!
- # get next timestamp
- pts, time_base = await self.next_timestamp()
+ def __init__(self, backend="mss", logging=False):
- # read video frame
- frame = self.stream.read()
+ # !!! define your own video source here !!!
+ self.source = ScreenGear(backend=backend, logging=logging)
- # if NoneType
- if frame is None:
- return MediaStreamError
+ # define running flag
+ self.running = True
- # reducer frames size if you want more performance otherwise comment this line
- frame = await reducer(frame, percentage=20) # reduce frame by 20%
+ def start(self):
- # contruct `av.frame.Frame` from `numpy.nd.array`
- if frame.shape[-1] == 4:
- # hack: handles `mss` backend that outputs BGRA frames
- av_frame = VideoFrame.from_ndarray(frame, format="bgra")
- else:
- av_frame = VideoFrame.from_ndarray(frame, format="bgr24")
- av_frame.pts = pts
- av_frame.time_base = time_base
+ # don't forget this function!!!
+ # This function is specific to VideoCapture APIs only
- # return `av.frame.Frame`
- return av_frame
+ if not self.source is None:
+ self.source.start()
- def terminate(self):
- """
- Gracefully terminates VideoGear stream
- """
- # don't forget this function!!!
+ def read(self):
- # terminate
- if not (self.stream is None):
- self.stream.stop()
- self.stream = None
+ # don't forget this function!!!
+ # check if source was initialized or not
+ if self.source is None:
+ return None
+ # check if we're still running
+ if self.running:
+ # read frame from provided source
+ frame = self.source.read()
+ # check if frame is available
+ if not(frame is None):
-# assign your custom media server to config with ScreenGear source
-web.config["server"] = Custom_RTCScreenGearServer(logging=True)
+ # do something with your OpenCV frame here
-# run this app on Uvicorn server at address http://localhost:8000/
-uvicorn.run(web(), host="localhost", port=8000)
+ # reducer frames size if you want more performance otherwise comment this line
+ frame = reducer(frame, percentage=20) # reduce frame by 20%
-# close app safely
-web.shutdown()
-```
+ # return our gray frame
+ return frame
+ else:
+ # signal we're not running now
+ self.running = False
+ # return None-type
+ return None
+
+ def stop(self):
+
+ # don't forget this function!!!
+
+ # flag that we're not running
+ self.running = False
+ # close stream
+ if not self.source is None:
+ self.source.stop()
+
+
+ # assign your Custom Streaming Class with adequate ScreenGear parameters
+ # to `custom_stream` attribute in options parameter
+ options = {"custom_stream": Custom_Stream_Class(backend="pil", logging=True)}
+
+ # initialize WebGear_RTC app without any source
+ web = WebGear_RTC(logging=True, **options)
+
+ # run this app on Uvicorn server at address http://localhost:8000/
+ uvicorn.run(web(), host="localhost", port=8000)
+
+ # close app safely
+ web.shutdown()
+ ```
diff --git a/docs/help/webgear_rtc_ex.md b/docs/help/webgear_rtc_ex.md
index 1bdf1876d..8b41c398d 100644
--- a/docs/help/webgear_rtc_ex.md
+++ b/docs/help/webgear_rtc_ex.md
@@ -90,17 +90,15 @@ web.shutdown()
In this example, we'll be displaying two video feeds side-by-side simultaneously on browser using WebGear_RTC API by simply concatenating frames in real-time:
-??? new "New in v0.2.2"
- This example was added in `v0.2.2`.
+??? new "New in v0.2.4"
+ This example was added in `v0.2.4`.
-```python
+```python hl_lines="10-22 26-92 97-101"
# import necessary libs
-import uvicorn, asyncio, cv2
+import uvicorn, cv2
import numpy as np
-from av import VideoFrame
-from aiortc import VideoStreamTrack
+from vidgear.gears.helper import reducer
from vidgear.gears.asyncio import WebGear_RTC
-from vidgear.gears.asyncio.helper import reducer
# initialize WebGear_RTC app without any source
web = WebGear_RTC(logging=True)
@@ -120,18 +118,15 @@ def get_conc_frame(frame1, frame2):
return vis
-# create your own Bare-Minimum Custom Media Server
-class Custom_RTCServer(VideoStreamTrack):
+# create your own custom streaming class
+class Custom_Stream_Class:
"""
- Custom Media Server using OpenCV, an inherit-class
- to aiortc's VideoStreamTrack.
+ Custom Streaming using two OpenCV sources
"""
def __init__(self, source1=None, source2=None):
- # don't forget this line!
- super().__init__()
-
+ # !!! define your own video source here !!!
# check is source are provided
if source1 is None or source2 is None:
raise ValueError("Provide both source")
@@ -141,46 +136,49 @@ class Custom_RTCServer(VideoStreamTrack):
self.stream1 = cv2.VideoCapture(source1)
self.stream2 = cv2.VideoCapture(source2)
- async def recv(self):
- """
- A coroutine function that yields `av.frame.Frame`.
- """
- # don't forget this function!!!
+ # define running flag
+ self.running = True
- # get next timestamp
- pts, time_base = await self.next_timestamp()
+ def read(self):
- # read video frame
- (grabbed1, frame1) = self.stream1.read()
- (grabbed2, frame2) = self.stream2.read()
+ # don't forget this function!!!
- # if NoneType
- if not grabbed1 or not grabbed2:
+ # check if sources were initialized or not
+ if self.stream1 is None or self.stream2 is None:
return None
- else:
- print("Got frames")
- # concatenate frame
- frame = get_conc_frame(frame1, frame2)
+ # check if we're still running
+ if self.running:
+ # read video frame
+ (grabbed1, frame1) = self.stream1.read()
+ (grabbed2, frame2) = self.stream2.read()
+
+ # if NoneType
+ if not grabbed1 or not grabbed2:
+
+ # do something with your OpenCV frame here
- # reducer frames size if you want more performance otherwise comment this line
- # frame = await reducer(frame, percentage=30) # reduce frame by 30%
+ # concatenate frame
+ frame = get_conc_frame(frame1, frame2)
- # contruct `av.frame.Frame` from `numpy.nd.array`
- av_frame = VideoFrame.from_ndarray(frame, format="bgr24")
- av_frame.pts = pts
- av_frame.time_base = time_base
+ # reducer frames size if you want more performance otherwise comment this line
+ # frame = await reducer(frame, percentage=30) # reduce frame by 30%
- # return `av.frame.Frame`
- return av_frame
+ # return our gray frame
+ return frame
+ else:
+ # signal we're not running now
+ self.running = False
+ # return None-type
+ return None
+
+ def stop(self):
- def terminate(self):
- """
- Gracefully terminates VideoGear stream
- """
# don't forget this function!!!
- # terminate
+ # flag that we're not running
+ self.running = False
+ # close stream
if not (self.stream1 is None):
self.stream1.release()
self.stream1 = None
@@ -190,10 +188,16 @@ class Custom_RTCServer(VideoStreamTrack):
self.stream2 = None
-# assign your custom media server to config with both adequate sources (for e.g. foo1.mp4 and foo2.mp4)
-web.config["server"] = Custom_RTCServer(
- source1="dance_videos/foo1.mp4", source2="dance_videos/foo2.mp4"
-)
+# assign your Custom Streaming Class with adequate two sources
+# to `custom_stream` attribute in options parameter
+options = {
+ "custom_stream": Custom_Stream_Class(
+ source1="foo1.mp4", source2="foo2.mp4"
+ )
+}
+
+# initialize WebGear_RTC app without any source
+web = WebGear_RTC(logging=True, **options)
# run this app on Uvicorn server at address http://localhost:8000/
uvicorn.run(web(), host="localhost", port=8000)
diff --git a/docs/overrides/main.html b/docs/overrides/main.html
index d8bec1688..e91bccebe 100644
--- a/docs/overrides/main.html
+++ b/docs/overrides/main.html
@@ -24,10 +24,16 @@
{% endblock %}
{% block announce %}
- {% set announcement_link = config.site_url ~ '/installation/pip_install/#Installation' %}
+ {% set announcement_link = config.site_url ~ '/installation/pip_install/#installation' %}
Installation command has been changed in v0.2.4
. More information can be found here ➶
{% endblock %}
+{% block outdated %}
+ You're not viewing the latest version.
+
+ Click here to go to latest.
+
+{% endblock %}
{% block content %}
{{ super() }}