Those are my notes about using the TP-Link Tapo C500 camera in my Linux environment.
More precisely, my Linux system are
- a Debian Testing desktop pc
- a few raspberry pi
- an Asustor NAS that is running a highly customized Linux
- https://www.tp-link.com/en/home-networking/cloud-camera/tapo-c500/
- ONVIF protocol
- https://www.onvif.org/
- https://www.onvif.org/specs/DocMap.html
- Recording on SD Card or Cloud (not enabled)
- PTZ controls to pan, rotate, zoom, ...
- RTSP protocol for video and audio stream
- using either UDP or TCP for transport
- Configuration via the Android Tapo application
- No Web interface!
- or using ONVIF protocol
- IPv4 only (so IPv6)
The camera is using the default rtsp port (554) and provides 2 profiles accessible with the followng URLS
rtsp://username:password@camera_ip/stream1
- The resolution can be 1920x1024, 1280x720 or 640x360
- As far as know, there is no way to specify it in the URL.
- It can only be done via Onvif or the Android app
rtsp://username:password@camera_ip/stream2
- This is always 640x360
nmap reports the following
PORT STATE SERVICE
443/tcp open https
554/tcp open rtsp
1024/tcp open kdm (can also be 1025)
2020/tcp open xinupageserver
8800/tcp open sunwebadmin
That port can be opened with a web browser or with curl -v -k https:\\camera_ip
but produces an error 404.
That could be a hidden web interface or something related to the HTTP transport mode of RTSP
TO BE INVESTIGATED.
This is the default RTSP port so nothing unusual.
The port number changes over time.
This is probably used to sent notifications event to the Onvif clients.
See also port 8800 below.
This is the ONVIF port (non-standard)
After opening it with nc camera_ic 8800
I once got the following reply:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:chan="http://schemas.microsoft.com/ws/2005/02/duplex" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:xmime="http://tempuri.org/xmime.xsd" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:wsrfbf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrfr="http://docs.oasis-open.org/wsrf/r-2" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:tdn="http://www.onvif.org/ver10/network/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:trp="http://www.onvif.org/ver10/replay/wsdl" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl" xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema">
<SOAP-ENV:Header>
<wsa:MessageID>urn:uuid:388f2f01-57ac-4929-9a8f-5e0319e3cff8</wsa:MessageID>
<wsa:To SOAP-ENV:mustUnderstand="true">http://192.168.1.26:1024/event-1024_1024</wsa:To>
<wsa:Action SOAP-ENV:mustUnderstand="true">http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesRequest</wsa:Action>
<wsa5:Action SOAP-ENV:mustUnderstand="true">http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesResponse</wsa5:Action>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<tev:PullMessagesResponse>
<tev:CurrentTime>2024-01-26T10:33:08Z</tev:CurrentTime>
<tev:TerminationTime>2024-01-26T10:34:08Z</tev:TerminationTime>
</tev:PullMessagesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
That message is obviously related to the event mechanism (e.g. a movement was detected) of ONVIF.
The URL on the 4 line also tells me that port 1024 is used to send those events.
TODO: Check for port 8800 in the ONVIF description of the available services.
mpv rtsp://username:password@camera_ip/stream1 --profile=low-latency --untimed
The two options --profile=low-latency --untimed
reduces the latency from about 3s to 1s.
See
ffplay rtsp://username:password@camera_ip/stream1 -rtsp_transport tcp -flags +low_delay -fflags +nobuffer
The option -fflags +nobuffer
reduces the latency from about 3s to less than 1s.
If the option -rtsp_transport tcp
is not set, then ffplay is probably using UDP and the bottom of the image is usually corrupted.
https://www.reddit.com/r/ffmpeg/comments/u741n7/remove_delay_on_ffplay_for_capture_device/
See https://github.com/sr99622/libonvif
On Debian, use apt install onvif-tools libonvif1 libonvif-dev
but be aware that this is version 1.4.2.
In the current github trunk, onvif-gui was rewritten from C++ to Python.
TODO: install and test the latest github version.
A simple tool to control Onvif camera.
Press the discovery button (near the bottom right) and double click on a discovered camera to enable streaming.
Can be used to change the resolution of stream1
, move the camera (PTZ) and do a lot of other things.
Unfortunately, the output is often corrupted probably because it uses UDP transport.
TODO: Fill a ticket to request TCP (but test the trunk first)
I got some success with the following script
#!/bin/bash
# Customize the RTSP uri as needed
RTSP_URI="rtsp://xxxxxxx:[email protected]/stream1" # large view
#RTSP_URI="rtsp://xxxxxxx:[email protected]/stream2" # small preview
## See https://ffmpeg.org/ffmpeg-formats.html#hls-2 for more HLS muxer options
# Notes:
# - By default, libx264 will insert a keyframe every 250 frames
# which is problematic because segments are split at a keyframe
# so -hls_time 6 will be mostly ignored and the segment duration
# will be around 15s.
# The solution is to force keyframe even DELAY seconds with
# -force_key_frames "expr:gte(t,n_forced*DELAY)"
# where delay is a factor of the -hls_time value.
# See also https://www.reddit.com/r/ffmpeg/comments/nam6hg/mp4_to_hls_how_to_set_time_segments_properly/
# It is also possible to use '-hls_flags split_by_time' but then
# the segments will not start at a keyframe.
CMD=(
ffmpeg
############ RTSP options ############
-rtsp_transport tcp
-i "$RTSP_URI"
############ Audio settings ############
-c:a aac
-b:a 160000
-ac 2
############ Video settings ############
-s 800x600
-c:v libx264
-b:v 200000
############ HLS Output ############
-y
-force_key_frames "expr:gte(t,n_forced*2)"
-hls_time 6
# Only keep 10 segments on disk
-hls_list_size 10
-hls_flags delete_segments
-hls_allow_cache 0
#-start_number 1
###### and finally, the output HLS file
playlist.m3u8
)
echo "#" "${CMD[@]}"
"${CMD[@]}"
FFMPEG will generate start generating some TS files and a file playlist.m3u8
.
It is possible to watch the m3u8 stream locally for example using mpv:
mpv playlist.m3u8
The whole directory can also be accessed remotely using your http server (Apache, ...). If you do not have a http server, then start a simple one with python3 -m http.server
in the directory containing the files and watch the stream with
mpv http://localhost:8000/playlist.m3u8
ONVIF is a typical http based protocol using POST queries.
The protocol used to pass the password is quite complex but a few queries do not require authentication.
For instance, the GetCapabilities can performed as follow
Create a file request.xml such as
<?xml version=1.0' encoding='utf-8'>
<soap-env:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<soap-env:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GetCapabilities xmlns="http://www.onvif.org/ver10/device/wsdl"></GetCapabilities>
</soap-env:Body>
</soap-env:Envelope>
and then
curl -s -S -k -X POST --header 'Content-Type: text/xml; charset=utf-8' -d @request.xml http://192.168.1.26:2020/onvif/service
You may want to pipe the output in xmllint - -format
to make it more readable.
Similarly, the GetServices
query provides a shorter list of the supported services.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:chan="http://schemas.microsoft.com/ws/2005/02/duplex" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:xmime="http://tempuri.org/xmime.xsd" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:wsrfbf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrfr="http://docs.oasis-open.org/wsrf/r-2" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:tdn="http://www.onvif.org/ver10/network/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:trp="http://www.onvif.org/ver10/replay/wsdl" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl" xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema">
<SOAP-ENV:Body>
<tds:GetServicesResponse>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver10/device/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver10/media/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver10/events/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver20/analytics/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver20/imaging/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver20/ptz/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
<tds:Service>
<tds:Namespace>http://www.onvif.org/ver10/deviceIO/wsdl</tds:Namespace>
<tds:XAddr>http://192.168.1.26:2020/onvif/service</tds:XAddr>
<tds:Version>
<tt:Major>2</tt:Major>
<tt:Minor>20</tt:Minor>
</tds:Version>
</tds:Service>
</tds:GetServicesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The supported services are device, media, events, analytics, imaging, ptz and deviceIO. See https://www.onvif.org/specs/DocMap.html for their respective specifications.
device
is the core service.media
is about controlling the video and audio streams. This is where you can change the resolution ofstream1
.events
is about the event notifications (e.g. a movement was detected, camera tempering, ...)analytics
is about the image analysis (e.g. detect persons, track movements, ...)imaging
is about the image and camera settings (e.g. brightness, focus, ...)ptz
is about Pan, Tilt and ZoomdeviceIO
is about the input and output audio, video and relay.
What is obviously missing is the recording service. The Tapo android app must be using an extension to access the sd-card content.
Each service should have a GetServiceCapabilities
or something similar to get more details but that requires authentication.
However, the GetCapabilities
query gives some details about each service without auth. See Below.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery"
xmlns:chan="http://schemas.microsoft.com/ws/2005/02/duplex"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsa5="http://www.w3.org/2005/08/addressing"
xmlns:xmime="http://tempuri.org/xmime.xsd"
xmlns:xop="http://www.w3.org/2004/08/xop/include"
xmlns:wsrfbf="http://docs.oasis-open.org/wsrf/bf-2"
xmlns:wstop="http://docs.oasis-open.org/wsn/t-1"
xmlns:wsrfr="http://docs.oasis-open.org/wsrf/r-2"
xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
xmlns:tt="http://www.onvif.org/ver10/schema"
xmlns:ter="http://www.onvif.org/ver10/error"
xmlns:tns1="http://www.onvif.org/ver10/topics"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl"
xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl"
xmlns:trt="http://www.onvif.org/ver10/media/wsdl"
xmlns:tev="http://www.onvif.org/ver10/events/wsdl"
xmlns:tdn="http://www.onvif.org/ver10/network/wsdl"
xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl"
xmlns:trp="http://www.onvif.org/ver10/replay/wsdl"
xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl"
xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl"
xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl"
xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema">
<SOAP-ENV:Body>
<tds:GetCapabilitiesResponse>
<tds:Capabilities>
<tt:Analytics>
<tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
<tt:RuleSupport>true</tt:RuleSupport>
<tt:AnalyticsModuleSupport>true</tt:AnalyticsModuleSupport>
</tt:Analytics>
<tt:Device>
<tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
<tt:Network>
<tt:IPFilter>false</tt:IPFilter>
<tt:ZeroConfiguration>false</tt:ZeroConfiguration>
<tt:IPVersion6>false</tt:IPVersion6>
<tt:DynDNS>false</tt:DynDNS>
<tt:Extension>
<tt:Dot11Configuration>true</tt:Dot11Configuration>
</tt:Extension>
</tt:Network>
<tt:System>
<tt:DiscoveryResolve>false</tt:DiscoveryResolve>
<tt:DiscoveryBye>true</tt:DiscoveryBye>
<tt:RemoteDiscovery>false</tt:RemoteDiscovery>
<tt:SystemBackup>false</tt:SystemBackup>
<tt:SystemLogging>false</tt:SystemLogging>
<tt:FirmwareUpgrade>false</tt:FirmwareUpgrade>
<tt:SupportedVersions>
<tt:Major>20</tt:Major>
<tt:Minor>6</tt:Minor>
</tt:SupportedVersions>
<tt:Extension>
<tt:HttpFirmwareUpgrade>false</tt:HttpFirmwareUpgrade>
<tt:HttpSystemBackup>false</tt:HttpSystemBackup>
<tt:HttpSystemLogging>false</tt:HttpSystemLogging>
<tt:HttpSupportInformation>false</tt:HttpSupportInformation>
</tt:Extension>
</tt:System>
<tt:IO/>
<tt:Security>
<tt:TLS1.1>false</tt:TLS1.1>
<tt:TLS1.2>false</tt:TLS1.2>
<tt:OnboardKeyGeneration>false</tt:OnboardKeyGeneration>
<tt:AccessPolicyConfig>false</tt:AccessPolicyConfig>
<tt:X.509Token>false</tt:X.509Token>
<tt:SAMLToken>false</tt:SAMLToken>
<tt:KerberosToken>false</tt:KerberosToken>
<tt:RELToken>false</tt:RELToken>
</tt:Security>
</tt:Device>
<tt:Events>
<tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
<tt:WSSubscriptionPolicySupport>true</tt:WSSubscriptionPolicySupport>
<tt:WSPullPointSupport>true</tt:WSPullPointSupport>
<tt:WSPausableSubscriptionManagerInterfaceSupport>false</tt:WSPausableSubscriptionManagerInterfaceSupport>
</tt:Events>
<tt:Imaging>
<tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
</tt:Imaging>
<tt:Media>
<tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
<tt:StreamingCapabilities>
<tt:RTPMulticast>false</tt:RTPMulticast>
<tt:RTP_TCP>true</tt:RTP_TCP>
<tt:RTP_RTSP_TCP>true</tt:RTP_RTSP_TCP>
</tt:StreamingCapabilities>
</tt:Media>
<tt:PTZ>
<tt:XAddr>http://192.168.1.26:2020/onvif/service</tt:XAddr>
</tt:PTZ>
<tt:Extension>
<tt:DeviceIO>
<tt:XAddr/>
<tt:VideoSources>0</tt:VideoSources>
<tt:VideoOutputs>0</tt:VideoOutputs>
<tt:AudioSources>1</tt:AudioSources>
<tt:AudioOutputs>1</tt:AudioOutputs>
<tt:RelayOutputs>0</tt:RelayOutputs>
</tt:DeviceIO>
<hikxsd:hikCapabilities>
<hikxsd:XAddr>http://192.168.1.26:2020/onvif/service</hikxsd:XAddr>
<hikxsd:PTZ3DZoomSupport>true</hikxsd:PTZ3DZoomSupport>
<hikxsd:PTZPatternSupport>false</hikxsd:PTZPatternSupport>
<hikxsd:IOInputSupport>false</hikxsd:IOInputSupport>
<hikxsd:PrivacyMaskSupport>false</hikxsd:PrivacyMaskSupport>
<hikxsd:Language>2</hikxsd:Language>
</hikxsd:hikCapabilities>
</tt:Extension>
</tds:Capabilities>
</tds:GetCapabilitiesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
In Media/StreamingCapability
we have RTPMulticast
(i,e. RTSP over UDP), RTP_TCP
and RTP_RTSP_TCP
so http and websocket are obviously not supported. See also section 5.1.1.3 of https://www.onvif.org/specs/stream/ONVIF-Streaming-Spec.pdf
Device/Network/IPVersion6
is false so no IPv6
There are a few extensions but I do not see anything that could be related to recording or to SD card storage.
Hi, so are you able to get this camera's feed and record it on a Linux or NAS device? Thanks
Found this info re tapo cameras: https://www.tapo.com/uk/faq/34/