generic-pc: add alternative clutter based framebuffer

Add a framebuffer implementation based on clutter instead of "raw"
OpenGL. The performance is slightly worse, but it might bring some
platform abstraction and other benefits for the future.
This commit is contained in:
Stefan Seyfried
2016-10-30 13:08:34 +01:00
parent acac2e4f5a
commit 95d07cdfc9
6 changed files with 549 additions and 15 deletions

View File

@@ -20,11 +20,26 @@ AC_DISABLE_STATIC
AC_SYS_LARGEFILE
AC_PROG_LIBTOOL
AC_ARG_ENABLE(clutter,
AS_HELP_STRING(--enable-clutter, use clutter instead of OpenGL),
,[enable_clutter=no])
AM_CONDITIONAL(USE_CLUTTER,test "$enable_clutter" = "yes")
AM_CONDITIONAL(USE_OPENGL,test "$enable_clutter" = "no")
if test "$enable_clutter" = "yes"; then
AC_DEFINE(USE_CLUTTER,1,[use clutter instead of opengl])
else
AC_DEFINE(USE_OPENGL,1,[use opengl instead of clutter])
fi
if test x"$BOXTYPE" = x"tripledragon"; then
TUXBOX_APPS_LIB_PKGCONFIG(DIRECTFB, directfb)
fi
if test x$BOXTYPE = xgeneric; then
if test x"$enable_clutter" = xyes; then
PKG_CHECK_MODULES([CLUTTER], [clutter-1.0])
fi
if test x$BOXMODEL != xraspi; then
PKG_CHECK_MODULES([AVFORMAT], [libavformat >= 53.21.1])
PKG_CHECK_MODULES([AVCODEC], [libavcodec >= 54.28.0])

View File

@@ -1,29 +1,41 @@
noinst_LTLIBRARIES = libgeneric.la
AM_CPPFLAGS = -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS
AM_CPPFLAGS += -Wfatal-errors
AM_CPPFLAGS += \
-I$(top_srcdir)/common \
-I$(top_srcdir)/include \
@AVUTIL_CFLAGS@
@AVUTIL_CFLAGS@ \
@CLUTTER_CFLAGS@
AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing
AM_LDFLAGS = \
-lglut -lGL -lGLU -lGLEW -lao \
-lao \
-lOpenThreads \
@AVFORMAT_LIBS@ \
@AVUTIL_LIBS@ \
@AVCODEC_LIBS@ \
@SWRESAMPLE_LIBS@ \
@SWSCALE_LIBS@
@SWSCALE_LIBS@ \
@CLUTTER_LIBS@
if USE_OPENGL
AM_LDFLAGS += -lglut -lGL -lGLU -lGLEW -lao
endif
libgeneric_la_SOURCES = \
hardware_caps.c \
dmx.cpp \
video.cpp \
audio.cpp \
glfb.cpp \
init.cpp \
playback.cpp \
record.cpp
if USE_CLUTTER
libgeneric_la_SOURCES += clutterfb.cpp
endif
if USE_OPENGL
libgeneric_la_SOURCES += glfb.cpp
endif

481
generic-pc/clutterfb.cpp Normal file
View File

