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

news2024/11/29 2:38:53

植物大战僵尸游戏开发教程专栏地址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;

    // 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()函数用于获取当前视频的音量。

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

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

相关文章

.net反射(Reflection)

文章目录 一.概念&#xff1a;二.反射的作用&#xff1a;三.代码案例&#xff1a;四.运行结果&#xff1a; 一.概念&#xff1a; .NET 反射&#xff08;Reflection&#xff09;是指在运行时动态地检查、访问和修改程序集中的类型、成员和对象的能力。通过反射&#xff0c;你可…

分布式搭载博客网站

一.运行环境&#xff1a; IP主机名系统服务192.168.118.128Server-WebLinuxWeb192.168.118.131Server-NFS-DNSLinuxNFS/DNS 二.基础配置 1. 配置主机名&#xff0c;hosts映射 [rootserver ~]# hostnamectl set-hostname Server-Web [rootserver ~]# hostname Server-Web [r…

每日算法4/17

1552. 两球之间的磁力 题目 在代号为 C-137 的地球上&#xff0c;Rick 发现如果他将两个球放在他新发明的篮子里&#xff0c;它们之间会形成特殊形式的磁力。Rick 有 n 个空的篮子&#xff0c;第 i 个篮子的位置在 position[i] &#xff0c;Morty 想把 m 个球放到这些篮子里&…

目标检测——行人交通信号灯数据集

一、重要性及意义 行人交通信号灯检测的重要性及意义主要体现在以下几个方面&#xff1a; 首先&#xff0c;行人交通信号灯检测对于提高道路安全性至关重要。通过准确识别交通信号灯的状态&#xff0c;行人可以更加清晰地了解何时可以安全地过马路&#xff0c;从而避免与车辆…

《ElementPlus 与 ElementUI 差异集合》el-popconfirm 气泡确认框之插槽写法有差异

ElementUI 直接在 el-button 上配置属性 slot&#xff1b; <el-popconfirm title"确定删除吗&#xff1f;请谨慎操作&#xff01;" confirm"delete"><el-button slot"reference" size"small" type"danger">删…

C++stack oj题目详解

1. 最小栈 155. 最小栈 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void pop() 删除堆栈顶部的元素。 int top() 获取…

【Git】git命令大全(持续更新)

本文架构 0.描述git简介术语 1.常用命令2. 信息管理新建git库命令更改存在库设置获取当前库信息 3.工作空间相关将工作空间文件添加到缓存区&#xff08;增&#xff09;从工作空间中移除文件&#xff08;删&#xff09;撤销提交 4.远程仓库相关同步远程仓库分支 &#xff08;持…

IP爬虫代理服务器是什么以及为什么使用爬虫代理?

在网络抓取领域&#xff0c;爬虫代理发挥着关键作用。 但它们到底是什么&#xff1f; 从本质上讲&#xff0c;爬虫代理是位于网络抓取工具和目标网站之间的中间服务器。 该中间服务器充当盾牌&#xff0c;提供匿名性&#xff0c;并允许您访问网站并提取数据&#xff0c;而无需透…

Unity应用开机自启动

使用说明 以代码设置的方式设置Unity应用开机自启动。 将下面脚本挂载到场景物体&#xff0c;通过UI按钮开启应用自启动和取消应用自启动&#xff0c;设置下次运行应用生效。 所用到的Dll下载地址&#xff1a;Interop.IWshRuntimeLibrary 脚本代码 using System; using Syst…

考研数学|「基础」和「强化」阶段分别怎么做?

从目前考研数学的趋势来看&#xff0c;更加注重数学基础的理解和计算量。也就是基础知识和计算&#xff0c;如何锻炼这两种能力就显得尤为重要。希望我的复习经验可以给到读者一些启发。 数学规划 从备考过程来看&#xff0c;数学的复习可以分为三个阶段&#xff1a;1、基础阶…

