Skip to content

Instantly share code, notes, and snippets.

@crayfishapps
Forked from mike-zhang/rtspTcpClient_DSS.py
Last active October 3, 2023 17:29
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save crayfishapps/a13e2026ba872ec192695a95b851f4a0 to your computer and use it in GitHub Desktop.
Save crayfishapps/a13e2026ba872ec192695a95b851f4a0 to your computer and use it in GitHub Desktop.
RTSP client with basic and digest authentication
#! /usr/bin/python
import socket,time,string,base64,hashlib,xml.etree.ElementTree as ET
m_Vars = {
"bufLen" : 1024,
"defaultServerIp" : "172.172.172.172",
"defaultServerPort" : 554,
"defaultTestUri" : "/video.mp4",
"defaultUserAgent" : "RTSP Client",
"defaultUsername" : "admin",
"defaultPassword" : "password"
}
def genmsg_DESCRIBE(url,seq,userAgent,authSeq):
msgRet = "DESCRIBE " + url + " RTSP/1.0\r\n"
msgRet += "CSeq: " + str(seq) + "\r\n"
msgRet += "Authorization: " + authSeq + "\r\n"
msgRet += "User-Agent: " + userAgent + "\r\n"
msgRet += "Accept: application/sdp\r\n"
msgRet += "\r\n"
return msgRet
def genmsg_SETUP(url,seq,userAgent,authSeq):
msgRet = "SETUP " + url + " RTSP/1.0\r\n"
msgRet += "CSeq: " + str(seq) + "\r\n"
msgRet += "Authorization: " + authSeq + "\r\n"
msgRet += "User-Agent: " + userAgent + "\r\n"
msgRet += "Blocksize: 65535\r\n"
msgRet += "Transport: RTP/AVP/TCP;unicast\r\n"
msgRet += "\r\n"
return msgRet
def genmsg_OPTIONS(url,seq,userAgent,sessionId,authSeq):
msgRet = "OPTIONS " + url + " RTSP/1.0\r\n"
msgRet += "CSeq: " + str(seq) + "\r\n"
msgRet += "User-Agent: " + userAgent + "\r\n"
msgRet += "Session: " + sessionId + "\r\n"
msgRet += "\r\n"
return msgRet
def genmsg_PLAY(url,seq,userAgent,sessionId,authSeq):
msgRet = "PLAY " + url + " RTSP/1.0\r\n"
msgRet += "CSeq: " + str(seq) + "\r\n"
msgRet += "User-Agent: " + userAgent + "\r\n"
msgRet += "Session: " + sessionId + "\r\n"
msgRet += "Range: npt=0.000-\r\n"
msgRet += "\r\n"
return msgRet
def genmsg_TEARDOWN(url,seq,userAgent,sessionId,authSeq):
msgRet = "TEARDOWN " + url + " RTSP/1.0\r\n"
msgRet += "CSeq: " + str(seq) + "\r\n"
msgRet += "User-Agent: " + userAgent + "\r\n"
msgRet += "Session: " + sessionId + "\r\n"
msgRet += "\r\n"
return msgRet
def decodeControl(strContent):
mapRetInf = {}
messageStrings = strContent.split("\n")
for element in messageStrings:
a = element.find("rtsp")
if a >= 0:
mapRetInf = element[a:]
return mapRetInf
def decodeSession(strContent):
mapRetInf = {}
messageStrings = strContent.split("\n")
for element in messageStrings:
if "Session" in element:
a = element.find(":")
b = element.find(";")
mapRetInf = element[a+2:b]
return mapRetInf
def generateAuthString(username,password,realm,method,uri,nonce):
mapRetInf = {}
m1 = hashlib.md5(username + ":" + realm + ":" + password).hexdigest()
m2 = hashlib.md5(method + ":" + uri).hexdigest()
response = hashlib.md5(m1 + ":" + nonce + ":" + m2).hexdigest()
mapRetInf = "Digest "
mapRetInf += "username=\"" + m_Vars["defaultUsername"] + "\", "
mapRetInf += "realm=\"" + realm + "\", "
mapRetInf += "algorithm=\"MD5\", "
mapRetInf += "nonce=\"" + nonce + "\", "
mapRetInf += "uri=\"" + uri + "\", "
mapRetInf += "response=\"" + response + "\""
return mapRetInf
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((m_Vars["defaultServerIp"],m_Vars["defaultServerPort"]))
seq = 1
url = "rtsp://" + m_Vars["defaultServerIp"] + m_Vars["defaultTestUri"]
isDigest = False
authSeq = base64.b64encode((m_Vars["defaultUsername"] + ":" + m_Vars["defaultPassword"]).encode("ascii"))
authSeq = "Basic " + authSeq
print genmsg_DESCRIBE(url,seq,m_Vars["defaultUserAgent"],authSeq)
s.send(genmsg_DESCRIBE(url,seq,m_Vars["defaultUserAgent"],authSeq))
msg1 = s.recv(m_Vars["bufLen"])
print msg1
seq = seq + 1
if msg1.find("Unauthorized") > 1:
isDigest = True
# New DESCRIBE with digest authentication
start = msg1.find("realm")
begin = msg1.find("\"", start)
end = msg1.find("\"", begin + 1)
realm = msg1[begin+1:end]
start = msg1.find("nonce")
begin = msg1.find("\"", start)
end = msg1.find("\"", begin + 1)
nonce = msg1[begin+1:end]
authSeq = generateAuthString(m_Vars["defaultUsername"],m_Vars["defaultPassword"],realm,"DESCRIBE",m_Vars["defaultTestUri"],nonce)
print genmsg_DESCRIBE(url,seq,m_Vars["defaultUserAgent"],authSeq)
s.send(genmsg_DESCRIBE(url,seq,m_Vars["defaultUserAgent"],authSeq))
msg1 = s.recv(m_Vars["bufLen"])
print msg1
seq = seq + 1
control = decodeControl(msg1)
if isDigest == True:
authSeq = generateAuthString(m_Vars["defaultUsername"],m_Vars["defaultPassword"],realm,"SETUP",m_Vars["defaultTestUri"],nonce)
print genmsg_SETUP(control,seq,m_Vars["defaultUserAgent"],authSeq)
s.send(genmsg_SETUP(control,seq,m_Vars["defaultUserAgent"],authSeq))
msg1 = s.recv(m_Vars["bufLen"])
print msg1
seq = seq + 1
sessionId = decodeSession(msg1)
print genmsg_OPTIONS(url,seq,m_Vars["defaultUserAgent"],sessionId,authSeq)
s.send(genmsg_OPTIONS(url,seq,m_Vars["defaultUserAgent"],sessionId,authSeq))
msg1 = s.recv(m_Vars["bufLen"])
print msg1
seq = seq + 1
print genmsg_PLAY(url + "/",seq,m_Vars["defaultUserAgent"],sessionId,authSeq)
s.send(genmsg_PLAY(url + "/",seq,m_Vars["defaultUserAgent"],sessionId,authSeq))
msg1 = s.recv(m_Vars["bufLen"])
print msg1
seq = seq + 1
starttime = time.time()
while True :
# Send a new RTSP OPTION command to keep the stream alive
now = time.time()
if (now - starttime) > 50:
print genmsg_OPTIONS(url,seq,m_Vars["defaultUserAgent"],sessionId,authSeq)
s.send(genmsg_OPTIONS(url,seq,m_Vars["defaultUserAgent"],sessionId,authSeq))
msg1 = s.recv(m_Vars["bufLen"])
print msg1
starttime = time.time()
msgRcv = s.recv(m_Vars["bufLen"])
seq = seq + 1
print genmsg_TEARDOWN(url,seq,m_Vars["defaultUserAgent"],sessionId,authSeq)
s.send(genmsg_TEARDOWN(url,seq,m_Vars["defaultUserAgent"],sessionId,authSeq))
msg1 = s.recv(m_Vars["bufLen"])
print msg1
s.close()
@ismetbalat
Copy link

