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:
parent
ffaa831c54
commit
799584c8e3
@ -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)
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user