使用Ogre快速渲染视频纹理

基本思路

测试时可使用和视频画面同大小的全屏四边形Rectangle2D,该rect使用动态纹理材质。

渲染时按帧率动态替换该材质的纹理单元为当前帧图像

视频读取

读取每帧视频画面我使用的是OpenCV,类似如下:

CvCapture* mCapture = cvCreateFileCapture(mFileName.c_str());

int totalFrames = (int)cvGetCaptureProperty(mCapture, CV_CAP_PROP_FRAME_COUNT);

int fps = cvGetCaptureProperty(mCapture, CV_CAP_PROP_FPS);

IplImage* frame = cvQueryFrame(mCapture);

frame即为捕捉到的画面,其中最需要的三个属性:

  width 图像宽

  height 图像高

  imageData RGB格式的数据区

你可以使用任意数据源,最终的Ogre处理都是一样的

第一次尝试

首先想到的是直接使用已有的材质,通过卸载、加载纹理单元的方式:

//卸载原纹理

Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().getByName("testMat");

Ogre::TexturePtr textureOld = mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->_getTexturePtr(0);

textureOld->unload();//可选

Ogre::TextureManager::getSingleton().remove(static_cast<Ogre::ResourcePtr>(textureOld));

//加载新纹理

Ogre::DataStreamPtr pDataStream(new Ogre::MemoryDataStream(frame->imageData, frame->width * frame->height * 3, false, true));

Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().loadRawData("testTexture",

    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, pDataStream, frame->width, frame->height,

    Ogre::PF_R8G8B8, Ogre::TEX_TYPE_2D);

mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("testTexture");

因为我们有原始内存数据frame->imageData,因此可以使用内存数据流,并调用loadRawData方法加载纹理

按理说这种方法是很快的,因此只需担心能不能正确的画面

运行之后,画面是显示出来的,但灰突突的,没有原先的光泽度

想来大概是需要启用gamma矫正,即纹理创建改为:

Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().loadRawData("testTexture",

    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, pDataStream, frame->width, frame->height,

    Ogre::PF_R8G8B8, Ogre::TEX_TYPE_2D, 0, 1.0f, true);

最后三个参数,分别设置mipmap为0, 采用硬件gamma校正(如果用软件校正,即将1.0f改为2.2,将会惊人的慢)

这一次,图像完全和原始视频相同了,但是帧率非常的低

改进

因为每次切换画面使用的纹理格式、大小都完全相同

显然可以考虑直接替换已有纹理单元的内存数据区,而不是先销毁再创建,代码如下:

Ogre::PixelBox box(frame->width, frame->height, 1, Ogre::PF_R8G8B8, frame->imageData);

texture->getBuffer(0, 0)->blitFromMemory(box);

这一次想来应该是足够快了,然而结果仍不理想

跟踪下去,发现blitFromMemory 类似实现最终都调用了D3DXLoadSurfaceFromMemory,性能的瓶颈都出在这里

因为已经是D3D API,这条路也就不能继续走下去了

另外虽然HardwarePixelBuffer的接口声明了writeData接口,但并没有实现,也是不能使用

看来只剩下一种办法,通过lock复制数据,希望可以成功了:

void* dst = texture->getBuffer(0, 0)->lock(Ogre::HardwareBuffer::HBL_DISCARD);

memcpy(dst, frame->imageData, frame->width * frame->height * 3);

texture->getBuffer(0, 0)->unlock();

这么做发现帧速确实上去了,但图像变成了重影的灰度图,显然是因为内存格式不一致

好在看显示的图像高度好像正好是原来的3/4

考虑我们用的是RGB格式,也许这是因为硬件使用4字节RGBA存储像素的原因

于是修改代码为:

char* dst =(char*)( texture->getBuffer(0, 0)->lock(Ogre::HardwareBuffer::HBL_DISCARD));

char* src = frame->imageData;

for(int i=0; i<frame->width; ++i)

{

  for(int j=0; j<frame->height; ++j)

  {

    *dst++=*src++;

    *dst++=*src++;

    *dst++=*src++;

    *dst++=0; //填充

  }

}

texture->getBuffer(0, 0)->unlock();

啊,这一次终于成功了

进一步改进

使用的默认纹理单元时,缓冲区用途默认为TU_DEFAULT

对于需要快速刷新的场景应使用TU_DYNAMIC_WRITE_ONLY_DISCARDABLE

因此可以将纹理的创建改写为:

texture = Ogre::TextureManager::getSingleton().createManual(textureName,

  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, frame->width, frame->height, 0,

  Ogre::PF_R8G8B8, Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE, 0, true);

