encoder: fix color space to bt709, improve text sharpness, eliminate mmap thrashing, and enhance notification bar vibrancy

This commit is contained in:
katR 2026-09-12 11:25:14 +05:30
parent 5a1e503508
commit 1e224edceb
4 changed files with 122 additions and 27 deletions

View file

@ -690,13 +690,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
recv(ticker) -> _ => {
while ticker.try_recv().is_ok() {}
if last_malloc_trim.elapsed().as_secs() >= 5 {
last_malloc_trim = std::time::Instant::now();
#[cfg(target_os = "linux")]
unsafe { libc::malloc_trim(0); }
}
if !normal_recording && !config.replay_enabled {
if last_malloc_trim.elapsed().as_secs() >= 5 {
last_malloc_trim = std::time::Instant::now();
#[cfg(target_os = "linux")]
unsafe { libc::malloc_trim(0); }
}
has_new_frame = false;
continue;
}

View file

@ -75,6 +75,12 @@ impl VaapiEncoder {
};
(*codec_ctx).flags |= AV_CODEC_FLAG_GLOBAL_HEADER as libc::c_int;
// Rec.709 Color Space & MPEG Limited Range (Broadcast / Web standard, avoids yellow tint)
(*codec_ctx).colorspace = AVColorSpace::AVCOL_SPC_BT709;
(*codec_ctx).color_primaries = AVColorPrimaries::AVCOL_PRI_BT709;
(*codec_ctx).color_trc = AVColorTransferCharacteristic::AVCOL_TRC_BT709;
(*codec_ctx).color_range = AVColorRange::AVCOL_RANGE_MPEG;
let mut hw_device_ctx: *mut AVBufferRef = ptr::null_mut();
let ret = av_hwdevice_ctx_create(
&mut hw_device_ctx,
@ -123,10 +129,18 @@ impl VaapiEncoder {
(*staged_nv12).format = AVPixelFormat::AV_PIX_FMT_NV12 as i32;
(*staged_nv12).width = width as i32;
(*staged_nv12).height = height as i32;
(*staged_nv12).colorspace = AVColorSpace::AVCOL_SPC_BT709;
(*staged_nv12).color_primaries = AVColorPrimaries::AVCOL_PRI_BT709;
(*staged_nv12).color_trc = AVColorTransferCharacteristic::AVCOL_TRC_BT709;
(*staged_nv12).color_range = AVColorRange::AVCOL_RANGE_MPEG;
av_frame_get_buffer(staged_nv12, 32);
let hw_frame = av_frame_alloc();
(*hw_frame).format = AVPixelFormat::AV_PIX_FMT_VAAPI as i32;
(*hw_frame).colorspace = AVColorSpace::AVCOL_SPC_BT709;
(*hw_frame).color_primaries = AVColorPrimaries::AVCOL_PRI_BT709;
(*hw_frame).color_trc = AVColorTransferCharacteristic::AVCOL_TRC_BT709;
(*hw_frame).color_range = AVColorRange::AVCOL_RANGE_MPEG;
let sws_ctx = sws_getContext(
width as i32,
@ -135,12 +149,28 @@ impl VaapiEncoder {
width as i32,
height as i32,
AVPixelFormat::AV_PIX_FMT_NV12,
1,
(SwsFlags::SWS_BICUBIC as libc::c_int) | (SwsFlags::SWS_ACCURATE_RND as libc::c_int),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
);
if !sws_ctx.is_null() {
let coeffs = sws_getCoefficients(SWS_CS_ITU709);
if !coeffs.is_null() {
sws_setColorspaceDetails(
sws_ctx,
coeffs,
1, // srcRange: 1 (sRGB full range 0-255)
coeffs,
0, // dstRange: 0 (MPEG limited range 16-235)
0,
1 << 16,
1 << 16,
);
}
}
Ok(Self {
codec_ctx,
hw_device_ctx,
@ -291,9 +321,11 @@ impl VaapiEncoder {
0,
);
if p != libc::MAP_FAILED {
if self.dma_mmap_cache.len() >= 4 {
for (_, (old_p, old_size)) in self.dma_mmap_cache.drain() {
libc::munmap(old_p, old_size);
if self.dma_mmap_cache.len() >= 16 {
if let Some(old_fd) = self.dma_mmap_cache.keys().next().copied() {
if let Some((old_p, old_size)) = self.dma_mmap_cache.remove(&old_fd) {
libc::munmap(old_p, old_size);
}
}
}
self.dma_mmap_cache.insert(*fd, (p, mmap_size));

View file

@ -354,22 +354,42 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) {
cr.rectangle(0.5, 0.5, w - 1.0, h - 1.0);
let _ = cr.stroke();
// 5. Animated countdown timer line on bottom edge (high visibility)
// 5. Animated countdown timer line on bottom edge (vibrant accent glow)
let progress = 1.0 - (elapsed / total_dur).clamp(0.0, 1.0);
let bar_h = 3.5;
cr.set_source_rgba(1.0, 1.0, 1.0, 0.15 * alpha);
let bar_w = (w * progress).max(0.0);
// Track: glowing tinted accent baseline
cr.set_source_rgba(active_accent.0, active_accent.1, active_accent.2, 0.22 * alpha);
cr.rectangle(0.0, h - bar_h, w, bar_h);
let _ = cr.fill();
let bar_w = (w * progress).max(0.0);
cr.set_source_rgba(active_accent.0, active_accent.1, active_accent.2, 0.95 * alpha);
// Ambient vibrant glow above bar
let glow_h = 3.0;
cr.set_source_rgba(active_accent.0, active_accent.1, active_accent.2, 0.28 * alpha);
cr.rectangle(0.0, h - bar_h - glow_h, bar_w, glow_h);
let _ = cr.fill();
// Solid vibrant core bar
cr.set_source_rgba(active_accent.0, active_accent.1, active_accent.2, 1.0 * alpha);
cr.rectangle(0.0, h - bar_h, bar_w, bar_h);
let _ = cr.fill();
// Top neon specular edge highlight
let high_r = (active_accent.0 + 0.35).min(1.0);
let high_g = (active_accent.1 + 0.35).min(1.0);
let high_b = (active_accent.2 + 0.35).min(1.0);
cr.set_source_rgba(high_r, high_g, high_b, 0.90 * alpha);
cr.set_line_width(1.0);
cr.move_to(0.0, h - bar_h);
cr.line_to(bar_w, h - bar_h);
let _ = cr.stroke();
// Laser-sharp white leading tip indicator
if bar_w > 2.0 {
cr.set_source_rgba(1.0, 1.0, 1.0, 0.85 * alpha);
cr.set_line_width(1.5);
cr.move_to(bar_w, h - bar_h);
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0 * alpha);
cr.set_line_width(2.0);
cr.move_to(bar_w, h - bar_h - 1.0);
cr.line_to(bar_w, h);
let _ = cr.stroke();
}

View file

@ -2224,18 +2224,40 @@ impl ScytheOverlayApp {
egui::StrokeKind::Inside,
);
// 5. Animated Countdown Timer Line (bottom edge - high visibility)
// 5. Animated Countdown Timer Line (bottom edge - vibrant accent glow)
let progress = 1.0 - (elapsed / total_dur).clamp(0.0, 1.0);
let bar_h = 3.5_f32;
let bar_track = egui::Rect::from_min_size(egui::pos2(toast_rect.left(), toast_rect.bottom() - bar_h), egui::vec2(card_w, bar_h));
painter.rect_filled(bar_track, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(255, 255, 255, (30.0 * anim_alpha) as u8));
let bar_w = (card_w * progress).max(0.0);
// Track: glowing tinted accent baseline
let bar_track = egui::Rect::from_min_size(egui::pos2(toast_rect.left(), toast_rect.bottom() - bar_h), egui::vec2(card_w, bar_h));
painter.rect_filled(bar_track, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (45.0 * anim_alpha) as u8));
// Ambient vibrant glow above bar
let glow_h = 3.0_f32;
let glow_rect = egui::Rect::from_min_size(egui::pos2(toast_rect.left(), toast_rect.bottom() - bar_h - glow_h), egui::vec2(bar_w, glow_h));
painter.rect_filled(glow_rect, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (50.0 * anim_alpha) as u8));
// Solid vibrant core bar
let bar_rect = egui::Rect::from_min_size(egui::pos2(toast_rect.left(), toast_rect.bottom() - bar_h), egui::vec2(bar_w, bar_h));
painter.rect_filled(bar_rect, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (255.0 * anim_alpha) as u8));
// Top neon specular edge highlight for intense vibrancy
painter.line_segment(
[egui::pos2(toast_rect.left(), toast_rect.bottom() - bar_h), egui::pos2(toast_rect.left() + bar_w, toast_rect.bottom() - bar_h)],
Stroke::new(1.0_f32, Color32::from_rgba_unmultiplied(
(active_color.r() as u16 + 80).min(255) as u8,
(active_color.g() as u16 + 80).min(255) as u8,
(active_color.b() as u16 + 80).min(255) as u8,
(240.0 * anim_alpha) as u8,
)),
);
// Laser-sharp white leading tip indicator
if bar_w > 2.0 {
painter.line_segment(
[egui::pos2(toast_rect.left() + bar_w, toast_rect.bottom() - bar_h), egui::pos2(toast_rect.left() + bar_w, toast_rect.bottom())],
Stroke::new(1.5_f32, Color32::from_rgba_unmultiplied(255, 255, 255, (220.0 * anim_alpha) as u8)),
[egui::pos2(toast_rect.left() + bar_w, toast_rect.bottom() - bar_h - 1.0), egui::pos2(toast_rect.left() + bar_w, toast_rect.bottom())],
Stroke::new(2.0_f32, Color32::from_rgba_unmultiplied(255, 255, 255, (255.0 * anim_alpha) as u8)),
);
}
@ -2776,18 +2798,40 @@ impl eframe::App for ShadowPlayToastApp {
egui::StrokeKind::Inside,
);
// 5. Animated Countdown Timer Line (bottom edge - high visibility)
// 5. Animated Countdown Timer Line (bottom edge - vibrant accent glow)
let progress = 1.0 - (elapsed / total_dur).clamp(0.0, 1.0);
let bar_h = 3.5_f32;
let bar_track = egui::Rect::from_min_size(egui::pos2(rect.left(), rect.bottom() - bar_h), egui::vec2(320.0, bar_h));
painter.rect_filled(bar_track, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(255, 255, 255, (30.0 * anim_alpha) as u8));
let bar_w = (320.0 * progress).max(0.0);
// Track: glowing tinted accent baseline
let bar_track = egui::Rect::from_min_size(egui::pos2(rect.left(), rect.bottom() - bar_h), egui::vec2(320.0, bar_h));
painter.rect_filled(bar_track, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (45.0 * anim_alpha) as u8));
// Ambient vibrant glow above bar
let glow_h = 3.0_f32;
let glow_rect = egui::Rect::from_min_size(egui::pos2(rect.left(), rect.bottom() - bar_h - glow_h), egui::vec2(bar_w, glow_h));
painter.rect_filled(glow_rect, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (50.0 * anim_alpha) as u8));
// Solid vibrant core bar
let bar_rect = egui::Rect::from_min_size(egui::pos2(rect.left(), rect.bottom() - bar_h), egui::vec2(bar_w, bar_h));
painter.rect_filled(bar_rect, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (255.0 * anim_alpha) as u8));
// Top neon specular edge highlight for intense vibrancy
painter.line_segment(
[egui::pos2(rect.left(), rect.bottom() - bar_h), egui::pos2(rect.left() + bar_w, rect.bottom() - bar_h)],
Stroke::new(1.0_f32, Color32::from_rgba_unmultiplied(
(active_color.r() as u16 + 80).min(255) as u8,
(active_color.g() as u16 + 80).min(255) as u8,
(active_color.b() as u16 + 80).min(255) as u8,
(240.0 * anim_alpha) as u8,
)),
);
// Laser-sharp white leading tip indicator
if bar_w > 2.0 {
painter.line_segment(
[egui::pos2(rect.left() + bar_w, rect.bottom() - bar_h), egui::pos2(rect.left() + bar_w, rect.bottom())],
Stroke::new(1.5_f32, Color32::from_rgba_unmultiplied(255, 255, 255, (220.0 * anim_alpha) as u8)),
[egui::pos2(rect.left() + bar_w, rect.bottom() - bar_h - 1.0), egui::pos2(rect.left() + bar_w, rect.bottom())],
Stroke::new(2.0_f32, Color32::from_rgba_unmultiplied(255, 255, 255, (255.0 * anim_alpha) as u8)),
);
}