scottlamb / retina

High-level RTSP multimedia streaming library, in Rust
https://crates.io/crates/retina
Apache License 2.0
237 stars 47 forks source link

work around invalid sprop-parameter-sets from VStarcam cameras #42

Closed lattice0 closed 2 years ago

lattice0 commented 2 years ago

I was trying to use the example but it failed with https://github.com/scottlamb/retina/issues/41. I'll try to debug this when I have more time. I was just testing retina new updates with Vstarcam since I promised I'd test if everything works. On my code, I'm getting:

thread 'retina_client_cam1' panicked at 'called `Result::unwrap()` on an `Err` value: RtspResponseError { conn_ctx: ConnectionContext { local_addr: 172.17.0.2:48346, peer_addr: 192.168.1.22:10554, established_wall: WallTime(Timespec { sec: 1638133120, nsec: 895297209 }), established: Instant { tv_sec: 3367, tv_nsec: 506005897 } }, msg_ctx: RtspMessageContext { pos: 119, received_wall: WallTime(Timespec { sec: 1638133120, nsec: 963622369 }), received: Instant { tv_sec: 3367, tv_nsec: 574330667 } }, method: Describe, cseq: 2, status: Ok, description: "bad NAL header e9" }', /home/dev/project/src/rtsp/retina_client.rs:150:44

I'm sending you the wireshark capture via email.

scottlamb commented 2 years ago

Okay, I understand what's happening now. Retina is correct in saying that the camera's DESCRIBE response is invalid. I'm not sure what the best workaround is though.

From the packet capture, here's the DESCRIBE response:

RTSP/1.0 200 OK
Cseq: 2
Date: Sun, Nov 28 2021 20:58:40 GMT
Content-Type: application/sdp
Content-Length: 394

v=0
o=VSTC 3847121920 3847121920 IN IP4 192.168.1.22
s=streamed by the VSTARCAM RTSP server
e=NONE
c=IN IP4 0.0.0.0
t=0 0
m=video 0 RTP/AVP 96
b=AS:1536
a=control:track0
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=00f004;sprop-parameter-sets=6QDwBE/LCAAAH0gAB1TgIAAAAAA=,AAAAAA==
m=audio 0 RTP/AVP 8  
b=AS:64
a=control:track1
a=rtpmap:8 PCMA/8000/1

RFC 6184 section 8.1 says the sprop-parameter-sets is supposed to contain "a comma-separated (',') list of base64 [...] representations of parameter set NAL units as specified in Sections 7.3.2.1 and 7.3.2.2 of [the H.264 specification]." In this case, sprop-parameter-sets contains two items:

They're both wrong. The first one starts with the e9 byte in the error. H.264 section 7.3.1 says the high bit is forbidden_zero_bit. It's set to 1, so this is invalid. The second one is just NUL bytes. We need the SPS and PPS, and I don't know how we can get them from this garbage.

Maybe we could ignore the sprop-parameter-sets if they don't parse and expect to receive in-band parameter sets that make more sense. I'd be interested to see a packet capture from a RTSP session that proceeds past this error. You should be able to get this from Retina's packet-level interface (not calling Session::demuxed) or any other RTSP software that successfully talks to this camera. From that packet capture, I can pull out the in-band parameter sets to see if they're valid and so if this is likely to work.

fwiw, your previous VStarcam packet captures didn't show this same problem. The checked-in vstarcam_describe.txt has a more plausible sprop-parameter-sets=Z00AKp2oHgCJ+WbgICAoAAADAAgAAAMAfCA=,aO48gA==: a NAL unit starting with 0x67 (an SPS) and a NAL unit starting with 0x68 (a PPS). Was that running a different firmware version or something?

lattice0 commented 2 years ago

Hmmmm I see. So, yes, the Vstarcam cameras I was testing before are the same model but I lost the VPN connection to that house and I'm too far to fix it, so I bought a new one which possibly has a new firmware. These are really well sold and if I remember correctly they use live555 as server, I'm not sure.

Gonna try to test with ZMediaKit then, gotta find some time to compile because I completely abandoned the C++ interface that I had for it on Rust on my code.

scottlamb commented 2 years ago

I got your new packet capture. I see the RTP packets start with parameters:

so I think ignoring the bogus out-of-band parameters (sprop-parameter-sets) in favor of in-band parameters (these ones at the beginning of the RTP packet stream) should work. That's probably what ZLMediaKit is doing.

scottlamb commented 2 years ago

This commit should do it; let me know though if it works or not...