diff options
Diffstat (limited to 'frontend_local.c')
-rw-r--r-- | frontend_local.c | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/frontend_local.c b/frontend_local.c new file mode 100644 index 00000000..6c7b40e0 --- /dev/null +++ b/frontend_local.c @@ -0,0 +1,452 @@ +/* + * frontend_local.c: + * + * See the main source file 'xineliboutput.c' for copyright information and + * how to reach the author. + * + * $Id: frontend_local.c,v 1.1 2006-06-03 10:01:17 phintuka Exp $ + * + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <dlfcn.h> + +#include <vdr/config.h> +#include <vdr/tools.h> + +#include "logdefs.h" +#include "config.h" + +#include "xine_frontend.h" + +#include "frontend_local.h" + +//------------------------------ cRwLockBlock --------------------------------- + +class cRwLockBlock +{ + private: + cRwLock& m_Lock; + + public: + cRwLockBlock(cRwLock& lock, bool write) : m_Lock(lock) + { m_Lock.Lock(write);} + + ~cRwLockBlock() + { m_Lock.Unlock(); } +}; + +#define LOCK_FE cRwLockBlock(m_feLock, false) +#define LOCK_FE_WR cRwLockBlock(m_feLock, true) + +//----------------------------- cXinelibLocal -------------------------------- + +cXinelibLocal::cXinelibLocal(const char *frontend_name) : + cXinelibThread("Local decoder/display (cXinelibThread)"), m_feLock(true) +{ + fe = NULL; + h_fe_lib = NULL; + m_bReconfigRequest = true; +} + +cXinelibLocal::~cXinelibLocal() +{ + TRACEF("cXinelibLocal::~cXinelibLocal"); + + Stop(); + if(fe) { + fe->fe_free(fe); + fe = NULL; + } + if(h_fe_lib) { + dlclose(h_fe_lib); + } +} + +void cXinelibLocal::Stop(void) +{ + TRACEF("cXinelibLocal::Stop"); + + SetStopSignal(); + + if(1) { + LOCK_FE; + m_bReady=false; + if(fe) + fe->fe_interrupt(fe); + } + + cXinelibThread::Stop(); +} + +// +// Data transfer +// + +int cXinelibLocal::Play_PES(const uchar *data, int len) +{ + TRACEF("cXinelibLocal::Play_PES"); + LOCK_FE; + if(fe) { + //m_bLoopPlay = false; + int done = fe->xine_queue_pes_packet(fe, (char*)data, len); + if(done>0) { + Lock(); + m_StreamPos += done; + Unlock(); + } else { + cCondWait::SleepMs(5); + } + return done; + } + + return 0; +} + +void cXinelibLocal::OsdCmd(void *cmd) +{ + TRACEF("cXinelibLocal::OsdCmd"); + if(cmd) { + LOCK_FE; + if(fe) + fe->xine_osd_command(fe, (struct osd_command_s*)cmd); + } +} + +uchar *cXinelibLocal::GrabImage(int &Size, bool Jpeg, + int Quality, int SizeX, + int SizeY) +{ + uchar *data; + LOCK_FE; + if(fe && fe->grab) + if((data = (uchar*)fe->grab(fe, &Size, Jpeg, Quality, SizeX, SizeY))) + return data; + return NULL; +} + +int64_t cXinelibLocal::GetSTC() +{ + TRACEF("cXinelibLocal::GetSTC"); + + int64_t pts = -1; + char buf[32] = {0}; + strcpy(buf, "GETSTC\r\n"); + + LOCK_FE; + if(fe) + if(0 == fe->xine_control(fe, (char*)buf)) + //if(*((int64_t *)buf) < MAX_SCR) + // if(*((int64_t *)buf) >= 0LL) + pts = *((int64_t *)buf); + return pts; +} + +// +// Configuration +// + +void cXinelibLocal::ConfigureWindow(int fullscreen, int width, int height, + int modeswitch, char *modeline, + int aspect, int scale_video, + int field_order) +{ + LOCK_FE; + if(fe) + fe->fe_display_config(fe, width, height, fullscreen, modeswitch, modeline, + aspect, scale_video, field_order); +} + +void cXinelibLocal::ConfigureDecoder(int pes_buffers, int priority) +{ + // needs xine restart + { + LOCK_FE; + xc.pes_buffers = pes_buffers; + xc.decoder_priority = priority; + if(!fe) + return; + m_bReady=false; + m_bReconfigRequest=true; + fe->fe_interrupt(fe); + } + + while(!m_bReady && !GetStopSignal()) { + cCondWait::SleepMs(100); + pthread_yield(); + } + + cCondWait::SleepMs(100); +} + +// +// Xine control +// + +int cXinelibLocal::Xine_Control(const char *cmd) +{ + TRACEF("cXinelibLocal::Xine_Control"); + char buf[256]; + sprintf(buf, "%s\r\n", cmd); + LOCK_FE; + if(fe) + return fe->xine_control(fe, (char*)buf); + return 0; +} + +// +// keyboard control handler (C callback) +// + +extern "C" { + static void keypress_handler(char *keymap, char *key) + { + if(!xc.use_x_keyboard || !key) { + /* Only X11 key events came this way in local mode. + Keyboard is handled by vdr. */ + LOGMSG("keypress_handler(%s): X11 Keyboard disabled in config", key); + return; + } + cXinelibThread::KeypressHandler(keymap, key, false, false); + } +}; + +// +// Frontend loader +// + +frontend_t *cXinelibLocal::load_frontend(const char *fe_name) +{ + Dl_info info; + struct stat statbuffer; + char libname[4096]=""; + void *lib = NULL; + fe_creator_f *fe_creator = NULL; + static int my_marker = 0; + + if(!dladdr((void *)&my_marker, &info)) { + LOGERR("Error searching plugin: dladdr() returned false (%s)",dlerror()); + return NULL; + } + LOGDBG("xineliboutput: plugin file is %s", info.dli_fname); + + int fe_ind = strstra(fe_name, xc.s_frontends, FRONTEND_NONE); + bool fe_try = false; + if(fe_ind == FRONTEND_NONE) { + LOGMSG("Front-end %s unknown!", fe_name); + fe_ind = 0; + fe_try = true; + } + + strcpy(libname, info.dli_fname); + if(strrchr(libname, '/')) + *(strrchr(libname, '/')+1) = 0; + + LOGMSG("Searching frontend %s from %s", xc.s_frontends[fe_ind], libname); + + do { + strcat(libname, xc.s_frontend_files[fe_ind]); + LOGMSG("Probing %s", libname); + + if (stat(libname, &statbuffer)) { + LOGERR("load_frontend: can't stat %s",libname); + } else if((statbuffer.st_mode & S_IFMT) != S_IFREG) { + LOGMSG("load_frontend: %s not regular file ! trying to load anyway ...", + libname); + } + + if( !(lib = dlopen (libname, RTLD_LAZY | RTLD_GLOBAL))) { + char *dl_error_msg = dlerror(); + LOGERR("load_frontend: cannot dlopen file %s: %s", + libname, dl_error_msg); + } else if ( (fe_creator = (fe_creator_f*)dlsym(lib, "fe_creator"))) { + LOGDBG("load_frontend: entry at %p", fe_creator); + frontend_t *fe = (**fe_creator)(); + + if(fe) { + if(h_fe_lib) + dlclose(h_fe_lib); + h_fe_lib = lib; + + LOGMSG("Using frontend %s (%s) from %s", + xc.s_frontends[fe_ind], xc.s_frontendNames[fe_ind], + xc.s_frontend_files[fe_ind]); + + return fe; + } else { + LOGMSG("Frontend %s (%s) creation failed", + xc.s_frontends[fe_ind], xc.s_frontendNames[fe_ind]); + } + } else { + LOGERR("Frontend entry point not found"); + dlclose(lib); + } + + fe_ind++; // try next frontend ... + + } while(fe_try && fe_ind < FRONTEND_count); + + LOGMSG("No usable frontends found, giving up !"); + return NULL; +} + +// +// Thread main loop +// + +void cXinelibLocal::Action(void) +{ + frontend_t *curr_fe = NULL; + + TRACEF("cXinelibLocal::Action"); + + SetPriority(2); /* lower priority */ +#if 0 + // set priority + sched_param temp; + temp.sched_priority = 2; + + if (!pthread_setschedparam(pthread_self(), SCHED_RR, &temp)) { + TRACE("cXinelibLocal("<<getpid()<<"): priority set successful to " + << temp.sched_priority << + " [" << sched_get_priority_min(SCHED_RR) << "," + << sched_get_priority_max(SCHED_RR) << "]"); + } else { + TRACE("cXinelibLocal(" << getpid() << "): Error: can't set priority to " + << temp.sched_priority << " [" + << sched_get_priority_min(SCHED_RR) + << "," << sched_get_priority_max(SCHED_RR) << "]"); + } + errno = 0; +#endif + + // init frontend + if(!curr_fe) { + curr_fe = load_frontend(xc.local_frontend); + if(!curr_fe) { + LOGMSG("cXinelibLocal: Error initializing frontend"); + SetStopSignal(); + } else { + LOGDBG("cXinelibLocal::Action - fe created"); + if(!curr_fe->fe_display_open(curr_fe, xc.width, xc.height, xc.fullscreen, + xc.modeswitch, xc.modeline, + xc.display_aspect, keypress_handler, + xc.video_port, xc.scale_video, + xc.field_order)) { + LOGMSG("cXinelibLocal: Error initializing display"); + SetStopSignal(); + } else { + LOGDBG("cXinelibLocal::Action - fe->fe_display_open ok"); + } + } + } + + // main loop + while (!GetStopSignal()) { + + { + // init and start xine engine + LOCK_FE_WR; + LOGDBG("cXinelibLocal::Action - xine_init"); + + fe = curr_fe; + if(m_bReconfigRequest) { + if(!fe->xine_init(fe, xc.audio_driver, xc.audio_port, + xc.video_driver, + xc.pes_buffers, xc.decoder_priority, + xc.post_plugins)) { + LOGMSG("cXinelibLocal: Error initializing frontend"); + break; + } + LOGDBG("cXinelibLocal::Action - fe->xine_init ok"); + m_bReconfigRequest = false; + } + + // open (xine) stream + LOGDBG("cXinelibLocal::Action - xine_open"); + if(!fe->xine_open(fe, NULL)) { + LOGMSG("cXinelibLocal: Error opening xvdr://"); + break; + } + LOGDBG("cXinelibLocal::Action - fe->xine_open ok"); + + // start playing (xine) stream + if(!fe->xine_play(fe)) { + LOGMSG("cXinelibLocal: Error playing xvdr://"); + break; + } + LOGDBG("cXinelibLocal::Action - fe->xine_play ok"); + + m_StreamPos = 0; + Xine_Control("STREAMPOS 0"); + } + + // configure frontend and xine + m_bNoVideo = false; + ConfigureOSD(xc.prescale_osd, xc.unscaled_osd); + ConfigurePostprocessing(xc.deinterlace_method, xc.audio_delay, + xc.audio_compression, xc.audio_equalizer, + xc.audio_surround); + ConfigureVideo(xc.hue, xc.saturation, xc.brightness, xc.contrast); + ConfigurePostprocessing("upmix", xc.audio_upmix ? true : false, NULL); +#ifdef ENABLE_TEST_POSTPLUGINS + ConfigurePostprocessing("autocrop", xc.autocrop ? true : false, NULL); + ConfigurePostprocessing("headphone", xc.headphone ? true : false, NULL); +#endif + LOGDBG("cXinelibLocal::Action - fe config OK"); + + LogoDisplay(); + LOGDBG("cXinelibLocal::Action - logo sent"); + + { + LOCK_THREAD; + Xine_Control("NOVIDEO 0"); + Xine_Control("LIVE 0"); + m_bNoVideo = false; + m_bLiveMode = false; + m_bReady = true; + } + + // main event loop + LOGDBG("cXinelibLocal:Action - Starting event loop"); + { + LOCK_FE; + while(!GetStopSignal() && m_bReady && + (/*m_bLoopPlay ||*/ !fe->xine_is_finished(fe)) && + fe->fe_run(fe)) + /*cCondWait::SleepMs(50)*/ ; + } + + LOGDBG("cXinelibLocal::Action - event loop terminated, " + "xine_is_finished=%d", fe->xine_is_finished(fe)); + + { + LOCK_THREAD; + m_bReady = false; + m_bEndOfStreamReached = true; + } + + { + LOCK_FE_WR; + if(fe) + fe->xine_close(fe); + fe = NULL; + } + + LOGMSG("cXinelibLocal::Action - Xine closed"); + } + + if(curr_fe) { + curr_fe->xine_exit(fe); + curr_fe->fe_display_close(curr_fe); + curr_fe->fe_free(curr_fe); + } + + m_bIsFinished = true; + LOGMSG("cXinelibLocal::Action - finished"); +} + |