using ytLive.Services; namespace ytLive.ViewModels; public partial class MainViewModel { /// The alert announcement strip as the preview pane shows it: a /// full-master-width bitmap, or null when no alert is playing (or a Flash is in /// its off half). Mirrors the social bar's global-overlay pattern — the strip is /// NOT a per-source frame, so it can't ride the alert box's /// VideoImageSource. private System.Windows.Media.Imaging.WriteableBitmap? _alertTickerBitmap; public System.Windows.Media.Imaging.WriteableBitmap? AlertTickerImageSource { get => _alertTickerBitmap; private set { _alertTickerBitmap = value; OnPropertyChanged(nameof(AlertTickerImageSource)); } } public bool AlertTickerVisible => _alertTickerBitmap != null; /// Publishes one ticker frame to the preview pane. Called on the UI /// thread from the alert layer's own tick, so the WPF bitmap write is legal. /// Reuses one and /// overwrites its back buffer — a fresh bitmap every tick would churn the /// render cache for no reason. internal void PublishAlertTickerPreview(VideoFrame? frame) { if (frame == null) { if (_alertTickerBitmap != null) { AlertTickerImageSource = null; OnPropertyChanged(nameof(AlertTickerVisible)); } return; } if (_alertTickerBitmap == null || _alertTickerBitmap.PixelWidth != frame.Width || _alertTickerBitmap.PixelHeight != frame.Height) { AlertTickerImageSource = new System.Windows.Media.Imaging.WriteableBitmap( frame.Width, frame.Height, 96, 96, System.Windows.Media.PixelFormats.Bgra32, null); OnPropertyChanged(nameof(AlertTickerVisible)); } var target = _alertTickerBitmap!; target.WritePixels( new System.Windows.Int32Rect(0, 0, frame.Width, frame.Height), frame.BgraPixels, frame.Stride, 0); // The bitmap instance is unchanged, so the pane's Source binding still // points at it — nudge it so WPF re-reads the back buffer this tick. OnPropertyChanged(nameof(AlertTickerImageSource)); } }