generic-pc: rework glfb / cVideo internals

* hide implementation details in private classes / objects
* remove unneccessary internals from library include files
The goal is to finally have identical include files for all
platforms to faciliate easy cross-platform library installation.
This commit is contained in:
Stefan Seyfried
2013-10-31 08:48:44 +01:00
parent 91775a6029
commit d0a4a496ec
7 changed files with 462 additions and 239 deletions

View File

@@ -37,8 +37,8 @@
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include "glfb.h"
#include "video_lib.h"
#include "glfb_priv.h"
#include "video_priv.h"
#include "audio_lib.h"
#include "lt_debug.h"
@@ -49,13 +49,39 @@
#define lt_info(args...) _lt_info(HAL_DEBUG_INIT, this, args)
extern cVideo *videoDecoder;
extern VDec *vdec;
extern cAudio *audioDecoder;
static GLFramebuffer *gThiz = 0; /* GLUT does not allow for an arbitrary argument to the render func */
/* the private class that does stuff only needed inside libstb-hal.
* is used e.g. by cVideo... */
GLFbPC *glfb_priv = NULL;
GLFramebuffer::GLFramebuffer(int x, int y): mReInit(true), mShutDown(false), mInitDone(false)
GLFramebuffer::GLFramebuffer(int x, int y)
{
Init();
glfb_priv = new GLFbPC(x, y, osd_buf);
si = glfb_priv->getScreenInfo();
start();
while (!glfb_priv->mInitDone)
usleep(1);
}
GLFramebuffer::~GLFramebuffer()
{
glfb_priv->mShutDown = true;
join();
delete glfb_priv;
glfb_priv = NULL;
}
void GLFramebuffer::blit()
{
glfb_priv->blit();
}
GLFbPC::GLFbPC(int x, int y, std::vector<unsigned char> &buf): mReInit(true), mShutDown(false), mInitDone(false)
{
osd_buf = &buf;
mState.width = x;
mState.height = y;
mX = &_mX[0];
@@ -76,19 +102,19 @@ GLFramebuffer::GLFramebuffer(int x, int y): mReInit(true), mShutDown(false), mIn
last_apts = 0;
/* linux framebuffer compat mode */
screeninfo.bits_per_pixel = 32;
screeninfo.xres = mState.width;
screeninfo.xres_virtual = screeninfo.xres;
screeninfo.yres = mState.height;
screeninfo.yres_virtual = screeninfo.yres;
screeninfo.blue.length = 8;
screeninfo.blue.offset = 0;
screeninfo.green.length = 8;
screeninfo.green.offset = 8;
screeninfo.red.length = 8;
screeninfo.red.offset = 16;
screeninfo.transp.length = 8;
screeninfo.transp.offset = 24;
si.bits_per_pixel = 32;
si.xres = mState.width;
si.xres_virtual = si.xres;
si.yres = mState.height;
si.yres_virtual = si.yres;
si.blue.length = 8;
si.blue.offset = 0;
si.green.length = 8;
si.green.offset = 8;
si.red.length = 8;
si.red.offset = 16;
si.transp.length = 8;
si.transp.offset = 24;
unlink("/tmp/neutrino.input");
mkfifo("/tmp/neutrino.input", 0600);
@@ -96,20 +122,17 @@ GLFramebuffer::GLFramebuffer(int x, int y): mReInit(true), mShutDown(false), mIn
if (input_fd < 0)
lt_info("%s: could not open /tmp/neutrino.input FIFO: %m\n", __func__);
initKeys();
OpenThreads::Thread::start();
while (!mInitDone)
usleep(1);
}
GLFramebuffer::~GLFramebuffer()
GLFbPC::~GLFbPC()
{
mShutDown = true;
OpenThreads::Thread::join();
if (input_fd >= 0)
close(input_fd);
osd_buf->clear();
}
void GLFramebuffer::initKeys()
void GLFbPC::initKeys()
{
mSpecialMap[GLUT_KEY_UP] = KEY_UP;
mSpecialMap[GLUT_KEY_DOWN] = KEY_DOWN;
@@ -155,9 +178,21 @@ void GLFramebuffer::initKeys()
void GLFramebuffer::run()
{
setupCtx();
setupOSDBuffer();
mInitDone = true; /* signal that setup is finished */
int argc = 1;
int x = glfb_priv->mState.width;
int y = glfb_priv->mState.height;
/* some dummy commandline for GLUT to be happy */
char const *argv[2] = { "neutrino", 0 };
lt_info("GLFB: GL thread starting x %d y %d\n", x, y);
glutInit(&argc, const_cast<char **>(argv));
glutInitWindowSize(x, y);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Neutrino");
/* 32bit FB depth, *2 because tuxtxt uses a shadow buffer */
int fbmem = x * y * 4 * 2;
osd_buf.resize(fbmem);
lt_info("GLFB: OSD buffer set to %d bytes at 0x%p\n", fbmem, osd_buf.data());
glfb_priv->mInitDone = true; /* signal that setup is finished */
/* init the good stuff */
GLenum err = glewInit();
@@ -172,16 +207,15 @@ void GLFramebuffer::run()
}
else
{
gThiz = this;
glutSetCursor(GLUT_CURSOR_NONE);
glutDisplayFunc(GLFramebuffer::rendercb);
glutKeyboardFunc(GLFramebuffer::keyboardcb);
glutSpecialFunc(GLFramebuffer::specialcb);
glutReshapeFunc(GLFramebuffer::resizecb);
setupGLObjects(); /* needs GLEW prototypes */
glutDisplayFunc(GLFbPC::rendercb);
glutKeyboardFunc(GLFbPC::keyboardcb);
glutSpecialFunc(GLFbPC::specialcb);
glutReshapeFunc(GLFbPC::resizecb);
glfb_priv->setupGLObjects(); /* needs GLEW prototypes */
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
glutMainLoop();
releaseGLObjects();
glfb_priv->releaseGLObjects();
}
}
else
@@ -189,20 +223,20 @@ void GLFramebuffer::run()
lt_info("GLFB: GL thread stopping\n");
}
void GLFramebuffer::setupCtx()
#if 0
void GLFbPC::setupCtx()
{
int argc = 1;
/* some dummy commandline for GLUT to be happy */
char const *argv[2] = { "neutrino", 0 };
lt_info("GLFB: GL thread starting\n");
lt_info("GLFB: GL thread starting x %d y %d\n", mX[0], mY[0]);
glutInit(&argc, const_cast<char **>(argv));
glutInitWindowSize(mX[0], mY[0]);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Neutrino");
}
void GLFramebuffer::setupOSDBuffer()
void GLFbPC::setupOSDBuffer()
{ /* the OSD buffer size can be decoupled from the actual
window size since the GL can blit-stretch with no
trouble at all, ah, the luxury of ignorance... */
@@ -211,12 +245,13 @@ void GLFramebuffer::setupOSDBuffer()
{
/* 32bit FB depth, *2 because tuxtxt uses a shadow buffer */
int fbmem = mState.width * mState.height * 4 * 2;
mOSDBuffer.resize(fbmem);
lt_info("GLFB: OSD buffer set to %d bytes\n", fbmem);
osd_buf->resize(fbmem);
lt_info("GLFB: OSD buffer set to %d bytes at 0x%p\n", fbmem, osd_buf->data());
}
}
#endif
void GLFramebuffer::setupGLObjects()
void GLFbPC::setupGLObjects()
{
unsigned char buf[4] = { 0, 0, 0, 0 }; /* 1 black pixel */
glGenTextures(1, &mState.osdtex);
@@ -244,7 +279,7 @@ void GLFramebuffer::setupGLObjects()
}
void GLFramebuffer::releaseGLObjects()
void GLFbPC::releaseGLObjects()
{
glDeleteBuffers(1, &mState.pbo);
glDeleteBuffers(1, &mState.displaypbo);
@@ -253,56 +288,56 @@ void GLFramebuffer::releaseGLObjects()
}
/* static */ void GLFramebuffer::rendercb()
/* static */ void GLFbPC::rendercb()
{
gThiz->render();
glfb_priv->render();
}
/* static */ void GLFramebuffer::keyboardcb(unsigned char key, int /*x*/, int /*y*/)
/* static */ void GLFbPC::keyboardcb(unsigned char key, int /*x*/, int /*y*/)
{
lt_debug_c("GLFB::%s: 0x%x\n", __func__, key);
struct input_event ev;
if (key == 'f')
{
lt_info_c("GLFB::%s: toggle fullscreen %s\n", __func__, gThiz->mFullscreen?"off":"on");
gThiz->mFullscreen = !(gThiz->mFullscreen);
gThiz->mReInit = true;
lt_info_c("GLFB::%s: toggle fullscreen %s\n", __func__, glfb_priv->mFullscreen?"off":"on");
glfb_priv->mFullscreen = !(glfb_priv->mFullscreen);
glfb_priv->mReInit = true;
return;
}
std::map<unsigned char, int>::const_iterator i = gThiz->mKeyMap.find(key);
if (i == gThiz->mKeyMap.end())
std::map<unsigned char, int>::const_iterator i = glfb_priv->mKeyMap.find(key);
if (i == glfb_priv->mKeyMap.end())
return;
ev.code = i->second;
ev.value = 1; /* key own */
ev.type = EV_KEY;
gettimeofday(&ev.time, NULL);
lt_debug_c("GLFB::%s: pushing 0x%x\n", __func__, ev.code);
write(gThiz->input_fd, &ev, sizeof(ev));
write(glfb_priv->input_fd, &ev, sizeof(ev));
ev.value = 0; /* neutrino is stupid, so push key up directly after key down */
write(gThiz->input_fd, &ev, sizeof(ev));
write(glfb_priv->input_fd, &ev, sizeof(ev));
}
/* static */ void GLFramebuffer::specialcb(int key, int /*x*/, int /*y*/)
/* static */ void GLFbPC::specialcb(int key, int /*x*/, int /*y*/)
{
lt_debug_c("GLFB::%s: 0x%x\n", __func__, key);
struct input_event ev;
std::map<int, int>::const_iterator i = gThiz->mSpecialMap.find(key);
if (i == gThiz->mSpecialMap.end())
std::map<int, int>::const_iterator i = glfb_priv->mSpecialMap.find(key);
if (i == glfb_priv->mSpecialMap.end())
return;
ev.code = i->second;
ev.value = 1;
ev.type = EV_KEY;
gettimeofday(&ev.time, NULL);
lt_debug_c("GLFB::%s: pushing 0x%x\n", __func__, ev.code);
write(gThiz->input_fd, &ev, sizeof(ev));
write(glfb_priv->input_fd, &ev, sizeof(ev));
ev.value = 0;
write(gThiz->input_fd, &ev, sizeof(ev));
write(glfb_priv->input_fd, &ev, sizeof(ev));
}
int sleep_us = 30000;
void GLFramebuffer::render()
void GLFbPC::render()
{
if(mShutDown)
glutLeaveMainLoop();
@@ -430,12 +465,12 @@ void GLFramebuffer::render()
glutPostRedisplay();
}
/* static */ void GLFramebuffer::resizecb(int w, int h)
/* static */ void GLFbPC::resizecb(int w, int h)
{
gThiz->checkReinit(w, h);
glfb_priv->checkReinit(w, h);
}
void GLFramebuffer::checkReinit(int x, int y)
void GLFbPC::checkReinit(int x, int y)
{
static int last_x = 0, last_y = 0;
@@ -455,7 +490,7 @@ void GLFramebuffer::checkReinit(int x, int y)
last_y = y;
}
void GLFramebuffer::drawSquare(float size, float x_factor)
void GLFbPC::drawSquare(float size, float x_factor)
{
GLfloat vertices[] = {
1.0f, 1.0f,
@@ -473,17 +508,17 @@ void GLFramebuffer::drawSquare(float size, float x_factor)
1.0, 1.0,
};
if (x_factor > -99.0) { /* x_factor == -100 => OSD */
if (videoDecoder &&
videoDecoder->pig_x > 0 && videoDecoder->pig_y > 0 &&
videoDecoder->pig_w > 0 && videoDecoder->pig_h > 0) {
if (vdec &&
vdec->pig_x > 0 && vdec->pig_y > 0 &&
vdec->pig_w > 0 && vdec->pig_h > 0) {
/* these calculations even consider cropping and panscan mode
* maybe this could be done with some clever opengl tricks? */
double w2 = (double)mState.width * 0.5l;
double h2 = (double)mState.height * 0.5l;
double x = (double)(videoDecoder->pig_x - w2) / w2 / x_factor / size;
double y = (double)(h2 - videoDecoder->pig_y) / h2 / size;
double w = (double)videoDecoder->pig_w / w2;
double h = (double)videoDecoder->pig_h / h2;
double x = (double)(vdec->pig_x - w2) / w2 / x_factor / size;
double y = (double)(h2 - vdec->pig_y) / h2 / size;
double w = (double)vdec->pig_w / w2;
double h = (double)vdec->pig_h / h2;
x += ((1.0l - x_factor * size) / 2.0l) * w / x_factor / size;
y += ((size - 1.0l) / 2.0l) * h / size;
vertices[0] = x + w; /* top right x */
@@ -511,11 +546,11 @@ void GLFramebuffer::drawSquare(float size, float x_factor)
}
void GLFramebuffer::bltOSDBuffer()
void GLFbPC::bltOSDBuffer()
{
/* FIXME: copy each time */
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mState.pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, mOSDBuffer.size(), &mOSDBuffer[0], GL_STREAM_DRAW_ARB);
glBufferData(GL_PIXEL_UNPACK_BUFFER, osd_buf->size(), osd_buf->data(), GL_STREAM_DRAW_ARB);
glBindTexture(GL_TEXTURE_2D, mState.osdtex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mState.width, mState.height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
@@ -523,12 +558,12 @@ void GLFramebuffer::bltOSDBuffer()
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
void GLFramebuffer::bltDisplayBuffer()
void GLFbPC::bltDisplayBuffer()
{
if (!videoDecoder) /* cannot start yet */
if (!vdec) /* cannot start yet */
return;
static bool warn = true;
cVideo::SWFramebuffer *buf = videoDecoder->getDecBuf();
VDec::SWFramebuffer *buf = vdec->getDecBuf();
if (!buf) {
if (warn)
lt_info("GLFB::%s did not get a buffer...\n", __func__);
@@ -560,8 +595,7 @@ void GLFramebuffer::bltDisplayBuffer()
* this implementation is pretty naive and not working too well, but
* better this than nothing... :-) */
int64_t apts = 0;
/* 18000 is the magic value for A/V sync in my libao->pulseaudio->intel_hda setup */
int64_t vpts = buf->pts() + 18000;
int64_t vpts = buf->pts();
if (audioDecoder)
apts = audioDecoder->getPts();
if (apts != last_apts) {
@@ -571,7 +605,7 @@ void GLFramebuffer::bltDisplayBuffer()
else if (sleep_us > 1000)
sleep_us -= 1000;
last_apts = apts;
videoDecoder->getPictureInfo(dummy1, dummy2, rate);
vdec->getPictureInfo(dummy1, dummy2, rate);
if (rate > 0)
rate = 2000000 / rate; /* limit to half the frame rate */
else
@@ -582,11 +616,5 @@ void GLFramebuffer::bltDisplayBuffer()
sleep_us = 1;
}
lt_debug("vpts: 0x%" PRIx64 " apts: 0x%" PRIx64 " diff: %6.3f sleep_us %d buf %d\n",
buf->pts(), apts, (buf->pts() - apts)/90000.0, sleep_us, videoDecoder->buf_num);
}
void GLFramebuffer::clear()
{
/* clears front and back buffer */
memset(&mOSDBuffer[0], 0, mOSDBuffer.size());
buf->pts(), apts, (buf->pts() - apts)/90000.0, sleep_us, vdec->buf_num);
}