@@ -0,0 +1,481 @@
/*
Framebuffer implementation using clutter https://developer.gnome.org/clutter/
Copyright (C) 2016 Stefan Seyfried <seife@tuxboxcvs.slipkontur.de>
based on the openGL framebuffer implementation
Copyright 2010 Carsten Juttner <carjay@gmx.net>
Copyright 2012,2013 Stefan Seyfried <seife@tuxboxcvs.slipkontur.de>
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 <http://www.gnu.org/licenses/>.
TODO: AV-Sync code is "experimental" at best
*/
#include "config.h"
#include <vector>
#include <sys/types.h>
#include <signal.h>
#include <cstdio>
#include <cstring>
#include <errno.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include "glfb_priv.h"
#include "video_priv.h"
#include "audio_priv.h"
#include <clutter/x11/clutter-x11.h>
#include "lt_debug.h"
#define lt_debug_c(args...) _lt_debug(HAL_DEBUG_INIT, NULL, args)
#define lt_info_c(args...) _lt_info(HAL_DEBUG_INIT, NULL, args)
#define lt_debug(args...) _lt_debug(HAL_DEBUG_INIT, this, args)
#define lt_info(args...) _lt_info(HAL_DEBUG_INIT, this, args)
extern VDec *vdec;
extern ADec *adec;
/* 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)
{
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];
mY = &_mY[0];
*mX = x;
*mY = y;
av_reduce(&mOA.num, &mOA.den, x, y, INT_MAX);
mVA = mOA; /* initial aspect ratios are from the FB resolution, those */
_mVA = mVA; /* will be updated by the videoDecoder functions anyway */
mVAchanged = true;
mCrop = DISPLAY_AR_MODE_PANSCAN;
zoom = 1.0;
xscale = 1.0;
const char *tmp = getenv("GLFB_FULLSCREEN");
mFullscreen = !!(tmp);
mState.blit = true;
last_apts = 0;
/* linux framebuffer compat mode */
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);
input_fd = open("/tmp/neutrino.input", O_RDWR|O_CLOEXEC|O_NONBLOCK);
if (input_fd < 0)
lt_info("%s: could not open /tmp/neutrino.input FIFO: %m\n", __func__);
initKeys();
}
GLFbPC::~GLFbPC()
{
mShutDown = true;
if (input_fd >= 0)
close(input_fd);
osd_buf->clear();
}
void GLFbPC::initKeys()
{
mKeyMap[CLUTTER_KEY_Up] = KEY_UP;
mKeyMap[CLUTTER_KEY_Down] = KEY_DOWN;
mKeyMap[CLUTTER_KEY_Left] = KEY_LEFT;
mKeyMap[CLUTTER_KEY_Right] = KEY_RIGHT;
mKeyMap[CLUTTER_KEY_F1] = KEY_RED;
mKeyMap[CLUTTER_KEY_F2] = KEY_GREEN;
mKeyMap[CLUTTER_KEY_F3] = KEY_YELLOW;
mKeyMap[CLUTTER_KEY_F4] = KEY_BLUE;
mKeyMap[CLUTTER_KEY_F5] = KEY_WWW;
mKeyMap[CLUTTER_KEY_F6] = KEY_SUBTITLE;
mKeyMap[CLUTTER_KEY_F7] = KEY_MOVE;
mKeyMap[CLUTTER_KEY_F8] = KEY_SLEEP;
mKeyMap[CLUTTER_KEY_Page_Up] = KEY_PAGEUP;
mKeyMap[CLUTTER_KEY_Page_Down] = KEY_PAGEDOWN;
mKeyMap[CLUTTER_KEY_Return] = KEY_OK;
mKeyMap[CLUTTER_KEY_Escape] = KEY_EXIT;
mKeyMap['e'] = KEY_EPG;
mKeyMap['i'] = KEY_INFO;
mKeyMap['m'] = KEY_MENU;
mKeyMap['+'] = KEY_VOLUMEUP;
mKeyMap['-'] = KEY_VOLUMEDOWN;
mKeyMap['.'] = KEY_MUTE;
mKeyMap['h'] = KEY_HELP;
mKeyMap['p'] = KEY_POWER;
mKeyMap['0'] = KEY_0;
mKeyMap['1'] = KEY_1;
mKeyMap['2'] = KEY_2;
mKeyMap['3'] = KEY_3;
mKeyMap['4'] = KEY_4;
mKeyMap['5'] = KEY_5;
mKeyMap['6'] = KEY_6;
mKeyMap['7'] = KEY_7;
mKeyMap['8'] = KEY_8;
mKeyMap['9'] = KEY_9;
}
static ClutterActor *stage = NULL;
static ClutterActor *fb_actor = NULL;
static ClutterActor *vid_actor = NULL;
static ClutterTimeline *tl = NULL;
void GLFramebuffer::run()
{
int argc = 1;
int x = glfb_priv->mState.width;
int y = glfb_priv->mState.height;
/* some dummy commandline for GLUT to be happy */
char *a = (char *)"neutrino";
char **argv = (char **)malloc(sizeof(char *) * 2);
argv[0] = a;
argv[1] = NULL;
lt_info("GLFB: GL thread starting x %d y %d\n", x, y);
if (clutter_init(&argc, &argv) != CLUTTER_INIT_SUCCESS) {
lt_info("GLFB: error initializing clutter\n");
return;
}
lt_info("GLFB: %s:%d\n", __func__, __LINE__);
ClutterColor stage_color = { 0, 0, 0, 255 };
stage = clutter_stage_new();
clutter_actor_set_size(stage, x, y);
clutter_actor_set_background_color(stage, &stage_color);
clutter_actor_set_content_gravity(stage, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT);
//g_signal_connect(stage, "destroy", G_CALLBACK(clutter_main_quit), NULL);
g_signal_connect(stage, "key-press-event", G_CALLBACK(GLFbPC::keyboardcb), (void *)1);
g_signal_connect(stage, "key-release-event", G_CALLBACK(GLFbPC::keyboardcb), NULL);
clutter_stage_set_user_resizable(CLUTTER_STAGE (stage), TRUE);
clutter_actor_grab_key_focus(stage);
clutter_actor_show(stage);
/* 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());
/* video plane is below FB plane, so it comes first */
vid_actor = clutter_actor_new();
ClutterContent *fb = clutter_image_new();
/* osd_buf, because it starts up black */
if (!clutter_image_set_data(CLUTTER_IMAGE(fb), osd_buf.data(), COGL_PIXEL_FORMAT_BGR_888, x, y, x*3, NULL)) {
lt_info("GLFB::%s clutter_image_set_data failed? (vid)\n", __func__);
_exit(1); /* life is hard */
}
clutter_actor_set_content(vid_actor, fb);
g_object_unref(fb);
clutter_actor_set_size(vid_actor, x, y);
clutter_actor_set_position(vid_actor, 0, 0);
clutter_actor_add_constraint(vid_actor, clutter_bind_constraint_new(stage, CLUTTER_BIND_WIDTH, 0));
clutter_actor_add_constraint(vid_actor, clutter_bind_constraint_new(stage, CLUTTER_BIND_HEIGHT, 0));
clutter_actor_add_constraint(vid_actor, clutter_bind_constraint_new(stage, CLUTTER_BIND_X, 0));
clutter_actor_add_constraint(vid_actor, clutter_bind_constraint_new(stage, CLUTTER_BIND_Y, 0));
clutter_actor_set_content_gravity(vid_actor, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT);
clutter_actor_set_pivot_point(vid_actor, 0.5, 0.5);
clutter_actor_add_child(stage, vid_actor);
clutter_actor_show(vid_actor);
fb_actor = clutter_actor_new();
fb = clutter_image_new();
if (!clutter_image_set_data(CLUTTER_IMAGE(fb), osd_buf.data(), COGL_PIXEL_FORMAT_BGRA_8888, x, y, x*4, NULL)) {
lt_info("GLFB::%s clutter_image_set_data failed? (osd)\n", __func__);
_exit(1); /* life is hard */
}
clutter_actor_set_content(fb_actor, fb);
g_object_unref(fb);
clutter_actor_set_size(fb_actor, x, y);
clutter_actor_set_position(fb_actor, 0, 0);
clutter_actor_add_constraint(fb_actor, clutter_bind_constraint_new(stage, CLUTTER_BIND_WIDTH, 0));
clutter_actor_add_constraint(fb_actor, clutter_bind_constraint_new(stage, CLUTTER_BIND_HEIGHT, 0));
clutter_actor_add_constraint(fb_actor, clutter_bind_constraint_new(stage, CLUTTER_BIND_X, 0));
clutter_actor_add_constraint(fb_actor, clutter_bind_constraint_new(stage, CLUTTER_BIND_Y, 0));
clutter_actor_set_content_gravity(fb_actor, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT);
clutter_actor_add_child(stage, fb_actor);
clutter_actor_show(fb_actor);
glfb_priv->mInitDone = true; /* signal that setup is finished */
tl = clutter_timeline_new(100);
g_signal_connect(tl, "new-frame", G_CALLBACK(GLFbPC::rendercb), NULL);
clutter_timeline_set_repeat_count(tl, -1);
clutter_timeline_start(tl);
clutter_main();
lt_info("GLFB: GL thread stopping\n");
}
/* static */ void GLFbPC::rendercb()
{
glfb_priv->render();
}
/* static */ bool GLFbPC::keyboardcb(ClutterActor * /*actor*/, ClutterEvent *event, gpointer user_data)
{
guint key = clutter_event_get_key_symbol (event);
int keystate = user_data ? 1 : 0;
lt_info_c("GLFB::%s: 0x%x, %d\n", __func__, key, keystate);
struct input_event ev;
if (key == 'f' && keystate)
{
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 true;
}
std::map<int, int>::const_iterator i = glfb_priv->mKeyMap.find(key);
if (i == glfb_priv->mKeyMap.end())
return true;
ev.code = i->second;
ev.value = keystate; /* key own */
ev.type = EV_KEY;
gettimeofday(&ev.time, NULL);
lt_debug_c("GLFB::%s: pushing 0x%x\n", __func__, ev.code);
write(glfb_priv->input_fd, &ev, sizeof(ev));
return true;
}
int sleep_us = 30000;
void GLFbPC::render()
{
if(mShutDown)
clutter_main_quit();
mReInitLock.lock();
if (mReInit)
{
int xoff = 0;
int yoff = 0;
mVAchanged = true;
mReInit = false;
#if 0
mX = &_mX[mFullscreen];
mY = &_mY[mFullscreen];
#endif
*mX = *mY * mOA.num / mOA.den;
if (mFullscreen) {
clutter_stage_set_fullscreen(CLUTTER_STAGE(stage), TRUE);
clutter_actor_show(stage);
clutter_stage_ensure_redraw(CLUTTER_STAGE(stage));
} else {
clutter_stage_set_fullscreen(CLUTTER_STAGE(stage), FALSE);
// *mX = *mY * mOA.num / mOA.den;
clutter_actor_set_size(stage, *mX, *mY);
}
lt_info("%s: reinit mX:%d mY:%d xoff:%d yoff:%d fs %d\n",
__func__, *mX, *mY, xoff, yoff, mFullscreen);
}
mReInitLock.unlock();
bltDisplayBuffer(); /* decoded video stream */
if (mState.blit) {
/* only blit manually after fb->blit(), this helps to find missed blit() calls */
mState.blit = false;
lt_debug("GLFB::%s blit!\n", __func__);
bltOSDBuffer(); /* OSD */
}
if (mVAchanged)
{
mVAchanged = false;
zoom = 1.0;
float xzoom = 1.0;
//xscale = 1.0;
int cmp = av_cmp_q(mVA, mOA);
const AVRational a149 = { 14, 9 };
switch (cmp) {
default:
case INT_MIN: /* invalid */
case 0: /* identical */
lt_debug("%s: mVA == mOA (or fullscreen mode :-)\n", __func__);
break;
case 1: /* mVA > mOA -- video is wider than display */
lt_debug("%s: mVA > mOA\n", __func__);
switch (mCrop) {
case DISPLAY_AR_MODE_PANSCAN:
zoom = av_q2d(mVA) / av_q2d(mOA);
break;
case DISPLAY_AR_MODE_LETTERBOX:
break;
case DISPLAY_AR_MODE_PANSCAN2:
zoom = av_q2d(a149) / av_q2d(mOA);
break;
case DISPLAY_AR_MODE_NONE:
xzoom = av_q2d(mOA) / av_q2d(mVA);
zoom = av_q2d(mVA) / av_q2d(mOA);
break;
default:
break;
}
break;
case -1: /* mVA < mOA -- video is taller than display */
lt_debug("%s: mVA < mOA\n", __func__);
switch (mCrop) {
case DISPLAY_AR_MODE_LETTERBOX:
break;
case DISPLAY_AR_MODE_PANSCAN2:
if (av_cmp_q(a149, mOA) < 0) {
zoom = av_q2d(mVA) * av_q2d(a149) / av_q2d(mOA);
break;
}
/* fallthrough for output format 14:9 */
case DISPLAY_AR_MODE_PANSCAN:
zoom = av_q2d(mOA) / av_q2d(mVA);
break;
case DISPLAY_AR_MODE_NONE:
xzoom = av_q2d(mOA) / av_q2d(mVA);
break;
default:
break;
}
break;
}
lt_debug("zoom: %f xscale: %f xzoom: %f\n", zoom, xscale,xzoom);
clutter_actor_set_scale(vid_actor, xscale*zoom*xzoom, zoom);
}
clutter_timeline_stop(tl);
clutter_timeline_set_delay(tl, sleep_us/1000);
clutter_timeline_start(tl);
}
void GLFbPC::bltOSDBuffer()
{
// lt_info("%s\n", __func__);
int x = glfb_priv->mState.width;
int y = glfb_priv->mState.height;
ClutterContent *fb = clutter_image_new();
if (!clutter_image_set_data(CLUTTER_IMAGE(fb), osd_buf->data(), COGL_PIXEL_FORMAT_BGRA_8888, x, y, x*4, NULL)) {
lt_info("GLFB::%s clutter_image_set_data failed?\n", __func__);
_exit(1); /* life is hard */
}
clutter_actor_set_content(fb_actor, fb);
g_object_unref(fb);
clutter_actor_show(fb_actor);
}
void GLFbPC::bltDisplayBuffer()
{
// lt_info("GLFB::%s vdec: %p\n", __func__, vdec);
if (!vdec) /* cannot start yet */
return;
static bool warn = true;
VDec::SWFramebuffer *buf = vdec->getDecBuf();
if (!buf) {
if (warn)
lt_info("GLFB::%s did not get a buffer...\n", __func__);
warn = false;
return;
}
warn = true;
int w = buf->width(), h = buf->height();
if (w == 0 || h == 0)
return;
AVRational a = buf->AR();
if (a.den != 0 && a.num != 0 && av_cmp_q(a, _mVA)) {
_mVA = a;
/* _mVA is the raw buffer's aspect, mVA is the real scaled output aspect */
av_reduce(&mVA.num, &mVA.den, w * a.num, h * a.den, INT_MAX);
// mVA.num: 16 mVA.den: 9 w: 720 h: 576
// 16*576/720/9 = 1.42222
xscale = (double)mVA.num*h/(double)mVA.den/w;
mVAchanged = true;
}
ClutterContent *fb = clutter_image_new();
if (!clutter_image_set_data(CLUTTER_IMAGE(fb), &(*buf)[0], COGL_PIXEL_FORMAT_BGR_888, w, h, w*3, NULL)) {
lt_info("GLFB::%s clutter_image_set_data failed?\n", __func__);
_exit(1); /* life is hard */
}
clutter_actor_set_content(vid_actor, fb);
g_object_unref(fb);
clutter_actor_show(vid_actor);
/* "rate control" mechanism starts here...
* this implementation is pretty naive and not working too well, but
* better this than nothing... :-) */
int64_t apts = 0;
int64_t vpts = buf->pts();
if (adec)
apts = adec->getPts();
if (apts != last_apts) {
int rate, dummy1, dummy2;
if (apts < vpts)
sleep_us = (sleep_us * 2 + (vpts - apts)*10/9) / 3;
else if (sleep_us > 1000)
sleep_us -= 1000;
last_apts = apts;
vdec->getPictureInfo(dummy1, dummy2, rate);
if (rate > 0)
rate = 2000000 / rate; /* limit to half the frame rate */
else
rate = 50000; /* minimum 20 fps */
if (sleep_us > rate)
sleep_us = rate;
else if (sleep_us < 1)
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, vdec->buf_num);
}

