Skip to content

Commit

Permalink
WIP: h.265 support
Browse files Browse the repository at this point in the history
left to do:
* use released version of h264-reader
* fix definition of is random access point to take into account nuh
  layer id, check if we're doing the right thing with stsa
* fill in validate_order
  • Loading branch information
scottlamb committed Aug 14, 2024
1 parent 0f6e81a commit f0488e6
Show file tree
Hide file tree
Showing 17 changed files with 2,632 additions and 144 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ jobs:
matrix:
rust:
- stable
- 1.67
- 1.79
include:
- rust: stable
extra_components: rustfmt
fail-fast: false
runs-on: ubuntu-20.04
steps:
- name: Checkout
Expand Down
36 changes: 20 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ categories = ["network-programming", "multimedia"]
description = "high-level RTSP multimedia streaming library"
repository = "https://github.com/scottlamb/retina"
include = ["src/**/*", "benches", "Cargo.toml"]
rust-version = "1.67"
rust-version = "1.79"

[features]
unstable-sample-entry = []
unstable-h265 = []

[package.metadata.docs.rs]
# https://docs.rs/about/metadata
Expand All @@ -29,7 +30,9 @@ base64 = "0.21.0"
bitstream-io = "1.1"
bytes = "1.0.1"
futures = "0.3.14"
h264-reader = "0.7.0"
#h264-reader = "0.7.0"
#h264-reader = { path = "../../crates/h264-reader" }
h264-reader = { git = "https://github.com/scottlamb/h264-reader", rev = "35968d5ca67f317fd35c1e344adb8ae14ee2efd6" }
hex = "0.4.3"
http-auth = "0.1.2"
log = "0.4.8"
Expand Down
5 changes: 3 additions & 2 deletions examples/client/src/mp4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -709,8 +709,9 @@ pub async fn run(opts: Opts) -> Result<(), Error> {
let video_stream_i = if !opts.no_video {
let s = session.streams().iter().position(|s| {
if s.media() == "video" {
if s.encoding_name() == "h264" || s.encoding_name() == "jpeg" {
log::info!("Using h264 video stream");
let encoding_name = s.encoding_name();
if matches!(encoding_name, "h264" | "h265" | "jpeg") {
log::info!("Using {encoding_name} video stream");
return true;
}
log::info!(
Expand Down
32 changes: 17 additions & 15 deletions fuzz/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ libfuzzer-sys = "0.4"

[dependencies.retina]
path = ".."
features = ["unstable-h265"]

# Prevent this from interfering with workspaces
[workspace]
Expand All @@ -26,6 +27,12 @@ path = "fuzz_targets/depacketize_h264.rs"
test = false
doc = false

[[bin]]
name = "depacketize_h265"
path = "fuzz_targets/depacketize_h265.rs"
test = false
doc = false

[[bin]]
name = "roundtrip_h264"
path = "fuzz_targets/roundtrip_h264.rs"
Expand All @@ -37,3 +44,9 @@ name = "depacketize_jpeg"
path = "fuzz_targets/depacketize_jpeg.rs"
test = false
doc = false

[[bin]]
name = "h265_nal"
path = "fuzz_targets/h265_nal.rs"
test = false
doc = false
60 changes: 60 additions & 0 deletions fuzz/fuzz_targets/depacketize_h265.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (C) 2021 Scott Lamb <[email protected]>
// SPDX-License-Identifier: MIT OR Apache-2.0

#![no_main]
use libfuzzer_sys::fuzz_target;
use std::num::NonZeroU32;

fuzz_target!(|data: &[u8]| {
let mut data = data;
let mut depacketizer = retina::codec::Depacketizer::new(
"video", "h265", 90_000, None, Some("profile-id=1;sprop-sps=QgEBAWAAAAMAsAAAAwAAAwBaoAWCAeFja5JFL83BQYFBAAADAAEAAAMADKE=;sprop-pps=RAHA8saNA7NA;sprop-vps=QAEMAf//AWAAAAMAsAAAAwAAAwBarAwAAAMABAAAAwAyqA==")).unwrap();
let mut timestamp = retina::Timestamp::new(0, NonZeroU32::new(90_000).unwrap(), 0).unwrap();
let mut sequence_number: u16 = 0;
let conn_ctx = retina::ConnectionContext::dummy();
let stream_ctx = retina::StreamContext::dummy();
let pkt_ctx = retina::PacketContext::dummy();
loop {
let (hdr, rest) = match data.split_first() {
Some(r) => r,
None => return,
};
let ts_change = (hdr & 0b001) != 0;
let mark = (hdr & 0b010) != 0;
let loss = (hdr & 0b100) != 0;
let len = usize::from(hdr >> 3);
if rest.len() < len {
return;
}
let (payload, rest) = rest.split_at(len);
data = rest;
if loss {
sequence_number = sequence_number.wrapping_add(1);
}
if ts_change {
timestamp = timestamp.try_add(1).unwrap();
}
let pkt = retina::rtp::ReceivedPacketBuilder {
ctx: pkt_ctx,
stream_id: 0,
timestamp,
ssrc: 0,
sequence_number,
loss: u16::from(loss),
payload_type: 96,
mark,
}
.build(payload.iter().copied())
.unwrap();
// println!("pkt: {:#?}", pkt);
if depacketizer.push(pkt).is_err() {
return;
}
while let Some(item) = depacketizer.pull(&conn_ctx, &stream_ctx).transpose() {
if item.is_err() {
return;
}
}
sequence_number = sequence_number.wrapping_add(1);
}
});
23 changes: 23 additions & 0 deletions fuzz/fuzz_targets/h265_nal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (C) 2024 Scott Lamb <[email protected]>
// SPDX-License-Identifier: MIT OR Apache-2.0

#![no_main]
use libfuzzer_sys::fuzz_target;

use retina::codec::h265::nal;

fuzz_target!(|data: &[u8]| {
let Ok((h, bits)) = nal::split(data) else {
return;
};

match h.unit_type() {
nal::UnitType::SpsNut => {
let _ = nal::Sps::from_bits(bits);
}
nal::UnitType::PpsNut => {
let _ = nal::Pps::from_bits(bits);
}
_ => {}
}
});
21 changes: 13 additions & 8 deletions src/client/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -943,14 +943,19 @@ mod tests {
assert_eq!(p.streams[0].media(), "video");
assert_eq!(p.streams[0].encoding_name(), "h265");
assert_eq!(p.streams[0].rtp_payload_type, 98);
assert!(p.streams[0].parameters().is_none());
assert_eq!(p.streams[1].media(), "audio");
assert_eq!(p.streams[1].encoding_name(), "pcma");
assert_eq!(p.streams[1].rtp_payload_type, 8);
match p.streams[1].parameters().unwrap() {
ParametersRef::Audio(_) => {}
_ => panic!(),
};

if cfg!(feature = "unstable-h265") {
assert!(p.streams[0].parameters().is_some());
assert_eq!(p.streams[1].media(), "audio");
assert_eq!(p.streams[1].encoding_name(), "pcma");
assert_eq!(p.streams[1].rtp_payload_type, 8);
match p.streams[1].parameters().unwrap() {
ParametersRef::Audio(_) => {}
_ => panic!(),
};
} else {
assert!(p.streams[0].parameters().is_none());
}
}

#[test]
Expand Down
Loading

0 comments on commit f0488e6

Please sign in to comment.