more anamorphic streams

* my dad's GW4089IP cameras use 720x480
* some Reolink cameras use 640x352
* I'm playing with rotated cameras (16x9 -> 9x16)

I'd prefer to calculate pasp from a configured camera aspect ratio
than to hardcode the assumption these are 16x9, but that requires
a schema change. This is an improvement for now.
This commit is contained in:
Scott Lamb 2021-05-22 14:43:58 -07:00
parent 54bd068706
commit 0068a9ae70
3 changed files with 33 additions and 7 deletions

1
server/Cargo.lock generated
View File

@ -1265,6 +1265,7 @@ dependencies = [
"mylog",
"nix",
"nom",
"num-rational",
"parking_lot",
"protobuf",
"reffers",

View File

@ -64,6 +64,7 @@ url = "2.1.1"
uuid = { version = "0.8", features = ["serde", "std", "v4"] }
[dev-dependencies]
num-rational = { version = "0.3.2", default-features = false, features = ["std"] }
reqwest = { version = "0.11.0", default-features = false, features = ["json"] }
tempfile = "3.2.0"

View File

@ -30,11 +30,15 @@ const NAL_UNIT_PIC_PARAMETER_SET: u8 = 8;
const NAL_UNIT_TYPE_MASK: u8 = 0x1F; // bottom 5 bits of first byte of unit.
// For certain common sub stream anamorphic resolutions, add a pixel aspect ratio box.
const PIXEL_ASPECT_RATIOS: [((u16, u16), (u16, u16)); 4] = [
// Assume the camera is 16x9. These are just the standard wide mode; default_pixel_aspect_ratio
// tries the transpose also.
const PIXEL_ASPECT_RATIOS: [((u16, u16), (u16, u16)); 6] = [
((320, 240), (4, 3)),
((352, 240), (40, 33)),
((640, 352), (44, 45)),
((640, 480), (4, 3)),
((704, 480), (40, 33)),
((720, 480), (32, 27)),
];
/// Get the pixel aspect ratio to use if none is specified.
@ -47,13 +51,19 @@ const PIXEL_ASPECT_RATIOS: [((u16, u16), (u16, u16)); 4] = [
/// Note that at least in the case of .mp4 muxing, we don't need to fix up the underlying SPS.
/// SPS; PixelAspectRatioBox's definition says that it overrides the H.264-level declaration.
fn default_pixel_aspect_ratio(width: u16, height: u16) -> (u16, u16) {
let dims = (width, height);
for r in &PIXEL_ASPECT_RATIOS {
if r.0 == dims {
return r.1;
}
if width >= height {
PIXEL_ASPECT_RATIOS
.iter()
.find(|r| r.0 == (width, height))
.map(|r| r.1)
.unwrap_or((1, 1))
} else {
PIXEL_ASPECT_RATIOS
.iter()
.find(|r| r.0 == (height, width))
.map(|r| (r.1 .1, r.1 .0))
.unwrap_or((1, 1))
}
(1, 1)
}
/// Decodes a H.264 Annex B byte stream into NAL units. Calls `f` for each NAL unit in the byte
@ -435,4 +445,18 @@ mod tests {
super::transform_sample_data(&INPUT, &mut out).unwrap();
assert_eq!(&out[..], &EXPECTED_OUTPUT[..]);
}
#[test]
fn pixel_aspect_ratios() {
use super::default_pixel_aspect_ratio;
use num_rational::Ratio;
for &((w, h), _) in &super::PIXEL_ASPECT_RATIOS {
let (h_spacing, v_spacing) = default_pixel_aspect_ratio(w, h);
assert_eq!(Ratio::new(w * h_spacing, h * v_spacing), Ratio::new(16, 9));
// 90 or 270 degree rotation.
let (h_spacing, v_spacing) = default_pixel_aspect_ratio(h, w);
assert_eq!(Ratio::new(h * h_spacing, w * v_spacing), Ratio::new(9, 16));
}
}
}