Cocos2d-x VLC Player_cocos vlc-程序员宅基地

技术标签: cocos2d-x  Cocos2d-x  windows  

        由于项目需要用到动态的背景,测试发现,如果用帧序列动画将占用超过1G的内存,而CPU的利用率则一直保持在5%左右,所以想到将动态效果做成视频,循环播放,以作为背景之用。查询之下发现cocos2d-x本身带有一个叫做VideoPlayer的类,但是很可惜,它们只能用在移动平台上,而笔者的项目是基于Windows平台的,所以便在网上搜索实现方法,最终利用VLC Player实现了所需的效果。
        首先需要下载VLC Player播放器,安装之后可以在安装目录下的SDK文件夹内找到头文件、lib、dll。
        其实原理也很简单,就是利用VLC从视频中提取数据流,然后打入buffer中,然后以buffer作为纹理绘制整个画面,代码如下:
#include "VLCPlayer.h"

USING_NS_CC;

void *lock(void *data, void **p_pixels)
{
    auto player = static_cast
    
    
     
     (data);
    *p_pixels = player->m_videobuf;
    return NULL;
}

void unlock(void *data, void *id, void *const *p_pixels)
{
    assert(id == NULL);
}

void display(void *data, void *id)
{
    auto player = static_cast
     
     
      
      (data);
    player->m_readyToShow = true;
    assert(id == NULL);
}

void endReached(const struct libvlc_event_t *event, void *data)
{
    if (libvlc_MediaPlayerEndReached == event->type)
    {
        VLCPlayer *self = (VLCPlayer *)data;
        self->m_isEndReached = true;
    }
}

VLCPlayer::~VLCPlayer()
{
    libvlc_media_player_stop(vlc_player);
    libvlc_media_player_release(vlc_player);
    libvlc_release(vlc);
    free(m_videobuf);
}

VLCPlayer* VLCPlayer::create(Size size)
{
    auto player = new VLCPlayer;
    if (player && player->init(size)) {
        player->autorelease();
    } else {
        CC_SAFE_DELETE(player);
    }
    return player;
}

bool VLCPlayer::init(Size &size)
{
    vlc = libvlc_new(0, NULL);
    vlc_player = libvlc_media_player_new(vlc);
    width = size.width;
    height = size.height;
    m_videobuf = (char *)malloc((width * height) << 2);
    memset(m_videobuf, 0, (width * height) << 2);
    libvlc_video_set_callbacks(vlc_player, lock, unlock, display, this);
    libvlc_video_set_format(vlc_player, "RGBA", width, height, width << 2);
    libvlc_event_attach(libvlc_media_player_event_manager(vlc_player), 
                        libvlc_MediaPlayerEndReached, 
                        endReached,
                        (void *)this);
    Texture2D *texture = new Texture2D();
    texture->initWithData(m_videobuf, 
                          (width * height) << 2, 
                          Texture2D::PixelFormat::RGBA8888, 
                          width, height, size);
    texture->autorelease();
    initWithTexture(texture);
    scheduleUpdate();
    return true;
}

void VLCPlayer::o_play(std::string &path, bool repeat)
{
    m_isEndReached = false;
    m_curMedia = path;
    m_repeat = repeat;
    m_readyToShow = false;
    libvlc_media_t *media = libvlc_media_new_path(vlc, path.c_str());
    libvlc_media_player_set_media(vlc_player, media);
    libvlc_media_release(media);
    libvlc_media_player_play(vlc_player);
}
void VLCPlayer::o_stop(void)    { libvlc_media_player_stop(vlc_player); }
void VLCPlayer::o_resume(void)  { libvlc_media_player_set_pause(vlc_player, 0); }
void VLCPlayer::o_pause(void)   { libvlc_media_player_pause(vlc_player); }
bool VLCPlayer::isPlaying(void) { return (1 == libvlc_media_player_is_playing(vlc_player)) ? true : false; }
bool VLCPlayer::isEndReached()  { return m_isEndReached; }

void VLCPlayer::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    _insideBounds = (flags & FLAGS_TRANSFORM_DIRTY) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;
    if(_insideBounds)
    {
        if (m_readyToShow) {
            m_readyToShow = false;
            Texture2D *texture = new Texture2D();
            texture->initWithData(m_videobuf, 
                                  (width * height) << 2, 
                                  Texture2D::PixelFormat::RGBA8888, 
                                  width, height, Size(width, height));
            texture->autorelease();
            setTexture(texture);
        }
        _quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, transform);
        renderer->addCommand(&_quadCommand);
