Skip to content

Commit 2475a5d

Browse files
committed
Add RTSP video video streaming support
Adds support for streaming video from IP video sources over RTSP. This work was sponsored by OIP Sensor Systems. Signed-off-by: Thomas Vreys <thomas.vreys999@gmail.com>
1 parent 0e8d233 commit 2475a5d

8 files changed

Lines changed: 131 additions & 0 deletions

File tree

doc/configuration.rst

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,6 +1387,21 @@ Arguments:
13871387
Used by:
13881388
- `HTTPVideoDriver`_
13891389

1390+
RTSPVideoStream
1391+
~~~~~~~~~~~~~~~
1392+
An :any:`RTSPVideoStream` resource describes an IP video stream over RTSP.
1393+
1394+
.. code-block:: yaml
1395+
1396+
RTSPVideoStream:
1397+
url: 'rtsp://192.168.110.11/stream1'
1398+
1399+
Arguments:
1400+
- url (str): URI of the IP video stream
1401+
1402+
Used by:
1403+
- `RTSPVideoDriver`_
1404+
13901405
USBHub
13911406
~~~~~~
13921407

@@ -3448,6 +3463,25 @@ Although the driver can be used from Python code by calling the ``stream()``
34483463
method, it is currently mainly useful for the ``video`` subcommand of
34493464
``labgrid-client``.
34503465

3466+
RTSPVideoDriver
3467+
~~~~~~~~~~~~~~~
3468+
The :any:`RTSPVideoDriver` is used to show a video stream over RTSP
3469+
from a remote IP video source in a local window.
3470+
3471+
Binds to:
3472+
video:
3473+
- `RTSPVideoStream`_
3474+
3475+
Implements:
3476+
- :any:`VideoProtocol`
3477+
3478+
Arguments:
3479+
- latency (int, default=100): rtspsrc jitterbuffer size in milliseconds
3480+
3481+
Although the driver can be used from Python code by calling the ``stream()``
3482+
method, it is currently mainly useful for the ``video`` subcommand of
3483+
``labgrid-client``.
3484+
34513485
========== =========================================================
34523486
Key Description
34533487
========== =========================================================

labgrid/driver/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from .usbaudiodriver import USBAudioInputDriver
4141
from .usbvideodriver import USBVideoDriver
4242
from .httpvideodriver import HTTPVideoDriver
43+
from .rtspvideodriver import RTSPVideoDriver
4344
from .networkinterfacedriver import NetworkInterfaceDriver
4445
from .provider import HTTPProviderDriver, NFSProviderDriver, TFTPProviderDriver
4546
from .rawnetworkinterfacedriver import RawNetworkInterfaceDriver

labgrid/driver/rtspvideodriver.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import subprocess
2+
import sys
3+
from urllib.parse import urlsplit
4+
5+
import attr
6+
7+
from .common import Driver
8+
from ..factory import target_factory
9+
from ..util.proxy import proxymanager
10+
from ..protocol import VideoProtocol
11+
12+
13+
@target_factory.reg_driver
14+
@attr.s(eq=False)
15+
class RTSPVideoDriver(Driver, VideoProtocol):
16+
bindings = {
17+
"video": "RTSPVideoStream",
18+
}
19+
20+
latency = attr.ib(default=100, validator=attr.validators.instance_of(int))
21+
22+
@Driver.check_active
23+
def stream(self, quality_hint=None, controls=None):
24+
s = urlsplit(self.video.url)
25+
if s.scheme != "rtsp":
26+
print(f"Unknown scheme: {s.scheme}", file=sys.stderr)
27+
return
28+
29+
url = proxymanager.get_url(self.video.url, default_port=554)
30+
pipeline = [
31+
"gst-launch-1.0",
32+
"rtspsrc",
33+
f"location={url}",
34+
f"latency={self.latency}",
35+
"!",
36+
"decodebin",
37+
"!",
38+
"autovideoconvert",
39+
"!",
40+
"autovideosink",
41+
"sync=false",
42+
]
43+
44+
sub = subprocess.run(pipeline)
45+
return sub.returncode

