(十四)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;

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何配置Postgres的自动扩展功能以应对数据增长

文章目录 解决方案1. 表空间管理2. 分区表3. 自动扩展配置4. 监控和告警5. 使用外部工具和服务 示例代码示例1&#xff1a;创建表空间示例2&#xff1a;创建分区表示例3&#xff1a;调整配置参数示例4&#xff1a;使用监控和告警工具 总结 在PostgreSQL中&#xff0c;随着数据的…

Spring Boot:Web应用开发之登录与退出的实现

Spring Boot 前言实现登录功能配置拦截器 实现退出功能 前言 登录与退出功能作为 Web 应用中的基础且重要的组成部分&#xff0c;直接关系到用户的安全和隐私保护。通过实现登录与退出功能&#xff0c;可以对用户的身份进行验证和授权&#xff0c;确保只有合法的用户才能访问特…

吃鸡游戏msvcp140.dll丢失的解决方法

msvcp140.dll 是一个与 Microsoft Visual C Redistributable 相关的动态链接库&#xff08;DLL&#xff09;文件&#xff0c;是 Windows 操作系统中众多应用程序正常运行所必需的关键组件之一。以下是对 msvcp140.dll 文件的总体介绍和msvcp140.dll丢失的多个解决方案分享。 *…

Java项目实现Excel导出(Hutool)

官网&#xff1a; Excel生成-ExcelWriter (hutool.cn) 1.使用Hutool工具实现Excel导出&#xff08;.xlsx格式&#xff09; 业务场景&#xff1a; 使用SpringCloudmysqlmybatis-plus需要将数据库中的数据导出到Excel文件中 前端为Vue2 第零步&#xff1a;导入依赖 <!-…

NPL预训练模型-GPT-3

简介及特点 GPT-3是一个由OpenAI开发的自然语言处理&#xff08;NLP&#xff09;预训练模型&#xff0c;它是生成式预训练变换器&#xff08;Generative Pretrained Transformer&#xff09;系列的第三代模型。GPT-3以其巨大的规模和强大的语言处理能力而闻名&#xff0c;具有…

快速上手Linux核心命令

Linux 的重要性不用我多说了吧&#xff0c;大多数互联网公司&#xff0c;服务器都是采用的Linux操作系统 Linux是一个主要通过命令行来进行管理的操作系统。 只有熟练掌握Linux核心命令&#xff0c;在使用起来我们才会得心应手 这里给大家整理了Linux一些核心命令&#xff0…

游戏、app抓包

文章目录 协议app抓包游戏抓包 协议 在抓包之前&#xff0c;首先我们要对每个程序使用什么协议有个大致的了解&#xff0c;比如网页这种就是走的http协议。 在一些app中我们通过发送一个请求&#xff0c;然后服务器接受&#xff0c;响应&#xff0c;返回一个数据包&#xff0c…

数字人解决方案——EMAGE面部加肢体动画实现从音频生成数字人表情与动作

概述 AI数字人面部与肢体的驱动算法是数字人研发中至关重要的一环&#xff0c;它能够有效降低VR Chat、虚拟直播和游戏NPC等应用场景中的成本。随着技术的发展&#xff0c;基于语音的面部、肢体和手部动作生成模型已经逐步成熟并得到广泛应用。然而&#xff0c;当尝试将这些独…

反激电源——TL431及光耦反馈电路计算(不涉及环路补偿)

一、TL431及光耦反馈电路 TL431以及光耦电路是反激的副边反馈类型电路中的常见应用。 其反馈工作原理为&#xff1a;当副边的输出电压升高时&#xff0c;TL431的REF点采样电压也会升高&#xff0c;使得TL431的导通量增加&#xff0c;同时光耦内部的发光二极管流过的电流也增大&…

C++11 数据结构3 线性表的循环链式存储,实现,测试

上一节课&#xff0c;我们学了线性表 单向存储结构&#xff08;也就是单链表&#xff09;&#xff0c;这个是企业常用的技术&#xff0c;且是后面各种的基本&#xff0c;一定要牢牢掌握&#xff0c;如果没有掌握&#xff0c;下面的课程会云里雾里。 一 &#xff0c;循环链表 1…

遥测终端赋能水库泄洪监测预警,筑牢度汛安全防线!

4月10日&#xff0c;水利部召开水库安全度汛视频会议。会议要求着力强化水库防洪“四预”措施&#xff0c;加快构建雨水情监测预报“三道防线”&#xff0c;完善预警信息发布机制&#xff0c;推进数字孪生水利工程建设&#xff0c;为科学调度指挥决策提供支持。强调坚决牢牢守住…

基于3D点云的散货库存体积计算

首先&#xff0c;你需要散货库存的点云。 我将使用 IntelRealSense 捕获的散货库存的 .ply文件。 然而&#xff0c;任何其他产生点云的成像技术都同样有效。 点击这里查看本教程的 Github 上的代码。 NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - …

二叉树的中序遍历 - LeetCode 热题 36

大家好&#xff01;我是曾续缘&#x1f603; 今天是《LeetCode 热题 100》系列 发车第 36 天 二叉树第 1 题 ❤️点赞 &#x1f44d; 收藏 ⭐再看&#xff0c;养成习惯 二叉树的中序遍历 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输…

爬楼梯(c)

文章目录 描述分析思路关键代码运行结果 描述 给定一个整数数组 cost &#xff0c;其中 cost[i]是从楼梯第i 个台阶向上爬需要支付的费用&#xff0c;下标从0开始。-旦你支付此费用&#xff0c;即可选择向上爬一个或者两个台阶 要求&#xff1a;请你计算并返回达到楼梯顶部的…

4.17

while(1) { HAL_ADC_Start(&hadc); adcVal HAL_ADC_GetValue(&hadc); TIM3->CCR3 adcVal-2000; } 1.总结串口的发送和接收功能使用到的函数 HAL_UART_Transmit_DMA(&huart1,"hello world",strlen("hello world")); HAL_UART_Tr…

Linux:如何删除指定时间之前修改的文件?

1、与文件有关的时间 在说明如何删除符合这种要求的文件之前&#xff0c;先来看看与文件有关的有哪些时间 简名全名中文名含义atimeaccess time访问时间文件中的数据最后被访问的时间mtimemodify time修改时间文件中的数据最后被修改的时间ctime change time变化时间文件的元…

JavaSE高阶篇-IO流

第一部分 file类 1&#xff09;File类 计算机常识: 1.名字为".jpg"的一定是图片吗? 不一定,有可能是文件夹 2.什么叫做文本文档: 用记事本打开,人能看懂的文件 比如:.txt .html .css等 .doc -> 不是 …

如何安装 IntelliJ IDEA 最新版本——详细教程

IntelliJ IDEA 简称 IDEA&#xff0c;被业界公认为最好的 Java 集成开发工具&#xff0c;尤其在智能代码助手、代码自动提示、代码重构、代码版本管理(Git、SVN、Maven)、单元测试、代码分析等方面有着亮眼的发挥。IDEA 产于捷克&#xff0c;开发人员以严谨著称的东欧程序员为主…

vscode 搭建stm32开发环境记录(eide+cortex-debug+jlink)

前言 clion使用的快过期了&#xff0c;所以就准备使用vscode 来代替clion作为代码开发环境 vscode 插件安装 创建个空白工程 添加项目相关的源文件&#xff0c;和配置宏定义和头文件目录 编译和烧录(ok) 结合cortex-debug 结果(测试ok)

数据可视化-ECharts Html项目实战(13)

在之前的文章中&#xff0c;我们深入学习ECharts动态主题切换和自定义ECharts主题。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢。 数据可视化-ECharts Html项…