You have an RTSP URL.
You paste it into VLC.
Video appears immediately.
You add what appears to be exactly the same source to Milestone XProtect.
Nothing.
Black screen. Connection error. Perhaps it connects for a minute and then disappears.
So, if VLC can play it, why can't XProtect?
The useful answer is that VLC working proves the source can deliver playable media to VLC.
It doesn't prove that another RTSP client will negotiate that stream in exactly the same way.
That gives us a much better troubleshooting question:
Where is the first point that the successful VLC conversation and the unsuccessful XProtect conversation become different?
Once you start looking at the problem that way, RTSP troubleshooting becomes considerably less mysterious.
And considerably less dependent on changing random checkboxes until something happens.
This is the first thing I would check, and it is surprisingly easy to miss.
If you tested the RTSP stream from your laptop, you haven't necessarily tested the same network path that XProtect is using.
The XProtect Recording Server is the component retrieving the video.
So wherever practical:
Take the exact RTSP URL and test it from the XProtect Recording Server.
Not something similar.
Not a URL with the query string removed because it looks neater.
The exact URL.
For example:
rtsp://192.168.10.20:554/channel1/stream1?profile=main
If VLC is available on the Recording Server, use it.
If it isn't, use another machine in the same network position or use ffprobe, which we'll come to shortly.
Because your laptop and the Recording Server may have completely different:
A stream working from your engineering laptop only proves that the stream works from your engineering laptop.
That distinction has consumed more troubleshooting time over the years than I care to think about.
If the stream doesn't work from the Recording Server network position, stop there.
You have already learnt something useful.
This is probably not the time to investigate H.264 packetisation or an obscure Milestone setting.
Start with connectivity.
If it does work from the Recording Server, leave it running for a while.
One frame isn't enough.
We want:
Stable video.
Not:
"I saw a picture once, therefore this is definitely fine."
If the source supports ONVIF, my next stop is normally ONVIF Device Manager, usually shortened to ODM.
A quick clarification here because this sometimes gets muddled:
ONVIF and RTSP aren't the same thing.
And for troubleshooting purposes, that is useful.
I tend to think of the tools like this:
VLC tells me whether I can consume the media.
ONVIF tells me how the device describes its media.
XProtect tells me whether that source can be consumed reliably as part of the VMS.
Open the device in ODM and look at the media configuration.
You are interested in:
That last one is particularly useful.
You may have been given:
rtsp://192.168.10.20/live
while the device itself reports something more like:
rtsp://192.168.10.20:554/channel1/stream1?profile=main
If that happens, test the device-advertised URI.
You have just replaced a guessed configuration with information coming from the device itself.
That is normally progress.
That doesn't automatically mean RTSP is broken.
ONVIF discovery and direct RTSP playback are separate things.
You might have:
Treat ODM as another diagnostic view, not as a certification oracle.
If RTSP works directly but ODM doesn't, record that fact and continue.
This is where I would introduce FFmpeg / ffprobe.
VLC is excellent at answering:
Can I play this stream?
But VLC is deliberately good at making things work.
That is useful when watching video.
It is slightly less useful when you're trying to understand how the video was made to work.
ffprobe gives us a simple way of testing particular RTSP transport methods deliberately.
First, test RTSP over TCP:
ffprobe -hide_banner -rtsp_transport tcp "rtsp://192.168.10.20:554/channel1/stream1?profile=main"
Then test the exact same source using UDP:
ffprobe -hide_banner -rtsp_transport udp "rtsp://192.168.10.20:554/channel1/stream1?profile=main"
FFmpeg documents these RTSP transport options in its protocol documentation.
You aren't looking for a pretty video window here.
You are looking for whether ffprobe can establish the source and identify the media.
You might see output containing something broadly like:
Stream #0:0: Video: h264, 1920x1080, 25 fps
Now the result starts telling us where to look next.
Excellent.
We have evidence that both transport methods can work from this network position.
Move on.
Also useful.
You probably don't have some mysterious generic "Milestone codec problem".
You have narrowed the problem towards things such as:
And when we configure XProtect, we already know which transport worked.
Less common in many installations, but equally informative.
Again, the problem isn't:
"RTSP doesn't work."
The problem is now:
"One particular RTSP transport method doesn't work."
Much better.
Go back to fundamentals.
Check:
Don't keep adding complexity until you have a genuinely known-good source.
Before we start changing Universal Driver settings, check whether you actually need the Universal Driver.
My order would normally be:
If the manufacturer's native driver works correctly:
Use it.
If ONVIF gives you the integration you require:
Use it.
If the Universal Driver works reliably:
Use it.
There isn't an engineering prize for making the architecture more complicated than it needs to be.
This point becomes quite important later when I start talking about ORBNET products.
If the built-in solution works, I'm not going to suggest inserting another piece of software purely because we happen to make one.
The specialist tools become relevant when the source or the workflow genuinely needs something different.
The Universal Driver is extremely useful for generic RTSP sources.
But there are a handful of settings I would pay particular attention to.
Let's keep using the same source throughout:
rtsp://192.168.10.20:554/channel1/stream1?profile=main
This is one of the easiest places to go wrong.
Your complete RTSP URL is:
rtsp://192.168.10.20:554/channel1/stream1?profile=main
But the Universal Driver Connection URI is the path portion:
channel1/stream1?profile=main
Not the whole:
rtsp://192.168.10.20:554/channel1/stream1?profile=main
The host and RTSP port are configured independently.
It is obvious after somebody tells you.
It is considerably less obvious when you're staring at a black screen at 16:45 on a commissioning day.
RTSP commonly uses:
554
But don't assume that it does.
If your known-good URL is:
rtsp://192.168.10.20:8554/channel1/stream1
then the RTSP port is:
8554
Use the source's actual configuration.
This is where the earlier tests start paying for themselves.
ODM or ffprobe should already have told you what the source is advertising.
If it is H.264, configure H.264.
If it is H.265, configure H.265.
Again:
Facts, not guesses.
The same principle applies here.
If your earlier test established:
TCP works. UDP fails.
then I would test the corresponding TCP streaming mode first.
You can come back to why UDP isn't working later if the application requires it.
First establish whether XProtect can successfully consume the known-good path.
This becomes particularly interesting when a stream:
If it dies after approximately 30, 60 or 120 seconds every time, I start thinking about session management rather than initial connectivity.
Depending on the source, different keep-alive behaviours such as OPTIONS, GET_PARAMETER or RTCP may matter.
Again, the symptom has given us somewhere sensible to look.
This setting deserves a flashing arrow.
Remember our example?
rtsp://192.168.10.20:554/channel1/stream1?profile=main
Everything after the ? may be meaningful to the source.
It might identify:
Milestone's current Universal Driver documentation includes an Include URI options on PLAY setting.
If those query parameters are removed when the PLAY request is sent, the source can behave differently from the working VLC request.
You can therefore end up with the wonderfully confusing situation where much of the RTSP session looks fine, but the actual playback request isn't quite the same request VLC made.
If your URI contains:
?something=value
check this setting.
It is exactly the kind of tiny behavioural difference that makes:
"It works in VLC."
considerably less conclusive than it first appears.
One other trap.
Successfully adding Universal Driver hardware does not mean you have proven stable video.
After adding it:
The green tick isn't the end of the investigation.
The video is.
Authentication deserves its own section, because it produces some of the most convincing false leads in RTSP troubleshooting.
A stream that authenticates happily in VLC can still fail in XProtect.
Start with the obvious things:
Credentials embedded in a URL are worth a particular look.
If you tested with something like:
rtsp://admin:P%40ssw0rd@192.168.10.20:554/channel1/stream1?profile=main
then VLC handled the URL-encoded characters for you.
In XProtect, the credentials belong in the user name and password fields, not in the URI.
Characters such as @, :, / and ? in a password are a common source of an authentication failure that looks like a stream failure.
In a capture, the symptom is usually unmistakable:
DESCRIBE → 401 Unauthorized DESCRIBE + Authorization → 401 Unauthorized
A single 401 is normal. That is simply the device issuing a challenge.
A second 401 after the client has answered the challenge is the interesting one.
Fix authentication before you investigate anything else. You do not have an RTP problem yet.
This is the part that gets skipped, and it belongs firmly in the authentication conversation.
Check the clock on both ends:
And check three things, not one:
Why it matters here:
So while you are there:
Point the source and the Recording Server at the same NTP source, set the time zone deliberately, and confirm the date.
It takes a minute.
It removes an entire category of authentication failure that otherwise looks like a broken stream.
Before opening Wireshark, take a moment to describe the failure accurately.
Different symptoms point towards very different areas.
Start with:
Don't start debugging RTP.
You don't have an RTP problem yet.
The RTSP conversation hasn't got that far.
Start thinking:
Think:
Now check whether media actually arrives.
A successful RTSP PLAY response doesn't magically escort your RTP packets through the firewall afterwards.
These are different stages of the conversation.
And that brings us to the tool people often avoid until things get really unpleasant.
Open Wireshark.
And before anybody disappears at the mention of packet captures, you do not need to understand every packet in the trace.
We're looking for a fairly simple sequence:
DESCRIBE → SETUP → PLAY → RTP
That is enough to make a surprising amount of progress.
Milestone's own Universal Driver testing guidance points you towards checking the DESCRIBE, SETUP and PLAY requests.
My approach would be:
ffprobe working.That is the whole game.
This is broadly the client asking:
"Tell me what media you have available."
The response usually contains SDP, or Session Description Protocol.
You don't need to decode every line.
Initially, look for things such as:
For example:
m=video 0 RTP/AVP 96 a=rtpmap:96 H264/90000 a=control:trackID=1
For our purposes:
H264
tells us what codec the source advertised.
And:
trackID=1
identifies a media control target that may appear again during SETUP.
That's enough for now.
The client is now effectively saying:
"This is how I would like you to deliver that media."
This is where TCP versus UDP differences can suddenly become very obvious.
Compare VLC and XProtect.
Did they request the same transport?
Did one ask for UDP client ports while the other requested TCP interleaving?
Did the device accept one and reject the other?
If so, you have found something considerably more useful than:
"XProtect doesn't seem to like it."
Now the client is asking the source to start delivering media.
Check:
PLAY succeed?This is particularly relevant to the Include URI options on PLAY setting we looked at earlier.
And then the important bit.
Did the media actually arrive?
If:
DESCRIBE → 200 OK SETUP → 200 OK PLAY → 200 OK
but there is no media afterwards, then your RTSP control conversation may have succeeded.
The fault is now in a different category.
That is useful.
Before the filters themselves, one distinction that saves a lot of pain.
They are not the same thing, and they don't use the same syntax.
A capture filter decides what Wireshark writes to disk.
A display filter decides what you are shown from what was already captured.
Two practical consequences:
Capture filters use BPF syntax, the same style used by tcpdump:
host 192.168.10.20
Display filters use Wireshark's own syntax:
ip.addr == 192.168.10.20
Putting rtsp into the capture filter box will simply be rejected. It isn't valid BPF.
My habit for this kind of work:
That last point matters. If you capture only port 554, you capture the RTSP conversation and none of the media.
Everything to and from the source, control traffic and media together. This is the one I use most:
host 192.168.10.20
The same source on a non-standard RTSP port, keeping UDP media as well:
host 192.168.10.20 and (tcp port 8554 or udp)
RTSP control traffic only, when you are chasing a negotiation problem:
tcp port 554
Two specific hosts, which is useful for source to Recording Server:
host 192.168.10.20 and host 192.168.10.50
Exclude your own remote-desktop session so the capture isn't drowned by it:
host 192.168.10.20 and not tcp port 3389
A UDP media port range, where the source uses a known range:
host 192.168.10.20 and udp portrange 30000-40000
If you are capturing on the Recording Server itself and it has more than one interface, choose the interface facing the source before worrying about filters at all.
Start simple:
rtsp
Then:
rtsp || rtp || rtcp
If you only want traffic involving your source:
ip.addr == 192.168.10.20 && (rtsp || rtp || rtcp)
To concentrate on the main RTSP requests:
rtsp.method == "DESCRIBE" || rtsp.method == "SETUP" || rtsp.method == "PLAY"
And to look for RTSP errors:
rtsp.status >= 400
One small warning with RTP over UDP:
Wireshark may initially show the media simply as UDP because it hasn't identified the traffic as RTP.
If that happens, use Analyze → Decode As where appropriate and inspect the RTP stream.
Again, we are not trying to turn a security integrator into a protocol developer.
We're asking one much simpler question:
Does the stream XProtect is being offered look like the stream VLC was offered?
And if not:
Where did they become different?
This is where third-party video integration gets more interesting.
Historically, most XProtect video sources looked roughly like:
IP camera → XProtect
Today the "camera" might actually be:
Some of those systems produce excellent conventional RTSP.
Some produce RTSP that is slightly... creative.
And some don't use RTSP at all.
At some point the troubleshooting question needs to change from:
"How can I force this through the Universal Driver?"
to:
"What is actually the sensible way of getting this video into XProtect?"
That is where ORB Driver becomes relevant.
ORB Driver provides a more flexible XProtect-facing integration route for external video sources.
The important part isn't just the protocol list.
The important concept is:
ORB Driver's job is to make an unusual video source behave like something XProtect can sensibly manage.
Current supported workflows cover a broad range of external stream types, including:
It can also provide transcoding where compatibility requires it.
That changes the integration discussion.
Instead of spending another hour trying to convince a drone, mobile platform or specialist video system that it is secretly an IP camera, you have a layer designed specifically to present those kinds of sources into XProtect.
But there is another category of problem that is worth separating from this one.
Imagine the source is remote.
Perhaps it sits on:
Perhaps the source gives you SRT, but you need RTSP locally.
Perhaps several consumers need the same video.
Perhaps the source only allows a small number of connections.
Perhaps you need to:
At that point:
This has stopped being an RTSP driver problem.
It is now a video transport problem.
That is where ORBNET Streaming Engine fits.
I tend to describe Streaming Engine as:
Ingest → Convert → Route → Redistribute
It isn't simply another XProtect device driver.
It sits in the video path.
That means it can be useful where the real challenge is getting video:
from where and how it exists
to:
where and how it needs to exist.
Typical examples include:
And that distinction is important.
ORB Driver is primarily about presenting an unusual or supported external source into XProtect.
Streaming Engine is primarily about moving, converting, routing and distributing video.
They can be used independently.
Or they can be used together.
Once ORB Driver and Streaming Engine make sense individually, the wider StreamForce ecosystem becomes much easier to understand.
A complete workflow might look something like:
Source ↓ StreamLink, if required ↓ Streaming Engine, if required ↓ ORB Driver, if required ↓ XProtect
StreamLink is the edge contribution part of that architecture.
For example, it can sit at a remote or temporary location, acquire compatible local video and contribute it back using SRT.
That is useful for things such as:
But the most important words in that architecture remain:
If required.
You don't need every component in every installation.
If XProtect's native driver works:
Use it.
If ONVIF works:
Use it.
If Universal Driver works:
Use it.
If an external source needs a more flexible XProtect-facing integration layer:
ORB Driver.
If the bigger problem is transport, conversion or distribution:
Streaming Engine.
If video also needs collecting at the edge and contributing back across a less predictable network:
StreamLink may become part of the architecture.
Use the layers the workflow actually needs.
No more.
There comes a point where changing another random RTSP checkbox isn't troubleshooting.
It's archaeology.
If I arrived on site tomorrow and somebody said:
"The RTSP stream works in VLC but not XProtect."
this is the order I would work through it.
Include:
Don't simplify it.
Use VLC or ffprobe.
If it fails here but succeeds from your laptop, investigate the network before XProtect.
Prove stability.
One frame doesn't count.
Use ODM to inspect:
Compare the URI reported by the source with the one you have been given.
ffprobe -hide_banner -rtsp_transport tcp "rtsp://192.168.10.20:554/channel1/stream1?profile=main"
ffprobe -hide_banner -rtsp_transport udp "rtsp://192.168.10.20:554/channel1/stream1?profile=main"
Record whether one works and the other doesn't.
My order:
If it works reliably, stop.
For:
rtsp://192.168.10.20:554/channel1/stream1?profile=main
the Connection URI would be:
channel1/stream1?profile=main
Don't assume 554.
Use the known-good source configuration.
Use the codec established by ODM, VLC or ffprobe.
If TCP worked and UDP didn't, that matters.
Particularly if your stream URI contains:
?
Especially if the stream disconnects after a predictable interval.
Capture VLC or ffprobe working.
Then capture XProtect failing.
DESCRIBE → SETUP → PLAY → RTP
Find the first meaningful difference.
If you do, fix it.
If the source genuinely needs a more flexible route into XProtect, look at ORB Driver.
If the actual challenge is moving, converting, routing or redistributing the video, look at Streaming Engine.
If the workflow also involves remote or edge contribution, look at the wider StreamForce architecture.
Don't add complexity until the evidence tells you why you need it.
| Symptom | Likely area | Next test |
|---|---|---|
| Works on laptop, fails from Recording Server | Network path | Test routing, VLAN, firewall and DNS from the Recording Server |
| VLC works, ODM reports a different URI | Incorrect or stale RTSP path | Test the URI advertised by the source |
| TCP works, UDP fails | RTP / network transport | Check UDP firewalling, NAT and return path |
| DESCRIBE repeatedly returns 401 | Authentication | Compare credentials and authentication exchange, and check clock, date and time zone on both ends |
| DESCRIBE fails entirely | URI / auth / RTSP negotiation | Fix the control conversation before investigating RTP |
| SETUP fails | Transport negotiation | Compare VLC and XProtect SETUP requests |
| PLAY succeeds but no RTP appears | Media delivery | Check RTP traffic, firewall and negotiated transport |
| Stream drops after a repeatable interval | Session / keep-alive | Check timeout and keep-alive behaviour |
URI contains ? parameters |
PLAY URI handling | Check Include URI options on PLAY |
| Universal Driver adds successfully but video fails | Stream not actually validated | Test stable live video and capture the exchange |
| Source fundamentally doesn't behave like a camera | Integration model | Consider ORB Driver |
| Source needs conversion, WAN transport or fan-out | Video transport | Consider Streaming Engine |
A stream playing in VLC isn't proof that XProtect is wrong.
And XProtect failing doesn't automatically mean the video source is broken.
RTSP is a conversation.
Different clients can request different transports, use slightly different URIs, handle authentication differently or maintain the session in different ways.
So rather than asking:
"Why doesn't XProtect like this RTSP stream?"
I would ask:
"Where does XProtect's conversation first become different from the one that works?"
That is normally where the useful answer is hiding.
And if you eventually prove that the source simply doesn't behave like a conventional IP camera, or that the real challenge is moving the video across an unusual transport path, that is exactly the territory we spend rather a lot of time working in at ORBNET.
If you've got one of those streams that works everywhere except where you actually need it, feel free to send me the source details or the failing RTSP exchange.
I'm also quite interested in hearing the strangest RTSP behaviour you've encountered in the wild.
There are some wonderfully inventive implementations out there.