labgrid/remote/client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,6 +1373,7 @@ def video(self):
13731373
target = self._get_target(place)
13741374
name = self.args.name
13751375
from ..resource.httpvideostream import HTTPVideoStream
1376+
from ..resource.rtspvideostream import RTSPVideoStream
13761377
from ..resource.udev import USBVideo
13771378
from ..resource.remote import NetworkUSBVideo
13781379

@@ -1387,6 +1388,8 @@ def video(self):
13871388
drv = self._get_driver_or_new(target, "USBVideoDriver", name=name)
13881389
elif isinstance(resource, HTTPVideoStream):
13891390
drv = self._get_driver_or_new(target, "HTTPVideoDriver", name=name)
1391+
elif isinstance(resource, RTSPVideoStream):
1392+
drv = self._get_driver_or_new(target, "RTSPVideoDriver", name=name)
13901393
if drv:
13911394
break
13921395
if not drv:

labgrid/remote/exporter.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,24 @@ def _get_params(self):
749749
exports["HTTPVideoStream"] = HTTPVideoStreamExport
750750

751751

752+
@attr.s
753+
class RTSPVideoStreamExport(ResourceExport):
754+
"""ResourceExport for an RTSPVideoStream"""
755+
756+
def __attrs_post_init__(self):
757+
super().__attrs_post_init__()
758+
from ..resource.rtspvideostream import RTSPVideoStream
759+
760+
self.data["cls"] = "RTSPVideoStream"
761+
self.local = RTSPVideoStream(target=None, name=None, **self.local_params)
762+
763+
def _get_params(self):
764+
return self.local_params
765+
766+
767+
exports["RTSPVideoStream"] = RTSPVideoStreamExport
768+
769+
752770
@attr.s(eq=False)
753771
class LXAIOBusNodeExport(ResourceExport):
754772
"""ResourceExport for LXAIOBusNode devices accessed via the HTTP API"""

labgrid/resource/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
from .provider import TFTPProvider, NFSProvider, HTTPProvider
4545
from .mqtt import TasmotaPowerPort
4646
from .httpvideostream import HTTPVideoStream
47+
from .rtspvideostream import RTSPVideoStream
4748
from .dediprogflasher import DediprogFlasher, NetworkDediprogFlasher
4849
from .httpdigitalout import HttpDigitalOutput
4950
from .sigrok import SigrokDevice
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import attr
2+
3+
from ..factory import target_factory
4+
from .common import Resource
5+
6+
7+
@target_factory.reg_resource
8+
@attr.s(eq=False)
9+
class RTSPVideoStream(Resource):
10+
url = attr.ib(validator=attr.validators.instance_of(str))

tests/test_rtspvideo.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from labgrid.resource.rtspvideostream import RTSPVideoStream
2+
from labgrid.driver.rtspvideodriver import RTSPVideoDriver
3+
4+
5+
def test_ipvideo_create_rtsp(target):
6+
r = RTSPVideoStream(target, name=None, url="rtsp://localhost/stream1")
7+
d = RTSPVideoDriver(target, name=None)
8+
assert isinstance(d, RTSPVideoDriver)
9+
10+
def test_ipvideo_create_with_port(target):
11+
r = RTSPVideoStream(target, name=None, url="rtsp://localhost:8554/stream1")
12+
d = RTSPVideoDriver(target, name=None)
13+
assert isinstance(d, RTSPVideoDriver)
14+
15+
def test_ipvideo_create_with_latency(target):
16+
r = RTSPVideoStream(target, name=None, url="rtsp://localhost/stream1")
17+
d = RTSPVideoDriver(target, name=None, latency=500)
18+
assert isinstance(d, RTSPVideoDriver)
19+
assert d.latency == 500

0 commit comments

Comments
 (0)