这可以进一步提高性能

时间: 2024-10-07 22:35:53

使用Ogre快速渲染视频纹理的相关文章

m3u8编码视频webgl、threejs渲染视频纹理demo

<!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title>fz-live</title> <link href="./css/video.css" rel="stylesheet"> <script src="./js/video.js"></script> <script

NeHe OpenGL教程 第三十六课:从渲染到纹理

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第三十六课:从渲染到纹理 放射模糊和渲染到纹理: 如何实现放射状的滤镜效果呢,看上去很难,其实很简单.把渲染得图像作为纹理提取出来,在利用OpenGL本身自带的纹理过滤,就能实现这种效果,不信,你试试. 嗨,我是Dario Corn

教你微信图文消息快速添加视频的方法

最近国防部发布征兵宣传片:军营版<小苹果>的视频很火,好东西不能独享,决定让公众号粉丝也happy一下,怎样在微信图文消息快速添加视频呢?瞧下xmyanke摸索的方法吧. 首先,到腾讯视频搜索一下相关的video,把那个视频播放地址复制下来,当时是那么想的:微信和微视是同家,应该可以兼容.然后打开微信图文消息编辑框,点击插入视频按钮,把刚刚那个url黏贴进去. 添加一些文字说明,保存,预览 怎么样?这种方法添加微信图文消息视频是不是很快呢?不用在后台上传视频老半天都没反应,传好了又不能用的问题

unity3d 安卓播放视频替代视频纹理

导出apk,是不能用电影纹理的,所以我们只能用这个办法 这个 Handheld.PlayFullScreenMovie(); 或者这个函数            iPhoneUtils.PlayMovie(); void OnGUI() { if (GUI.Button(new Rect(Screen.width / 2 - 10, Screen.height / 2 - 10, 100,20), "(h)CancelOnTouch")) { Handheld.PlayFullScre

Qt 3D的研究(七):渲染至纹理

Qt 3D的研究(七):渲染至纹理 最近几天都没有怎么研究Qt 3D了,但是随着Qt5.5发布的日子一天天的靠近,我也不能懈怠,希望利用Qt 3D,将能够实现的功能进行实现,并且对Qt3D获取一个新的认识.两天多没有研究了,现在信心却是满满的! 蒋彩阳原创文章,首发地址:http://blog.csdn.net/gamesdev/article/details/44156633.欢迎同行前来探讨. Qt 3D还是在发展的过程中,也没有什么文档,所以有什么问题的话,只能去问库的作者了.我就在IRC

Windows D3D渲染到纹理

D3D渲染到纹理 1 #include <d3dx9.h> 2 3 //----------------------------------------------------------------------------- 4 // Desc: 全局变量 5 //----------------------------------------------------------------------------- 6 LPDIRECT3D9 g_pD3D = NULL; //Direct

转:Ogre内部渲染流程

以下是 Ogre 的代码中的详细说明: Renderable是OGRE中所有可渲染对象的抽象接口 这个接口抽象出了在渲染管线中的被分组的离散的可渲染对象基本的方法. 此接口的实现类必须是基于单一的材质.单一的世界矩阵(或者是一组通过权重混合的世界矩阵),以及单一的渲染操作. 通过这个说明,应该能明确的是,Renderable 封装了3D世界中被渲染对象的基本属性和数据,这包括:渲染操作,材质属性,光照信息.变换矩阵(四元组).LOD信息.渲染方式等信息.这些信息在渲染循环中被取出,并应用在图形渲

Chromium为视频标签&lt;video&gt;渲染视频画面的过程分析

在浏览器中,<video>标签与普通标签有一个显著不同点,它们的内容不是由浏览器自己绘制出来,而是由第三方组件提供的.例如,在Android平台上,<video>标签的内容来自于系统播放器MediaPlayer的输出.然而在非全屏模式下,<video>标签的内容又需要像普通标签一样,嵌入在HTML页面中显示,也就是由浏览器进行渲染.本文接下来就分析Chromium渲染<video>标签内容的原理. 老罗的新浪微博:http://weibo.com/sheng

cocos2dx-精灵如何被渲染and纹理如何被管理、产生与销毁

一.精灵是怎么被渲染出来的 cocos渲染用了opengl.所有精灵顶点的位置,都是真实的在opengl世界坐标系中的大小.这些点在XOY平面上,z都为0,它们进行模型视图变换,再进行投影变换,投影空间进行除法运算规格化最后通过视口变换转化为窗口上的一点. void CCDirector::setProjection(ccDirectorProjection kProjection) { CCSize size = m_obWinSizeInPoints; setViewport(); swit