AlexxIT / go2rtc

Ultimate camera streaming application with support RTSP, RTMP, HTTP-FLV, WebRTC, MSE, HLS, MP4, MJPEG, HomeKit, FFmpeg, etc.
https://github.com/AlexxIT/Blog
MIT License
4.89k stars 395 forks source link

Add support ONVIF source #380

Closed djmadfx closed 1 year ago

djmadfx commented 1 year ago

I am using Echo as my source. It triggers a Python script, which provides an RTSP URI that changes. Is there a way to retrigger the Python script when the source disconnects?

Full setup: Security cameras that have RTSP URIs that change. The Python script polls ONVIF for the updated URI. The go2rtc urls are used within BlueIris. My current solution is utilizing watchdog within BlueIris, which restarts the go2rtc container via a curl command for docker when a disconnect is detected. This seems to be the only way to retrigger the Python script, but it also kills all of my streams.

AlexxIT commented 1 year ago

Maybe I can support ONVIF. Show how you do it

djmadfx commented 1 year ago

My specific script handles my situation in the sense that I only need to push a single request to the camera requesting the RTSP URI for profile "MainProfileToken". The post below explains this better than I could ever: https://superuser.com/questions/1253126/how-do-i-find-the-video-stream-url-of-onvif-cameras-manually -- I'd imagine that you may need to add something to the GUI which would poll ONVIF so people could put a camera's IP, credentials, and ONVIF port along with which profile they want to pull the RTSP stream for.

AlexxIT commented 1 year ago

Can you show your script?

djmadfx commented 1 year ago

Here's the script I use. You just have to feed the camera's IP and ONVIF port. The ProfileToken will differ depending upon the camera being used. Thank you for your amazing work!

import requests
import xml.etree.ElementTree as ET
import sys

# Define the target IP address and port

ip_address = sys.argv[1]
port = sys.argv[2]

def get_rtsp_stream():

    # Define the SOAP request payload
    payload = """<?xml version="1.0" encoding="UTF-8"?>
    <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
        xmlns:a="http://www.w3.org/2005/08/addressing"
        xmlns:wsa5="http://www.w3.org/2005/08/addressing"
        xmlns:wsdl="http://www.onvif.org/ver10/media/wsdl"
        xmlns:tns1="http://www.onvif.org/ver10/topics"
        xmlns:tt="http://www.onvif.org/ver10/schema"
        xmlns:trt="http://www.onvif.org/ver10/media/wsdl">
        <s:Header>
            <a:Action>http://www.onvif.org/ver10/media/wsdl/GetStreamUri</a:Action>
            <a:To>http://{0}:{1}/onvif/media</a:To>
        </s:Header>
        <s:Body>
            <trt:GetStreamUri>
                <trt:StreamSetup>
                    <tt:Stream>RTP-Unicast</tt:Stream>
                    <tt:Transport>
                        <tt:Protocol>RTSP</tt:Protocol>
                    </tt:Transport>
                </trt:StreamSetup>
                <trt:ProfileToken>MainProfileToken</trt:ProfileToken>
            </trt:GetStreamUri>
        </s:Body>
    </s:Envelope>""".format(ip_address, port)

    # Define the request headers
    headers = {
        "Content-Type": "application/soap+xml; charset=utf-8; action=\"http://www.onvif.org/ver10/media/wsdl/GetStreamUri\"",
        "Content-Length": str(len(payload)),
        "Accept-Encoding": "gzip, deflate",
        "Connection": "close"
    }

    # Send the POST request and retrieve the response
    url = "http://{}:{}/onvif/media".format(ip_address, port)
    response = requests.post(url, data=payload, headers=headers)

    # Parse the response content as XML
    root = ET.fromstring(response.content)

    #(response.text)

    # Extract the URI value
    uri_element = root.find(".//{http://www.onvif.org/ver10/schema}Uri")
    uri_value = uri_element.text

    # Print the URI value
    print(uri_value)
    return uri_value

def main():

    stream_uri = get_rtsp_stream()

    return stream_uri

if __name__ == "__main__":
    main()
AlexxIT commented 1 year ago

You can try latest master version

streams:
  camera1: onvif://user:pass@host:port
djmadfx commented 1 year ago

I just tested it out. Wow, it works great! I even rebooted the camera and it recovered nicely after the camera rebooted. Thank you so much! This will help A LOT of people out.

felipecrs commented 1 year ago

@AlexxIT I believe you can close this issue now.