Skip to content
Search

ONVIF:Example:FindDevice

lastmod 2024-10-14created 2021-10-1322 edits

Notes on how to find cameras on the network and communicate with them over ONVIF. The code uses Python.

For the official ONVIF documentation, see the ONVIF Application Programmer's Guide.1

The WSDL specs of ONVIF can be downloaded from Network Interface Specifications - ONVIF or Github - onvif/specs.

Device Discovery

First check whether the device exists on the network. The spec used for this is WS-Discovery, and the Python library used is WSDiscovery.

It works over TCP and UDP port 3702 and uses the IP multicast address 239.255.255.250 or FF02::C; the actual communication is done with SOAP-over-UDP.

The code is as follows:

from wsdiscovery.discovery import ThreadedWSDiscovery as WSDiscovery

wsd = WSDiscovery()
wsd.start()
services = wsd.searchServices()
for service in services:
    for address in service.getXAddrs():
        print(service.getEPR() + ":" + address)

The output looks like this:

urn:uuid:03590000-e4f9-11b4-8389-5803fb986fcf:http://192.168.0.201/onvif/device_service
urn:uuid:03590000-e4f9-11b4-8389-5803fb986fcf:http://[fe80::5a03:fbff:fe98:6fcf]/onvif/device_service
urn:uuid:78c2c020-78c2-4c02-801d-78c2c0201d75:http://192.168.0.50/onvif/device_service
urn:uuid:594333b6-5750-4471-b3aa-bec2042940c6:http://192.168.0.61:5357/594333b6-5750-4471-b3aa-bec2042940c6/

Remember the device's UUID and the address for the WSDL.

WSDL Device Management

Get various information about the device through the WSDL device management service. It works over SOAP. Uses the zeep library.

from zeep import Client
wsdl = "http://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl"
client = Client(wsdl=wsdl)
service = client.create_service("{http://www.onvif.org/ver10/device/wsdl}DeviceBinding", "http://192.168.0.50/onvif/device_service")
print(service.GetCapabilities())

For the arguments to Client.create_service, see zeep#Client.create_service.

Device information can be obtained through the WSDL spec (devicemgmt.wsdl).

Importantly, Media-related information can be obtained through the GetCapabilities() SOAP API.

The output looks like this:

{
    ...
    'Media': {
        'XAddr': 'http://192.168.0.50/onvif/device_service',
        'StreamingCapabilities': {
            'RTPMulticast': True,
            'RTP_TCP': True,
            'RTP_RTSP_TCP': True,
            'Extension': None,
            '_attr_1': None
        },
        '_value_1': None,
        'Extension': None,
        '_attr_1': None
    },
    ...

Remember the XAddr and StreamingCapabilities above. They are needed at the last step, when getting the stream address.

Getting media profile information

Get media information through the media.wsdl spec. If needed, add authentication information such as UsernameToken, HTTPBasicAuth, or HTTPDigestAuth.

from zeep import Client
from zeep.wsse.username import UsernameToken

wsdl = "http://www.onvif.org/ver10/media/wsdl/media.wsdl"
client = Client(wsdl=wsdl, wsse=UsernameToken("admin", "0000", use_digest=True))
service = client.create_service("{http://www.onvif.org/ver10/media/wsdl}MediaBinding", "http://192.168.0.50/onvif/device_service")
profiles = service.GetProfiles()
print(profiles)

The profiles are printed as follows:

[{
    'Name': 'Profile1',
    'VideoSourceConfiguration': {
        ...
    },
    'token': 'Profile1',
...

Remember the token name of the profile to use for streaming. Above, it is "Profile1".

Note that wsse is a keyword indicating the pre-OASIS version.

Getting the stream URI

After getting the token name above, get the stream URI as follows.

factory = client.type_factory("http://www.onvif.org/ver10/schema")
transport = factory.Transport(Protocol='RTSP')
setup = factory.StreamSetup(Stream='RTP-Unicast', Transport=transport)
result = service.GetStreamUri(StreamSetup=setup, ProfileToken='Profile1')
print(result)

The result is printed as follows:

{
    'Uri': 'rtsp://192.168.0.50:554/media/1/1/Profile1',
    'InvalidAfterConnect': False,
    'InvalidAfterReboot': True,
    'Timeout': datetime.timedelta(0),
    '_value_1': None,
    '_attr_1': None
}

The list of Transport Protocols is as follows:

    <xs:simpleType name="TransportProtocol">
        <xs:restriction base="xs:string">
            <xs:enumeration value="UDP"/>
            <xs:enumeration value="TCP"/>
            <xs:enumeration value="RTSP"/>
            <xs:enumeration value="HTTP"/>
        </xs:restriction>
    </xs:simpleType>

The list of StreamSetup Streams is as follows:

    <xs:simpleType name="StreamType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="RTP-Unicast"/>
            <xs:enumeration value="RTP-Multicast"/>
        </xs:restriction>
    </xs:simpleType>

Getting a snapshot

Call GetSnapshotUri with the profile token.

service.GetSnapshotUri(ProfileToken='Profile1')

The following object is returned.

{
    'Uri': 'http://192.168.0.50/snapshot/1/snapshot.jpg',
    'InvalidAfterConnect': False,
    'InvalidAfterReboot': False,
    'Timeout': datetime.timedelta(0),
    '_value_1': None,
    '_attr_1': None
}

Open the URI above.

Code samples

See also

Favorite site

References


  1. See section 7.1 Using an Existing Profile for Media Streaming ↩

  2. ONVIF_and_SOAP_and_web_service.pdf ↩

  3. ONVIF_WG-APG-Application_Programmers_Guide-1.pdf ↩

author Zer0 sitemap