using ytLive.Services;
namespace ytLive.ViewModels;
public partial class MainViewModel
{
/// The branding credit as the preview pane shows it: a master-space
/// bitmap, or null while no credit is playing. It is the SAME frame the encoder
/// composites into the recording/stream (), so what
/// the creator sees is what the viewers get — the old preview-only TextBlock lied
/// about this, and a 1080p credit that is only in the preview is not advertising
/// anyone. It cannot ride a per-source VideoImageSource: it is a global
/// overlay, like the social bar and the alert ticker.
private System.Windows.Media.Imaging.WriteableBitmap? _brandFlashBitmap;
public System.Windows.Media.Imaging.WriteableBitmap? BrandFlashImageSource
{
get => _brandFlashBitmap;
private set
{
_brandFlashBitmap = value;
OnPropertyChanged(nameof(BrandFlashImageSource));
OnPropertyChanged(nameof(BrandFlashVisible));
}
}
public bool BrandFlashVisible => _brandFlashBitmap != null;
/// The credit for the output compositor, or null when none is due. Read by
/// the frame pump every output frame; null for a premium user, always —
/// the licence check lives inside the presenter so no caller can bypass it.
public VideoFrame? BrandFlashFrame() => _brandFlash.Frame;
/// Publish one credit frame to the preview pane, UI thread only (the
/// presenter fires this from its own dispatcher tick, so the bitmap write is legal).
/// Reuses one and
/// overwrites its back buffer — a fresh 8MB bitmap per tick would churn the render
/// cache for nothing.
internal void PublishBrandFlashPreview(VideoFrame? frame)
{
if (frame == null)
{
if (_brandFlashBitmap != null) BrandFlashImageSource = null;
return;
}
if (_brandFlashBitmap == null
|| _brandFlashBitmap.PixelWidth != frame.Width
|| _brandFlashBitmap.PixelHeight != frame.Height)
{
BrandFlashImageSource = new System.Windows.Media.Imaging.WriteableBitmap(
frame.Width, frame.Height, 96, 96,
System.Windows.Media.PixelFormats.Bgra32, null);
}
var target = _brandFlashBitmap!;
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(BrandFlashImageSource));
}
}