怎么在视频上叠加字幕和Logo--技术实现1

本文介绍了一种在视频渲染过程中利用DirectDraw API叠加字幕和Logo的方法。通过创建DirectDraw表面并利用GetDC获取DC,然后在DC上进行绘图。文章以Windows平台为例,演示了如何使用DirectDraw进行字幕和Logo的叠加,并提供了相应的代码流程,涉及到FFmpeg库的使用以及关键类的实现,如FileStreamReadTask、CDXDrawPainter和CMainFrame。
摘要由CSDN通过智能技术生成

 这篇文章我给大家讲解的这种字幕叠加和Logo叠加方法是在渲染视频的时候“画“上去的,其实是通过某种API将OSD和Logo绘制到显卡缓存,然后提交缓存到屏幕。我们知道渲染视频有几种常用的API:GDI,DirectDraw,D3D,OpenGL,SDL,其中SDL库是对前面几种API在不同平台上的封装,是一个大集合。我给大家演示的例子是针对Windows平台的,一般在Windows平台上我们会用DirectDraw或D3D绘制图像(不建议用GDI,因为效率低),而我写的这个叠加字幕和Logo的例子是基于DirectDraw绘图的,DirectDraw API用起来比较简单,并且效率也不错。

用本文介绍的DirectDraw API来绘制字幕和Logo(位图),实现起来并不复杂。因为DirectDraw创建的表面能通过GetDC方法获得一个DC,那么你可以往这个DC上画任何东西,就像用GDI在Windows窗口上绘图一样简单。基于DirectDraw实现,叠加字幕和叠加Logo没有太大区别,因为对显卡来说,两者都是一个图层,你可以往显卡缓存的某个坐标上输出一段字符,也可以画一个位图,只是输出字符和绘制位图调用的API有点不同。因为DirectDraw绘图对字幕叠加和位图叠加都是同样原理,所以没有必要对这两种对象的实现方式作一一介绍,下面提到的字幕叠加的实现方式跟位图叠加方式基本是一样的。

为了更清晰的给大家讲解这种方法的实现思路,我写了一个例子来演示叠加字幕和位图的效果。先亮一下这个Demo的界面:

     

这个例子具有的功能:播放视频,显示OSD文字,显示OSD图标,关闭OSD。打开视频从“文件”菜单选择一个视频文件的路径,然后按“开始播放”,视频就开始渲染到界面的窗口中。点击“编辑菜单”可以对OSD的打开关闭进行控制。

这个例子对视频的分离和解码用到FFmpeg库,而视频的显示和字幕和图标(Logo)的显示则用的是DirectDraw。

下面讲一下代码实现的流程。

因为用到FFmpeg,需要在预编译头文件引用FFmpeg的头文件和静态库:

#ifdef __cplusplus
extern "C" {
#endif 

#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif

#include "./include/libavcodec/avcodec.h"
#include "./include/libavutil/mathematics.h"
#include "./include/libavutil/avutil.h"
#include "./include/libswscale/swscale.h"
#include "./include/libavutil/fifo.h"
#include "./include/libavformat/avformat.h"
#include "./include/libavutil/opt.h"
#include "./include/libavutil/error.h"
#include "./include/libswresample/swresample.h"
#include "./include/libavutil/audio_fifo.h"
#include "./include/libavutil/time.h"
#ifdef __cplusplus
}
#endif

#pragma comment( lib, "avcodec.lib")
#pragma comment( lib, "avutil.lib")
#pragma comment( lib, "avformat.lib")
#pragma comment(lib,  "swresample.lib")
#pragma comment(lib,  "swscale.lib" )

还有要初始化FFmpeg库:

 avcodec_register_all();
 av_register_all();

程序中用到几个重要的类:

FileStreamReadTask: 这个类封装了FFmpeg对媒体文件的音视频分离,和视频解码的解码操作。并提供回调函数将解码出来的帧传到外部调用者。

CDXDrawPainter(基类是CVideoPlayer): 这个类负责渲染视频图像,以及在视频上叠加字幕和图标,支持叠加多个OSD区域,可以动态打开或关闭某个OSD图层显示。

CMainFrame: 这个主窗口界面内,负责管理各种对象,处理界面上某些Windows消息事件,菜单和按钮的响应都放在这个类里去处理。

CVideoDisplayWnd: 视频显示窗口,目前只是在OnPaint函数里用黑色画刷填充窗口背景,没有其他操作。

其中,在CMainFrame类里面定义了如下几个对象:

    FileStreamReadTask   m_FileStreamTask; //解码视频
	CDXDrawPainter       m_Painter; //用DirectDraw绘制
	CVideoDisplayWnd     m_wndView; //视频窗口类

在界面菜单上选择文件后,然后点击“开始播放”,会调用到CMainFrame的一个方法OnStartStream:

LRESULT  CMainFrame:: OnStartStream(WPARAM wParam, LPARAM lParam)
{
	if(strlen(m_szFilePath) == 0)
	{
		return 1;
	}

	int nRet = m_FileStreamTask.OpenMediaFile(m_szFilePath);
	if(nRet != 0)
	{
		MessageBox(_T("打开文件失败"), _T("提示"), MB_OK|MB_ICONERROR);
		return -1;
	}
	
	long cx, cy;
	cx = cy = 0;
	m_FileStreamTask.GetVideoSize(cx, cy); //获取视频的分辨率
	if(cx > 0 && cy > 0)
	{
		m_Painter.SetVideoWindow(m_wndView.GetSafeHwnd()); //设置视频预览窗口
		m_Painter.SetRenderSurfaceType(SURFACE_TYPE_YV12);
		m_Painter.SetSourceSize(CSize(cx, cy));
		m_Painter.Open(); //打开渲染器
	}

	m_FileStreamTask.SetVideoCaptureCB(VideoCaptureCallback);

	m_FileStreamTask.StartReadFile();

	StartTime = timeGetTime();

	m_frmCount = 0;
	m_nFPS = 0;
	m_bCapture = TRUE;

	return 0;
}

而“停止播放”触发的另外一个方法是OnStopStream,代码如下:

LRESULT  CMainFrame:: OnStopStream(WPARAM wParam, LPARAM lParam)
{
	m_FileStreamTask.StopReadFile();
    //m_Painter.Close();
	m_Painter.Stop();
	m_wndView.Invalidate(); //刷新视频窗口

	//TRACE("播放用时:%d 秒\n", (timeGetTime() - StartTime)/1000);
    m_bCapture = FALSE;
	StartTime = 0;

	return 0;
} 

在OnStartStream方法中,我们设置了视频解码后回调图像的回调函数:m_FileStreamTask.SetVideoCaptureCB(VideoCaptureCallback);

其中VideoCaptureCallback回调函数的实现代码是:

//视频图像回调
LRESULT CALLBACK VideoCaptureCallback(AVStream * input_st, enum PixelFormat pix_fmt, AVFrame *pframe, INT64 lTimeStamp)
{
	if(gpMainFrame->IsPreview())
	{
	   gpMainFrame->m_Painter.PlayAVFrame(input_st, pframe);
	}

	return 0;
}

m_Painter是CDXDrawPainter类的对象,负责渲染视频和叠加字幕,图标。回调函数中调用了m_Painter对

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值