前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Windows平台RTMP播放器/RTSP播放器播放窗口添加OSD文字叠加

Windows平台RTMP播放器/RTSP播放器播放窗口添加OSD文字叠加

原创
作者头像
音视频牛哥
修改2021-03-01 18:10:50
2.6K0
修改2021-03-01 18:10:50
举报

好多开发者在做Windows平台特别是单屏多画面显示时,希望像监控摄像机一样,可以在播放画面添加OSD台标,以实现字符叠加效果,大多开发者可很轻松的实现以上效果,针对此,本文以大牛直播SDK (Github)的Windows平台demo为例,简单介绍下具体实现:

Windows平台RTMP播放器、RTSP播放器C++ demo

Windows平台C++的demo,以录像过程为例,动态在左上角显示个闪动的图标+当前时间,具体效果如下:

核心代码

代码语言:javascript
复制
std::shared_ptr<nt_argb_image_logo> CSmartPlayerDlg::MakeLogo()
{
	std::shared_ptr<nt_argb_image_logo> 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<NT_BYTE[]> buffer(new NT_BYTE[buffer_size]);

		if (buffer)
		{
			logo_image = std::make_shared<nt_argb_image_logo>(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

Windows平台C#的demo,添加了“设置台标”选择框,在player窗口左上角显示“叠加字符展示”,具体内容、坐标可自定义,具体效果如下:

核心代码

代码语言:javascript
复制
        //设置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 < 1)
            {
                NTSmartPlayerSDK.NT_SP_SetRenderARGBLogo(player_handle_, IntPtr.Zero, 0, 0, 0, 0, 0, 0, 0);
                return;
            }

            Graphics graphics = this.CreateGraphics();

            SolidBrush solid_brush = new SolidBrush(Color.FromArgb(255, 255, 255));

            graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            SizeF text_size = new SizeF();
            text_size = graphics.MeasureString(draw_text, this.Font);

            int image_w = (int)text_size.Width + 4;
            int image_h = (int)text_size.Height + 4;

            image_w = (int)ByteAlign((UInt32)image_w, 4);
            image_h = (int)ByteAlign((UInt32)image_h, 4);

            Bitmap bmp = new Bitmap(image_w, image_h, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            Graphics g = Graphics.FromImage(bmp);

            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            float left = image_w / 2 - text_size.Width / 2;
            float top = image_h / 2 - text_size.Height / 2;

            g.DrawString(draw_text, this.Font, solid_brush, left, top);

            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

            System.Drawing.Imaging.BitmapData bmp_data = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);

            IntPtr ptr = bmp_data.Scan0;
            int strdie = Math.Abs(bmp_data.Stride);

            NTSmartPlayerSDK.NT_SP_SetRenderARGBLogo(player_handle_, ptr, strdie, bmp_data.Width,
                bmp_data.Height, 6, 6, bmp_data.Width, bmp_data.Height);

            // Unlock the bits.
            bmp.UnlockBits(bmp_data);
        }
    }

注意,如果GDI模式下,我们数据回调到上层绘制的,这样加起来更简单:

代码语言:javascript
复制
            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);
            }

感兴趣的开发者可自行尝试。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Windows平台RTMP播放器、RTSP播放器C++ demo
  • 核心代码
  • Windows平台RTMP播放器、RTSP播放器C# demo
  • 核心代码
相关产品与服务
云直播
云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档