From d702608eaf9ab8c33ac03c55dd7eeb2564f7912f Mon Sep 17 00:00:00 2001 From: MarekSpodBiedry <73122968+MarekSpodBiedry@users.noreply.github.com> Date: Sun, 11 Oct 2026 11:35:18 +0200 Subject: [PATCH] Count VideoToolbox sessions, frames and declined requests in perf.stats (#981) --- crates/platform/src/hardware_encode.rs | 8 +++++++- crates/platform/tests/hardware_encode.rs | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/crates/platform/src/hardware_encode.rs b/crates/platform/src/hardware_encode.rs index c715e927..eaf7e0dc 100644 --- a/crates/platform/src/hardware_encode.rs +++ b/crates/platform/src/hardware_encode.rs @@ -133,13 +133,18 @@ pub fn videotoolbox_encoder_factory( Ok(c) => c, Err(why) => { log::info!("hardware {name} encoding declined: {why}"); + filmcraft_export::note_hw_encode_declined(); return None; } }; match VtEncoder::new(config) { - Ok(vt) => Some(Ok(Box::new(HardwareEncoder { vt, y: Vec::new(), u: Vec::new(), v: Vec::new(), decoded: 0 }))), + Ok(vt) => { + filmcraft_export::note_hw_encode_session(); + Some(Ok(Box::new(HardwareEncoder { vt, y: Vec::new(), u: Vec::new(), v: Vec::new(), decoded: 0 }))) + } Err(why) => { log::info!("hardware {name} encoding declined: {why}"); + filmcraft_export::note_hw_encode_declined(); None } } @@ -222,6 +227,7 @@ impl VideoEncoder for HardwareEncoder { } filmcraft_export::timed(filmcraft_export::Stage::Convert, || filmcraft_export::rgba_to_yuv420_8(f.rgba, w, h, &mut self.y, &mut self.u, &mut self.v)); let packets = self.vt.encode(f.index, &self.y, &self.u, &self.v).map_err(ExportError::Encode)?; + filmcraft_export::note_hw_encode_frame(); // the muxer needs the parameter sets after the first group of pictures if f.index == 0 { let params = self.vt.parameter_sets().ok_or_else(|| ExportError::Encode("VideoToolbox returned no parameter sets for the first frame".into()))?; diff --git a/crates/platform/tests/hardware_encode.rs b/crates/platform/tests/hardware_encode.rs index 94b1b928..e4959415 100644 --- a/crates/platform/tests/hardware_encode.rs +++ b/crates/platform/tests/hardware_encode.rs @@ -9,7 +9,8 @@ use std::panic::AssertUnwindSafe; use std::sync::Arc; use filmcraft_export::{ - BitrateMode, EncodedPacket, EncoderFrame, ExportSettings, Format, H264Pass, H264Profile, HardwareEncoding, Progress, VideoEncoder, export, rgba_to_yuv420_8, + BitrateMode, EncodedPacket, EncoderFrame, ExportSettings, Format, H264Pass, H264Profile, HardwareEncoding, Progress, VideoEncoder, export, hw_encode_stats, + rgba_to_yuv420_8, }; use filmcraft_frame::PixelData; use filmcraft_isobmff::{CodecConfig, SampleEntry}; @@ -133,6 +134,22 @@ fn factory_only_acts_when_asked() { assert!(videotoolbox_encoder_factory(Format::H264, W, H, FPS, &ExportSettings { hardware_encoding: HardwareEncoding::Off, ..s }).is_none()); } +/// `perf.stats` reads these counters: a declined request, a session and every encoded picture must show. +/// The counters are process-wide and other tests add to them, so only increases are checked. +#[test] +fn hardware_encoder_counters_follow_the_export() { + let s = hardware_settings(); + let before = hw_encode_stats(); + // an odd picture size is declined before any session is created + assert!(videotoolbox_encoder_factory(Format::H264, W + 1, H, FPS, &s).is_none()); + assert!(hw_encode_stats().declined > before.declined, "a declined request is counted"); + let Some(mut enc) = hardware(&s, W, H) else { return }; + let created = hw_encode_stats(); + assert!(created.sessions > before.sessions, "a created session is counted"); + encode_all(&mut enc, 3); + assert!(hw_encode_stats().frames >= created.frames + 3, "every encoded picture is counted"); +} + #[test] fn round_trip_through_our_software_decoder() { let s = hardware_settings();