1.前言
上一章我们讲到了C/C++开发聊天室,主要运用的知识点是TCP
网络编程。
而本章我将再讲解一个项目的开发实现,即我们常见的视频播放器,比如腾讯、爱奇艺、优酷等等,看看这些视频播放器都是怎么开发出来的?
放心,既然将本章放到了这个,那么就请相信你目前是有能力开发的。
本文的目的也并不是非要你能够自制播放器,只是为了给你拓宽知识面,比如,如何去使用别人写好的开源库?
毕竟只有站在巨人的肩膀上我们才能走的更远。
2.VLC库介绍
让我们现在立马自己开发一个能播放视频的功能库,那明显是不现实的,因为先不说目前视频格式就一大堆,比如mp4、AVI、WMV等等等等。
就算只开发一种格式播放的播放器,如mp4,那都不是一件简单的事情。
所以这种时候,肯定第一时间想到的就是使用现成的库,而VLC
就是本章选择的视频播放器库。
这个库经过近20年的发展,目前已经是相当强悍的地步了,基本支持播放我们常见的所有视频格式。
库文件的下载地址为:这里
我这里就直接选用最新版本的库文件好了,目前最新版本的是3.0.20
。
不过由于我们是开发windows
视频播放器,所以肯定选择上面的两个,但目前已经普遍是64位电脑了,所以我这里也就直接选用win64
的:
然后我们要下载的是这个包含库文件的压缩包:
解压后,可以看到目录:
首先就是将plugins
文件夹以及下方两个动态库libvlc.dll
、libvlccore.dll
复制到我们的项目文件夹中。
然后来到sdk
文件夹中,将头文件以及库文件目录也要复制到我们的项目中:
3.库函数详解及封装
3.1 初步使用
一般在正式使用一个库前,我们还需要先学会如何使用这个库里面包含的函数,最简单的方式当然是使用控制台了。
先随便建立一个测试用的控制台项目:
然后,将上面的文件复制到当前项目中:
接着,我们还要在项目里面添加它们:
#include"include/vlc/vlc.h"
#pragma comment(lib,"lib/libvlc.lib")
#pragma comment(lib,"lib/libvlccore.lib")
int main() {
}
但这样直接运行会报错,因为vlc.h
这个头文件里面包含了很多其它头文件,它是一个vlc
所有头文件的集合:
但其使用的路径都为:vlc/...
,所以就会找不到,因为按相对路径来看,这些头文件是在include
文件夹下的vlc
文件夹中,而且这些都是使用的尖括号<>
,所以必须将vlc
文件夹添加到VS的搜索目录中。
而vlc文件夹在include
文件夹中,所以我们只需要将include
文件夹添加到当前项目属性的包含目录中即可:
这里要注意上面的配置,最好将release
与debug
都添加上为好。
因为include
目录也在vs的包含目录中,所以我们就可以使用尖括号,直接引用vlc/vlc.h
了:
#include<vlc/vlc.h>
#pragma comment(lib,"lib/libvlc.lib")
#pragma comment(lib,"lib/libvlccore.lib")
int main() {
}
但运行依旧会报错,而且还是一堆莫名其妙的错误,这就是vlc
这个库的一个小bug
:
只需要我们在vlc.h
头文件前面,添加一个定义类型就好了:
typedef long long ssize_t;
#include<vlc/vlc.h>
#pragma comment(lib,"lib/libvlc.lib")
#pragma comment(lib,"lib/libvlccore.lib")
int main() {
}
这样我们就完成了库的引入,接下来是如何使用这个库播放视频
typedef long long ssize_t;
#include<vlc/vlc.h>
#pragma comment(lib,"lib/libvlc.lib")
#pragma comment(lib,"lib/libvlccore.lib")
int main() {
libvlc_instance_t* m_instance = libvlc_new(0, NULL); //创建实例
libvlc_media_t* m_media = libvlc_media_new_location(m_instance, "file:///D:\\Program\\vlcPractice\\vlcPractice\\1.mp4"); //根据视频文件创建媒体
libvlc_media_player_t* m_player = libvlc_media_player_new_from_media(m_media); //根据媒体创建播放器
libvlc_media_player_play(m_player); //播放
getchar();
libvlc_media_player_pause(m_player); //暂停
libvlc_media_player_stop(m_player); //停止播放
libvlc_media_player_release(m_player);
libvlc_media_release(m_media);
libvlc_release(m_instance);
}
因为这个库是用C语言写的,所以看起来会很复杂,而且函数名相当长,所以后面我们肯定得进行封装,不然太难用了,这里主要理解一下它的主要使用流程即可:
- 创建实例:
libvlc_new
。 - 根据实例,以及要进行播放的视频,新建媒体实例:
libvlc_media_new_location
。 - 然后根据这个新建的媒体实例,创建播放器:
libvlc_media_player_new_from_media
。 - 然后我们就可以通过这个播放器实例,对视频进行一些操作,比如暂停、停止播放等等,使用特定的函数即可。
- 最后依次释放掉这三个实例。
这里注意,视频文件必须得是全路径,并且由于它采用的特定格式,如果你是本地的文件,那就还需要在前面添加:file:///
,这是本地协议。
如果你是网络上面的视频文件,前面就会有其它格式,直接复制即可,这个库是支持网络路径视频的。
上面之所以有个getchar
函数,目的是让程序暂停下来,否则就会一下子执行结束,看不到效果,当你按下任意一个键之后,就会继续运行下面的代码。
还有一个很重要的问题,vlc库采用的编码是utf-8
,也就是说,如果你的视频路径里面包含了中文,那么这样直接写肯定会报错打不开的,下面封装这个库的时候我会给出解决方案。
3.2 封装
CVlc.h
头文件:
#pragma once
#include<string>
typedef long long ssize_t;
#include<vlc/vlc.h>
#pragma comment(lib,"lib/libvlc.lib")
#pragma comment(lib,"lib/libvlccore.lib")
#include<Windows.h>
struct MediaSize {
int width;
int hight;
MediaSize(int _width,int _hight) {
width = _width;
hight = _hight;
}
};
class CVlc
{
private:
libvlc_instance_t* m_instance;
libvlc_media_t* m_media;
libvlc_media_player_t* m_player;
HWND m_hWnd;
private:
std::string ToUTF8(const std::wstring& str);
public:
CVlc();
~CVlc();
//加载视频媒体
bool LoadMedia(const std::wstring &path);
//设置播放窗口
void SetHWnd(HWND hWnd);
//播放视频
bool Play();
//暂停视频
bool Pause();
//停止视频
bool Stop();
//获取播放进度
float GetPosition();
//设置播放进度
void SetPosition(float pos);
//获取音量
int GetVolume();
//设置音量
void SetVolume(int volume);
//获取媒体时长(秒)
int GetLenth();
//设置播放速率
bool SetRate(float rate);
//获取媒体宽高
MediaSize GetMediaInfo();
};
CVlc.cpp
源文件:
#include "CVlc.h"
std::string CVlc::ToUTF8(const std::wstring& str)
{
int len = WideCharToMultiByte(CP_UTF8, 0, str.data(), -1, 0, 0, 0, 0);
std::string s;
s.resize(len + 1);
WideCharToMultiByte(CP_UTF8, 0, str.data(), -1, (LPSTR)s.data(), len + 1, 0, 0);
return s;
}
CVlc::CVlc()
{
m_instance = libvlc_new(0, NULL);
m_media = NULL;
m_player = NULL;
m_hWnd = NULL;
}
CVlc::~CVlc()
{
if (m_player != NULL) {
libvlc_media_player_release(m_player);
m_player = NULL;
}
if (m_media != NULL) {
libvlc_media_release(m_media);
m_media = NULL;
}
if (m_instance != NULL) {
libvlc_release(m_instance);
m_instance = NULL;
}
}
bool CVlc::LoadMedia(const std::wstring& path)
{
if (m_instance == NULL) return false;
std::string s=ToUTF8(path);
if (m_media != NULL) {
libvlc_media_release(m_media);
m_media = NULL;
}
m_media=libvlc_media_new_location(m_instance,s.data());
if (m_media == NULL) return false;
if (m_player != NULL) {
libvlc_media_player_release(m_player);
m_player = NULL;
}
m_player=libvlc_media_player_new_from_media(m_media);
if (m_player == NULL) return false;
return true;
}
void CVlc::SetHWnd(HWND hWnd)
{
m_hWnd = hWnd;
}
bool CVlc::Play()
{
if (m_player == NULL) return false;
if (m_hWnd != NULL) {
libvlc_media_player_set_hwnd(m_player, m_hWnd);