From ab6c3b4de81554dab6beee615c2744af42b15fd4 Mon Sep 17 00:00:00 2001 From: Johns Date: Wed, 7 Dec 2011 14:37:51 +0100 Subject: [PATCH] C++ part of the plugin. --- softhddevice.cpp | 731 +++++++++++++++++++++++++++++++++++++++++++++++ softhddevice.h | 21 ++ 2 files changed, 752 insertions(+) create mode 100644 softhddevice.cpp create mode 100644 softhddevice.h diff --git a/softhddevice.cpp b/softhddevice.cpp new file mode 100644 index 0000000..532b5dd --- /dev/null +++ b/softhddevice.cpp @@ -0,0 +1,731 @@ +/// +/// @file softhddevice.cpp @brief A software HD device plugin for VDR. +/// +/// Copyright (c) 2011 by Johns. All Rights Reserved. +/// +/// 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 +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG +#include "config.h" +#endif + +#include "softhddev.h" +#include "softhddevice.h" + +////////////////////////////////////////////////////////////////////////////// + +static const char *const VERSION = "0.0.8"; +static const char *const DESCRIPTION = +trNOOP("A software and GPU emulated HD device"); + +//static const char *MAINMENUENTRY = trNOOP("Soft-HD-Device"); +static class cSoftHdDevice *MyDevice; + +////////////////////////////////////////////////////////////////////////////// + +static char ConfigMakePrimary = 1; +static char DoMakePrimary; + +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// C Callbacks +////////////////////////////////////////////////////////////////////////////// + +class cSoftRemote:public cRemote +{ + public: + cSoftRemote(const char *name):cRemote(name) + { + }; + + bool Put(const char *code, bool repeat = false, bool release = false) { + return cRemote::Put(code, repeat, release); + }; +}; + +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) { + csoft = (cSoftRemote *) remote; + } else { + dsyslog("[softhddev]%s: remote '%s' not found\n", __FUNCTION__, + keymap); + csoft = new cSoftRemote(keymap); + } + + dsyslog("[softhddev]%s %s, %s\n", __FUNCTION__, keymap, key); + csoft->Put(key, repeat, release); +} + +////////////////////////////////////////////////////////////////////////////// +// OSD +////////////////////////////////////////////////////////////////////////////// + +class cSoftOsd:public cOsd +{ + public: + cSoftOsd(int, int, uint); + virtual ~ cSoftOsd(void); + virtual void Flush(void); + // virtual void SetActive(bool); +}; + +cSoftOsd::cSoftOsd(int left, int top, uint level) +:cOsd(left, top, level) +{ + // FIXME: OsdWidth/OsdHeight not correct! + dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(), + OsdHeight(), left, top, level); + + //SetActive(true); +} + +cSoftOsd::~cSoftOsd(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + SetActive(false); + + OsdClose(); +} + +/// +/// Actually commits all data to the OSD hardware. +/// +void cSoftOsd::Flush(void) +{ + cPixmapMemory *pm; + + if (!Active()) { + return; + } + //dsyslog("[softhddev]%s:\n", __FUNCTION__); + 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 + if (!bitmap->Dirty(x1, y1, x2, y2)) { + continue; // nothing dirty continue + } + // FIXME: need only to convert and upload dirty areas + + // DrawBitmap(bitmap); + argb = (uint8_t *) malloc(bitmap->Width() * bitmap->Height() * 4); + + w = bitmap->Width(); + h = bitmap->Height(); + for (y = 0; y < h; ++y) { + for (x = 0; x < w; ++x) { + ((uint32_t *) argb)[(x + y * w)] = bitmap->GetColor(x, y); + } + } + + OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(), + bitmap->Width(), bitmap->Height(), argb); + + bitmap->Clean(); + free(argb); + } + 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(); + + dsyslog("[softhddev]%s: draw %dx%d+%d+%d %p\n", __FUNCTION__, w, h, x, + y, pm->Data()); + + OsdDrawARGB(x, y, w, h, pm->Data()); + + delete pm; + } +} + +////////////////////////////////////////////////////////////////////////////// +// OSD provider +////////////////////////////////////////////////////////////////////////////// + +class cSoftOsdProvider:public cOsdProvider +{ + private: + static cOsd *Osd; + public: + virtual cOsd * CreateOsd(int, int, uint); + virtual bool ProvidesTrueColor(void); + cSoftOsdProvider(void); +}; + +cOsd *cSoftOsdProvider::Osd; + +/** +** Create a new OSD. +*/ +cOsd *cSoftOsdProvider::CreateOsd(int left, int top, uint level) +{ + dsyslog("[softhddev]%s: %d, %d, %d\n", __FUNCTION__, left, top, level); + + Osd = new cSoftOsd(left, top, level); + return Osd; +} + +/** +** Returns true if this OSD provider is able to handle a true color OSD. +*/ +bool cSoftOsdProvider::ProvidesTrueColor(void) +{ + return true; +} + +cSoftOsdProvider::cSoftOsdProvider(void) +: cOsdProvider() +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); +} + +////////////////////////////////////////////////////////////////////////////// +// cMenuSetupPage +////////////////////////////////////////////////////////////////////////////// + +class cMenuSetupSoft:public cMenuSetupPage +{ + protected: + int MakePrimary; + protected: + virtual void Store(void); + public: + cMenuSetupSoft(void); +}; + +/** +** Constructor setup menu. +*/ +cMenuSetupSoft::cMenuSetupSoft(void) +{ + // cMenuEditBoolItem cMenuEditBitItem cMenuEditNumItem + // cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem + Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary, + tr("no"), tr("yes"))); +} + +/** +** Store setup. +*/ +void cMenuSetupSoft::Store(void) +{ + SetupStore("MakePrimary", MakePrimary); +} + +////////////////////////////////////////////////////////////////////////////// +// cDevice +////////////////////////////////////////////////////////////////////////////// + +class cSoftHdDevice:public cDevice +{ + public: + cSoftHdDevice(void); + virtual ~ cSoftHdDevice(void); + + 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 SetVolumeDevice(int); + virtual void StillPicture(const uchar *, int); + virtual bool Poll(cPoller &, int = 0); + virtual bool Flush(int = 0); + virtual int64_t GetSTC(void); + virtual void GetOsdSize(int &, int &, double &); + virtual int PlayVideo(const uchar *, int); + //virtual int PlayTsVideo(const uchar *, int); + virtual void SetAudioChannelDevice(int); + virtual int GetAudioChannelDevice(void); + virtual void SetDigitalAudioDevice(bool); + virtual void SetAudioTrackDevice(eTrackType); + virtual int PlayAudio(const uchar *, int, uchar); + +// Image Grab facilities + + virtual uchar *GrabImage(int &, bool, int, int, int); + + virtual int ProvidesCa(const cChannel *) const; + +// SPU facilities + private: + cDvbSpuDecoder * spuDecoder; + public: + virtual cSpuDecoder * GetSpuDecoder(void); + + protected: + virtual void MakePrimaryDevice(bool); +}; + +cSoftHdDevice::cSoftHdDevice(void) +{ + dsyslog("[softhddev]%s\n", __FUNCTION__); +} + +cSoftHdDevice::~cSoftHdDevice(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); +} + +int64_t cSoftHdDevice::GetSTC(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + return 0L; +}; + +void cSoftHdDevice::MakePrimaryDevice(bool on) +{ + dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on); + + cDevice::MakePrimaryDevice(on); + if (on) { + new cSoftOsdProvider(); + } +} + +int cSoftHdDevice::ProvidesCa( + __attribute__ ((unused)) const cChannel * channel) const +{ + dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel); + + return 0; +} + +cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + + if (IsPrimaryDevice() && !spuDecoder) { + spuDecoder = new cDvbSpuDecoder(); + } + return spuDecoder; +}; + +bool cSoftHdDevice::HasDecoder(void) const +{ + return true; +} + +bool cSoftHdDevice::CanReplay(void) const +{ + return true; +} + +bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode) +{ + dsyslog("[softhddev]%s: %d\n", __FUNCTION__, PlayMode); + + switch (PlayMode) { + case pmAudioVideo: + break; + case pmAudioOnly: + case pmAudioOnlyBlack: + break; + case pmVideoOnly: + break; + case pmNone: + break; + case pmExtern_THIS_SHOULD_BE_AVOIDED: + break; + default: + dsyslog("[softhddev]playmode not implemented... %d\n", PlayMode); + break; + } + ::SetPlayMode(); + return true; +} + +void cSoftHdDevice::TrickSpeed(int Speed) +{ + dsyslog("[softhddev]%s: %d\n", __FUNCTION__, Speed); +} + +void cSoftHdDevice::Clear(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); +} + +void cSoftHdDevice::Play(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); +} + +void cSoftHdDevice::Freeze(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); +} + +void cSoftHdDevice::Mute(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + + cDevice::Mute(); + + ::Mute(); +} + +void cSoftHdDevice::SetVolumeDevice(int volume) +{ + dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume); + + ::SetVolumeDevice(volume); +} + +void cSoftHdDevice::StillPicture( + __attribute__ ((unused)) const uchar * data, __attribute__ ((unused)) + int length) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); +} + +bool cSoftHdDevice::Poll( + __attribute__ ((unused)) cPoller & poller, __attribute__ ((unused)) + int timeout_ms) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + return true; +} + +bool cSoftHdDevice::Flush( __attribute__ ((unused)) int timeout_ms) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + return true; +}; + +// ---------------------------------------------------------------------------- + +/** +** Returns the With, Height and PixelAspect ratio the OSD. +** +** FIXME: Called every second, for nothing (no OSD displayed)? +*/ +void cSoftHdDevice::GetOsdSize(int &width, int &height, double &pixel_aspect) +{ + ::GetOsdSize(&width, &height, &pixel_aspect); +} + +// ---------------------------------------------------------------------------- + +int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id) +{ + //dsyslog("[softhddev]%s: %p %p %d %d\n", __FUNCTION__, this, data, length, id); + + ::PlayAudio(data, length, id); + + return length; +} + +void cSoftHdDevice::SetAudioTrackDevice( + __attribute__ ((unused)) eTrackType type) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); +} + +void cSoftHdDevice::SetDigitalAudioDevice(bool on) +{ + dsyslog("[softhddev]%s: %s\n", __FUNCTION__, on ? "true" : "false"); +} + +void cSoftHdDevice::SetAudioChannelDevice(int audio_channel) +{ + dsyslog("[softhddev]%s: %d\n", __FUNCTION__, audio_channel); +} + +int cSoftHdDevice::GetAudioChannelDevice(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + return 0; +} + +// ---------------------------------------------------------------------------- + +/// +/// Play a video packet. +/// +int cSoftHdDevice::PlayVideo(const uchar * data, int length) +{ + //dsyslog("[softhddev]%s: %p %d\n", __FUNCTION__, data, length); + + ::PlayVideo(data, length); + + return length; +} + +#if 0 +/// +/// Play a TS video packet. +/// +int cSoftHdDevice::PlayTsVideo(const uchar * Data, int Length) +{ + // many code to repeat +} +#endif + +uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int sizex, + int sizey) +{ + dsyslog("[softhddev]%s: %d, %d, %d, %dx%d\n", __FUNCTION__, size, jpeg, + quality, sizex, sizey); + + return NULL; +}; + +////////////////////////////////////////////////////////////////////////////// +// 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); + virtual void MainThreadHook(void); +// virtual const char *MainMenuEntry(void); +// virtual cOsdObject *MainMenuAction(void); + virtual cMenuSetupPage *SetupMenu(void); + virtual bool SetupParse(const char *, const char *); +// virtual bool Service(const char *Id, void *Data = NULL); +}; + +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__); +} + +cPluginSoftHdDevice::~cPluginSoftHdDevice(void) +{ + // Clean up after yourself! + dsyslog("[softhddev]%s:\n", __FUNCTION__); +} + +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__); + + return::ProcessArgs(argc, argv); +} + +bool cPluginSoftHdDevice::Initialize(void) +{ + // Start any background activities the plugin shall perform. + dsyslog("[softhddev]%s:\n", __FUNCTION__); + + MyDevice = new cSoftHdDevice(); + + return true; +} + +bool cPluginSoftHdDevice::Start(void) +{ + const cDevice *primary; + + // Start any background activities the plugin shall perform. + dsyslog("[softhddev]%s:\n", __FUNCTION__); + + primary = cDevice::PrimaryDevice(); + if (MyDevice != primary) { + 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 = 1; + } else { + isyslog("[softhddev] softhddevice %d is not the primary device!", + MyDevice->DeviceNumber()); + } + } + + ::Start(); + + return true; +} + +void cPluginSoftHdDevice::Stop(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + + ::Stop(); +} + +#if 0 + +void cPluginSoftHdDevice::Housekeeping(void) +{ + // Perform any cleanup or other regular tasks. +} + +const char *cPluginSoftHdDevice::MainMenuEntry(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + return tr(MAINMENUENTRY); + return NULL; +} + +#endif + +/** +** Called for every plugin once during every cycle of VDR's main program +** loop. +*/ +void cPluginSoftHdDevice::MainThreadHook(void) +{ + // dsyslog("[softhddev]%s:\n", __FUNCTION__); + + if (DoMakePrimary && MyDevice) { + dsyslog("[softhddev]%s: switching primary device\n", __FUNCTION__); + cDevice::SetPrimaryDevice(MyDevice->DeviceNumber() + 1); + DoMakePrimary = 0; + } + + ::MainThreadHook(); +} + +#if 0 + +bool cPluginSoftHdDevice::Service(const char *Id, void *Data) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + + return false; +} + +cOsdObject *cPluginSoftHdDevice::MainMenuAction(void) +{ + // Perform the action when selected from the main VDR menu. + dsyslog("[softhddev]%s:\n", __FUNCTION__); + + return NULL; +} + +#endif + +/** +** Return our setup menu. +*/ +cMenuSetupPage *cPluginSoftHdDevice::SetupMenu(void) +{ + dsyslog("[softhddev]%s:\n", __FUNCTION__); + + return new cMenuSetupSoft; +} + +/** +** Parse setup parameters +*/ +bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value) +{ + dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value); + + // FIXME: handle the values + if (!strcmp(name, "MakePrimary")) { + ConfigMakePrimary = atoi(value); + return true; + } + + return false; +} + +VDRPLUGINCREATOR(cPluginSoftHdDevice); // Don't touch this! diff --git a/softhddevice.h b/softhddevice.h new file mode 100644 index 0000000..1729441 --- /dev/null +++ b/softhddevice.h @@ -0,0 +1,21 @@ +/// +/// @file softhddevice.h @brief software HD device plugin header file. +/// +/// Copyright (c) 2011 by Johns. All Rights Reserved. +/// +/// 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$ +//////////////////////////////////////////////////////////////////////////////