vdr-plugin-softhddevice/softhddevice.cpp

1870 lines
48 KiB
C++
Raw Normal View History

2011-12-07 14:37:51 +01:00
///
/// @file softhddevice.cpp @brief A software HD device plugin for VDR.
///
2012-01-02 19:31:08 +01:00
/// Copyright (c) 2011, 2012 by Johns. All Rights Reserved.
2011-12-07 14:37:51 +01:00
///
/// Contributor(s):
///
/// License: AGPLv3
///
/// This program is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License as
/// published by the Free Software Foundation, either version 3 of the
/// License.
///
/// 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 Affero General Public License for more details.
///
/// $Id$
//////////////////////////////////////////////////////////////////////////////
#include <vdr/interface.h>
#include <vdr/plugin.h>
#include <vdr/player.h>
#include <vdr/osd.h>
#include <vdr/dvbspu.h>
#include <vdr/shutdown.h>
#ifdef HAVE_CONFIG
#include "config.h"
#endif
#include "softhddev.h"
#include "softhddevice.h"
extern "C"
{
#include "video.h"
2012-03-26 20:49:18 +02:00
extern const char *X11DisplayName; ///< x11 display name
extern void AudioPoller(void);
extern void CodecSetAudioPassthrough(int);
2012-02-21 22:24:28 +01:00
extern void CodecSetAudioDownmix(int);
}
2011-12-07 14:37:51 +01:00
//////////////////////////////////////////////////////////////////////////////
2012-03-10 17:46:00 +01:00
/// vdr-plugin version number.
/// Makefile extracts the version number for generating the file name
/// for the distribution archive.
2012-03-05 17:34:10 +01:00
static const char *const VERSION = "0.5.0"
#ifdef GIT_REV
"-GIT" GIT_REV
#endif
;
2012-03-10 17:46:00 +01:00
/// vdr-plugin description.
2011-12-07 14:37:51 +01:00
static const char *const DESCRIPTION =
trNOOP("A software and GPU emulated HD device");
2012-03-10 17:46:00 +01:00
/// vdr-plugin text of main menu entry
2012-02-19 19:22:03 +01:00
static const char *MAINMENUENTRY = trNOOP("SoftHdDevice");
2012-03-10 17:46:00 +01:00
/// single instance of softhddevice plugin device.
2011-12-07 14:37:51 +01:00
static class cSoftHdDevice *MyDevice;
//////////////////////////////////////////////////////////////////////////////
#define RESOLUTIONS 4 ///< number of resolutions
/// resolutions names
static const char *const Resolution[RESOLUTIONS] = {
"576i", "720p", "1080i_fake", "1080i"
};
static char ConfigMakePrimary; ///< config primary wanted
static char ConfigHideMainMenuEntry; ///< config hide main menu entry
static uint32_t ConfigVideoBackground; ///< config video background color
static int ConfigVideoSkipLines; ///< config skip lines top/bottom
2012-03-26 20:49:18 +02:00
static int ConfigVideoSkipPixels; ///< config skip pixels left/right
static char ConfigVideoStudioLevels; ///< config use studio levels
static char ConfigVideo60HzMode; ///< config use 60Hz display mode
static char ConfigVideoSoftStartSync; ///< config use softstart sync
/// config deinterlace
static int ConfigVideoDeinterlace[RESOLUTIONS];
/// config skip chroma
static int ConfigVideoSkipChromaDeinterlace[RESOLUTIONS];
/// config inverse telecine
static int ConfigVideoInverseTelecine[RESOLUTIONS];
/// config denoise
static int ConfigVideoDenoise[RESOLUTIONS];
/// config sharpen
static int ConfigVideoSharpen[RESOLUTIONS];
/// config scaling
static int ConfigVideoScaling[RESOLUTIONS];
static int ConfigVideoAudioDelay; ///< config audio delay
static int ConfigAudioPassthrough; ///< config audio pass-through
2012-02-21 22:24:28 +01:00
static int ConfigAudioDownmix; ///< config audio downmix
2012-01-20 15:33:37 +01:00
static int ConfigAutoCropInterval; ///< auto crop detection interval
static int ConfigAutoCropDelay; ///< auto crop detection delay
2012-01-27 23:49:05 +01:00
static int ConfigAutoCropTolerance; ///< auto crop detection tolerance
2012-01-20 15:33:37 +01:00
2012-01-26 15:00:49 +01:00
static char ConfigSuspendClose; ///< suspend should close devices
static char ConfigSuspendX11; ///< suspend should stop x11
static volatile int DoMakePrimary; ///< switch primary device to this
2011-12-07 14:37:51 +01:00
2012-03-01 22:12:22 +01:00
#define SUSPEND_EXTERNAL -1 ///< play external suspend mode
#define NOT_SUSPENDED 0 ///< not suspend mode
#define SUSPEND_NORMAL 1 ///< normal suspend mode
#define SUSPEND_DETACHED 2 ///< detached suspend mode
2012-03-01 22:12:22 +01:00
static char SuspendMode; ///< suspend mode
2011-12-07 14:37:51 +01:00
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// C Callbacks
//////////////////////////////////////////////////////////////////////////////
/**
** Soft device plugin remote class.
*/
2011-12-07 14:37:51 +01:00
class cSoftRemote:public cRemote
{
public:
/**
** Soft device remote class constructor.
**
** @param name remote name
*/
2011-12-07 14:37:51 +01:00
cSoftRemote(const char *name):cRemote(name)
{
2011-12-14 18:01:03 +01:00
}
2011-12-07 14:37:51 +01:00
/**
** Put keycode into vdr event queue.
**
** @param code key code
** @param repeat flag key repeated
** @param release flag key released
*/
2011-12-07 14:37:51 +01:00
bool Put(const char *code, bool repeat = false, bool release = false) {
return cRemote::Put(code, repeat, release);
2011-12-14 18:01:03 +01:00
}
2011-12-07 14:37:51 +01:00
};
/**
** Feed key press as remote input (called from C part).
**
** @param keymap target keymap "XKeymap" name
** @param key pressed/released key name
** @param repeat repeated key flag
** @param release released key flag
*/
2011-12-07 14:37:51 +01:00
extern "C" void FeedKeyPress(const char *keymap, const char *key, int repeat,
int release)
{
cRemote *remote;
cSoftRemote *csoft;
if (!keymap || !key) {
return;
}
// find remote
for (remote = Remotes.First(); remote; remote = Remotes.Next(remote)) {
if (!strcmp(remote->Name(), keymap)) {
break;
}
}
// if remote not already exists, create it
2011-12-07 14:37:51 +01:00
if (remote) {
csoft = (cSoftRemote *) remote;
} else {
dsyslog("[softhddev]%s: remote '%s' not found\n", __FUNCTION__,
keymap);
csoft = new cSoftRemote(keymap);
}
2012-01-20 21:46:22 +01:00
//dsyslog("[softhddev]%s %s, %s\n", __FUNCTION__, keymap, key);
if (key[1]) { // no single character
csoft->Put(key, repeat, release);
} else if (!csoft->Put(key, repeat, release)) {
cRemote::Put(KBDKEY(key[0])); // feed it for edit mode
}
2011-12-07 14:37:51 +01:00
}
//////////////////////////////////////////////////////////////////////////////
// OSD
//////////////////////////////////////////////////////////////////////////////
2012-02-16 15:31:53 +01:00
/**
** Soft device plugin OSD class.
*/
2011-12-07 14:37:51 +01:00
class cSoftOsd:public cOsd
{
public:
2012-03-10 17:46:00 +01:00
static volatile char Dirty; ///< flag force redraw everything
cSoftOsd(int, int, uint); ///< constructor
virtual ~ cSoftOsd(void); ///< destructor
virtual void Flush(void); ///< commits all data to the hardware
virtual void SetActive(bool); ///< sets OSD to be the active one
2011-12-07 14:37:51 +01:00
};
2012-03-10 17:46:00 +01:00
volatile char cSoftOsd::Dirty; ///< flag force redraw everything
/**
** Sets this OSD to be the active one.
**
** @param on true on, false off
**
** @note only needed as workaround for text2skin plugin with
** undrawn areas.
*/
void cSoftOsd::SetActive(bool on)
{
2012-02-16 15:31:53 +01:00
//dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on);
if (Active() == on) {
return; // already active, no action
}
cOsd::SetActive(on);
if (on) {
2012-03-10 17:46:00 +01:00
Dirty = 1;
} else {
OsdClose();
}
}
2012-03-10 17:46:00 +01:00
/**
** Constructor OSD.
**
** Initializes the OSD with the given coordinates.
**
** @param left x-coordinate of osd on display
** @param top y-coordinate of osd on display
** @param level level of the osd (smallest is shown)
*/
2011-12-07 14:37:51 +01:00
cSoftOsd::cSoftOsd(int left, int top, uint level)
:cOsd(left, top, level)
{
2012-01-21 15:56:45 +01:00
/* FIXME: OsdWidth/OsdHeight not correct!
dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(),
OsdHeight(), left, top, level);
*/
2011-12-07 14:37:51 +01:00
2012-01-21 15:56:45 +01:00
SetActive(true);
2011-12-07 14:37:51 +01:00
}
2012-03-10 17:46:00 +01:00
/**
** OSD Destructor.
**
** Shuts down the OSD.
*/
2011-12-07 14:37:51 +01:00
cSoftOsd::~cSoftOsd(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
SetActive(false);
// done by SetActive: OsdClose();
2011-12-07 14:37:51 +01:00
#ifdef USE_YAEPG
// support yaepghd, video window
if (vidWin.bpp) { // restore fullsized video
int width;
int height;
double video_aspect;
::GetOsdSize(&width, &height, &video_aspect);
// works osd relative
VideoSetOutputPosition(0, 0, width, height);
}
#endif
2011-12-07 14:37:51 +01:00
}
/**
** Actually commits all data to the OSD hardware.
*/
2011-12-07 14:37:51 +01:00
void cSoftOsd::Flush(void)
{
cPixmapMemory *pm;
if (!Active()) {
return;
}
#ifdef USE_YAEPG
// support yaepghd, video window
if (vidWin.bpp) {
dsyslog("[softhddev]%s: %dx%d+%d+%d\n", __FUNCTION__, vidWin.Width(),
vidWin.Height(), vidWin.x1, vidWin.y2);
// FIXME: vidWin is OSD relative not video window.
VideoSetOutputPosition(Left() + vidWin.x1, Top() + vidWin.y1,
vidWin.Width(), vidWin.Height());
}
#endif
2011-12-07 14:37:51 +01:00
if (!IsTrueColor()) {
static char warned;
cBitmap *bitmap;
int i;
if (!warned) {
dsyslog("[softhddev]%s: FIXME: should be truecolor\n",
__FUNCTION__);
warned = 1;
}
// draw all bitmaps
for (i = 0; (bitmap = GetBitmap(i)); ++i) {
uint8_t *argb;
int x;
int y;
int w;
int h;
int x1;
int y1;
int x2;
int y2;
// get dirty bounding box
2012-03-10 17:46:00 +01:00
if (Dirty) { // forced complete update
x1 = 0;
y1 = 0;
x2 = bitmap->Width() - 1;
y2 = bitmap->Height() - 1;
} else if (!bitmap->Dirty(x1, y1, x2, y2)) {
2011-12-07 14:37:51 +01:00
continue; // nothing dirty continue
}
// convert and upload only dirty areas
w = x2 - x1 + 1;
h = y2 - y1 + 1;
if (1) { // just for the case it makes trouble
int width;
int height;
double video_aspect;
::GetOsdSize(&width, &height, &video_aspect);
if (w > width) {
w = width;
x2 = x1 + width - 1;
}
if (h > height) {
h = height;
y2 = y1 + height - 1;
}
}
#ifdef DEBUG
if (w > bitmap->Width() || h > bitmap->Height()) {
esyslog(tr("[softhddev]: dirty area too big\n"));
abort();
2012-01-12 18:55:07 +01:00
}
#endif
argb = (uint8_t *) malloc(w * h * sizeof(uint32_t));
for (y = y1; y <= y2; ++y) {
for (x = x1; x <= x2; ++x) {
((uint32_t *) argb)[x - x1 + (y - y1) * w] =
bitmap->GetColor(x, y);
}
}
OsdDrawARGB(Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1,
w, h, argb);
2011-12-07 14:37:51 +01:00
bitmap->Clean();
// FIXME: reuse argb
2011-12-07 14:37:51 +01:00
free(argb);
}
2012-03-10 17:46:00 +01:00
cSoftOsd::Dirty = 0;
2011-12-07 14:37:51 +01:00
return;
}
LOCK_PIXMAPS;
while ((pm = RenderPixmaps())) {
int x;
int y;
int w;
int h;
x = Left() + pm->ViewPort().X();
y = Top() + pm->ViewPort().Y();
w = pm->ViewPort().Width();
h = pm->ViewPort().Height();
/*
2012-01-20 21:46:22 +01:00
dsyslog("[softhddev]%s: draw %dx%d+%d+%d %p\n", __FUNCTION__, w, h,
x, y, pm->Data());
*/
2011-12-07 14:37:51 +01:00
OsdDrawARGB(x, y, w, h, pm->Data());
delete pm;
}
}
//////////////////////////////////////////////////////////////////////////////
// OSD provider
//////////////////////////////////////////////////////////////////////////////
2012-02-16 15:31:53 +01:00
/**
** Soft device plugin OSD provider class.
*/
2011-12-07 14:37:51 +01:00
class cSoftOsdProvider:public cOsdProvider
{
private:
static cOsd *Osd;
public:
virtual cOsd * CreateOsd(int, int, uint);
virtual bool ProvidesTrueColor(void);
cSoftOsdProvider(void);
};
cOsd *cSoftOsdProvider::Osd; ///< single osd
2011-12-07 14:37:51 +01:00
/**
** Create a new OSD.
**
** @param left x-coordinate of OSD
** @param top y-coordinate of OSD
** @param level layer level of OSD
2011-12-07 14:37:51 +01:00
*/
cOsd *cSoftOsdProvider::CreateOsd(int left, int top, uint level)
{
//dsyslog("[softhddev]%s: %d, %d, %d\n", __FUNCTION__, left, top, level);
2011-12-07 14:37:51 +01:00
2012-02-16 15:31:53 +01:00
return Osd = new cSoftOsd(left, top, level);
2011-12-07 14:37:51 +01:00
}
/**
2012-02-16 15:31:53 +01:00
** Check if this OSD provider is able to handle a true color OSD.
**
** @returns true we are able to handle a true color OSD.
2011-12-07 14:37:51 +01:00
*/
bool cSoftOsdProvider::ProvidesTrueColor(void)
{
return true;
}
/**
** Create cOsdProvider class.
*/
2011-12-07 14:37:51 +01:00
cSoftOsdProvider::cSoftOsdProvider(void)
: cOsdProvider()
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
}
//////////////////////////////////////////////////////////////////////////////
// cMenuSetupPage
//////////////////////////////////////////////////////////////////////////////
2012-02-19 19:22:03 +01:00
/**
** Soft device plugin menu setup page class.
*/
2011-12-07 14:37:51 +01:00
class cMenuSetupSoft:public cMenuSetupPage
{
protected:
2012-02-19 19:22:03 +01:00
///
/// local copies of global setup variables:
/// @{
2011-12-07 14:37:51 +01:00
int MakePrimary;
int HideMainMenuEntry;
uint32_t Background;
uint32_t BackgroundAlpha;
int SkipLines;
2012-03-26 20:49:18 +02:00
int SkipPixels;
int StudioLevels;
int _60HzMode;
int SoftStartSync;
int Scaling[RESOLUTIONS];
int Deinterlace[RESOLUTIONS];
int SkipChromaDeinterlace[RESOLUTIONS];
int InverseTelecine[RESOLUTIONS];
int Denoise[RESOLUTIONS];
int Sharpen[RESOLUTIONS];
int AudioDelay;
int AudioPassthrough;
2012-02-21 22:24:28 +01:00
int AudioDownmix;
2012-01-20 15:33:37 +01:00
int AutoCropInterval;
int AutoCropDelay;
2012-01-27 23:49:05 +01:00
int AutoCropTolerance;
int SuspendClose;
int SuspendX11;
2012-02-19 19:22:03 +01:00
/// @}
2011-12-07 14:37:51 +01:00
protected:
virtual void Store(void);
public:
cMenuSetupSoft(void);
};
/**
** Create a seperator item.
2012-01-20 15:33:37 +01:00
**
** @param label text inside separator
*/
static inline cOsdItem *SeparatorItem(const char *label)
{
cOsdItem *item;
item = new cOsdItem(cString::sprintf("* %s: ", label));
item->SetSelectable(false);
return item;
}
2011-12-07 14:37:51 +01:00
/**
** Constructor setup menu.
*/
cMenuSetupSoft::cMenuSetupSoft(void)
{
static const char *const deinterlace[] = {
"Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software Bob",
"Software Spatial",
};
static const char *const scaling[] = {
"Normal", "Fast", "HQ", "Anamorphic"
};
static const char *const passthrough[] = {
"None", "AC-3"
};
static const char *const resolution[RESOLUTIONS] = {
"576i", "720p", "fake 1080i", "1080i"
};
int i;
2011-12-07 14:37:51 +01:00
// cMenuEditBoolItem cMenuEditBitItem cMenuEditNumItem
// cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem
MakePrimary = ConfigMakePrimary;
2011-12-07 14:37:51 +01:00
Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary,
2012-01-19 00:16:15 +01:00
trVDR("no"), trVDR("yes")));
HideMainMenuEntry = ConfigHideMainMenuEntry;
Add(new cMenuEditBoolItem(tr("Hide main menu entry"), &HideMainMenuEntry,
2012-01-19 00:16:15 +01:00
trVDR("no"), trVDR("yes")));
//
// video
//
Add(SeparatorItem(tr("Video")));
// no unsigned int menu item supported, split background color/alpha
Background = ConfigVideoBackground >> 8;
BackgroundAlpha = ConfigVideoBackground & 0xFF;
Add(new cMenuEditIntItem(tr("video background color (RGB)"),
(int *)&Background, 0, 0x00FFFFFF));
Add(new cMenuEditIntItem(tr("video background color (Alpha)"),
(int *)&BackgroundAlpha, 0, 0xFF));
SkipLines = ConfigVideoSkipLines;
Add(new cMenuEditIntItem(tr("Skip lines top+bot (pixel)"), &SkipLines, 0,
64));
2012-03-26 20:49:18 +02:00
SkipPixels = ConfigVideoSkipPixels;
Add(new cMenuEditIntItem(tr("Skip pixels left+right (pixel)"), &SkipPixels,
0, 64));
StudioLevels = ConfigVideoStudioLevels;
Add(new cMenuEditBoolItem(tr("Use studio levels (vdpau only)"),
&StudioLevels, trVDR("no"), trVDR("yes")));
_60HzMode = ConfigVideo60HzMode;
Add(new cMenuEditBoolItem(tr("60hz display mode"), &_60HzMode, trVDR("no"),
trVDR("yes")));
SoftStartSync = ConfigVideoSoftStartSync;
Add(new cMenuEditBoolItem(tr("soft start a/v sync"), &SoftStartSync,
trVDR("no"), trVDR("yes")));
for (i = 0; i < RESOLUTIONS; ++i) {
Add(SeparatorItem(resolution[i]));
Scaling[i] = ConfigVideoScaling[i];
Add(new cMenuEditStraItem(tr("Scaling"), &Scaling[i], 4, scaling));
Deinterlace[i] = ConfigVideoDeinterlace[i];
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace[i], 6,
deinterlace));
SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i];
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),
2012-01-19 00:16:15 +01:00
&SkipChromaDeinterlace[i], trVDR("no"), trVDR("yes")));
InverseTelecine[i] = ConfigVideoInverseTelecine[i];
Add(new cMenuEditBoolItem(tr("Inverse Telecine (vdpau)"),
&InverseTelecine[i], trVDR("no"), trVDR("yes")));
Denoise[i] = ConfigVideoDenoise[i];
Add(new cMenuEditIntItem(tr("Denoise (0..1000) (vdpau)"), &Denoise[i],
0, 1000, tr("off"), tr("max")));
Sharpen[i] = ConfigVideoSharpen[i];
Add(new cMenuEditIntItem(tr("Sharpen (-1000..1000) (vdpau)"),
&Sharpen[i], -1000, 1000, tr("blur max"), tr("sharpen max")));
}
//
// audio
//
Add(SeparatorItem(tr("Audio")));
AudioDelay = ConfigVideoAudioDelay;
Add(new cMenuEditIntItem(tr("Audio delay (ms)"), &AudioDelay, -1000,
1000));
AudioPassthrough = ConfigAudioPassthrough;
Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2,
passthrough));
2012-02-21 22:24:28 +01:00
AudioDownmix = ConfigAudioDownmix;
Add(new cMenuEditBoolItem(tr("Enable AC-3 downmix"), &AudioDownmix,
trVDR("no"), trVDR("yes")));
2012-01-20 15:33:37 +01:00
//
// auto-crop
//
Add(SeparatorItem(tr("Auto-crop")));
AutoCropInterval = ConfigAutoCropInterval;
Add(new cMenuEditIntItem(tr("autocrop interval (frames)"),
&AutoCropInterval, 0, 200, tr("off")));
2012-01-20 15:33:37 +01:00
AutoCropDelay = ConfigAutoCropDelay;
Add(new cMenuEditIntItem(tr("autocrop delay (n * interval)"),
&AutoCropDelay, 0, 200));
2012-01-27 23:49:05 +01:00
AutoCropTolerance = ConfigAutoCropTolerance;
Add(new cMenuEditIntItem(tr("autocrop tolerance (pixel)"),
&AutoCropTolerance, 0, 32));
//
// suspend
//
Add(SeparatorItem(tr("Suspend")));
SuspendClose = ConfigSuspendClose;
Add(new cMenuEditBoolItem(tr("suspend closes video+audio"), &SuspendClose,
trVDR("no"), trVDR("yes")));
SuspendX11 = ConfigSuspendX11;
Add(new cMenuEditBoolItem(tr("suspend stops x11"), &SuspendX11,
trVDR("no"), trVDR("yes")));
2011-12-07 14:37:51 +01:00
}
/**
** Store setup.
*/
void cMenuSetupSoft::Store(void)
{
int i;
2011-12-17 19:25:08 +01:00
SetupStore("MakePrimary", ConfigMakePrimary = MakePrimary);
SetupStore("HideMainMenuEntry", ConfigHideMainMenuEntry =
HideMainMenuEntry);
ConfigVideoBackground = Background << 8 | (BackgroundAlpha & 0xFF);
SetupStore("Background", ConfigVideoBackground);
VideoSetBackground(ConfigVideoBackground);
SetupStore("SkipLines", ConfigVideoSkipLines = SkipLines);
VideoSetSkipLines(ConfigVideoSkipLines);
2012-03-26 20:49:18 +02:00
SetupStore("SkipPixels", ConfigVideoSkipPixels = SkipPixels);
VideoSetSkipPixels(ConfigVideoSkipPixels);
SetupStore("StudioLevels", ConfigVideoStudioLevels = StudioLevels);
VideoSetStudioLevels(ConfigVideoStudioLevels);
SetupStore("60HzMode", ConfigVideo60HzMode = _60HzMode);
VideoSet60HzMode(ConfigVideo60HzMode);
SetupStore("SoftStartSync", ConfigVideoSoftStartSync = SoftStartSync);
VideoSetSoftStartSync(ConfigVideoSoftStartSync);
for (i = 0; i < RESOLUTIONS; ++i) {
char buf[128];
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
SetupStore(buf, ConfigVideoScaling[i] = Scaling[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Deinterlace");
SetupStore(buf, ConfigVideoDeinterlace[i] = Deinterlace[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i],
"SkipChromaDeinterlace");
SetupStore(buf, ConfigVideoSkipChromaDeinterlace[i] =
SkipChromaDeinterlace[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "InverseTelecine");
SetupStore(buf, ConfigVideoInverseTelecine[i] = InverseTelecine[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise");
SetupStore(buf, ConfigVideoDenoise[i] = Denoise[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Sharpen");
SetupStore(buf, ConfigVideoSharpen[i] = Sharpen[i]);
}
VideoSetScaling(ConfigVideoScaling);
2011-12-17 19:25:08 +01:00
VideoSetDeinterlace(ConfigVideoDeinterlace);
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
VideoSetInverseTelecine(ConfigVideoInverseTelecine);
VideoSetDenoise(ConfigVideoDenoise);
VideoSetSharpen(ConfigVideoSharpen);
SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay);
VideoSetAudioDelay(ConfigVideoAudioDelay);
SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough);
CodecSetAudioPassthrough(ConfigAudioPassthrough);
2012-02-21 22:24:28 +01:00
SetupStore("AudioDownmix", ConfigAudioDownmix = AudioDownmix);
CodecSetAudioDownmix(ConfigAudioDownmix);
2012-01-20 15:33:37 +01:00
SetupStore("AutoCrop.Interval", ConfigAutoCropInterval = AutoCropInterval);
SetupStore("AutoCrop.Delay", ConfigAutoCropDelay = AutoCropDelay);
SetupStore("AutoCrop.Tolerance", ConfigAutoCropTolerance =
AutoCropTolerance);
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay,
ConfigAutoCropTolerance);
SetupStore("Suspend.Close", ConfigSuspendClose = SuspendClose);
SetupStore("Suspend.X11", ConfigSuspendX11 = SuspendX11);
2011-12-07 14:37:51 +01:00
}
//////////////////////////////////////////////////////////////////////////////
// cPlayer
//////////////////////////////////////////////////////////////////////////////
/**
** Dummy player for suspend mode.
*/
class cSoftHdPlayer:public cPlayer
{
protected:
public:
cSoftHdPlayer(void);
virtual ~ cSoftHdPlayer();
};
cSoftHdPlayer::cSoftHdPlayer(void)
{
}
cSoftHdPlayer::~cSoftHdPlayer()
{
Detach();
}
//////////////////////////////////////////////////////////////////////////////
// cControl
//////////////////////////////////////////////////////////////////////////////
/**
** Dummy control class for suspend mode.
*/
class cSoftHdControl:public cControl
{
public:
static cSoftHdPlayer *Player; ///< dummy player
virtual void Hide(void) ///< hide control
{
}
virtual eOSState ProcessKey(eKeys); ///< process input events
cSoftHdControl(void); ///< control constructor
virtual ~ cSoftHdControl(); ///< control destructor
};
cSoftHdPlayer *cSoftHdControl::Player; ///< dummy player instance
/**
** Handle a key event.
**
** @param key key pressed
*/
eOSState cSoftHdControl::ProcessKey(eKeys key)
{
2012-03-01 22:12:22 +01:00
if (SuspendMode == SUSPEND_NORMAL && (!ISMODELESSKEY(key)
|| key == kMenu || key == kBack || key == kStop)) {
if (Player) {
delete Player;
Player = NULL;
}
Resume();
SuspendMode = NOT_SUSPENDED;
return osEnd;
}
return osContinue;
}
2012-02-19 19:22:03 +01:00
/**
** Player control constructor.
*/
cSoftHdControl::cSoftHdControl(void)
: cControl(Player = new cSoftHdPlayer)
{
}
2012-02-19 19:22:03 +01:00
/**
** Player control destructor.
*/
cSoftHdControl::~cSoftHdControl()
{
if (Player) {
delete Player;
Player = NULL;
}
2012-03-01 22:12:22 +01:00
dsyslog("[softhddev]%s: dummy player stopped\n", __FUNCTION__);
}
2012-02-19 19:22:03 +01:00
//////////////////////////////////////////////////////////////////////////////
// cOsdMenu
//////////////////////////////////////////////////////////////////////////////
/**
** Soft device plugin menu class.
*/
class cSoftHdMenu:public cOsdMenu
{
int HotkeyState; ///< current hot-key state
int HotkeyCode; ///< current hot-key code
public:
cSoftHdMenu(const char *, int = 0, int = 0, int = 0, int = 0, int = 0);
virtual ~ cSoftHdMenu();
virtual eOSState ProcessKey(eKeys);
};
/**
** Soft device menu constructor.
*/
cSoftHdMenu::cSoftHdMenu(const char *title, int c0, int c1, int c2, int c3,
int c4)
:cOsdMenu(title, c0, c1, c2, c3, c4)
{
HotkeyState = 0;
SetHasHotkeys();
Add(new cOsdItem(hk(tr("Suspend SoftHdDevice")), osUser1));
}
/**
** Soft device menu destructor.
*/
cSoftHdMenu::~cSoftHdMenu()
{
}
/**
** Handle hot key commands.
**
** @param code numeric hot key code
2012-02-19 19:22:03 +01:00
*/
static void HandleHotkey(int code)
{
switch (code) {
case 10: // disable pass-through
CodecSetAudioPassthrough(ConfigAudioPassthrough = 0);
break;
case 11: // enable pass-through
CodecSetAudioPassthrough(ConfigAudioPassthrough = 1);
break;
case 12: // toggle pass-through
CodecSetAudioPassthrough(ConfigAudioPassthrough ^= 1);
break;
default:
esyslog(tr("[softhddev]: hot key %d is not supported\n"), code);
2012-02-19 19:22:03 +01:00
break;
}
}
/**
** Handle key event.
**
** @param key key event
*/
eOSState cSoftHdMenu::ProcessKey(eKeys key)
{
eOSState state;
//dsyslog("[softhddev]%s: %x\n", __FUNCTION__, key);
switch (HotkeyState) {
case 0: // initial state, waiting for hot key
if (key == kBlue) {
HotkeyState = 1;
return osContinue;
}
break;
case 1:
if (k0 <= key && key <= k9) {
HotkeyCode = key - k0;
HotkeyState = 2;
return osContinue;
}
HotkeyState = 0;
break;
case 2:
if (k0 <= key && key <= k9) {
HotkeyCode *= 10;
HotkeyCode += key - k0;
HotkeyState = 0;
dsyslog("[softhddev]%s: hot-key %d\n", __FUNCTION__,
HotkeyCode);
HandleHotkey(HotkeyCode);
return osEnd;
}
if (key == kOk) {
HotkeyState = 0;
dsyslog("[softhddev]%s: hot-key %d\n", __FUNCTION__,
HotkeyCode);
HandleHotkey(HotkeyCode);
return osEnd;
}
HotkeyState = 0;
break;
}
// call standard function
state = cOsdMenu::ProcessKey(key);
switch (state) {
case osUser1:
// not already suspended
if (SuspendMode == NOT_SUSPENDED && !cSoftHdControl::Player) {
2012-02-19 19:22:03 +01:00
cControl::Launch(new cSoftHdControl);
cControl::Attach();
Suspend(ConfigSuspendClose, ConfigSuspendClose,
ConfigSuspendX11);
SuspendMode = SUSPEND_NORMAL;
2012-02-19 19:22:03 +01:00
if (ShutdownHandler.GetUserInactiveTime()) {
dsyslog("[softhddev]%s: set user inactive\n",
__FUNCTION__);
ShutdownHandler.SetUserInactive();
}
}
return osEnd;
default:
break;
}
return state;
}
2011-12-07 14:37:51 +01:00
//////////////////////////////////////////////////////////////////////////////
// cDevice
//////////////////////////////////////////////////////////////////////////////
class cSoftHdDevice:public cDevice
{
public:
cSoftHdDevice(void);
2012-02-19 19:22:03 +01:00
virtual ~ cSoftHdDevice(void);
2011-12-07 14:37:51 +01:00
virtual bool HasDecoder(void) const;
virtual bool CanReplay(void) const;
virtual bool SetPlayMode(ePlayMode);
virtual void TrickSpeed(int);
virtual void Clear(void);
virtual void Play(void);
virtual void Freeze(void);
virtual void Mute(void);
virtual void StillPicture(const uchar *, int);
virtual bool Poll(cPoller &, int = 0);
virtual bool Flush(int = 0);
virtual int64_t GetSTC(void);
virtual void SetVideoDisplayFormat(eVideoDisplayFormat);
virtual void SetVideoFormat(bool);
virtual void GetVideoSize(int &, int &, double &);
2011-12-07 14:37:51 +01:00
virtual void GetOsdSize(int &, int &, double &);
virtual int PlayVideo(const uchar *, int);
virtual int PlayAudio(const uchar *, int, uchar);
#ifdef USE_TS_VIDEO
virtual int PlayTsVideo(const uchar *, int);
#endif
#if !defined(USE_AUDIO_THREAD) || !defined(NO_TS_AUDIO)
virtual int PlayTsAudio(const uchar *, int);
#endif
2011-12-07 14:37:51 +01:00
virtual void SetAudioChannelDevice(int);
virtual int GetAudioChannelDevice(void);
virtual void SetDigitalAudioDevice(bool);
virtual void SetAudioTrackDevice(eTrackType);
2012-02-12 20:14:43 +01:00
virtual void SetVolumeDevice(int);
2011-12-07 14:37:51 +01:00
// Image Grab facilities
virtual uchar *GrabImage(int &, bool, int, int, int);
2012-01-12 18:55:07 +01:00
#if 0
2011-12-07 14:37:51 +01:00
// SPU facilities
private:
2012-02-19 19:22:03 +01:00
cDvbSpuDecoder * spuDecoder;
2011-12-07 14:37:51 +01:00
public:
2012-02-19 19:22:03 +01:00
virtual cSpuDecoder * GetSpuDecoder(void);
2012-01-12 18:55:07 +01:00
#endif
2011-12-07 14:37:51 +01:00
protected:
2012-02-19 19:22:03 +01:00
virtual void MakePrimaryDevice(bool);
2011-12-07 14:37:51 +01:00
};
cSoftHdDevice::cSoftHdDevice(void)
{
//dsyslog("[softhddev]%s\n", __FUNCTION__);
2012-01-12 18:55:07 +01:00
#if 0
spuDecoder = NULL;
2012-01-12 18:55:07 +01:00
#endif
2011-12-07 14:37:51 +01:00
}
cSoftHdDevice::~cSoftHdDevice(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
}
2012-01-19 00:16:15 +01:00
/**
** Informs a device that it will be the primary device.
**
** @param on flag if becoming or loosing primary
*/
2011-12-07 14:37:51 +01:00
void cSoftHdDevice::MakePrimaryDevice(bool on)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on);
cDevice::MakePrimaryDevice(on);
if (on) {
new cSoftOsdProvider();
2012-03-02 00:22:08 +01:00
if (SuspendMode == SUSPEND_DETACHED) {
Resume();
SuspendMode = NOT_SUSPENDED;
2012-03-02 00:22:08 +01:00
}
} else if (SuspendMode == NOT_SUSPENDED) {
2012-03-02 00:22:08 +01:00
Suspend(1, 1, 0);
SuspendMode = SUSPEND_DETACHED;
2011-12-07 14:37:51 +01:00
}
}
2012-01-12 18:55:07 +01:00
#if 0
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
2011-12-07 14:37:51 +01:00
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
if (IsPrimaryDevice() && !spuDecoder) {
spuDecoder = new cDvbSpuDecoder();
}
return spuDecoder;
2011-12-14 18:01:03 +01:00
}
2011-12-07 14:37:51 +01:00
2012-01-12 18:55:07 +01:00
#endif
2012-03-10 17:46:00 +01:00
/**
** Tells whether this device has a MPEG decoder.
*/
2011-12-07 14:37:51 +01:00
bool cSoftHdDevice::HasDecoder(void) const
{
return true;
}
/**
** Returns true if this device can currently start a replay session.
*/
2011-12-07 14:37:51 +01:00
bool cSoftHdDevice::CanReplay(void) const
{
return true;
}
/**
2012-03-01 22:12:22 +01:00
** Sets the device into the given play mode.
**
** @param play_mode new play mode (Audio/Video/External...)
*/
bool cSoftHdDevice::SetPlayMode(ePlayMode play_mode)
2011-12-07 14:37:51 +01:00
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, play_mode);
2011-12-07 14:37:51 +01:00
switch (play_mode) {
2011-12-07 14:37:51 +01:00
case pmAudioVideo:
break;
case pmAudioOnly:
case pmAudioOnlyBlack:
break;
case pmVideoOnly:
break;
case pmNone:
2012-01-11 18:01:18 +01:00
return true;
2011-12-07 14:37:51 +01:00
case pmExtern_THIS_SHOULD_BE_AVOIDED:
dsyslog("[softhddev] play mode external\n");
2012-01-26 15:00:49 +01:00
Suspend(1, 1, 0);
SuspendMode = SUSPEND_EXTERNAL;
2012-01-26 15:00:49 +01:00
return true;
2011-12-07 14:37:51 +01:00
default:
dsyslog("[softhddev] playmode not implemented... %d\n", play_mode);
2011-12-07 14:37:51 +01:00
break;
}
if (SuspendMode != NOT_SUSPENDED) {
2012-03-01 22:12:22 +01:00
if (SuspendMode != SUSPEND_EXTERNAL) {
return false;
2012-03-01 22:12:22 +01:00
}
Resume();
SuspendMode = NOT_SUSPENDED;
2012-03-01 22:12:22 +01:00
}
return::SetPlayMode(play_mode);
2011-12-07 14:37:51 +01:00
}
/**
** Gets the current System Time Counter, which can be used to
** synchronize audio, video and subtitles.
*/
2011-12-14 18:01:03 +01:00
int64_t cSoftHdDevice::GetSTC(void)
{
2012-01-22 17:07:08 +01:00
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-14 18:01:03 +01:00
return::GetSTC();
2011-12-14 18:01:03 +01:00
}
2012-01-08 21:46:00 +01:00
/**
** Set trick play speed.
**
2012-02-16 15:31:53 +01:00
** Every single frame shall then be displayed the given number of
** times.
**
2012-01-08 21:46:00 +01:00
** @param speed trick speed
*/
void cSoftHdDevice::TrickSpeed(int speed)
2011-12-07 14:37:51 +01:00
{
2012-01-08 21:46:00 +01:00
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, speed);
2012-02-16 15:31:53 +01:00
::TrickSpeed(speed);
2011-12-07 14:37:51 +01:00
}
2012-02-16 15:31:53 +01:00
/**
** Clears all video and audio data from the device.
*/
2011-12-07 14:37:51 +01:00
void cSoftHdDevice::Clear(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-14 18:01:03 +01:00
cDevice::Clear();
::Clear();
2011-12-07 14:37:51 +01:00
}
2012-02-16 15:31:53 +01:00
/**
** Sets the device into play mode (after a previous trick mode)
*/
2011-12-07 14:37:51 +01:00
void cSoftHdDevice::Play(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-14 18:01:03 +01:00
cDevice::Play();
::Play();
2011-12-07 14:37:51 +01:00
}
/**
** Puts the device into "freeze frame" mode.
*/
2011-12-07 14:37:51 +01:00
void cSoftHdDevice::Freeze(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-14 18:01:03 +01:00
cDevice::Freeze();
::Freeze();
2011-12-07 14:37:51 +01:00
}
2012-02-12 20:14:43 +01:00
/**
** Turns off audio while replaying.
*/
2011-12-07 14:37:51 +01:00
void cSoftHdDevice::Mute(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
cDevice::Mute();
::Mute();
}
2012-01-08 21:46:00 +01:00
/**
** Display the given I-frame as a still picture.
2012-03-10 17:46:00 +01:00
**
** @param data pes or ts data of a frame
** @param length length of data area
2012-01-08 21:46:00 +01:00
*/
void cSoftHdDevice::StillPicture(const uchar * data, int length)
2011-12-07 14:37:51 +01:00
{
2012-01-24 16:37:11 +01:00
dsyslog("[softhddev]%s: %s %p %d\n", __FUNCTION__,
data[0] == 0x47 ? "ts" : "pes", data, length);
2012-01-08 21:46:00 +01:00
if (data[0] == 0x47) { // ts sync
2012-01-08 21:46:00 +01:00
cDevice::StillPicture(data, length);
return;
}
::StillPicture(data, length);
2011-12-07 14:37:51 +01:00
}
2012-01-08 21:46:00 +01:00
/**
** Check if the device is ready for further action.
**
** @param poller file handles (unused)
** @param timeout_ms timeout in ms to become ready
**
** @retval true if ready
** @retval false if busy
2012-01-08 21:46:00 +01:00
*/
2011-12-07 14:37:51 +01:00
bool cSoftHdDevice::Poll(
__attribute__ ((unused)) cPoller & poller, int timeout_ms)
2011-12-07 14:37:51 +01:00
{
2012-01-22 17:07:08 +01:00
//dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms);
return::Poll(timeout_ms);
2011-12-07 14:37:51 +01:00
}
2012-01-08 21:46:00 +01:00
/**
** Flush the device output buffers.
**
** @param timeout_ms timeout in ms to become ready
*/
2011-12-14 18:01:03 +01:00
bool cSoftHdDevice::Flush(int timeout_ms)
2011-12-07 14:37:51 +01:00
{
2011-12-14 18:01:03 +01:00
dsyslog("[softhddev]%s: %d ms\n", __FUNCTION__, timeout_ms);
2012-01-08 21:46:00 +01:00
return::Flush(timeout_ms);
2011-12-14 18:01:03 +01:00
}
2011-12-07 14:37:51 +01:00
// ----------------------------------------------------------------------------
/**
** Sets the video display format to the given one (only useful if this
** device has an MPEG decoder).
*/
void cSoftHdDevice:: SetVideoDisplayFormat(eVideoDisplayFormat
video_display_format)
{
static int last = -1;
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, video_display_format);
cDevice::SetVideoDisplayFormat(video_display_format);
// called on every channel switch, no need to kill osd...
if (last != video_display_format) {
last = video_display_format;
::VideoSetDisplayFormat(video_display_format);
2012-03-10 17:46:00 +01:00
cSoftOsd::Dirty = 1;
}
}
/**
** Sets the output video format to either 16:9 or 4:3 (only useful
** if this device has an MPEG decoder).
**
** Should call SetVideoDisplayFormat.
**
** @param video_format16_9 flag true 16:9.
*/
void cSoftHdDevice::SetVideoFormat(bool video_format16_9)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, video_format16_9);
// FIXME: 4:3 / 16:9 video format not supported.
SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
}
2011-12-07 14:37:51 +01:00
/**
** Returns the width, height and video_aspect ratio of the currently
** displayed video material.
**
** @note the size is used to scale the subtitle.
*/
void cSoftHdDevice::GetVideoSize(int &width, int &height, double &video_aspect)
{
::GetOsdSize(&width, &height, &video_aspect);
}
/**
** Returns the width, height and pixel_aspect ratio the OSD.
2011-12-07 14:37:51 +01:00
**
** FIXME: Called every second, for nothing (no OSD displayed)?
*/
void cSoftHdDevice::GetOsdSize(int &width, int &height, double &pixel_aspect)
{
::GetOsdSize(&width, &height, &pixel_aspect);
}
// ----------------------------------------------------------------------------
2012-01-08 21:46:00 +01:00
/**
** Play a audio packet.
**
** @param data exactly one complete PES packet (which is incomplete)
** @param length length of PES packet
** @param id type of audio data this packet holds
2012-01-08 21:46:00 +01:00
*/
2011-12-07 14:37:51 +01:00
int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id)
{
//dsyslog("[softhddev]%s: %p %p %d %d\n", __FUNCTION__, this, data, length, id);
2012-01-08 21:46:00 +01:00
return::PlayAudio(data, length, id);
2011-12-07 14:37:51 +01:00
}
void cSoftHdDevice::SetAudioTrackDevice(
__attribute__ ((unused)) eTrackType type)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
}
void cSoftHdDevice::SetDigitalAudioDevice( __attribute__ ((unused)) bool on)
2011-12-07 14:37:51 +01:00
{
//dsyslog("[softhddev]%s: %s\n", __FUNCTION__, on ? "true" : "false");
2011-12-07 14:37:51 +01:00
}
void cSoftHdDevice::SetAudioChannelDevice( __attribute__ ((unused))
int audio_channel)
2011-12-07 14:37:51 +01:00
{
//dsyslog("[softhddev]%s: %d\n", __FUNCTION__, audio_channel);
2011-12-07 14:37:51 +01:00
}
int cSoftHdDevice::GetAudioChannelDevice(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
return 0;
}
2012-02-12 20:14:43 +01:00
/**
** Sets the audio volume on this device (Volume = 0...255).
**
** @param volume device volume
*/
void cSoftHdDevice::SetVolumeDevice(int volume)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
::SetVolumeDevice(volume);
}
2011-12-07 14:37:51 +01:00
// ----------------------------------------------------------------------------
/**
** Play a video packet.
**
** @param data exactly one complete PES packet (which is incomplete)
** @param length length of PES packet
*/
2011-12-07 14:37:51 +01:00
int cSoftHdDevice::PlayVideo(const uchar * data, int length)
{
//dsyslog("[softhddev]%s: %p %d\n", __FUNCTION__, data, length);
return::PlayVideo(data, length);
2011-12-07 14:37:51 +01:00
}
#ifdef USE_TS_VIDEO
2011-12-07 14:37:51 +01:00
///
/// Play a TS video packet.
///
/// @param data ts data buffer
/// @param length ts packet length (188)
///
2012-01-19 00:16:15 +01:00
int cSoftHdDevice::PlayTsVideo(const uchar * data, int length)
2011-12-07 14:37:51 +01:00
{
}
2011-12-07 14:37:51 +01:00
#endif
#if !defined(USE_AUDIO_THREAD) || !defined(NO_TS_AUDIO)
2012-01-19 00:16:15 +01:00
///
/// Play a TS audio packet.
///
2012-01-19 00:16:15 +01:00
/// @param data ts data buffer
/// @param length ts packet length (188)
2012-01-19 00:16:15 +01:00
///
int cSoftHdDevice::PlayTsAudio(const uchar * data, int length)
{
#ifndef NO_TS_AUDIO
2012-02-19 19:22:03 +01:00
return::PlayTsAudio(data, length);
#else
AudioPoller();
return cDevice::PlayTsAudio(data, length);
2012-02-19 19:22:03 +01:00
#endif
}
2012-01-19 00:16:15 +01:00
#endif
2012-01-20 21:46:22 +01:00
/**
** Grabs the currently visible screen image.
**
** @param size size of the returned data
** @param jpeg flag true, create JPEG data
** @param quality JPEG quality
** @param width number of horizontal pixels in the frame
** @param height number of vertical pixels in the frame
*/
uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int width,
int height)
2011-12-07 14:37:51 +01:00
{
dsyslog("[softhddev]%s: %d, %d, %d, %dx%d\n", __FUNCTION__, size, jpeg,
2012-01-20 21:46:22 +01:00
quality, width, height);
2011-12-07 14:37:51 +01:00
2012-01-21 15:56:45 +01:00
return::GrabImage(&size, jpeg, quality, width, height);
2011-12-14 18:01:03 +01:00
}
2011-12-07 14:37:51 +01:00
/**
** Call rgb to jpeg for C Plugin.
*/
extern "C" uint8_t * CreateJpeg(uint8_t * image, int *size, int quality,
int width, int height)
{
return (uint8_t *) RgbToJpeg((uchar *) image, width, height, *size,
quality);
}
2011-12-07 14:37:51 +01:00
//////////////////////////////////////////////////////////////////////////////
// cPlugin
//////////////////////////////////////////////////////////////////////////////
class cPluginSoftHdDevice:public cPlugin
{
public:
cPluginSoftHdDevice(void);
virtual ~ cPluginSoftHdDevice(void);
virtual const char *Version(void);
virtual const char *Description(void);
virtual const char *CommandLineHelp(void);
virtual bool ProcessArgs(int, char *[]);
virtual bool Initialize(void);
virtual bool Start(void);
virtual void Stop(void);
virtual void Housekeeping(void);
2011-12-07 14:37:51 +01:00
virtual void MainThreadHook(void);
virtual const char *MainMenuEntry(void);
virtual cOsdObject *MainMenuAction(void);
2011-12-07 14:37:51 +01:00
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *, const char *);
2012-01-12 15:20:01 +01:00
// virtual bool Service(const char *, void * = NULL);
virtual const char **SVDRPHelpPages(void);
virtual cString SVDRPCommand(const char *, const char *, int &);
2011-12-07 14:37:51 +01:00
};
cPluginSoftHdDevice::cPluginSoftHdDevice(void)
{
// Initialize any member variables here.
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
}
cPluginSoftHdDevice::~cPluginSoftHdDevice(void)
{
// Clean up after yourself!
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
::SoftHdDeviceExit();
2011-12-07 14:37:51 +01:00
}
/**
** Return plugin version number.
**
** @returns version number as constant string.
*/
2011-12-07 14:37:51 +01:00
const char *cPluginSoftHdDevice::Version(void)
{
return VERSION;
}
const char *cPluginSoftHdDevice::Description(void)
{
return tr(DESCRIPTION);
}
/**
** Return a string that describes all known command line options.
*/
const char *cPluginSoftHdDevice::CommandLineHelp(void)
{
return::CommandLineHelp();
}
/**
** Process the command line arguments.
*/
bool cPluginSoftHdDevice::ProcessArgs(int argc, char *argv[])
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
return::ProcessArgs(argc, argv);
}
bool cPluginSoftHdDevice::Initialize(void)
{
// Start any background activities the plugin shall perform.
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
MyDevice = new cSoftHdDevice();
return true;
}
2012-01-11 18:01:18 +01:00
/**
** Start any background activities the plugin shall perform.
*/
2011-12-07 14:37:51 +01:00
bool cPluginSoftHdDevice::Start(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
2012-01-11 18:01:18 +01:00
if (!MyDevice->IsPrimaryDevice()) {
2011-12-07 14:37:51 +01:00
isyslog("[softhddev] softhddevice is not the primary device!");
if (ConfigMakePrimary) {
// Must be done in the main thread
dsyslog("[softhddev] makeing softhddevice %d the primary device!",
MyDevice->DeviceNumber());
DoMakePrimary = MyDevice->DeviceNumber() + 1;
2011-12-07 14:37:51 +01:00
} else {
isyslog("[softhddev] softhddevice %d is not the primary device!",
MyDevice->DeviceNumber());
}
}
if (!::Start()) {
cControl::Launch(new cSoftHdControl);
cControl::Attach();
SuspendMode = SUSPEND_NORMAL;
}
2011-12-07 14:37:51 +01:00
return true;
}
/**
** Shutdown plugin. Stop any background activities the plugin is
** performing.
*/
2011-12-07 14:37:51 +01:00
void cPluginSoftHdDevice::Stop(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
::Stop();
}
/**
** Perform any cleanup or other regular tasks.
*/
2011-12-07 14:37:51 +01:00
void cPluginSoftHdDevice::Housekeeping(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
// check if user is inactive, automatic enter suspend mode
// FIXME: cControl prevents shutdown, disable this until fixed
if (0 && SuspendMode == NOT_SUSPENDED && ShutdownHandler.IsUserInactive()) {
// don't overwrite already suspended suspend mode
cControl::Launch(new cSoftHdControl);
cControl::Attach();
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
SuspendMode = SUSPEND_NORMAL;
}
2011-12-07 14:37:51 +01:00
::Housekeeping();
}
/**
** Create main menu entry.
*/
2011-12-07 14:37:51 +01:00
const char *cPluginSoftHdDevice::MainMenuEntry(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
return ConfigHideMainMenuEntry ? NULL : tr(MAINMENUENTRY);
2011-12-07 14:37:51 +01:00
}
/**
** Perform the action when selected from the main VDR menu.
*/
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
{
2012-01-22 17:07:08 +01:00
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2012-02-19 19:22:03 +01:00
return new cSoftHdMenu("SoftHdDevice");
}
2011-12-07 14:37:51 +01:00
/**
** Called for every plugin once during every cycle of VDR's main program
** loop.
*/
void cPluginSoftHdDevice::MainThreadHook(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
if (DoMakePrimary) {
dsyslog("[softhddev]%s: switching primary device to %d\n",
__FUNCTION__, DoMakePrimary);
cDevice::SetPrimaryDevice(DoMakePrimary);
2011-12-07 14:37:51 +01:00
DoMakePrimary = 0;
}
2012-01-11 18:01:18 +01:00
2011-12-07 14:37:51 +01:00
::MainThreadHook();
}
/**
** Return our setup menu.
*/
cMenuSetupPage *cPluginSoftHdDevice::SetupMenu(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
2011-12-07 14:37:51 +01:00
return new cMenuSetupSoft;
}
/**
** Parse setup parameters
2012-01-20 15:33:37 +01:00
**
** @param name paramter name (case sensetive)
** @param value value as string
**
** @returns true if the parameter is supported.
2011-12-07 14:37:51 +01:00
*/
bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
{
int i;
//dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
2011-12-07 14:37:51 +01:00
if (!strcasecmp(name, "MakePrimary")) {
2011-12-07 14:37:51 +01:00
ConfigMakePrimary = atoi(value);
return true;
}
if (!strcasecmp(name, "HideMainMenuEntry")) {
ConfigHideMainMenuEntry = atoi(value);
return true;
}
if (!strcasecmp(name, "Background")) {
VideoSetBackground(ConfigVideoBackground = strtoul(value, NULL, 0));
return true;
}
if (!strcasecmp(name, "SkipLines")) {
VideoSetSkipLines(ConfigVideoSkipLines = atoi(value));
return true;
}
2012-03-26 20:49:18 +02:00
if (!strcasecmp(name, "SkipPixels")) {
VideoSetSkipPixels(ConfigVideoSkipPixels = atoi(value));
return true;
}
if (!strcasecmp(name, "StudioLevels")) {
VideoSetStudioLevels(ConfigVideoStudioLevels = atoi(value));
return true;
}
if (!strcasecmp(name, "60HzMode")) {
VideoSet60HzMode(ConfigVideo60HzMode = atoi(value));
return true;
}
if (!strcasecmp(name, "SoftStartSync")) {
VideoSetSoftStartSync(ConfigVideoSoftStartSync = atoi(value));
return true;
}
for (i = 0; i < RESOLUTIONS; ++i) {
2012-01-20 15:33:37 +01:00
char buf[128];
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
if (!strcasecmp(name, buf)) {
ConfigVideoScaling[i] = atoi(value);
VideoSetScaling(ConfigVideoScaling);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Deinterlace");
if (!strcasecmp(name, buf)) {
ConfigVideoDeinterlace[i] = atoi(value);
VideoSetDeinterlace(ConfigVideoDeinterlace);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i],
"SkipChromaDeinterlace");
if (!strcasecmp(name, buf)) {
ConfigVideoSkipChromaDeinterlace[i] = atoi(value);
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "InverseTelecine");
if (!strcasecmp(name, buf)) {
ConfigVideoInverseTelecine[i] = atoi(value);
VideoSetInverseTelecine(ConfigVideoInverseTelecine);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise");
if (!strcasecmp(name, buf)) {
ConfigVideoDenoise[i] = atoi(value);
VideoSetDenoise(ConfigVideoDenoise);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Sharpen");
if (!strcasecmp(name, buf)) {
ConfigVideoSharpen[i] = atoi(value);
VideoSetSharpen(ConfigVideoSharpen);
return true;
}
}
2012-01-20 15:33:37 +01:00
if (!strcasecmp(name, "AudioDelay")) {
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
return true;
}
if (!strcasecmp(name, "AudioPassthrough")) {
CodecSetAudioPassthrough(ConfigAudioPassthrough = atoi(value));
return true;
}
if (!strcasecmp(name, "AudioDownmix")) {
2012-02-21 22:24:28 +01:00
CodecSetAudioDownmix(ConfigAudioDownmix = atoi(value));
return true;
}
2011-12-07 14:37:51 +01:00
if (!strcasecmp(name, "AutoCrop.Interval")) {
2012-01-20 15:33:37 +01:00
VideoSetAutoCrop(ConfigAutoCropInterval =
2012-01-27 23:49:05 +01:00
atoi(value), ConfigAutoCropDelay, ConfigAutoCropTolerance);
2012-01-20 15:33:37 +01:00
return true;
}
if (!strcasecmp(name, "AutoCrop.Delay")) {
2012-01-20 15:33:37 +01:00
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay =
2012-01-27 23:49:05 +01:00
atoi(value), ConfigAutoCropTolerance);
return true;
}
if (!strcasecmp(name, "AutoCrop.Tolerance")) {
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay,
ConfigAutoCropTolerance = atoi(value));
2012-01-20 15:33:37 +01:00
return true;
}
if (!strcasecmp(name, "Suspend.Close")) {
ConfigSuspendClose = atoi(value);
return true;
}
if (!strcasecmp(name, "Suspend.X11")) {
ConfigSuspendX11 = atoi(value);
return true;
}
2011-12-07 14:37:51 +01:00
return false;
}
#if 0
bool cPluginSoftHdDevice::Service(const char *Id, void *Data)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
return false;
}
#endif
2012-01-12 15:20:01 +01:00
//----------------------------------------------------------------------------
// cPlugin SVDRP
//----------------------------------------------------------------------------
2012-03-14 15:07:08 +01:00
/**
** SVDRP commands help text.
** FIXME: translation?
*/
static const char *SVDRPHelpText[] = {
"SUSP\n" " Suspend plugin.\n\n"
" The plugin is suspended to save energie. Depending on the setup\n"
" 'softhddevice.Suspend.Close = 0' only the video and audio output\n"
" is stopped or with 'softhddevice.Suspend.Close = 1' the video\n"
" and audio devices are closed.\n"
" If 'softhddevice.Suspend.X11 = 1' is set and the X11 server was\n"
" started by the plugin, the X11 server would also be closed.\n"
" (Stopping X11 while suspended isn't supported yet)\n",
"RESU\n" " Resume plugin.\n\n"
" Resume the suspended plugin. The plugin could be suspended by\n"
" the command line option '-s' or by a previous SUSP command.\n"
" If the x11 server was stopped by the plugin, it will be\n"
" restarted.",
"DETA\n" " Detach plugin.\n\n"
" The plugin will be detached from the audio, video and DVB\n"
" devices. Other programs or plugins can use them now.\n",
"ATTA <-d display>\n" " Attach plugin.\n\n"
" Attach the plugin to audio, video and DVB devices.\n"
" Use -d display (f.e. -d :0.0) to use another X11 display.\n",
2012-03-14 15:07:08 +01:00
"PRIM <n>\n" " Make <n> the primary device.\n\n"
" <n> is the number of device. Without number softhddevice becomes\n"
" the primary device. If becoming primary, the plugin is attached\n"
" to the devices. If loosing primary, the plugin is detached from\n"
" the devices.",
"HOTK key\n" " Execute hotkey.\n\n"
" key is the hotkey number, following are supported:\n"
" 10: disable audio pass-through\n"
" 11: enable audio pass-through\n"
" 12: toggle audio pass-through\n",
NULL
};
2012-01-12 15:20:01 +01:00
/**
** Return SVDRP commands help pages.
**
** return a pointer to a list of help strings for all of the plugin's
** SVDRP commands.
*/
const char **cPluginSoftHdDevice::SVDRPHelpPages(void)
{
2012-03-14 15:07:08 +01:00
return SVDRPHelpText;
2012-01-12 15:20:01 +01:00
}
/**
** Handle SVDRP commands.
**
** @param command SVDRP command
** @param option all command arguments
** @param reply_code reply code
2012-01-12 15:20:01 +01:00
*/
cString cPluginSoftHdDevice::SVDRPCommand(const char *command,
2012-03-14 15:07:08 +01:00
const char *option, __attribute__ ((unused)) int &reply_code)
2012-01-12 15:20:01 +01:00
{
if (!strcasecmp(command, "SUSP")) {
if (cSoftHdControl::Player) { // already suspended
return "SoftHdDevice already suspended";
}
if (SuspendMode != NOT_SUSPENDED) {
return "SoftHdDevice already detached";
}
cControl::Launch(new cSoftHdControl);
cControl::Attach();
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
SuspendMode = SUSPEND_NORMAL;
2012-01-12 15:20:01 +01:00
return "SoftHdDevice is suspended";
}
if (!strcasecmp(command, "RESU")) {
if (SuspendMode == NOT_SUSPENDED) {
return "SoftHdDevice already resumed";
}
2012-03-01 22:12:22 +01:00
if (SuspendMode != SUSPEND_NORMAL) {
return "can't resume SoftHdDevice";
}
if (ShutdownHandler.GetUserInactiveTime()) {
ShutdownHandler.SetUserInactiveTimeout();
}
if (cSoftHdControl::Player) { // suspended
cControl::Shutdown(); // not need, if not suspended
}
Resume();
SuspendMode = NOT_SUSPENDED;
return "SoftHdDevice is resumed";
}
2012-03-01 22:12:22 +01:00
if (!strcasecmp(command, "DETA")) {
if (SuspendMode == SUSPEND_DETACHED) {
return "SoftHdDevice already detached";
}
2012-03-01 22:12:22 +01:00
if (cSoftHdControl::Player) { // already suspended
return "can't suspend SoftHdDevice already suspended";
}
cControl::Launch(new cSoftHdControl);
cControl::Attach();
Suspend(1, 1, 0);
SuspendMode = SUSPEND_DETACHED;
2012-03-01 22:12:22 +01:00
return "SoftHdDevice is detached";
}
if (!strcasecmp(command, "ATTA")) {
2012-03-02 00:38:52 +01:00
if (SuspendMode != SUSPEND_DETACHED) {
2012-03-01 22:12:22 +01:00
return "can't attach SoftHdDevice not detached";
}
2012-03-26 20:49:18 +02:00
if (!strncmp(option, "-d ", 3)) {
// FIXME: loose memory here
X11DisplayName = strdup(option + 3);
2012-03-26 20:49:18 +02:00
} else if (!strncmp(option, "-d", 2)) {
// FIXME: loose memory here
X11DisplayName = strdup(option + 2);
}
2012-03-01 22:12:22 +01:00
if (ShutdownHandler.GetUserInactiveTime()) {
ShutdownHandler.SetUserInactiveTimeout();
}
if (cSoftHdControl::Player) { // suspended
cControl::Shutdown(); // not need, if not suspended
}
Resume();
SuspendMode = NOT_SUSPENDED;
2012-03-01 22:12:22 +01:00
return "SoftHdDevice is attached";
}
if (!strcasecmp(command, "HOTK")) {
int hotk;
hotk = strtol(option, NULL, 0);
HandleHotkey(hotk);
return "hot-key executed";
}
if (!strcasecmp(command, "PRIM")) {
int primary;
primary = strtol(option, NULL, 0);
if (!primary && MyDevice) {
primary = MyDevice->DeviceNumber() + 1;
}
dsyslog("[softhddev] switching primary device to %d\n", primary);
DoMakePrimary = primary;
return "switching primary device requested";
}
2012-01-12 15:20:01 +01:00
return NULL;
}
2011-12-07 14:37:51 +01:00
VDRPLUGINCREATOR(cPluginSoftHdDevice); // Don't touch this!