If video effect API to draw text overlay is not enough, you can draw overlay manually in OnVideoFrameBuffer, using Bitmap and Graphics classes. The bitmap should be 32-bit (with alpha channel).
A version of code (simple) without an update of text or font on the fly:
// Image private Bitmap logoImage = null; // Image RGB32 buffer private IntPtr logoImageBuffer = IntPtr.Zero; private int logoImageBufferSize = 0; private string text1 = "Hello World"; private string text2 = "Hey-hey"; private string text3 = "Ocean of pancakes"; private void SDK_OnVideoFrameBuffer(Object sender, VideoFrameBufferEventArgs e) { // draw text to image if (logoImage == null) { logoImage = new Bitmap(e.Frame.Width, e.Frame.Height, PixelFormat.Format32bppArgb); using (var grf = Graphics.FromImage(logoImage)) { // antialiasing mode grf.TextRenderingHint = TextRenderingHint.AntiAlias; // drawing mode grf.InterpolationMode = InterpolationMode.HighQualityBicubic; // smoothing mode grf.SmoothingMode = SmoothingMode.HighQuality; // text 1 var brush1 = new SolidBrush(Color.Blue); var font1 = new Font("Arial", 30, FontStyle.Regular); grf.DrawString(text1, font1, brush1, 100, 100); // text 2 var brush2 = new SolidBrush(Color.Red); var font2 = new Font("Times New Roman", 35, FontStyle.Strikeout); grf.DrawString(text2, font2, brush2, e.Frame.Width / 2, e.Frame.Height / 2); // text 3 var brush3 = new SolidBrush(Color.Green); var font3 = new Font("Verdana", 40, FontStyle.Italic); grf.DrawString(text3, font3, brush3, 200, 200); } } // create image buffer if not allocated or have zero size if (logoImageBuffer == IntPtr.Zero || logoImageBufferSize == 0) { if (logoImageBuffer == IntPtr.Zero) { logoImageBufferSize = ImageHelper.GetStrideRGB32(logoImage.Width) * logoImage.Height; logoImageBuffer = Marshal.AllocCoTaskMem(logoImageBufferSize); } else { logoImageBufferSize = ImageHelper.GetStrideRGB32(logoImage.Width) * logoImage.Height; Marshal.FreeCoTaskMem(logoImageBuffer); logoImageBuffer = Marshal.AllocCoTaskMem(logoImageBufferSize); } ImageHelper.BitmapToIntPtr(logoImage, logoImageBuffer, logoImage.Width, logoImage.Height, PixelFormat.Format32bppArgb); } // Draw image MFP.Draw_RGB32OnRGB24(logoImageBuffer, logoImage.Width, logoImage.Height, e.Frame.Data, e.Frame.Width, e.Frame.Height, 0, 0); e.UpdateData = true; }
// Image Bitmap logoImage = null; // Image RGB32 buffer IntPtr logoImageBuffer = IntPtr.Zero; int logoImageBufferSize = 0; // text settings string text1 = "Hello World"; Font font1 = new Font("Arial", 30, FontStyle.Regular); SolidBrush brush1 = new SolidBrush(Color.Blue); string text2 = "Hey-hey"; Font font2 = new Font("Times New Roman", 35, FontStyle.Strikeout); SolidBrush brush2 = new SolidBrush(Color.Red); string text3 = "Ocean of pancakes"; Font font3 = new Font("Verdana", 40, FontStyle.Italic); SolidBrush brush3 = new SolidBrush(Color.Green); // update flag bool textUpdate = false; object textLock = new object(); // Update text overlay, index is [1..3] void UpdateText(int index, string text, Font font, SolidBrush brush) { lock (textLock) { textUpdate = true; } switch (index) { case 1: text1 = text; font1 = font; brush1 = brush; break; case 2: text2 = text; font2 = font; brush2 = brush; break; case 3: text3 = text; font3 = font; brush3 = brush; break; default: return; } } private void SDK_OnVideoFrameBuffer(Object sender, VideoFrameBufferEventArgs e) { lock (textLock) { if (textUpdate) { logoImage.Dispose(); logoImage = null; } // draw text to image if (logoImage == null) { logoImage = new Bitmap(e.Frame.Width, e.Frame.Height, PixelFormat.Format32bppArgb); using (var grf = Graphics.FromImage(logoImage)) { // antialiasing mode grf.TextRenderingHint = TextRenderingHint.AntiAlias; // drawing mode grf.InterpolationMode = InterpolationMode.HighQualityBicubic; // smoothing mode grf.SmoothingMode = SmoothingMode.HighQuality; // text 1 grf.DrawString(text1, font1, brush1, 100, 100); // text 2 grf.DrawString(text2, font2, brush2, e.Frame.Width / 2, e.Frame.Height / 2); // text 3 grf.DrawString(text3, font3, brush3, 200, 200); } } // create image buffer if not allocated or have zero size if (logoImageBuffer == IntPtr.Zero || logoImageBufferSize == 0) { if (logoImageBuffer == IntPtr.Zero) { logoImageBufferSize = ImageHelper.GetStrideRGB32(e.Frame.Width) * e.Frame.Height; logoImageBuffer = Marshal.AllocCoTaskMem(logoImageBufferSize); } else { logoImageBufferSize = ImageHelper.GetStrideRGB32(e.Frame.Width) * e.Frame.Height; Marshal.FreeCoTaskMem(logoImageBuffer); logoImageBuffer = Marshal.AllocCoTaskMem(logoImageBufferSize); } ImageHelper.BitmapToIntPtr(logoImage, logoImageBuffer, logoImage.Width, logoImage.Height, PixelFormat.Format32bppArgb); } if (textUpdate) { textUpdate = false; ImageHelper.BitmapToIntPtr(logoImage, logoImageBuffer, logoImage.Width, logoImage.Height, PixelFormat.Format32bppArgb); } // Draw image MFP.Draw_RGB32OnRGB24(logoImageBuffer, logoImage.Width, logoImage.Height, e.Frame.Data, e.Frame.Width, e.Frame.Height, 0, 0); e.UpdateData = true; } } private void btUpdateText1_Click(object sender, EventArgs e) { UpdateText(1, "Hello world", new Font("Arial", 48, FontStyle.Underline), new SolidBrush(Color.Aquamarine)); }