#if CC_SPRITE_DEBUG_DRAW
        _debugDrawNode->clear();
        Vec2 vertices[4] = {
            Vec2( _quad.bl.vertices.x, _quad.bl.vertices.y ),
            Vec2( _quad.br.vertices.x, _quad.br.vertices.y ),
            Vec2( _quad.tr.vertices.x, _quad.tr.vertices.y ),
            Vec2( _quad.tl.vertices.x, _quad.tl.vertices.y ),
        };
        _debugDrawNode->drawPoly(vertices, 4, true, Color4F(1.0, 1.0, 1.0, 1.0));
#endif //CC_SPRITE_DEBUG_DRAW
    }
}

void VLCPlayer::update(float dt)
{
    if (m_repeat && isEndReached()) {
        o_play(m_curMedia);
    }
}
#ifndef __MOVIEPLAYER_H__
#define __MOVIEPLAYER_H__

#include "vlc/vlc.h"
#include "cocos2d.h"

class VLCPlayer : public cocos2d::Sprite
{
public:
    ~VLCPlayer();
    static VLCPlayer* create(cocos2d::Size size);
    bool init(cocos2d::Size &size);

    void o_play(std::string &path, bool repeat = true);
    inline void o_stop(void);
    inline void o_pause(void);
    inline void o_resume(void);
    inline bool isPlaying(void);
    inline bool isEndReached();
    
    virtual void draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, uint32_t flags) override;
    virtual void update(float dt) override;

    friend void endReached(const struct libvlc_event_t *event, void *data);
    friend void *lock(void *data, void **p_pixels);
    friend void unlock(void *data, void *id, void *const *p_pixels);
    friend void display(void *data, void *id);

private:
    libvlc_instance_t     *vlc;
    libvlc_media_player_t *vlc_player;
    unsigned int          width;
    unsigned int          height
    char                  *m_videobuf;
    bool                  m_isEndReached;
    std::string           m_curMedia;
    bool                  m_repeat;
    bool                  m_readyToShow;
};
#endif
     
     
    
    
        最后说明一下,可以看到有一些函数以"o_"为开头,怎么会这么奇怪呢~~笔者之前没有加这个前缀,结果resume函数跟Node类的resume函数重名了,根据类的继承规则,Node的resume函数被"遮挡"住了,导致该节点没办法正常的恢复动作,比如,笔者在init方法里调用了scheduleUpdate方法,结果update方法却一直不被调用,查来查去,才发现是Node的resume方法被"遮挡"了,节点没有被正确的恢复。
        当然,还有一种办法就是在VLC类的resume方法里调用Node的resume方法,不过这样做可能导致一些不灵活的情况,所以笔者最终选择了改变函数名称。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/llong568/article/details/43484731

智能推荐

Yii2.0多文件上传实例及php yii2.0图片上传指南-程序员宅基地

文章浏览阅读98次。创建控制器FormControllernamespace frontend\controllers;use Yii;use yii\web\Controller;use frontend\models\Uploadm;use yii\web\UploadedFile;class FormController extends Controller{public function actionMyfi..._php file ->saveas

java入门-飞机游戏-用Jpanel类解决闪烁问题_jpanel动画闪烁-程序员宅基地

文章浏览阅读927次。java用JFrame类会出现闪烁问题原JFrame代码:package cn.game;/* * GameUtil类 */import java.awt.Image;import java.awt.image.BufferedImage;import java.io.IOException;import java.net.URL;import javax.image..._jpanel动画闪烁

element-ui中table合计行被遮盖或不显示的问题_element 表格合计列挡住表格-程序员宅基地

文章浏览阅读985次。不用改el-table的样式处理,直接在updated中处理即可。updated () { this.$nextTick(() => { this.$refs['dataTable'].doLayout(); }) },_element 表格合计列挡住表格

LNMP架构及Wordpress搭建(超详细版)_lnmp部署wordpress实验总结-程序员宅基地

文章浏览阅读7.7k次,点赞7次,收藏64次。写在前面:上个月双11期间,华为云服务器搞活动,一年才81块钱,就租了台服务器玩又注册了个域名,第一年才11块钱,挺便宜哈????接下来整了域名备案,不得不说华为客服挺好的(跟你沟通一些备案相关的事宜)寻思着用服务其整点啥呢,这两天就搭建了个wordpress博客,期间遇见了好多问题,也找了不少资料,在此记录一下希望可以帮助到需要的朋友,小编服务器的linux发行版本是Cen..._lnmp部署wordpress实验总结

目前记录♡最详细的一篇记录学习笔记 ---Python爬虫(18) selenium自动化安装和使用_selenium.webdriver import chrome0ptions-程序员宅基地

文章浏览阅读525次。selenium自动化介绍Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器),可以接收指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏.主讲chromeChromedriver的介绍 # 主讲这个WebDriver是一个用来进行复杂重复的web自动化测试的工具,可以理解它是谷歌的浏览器的驱动或者插件,自动化selenium提供调用该..._selenium.webdriver import chrome0ptions