View File

@@ -22,6 +22,7 @@
TODO: AV-Sync code is "experimental" at best
*/
#include "config.h"
#include <vector>
#include <sys/types.h>

View File

@@ -1,6 +1,6 @@
/*
Copyright 2010 Carsten Juttner <carjay@gmx.net>
Copyright 2012,2013 Stefan Seyfried <seife@tuxboxcvs.slipkontur.de>
Copyright 2012,2013,2016 Stefan Seyfried <seife@tuxboxcvs.slipkontur.de>
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
@@ -25,10 +25,15 @@
#include <OpenThreads/Mutex>
#include <vector>
#include <map>
#if USE_OPENGL
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <GL/gl.h>
#include <linux/fb.h> /* for screeninfo etc. */
#endif
#if USE_CLUTTER
#include <clutter/clutter.h>
#endif
#include "glfb.h"
extern "C" {
#include <libavutil/rational.h>
@@ -71,36 +76,48 @@ private:
std::vector<unsigned char> *osd_buf; /* silly bounce buffer */
#if USE_OPENGL
std::map<unsigned char, int> mKeyMap;
std::map<int, int> mSpecialMap;
#endif
#if USE_CLUTTER
std::map<int, int> mKeyMap;
#endif
int input_fd;
int64_t last_apts;
void run();
static void rendercb(); /* callback for GLUT */
void render(); /* actual render function */
#if USE_OPENGL
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 setupGLObjects(); /* PBOs, textures and stuff */
void releaseGLObjects();
void drawSquare(float size, float x_factor = 1); /* do not be square */
#endif
#if USE_CLUTTER
static bool keyboardcb(ClutterActor *actor, ClutterEvent *event, gpointer user_data);
#endif
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;
bool blit;
#if USE_OPENGL
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;
#endif
} mState;
void bltOSDBuffer();

View File

@@ -23,6 +23,7 @@
* TODO: buffer handling surely needs some locking...
*/
#include "config.h"
#include <unistd.h>
#include <cstring>
#include <cstdio>
@@ -38,6 +39,13 @@ extern "C" {
/* my own buf 256k */
#define DMX_BUF_SZ 0x20000
#if USE_OPENGL
#define VDEC_PIXFMT AV_PIX_FMT_RGB32
#endif
#if USE_CLUTTER
#define VDEC_PIXFMT AV_PIX_FMT_BGR24
#endif
#include "video_hal.h"
#include "dmx_hal.h"
#include "glfb_priv.h"
@@ -317,9 +325,9 @@ void VDec::ShowPicture(const char *fname)
if (avpkt.size > len)
lt_info("%s: WARN: pkt->size %d != len %d\n", __func__, avpkt.size, len);
if (got_frame) {
unsigned int need = avpicture_get_size(AV_PIX_FMT_RGB32, c->width, c->height);
unsigned int need = avpicture_get_size(VDEC_PIXFMT, c->width, c->height);
struct SwsContext *convert = sws_getContext(c->width, c->height, c->pix_fmt,
c->width, c->height, AV_PIX_FMT_RGB32,
c->width, c->height, VDEC_PIXFMT,
SWS_BICUBIC, 0, 0, 0);
if (!convert)
lt_info("%s: ERROR setting up SWS context\n", __func__);
@@ -328,7 +336,7 @@ void VDec::ShowPicture(const char *fname)
SWFramebuffer *f = &buffers[buf_in];
if (f->size() < need)
f->resize(need);
avpicture_fill((AVPicture *)rgbframe, &(*f)[0], AV_PIX_FMT_RGB32,
avpicture_fill((AVPicture *)rgbframe, &(*f)[0], VDEC_PIXFMT,
c->width, c->height);
sws_scale(convert, frame->data, frame->linesize, 0, c->height,
rgbframe->data, rgbframe->linesize);
@@ -543,10 +551,10 @@ void VDec::run(void)
if (avpkt.size > len)
lt_info("%s: WARN: pkt->size %d != len %d\n", __func__, avpkt.size, len);
if (got_frame) {
unsigned int need = avpicture_get_size(AV_PIX_FMT_RGB32, c->width, c->height);
unsigned int need = avpicture_get_size(VDEC_PIXFMT, c->width, c->height);
convert = sws_getCachedContext(convert,
c->width, c->height, c->pix_fmt,
c->width, c->height, AV_PIX_FMT_RGB32,
c->width, c->height, VDEC_PIXFMT,
SWS_BICUBIC, 0, 0, 0);
if (!convert)
lt_info("%s: ERROR setting up SWS context\n", __func__);
@@ -555,7 +563,7 @@ void VDec::run(void)
SWFramebuffer *f = &buffers[buf_in];
if (f->size() < need)
f->resize(need);
avpicture_fill((AVPicture *)rgbframe, &(*f)[0], AV_PIX_FMT_RGB32,
avpicture_fill((AVPicture *)rgbframe, &(*f)[0], VDEC_PIXFMT,
c->width, c->height);
sws_scale(convert, frame->data, frame->linesize, 0, c->height,
rgbframe->data, rgbframe->linesize);