From d0a4a496ec49e34340c8448136399a7b1bee68f8 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Thu, 31 Oct 2013 08:48:44 +0100 Subject: [PATCH] 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. --- generic-pc/dmx.cpp | 8 +- generic-pc/glfb.cpp | 196 +++++++++++++++++++++++----------------- generic-pc/glfb.h | 85 ++--------------- generic-pc/glfb_priv.h | 109 ++++++++++++++++++++++ generic-pc/video.cpp | 101 +++++++++++++++++---- generic-pc/video_lib.h | 98 +++++++++----------- generic-pc/video_priv.h | 104 +++++++++++++++++++++ 7 files changed, 462 insertions(+), 239 deletions(-) create mode 100644 generic-pc/glfb_priv.h create mode 100644 generic-pc/video_priv.h diff --git a/generic-pc/dmx.cpp b/generic-pc/dmx.cpp index fe1d161..9c3d569 100644 --- a/generic-pc/dmx.cpp +++ b/generic-pc/dmx.cpp @@ -36,8 +36,8 @@ #include "lt_debug.h" /* needed for getSTC :-( */ -#include "video_lib.h" -extern cVideo *videoDecoder; +#include "video_priv.h" +extern VDec *vdec; #define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_DEMUX, this, args) #define lt_info(args...) _lt_info(TRIPLE_DEBUG_DEMUX, this, args) @@ -478,8 +478,8 @@ void cDemux::removePid(unsigned short Pid) void cDemux::getSTC(int64_t * STC) { int64_t pts = 0; - if (videoDecoder) - pts = videoDecoder->GetPTS(); + if (vdec) + pts = vdec->GetPTS(); *STC = pts; } diff --git a/generic-pc/glfb.cpp b/generic-pc/glfb.cpp index 2db24d8..4eb0e10 100644 --- a/generic-pc/glfb.cpp +++ b/generic-pc/glfb.cpp @@ -37,8 +37,8 @@ #include #include #include -#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 &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(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(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::const_iterator i = gThiz->mKeyMap.find(key); - if (i == gThiz->mKeyMap.end()) + std::map::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::const_iterator i = gThiz->mSpecialMap.find(key); - if (i == gThiz->mSpecialMap.end()) + std::map::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); } diff --git a/generic-pc/glfb.h b/generic-pc/glfb.h index c6999d5..bd37bb2 100644 --- a/generic-pc/glfb.h +++ b/generic-pc/glfb.h @@ -16,92 +16,25 @@ along with this program. If not, see . */ -#ifndef __glthread__ -#define __glthread__ +#ifndef __glfb__ +#define __glfb__ #include -#include #include -#include -#include -#include -#include #include /* for screeninfo etc. */ -extern "C" { -#include -} class GLFramebuffer : public OpenThreads::Thread { public: GLFramebuffer(int x, int y); ~GLFramebuffer(); - - void run(); - std::vector *getOSDBuffer() { return &mOSDBuffer; } /* pointer to OSD bounce buffer */ - - int getOSDWidth() { return mState.width; } - int getOSDHeight() { return mState.height; } - void blit() { mState.blit = true; } - - void setOutputFormat(AVRational a, int h, int c) { mOA = a; *mY = h; mCrop = c; mReInit = true; } - - void clear(); - fb_var_screeninfo getScreenInfo() { return screeninfo; } + std::vector *getOSDBuffer() { return &osd_buf; } /* pointer to OSD bounce buffer */ + void blit(); + fb_var_screeninfo getScreenInfo() { return si; } private: - fb_var_screeninfo screeninfo; - int *mX; - int *mY; - int _mX[2]; /* output window size */ - int _mY[2]; /* [0] = normal, [1] = fullscreen */ - AVRational mOA; /* output window aspect ratio */ - AVRational mVA; /* video aspect ratio */ - AVRational _mVA; /* for detecting changes in mVA */ - bool mVAchanged; - float zoom; /* for cropping */ - float xscale; /* and aspect ratio */ - int mCrop; /* DISPLAY_AR_MODE */ - - bool mFullscreen; /* fullscreen? */ - bool mReInit; /* setup things for GL */ - OpenThreads::Mutex mReInitLock; - bool mShutDown; /* if set main loop is left */ - bool mInitDone; /* condition predicate */ - // OpenThreads::Condition mInitCond; /* condition variable for init */ - // mutable OpenThreads::Mutex mMutex; /* lock our data */ - - std::vector mOSDBuffer; /* silly bounce buffer */ - - std::map mKeyMap; - std::map mSpecialMap; - int input_fd; - int64_t last_apts; - - static void rendercb(); /* callback for GLUT */ - void render(); /* actual render function */ - static void keyboardcb(unsigned char key, int x, int y); - static void specialcb(int key, int x, int y); - static void resizecb(int w, int h); - void checkReinit(int w, int h); /* e.g. in case window was resized */ - - void initKeys(); /* setup key bindings for window */ - void setupCtx(); /* create the window and make the context current */ - void setupOSDBuffer(); /* create the OSD buffer */ - void setupGLObjects(); /* PBOs, textures and stuff */ - void releaseGLObjects(); - void drawSquare(float size, float x_factor = 1); /* do not be square */ - - struct { - int width; /* width and height, fixed for a framebuffer instance */ - int height; - GLuint osdtex; /* holds the OSD texture */ - GLuint pbo; /* PBO we use for transfer to texture */ - GLuint displaytex; /* holds the display texture */ - GLuint displaypbo; - bool blit; - } mState; - - void bltOSDBuffer(); - void bltDisplayBuffer(); + fb_var_screeninfo si; + std::vector osd_buf; /* silly bounce buffer */ + void run(); /* for OpenThreads::Thread */ + void *pdata; /* not yet used */ }; #endif diff --git a/generic-pc/glfb_priv.h b/generic-pc/glfb_priv.h new file mode 100644 index 0000000..b86ae3b --- /dev/null +++ b/generic-pc/glfb_priv.h @@ -0,0 +1,109 @@ +/* + Copyright 2010 Carsten Juttner + Copyright 2012,2013 Stefan Seyfried + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + ******************************************************************** + private stuff of the GLFB thread that is only used inside libstb-hal + and not exposed to the application. +*/ + +#ifndef __glfb_priv__ +#define __glfb_priv__ +#include +#include +#include +#include +#include +#include +#include /* for screeninfo etc. */ +#include "glfb.h" +extern "C" { +#include +} + +class GLFbPC +{ +public: + GLFbPC(int x, int y, std::vector &buf); + ~GLFbPC(); + std::vector *getOSDBuffer() { return osd_buf; } /* pointer to OSD bounce buffer */ + int getOSDWidth() { return mState.width; } + int getOSDHeight() { return mState.height; } + void blit() { mState.blit = true; }; + fb_var_screeninfo getScreenInfo() { return si; } + void setOutputFormat(AVRational a, int h, int c) { mOA = a; *mY = h; mCrop = c; mReInit = true; } +/* just make everything public for simplicity - this is only used inside libstb-hal anyway +private: +*/ + fb_var_screeninfo si; + int *mX; + int *mY; + int _mX[2]; /* output window size */ + int _mY[2]; /* [0] = normal, [1] = fullscreen */ + AVRational mOA; /* output window aspect ratio */ + AVRational mVA; /* video aspect ratio */ + AVRational _mVA; /* for detecting changes in mVA */ + bool mVAchanged; + float zoom; /* for cropping */ + float xscale; /* and aspect ratio */ + int mCrop; /* DISPLAY_AR_MODE */ + + bool mFullscreen; /* fullscreen? */ + bool mReInit; /* setup things for GL */ + OpenThreads::Mutex mReInitLock; + bool mShutDown; /* if set main loop is left */ + bool mInitDone; /* condition predicate */ + // OpenThreads::Condition mInitCond; /* condition variable for init */ + // mutable OpenThreads::Mutex mMutex; /* lock our data */ + + std::vector *osd_buf; /* silly bounce buffer */ + + std::map mKeyMap; + std::map mSpecialMap; + int input_fd; + int64_t last_apts; + void run(); + + static void rendercb(); /* callback for GLUT */ + void render(); /* actual render function */ + static void keyboardcb(unsigned char key, int x, int y); + static void specialcb(int key, int x, int y); + static void resizecb(int w, int h); + void checkReinit(int w, int h); /* e.g. in case window was resized */ + + void initKeys(); /* setup key bindings for window */ +#if 0 + void setupCtx(); /* create the window and make the context current */ + void setupOSDBuffer(); /* create the OSD buffer */ +#endif + void setupGLObjects(); /* PBOs, textures and stuff */ + void releaseGLObjects(); + void drawSquare(float size, float x_factor = 1); /* do not be square */ + + struct { + int width; /* width and height, fixed for a framebuffer instance */ + int height; + GLuint osdtex; /* holds the OSD texture */ + GLuint pbo; /* PBO we use for transfer to texture */ + GLuint displaytex; /* holds the display texture */ + GLuint displaypbo; + bool blit; + } mState; + + void bltOSDBuffer(); + void bltDisplayBuffer(); +}; +#endif diff --git a/generic-pc/video.cpp b/generic-pc/video.cpp index 912cbeb..1d2c904 100644 --- a/generic-pc/video.cpp +++ b/generic-pc/video.cpp @@ -40,15 +40,17 @@ extern "C" { #include "video_lib.h" #include "dmx_lib.h" -#include "glfb.h" +#include "glfb_priv.h" +#include "video_priv.h" #include "lt_debug.h" #define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_VIDEO, this, args) #define lt_info(args...) _lt_info(TRIPLE_DEBUG_VIDEO, this, args) #define lt_info_c(args...) _lt_info(TRIPLE_DEBUG_VIDEO, NULL, args) +VDec *vdec = NULL; cVideo *videoDecoder = NULL; extern cDemux *videoDemux; -extern GLFramebuffer *glfb; +extern GLFbPC *glfb_priv; int system_rev = 0; extern bool HAL_nodec; @@ -68,6 +70,11 @@ static const AVRational aspect_ratios[6] = { cVideo::cVideo(int, void *, void *, unsigned int) { lt_debug("%s\n", __func__); + vdec = new VDec(); +} + +VDec::VDec() +{ av_register_all(); if (!HAL_nodec) dmxbuf = (uint8_t *)malloc(DMX_BUF_SZ); @@ -84,14 +91,27 @@ cVideo::cVideo(int, void *, void *, unsigned int) v_format = VIDEO_FORMAT_MPEG2; } +VDec::~VDec(void) +{ + free(dmxbuf); +} + cVideo::~cVideo(void) { Stop(); /* ouch :-( */ - videoDecoder = NULL; +// videoDecoder = NULL; + delete vdec; +// vdec = NULL; } + int cVideo::setAspectRatio(int vformat, int cropping) +{ + return vdec->setAspectRatio(vformat, cropping); +} + +int VDec::setAspectRatio(int vformat, int cropping) { lt_info("%s(%d, %d)\n", __func__, vformat, cropping); if (vformat >= 0) @@ -99,11 +119,16 @@ int cVideo::setAspectRatio(int vformat, int cropping) if (cropping >= 0) display_crop = (DISPLAY_AR_MODE) cropping; if (display_aspect < DISPLAY_AR_RAW) /* don't know what to do with this */ - glfb->setOutputFormat(aspect_ratios[display_aspect], output_h, display_crop); + glfb_priv->setOutputFormat(aspect_ratios[display_aspect], output_h, display_crop); return 0; } int cVideo::getAspectRatio(void) +{ + return vdec->getAspectRatio(); +} + +int VDec::getAspectRatio(void) { buf_m.lock(); int ret = 0; @@ -132,12 +157,22 @@ int cVideo::getAspectRatio(void) return ret; } -int cVideo::setCroppingMode(int) +int cVideo::setCroppingMode(void) { return 0; } int cVideo::Start(void *, unsigned short, unsigned short, void *) +{ + return vdec->Start(); +} + +int cVideo::Stop(bool b) +{ + return vdec->Stop(b); +} + +int VDec::Start() { lt_debug("%s running %d >\n", __func__, thread_running); if (!thread_running && !HAL_nodec) @@ -146,7 +181,7 @@ int cVideo::Start(void *, unsigned short, unsigned short, void *) return 0; } -int cVideo::Stop(bool) +int VDec::Stop(bool) { lt_debug("%s running %d >\n", __func__, thread_running); if (thread_running) { @@ -163,6 +198,11 @@ int cVideo::setBlank(int) } int cVideo::SetVideoSystem(int system, bool) +{ + return vdec->SetVideoSystem(system); +} + +int VDec::SetVideoSystem(int system) { int h; switch(system) @@ -195,16 +235,16 @@ int cVideo::SetVideoSystem(int system, bool) lt_info("%s: unhandled value %d\n", __func__, system); return 0; } - v_std = (VIDEO_STD) system; +// v_std = (VIDEO_STD) system; output_h = h; if (display_aspect < DISPLAY_AR_RAW) /* don't know what to do with this */ - glfb->setOutputFormat(aspect_ratios[display_aspect], output_h, display_crop); + glfb_priv->setOutputFormat(aspect_ratios[display_aspect], output_h, display_crop); return 0; } int cVideo::getPlayState(void) { - return VIDEO_PLAYING; + return 1; } void cVideo::SetVideoMode(analog_mode_t) @@ -212,6 +252,11 @@ void cVideo::SetVideoMode(analog_mode_t) } void cVideo::ShowPicture(const char *fname) +{ + vdec->ShowPicture(fname); +} + +void VDec::ShowPicture(const char *fname) { lt_info("%s(%s)\n", __func__, fname); if (access(fname, R_OK)) @@ -327,6 +372,11 @@ int cVideo::getBlank(void) } void cVideo::Pig(int x, int y, int w, int h, int, int) +{ + vdec->Pig(x, y, w, h); +} + +void VDec::Pig(int x, int y, int w, int h) { pig_x = x; pig_y = y; @@ -336,9 +386,14 @@ void cVideo::Pig(int x, int y, int w, int h, int, int) void cVideo::getPictureInfo(int &width, int &height, int &rate) { - width = dec_w; - height = dec_h; - rate = dec_r; + vdec->getPictureInfo(width, height, rate); +} + +void VDec::getPictureInfo(int &width, int &height, int &rate) +{ + width = vdec->dec_w; + height = vdec->dec_h; + rate = vdec->dec_r; } void cVideo::SetSyncMode(AVSYNC_TYPE) @@ -346,12 +401,17 @@ void cVideo::SetSyncMode(AVSYNC_TYPE) }; int cVideo::SetStreamType(VIDEO_FORMAT v) +{ + return vdec->SetStreamType(v); +} + +int VDec::SetStreamType(VIDEO_FORMAT v) { v_format = v; return 0; } -cVideo::SWFramebuffer *cVideo::getDecBuf(void) +VDec::SWFramebuffer *VDec::getDecBuf(void) { buf_m.lock(); if (buf_num == 0) { @@ -390,7 +450,7 @@ static int my_read(void *, uint8_t *buf, int buf_size) return tmp; } -void cVideo::run(void) +void VDec::run(void) { lt_info("====================== start decoder thread ================================\n"); AVCodec *codec; @@ -507,7 +567,10 @@ void cVideo::run(void) f->width(c->width); f->height(c->height); int64_t vpts = av_frame_get_best_effort_timestamp(frame); + /* a/v delay determined experimentally :-) */ if (v_format == VIDEO_FORMAT_MPEG2) + vpts += 90000*4/10; /* 400ms */ + else vpts += 90000*3/10; /* 300ms */ f->pts(vpts); AVRational a = av_guess_sample_aspect_ratio(avfc, avfc->streams[0], frame); @@ -573,7 +636,7 @@ static bool swscale(unsigned char *src, unsigned char *dst, int sw, int sh, int return ret; } -bool cVideo::GetScreenImage(unsigned char * &data, int &xres, int &yres, bool get_video, bool get_osd, bool scale_to_video) +bool VDec::GetScreenImage(unsigned char * &data, int &xres, int &yres, bool get_video, bool get_osd, bool scale_to_video) { lt_info("%s: data 0x%p xres %d yres %d vid %d osd %d scale %d\n", __func__, data, xres, yres, get_video, get_osd, scale_to_video); @@ -581,8 +644,8 @@ bool cVideo::GetScreenImage(unsigned char * &data, int &xres, int &yres, bool ge std::vector *osd = NULL; std::vector s_osd; /* scaled OSD */ int vid_w = 0, vid_h = 0; - int osd_w = glfb->getOSDWidth(); - int osd_h = glfb->getOSDHeight(); + int osd_w = glfb_priv->getOSDWidth(); + int osd_h = glfb_priv->getOSDHeight(); xres = osd_w; yres = osd_h; if (get_video) { @@ -601,7 +664,7 @@ bool cVideo::GetScreenImage(unsigned char * &data, int &xres, int &yres, bool ge } } if (get_osd) - osd = glfb->getOSDBuffer(); + osd = glfb_priv->getOSDBuffer(); unsigned int need = avpicture_get_size(PIX_FMT_RGB32, xres, yres); data = (unsigned char *)realloc(data, need); /* will be freed by caller */ if (data == NULL) /* out of memory? */ @@ -651,7 +714,7 @@ bool cVideo::GetScreenImage(unsigned char * &data, int &xres, int &yres, bool ge return true; } -int64_t cVideo::GetPTS(void) +int64_t VDec::GetPTS(void) { int64_t pts = 0; buf_m.lock(); diff --git a/generic-pc/video_lib.h b/generic-pc/video_lib.h index f3f2764..9e4c45a 100644 --- a/generic-pc/video_lib.h +++ b/generic-pc/video_lib.h @@ -1,15 +1,26 @@ -#ifndef _VIDEO_TD_H -#define _VIDEO_TD_H +/* + Copyright 2010-2013 Stefan Seyfried + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifndef _VIDEO_LIB_H +#define _VIDEO_LIB_H -#include -#include #include -#include #include -#include "dmx_lib.h" -extern "C" { -#include -} typedef enum { ANALOG_SD_RGB_CINCH = 0x00, @@ -26,11 +37,25 @@ typedef enum { typedef enum { VIDEO_FORMAT_MPEG2 = 0, - VIDEO_FORMAT_MPEG4, + VIDEO_FORMAT_MPEG4, /* H264 */ VIDEO_FORMAT_VC1, VIDEO_FORMAT_JPEG, VIDEO_FORMAT_GIF, - VIDEO_FORMAT_PNG + VIDEO_FORMAT_PNG, + VIDEO_FORMAT_DIVX,/* DIVX 3.11 */ + VIDEO_FORMAT_MPEG4PART2,/* MPEG4 SVH, MPEG4 SP, MPEG4 ASP, DIVX4,5,6 */ + VIDEO_FORMAT_REALVIDEO8, + VIDEO_FORMAT_REALVIDEO9, + VIDEO_FORMAT_ON2_VP6, + VIDEO_FORMAT_ON2_VP8, + VIDEO_FORMAT_SORENSON_SPARK, + VIDEO_FORMAT_H263, + VIDEO_FORMAT_H263_ENCODER, + VIDEO_FORMAT_H264_ENCODER, + VIDEO_FORMAT_MPEG4PART2_ENCODER, + VIDEO_FORMAT_AVS, + VIDEO_FORMAT_VIP656, + VIDEO_FORMAT_UNSUPPORTED } VIDEO_FORMAT; typedef enum { @@ -96,8 +121,9 @@ typedef enum { VIDEO_STD_1080P30, VIDEO_STD_1080P24, VIDEO_STD_1080P25, + VIDEO_STD_1080P50, + VIDEO_STD_1080P60, VIDEO_STD_AUTO, - VIDEO_STD_1080P50, /* SPARK only */ VIDEO_STD_MAX } VIDEO_STD; @@ -118,34 +144,10 @@ typedef enum VIDEO_CONTROL_MAX = VIDEO_CONTROL_SHARPNESS } VIDEO_CONTROL; +class cDemux; -#define VDEC_MAXBUFS 0x30 -class cVideo : public OpenThreads::Thread +class cVideo { - friend class GLFramebuffer; - friend class cDemux; - private: - /* called from GL thread */ - class SWFramebuffer : public std::vector - { - public: - SWFramebuffer() : mWidth(0), mHeight(0) {} - void width(int w) { mWidth = w; } - void height(int h) { mHeight = h; } - void pts(uint64_t p) { mPts = p; } - void AR(AVRational a) { mAR = a; } - int width() const { return mWidth; } - int height() const { return mHeight; } - int64_t pts() const { return mPts; } - AVRational AR() const { return mAR; } - private: - int mWidth; - int mHeight; - int64_t mPts; - AVRational mAR; - }; - int buf_in, buf_out, buf_num; - int64_t GetPTS(void); public: /* constructor & destructor */ cVideo(int mode, void *, void *, unsigned int unit = 0); @@ -160,7 +162,7 @@ class cVideo : public OpenThreads::Thread int setAspectRatio(int aspect, int mode); /* cropping mode */ - int setCroppingMode(int x = 0 /*vidDispMode_t x = VID_DISPMODE_NORM*/); + int setCroppingMode(void); /* get play state */ int getPlayState(void); @@ -197,24 +199,8 @@ class cVideo : public OpenThreads::Thread int StopVBI(void) { return 0; }; void SetDemux(cDemux *dmx); bool GetScreenImage(unsigned char * &data, int &xres, int &yres, bool get_video = true, bool get_osd = false, bool scale_to_video = false); - SWFramebuffer *getDecBuf(void); private: - void run(); - SWFramebuffer buffers[VDEC_MAXBUFS]; - int dec_w, dec_h; - int dec_r; - bool w_h_changed; - bool thread_running; - VIDEO_FORMAT v_format; - VIDEO_STD v_std; - OpenThreads::Mutex buf_m; - DISPLAY_AR display_aspect; - DISPLAY_AR_MODE display_crop; - int output_h; - int pig_x; - int pig_y; - int pig_w; - int pig_h; + void *pdata; /* not yet used */ }; #endif diff --git a/generic-pc/video_priv.h b/generic-pc/video_priv.h new file mode 100644 index 0000000..3221511 --- /dev/null +++ b/generic-pc/video_priv.h @@ -0,0 +1,104 @@ +/* + Copyright 2013 Stefan Seyfried + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __vdec__ + +#include +#include + +#include "video_lib.h" +extern "C" { +#include +} + +#define VDEC_MAXBUFS 0x40 +class VDec : public OpenThreads::Thread +{ + friend class GLFbPC; + friend class cDemux; + private: + /* called from GL thread */ + class SWFramebuffer : public std::vector + { + public: + SWFramebuffer() : mWidth(0), mHeight(0) {} + void width(int w) { mWidth = w; } + void height(int h) { mHeight = h; } + void pts(uint64_t p) { mPts = p; } + void AR(AVRational a) { mAR = a; } + int width() const { return mWidth; } + int height() const { return mHeight; } + int64_t pts() const { return mPts; } + AVRational AR() const { return mAR; } + private: + int mWidth; + int mHeight; + int64_t mPts; + AVRational mAR; + }; + int buf_in, buf_out, buf_num; + public: + /* constructor & destructor */ + VDec(void); + ~VDec(void); + /* aspect ratio */ + int getAspectRatio(void); + int setAspectRatio(int aspect, int mode); + void getPictureInfo(int &width, int &height, int &rate); + +#if 0 + /* cropping mode */ + int setCroppingMode(int x = 0 /*vidDispMode_t x = VID_DISPMODE_NORM*/); + + /* get play state */ + int getPlayState(void); + + /* blank on freeze */ + int getBlank(void); + int setBlank(int enable); +#endif + int SetVideoSystem(int system); + + /* change video play state. Parameters are all unused. */ + int Start(); + int Stop(bool blank = true); + + int SetStreamType(VIDEO_FORMAT type); + void ShowPicture(const char * fname); + void Pig(int x, int y, int w, int h); + bool GetScreenImage(unsigned char * &data, int &xres, int &yres, bool get_video = true, bool get_osd = false, bool scale_to_video = false); + SWFramebuffer *getDecBuf(void); + int64_t GetPTS(void); + private: + void run(); + SWFramebuffer buffers[VDEC_MAXBUFS]; + int dec_w, dec_h; + int dec_r; + bool w_h_changed; + bool thread_running; + VIDEO_FORMAT v_format; + OpenThreads::Mutex buf_m; + DISPLAY_AR display_aspect; + DISPLAY_AR_MODE display_crop; + int output_h; + VIDEO_STD v_std; + int pig_x; + int pig_y; + int pig_w; + int pig_h; +}; +#endif