替换JSONObject的key值_jsonobject替换某个key的值-程序员宅基地

文章浏览阅读4.1k次。将JSONObject的key转换成目标值//调用,formData是被替换的json,map是要替换的key值(原理:重组json)//jsonObj = changeJsonObj(jsonObject, hashedMap); public static JSONObject changeJsonObj(JSONObject jsonObj, Map<String, String> keyMap) { JSONObject json = new JSONObj_jsonobject替换某个key的值

随便推点

Android实现图片高斯模糊_android gaussian blur-程序员宅基地

文章浏览阅读1.9k次。最近项目设计上需要用到稍微比较模糊的图片,因此我就去百度搜了一下,处理办法大概就是借助神器PS(花千骨看多了,呵呵)。但是在程序猿的眼里,代码可以实现一切。下面我就来实现一个Android高斯模糊。高斯模糊:高斯模糊(Gaussian Blur)是美国Adobe图像软件公司开发的一个图像处理软件:Adobe Photoshop(系列)中的一个滤镜,具体的位置在:滤镜—模糊——高斯模糊!高斯模糊的原理_android gaussian blur

linux 查找文件 locate,linux文件查找(find,locate)-程序员宅基地

文章浏览阅读94次。文件查找:locate:非实时,模糊匹配,查找是根据全系统文件数据库进行的;# updatedb, 手动生成文件数据库速度快find:实时精确支持众多查找标准遍历指定目录中的所有文件完成查找,速度慢;find 查找路径 查找标准 查找到以后的处理运作查找路径:默认为当前目录查找标准:默认为指定路径下的所有文件处理运作:默认为显示匹配标准:-name 'FILENAME':对文件名作精确匹配文件名通..._find ./ -name \*.pak -printf

二阶矩阵特征值与特征向量的计算matlab程序(可指定计算精度)_求二次型的特征值的matlab算法-程序员宅基地

文章浏览阅读2.4k次。先前由于项目需要,自己实现了二阶矩阵特征值与特征向量的求取代码,其实很简单,主要部分就是求解一个二次方程的根,现在分享给大家作为参考(因为组长说求平方根可能比较费资源,为方便硬件实现,甚至连平方根求取的代码都是自己写的\笑哭):function [V,lamda]=myEig(A,err);% 求特征值与特征向量的程序% err为指定的计算误差a11=A(1,1);a12=A(1,2);a21=A(2,1);a22=A(2,2);delta=(a11-a22)^2+4*a12*a21;_求二次型的特征值的matlab算法

anaconda环境下的tensorflow版本安装及查看_ancacoda中如何查看tensorflow版本-程序员宅基地

文章浏览阅读1.8w次,点赞11次,收藏33次。一、安装对应版本安装tensorflow时不要直接安装,默认安装的是2.x版本,根据自己的需求选择性的安装自己想要的对应自己环境的版本1、先执行命令anaconda search -t conda tensorflow,出现相关的可选择的tensorflow版本,对应自己的平台进行选择(我是win64)2、然后根据需求找到自己需要版本的名称,查看安装命令输入命令:anaconda show conda-forge/tensorflow-estimator,(conda-..._ancacoda中如何查看tensorflow版本

〖Python 数据库开发实战 - MongoDB篇①〗- MongoDB数据库简介_〖python 数据库开发实战 - mongodb篇 〗- mongodb数据的导入导出-程序员宅基地

文章浏览阅读3.6w次,点赞24次,收藏15次。接下来的一段时间我们将要学习一下 MongoDB 数据库的内容,首先要了解 MongoDB 数据库的背景知识,比如与其他 NoSQL数据库 的区别。接下来就是安装 MongoDB 数据库 与 Robot3T 客户端 ,这样就可以操作 MongoDB 了。需要注意的是 MongoDB 数据库并没有提供类似 Redis 那样的指令,也没有 MySQL 那样的 SQL 语法,操作 MongoDB 的是 JavaScript 的代码,利用 JavaScript 语句操作 MongoDB 数据库。还有一点就是,_〖python 数据库开发实战 - mongodb篇 〗- mongodb数据的导入导出

[Vuejs+php] MySQL数据转JSON传值到前端-程序员宅基地

文章浏览阅读224次。说在前面JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。优点如下[转]:1.占带宽小(格式是压缩的)2.js通过eval()进行Json读取(便于客户端读取)3. JSON支持多种语言(c、c++、PHP等),便于服务端解析关键代码json_encode( $arr )  <文档传送门>ajax   ..._vue sql语句转json

推荐文章

热门文章

相关标签