(十四)C++自制植物大战僵尸游戏windows平台视频播放实现

植物大战僵尸游戏开发教程专栏地址icon-default.png?t=N7T8http://t.csdnimg.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:视频高度。
    • 静态成员变量 _instanceVideoPlayer类的单例对象。

VideoPlayer.cpp 

构造函数

VideoPlayer::VideoPlayer() :vlc(0), vlc_player(0), video_length(-1)
{init();
}

在构造函数中,初始化了VideoPlayer类的成员变量。具体来说:

  • vlcvlc_playervideo_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

  • 获取窗口的大小,并将宽度和高度存储在成员变量widthheight中。

  • 使用malloc()函数分配内存给videobuf,大小为(width * height) << 2字节(即每个像素占4字节)。

  • 使用memset()函数将videobuf的内存清零。

  • 使用libvlc_video_set_callbacks()函数设置视频回调函数lockunlockdisplay,以及传递nullptr作为用户数据。

  • 使用libvlc_video_set_format()函数设置视频格式为RGBA,宽度和高度为widthheight,行字节数为width << 2

  • 使用Texture2D类创建一个新的纹理对象texture,并使用initWithData()函数初始化纹理数据,包括videobuf的数据、像素格式为RGBA8888、宽度和高度为widthheight

  • 最后,调用基类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;// vertexint diff = offsetof(ccV3F_C4B_T2F, vertices);glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));// texCoodsdiff = offsetof(ccV3F_C4B_T2F, texCoords);glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));// colordiff = 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()函数用于获取当前视频的音量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/825034.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚幻引擎源码版安装下载,点击GenerateProjectFiles.bat报错 error NU1101NuGet包问题解决参考方案

开发环境配置与源码安装使用 安装VS2022 按照官方文档安装需要的vs配置 虚幻引擎源代码下载 Epic里面下载的引擎与源代码引擎区别&#xff1a;Epic里面下载的引擎是已经编译过的它的源代码访问权限不完整&#xff0c;源代码版本提供比较完整引擎代码&#xff0c;并且可以修…

MDK stm32怎么生成bin文件

第一种 D:\Keil_v5\ARM\ac5.6\bin\fromelf.exe --bin -o ../../Output/atk_f407.bin ../../Output/atk_f407.axf 空格解析 D:\Keil_v5\ARM\ac5.6\bin\fromelf.exe一个空格--bin一个空格-o两个空格../../Output/atk_f407.bin ../../Output/atk_f407.axf &#xff08;注意后…

ELK,ELFK日志收集分析系统

ELK简介 ELK是一套完整的日志集中处理解决方案&#xff0c;将ElasticSearch&#xff0c;Logstash和Kibana三个开源工具配合使用&#xff0c;实现用户对日志的查询、排序、统计需求。 ELK工作原理 在所有需要收集日志的服务器上部署Logstash&#xff0c;或者先将日志进行集中…

c# .net 香橙派 Orangepi GPIO高低电平、上升沿触发\下降沿触发 监听回调方法

c# .net 香橙派GPIO高低电平、上升沿触发\下降沿触发 监听回调方法 通过gpio readall 查看 gpio编码 这里用orangepi zero3 ,gpio= 70为例 当gpio 70 输入高电平时,触发回调 c# .net 代码 方法1: Nuget 包 System.Device.Gpio ,微软官方库对香橙派支持越来越好了,用得…

SpringBoot多数据源(二)

SpringBoot多数据源AbstractRoutingDataSource&#xff08;二&#xff09; 1.多数据源配置2.多数据源调用流程3.实现 1.多数据源配置 spring-jdbc模块提供AbstractRoutingDataSource,其内部可以包含了多个DataSource&#xff0c; 然后在运行时来动态的访问数据库 2.多数据源…

【Python系列】查看虚拟环境信息和包大小

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Java基于SpringBoot+Vue的蜗牛兼职网系统的研究与实现

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

CSS-布局

display display 属性是用于控制 布局 的最重要的 CSS 属性。display 属性规定是否/如何显示元素。 每个 HTML 元素都有一个默认的 display 值&#xff0c;具体取决于它的元素类型。大多数元素的默认 display 值为 block 或 inline。 block block&#xff1a;块级元素。块级…

