Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ opt-level = 2
[profile.dev.package.cap-audio]
opt-level = 2

# opt-level 0 compiles the AVX2 BT.709 kernel into a spill loop. On the
# ci-verify profile that is 180 ms for 1080p against 3 ms for swscale, and
# the Windows real-capture job then keeps about 6 fps. opt-level 1 is under
# 2 ms, still faster than swscale.
[profile.dev.package.cap-enc-ffmpeg]
opt-level = 1

# The verification suite decodes markers from every output pixel it reads;
# unoptimised it spends minutes in its own loops.
[profile.dev.package.cap-verify]
Expand All @@ -126,6 +133,11 @@ incremental = false
[profile.ci-verify.package."*"]
opt-level = 1

# `package."*"` does not cover workspace members, so this crate otherwise
# stays at opt-level 0. See `[profile.dev.package.cap-enc-ffmpeg]`.
[profile.ci-verify.package.cap-enc-ffmpeg]
opt-level = 1

[profile.ci-verify.package.cap-verify]
opt-level = 3

Expand Down
58 changes: 54 additions & 4 deletions crates/enc-ffmpeg/src/video/h264.rs
Original file line number Diff line number Diff line change
Expand Up @@ -915,8 +915,7 @@ impl H264Encoder {
let frame_to_send = if let Some(converter) = &mut self.converter {
let pts = frame.pts();
let converted = self.converted_frame_pool.as_mut().unwrap();
converter
.run(&frame, converted)
super::rgb_to_yuv::convert_or_scale(&frame, converted, converter)
.map_err(QueueFrameError::Converter)?;
converted.set_pts(pts);
converted as &frame::Video
Expand Down Expand Up @@ -945,8 +944,7 @@ impl H264Encoder {
let converted = converted_frame.get_or_insert_with(|| {
frame::Video::new(self.output_format, self.output_width, self.output_height)
});
converter
.run(frame, converted)
super::rgb_to_yuv::convert_or_scale(frame, converted, converter)
.map_err(QueueFrameError::Converter)?;
converted.set_pts(pts);
converted as &frame::Video
Expand Down Expand Up @@ -2089,6 +2087,58 @@ mod rgb_color_tests {
}
}

#[test]
fn queue_frame_to_bgrz_flat_red_decodes_as_bt709() {
ffmpeg::init().unwrap();
let directory = tempfile::tempdir().unwrap();
let path = directory.path().join("bgrz.mp4");
let mut output = format::output_as(&path, "mp4").unwrap();
let info = VideoInfo::from_raw_ffmpeg(format::Pixel::BGRZ, 64, 64, 30);
let mut encoder = H264Encoder::builder(info)
.with_preset(H264Preset::Ultrafast)
.with_crf(18)
.with_encoder_priority_override(&["libx264"])
.build(&mut output)
.unwrap();
let mut frame = frame::Video::new(format::Pixel::BGRZ, 64, 64);
for y in 0..64 {
let stride = frame.stride(0);
for x in 0..64 {
let offset = y * stride + x * 4;
frame.data_mut(0)[offset..offset + 4].copy_from_slice(&[40, 40, 220, 255]);
}
}
let mut sink = crate::PacketQueue::new(ffmpeg::Rational(1, 90_000));
encoder
.queue_frame_to(frame, Duration::ZERO, &mut sink)
.unwrap();
encoder.flush_to(&mut sink).unwrap();
let packets = sink.take();
assert!(!packets.is_empty());

let codec = ffmpeg::decoder::find(ffmpeg::codec::Id::H264).unwrap();
let mut decoder = context::Context::new_with_codec(codec)
.decoder()
.video()
.unwrap();
let mut frames = Vec::new();
for packet in &packets {
decoder.send_packet(packet).unwrap();
receive_frames(&mut decoder, &mut frames);
}
decoder.send_eof().unwrap();
receive_frames(&mut decoder, &mut frames);
assert_eq!(frames.len(), 1);
let decoded = &frames[0];
assert_eq!(decoded.color_space(), color::Space::BT709);
assert_eq!(decoded.color_range(), color::Range::MPEG);
let y = decoded.data(0)[32 * decoded.stride(0) + 32];
assert!(
y.abs_diff(83) <= 2,
"decoded luma {y} is not limited BT.709 red"
);
}

#[test]
fn rgb_classification_does_not_treat_yuv_or_hardware_as_rgb() {
for format in [
Expand Down
6 changes: 2 additions & 4 deletions crates/enc-ffmpeg/src/video/h264_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,7 @@ impl H264PacketEncoder {
let converted = self.converted_frame_pool.as_mut().expect(
"converted_frame_pool present whenever converter is Some (invariant preserved by from_opened)",
);
converter
.run(&frame, converted)
super::rgb_to_yuv::convert_or_scale(&frame, converted, converter)
.map_err(EncodePacketError::Converter)?;
converted.set_pts(pts);
converted as &frame::Video
Expand Down Expand Up @@ -173,8 +172,7 @@ impl H264PacketEncoder {
let converted = converted_frame.get_or_insert_with(|| {
frame::Video::new(self.output_format, self.output_width, self.output_height)
});
converter
.run(frame, converted)
super::rgb_to_yuv::convert_or_scale(frame, converted, converter)
.map_err(EncodePacketError::Converter)?;
converted.set_pts(pts);
converted as &frame::Video
Expand Down
1 change: 1 addition & 0 deletions crates/enc-ffmpeg/src/video/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ pub mod h264;
pub mod h264_packet;
pub mod hevc;
pub mod prores;
mod rgb_to_yuv;
#[cfg(target_os = "macos")]
pub mod videotoolbox_hw;
Loading
Loading