社区论坛小圈子小程序源码系统:自定义小程序管理社区圈子软件圈子系统系统开发 - 做社区圈子

制作阶段 1.确定需求&#xff1a;首先&#xff0c;要明确小程序的功能需求。例如&#xff0c;用户注册、登录、发表动态、浏览动态、评论、点赞等。同时&#xff0c;要确定页面的布局和设计风格。 2.设计界面&#xff1a;根据需求&#xff0c;进行界面设计。包括首页、个人中…

Android开发——实现简易登录功能

登录界面&#xff08;mainActivity.xml) <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent" android:layout_height&…

动手写sql 《牛客网80道sql》

第1章&#xff1a;SQL编写基础逻辑和常见问题 基础逻辑 SELECT语句: 选择数据表中的列。FROM语句: 指定查询将要从哪个表中检索数据。WHERE语句: 过滤条件&#xff0c;用于提取满足特定条件的记录。GROUP BY语句: 对结果进行分组。HAVING语句: 对分组后的结果进行条件过滤。O…

TRIZ理论下攀爬机器人的创新设计与研究

随着科技的飞速发展&#xff0c;机器人技术已广泛应用于各个领域。特别是在复杂环境下的作业&#xff0c;如灾难救援、太空探测等&#xff0c;对机器人的移动能力和适应性提出了更高要求。在这样的背景下&#xff0c;基于TRIZ理论的攀爬机器人设计与研究应运而生&#xff0c;它…

.net9 AOT编绎生成标准DLL,输出API函数教程-中国首创

1&#xff0c;安装VS2022预览版&#xff08;Visual Studio Preview&#xff09; https://visualstudio.microsoft.com/zh-hans/vs/preview/#download-preview 2&#xff0c;选择安装组件&#xff1a;使用C的桌面开发 和 .NET桌面开发 ------------------------------------- …

ElasticSearch有账号密码时: kibana配置

上一篇文章我们介绍过ElasticSearch关闭账号密码的的方式&#xff1a; config/elasticsearch.yml文件中 xpack.security.enabled: false 当我们关闭 账号密码&#xff0c;kibana是可以直接访问ElasticSearch的。 真实项目中&#xff0c;我们是不允许数据库裸跑的&#xff0c;所…

Windows平台下的Oracle 19c补丁升级

Windows平台下的Oracle 19c补丁升级 文章目录 Windows平台下的Oracle 19c补丁升级第一章 概述第二章 安装前备份2.1 软件目录备份2.2 权限备份2.3 备份数据库 第三章 安装前检查3.1 查看数据库版本3.2 升级opatch版本 第四章 安装补丁4.1 设置环境变量4.2 关闭oracle相关服务4.…

【R语言】概率密度图

概率密度图是用来表示连续型数据的分布情况的一种图形化方法。它通过在数据的取值范围内绘制一条曲线来描述数据的分布情况&#xff0c;曲线下的面积代表了在该范围内观察到某一数值的概率。具体来说&#xff0c;对于给定的连续型数据&#xff0c;概率密度图会使用核密度估计&a…

工业级3D可视化工具HOOPS Visualize, 快速构建移动端和PC端工程应用程序!

HOOPS Visualize是一款强大的工业级3D渲染引擎&#xff0c;帮助您打造出众的工程应用程序。HOOPS Visualize的基石是图形内核&#xff0c;这是一种全功能的&#xff0c;以工程为重点的场景图技术&#xff0c;我们称为Core Graphics。Core Graphics集成到一个框架中&#xff0c;…

保护视力,从 CareUEyes 开始 —— 你的电脑护眼小助手

在数字化时代&#xff0c;我们的眼睛比以往任何时候都更频繁地面对屏幕。长时间盯着电脑工作&#xff0c;不仅影响视力&#xff0c;还可能导致眼疲劳和不适。今天&#xff0c;我要向大家推荐一款专为电脑用户设计的护眼软件——CareUEyes。 CareUEyes&#xff1a;你的视力守护者…