在windows平台上,许多开发者在开发单屏多画面显示功能时,期望像监控摄像机一样,能够在播放画面中添加osd台标,以实现字符叠加效果。大多数开发者可以轻松实现这种效果。本文将以大牛直播sdk(github)在windows平台上的demo为例,简要介绍具体实现方法:
Windows平台RTMP播放器和RTSP播放器的C++ demo,以录像过程为例,动态在左上角显示一个闪动的图标以及当前时间,具体效果如下:

核心代码如下:
std::shared_ptrCSmartPlayerDlg::MakeLogo(){ std::shared_ptr logo_image; if (!is_init_gdi_plus_ok_) return logo_image; if (!recoder_image_){ static bool is_load_image_failed = false; if (!is_load_image_failed){ recoder_image_.reset(Gdiplus::Image::FromFile(_T("red_circle.png"))); if (recoder_image_ && Gdiplus::Ok != recoder_image_->GetLastStatus()){ is_load_image_failed = true; recoder_image_.reset(); } } } is_has_recoder_image_ = !is_has_recoder_image_; if (!recoder_image_){ is_has_recoder_image_ = false; } if (m_hWnd == nullptr || !::IsWindow(m_hWnd)) return logo_image; if (cur_logo_font_name_.empty()){ cur_logo_font_name_ = FindLogoFontName(); } if (cur_logo_font_name_.empty()){ return logo_image; } Gdiplus::FontFamily font_family(cur_logo_font_name_.c_str()); if (!font_family.IsAvailable()){ return logo_image; } Gdiplus::Font font(&font_family, 10, Gdiplus::FontStyleBold, Gdiplus::Unit::UnitPoint); if (!font.IsAvailable()){ return logo_image; } // 白色 Gdiplus::SolidBrush solid_brush(Gdiplus::Color(255, 255, 255)); Gdiplus::Graphics graphics(m_hWnd); if (Gdiplus::Ok != graphics.GetLastStatus()){ return logo_image; } int recoder_image_w = 18; int recoder_image_h = 18; if (recoder_image_){ recoder_image_w = recoder_image_->GetWidth(); recoder_image_h = recoder_image_->GetHeight(); } auto image_w = recoder_image_w + 2 + 5; auto image_h = recoder_image_h + 5 + 5; graphics.SetTextRenderingHint(Gdiplus::TextRenderingHint::TextRenderingHintClearTypeGridFit); auto cur_time_str = MakeCurTimerStr(); Gdiplus::RectF bounding_box(0, 0, 0, 0); graphics.MeasureString(cur_time_str.c_str(), -1, &font, Gdiplus::PointF(0, 0), &bounding_box); Gdiplus::SizeF text_size(0, 0); bounding_box.GetSize(&text_size); image_w += (int)text_size.Width; image_h = image_h > ((int)text_size.Height) ? image_h : ((int)text_size.Height); image_w += 2; image_h += 2; image_w = ByteAlign(image_w, 4); image_h = ByteAlign(image_h, 4); Gdiplus::Bitmap bitmap(image_w, image_h, PixelFormat32bppARGB); if (Gdiplus::Ok != bitmap.GetLastStatus()){ return logo_image; } Gdiplus::Graphics g(&bitmap); if (Gdiplus::Ok != g.GetLastStatus()){ return logo_image; } int r_left = 2; int r_top = (image_h / 2) - (recoder_image_h / 2); r_top -= 1; if (is_has_recoder_image_){ g.DrawImage(recoder_image_.get(), r_left, r_top); } r_left += recoder_image_w; r_left += 5; r_top = (image_h / 2) - (text_size.Height / 2); g.DrawString(cur_time_str.c_str(), -1, &font, Gdiplus::PointF(r_left, r_top), &solid_brush); Gdiplus::BitmapData locked_bitmapData; if (Gdiplus::Ok == bitmap.LockBits(nullptr, Gdiplus::ImageLockModeRead, PixelFormat32bppARGB, &locked_bitmapData)){ auto buffer_size = locked_bitmapData.Stride * locked_bitmapData.Height; std::unique_ptr buffer(new NT_BYTE[buffer_size]); if (buffer){ logo_image = std::make_shared (locked_bitmapData.Width, locked_bitmapData.Height); logo_image->stride_ = locked_bitmapData.Stride; memcpy(buffer.get(), locked_bitmapData.Scan0, buffer_size); logo_image->data_.swap(buffer); } bitmap.UnlockBits(&locked_bitmapData); } return logo_image; }
Windows平台RTMP播放器和RTSP播放器的C# demo,增加了“设置台标”选择框,在player窗口左上角显示“叠加字符展示”,具体内容和坐标可以自定义,具体效果如下:

核心代码如下:
//设置OSD文本
private void DrawOSD(string draw_text)
{
// 如果是GDI渲染,文本需要自己绘制
if (is_gdi_render_)
return;
if (player_handle_ == IntPtr.Zero)
return;
if (draw_text == null || draw_text.Length == 0)
return;
// 在此处添加绘制OSD文本的逻辑
}
需要注意的是,如果在GDI模式下,我们可以通过数据回调到上层进行绘制,这样实现起来会更加简单:
if (btn_check_add_osd.Checked)
{
string draw_text = "叠加字符展示";
Graphics graphics = this.CreateGraphics();
SolidBrush solid_brush = new SolidBrush(Color.FromArgb(255, 255, 255));
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
float left = playWnd.Left + 4;
float top = playWnd.Top + 4;
g.DrawString(draw_text, this.Font, solid_brush, left, top);
}对这方面感兴趣的开发者可以自行尝试。











