植物大战僵尸游戏开发教程专栏地址http://t.****img.cn/8UFMs
VLC库
在Cocos2d-x游戏开发框架中,没有实现windows平台视频播放的功能,需要自定义实现。在本项目中使用vlc库实现windows平台的视频播放功能。
vlc官网:网址
下载完成后,找到所下载文件的sdk目录 ,里面有实现视频播放的库文件。将头文件和库文件配置到项目中,然后使用其播放视频。
代码文件位置
代码文件的位置在Class\Based文件夹中。
VideoPlayer.h
在实现的头文件中引入vlc库的头文件。
#include "Based/vlc/vlc.h"
将用到的库文件进行声明。
#pragma comment (lib, "libvlc.lib")
#pragma comment (lib, "libvlccore.lib")
定义VideoPlayer类实现视频播放,继承Sprite。
class VideoPlayer : public Sprite
{
public:
~VideoPlayer();
static VideoPlayer* instance(void);
bool init(void);
void play(const char* path);
void play();
void stop(void);
void pause(void);
void draw(Renderer* renderer, const Mat4& transform, uint32_t flags);
void changeVideoState();
void setPrecent(const float precent);
float getPrecent();
void setVolume(int volume);
int getVolume() const;
void setVideoTime(const libvlc_time_t time);
libvlc_time_t getVideoTime() const;
protected:
VideoPlayer();
private:
libvlc_instance_t* vlc;
libvlc_media_player_t* vlc_player;
libvlc_media_list_player_t* vlc_list_player;
libvlc_media_list_t* vlc_list;
libvlc_media_t* vlc_media;
libvlc_time_t video_length;
unsigned int width;
unsigned int height;
static VideoPlayer* _instance;
};
以下是
VideoPlayer
类的成员函数和成员变量:
成员函数:
- 析构函数
~VideoPlayer()
:用于销毁VideoPlayer
对象。- 静态成员函数
instance()
:返回VideoPlayer
类的单例对象。init()
:初始化视频播放器。play(const char* path)
:播放指定路径的视频。play()
:播放当前视频。stop()
:停止视频播放。pause()
:暂停视频播放。draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
:绘制函数,用于渲染视频画面。changeVideoState()
:改变视频状态。setPrecent(const float precent)
:设置视频播放进度。getPrecent()
:获取当前视频播放进度。setVolume(int volume)
:设置音量大小。getVolume() const
:获取当前音量大小。setVideoTime(const libvlc_time_t time)
:设置视频播放时间。getVideoTime() const
:获取当前视频播放时间。成员变量:
vlc
:libvlc实例。vlc_player
:libvlc媒体播放器。vlc_list_player
:libvlc媒体列表播放器。vlc_list
:libvlc媒体列表。vlc_media
:libvlc媒体。video_length
:视频长度。width
:视频宽度。height
:视频高度。- 静态成员变量
_instance
:VideoPlayer
类的单例对象。
VideoPlayer.cpp
构造函数
VideoPlayer::VideoPlayer() :
vlc(0), vlc_player(0), video_length(-1)
{
init();
}
在构造函数中,初始化了
VideoPlayer
类的成员变量。具体来说:
vlc
、vlc_player
和video_length
被初始化为0或-1。调用
init()
函数进行初始化。构造函数的主要目的是设置初始状态和准备视频播放器的环境。由于构造函数调用了
init()
函数,在init()
函数中进行了与视频播放器相关的初始化操作。
析构函数
VideoPlayer::~VideoPlayer()
{
CCSprite::~CCSprite();
free(videobuf);
libvlc_media_player_stop(vlc_player);
libvlc_media_player_release(vlc_player);
libvlc_release(vlc);
}
析构函数用于在对象销毁时执行清理操作。具体来说:
调用基类
CCSprite
的析构函数CCSprite::~CCSprite()
,以释放基类的资源。使用
free()
函数释放videobuf
的内存。调用
libvlc_media_player_stop()
函数停止视频播放。调用
libvlc_media_player_release()
函数释放视频播放器相关的资源。调用
libvlc_release()
函数释放libvlc
实例的资源。这些操作用于确保在销毁
VideoPlayer
对象时,相关的资源得到正确释放,避免内存泄漏和资源泄漏。
instance函数
VideoPlayer* VideoPlayer::instance()
{
if (_instance == nullptr)
_instance = new VideoPlayer();
return _instance;
}
这个函数实现了单例模式,用于获取
VideoPlayer
类的唯一实例。
- 首先,它检查静态成员变量
_instance
是否为空指针。- 如果
_instance
为空指针,则创建一个新的VideoPlayer
对象,并将其赋值给_instance
。- 最后,返回
_instance
指针。这样,每次调用
instance()
函数时,只会返回同一个VideoPlayer
对象的指针,确保只有一个VideoPlayer
实例存在。
init函数
bool VideoPlayer::init(void)
{
vlc = libvlc_new(0, nullptr);
vlc_player = libvlc_media_player_new(vlc);
Size size = Director::getInstance()->getWinSize();
width = size.width;
height = size.height;
videobuf = (char*)malloc((width * height) << 2);
memset(videobuf, 0, (width * height) << 2);
libvlc_video_set_callbacks(vlc_player, lock, unlock, display, nullptr);
libvlc_video_set_format(vlc_player, "RGBA", width, height, width << 2);
Texture2D* texture = new Texture2D();
texture->initWithData(videobuf, sizeof(videobuf), Texture2D::PixelFormat::RGBA8888, width, height, size);
return initWithTexture(texture);
}
该函数用于初始化视频播放器。具体来说:
调用
libvlc_new()
函数创建一个新的libvlc
实例,并将其赋值给成员变量vlc
。使用
libvlc_media_player_new()
函数创建一个新的libvlc_media_player
,并将其赋值给成员变量vlc_player
。获取窗口的大小,并将宽度和高度存储在成员变量
width
和height
中。使用
malloc()
函数分配内存给videobuf
,大小为(width * height) << 2
字节(即每个像素占4字节)。使用
memset()
函数将videobuf
的内存清零。使用
libvlc_video_set_callbacks()
函数设置视频回调函数lock
、unlock
和display
,以及传递nullptr
作为用户数据。使用
libvlc_video_set_format()
函数设置视频格式为RGBA,宽度和高度为width
和height
,行字节数为width << 2
。使用
Texture2D
类创建一个新的纹理对象texture
,并使用initWithData()
函数初始化纹理数据,包括videobuf
的数据、像素格式为RGBA8888、宽度和高度为width
和height
。最后,调用基类
initWithTexture()
函数初始化VideoPlayer
对象的纹理,并返回初始化结果。该函数的作用是设置视频播放器的初始化状态,包括创建
libvlc
实例、创建libvlc_media_player
、设置视频回调函数、设置视频格式,并初始化纹理对象。
play(path)函数
void VideoPlayer::play(const char* path)
{
vlc_list = libvlc_media_list_new(vlc);
vlc_media = libvlc_media_new_path(vlc, path);
libvlc_media_list_add_media(vlc_list, vlc_media);
vlc_list_player = libvlc_media_list_player_new(vlc);
libvlc_media_list_player_set_media_list(vlc_list_player, vlc_list);
libvlc_media_list_player_set_media_player(vlc_list_player, vlc_player);
libvlc_media_list_player_set_playback_mode(vlc_list_player, libvlc_playback_mode_loop);
libvlc_media_list_player_play(vlc_list_player);
}
该函数用于播放指定路径的视频。具体来说:
使用
libvlc_media_list_new()
函数创建一个新的libvlc_media_list
对象,并将其赋值给成员变量vlc_list
。使用
libvlc_media_new_path()
函数根据提供的路径创建一个新的libvlc_media
对象,并将其赋值给成员变量vlc_media
。使用
libvlc_media_list_add_media()
函数将vlc_media
添加到vlc_list
中。使用
libvlc_media_list_player_new()
函数创建一个新的libvlc_media_list_player
对象,并将其赋值给成员变量vlc_list_player
。使用
libvlc_media_list_player_set_media_list()
函数将vlc_list
设置为vlc_list_player
的媒体列表。使用
libvlc_media_list_player_set_media_player()
函数将vlc_player
设置为vlc_list_player
的媒体播放器。使用
libvlc_media_list_player_set_playback_mode()
函数设置vlc_list_player
的播放模式为循环播放模式。使用
libvlc_media_list_player_play()
函数开始播放vlc_list_player
中的媒体。该函数的作用是设置视频播放器的相关参数,并开始播放指定路径的视频。它使用了
libvlc
库中的函数来实现视频播放的功能。
play()、stop()、pause()函数
void VideoPlayer::play()
{
libvlc_media_player_play(vlc_player);
}
void VideoPlayer::stop(void)
{
libvlc_media_player_stop(vlc_player);
}
void VideoPlayer::pause(void)
{
libvlc_media_player_pause(vlc_player);
}
这些函数用于控制视频播放的操作。具体来说:
play()
函数调用libvlc_media_player_play()
函数,开始播放当前视频。
stop()
函数调用libvlc_media_player_stop()
函数,停止当前视频的播放。
pause()
函数调用libvlc_media_player_pause()
函数,暂停当前视频的播放。这些函数使用
libvlc
库中的函数来控制视频播放器的播放、停止和暂停操作。
draw函数
void VideoPlayer::draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
{
CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw");
CC_NODE_DRAW_SETUP();
GL::blendFunc(_blendFunc.src, _blendFunc.dst);
if (_texture != NULL)
{
GL::bindTexture2D(_texture->getName());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (uint8_t*)videobuf);
}
else
{
GL::bindTexture2D(static_cast<GLuint>(0));
}
//
// Attributes
//
GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX);
#define kQuadSize sizeof(_quad.bl)
long offset = (long)&_quad;
// vertex
int diff = offsetof(ccV3F_C4B_T2F, vertices);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));
// texCoods
diff = offsetof(ccV3F_C4B_T2F, texCoords);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));
// color
diff = offsetof(ccV3F_C4B_T2F, colors);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
CHECK_GL_ERROR_DEBUG();
CC_INCREMENT_GL_DRAWS(1);
CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw");
}
该函数用于绘制视频帧。具体来说:
使用
CC_PROFILER_START_CATEGORY()
函数开始性能分析。使用
CC_NODE_DRAW_SETUP()
函数设置绘制环境。使用
GL::blendFunc()
函数设置混合函数。如果纹理
_texture
不为空,则绑定纹理并使用glTexImage2D()
函数将视频帧数据写入纹理。如果纹理
_texture
为空,则绑定一个空的纹理。使用
GL::enableVertexAttribs()
函数启用顶点属性。计算顶点属性的偏移量,并使用
glVertexAttribPointer()
函数设置顶点属性的指针。使用
glDrawArrays()
函数绘制四边形。使用
CHECK_GL_ERROR_DEBUG()
函数检查OpenGL错误。使用
CC_INCREMENT_GL_DRAWS()
函数增加绘制计数。使用
CC_PROFILER_STOP_CATEGORY()
函数停止性能分析。该函数的作用是在OpenGL上下文中绘制视频帧。它使用了OpenGL的函数和引擎中的辅助函数来实现绘制操作。
changeVideoState函数
void VideoPlayer::changeVideoState()
{
switch (libvlc_media_get_state(vlc_media))
{
case libvlc_state_t::libvlc_Playing: pause(); break;
case libvlc_state_t::libvlc_Paused: play(); break;
default: break;
}
}
该函数用于切换视频的播放状态。具体来说:
使用
libvlc_media_get_state()
函数获取当前视频的状态。根据视频的状态进行切换操作:
- 如果视频正在播放(
libvlc_Playing
状态),则调用pause()
函数暂停视频。- 如果视频已暂停(
libvlc_Paused
状态),则调用play()
函数继续播放视频。- 对于其他状态,不执行任何操作。
该函数根据当前视频的状态来切换播放状态,从而实现暂停和继续播放的功能。它使用了
libvlc
库中的函数和VideoPlayer
类中的相应函数来控制视频的播放和暂停。
setVideoTime、getVideoTime函数
void VideoPlayer::setVideoTime(const libvlc_time_t time)
{
libvlc_media_player_set_time(vlc_player, time);
}
libvlc_time_t VideoPlayer::getVideoTime() const
{
return libvlc_media_player_get_time(vlc_player);
}
这些函数用于设置和获取视频的播放时间。具体来说:
setVideoTime()
函数调用libvlc_media_player_set_time()
函数,将指定的时间time
设置为视频播放的时间。
getVideoTime()
函数调用libvlc_media_player_get_time()
函数,返回当前视频的播放时间。这些函数使用了
libvlc
库中的函数来设置和获取视频播放器的时间信息。setVideoTime()
函数用于设置视频的播放时间,而getVideoTime()
函数用于获取当前视频的播放时间。
setPrecent、 getPrecent函数
void VideoPlayer::setPrecent(const float precent)
{
video_length < 0 ? video_length = libvlc_media_get_duration(vlc_media) : video_length;
libvlc_media_player_set_time(vlc_player, static_cast<libvlc_time_t>(video_length * precent));
}
float VideoPlayer::getPrecent()
{
auto videoCurrentTime = libvlc_media_player_get_time(vlc_player);
video_length < 0 ? video_length = libvlc_media_get_duration(vlc_media) : video_length;
if (videoCurrentTime != -1 && video_length != -1)
{
return videoCurrentTime * 1.0f / video_length * 100;
}
return -1;
}
这些函数用于设置和获取视频的播放进度百分比。具体来说:
setPrecent()
函数根据当前视频的总时长(video_length
)和传入的百分比(precent
)计算出对应的时间,然后调用libvlc_media_player_set_time()
函数将视频的播放时间设置为计算得到的时间。
getPrecent()
函数获取当前视频的播放时间(videoCurrentTime
)和总时长(video_length
),然后根据这两个值计算出播放进度的百分比。如果视频的播放时间和总时长都有效,则返回计算得到的进度百分比;否则返回-1。这些函数使用了
libvlc
库中的函数来获取视频的总时长和当前播放时间,并通过计算得到播放进度的百分比。setPrecent()
函数用于设置视频的播放进度,而getPrecent()
函数用于获取当前的播放进度百分比。
setVolume、getVolume 函数
void VideoPlayer::setVolume(int volume)
{
if (volume < 0) volume = 0;
if (volume > 100)volume = 100;
libvlc_audio_set_volume(vlc_player, volume);
}
int VideoPlayer::getVolume() const
{
return libvlc_audio_get_volume(vlc_player);
}
这些函数用于设置和获取视频的音量。具体来说:
setVolume()
函数用于设置视频的音量。它首先对音量进行范围检查,确保音量值在0到100之间。然后,使用libvlc_audio_set_volume()
函数将音量设置为指定的值。
getVolume()
函数用于获取当前视频的音量。它调用libvlc_audio_get_volume()
函数来获取当前音量值,并将其返回。这些函数使用了
libvlc
库中的函数来设置和获取视频播放器的音量信息。setVolume()
函数用于设置视频的音量,而getVolume()
函数用于获取当前视频的音量。