feat(stats): wire real scale/transfer/encode timing from EncState
Oracle step 4 (option A) — give the scale_*, transfer_*, encode_* stats
fields real producers instead of misleading zeros. The fields existed in
FrameTimings and PipelineStats already; producers just weren't passing
non-zero values.
- avhw.rs: new EncodeStages { scale_us, transfer_us, encode_us } struct.
EncState::encode_frame (HW VAAPI path) now times the filter graph
separately from avcodec_send_frame, returning EncodeStages. transfer_us
is honestly 0 because the HW path never reads back to CPU.
SwEncState::encode_frame (SW fallback path) returns EncodeStages too;
there import_and_scale bundles GPU scale + GPU→CPU readback into one
call, so scale_us includes transfer for SW. Documented inline.
- state.rs: StreamingEncoder::encode_frame return type bumps from
Result<()> to Result<EncodeStages>; wlr-screencopy path now feeds
real per-stage timings into FrameTimings instead of just total_us.
- state_portal.rs: HW portal path (enc.encode_frame) now extracts
stages.scale_us / stages.transfer_us / stages.encode_us into
FrameTimings. Removed the now-unused t_encode_start binding.
Deferred (documented):
- state_portal.rs SW portal path (line 525) calls import_and_scale +
enc_thread separately and bypasses SwEncState::encode_frame. To wire
scale/transfer timing there too, either route through SwEncState or
thread timing out of import_and_scale. Out of scope for this commit.
- SW path lumps transfer into scale_us. Splitting requires extending
import_and_scale's return type — left as a follow-up if operational
need arises (current default is HW VAAPI).
Oracle audit 2026-06-28 step 4 (option A: integrate, not delete).
All 79 unit tests + 3 integration tests pass. clippy: 0 errors.
This commit is contained in:
+16
-9
@@ -126,7 +126,7 @@ impl StreamingEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_frame(&mut self, hw_frame: &ffmpeg_next::frame::Video) -> anyhow::Result<()> {
|
||||
fn encode_frame(&mut self, hw_frame: &ffmpeg_next::frame::Video) -> anyhow::Result<crate::avhw::EncodeStages> {
|
||||
match self {
|
||||
StreamingEncoder::Mp4(enc) => enc.encode_frame(hw_frame),
|
||||
StreamingEncoder::WebRtc(enc) => enc.encode_frame(hw_frame),
|
||||
@@ -626,15 +626,22 @@ impl<S: CaptureSource> State<S> {
|
||||
};
|
||||
if should_encode {
|
||||
let encode_start = Instant::now();
|
||||
if let Err(e) = enc.encode_frame(&surface) {
|
||||
tracing::error!("encode_frame failed: {}", e);
|
||||
self.errored = true;
|
||||
match enc.encode_frame(&surface) {
|
||||
Ok(stages) => {
|
||||
let encode_elapsed = encode_start.elapsed().as_micros() as u64;
|
||||
self.stats.record_encode(&FrameTimings {
|
||||
scale_us: stages.scale_us,
|
||||
transfer_us: stages.transfer_us,
|
||||
encode_us: stages.encode_us,
|
||||
total_us: encode_elapsed,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("encode_frame failed: {}", e);
|
||||
self.errored = true;
|
||||
}
|
||||
}
|
||||
let encode_elapsed = encode_start.elapsed().as_micros() as u64;
|
||||
self.stats.record_encode(&FrameTimings {
|
||||
total_us: encode_elapsed,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
self.stats_frames += 1;
|
||||
if let Some(last) = self.stats_last_time {
|
||||
|
||||
Reference in New Issue
Block a user