Skip to content

Commit

Permalink
skip Geovision's strange pt=50 packets
Browse files Browse the repository at this point in the history
Once #33 is fixed, this should allow Geovision cameras to more or
less work.
  • Loading branch information
scottlamb committed Sep 7, 2021
1 parent ffaa831 commit 799584c
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## unreleased

* 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)

Expand Down
93 changes: 83 additions & 10 deletions src/client/rtp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
//! RTP and RTCP handling; see [RFC 3550](https://datatracker.ietf.org/doc/html/rfc3550).
use bytes::{Buf, Bytes};
use log::trace;
use log::{debug, trace};
use pretty_hex::PrettyHex;

use crate::client::PacketItem;
use crate::{Error, ErrorInt};
use crate::{ConnectionContext, Error, ErrorInt, PacketContext};

use super::{SessionOptions, Timeline};

/// A received RTP packet.
pub struct Packet {
pub ctx: crate::PacketContext,
pub ctx: PacketContext,
pub stream_id: usize,
pub timestamp: crate::Timestamp,
pub ssrc: u32,
Expand Down Expand Up @@ -51,7 +53,7 @@ impl std::fmt::Debug for Packet {
#[derive(Debug)]
pub struct SenderReport {
pub stream_id: usize,
pub ctx: crate::PacketContext,
pub ctx: PacketContext,
pub timestamp: crate::Timestamp,
pub ntp_timestamp: crate::NtpTimestamp,
}
Expand Down Expand Up @@ -88,10 +90,10 @@ impl InorderParser {

pub fn rtp(
&mut self,
session_options: &super::SessionOptions,
conn_ctx: &crate::ConnectionContext,
pkt_ctx: &crate::PacketContext,
timeline: &mut super::Timeline,
session_options: &SessionOptions,
conn_ctx: &ConnectionContext,
pkt_ctx: &PacketContext,
timeline: &mut Timeline,
stream_id: usize,
mut data: Bytes,
) -> Result<Option<PacketItem>, Error> {
Expand All @@ -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 ssrc = reader.ssrc();
let loss = sequence_number.wrapping_sub(self.next_seq.unwrap_or(sequence_number));
Expand Down Expand Up @@ -186,8 +200,8 @@ impl InorderParser {

pub fn rtcp(
&mut self,
pkt_ctx: &crate::PacketContext,
timeline: &mut super::Timeline,
pkt_ctx: &PacketContext,
timeline: &mut Timeline,
stream_id: usize,
data: Bytes,
) -> Result<Option<PacketItem>, String> {
Expand Down Expand Up @@ -233,3 +247,62 @@ impl InorderParser {
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),
}
}
}

0 comments on commit 799584c

Please sign in to comment.