Last active
December 26, 2018 21:51
-
-
Save jvcleave/315456c2c5dd7a8a4ddf158410af6572 to your computer and use it in GitHub Desktop.
videocore fast pixel access
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "ofMain.h" | |
#include "ofAppEGLWindow.h" | |
#include "user-vcsm.h" | |
#include "ofxOMXPlayer.h" | |
#include "TerminalListener.h" | |
class ofApp : public ofBaseApp, public KeyListener{ | |
public: | |
ofxOMXPlayer omxPlayer; | |
unsigned char* videoCorePixels; | |
int videoCoreBufferDim; | |
int videoCorePixelDataSize; | |
ofTexture videoCoreTexture; | |
EGLImageKHR eglFbImage; | |
ofFbo eglEnabledFBO; | |
ofTexture readPixelsTexture; | |
void setup(); | |
void update(); | |
void draw(); | |
TerminalListener consoleListener; | |
void keyPressed(int key); | |
void onCharacterReceived(KeyListenerEventData& e) | |
{ | |
keyPressed((int)e.character); | |
} | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ofApp.h" | |
#define GLCHK(X) \ | |
do { \ | |
GLenum err = GL_NO_ERROR; \ | |
X; \ | |
while ((err = glGetError())) \ | |
{ \ | |
ofLog(OF_LOG_ERROR, "GL error 0x%x in " #X "file %s line %d", err, __FILE__,__LINE__); \ | |
vcos_assert(err == GL_NO_ERROR); \ | |
} \ | |
} \ | |
while(0) | |
egl_image_brcm_vcsm_info vcsm_info; | |
vector<unsigned char> videoCorePixelVector; | |
bool doSaveImage = false; | |
bool doEnablePixels = true; | |
bool doUseReadPixels = false; | |
bool doDrawPixels = true; | |
void ofApp::setup() | |
{ | |
ofSetLogLevel(OF_LOG_VERBOSE); | |
consoleListener.setup(this); | |
omxPlayer.loadMovie("/home/pi/videos/current/Timecoded_Big_bunny_1.mov"); | |
readPixelsTexture.allocate(omxPlayer.getWidth(), omxPlayer.getHeight(), GL_RGBA); | |
vcsm_init(); | |
/* | |
videoCoreBufferDim must be one of: | |
64 | |
128 | |
256 | |
512 | |
1024 | |
2048 | |
*/ | |
videoCoreBufferDim = 1024; | |
eglEnabledFBO.allocate(videoCoreBufferDim, videoCoreBufferDim); | |
videoCorePixelDataSize = videoCoreBufferDim * videoCoreBufferDim * 4; | |
videoCorePixelVector.resize(videoCorePixelDataSize); | |
videoCorePixels = &videoCorePixelVector[0]; | |
memset(videoCorePixels, 0xff, videoCorePixelDataSize); //set to white | |
videoCoreTexture.loadData(videoCorePixels, videoCoreBufferDim, videoCoreBufferDim, GL_RGBA); | |
vcsm_info.width = videoCoreBufferDim; | |
vcsm_info.height = videoCoreBufferDim; | |
ofAppEGLWindow* appEGLWindow = (ofAppEGLWindow *) ofGetWindowPtr(); | |
eglEnabledFBO.begin(); | |
eglFbImage = eglCreateImageKHR(appEGLWindow->getEglDisplay(), EGL_NO_CONTEXT, | |
EGL_IMAGE_BRCM_VCSM, &vcsm_info, NULL); | |
if (eglFbImage == EGL_NO_IMAGE_KHR) | |
{ | |
ofLog() << "Create EGLImage FAIL <---------------- :("; | |
} | |
else | |
{ | |
ofLog() << "Create EGLImage PASS <---------------- :)"; | |
ofLog() << "vcsm_info.vcsm_handle: " << vcsm_info.vcsm_handle; | |
} | |
eglEnabledFBO.end(); | |
eglEnabledFBO.getTexture().bind(); | |
GLCHK(glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglFbImage)); | |
eglEnabledFBO.getTexture().unbind(); | |
} | |
void ofApp::update() | |
{ | |
} | |
void ofApp::draw() | |
{ | |
if(doEnablePixels) | |
{ | |
if(omxPlayer.isFrameNew()) | |
{ | |
if(doUseReadPixels) | |
{ | |
omxPlayer.updatePixels(); | |
if(doDrawPixels) | |
{ | |
readPixelsTexture.loadData(omxPlayer.getPixels(), omxPlayer.getWidth(), omxPlayer.getHeight(), GL_RGBA); | |
} | |
}else | |
{ | |
unsigned char *vcsm_buffer = NULL; | |
VCSM_CACHE_TYPE_T cache_type; | |
eglEnabledFBO.begin(); | |
omxPlayer.draw(0, 0, videoCoreBufferDim, videoCoreBufferDim); | |
eglEnabledFBO.end(); | |
// Make the buffer CPU addressable with host cache enabled | |
vcsm_buffer = (unsigned char *) vcsm_lock_cache(vcsm_info.vcsm_handle, VCSM_CACHE_TYPE_HOST, &cache_type); | |
if (!vcsm_buffer) { | |
ofLog(OF_LOG_ERROR,"Failed to lock VCSM buffer for handle %d\n", vcsm_info.vcsm_handle); | |
}else | |
{ | |
memcpy(videoCorePixels, vcsm_buffer, videoCorePixelDataSize); | |
//int randomStart = ofRandom(pixelVector.size()/4); | |
//random_shuffle(pixelVector.begin()+randomStart, pixelVector.end(); | |
// Release the locked texture memory to flush the CPU cache and allow GPU to read it | |
vcsm_unlock_ptr(vcsm_buffer); | |
} | |
// | |
if(doDrawPixels) | |
{ | |
videoCoreTexture.loadData(videoCorePixels, videoCoreBufferDim, videoCoreBufferDim, GL_RGBA); | |
} | |
} | |
} | |
} | |
stringstream description; | |
if(doEnablePixels) | |
{ | |
description << "Pixels are enabled." << endl; | |
if(doDrawPixels) | |
{ | |
description << "Reloading pixels into a texture which is the biggest bottleneck." << endl; | |
if(doUseReadPixels) | |
{ | |
description << "Using glReadPixels which is the slowest option." << endl; | |
readPixelsTexture.draw(0, 0, omxPlayer.getWidth(), omxPlayer.getHeight()); | |
}else | |
{ | |
description << "Using videocore direct access which is the faster option." << endl; | |
videoCoreTexture.draw(0, 0, omxPlayer.getWidth(), omxPlayer.getHeight()); | |
} | |
}else | |
{ | |
if(doUseReadPixels) | |
{ | |
description << "Using glReadPixels which is still taxing even though not being drawn" << endl; | |
}else | |
{ | |
description << "Using videocore direct access which captures pixels with little performance hit" << endl; | |
} | |
omxPlayer.draw(0, 0, omxPlayer.getWidth(), omxPlayer.getHeight()); | |
} | |
}else | |
{ | |
description << "Pixels are are disabled." << endl; | |
omxPlayer.draw(0, 0, omxPlayer.getWidth(), omxPlayer.getHeight()); | |
} | |
stringstream info; | |
info << "DESCRIPTION: " << endl; | |
info << description.str() << endl; | |
info << omxPlayer.getInfo() << endl; | |
info << "PRESS 1 TO ENABLE PIXELS: " << doEnablePixels << endl; | |
info << "PRESS 2 TO TOGGLE doUseReadPixels: " << doUseReadPixels << endl; | |
info << "PRESS 3 TO TOGGLE doDrawPixels: " << doDrawPixels << endl; | |
ofDrawBitmapStringHighlight(info.str(), 100, 60, ofColor(ofColor::black, 90), ofColor::yellow); | |
} | |
void ofApp::keyPressed (int key) | |
{ | |
ofLog(OF_LOG_VERBOSE, "%c keyPressed", key); | |
switch(key) | |
{ | |
case '1': | |
{ | |
doEnablePixels = !doEnablePixels; | |
break; | |
} | |
case '2': | |
{ | |
doUseReadPixels = !doUseReadPixels; | |
break; | |
} | |
case '3': | |
{ | |
doDrawPixels = !doDrawPixels; | |
break; | |
} | |
case 's': | |
{ | |
doSaveImage = !doSaveImage; | |
break; | |
} | |
case ' ': | |
{ | |
omxPlayer.togglePause(); | |
break; | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://youtu.be/YyweKDiD1Mw