skip Geovision's strange pt=50 packets

Once #33 is fixed, this should allow Geovision cameras to more or
less work.
This commit is contained in:
Scott Lamb 2021-09-07 15:35:42 -07:00
parent ffaa831c54
commit 799584c8e3
2 changed files with 84 additions and 10 deletions

View File

@ -1,6 +1,7 @@
## unreleased ## unreleased
* warn when connecting via TCP to a known-broken live555 server version. * warn when connecting via TCP to a known-broken live555 server version.
* improve compatibility with Geovision cameras (work in progress).
## `v0.3.0` (2021-08-31) ## `v0.3.0` (2021-08-31)

View File

@ -4,15 +4,17 @@
//! RTP and RTCP handling; see [RFC 3550](https://datatracker.ietf.org/doc/html/rfc3550). //! RTP and RTCP handling; see [RFC 3550](https://datatracker.ietf.org/doc/html/rfc3550).
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
use log::trace; use log::{debug, trace};
use pretty_hex::PrettyHex; use pretty_hex::PrettyHex;
use crate::client::PacketItem; use crate::client::PacketItem;
use crate::{Error, ErrorInt}; use crate::{ConnectionContext, Error, ErrorInt, PacketContext};
use super::{SessionOptions, Timeline};
/// A received RTP packet. /// A received RTP packet.
pub struct Packet { pub struct Packet {
pub ctx: crate::PacketContext, pub ctx: PacketContext,
pub stream_id: usize, pub stream_id: usize,
pub timestamp: crate::Timestamp, pub timestamp: crate::Timestamp,
pub ssrc: u32, pub ssrc: u32,
@ -51,7 +53,7 @@ impl std::fmt::Debug for Packet {
#[derive(Debug)] #[derive(Debug)]
pub struct SenderReport { pub struct SenderReport {
pub stream_id: usize, pub stream_id: usize,
pub ctx: crate::PacketContext, pub ctx: PacketContext,
pub timestamp: crate::Timestamp, pub timestamp: crate::Timestamp,
pub ntp_timestamp: crate::NtpTimestamp, pub ntp_timestamp: crate::NtpTimestamp,
} }
@ -88,10 +90,10 @@ impl InorderParser {
pub fn rtp( pub fn rtp(
&mut self, &mut self,
session_options: &super::SessionOptions, session_options: &SessionOptions,
conn_ctx: &crate::ConnectionContext, conn_ctx: &ConnectionContext,
pkt_ctx: &crate::PacketContext, pkt_ctx: &PacketContext,
timeline: &mut super::Timeline, timeline: &mut Timeline,
stream_id: usize, stream_id: usize,
mut data: Bytes, mut data: Bytes,
) -> Result<Option<PacketItem>, Error> { ) -> Result<Option<PacketItem>, Error> {
@ -108,6 +110,18 @@ impl InorderParser {
), ),
}) })
})?; })?;
// Skip pt=50 packets, sent by at least Geovision cameras. I'm not sure
// what purpose these serve, but they have the same sequence number as
// the packet immediately before. In TCP streams, this can cause an
// "Out-of-order packet or large loss" error. In UDP streams, if these
// are delivered out of order, they will cause the more important other
// packet with the same sequence number to be skipped.
if reader.payload_type() == 50 {
debug!("skipping pkt with invalid payload type 50");
return Ok(None);
}
let sequence_number = u16::from_be_bytes([data[2], data[3]]); // I don't like rtsp_rs::Seq. let sequence_number = u16::from_be_bytes([data[2], data[3]]); // I don't like rtsp_rs::Seq.
let ssrc = reader.ssrc(); let ssrc = reader.ssrc();
let loss = sequence_number.wrapping_sub(self.next_seq.unwrap_or(sequence_number)); let loss = sequence_number.wrapping_sub(self.next_seq.unwrap_or(sequence_number));
@ -186,8 +200,8 @@ impl InorderParser {
pub fn rtcp( pub fn rtcp(
&mut self, &mut self,
pkt_ctx: &crate::PacketContext, pkt_ctx: &PacketContext,
timeline: &mut super::Timeline, timeline: &mut Timeline,
stream_id: usize, stream_id: usize,
data: Bytes, data: Bytes,
) -> Result<Option<PacketItem>, String> { ) -> Result<Option<PacketItem>, String> {
@ -233,3 +247,62 @@ impl InorderParser {
Ok(sr.map(PacketItem::SenderReport)) Ok(sr.map(PacketItem::SenderReport))
} }
} }
#[cfg(test)]
mod tests {
use super::*;
/// Checks dropping and logging Geovision's extra payload type 50 packets.
/// On a GV-EBD4701 running V1.02_2021_04_08, these seem to appear after
/// every IDR frame, with the same sequence number as the final packet in
/// that frame.
#[test]
fn geovision_pt50_packet() {
let mut timeline = Timeline::new(None, 90_000, None).unwrap();
let mut parser = InorderParser::new(Some(0xd25614e), None);
// Normal packet.
match parser.rtp(
&SessionOptions::default(),
&ConnectionContext::dummy(),
&PacketContext::dummy(),
&mut timeline,
0,
rtp_rs::RtpPacketBuilder::new()
.payload_type(105)
.ssrc(0xd25614e)
.sequence(0x1234.into())
.timestamp(141000)
.marked(true)
.payload(b"foo")
.build()
.unwrap()
.into(),
) {
Ok(Some(PacketItem::RtpPacket(_))) => {}
o => panic!("unexpected packet 1 result: {:#?}", o),
}
// Mystery pt=50 packet with same sequence number.
match parser.rtp(
&SessionOptions::default(),
&ConnectionContext::dummy(),
&PacketContext::dummy(),
&mut timeline,
0,
rtp_rs::RtpPacketBuilder::new()
.payload_type(50)
.ssrc(0xd25614e)
.sequence(0x1234.into())
.timestamp(141000)
.marked(true)
.payload(b"bar")
.build()
.unwrap()
.into(),
) {
Ok(None) => {}
o => panic!("unexpected packet 2 result: {:#?}", o),
}
}
}