越来越多服务区安装智慧公厕是什么原因

随着社会的不断发展&#xff0c;人们对生活质量的要求也越来越高。在这种背景下&#xff0c;越来越多的服务区开始安装智慧公厕&#xff0c;以满足人们在出行过程中的生活需求。那么&#xff0c;为什么越来越多的服务区选择安装智慧公厕呢&#xff1f;这其中究竟有哪些原因呢&a…

你信不信,五分钟快速学习Nginx

Nginx是什么&#xff1f; Nginx 是一个高性能的HTTP和反向代理服务器。它是由俄罗斯程序员Igor Sysoev开发的&#xff0c;最初是为了解决俄罗斯大型的门户网站的高流量问题。 说到反向代理&#xff0c;那么有没有正向代理呢&#xff1f; 正向代理&#xff1a;客户端非常明确要…

Swift Publisher 5 for mac:打造精美版面

Swift Publisher 5 for mac&#xff1a;打造精美版面 Swift Publisher 5是一款专业的版面设计和编辑工具&#xff0c;为Mac用户提供了强大的设计功能和直观的操作界面。以下是关于Swift Publisher 5的功能介绍&#xff1a; 直观易用的界面&#xff1a;用户能够轻松地使用Swift …

每日两题 / 189. 轮转数组 560. 和为 K 的子数组(LeetCode热题100)

189. 轮转数组 - 力扣&#xff08;LeetCode&#xff09; 向右轮转将使尾部k个元素顶到头部 将整个数组反转&#xff0c;再分别反转前k个元素和剩下的元素即可 class Solution { public:void rotate(vector<int>& nums, int k) {k % nums.size();reverse(nums.begi…

C# 自动填充文字内容到指定图片

目录 需求 开发运行环境 方法设计 实现代码 AddText方法 图片转Base64 调用示例 小结 需求 在我们的一些发布系统项目应用中&#xff0c;会经常发布一些链接图标&#xff0c;该图标基本上以模板背景为主&#xff0c;并填充项目文字内容。解决方式一般会让美工进行制作…

Qt 拖放功能详解:理论与实践并举的深度指南

拖放&#xff08;Drag and Drop&#xff09;作为一种直观且高效的用户交互方式&#xff0c;在现代图形用户界面中扮演着重要角色。Qt 框架提供了完善的拖放支持&#xff0c;允许开发者在应用程序中轻松实现这一功能。本篇博文将详细阐述Qt拖放机制的工作原理&#xff0c;结合详…

代码随想录阅读笔记-回溯【N皇后】

题目 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案。 每一种解法包含一个不同的 n 皇后问题 的棋子放置方案&#xff0c;该方案中 Q 和 . 分别代表…

【2024】使用Rancher管理k8s集群和创建k8s集群

Rancher管理k8s集群及创建k8s集群。 Rancher版本为:2.8.2目录 rancher管理k8s集群rancher创建k8s集群rancher管理k8s集群 使用rancher管理已经存在的k8s集群。 本部分内容需要自行准备好k8s集群及rancher平台,部署请看本人其他文章 。 登录到rancher平台后,点击集群管理,…

部署wordpress

查看别名type ll ll 是 ls -l --colorauto 的别名 设置别名alias alias ymyum install -y 使用别名ym nginx 取消别名unalias ym 基于LNMP做一个wordpress nginx mysql 5.7 PHP 7.4 1、linux基本环境 修改主机名 hostnamectl set-hostname $name 关闭防火墙及selinux …

113 如何排查 cpu 过高的业务进程

前言 又是一个面试问题, 呵呵 之前碰到的 一个 java 进程 cpu 占用率过高, 应该如何排查? 对于这种问题, 第一反应就是 jstack, pstack, 然后仔细观察多次堆栈信息结果的 重复率较高的代码 因此 我给出的思路是, 写脚本 多次 jstack 目标进程, 然后 再统计分析一下 出现频…

Stable Diffusion 模型分享:CyberRealistic XL(真实)cyberrealisticXL_v11VAE.safetensors

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八下载地址模型介绍

mybatisPlus数据字段填充

这里用到的时实体类User import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import lombok.…