1)增加头文件的包含目录:
2)配置附加库目录:
2)配置附加依赖项。
1>d:\test\testvlc\testvlc\vlc\libvlc_structures.h(46): error C2146: 语法错误: 缺少“;”(在标识符“libvlc_time_t”的前面)
1>d:\test\testvlc\testvlc\vlc\libvlc_structures.h(46): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认 int
1>d:\test\testvlc\testvlc\vlc\libvlc_structures.h(46): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认 int
1>d:\test\testvlc\testvlc\vlc\libvlc_media.h(149): error C2146: 语法错误: 缺少“;”(在标识符“i_codec”的前面)
1>d:\test\testvlc\testvlc\vlc\libvlc_media.h(149): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media.h(149): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media.h(419): error C2146: 语法错误: 缺少“;”(在标识符“libvlc_media_get_duration”的前面)
1>d:\test\testvlc\testvlc\vlc\libvlc_media.h(419): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media.h(419): error C2086: “int libvlc_time_t”: 重定义
1> d:\test\testvlc\testvlc\vlc\libvlc_structures.h(46) : 参见“libvlc_time_t”的声明
1>d:\test\testvlc\testvlc\vlc\libvlc_media.h(419): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(412): error C2061: 语法错误: 标识符“uint32_t”
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(420): error C2146: 语法错误: 缺少“;”(在标识符“libvlc_media_player_get_agl”的前面)
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(420): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(420): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(436): error C2061: 语法错误: 标识符“uint32_t”
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(447): error C2146: 语法错误: 缺少“;”(在标识符“libvlc_media_player_get_xwindow”的前面)
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(447): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(447): error C2086: “int uint32_t”:重定义
1> d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(420) : 参见“uint32_t”的声明
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(447): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(613): error C2146: 语法错误: 缺少“;”(在标识符“libvlc_media_player_get_length”的前面)
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(613): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(613): error C2086: “int libvlc_time_t”: 重定义
1> d:\test\testvlc\testvlc\vlc\libvlc_structures.h(46) : 参见“libvlc_time_t”的声明
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(613): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(621): error C2146: 语法错误: 缺少“;”(在标识符“libvlc_media_player_get_time”的前面)
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(621): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(621): error C2086: “int libvlc_time_t”: 重定义
1> d:\test\testvlc\testvlc\vlc\libvlc_structures.h(46) : 参见“libvlc_time_t”的声明
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(621): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_media_player.h(630): error C2061: 语法错误: 标识符“libvlc_time_t”
1>d:\test\testvlc\testvlc\vlc\libvlc_events.h(152): error C2146: 语法错误: 缺少“;”(在标识符“new_time”的前面)
1>d:\test\testvlc\testvlc\vlc\libvlc_events.h(152): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_events.h(152): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_events.h(208): error C2146: 语法错误: 缺少“;”(在标识符“new_length”的前面)
1>d:\test\testvlc\testvlc\vlc\libvlc_events.h(208): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
1>d:\test\testvlc\testvlc\vlc\libvlc_events.h(208): error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int
此问题是因为VS老的编译器引起的,在vlc.h头文件顶部(头文件宏定义之下)中增加如下定义:
// Typedefs for old MScompilers
typedefunsigned__int32 uint32_t;
typedef __int64 int64_t;
可以解决。
以上使用vlc库的开发环境配置完毕。
这部分代码不是必须的,是为了上层应用简化封装出来的,可以使用,也可以使用,直接调用VLC提供的函数。若使用,之后再添加新的接口,需要在对应的文件里封装好就可以。
拷贝VLCWrapper.cppVLCWrapper.h VLCWrapperImpl.cpp VLCWrapperImpl.h 4个文件到工程源文件目录下,并添加CPP文件到工程里。
1)在对话框头文件中包含
#include "VLCWrapper.h"
2)在类中增加私有变量声明:
VLCWrapper vlcPlayer;
1)首先,在对话框界面上增加一个STATIC控件,用来显示播放视频,设置控件ID为IDC_STATIC1;
2)增加一个类的成员变量,用来保存打开的文件全路径名称。
private:
CString m_strVideoPathName;
3)其次,在对话框界面上增加一个BUTTON按钮,caption修改为“添加”,该按钮用来打开播放文件,该按钮的处理函数如下:
voidCtestVlcDlg::OnBnClickedButton1()
{
// TODO:在此添加控件通知处理程序代码
CFileDialogfileDlg(TRUE, _T("*.*"),"", OFN_OVERWRITEPROMPT, _T("所有文件(*.*;)|*.*||"), NULL);
//this->SetFocus();
if (IDOK == fileDlg.DoModal())
{
m_strVideoPathName= fileDlg.GetPathName();
}
}
4)增加一个BUUTON按钮,caption修改为“播放”,该按钮用来播放打开的文件,该按钮的处理函数如下,其中对路径的特殊处理是为了兼容中文路径的:
voidCtestVlcDlg::OnBnClickedButton2()
{
// TODO:在此添加控件通知处理程序代码
vlcPlayer.SetOutputWindow(GetDlgItem(IDC_STATIC1)->GetSafeHwnd());
USES_CONVERSION;
CStringWcstr_url;
cstr_url.Format(L"%s",A2W(m_strVideoPathName));
std::string str_url;
UNICODE_to_UTF8(cstr_url, str_url);
constchar*outPutUTF8FilePath =str_url.c_str();
vlcPlayer.OpenMedia(outPutUTF8FilePath);
vlcPlayer.Play();
}
voidUNICODE_to_UTF8(CStringW& unicodeString, std::string& str)
{
int stringLength =::WideCharToMultiByte(CP_UTF8, NULL, unicodeString, wcslen(unicodeString),NULL, 0, NULL, NULL);
char* buffer =newchar[stringLength + 1];
::WideCharToMultiByte(CP_UTF8, NULL, unicodeString,wcslen(unicodeString), buffer, stringLength, NULL, NULL);
buffer[stringLength] = '\0';
str = buffer;
delete[] buffer;
}
5)增加一个BUTTON按钮, caption改为"停止",该按钮是用来实现停止视频播放的;该按钮的处理函数如下:
voidCtestVlcDlg::OnBnClickedButton3()
{
// TODO:在此添加控件通知处理程序代码
vlcPlayer.Stop();
}
6)考虑到正在播放时,关闭对话框的场景,需要在对话框关闭时先停止播放。
点击对话框属性,增加对WM_DESTROY消息的处理函数,在函数中增加VLC播放器的停止操作。
voidCtestVlcDlg::OnDestroy()
{
CDialog::OnDestroy();
vlcPlayer.Stop();
}
以上简单的就具有了简单的播放功能,下边增加进度条显示、播放时间显示。
1) 在对话框增加一个Slider control控件,添加控制变量m_sliderCtrl;
2) 增加一个STATIC控件,修改ID为IDC_STATIC2;
3) 在类声明中增加三个私有变量,用来控制进度条显示:
int m_nMax;
int m_nMin;
int m_nPos;
4) 增加函数,初始化slider的控制变量:
voidCtestVlcDlg::SliderInit()
{
m_nMin= 0;
m_nMax= 100;
m_nPos= 0;
m_sliderCtrl.SetRange(m_nMin,m_nMax );
m_sliderCtrl.SetPos(m_nPos);
vlcPlayer.SetTime(0);
}
在点击播放时先调用这个函数初始化进度条,函数变为:
oidCtestVlcDlg::OnBnClickedButton2()
{
// TODO:在此添加控件通知处理程序代码
vlcPlayer.SetOutputWindow(GetDlgItem(IDC_STATIC1)->GetSafeHwnd());
SliderInit();
USES_CONVERSION;
CStringWcstr_url;
cstr_url.Format(L"%s",A2W(m_strVideoPathName));
std::string str_url;
UNICODE_to_UTF8(cstr_url, str_url);
constchar*outPutUTF8FilePath =str_url.c_str();
vlcPlayer.OpenMedia(outPutUTF8FilePath);
vlcPlayer.Play();
}
4)要控制进度条显示,还需要增加VLC播放器的事件回调函数处理VLC播放器播放时间变化事件,处理函数如下;
staticvoid HandleVLCEvents(constVLCEvent* pEvt,void* pUserData)
{
CtestVlcDlg*pDlg = reinterpret_cast
switch(pEvt->type)
{
case libvlc_MediaPlayerTimeChanged:
{
if (pDlg != NULL)
{
pDlg->UpdatePosition();
}
break;
}
default:
{
break;
}
}
}
voidCtestVlcDlg::UpdatePosition()
{
int64_tm_videoLen = vlcPlayer.GetLength();
int64_tnewPosition = vlcPlayer.GetTime();
CTimeSpanlength(static_cast
CTimeSpanactualPosition(static_cast
CStringlengthString;
lengthString.Format(_T("[%02d:%02d:%02d/%02d:%02d:%02d]"),
actualPosition.GetHours(),actualPosition.GetMinutes(), actualPosition.GetSeconds(),
length.GetHours(),length.GetMinutes(), length.GetSeconds());
GetDlgItem(IDC_STATIC2)->SetWindowText(lengthString);
int newSliderPos = m_videoLen ?static_cast<int>((static_cast<double>(newPosition)/static_cast<double>(m_videoLen)* 100)) : 0;
m_sliderCtrl.SetPos(newSliderPos);
} 在点击播放按钮时把回调函数挂接上去,于是播放按钮的代码变为:
voidCtestVlcDlg::OnBnClickedButton2()
{
// TODO:在此添加控件通知处理程序代码
vlcPlayer.SetOutputWindow(GetDlgItem(IDC_STATIC1)->GetSafeHwnd());
vlcPlayer.SetEventHandler(&HandleVLCEvents,this);
SliderInit();
USES_CONVERSION;
CStringWcstr_url;
cstr_url.Format(L"%s",A2W(m_strVideoPathName));
std::string str_url;
UNICODE_to_UTF8(cstr_url, str_url);
constchar*outPutUTF8FilePath =str_url.c_str();
vlcPlayer.OpenMedia(outPutUTF8FilePath);
vlcPlayer.Play();
}
5)在停止按钮中也要增加对进度条的处理,增加后,按钮3的处理函数变为:
voidCtestVlcDlg::OnBnClickedButton3()
{
// TODO:在此添加控件通知处理程序代码
vlcPlayer.Stop();
SliderInit();
GetDlgItem(IDC_STATIC2)->SetWindowText("00:00:00/00:00:00");
}
至此,进度条添加完成。
1)在对话框上增加一个按钮,caption改为“暂停”,按钮的处理函数如下:
voidCtestVlcDlg::OnBnClickedButton4()
{
vlcPlayer.Pause();
}
在对话框界面上增加一个按钮,caption改为“快进”。
快进按钮功能:点击一下双倍,再点击回到正常播放速度。
在类的声明里增加变量bool bFastRate,用来记录当前是否在快进状态。
在类的构造函数中初始化该变量为false;
CtestVlcDlg::CtestVlcDlg(CWnd* pParent/*=NULL*/)
:CDialog(CtestVlcDlg::IDD, pParent)
{
m_bFastRate= false;
m_hIcon= AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
按钮的处理函数如下:
voidCtestVlcDlg::OnBnClickedButton5()
{
float fRate = 0.0;
if (m_bFastRate)
{
fRate = 1.0;
vlcPlayer.SetRate(fRate);
m_bFastRate = false;
}
else
{
fRate = 2.0;
vlcPlayer.SetRate(fRate);
m_bFastRate = true;
}
}
在对话框上增加一个BUTTON按钮,按钮的caption修改为"抓图",抓图功能会阻塞进程,所以需要启动一个进程实现抓图,在抓图完成后会发送抓图成功消息。
在类的声明里新增一个变量,用来保存抓图文件存储的路径全名。
CStringm_strSnapShotPath;
按钮的处理函数如下:
voidCtestVlcDlg::OnBnClickedButton6()
{
TCHARszFilter[] = _T("*.jpg|所有文件(*.*)|*.*||");
CFileDialogfileDlg(FALSE, _T("*.jpg"),"", OFN_HIDEREADONLY |OFN_OVERWRITEPROMPT, szFilter,this);
//this->SetFocus();
if (IDOK == fileDlg.DoModal())
{
//如果点击了文件对话框上的“保存”按钮,则将选择的文件路径显示到编辑框里
m_strSnapShotPath= fileDlg.GetPathName();
}
AfxBeginThread(&TakeSnapThread,this);
}
UINT CtestVlcDlg::TakeSnapThread(void *param)
{
CtestVlcDlg*pDialog = (CtestVlcDlg*)param;
std::stringstrVideoPathName =pDialog->m_strSnapShotPath;
constchar*char_url=strVideoPathName.c_str();
pDialog->vlcPlayer.SnapShot(0,char_url, 0, 0);
return 0;
}
因为在接收到VLC播放器的播放进度变更消息时,系统会进行进度条的进度显示。此时需要通过拖拉进度条实现播放点的设置,若两个同时存在,会在拖拉过程中,进度条被刷新回播放的位置。因此在实现的时候需要考虑在拖拉过程中禁止通过消息处理函数设置进度条的位置。
此处需要从CSliderCtrl继承一个新的类,实现左键按下和释放的处理,在按下和释放的函数中增加一个全局变量,用来表明正在进行拖动处理,在该值为fasle时,接收到VLC播放器的位置更新消息才能进行进度条控制。
1) CSliderCtrl的继承类CMySliderCtrl的代码如下,其中bSliderLButtonDown为控制变量,在对话框文件中使用:
头文件:
#pragmaonce
#include"afxcmn.h"
classCMySliderCtrl :
public CSliderCtrl
{
public:
CMySliderCtrl(void);
~CMySliderCtrl(void);
afx_msgvoid OnLButtonDown(UINT nFlags, CPoint point);
afx_msgvoid OnLButtonUp(UINT nFlags, CPoint point);
protected:
DECLARE_MESSAGE_MAP()
};
源代码文件:
#include"StdAfx.h"
#include"MySliderCtrl.h"
boolg_bSliderLButtonDown =false;
BEGIN_MESSAGE_MAP(CMySliderCtrl,CSliderCtrl)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
CMySliderCtrl::CMySliderCtrl(void)
{
CSliderCtrl::CSliderCtrl();
}
CMySliderCtrl::~CMySliderCtrl(void)
{
CSliderCtrl::~CSliderCtrl();
}
voidCMySliderCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
g_bSliderLButtonDown= true;
CSliderCtrl::OnLButtonDown(nFlags,point);
}
voidCMySliderCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
g_bSliderLButtonDown= false;
CSliderCtrl::OnLButtonUp(nFlags,point);
}
2)对话框源文件中的UpdatePosition函数更新如下:
voidCtestVlcDlg::UpdatePosition()
{
if (!g_bSliderLButtonDown)
{
int64_tm_videoLen = vlcPlayer.GetLength();
int64_tnewPosition = vlcPlayer.GetTime();
CTimeSpanlength(static_cast
CTimeSpanactualPosition(static_cast
CStringlengthString;
lengthString.Format(_T("[%02d:%02d:%02d/%02d:%02d:%02d]"),
actualPosition.GetHours(),actualPosition.GetMinutes(), actualPosition.GetSeconds(),
length.GetHours(),length.GetMinutes(), length.GetSeconds());
GetDlgItem(IDC_STATIC2)->SetWindowText(lengthString);
int newSliderPos = m_videoLen ?static_cast<int>((static_cast<double>(newPosition)/static_cast<double>(m_videoLen)* 100)) : 0;
m_sliderCtrl.SetPos(newSliderPos);
}
else
{
}
}
3)在对话框属性中,添加WM_HSCROLL的处理函数,用来处理滚动条滚动事件,在事件中设置播放进度:
voidCtestVlcDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if(pScrollBar->GetSafeHwnd() == m_sliderCtrl.GetSafeHwnd()){
float posf=0.0;
if(nSBCode==SB_THUMBPOSITION){
posf=(float)nPos/100.0;
vlcPlayer.SetPos(posf);
}
}
CDialog::OnHScroll(nSBCode,nPos, pScrollBar);
}
4)注意,这样的滚动条适合无压缩的原始数据,对于压缩的数据,因为滚动条可能会拖到非关键帧上,会造成视频花屏,需要在解码中进行特殊处理,丢掉非关键帧之前的数据,从关键帧开始播放。解决方法,下篇文章会详细说明。