ismetbalat commented Apr 18, 2020

control = decodeControl(msg1) return rtsp://203.xxx.18.25/0 and SETUP command respond 406 error code. But rtsp://203.xxx.18.25/0/trackID=0 works fine. My DESCRIBE respond below. Is it general problem or have I specifically add a parameter end of rtsp address (a=control:trackID=0)?

RTSP/1.0 200 OK
Cseq: 2
Server: Rtsp Server 1920*1080*10*4096
Content-Type: application/sdp
Content-length: 381
Content-Base: rtsp://203.xxx.18.25/0

v=0
o=StreamingServer 3331435948 1116907222000 IN IP4 203.xxx.18.25
s=h264.mp4
c=IN IP4 0.0.0.0
t=0 0
a=control:*
m=video 0 RTP/AVP 96
a=control:trackID=0
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z00AKp2oHgCJ+WbgICAgQA==,aO48gA==
a=videoinfo:1920*1080*10*4096
m=audio 0 RTP/AVP 0
a=control:trackID=1
a=rtpmap:0 PCMU/8000
a=ptime:20

@crayfishapps
Copy link
Author

In the DESCRIBE response, you will get the information about the available media streams and how to access them. In your case, trackID=0 for video and trackID=1 for the audio stream. There is a good explanation available here:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment