mirror of
https://github.com/tuxbox-fork-migrations/recycled-ni-libstb-hal.git
synced 2025-08-31 17:30:58 +02:00
Merge branch 'master' of https://bitbucket.org/max_10/libstb-hal-max
Origin commit data
------------------
Branch: master
Commit: dddd094e2b
Author: TangoCash <eric@loxat.de>
Date: 2018-10-02 (Tue, 02 Oct 2018)
------------------
No further description and justification available within origin commit message!
------------------
This commit was generated by Migit
This commit is contained in:
@@ -1,29 +1,44 @@
|
||||
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
|
||||
-I$(top_srcdir)/include \
|
||||
@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 \
|
||||
record.cpp
|
||||
|
||||
if USE_CLUTTER
|
||||
libgeneric_la_SOURCES += clutterfb.cpp
|
||||
endif
|
||||
if USE_OPENGL
|
||||
libgeneric_la_SOURCES += glfb.cpp
|
||||
endif
|
||||
|
||||
if ENABLE_GSTREAMER_01
|
||||
libgeneric_la_SOURCES += \
|
||||
playback_gst_01.cpp
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#define lt_debug(args...) _lt_debug(HAL_DEBUG_AUDIO, this, args)
|
||||
#define lt_info(args...) _lt_info(HAL_DEBUG_AUDIO, this, args)
|
||||
|
||||
#include <OpenThreads/Thread>
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
@@ -104,7 +105,7 @@ int cAudio::Start(void)
|
||||
{
|
||||
lt_debug("%s >\n", __func__);
|
||||
if (! HAL_nodec)
|
||||
Thread::startThread();
|
||||
OpenThreads::Thread::start();
|
||||
lt_debug("%s <\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
@@ -115,7 +116,7 @@ int cAudio::Stop(void)
|
||||
if (thread_started)
|
||||
{
|
||||
thread_started = false;
|
||||
Thread::joinThread();
|
||||
OpenThreads::Thread::join();
|
||||
}
|
||||
lt_debug("%s <\n", __func__);
|
||||
return 0;
|
||||
@@ -201,8 +202,34 @@ void cAudio::getAudioInfo(int &type, int &layer, int &freq, int &bitrate, int &m
|
||||
freq = 0;
|
||||
bitrate = 0; /* not used, but easy to get :-) */
|
||||
mode = 0; /* default: stereo */
|
||||
printf("cAudio::getAudioInfo c %p\n", c);
|
||||
if (c) {
|
||||
type = (c->codec_id != AV_CODEC_ID_MP2); /* only mpeg / not mpeg is indicated */
|
||||
switch (c->codec_id) {
|
||||
case AV_CODEC_ID_MP2:
|
||||
type = AUDIO_FMT_MPEG;
|
||||
break;
|
||||
case AV_CODEC_ID_MP3:
|
||||
type = AUDIO_FMT_MP3;
|
||||
break;
|
||||
case AV_CODEC_ID_AC3:
|
||||
case AV_CODEC_ID_TRUEHD:
|
||||
type = AUDIO_FMT_DOLBY_DIGITAL;
|
||||
break;
|
||||
case AV_CODEC_ID_EAC3:
|
||||
type = AUDIO_FMT_DD_PLUS;
|
||||
break;
|
||||
case AV_CODEC_ID_AAC:
|
||||
type = AUDIO_FMT_AAC;
|
||||
break;
|
||||
case AV_CODEC_ID_DTS:
|
||||
type = AUDIO_FMT_DTS;
|
||||
break;
|
||||
case AV_CODEC_ID_MLP:
|
||||
type = AUDIO_FMT_MLP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
freq = c->sample_rate;
|
||||
bitrate = c->bit_rate;
|
||||
if (c->channels == 1)
|
||||
@@ -240,7 +267,7 @@ void cAudio::getAudioInfo(int &type, int &layer, int &freq, int &bitrate, int &m
|
||||
}
|
||||
}
|
||||
lt_debug("%s t: %d l: %d f: %d b: %d m: %d codec_id: %x\n",
|
||||
__func__, type, layer, freq, bitrate, mode, c ? c->codec_id : 0);
|
||||
__func__, type, layer, freq, bitrate, mode, c?c->codec_id:-1);
|
||||
};
|
||||
|
||||
void cAudio::SetSRS(int /*iq_enable*/, int /*nmgr_enable*/, int /*iq_mode*/, int /*iq_level*/)
|
||||
|
@@ -4,7 +4,7 @@
|
||||
#define _AUDIO_LIB_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <thread_abstraction.h>
|
||||
#include <OpenThreads/Thread>
|
||||
#include "cs_types.h"
|
||||
|
||||
typedef enum
|
||||
@@ -38,7 +38,7 @@ typedef enum
|
||||
AUDIO_FMT_ADVANCED = AUDIO_FMT_MLP
|
||||
} AUDIO_FORMAT;
|
||||
|
||||
class cAudio : public Thread
|
||||
class cAudio : public OpenThreads::Thread
|
||||
{
|
||||
friend class cPlayback;
|
||||
private:
|
||||
|
481
generic-pc/clutterfb.cpp
Normal file
481
generic-pc/clutterfb.cpp
Normal 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);
|
||||
}
|
@@ -64,15 +64,12 @@ static const char *DMX_T[] = {
|
||||
};
|
||||
|
||||
/* map the device numbers. for now only demux0 is used */
|
||||
#define NUM_DEMUXDEV 1
|
||||
static const char *devname[NUM_DEMUXDEV] = {
|
||||
static const char *devname[] = {
|
||||
"/dev/dvb/adapter0/demux0",
|
||||
"/dev/dvb/adapter0/demux0",
|
||||
"/dev/dvb/adapter0/demux0"
|
||||
};
|
||||
|
||||
#define NUM_DEMUX 1
|
||||
static int dmx_source[NUM_DEMUX] = { 0 };
|
||||
static bool init[NUM_DEMUXDEV] = { false };
|
||||
|
||||
/* uuuugly */
|
||||
static int dmx_tp_count = 0;
|
||||
#define MAX_TS_COUNT 8
|
||||
@@ -492,28 +489,12 @@ int cDemux::getUnit(void)
|
||||
|
||||
bool cDemux::SetSource(int unit, int source)
|
||||
{
|
||||
//lt_info_c("%s(%d, %d): not implemented yet\n", __func__, unit, source);
|
||||
//return true;
|
||||
if (unit >= NUM_DEMUX || unit < 0) {
|
||||
lt_info_c("%s: unit (%d) out of range, NUM_DEMUX %d\n", __func__, unit, NUM_DEMUX);
|
||||
return false;
|
||||
}
|
||||
lt_info_c("%s(%d, %d) => %d to %d\n", __func__, unit, source, dmx_source[unit], source);
|
||||
if (source < 0 || source >= NUM_DEMUXDEV)
|
||||
lt_info_c("%s(%d, %d) ERROR: source %d out of range!\n", __func__, unit, source, source);
|
||||
else
|
||||
dmx_source[unit] = source;
|
||||
lt_info_c("%s(%d, %d): not implemented yet\n", __func__, unit, source);
|
||||
return true;
|
||||
}
|
||||
|
||||
int cDemux::GetSource(int unit)
|
||||
{
|
||||
//lt_info_c("%s(%d): not implemented yet\n", __func__, unit);
|
||||
//return 0;
|
||||
if (unit >= NUM_DEMUX || unit < 0) {
|
||||
lt_info_c("%s: unit (%d) out of range, NUM_DEMUX %d\n", __func__, unit, NUM_DEMUX);
|
||||
return -1;
|
||||
}
|
||||
lt_info_c("%s(%d) => %d\n", __func__, unit, dmx_source[unit]);
|
||||
return dmx_source[unit];
|
||||
lt_info_c("%s(%d): not implemented yet\n", __func__, unit);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@
|
||||
TODO: AV-Sync code is "experimental" at best
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <vector>
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -37,8 +38,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/input.h>
|
||||
#include "glfb.h"
|
||||
#include <GL/glx.h>
|
||||
#include "glfb_priv.h"
|
||||
#include "video_lib.h"
|
||||
#include "audio_lib.h"
|
||||
|
||||
@@ -53,10 +53,36 @@
|
||||
extern cVideo *videoDecoder;
|
||||
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];
|
||||
@@ -77,19 +103,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);
|
||||
@@ -97,21 +123,22 @@ 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();
|
||||
Thread::startThread();
|
||||
while (!mInitDone)
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
GLFramebuffer::~GLFramebuffer()
|
||||
GLFbPC::~GLFbPC()
|
||||
{
|
||||
mShutDown = true;
|
||||
Thread::joinThread();
|
||||
if (input_fd >= 0)
|
||||
close(input_fd);
|
||||
osd_buf->clear();
|
||||
}
|
||||
|
||||
void GLFramebuffer::initKeys()
|
||||
void GLFbPC::initKeys()
|
||||
{
|
||||
/*
|
||||
Keep in sync with initKeys() in clutterfb.cpp
|
||||
*/
|
||||
|
||||
mSpecialMap[GLUT_KEY_UP] = KEY_UP;
|
||||
mSpecialMap[GLUT_KEY_DOWN] = KEY_DOWN;
|
||||
mSpecialMap[GLUT_KEY_LEFT] = KEY_LEFT;
|
||||
@@ -132,8 +159,8 @@ void GLFramebuffer::initKeys()
|
||||
mSpecialMap[GLUT_KEY_F11] = KEY_NEXT;
|
||||
mSpecialMap[GLUT_KEY_F12] = KEY_PREVIOUS;
|
||||
|
||||
mSpecialMap[GLUT_KEY_PAGE_UP] = KEY_PAGEUP;
|
||||
mSpecialMap[GLUT_KEY_PAGE_DOWN] = KEY_PAGEDOWN;
|
||||
mSpecialMap[GLUT_KEY_PAGE_UP] = KEY_PAGEUP;
|
||||
mSpecialMap[GLUT_KEY_PAGE_DOWN] = KEY_PAGEDOWN;
|
||||
|
||||
mKeyMap[0x0d] = KEY_OK;
|
||||
mKeyMap[0x1b] = KEY_EXIT;
|
||||
@@ -176,9 +203,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();
|
||||
@@ -193,16 +232,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
|
||||
@@ -210,21 +248,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");
|
||||
GLWinID = glXGetCurrentDrawable(); // this was the holy grail to get the right window handle for gstreamer :D
|
||||
}
|
||||
|
||||
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... */
|
||||
@@ -233,12 +270,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);
|
||||
@@ -266,7 +304,7 @@ void GLFramebuffer::setupGLObjects()
|
||||
}
|
||||
|
||||
|
||||
void GLFramebuffer::releaseGLObjects()
|
||||
void GLFbPC::releaseGLObjects()
|
||||
{
|
||||
glDeleteBuffers(1, &mState.pbo);
|
||||
glDeleteBuffers(1, &mState.displaypbo);
|
||||
@@ -275,56 +313,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();
|
||||
@@ -452,12 +490,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;
|
||||
|
||||
@@ -477,7 +515,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,
|
||||
@@ -533,11 +571,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);
|
||||
@@ -545,7 +583,7 @@ void GLFramebuffer::bltOSDBuffer()
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
void GLFramebuffer::bltDisplayBuffer()
|
||||
void GLFbPC::bltDisplayBuffer()
|
||||
{
|
||||
if (!videoDecoder) /* cannot start yet */
|
||||
return;
|
||||
@@ -553,7 +591,7 @@ void GLFramebuffer::bltDisplayBuffer()
|
||||
cVideo::SWFramebuffer *buf = videoDecoder->getDecBuf();
|
||||
if (!buf) {
|
||||
if (warn)
|
||||
lt_debug("GLFB::%s did not get a buffer...\n", __func__);
|
||||
lt_info("GLFB::%s did not get a buffer...\n", __func__);
|
||||
warn = false;
|
||||
return;
|
||||
}
|
||||
@@ -606,9 +644,3 @@ void GLFramebuffer::bltDisplayBuffer()
|
||||
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());
|
||||
}
|
||||
|
@@ -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
|
||||
@@ -14,44 +14,46 @@
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************************************
|
||||
private stuff of the GLFB thread that is only used inside libstb-hal
|
||||
and not exposed to the application.
|
||||
*/
|
||||
|
||||
#ifndef __glthread__
|
||||
#define __glthread__
|
||||
#include <thread_abstraction.h>
|
||||
#include <mutex_abstraction.h>
|
||||
|
||||
#ifndef __glfb_priv__
|
||||
#define __glfb_priv__
|
||||
#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>
|
||||
}
|
||||
|
||||
class GLFramebuffer : public Thread
|
||||
class GLFbPC
|
||||
{
|
||||
public:
|
||||
GLFramebuffer(int x, int y);
|
||||
~GLFramebuffer();
|
||||
|
||||
void run();
|
||||
std::vector<unsigned char> *getOSDBuffer() { return &mOSDBuffer; } /* pointer to OSD bounce buffer */
|
||||
|
||||
GLFbPC(int x, int y, std::vector<unsigned char> &buf);
|
||||
~GLFbPC();
|
||||
std::vector<unsigned char> *getOSDBuffer() { return osd_buf; } /* pointer to OSD bounce buffer */
|
||||
int getOSDWidth() { return mState.width; }
|
||||
int getOSDHeight() { return mState.height; }
|
||||
void blit() { mState.blit = true; }
|
||||
|
||||
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; }
|
||||
|
||||
void clear();
|
||||
fb_var_screeninfo getScreenInfo() { return screeninfo; }
|
||||
int getWindowID() { return GLWinID; }
|
||||
|
||||
/* just make everything public for simplicity - this is only used inside libstb-hal anyway
|
||||
private:
|
||||
fb_var_screeninfo screeninfo;
|
||||
*/
|
||||
fb_var_screeninfo si;
|
||||
int *mX;
|
||||
int *mY;
|
||||
int _mX[2]; /* output window size */
|
||||
@@ -63,45 +65,59 @@ private:
|
||||
float zoom; /* for cropping */
|
||||
float xscale; /* and aspect ratio */
|
||||
int mCrop; /* DISPLAY_AR_MODE */
|
||||
int GLWinID;
|
||||
|
||||
bool mFullscreen; /* fullscreen? */
|
||||
bool mReInit; /* setup things for GL */
|
||||
Mutex mReInitLock;
|
||||
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<unsigned char> mOSDBuffer; /* silly bounce buffer */
|
||||
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 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 */
|
||||
#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
|
||||
|
||||
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();
|
@@ -1,4 +1,5 @@
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_td.h"
|
||||
|
@@ -23,6 +23,7 @@
|
||||
* TODO: buffer handling surely needs some locking...
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
@@ -39,9 +40,16 @@ 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_lib.h"
|
||||
#include "dmx_hal.h"
|
||||
#include "glfb.h"
|
||||
#include "glfb_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)
|
||||
@@ -49,7 +57,7 @@ extern "C" {
|
||||
|
||||
cVideo *videoDecoder = NULL;
|
||||
extern cDemux *videoDemux;
|
||||
extern GLFramebuffer *glfb;
|
||||
extern GLFbPC *glfb_priv;
|
||||
int system_rev = 0;
|
||||
|
||||
extern bool HAL_nodec;
|
||||
@@ -103,7 +111,7 @@ int cVideo::setAspectRatio(int vformat, int cropping)
|
||||
if (cropping >= 0)
|
||||
display_crop = (DISPLAY_AR_MODE) cropping;
|
||||
if (display_aspect < DISPLAY_AR_RAW && output_h > 0) /* 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;
|
||||
}
|
||||
|
||||
@@ -145,7 +153,7 @@ int cVideo::Start(void *, unsigned short, unsigned short, void *)
|
||||
{
|
||||
lt_debug("%s running %d >\n", __func__, thread_running);
|
||||
if (!thread_running && !HAL_nodec)
|
||||
Thread::startThread();
|
||||
OpenThreads::Thread::start();
|
||||
lt_debug("%s running %d <\n", __func__, thread_running);
|
||||
return 0;
|
||||
}
|
||||
@@ -155,7 +163,7 @@ int cVideo::Stop(bool)
|
||||
lt_debug("%s running %d >\n", __func__, thread_running);
|
||||
if (thread_running) {
|
||||
thread_running = false;
|
||||
Thread::joinThread();
|
||||
OpenThreads::Thread::join();
|
||||
}
|
||||
lt_debug("%s running %d <\n", __func__, thread_running);
|
||||
return 0;
|
||||
@@ -214,7 +222,7 @@ int cVideo::SetVideoSystem(int system, bool)
|
||||
// v_std = (VIDEO_STD) system;
|
||||
output_h = h;
|
||||
if (display_aspect < DISPLAY_AR_RAW && output_h > 0) /* 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;
|
||||
}
|
||||
|
||||
@@ -294,9 +302,9 @@ void cVideo::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 = av_image_get_buffer_size(AV_PIX_FMT_RGB32, c->width, c->height, 1);
|
||||
unsigned int need = av_image_get_buffer_size(VDEC_PIXFMT, c->width, c->height, 1);
|
||||
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__);
|
||||
@@ -305,7 +313,7 @@ void cVideo::ShowPicture(const char *fname)
|
||||
SWFramebuffer *f = &buffers[buf_in];
|
||||
if (f->size() < need)
|
||||
f->resize(need);
|
||||
av_image_fill_arrays(rgbframe->data, rgbframe->linesize, &(*f)[0], AV_PIX_FMT_RGB32,
|
||||
av_image_fill_arrays(rgbframe->data, rgbframe->linesize, &(*f)[0], VDEC_PIXFMT,
|
||||
c->width, c->height, 1);
|
||||
sws_scale(convert, frame->data, frame->linesize, 0, c->height,
|
||||
rgbframe->data, rgbframe->linesize);
|
||||
@@ -361,6 +369,7 @@ void cVideo::Pig(int x, int y, int w, int h, int /*osd_w*/, int /*osd_h*/, int /
|
||||
pig_y = y;
|
||||
pig_w = w;
|
||||
pig_h = h;
|
||||
pig_changed = true;
|
||||
}
|
||||
|
||||
void cVideo::getPictureInfo(int &width, int &height, int &rate)
|
||||
@@ -538,10 +547,10 @@ void cVideo::run(void)
|
||||
lt_info("%s: WARN: pkt->size %d != len %d\n", __func__, avpkt.size, len);
|
||||
still_m.lock();
|
||||
if (got_frame && ! stillpicture) {
|
||||
unsigned int need = av_image_get_buffer_size(AV_PIX_FMT_RGB32, c->width, c->height, 1);
|
||||
unsigned int need = av_image_get_buffer_size(VDEC_PIXFMT, c->width, c->height, 1);
|
||||
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__);
|
||||
@@ -550,7 +559,7 @@ void cVideo::run(void)
|
||||
SWFramebuffer *f = &buffers[buf_in];
|
||||
if (f->size() < need)
|
||||
f->resize(need);
|
||||
av_image_fill_arrays(rgbframe->data, rgbframe->linesize, &(*f)[0], AV_PIX_FMT_RGB32,
|
||||
av_image_fill_arrays(rgbframe->data, rgbframe->linesize, &(*f)[0], VDEC_PIXFMT,
|
||||
c->width, c->height, 1);
|
||||
sws_scale(convert, frame->data, frame->linesize, 0, c->height,
|
||||
rgbframe->data, rgbframe->linesize);
|
||||
@@ -564,10 +573,18 @@ 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 USE_OPENGL
|
||||
if (v_format == VIDEO_FORMAT_MPEG2)
|
||||
vpts += 90000*4/10; /* 400ms */
|
||||
else
|
||||
vpts += 90000*3/10; /* 300ms */
|
||||
#endif
|
||||
#if USE_CLUTTER
|
||||
/* no idea why there's a difference between OpenGL and clutter rendering... */
|
||||
if (v_format == VIDEO_FORMAT_MPEG2)
|
||||
vpts += 90000*3/10; /* 300ms */
|
||||
#endif
|
||||
f->pts(vpts);
|
||||
AVRational a = av_guess_sample_aspect_ratio(avfc, avfc->streams[0], frame);
|
||||
f->AR(a);
|
||||
@@ -667,8 +684,8 @@ bool cVideo::GetScreenImage(unsigned char * &data, int &xres, int &yres, bool ge
|
||||
std::vector<unsigned char> *osd = NULL;
|
||||
std::vector<unsigned char> 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) {
|
||||
@@ -692,24 +709,26 @@ bool cVideo::GetScreenImage(unsigned char * &data, int &xres, int &yres, bool ge
|
||||
yres = osd_h;
|
||||
}
|
||||
if (get_osd)
|
||||
osd = glfb->getOSDBuffer();
|
||||
osd = glfb_priv->getOSDBuffer();
|
||||
unsigned int need = av_image_get_buffer_size(AV_PIX_FMT_RGB32, xres, yres, 1);
|
||||
data = (unsigned char *)realloc(data, need); /* will be freed by caller */
|
||||
if (data == NULL) /* out of memory? */
|
||||
return false;
|
||||
|
||||
if (get_video) {
|
||||
//memcpy dont work with copy BGR24 to RGB32
|
||||
#if USE_OPENGL //memcpy dont work with copy BGR24 to RGB32
|
||||
if (vid_w != xres || vid_h != yres){ /* scale video into data... */
|
||||
bool ret = swscale(&video[0], data, vid_w, vid_h, xres, yres, AV_PIX_FMT_RGB32);
|
||||
#endif
|
||||
bool ret = swscale(&video[0], data, vid_w, vid_h, xres, yres,VDEC_PIXFMT);
|
||||
if(!ret){
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
//memcpy dont work with copy BGR24 to RGB32
|
||||
} else { /* get_video and no fancy scaling needed */
|
||||
#if USE_OPENGL //memcpy dont work with copy BGR24 to RGB32
|
||||
}else{ /* get_video and no fancy scaling needed */
|
||||
memcpy(data, &video[0], xres * yres * sizeof(uint32_t));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (get_osd && (osd_w != xres || osd_h != yres)) {
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#ifndef _VIDEO_LIB_H
|
||||
#define _VIDEO_LIB_H
|
||||
|
||||
#include <thread_abstraction.h>
|
||||
#include <mutex_abstraction.h>
|
||||
#include <OpenThreads/Thread>
|
||||
#include <OpenThreads/Mutex>
|
||||
#include <vector>
|
||||
#include <linux/dvb/video.h>
|
||||
#include "cs_types.h"
|
||||
@@ -120,10 +120,10 @@ typedef enum
|
||||
} VIDEO_CONTROL;
|
||||
|
||||
|
||||
#define VDEC_MAXBUFS 0x30
|
||||
class cVideo : public Thread
|
||||
#define VDEC_MAXBUFS 0x40
|
||||
class cVideo : public OpenThreads::Thread
|
||||
{
|
||||
friend class GLFramebuffer;
|
||||
friend class GLFbPC;
|
||||
friend class cDemux;
|
||||
private:
|
||||
/* called from GL thread */
|
||||
@@ -211,8 +211,7 @@ class cVideo : public Thread
|
||||
bool thread_running;
|
||||
VIDEO_FORMAT v_format;
|
||||
VIDEO_STD v_std;
|
||||
//OpenThreads::Mutex buf_m;
|
||||
Mutex buf_m;
|
||||
OpenThreads::Mutex buf_m;
|
||||
DISPLAY_AR display_aspect;
|
||||
DISPLAY_AR_MODE display_crop;
|
||||
int output_h;
|
||||
@@ -221,7 +220,7 @@ class cVideo : public Thread
|
||||
int pig_w;
|
||||
int pig_h;
|
||||
bool pig_changed;
|
||||
Mutex still_m;
|
||||
OpenThreads::Mutex still_m;
|
||||
bool stillpicture;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user