Entwicklung - Tipps und Tricks
(Andere Plugins aufrufen) |
Hulk (Diskussion | Beiträge) |
||
(16 dazwischenliegende Versionen von 10 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
− | Hier sind ein paar | + | Hier sind ein paar Tipps und Tricks die beim entwickeln von Plugins helfen können: |
== Bilder == | == Bilder == | ||
Es gibt zwei Möglichkeiten Bilder im Plugin zu verwenden. | Es gibt zwei Möglichkeiten Bilder im Plugin zu verwenden. | ||
# Das XPM Format | # Das XPM Format | ||
− | # Images | + | # Images rendern |
=== Das XPM Format === | === Das XPM Format === | ||
Zeile 73: | Zeile 73: | ||
Im VDR gibt es die Klasse cBitmap. Einem der Konstruktoren kann man dieses "XMP"Array übergeben. Schon kann man es verwenden. Somit lassen sich sehr leicht und auch sehr effektiv Zeichnungen oder Bilder erstellen. | Im VDR gibt es die Klasse cBitmap. Einem der Konstruktoren kann man dieses "XMP"Array übergeben. Schon kann man es verwenden. Somit lassen sich sehr leicht und auch sehr effektiv Zeichnungen oder Bilder erstellen. | ||
− | Leider kennt das Format keine | + | Leider kennt das Format keine Transparenz, daher würde ich raten die erste Farbe so zu wählen das man sie später mit Transparent ersetzen kann. |
cBitmap vdr(vdr_xpm); | cBitmap vdr(vdr_xpm); | ||
Zeile 83: | Zeile 83: | ||
− | === Image | + | === Image rendern === |
− | Auf diese Weise kann man recht gut fast jedes Bildformat zur Laufzeit einbinden. Dabei wird das Image auf ein cBitmap vom VDR | + | Auf diese Weise kann man recht gut fast jedes Bildformat zur Laufzeit einbinden. Dabei wird das Image auf ein cBitmap vom VDR gerendert. |
− | Sicher gibt es hier mehrere Möglichkeiten. Eine recht einfache Möglichkeit ist aber das verwenden von der Magick++ | + | Sicher gibt es hier mehrere Möglichkeiten. Eine recht einfache Möglichkeit ist aber das verwenden von der Magick++ Library. |
− | brougs78 aus dem VDR Portal hat eine schöne cOSDImageBitmap Klasse geschrieben die von einigen Leuten | + | brougs78 aus dem VDR Portal hat eine schöne cOSDImageBitmap Klasse geschrieben die von einigen Leuten weiterentwickelt wurde. Falls Euch Verbesserungen einfallen, könnt Ihr sie hier gerne reinschreiben. |
Zeile 283: | Zeile 283: | ||
cBitmap icon(75, 75, 4); | cBitmap icon(75, 75, 4); | ||
cOSDImageBitmap osdbitmap; | cOSDImageBitmap osdbitmap; | ||
− | if(osdbitmap.Load(/video/vdr.png)){ | + | if(osdbitmap.Load("/video/vdr.png")){ |
osdbitmap.Render(icon, 4); | osdbitmap.Render(icon, 4); | ||
osd->DrawBitmap(20, yoff + 20, icon); | osd->DrawBitmap(20, yoff + 20, icon); | ||
Zeile 290: | Zeile 290: | ||
== Download aus dem Internet == | == Download aus dem Internet == | ||
− | Es gibt immer wieder das Problem | + | Es gibt immer wieder das Problem, dass Leute was aus dem Internet laden wollen. |
− | Hier | + | Hier ein Vorschlag, wie man es sehr schnell lösen kann. Dazu wird "wget" verwendet, was den Vorteil hat, dass es durch Proxys/Firewalls durch geht. Die Datei wird dann lokal abgespeichert und kann von dort aus weiter verarbeitet werden. |
− | + | ||
− | + | ||
+ | Hier der Vorschlag für einen Download: | ||
+ | <pre> | ||
static const char *BASEURL = "www.vdr-portal.de"; | static const char *BASEURL = "www.vdr-portal.de"; | ||
static const char *FILENAME = "example.php"; | static const char *FILENAME = "example.php"; | ||
Zeile 307: | Zeile 307: | ||
char *tmpSystem = NULL; | char *tmpSystem = NULL; | ||
− | dsyslog(" | + | dsyslog("Downloading a file from the internet"); |
//create commandline | //create commandline | ||
asprintf(tmpSystem, "wget -O %s -o %s -T %s \"%s/%s?v=%s&n=%d\"",TMPLOCALFILENAME,LOGWGET,SERVERTIMEOUT,BASEURL,FILENAME,FIXPARAMETER,number); | asprintf(tmpSystem, "wget -O %s -o %s -T %s \"%s/%s?v=%s&n=%d\"",TMPLOCALFILENAME,LOGWGET,SERVERTIMEOUT,BASEURL,FILENAME,FIXPARAMETER,number); | ||
Zeile 318: | Zeile 318: | ||
return false; | return false; | ||
}else{ | }else{ | ||
− | dsyslog(" | + | dsyslog("Successful downloaded."); |
} | } | ||
return true; | return true; | ||
} | } | ||
+ | </pre> | ||
− | == | + | == Plugins aufrufen und Werte übergeben == |
− | Es gibt zwei Möglichkeiten vom eigenen Plugin aus andere Plugins aufzurufen. Leider kann man auf beiden Wegen keine Parameter mit übergeben, daher bietet es sich an das ganze in | + | Es gibt zwei Möglichkeiten vom eigenen Plugin aus andere Plugins aufzurufen. Leider kann man auf beiden Wegen keine Parameter mit übergeben, daher bietet es sich an das ganze in Kombination mit den Services zu benutzen. es ist auch drauf zu achten das es hier zu Threading Problemen kommen kann. |
=== cRemote::CallPlugin === | === cRemote::CallPlugin === | ||
Zeile 336: | Zeile 337: | ||
} | } | ||
if (!Skins.IsOpen() && !cOsd::IsOpen()) { | if (!Skins.IsOpen() && !cOsd::IsOpen()) { | ||
− | cRemote::CallPlugin(" | + | cRemote::CallPlugin("myPlugin2"); |
result = true; | result = true; | ||
}else{ | }else{ | ||
Zeile 343: | Zeile 344: | ||
=== Plugin->MainMenuAction === | === Plugin->MainMenuAction === | ||
− | Mit dieser Methode kann mal alle Methoden die ein Plugin hat | + | Mit dieser Methode kann mal alle Methoden die ein Plugin hat explezit aufrufen. Es stehen einem also neben der MainMenuAction auch noch alle anderen (z.B. Start(), Stop(), ProcessArgs(int argc, char *argv[]) ) zur Verfügung. |
Leider erhält das aufgerufene Plugin auf diesen Weg keine Kontrolle über das OSD. | Leider erhält das aufgerufene Plugin auf diesen Weg keine Kontrolle über das OSD. | ||
Zeile 352: | Zeile 353: | ||
} | } | ||
− | == | + | === Parameter übergeben === |
− | + | Sicher könnte man auch die ProcessArgs zum übergeben der Parameter missbrauchen aber dieses wäre zu unsauber. Daher möchte ich hier an die Services verweisen. | |
+ | |||
+ | Server | ||
+ | |||
+ | bool cPluginSvcSvr::Service(const char *Id, void *Data) | ||
+ | { | ||
+ | if (strcmp(Id,"ReportBoredPlugin-v1.0") == 0) { | ||
+ | if (Data) { | ||
+ | ReportBoredPlugin_v1_0 *rbp = (ReportBoredPlugin_v1_0*)Data; | ||
+ | char s[128]; | ||
+ | snprintf(s, sizeof(s), "Plugin %s informed server that it is bored.", rbp->BoredPlugin->Name()); | ||
+ | Interface->Confirm(s); | ||
+ | } | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | if (strcmp(Id,"AddService-v1.0") == 0) { | ||
+ | if (Data) { | ||
+ | AddService_v1_0 *data = (AddService_v1_0*)Data; | ||
+ | data->sum = data->a + data->b; | ||
+ | } | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | Client | ||
+ | bool cPluginSvcCli::Service(const char *Id, void *Data) | ||
+ | { | ||
+ | if (strcmp(Id, "ReportBoredPlugin-v1.0") == 0) { | ||
+ | if (Data) { | ||
+ | ReportBoredPlugin_v1_0 *rbp = (ReportBoredPlugin_v1_0*)Data; | ||
+ | char s[128]; | ||
+ | snprintf(s, sizeof(s), "Plugin %s informed client that it is bored.", rbp->BoredPlugin->Name()); | ||
+ | Interface->Confirm(s); | ||
+ | } | ||
+ | return true; | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | [[Kategorie:Entwicklung]] |
Aktuelle Version vom 29. August 2013, 20:55 Uhr
Hier sind ein paar Tipps und Tricks die beim entwickeln von Plugins helfen können:
Inhaltsverzeichnis |
[Bearbeiten] Bilder
Es gibt zwei Möglichkeiten Bilder im Plugin zu verwenden.
- Das XPM Format
- Images rendern
[Bearbeiten] Das XPM Format
XPM ist ein sehr interessantes Bildformat für C Entwickler. Das Format kann man mit vielen Bildbearbeitungsprogrammen bearbeiten und unter XPM speichern. In der Datei wird das ganze dann als C Array gespeichert. Die Datei kann dann mit einem Texteditor bearbeitet werden.
Das folgende Bild einmal als Image und einmal als "Text"
/* XPM */ static char * vdr_xpm[] = { "100 50 2 1", ". c #FFFFFF", " c #000000", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", ".................. ............. ... ............. .....................", ".................. ............. .... ......... ...................", ".................. ............ .... ........ ..................", "................... ........... .... ....... ..................", "................... .......... .... ..... ...... ..... .................", "................... ......... ..... ....... ...... ....... .................", "................... ......... ..... ........ .... ....... .................", "................... ........ ...... .......... .... ....... .................", ".................... ........ ....... .......... .... ....... .................", ".................... ....... ...... .......... .... ....... ..................", ".................... ...... ....... .......... .... ....... ..................", ".................... ..... ....... .......... .... ..... ...................", ".................... ..... ........ ........... ... ...................", "..................... .... ......... ........... ... ....................", "..................... .... ........ ........... .... ......................", "..................... ... ......... .......... .... ........................", "..................... . ......... .......... ..... . .........................", "...................... . .......... ......... .... .. ........................", "...................... .......... ......... ..... .. .......................", "...................... .......... ........ ..... ... .......................", "...................... ........... ..... ...... ... ......................", "...................... ........... ....... ..... ......................", "....................... ............ ........ ..... .....................", "....................... ............ ......... ...... .....................", "....................... ............. ............ ...... ....................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "....................................................................................................", "...................................................................................................."};
Im VDR kann man dieses sehr leicht verwenden.
Im VDR gibt es die Klasse cBitmap. Einem der Konstruktoren kann man dieses "XMP"Array übergeben. Schon kann man es verwenden. Somit lassen sich sehr leicht und auch sehr effektiv Zeichnungen oder Bilder erstellen.
Leider kennt das Format keine Transparenz, daher würde ich raten die erste Farbe so zu wählen das man sie später mit Transparent ersetzen kann.
cBitmap vdr(vdr_xpm); vdr.SetColor(0, clrTransparent);
Ein Nachteil dieses Formates ist es das es etwas schwer ist die Bilder erst zur Laufzeit einzubinden. Meist werden sie als include in die Header eingebunden.
Einige Beispiele findet man in dem Skinelchi oder den Skinreel.
[Bearbeiten] Image rendern
Auf diese Weise kann man recht gut fast jedes Bildformat zur Laufzeit einbinden. Dabei wird das Image auf ein cBitmap vom VDR gerendert. Sicher gibt es hier mehrere Möglichkeiten. Eine recht einfache Möglichkeit ist aber das verwenden von der Magick++ Library.
brougs78 aus dem VDR Portal hat eine schöne cOSDImageBitmap Klasse geschrieben die von einigen Leuten weiterentwickelt wurde. Falls Euch Verbesserungen einfallen, könnt Ihr sie hier gerne reinschreiben.
#ifndef _OSDIMAGE_BITMAP_H_ #define _OSDIMAGE_BITMAP_H_ #define X_DISPLAY_MISSING #include "setup.h" #include <vdr/osd.h> #include <vdr/skins.h> #include <Magick++.h> using namespace Magick; class cOSDImageBitmap { public: cOSDImageBitmap(); ~cOSDImageBitmap(); bool LoadZoomed(const char *file, int zoomWidth, int zoomHeight, int zoomLeft, int zoomTop); bool Load(const char *file); void Save(const char *file); void Render(cBitmap &bmp, int wWindow, int hWindow, int colors, bool dither); void Render(cBitmap &bmp, int colors, int alpha=255); inline int Width() { return width; } inline int Height() { return height; } private: bool LoadImageMagick(Image &imgkLoad, const char *file); void QuantizeImageMagick(Image &imgkQuant, int colors, bool dither); void ConvertImgk2Bmp(cBitmap &bmp, Image &imgkConv, int colors); Image imgkZoom; int ZoomWidth, ZoomHeight, ZoomLeft, ZoomTop; int origWidth, origHeight; bool loadingFailed; int width, height; }; #endif
#ifdef HAVE_C295 #include <stl.h> #endif #include "bitmap.h" using namespace std; //need ??? using namespace Magick; cOSDImageBitmap::cOSDImageBitmap() { } cOSDImageBitmap::~cOSDImageBitmap() { } bool cOSDImageBitmap::LoadZoomed(const char *file, int zoomWidth, int zoomHeight, int zoomLeft, int zoomTop) { bool status; status = LoadImageMagick(imgkZoom, file); if (zoomWidth != 0) imgkZoom.crop(Geometry(zoomWidth, zoomHeight, zoomLeft, zoomTop)); height = imgkZoom.rows(); width = imgkZoom.columns(); return status; } bool cOSDImageBitmap::Load(const char *file) { return LoadImageMagick(imgkImage, file); } void cOSDImageBitmap::Save(const char *file) { SaveImageMagick(imgkImage, file); } void cOSDImageBitmap::Render(cBitmap & bmp, int colors, int alpha) { dsyslog("start to rande image"); if (!loadingFailed) { // quantize the picture QuantizeImageMagick(imgkImage, colors, false); // generate cBitmap ConvertImgk2Bmp(bmp, imgkImage, alpha); } else { dsyslog("can't rander image, loading failed!!!!!!!!!!!!!!!!!"); } } void cOSDImageBitmap::Render(cBitmap &bmp, int wWindow, int hWindow, int colors, bool dither) { int w = wWindow; int h = hWindow; int wNew, hNew; wNew = wWindow; hNew = hWindow; if (!loadingFailed) { Image imgkRender = imgkZoom; width = imgkRender.columns(); height = imgkRender.rows(); if (height != h || width != w) { switch (SkinElchiSetup.resize) { case 0: imgkRender.sample(Geometry(wNew, hNew, 0, 0) ); break; case 1: imgkRender.scale(Geometry(wNew, hNew, 0, 0) ); break; case 2: imgkRender.zoom(Geometry(wNew, hNew, 0, 0) ); } width = imgkRender.columns(); height = imgkRender.rows(); if (colors == 16 && (height != wWindow || width != hWindow)) colors = 15; } QuantizeImageMagick(imgkRender, colors, dither); ConvertImgk2Bmp(bmp, imgkRender, colors); } else { bmp.SetSize(w, h); bmp.SetBpp((colors <= 16) ? 4 : 8); width = w; height = h; const cFont *font = cFont::GetFont(fontSml); int smalllineHeight = font->Height(); bmp.DrawRectangle(0, 0, width - 1, height - 1, Theme.Color(clrBackground)); bmp.DrawText(0, h - smalllineHeight + 1, tr("Error"), Theme.Color(clrButtonRedBg), Theme.Color(clrBackground), font, w, smalllineHeight, taCenter); } } bool cOSDImageBitmap::LoadImageMagick(Image &imgkLoad, const char *file) { try { imgkLoad.read(file); if (imgkLoad.fileSize() == 0) { loadingFailed = true; return false; } else { height = imgkLoad.baseRows(); width = imgkLoad.baseColumns(); origWidth = width; origHeight = height; loadingFailed = false; return true; } } catch(exception &error) { loadingFailed = true; return false; } } void cOSDImageBitmap::SaveImageMagick(Image & imgkSave, const char *file) { imgkImage.write(file); } void cOSDImageBitmap::QuantizeImageMagick(Image &imgkQuant, int colors, bool dither) { imgkQuant.quantizeColors(colors); imgkQuant.quantizeDither(dither); imgkQuant.quantize(); } void cOSDImageBitmap::ConvertImgk2Bmp(cBitmap &bmp, Image &imgkConv, int colors) { int w = Width(); int h = Height(); tColor col; bmp.SetSize(w, h); bmp.SetBpp((colors <= 16) ? 4 : 8); const PixelPacket *pixels = imgkConv.getConstPixels(0, 0, w, h); for (int iy = 0; iy < h; iy++) { for (int ix = 0; ix < w; ix++) { col = (0xFF << 24) | ( (pixels->green * 255 / MaxRGB) << 8) | ( (pixels->red * 255 / MaxRGB) << 16) | ( (pixels->blue * 255 / MaxRGB) ); bmp.DrawPixel(ix, iy, col); pixels++; } } }
Die Verwendung ist denkbar einfach:
cBitmap icon(75, 75, 4); cOSDImageBitmap osdbitmap; if(osdbitmap.Load("/video/vdr.png")){ osdbitmap.Render(icon, 4); osd->DrawBitmap(20, yoff + 20, icon); }
[Bearbeiten] Download aus dem Internet
Es gibt immer wieder das Problem, dass Leute was aus dem Internet laden wollen. Hier ein Vorschlag, wie man es sehr schnell lösen kann. Dazu wird "wget" verwendet, was den Vorteil hat, dass es durch Proxys/Firewalls durch geht. Die Datei wird dann lokal abgespeichert und kann von dort aus weiter verarbeitet werden.
Hier der Vorschlag für einen Download:
static const char *BASEURL = "www.vdr-portal.de"; static const char *FILENAME = "example.php"; static const char *LOGWGET = "/tmp/my_wget.log"; static const char *SERVERTIMEOUT = "8"; static const char *FIXPARAMETER = "42"; static const char *TMPLOCALFILENAME = "/tmp/test.xml"; bool cServer::download(int number){ char *tmpSystem = NULL; dsyslog("Downloading a file from the internet"); //create commandline asprintf(tmpSystem, "wget -O %s -o %s -T %s \"%s/%s?v=%s&n=%d\"",TMPLOCALFILENAME,LOGWGET,SERVERTIMEOUT,BASEURL,FILENAME,FIXPARAMETER,number); dsyslog("DEBUG %s",tmpSystem); //execute command int dow_i = system (tmpSystem); delete tmpSystem; if (dow_i != 0){ dsyslog("ERROR: can't get File from %s/%s!",BASEURL,FILENAME); return false; }else{ dsyslog("Successful downloaded."); } return true; }
[Bearbeiten] Plugins aufrufen und Werte übergeben
Es gibt zwei Möglichkeiten vom eigenen Plugin aus andere Plugins aufzurufen. Leider kann man auf beiden Wegen keine Parameter mit übergeben, daher bietet es sich an das ganze in Kombination mit den Services zu benutzen. es ist auch drauf zu achten das es hier zu Threading Problemen kommen kann.
[Bearbeiten] cRemote::CallPlugin
Mit dieser Methode kann man ein Plugin so starten als wenn der User im Menü auf das Plugin gegangen und hätte es direkt aufgerufen. Ich habe das ganze um ein Timeout erweitert, so das eine Zeit lang versucht wird das Plugin zu starten, wenn es nicht geht, dann kann man mit einer Fehlermeldung weiter machen. Der Vorteil dabei ist, dass das aufgerufene Plugin die Kontrolle über OSD erhält.
int timeout = 1000; //10sec while ((Skins.IsOpen() || cOsd::IsOpen()) && timeout) { usleep(10000); timeout--; } if (!Skins.IsOpen() && !cOsd::IsOpen()) { cRemote::CallPlugin("myPlugin2"); result = true; }else{ result = false; }
[Bearbeiten] Plugin->MainMenuAction
Mit dieser Methode kann mal alle Methoden die ein Plugin hat explezit aufrufen. Es stehen einem also neben der MainMenuAction auch noch alle anderen (z.B. Start(), Stop(), ProcessArgs(int argc, char *argv[]) ) zur Verfügung. Leider erhält das aufgerufene Plugin auf diesen Weg keine Kontrolle über das OSD.
cPlugin *Plugin = cPluginManager::GetPlugin("myShowMessage"); if (Plugin){ Plugin->Start(); Plugin->MainMenuAction(); }
[Bearbeiten] Parameter übergeben
Sicher könnte man auch die ProcessArgs zum übergeben der Parameter missbrauchen aber dieses wäre zu unsauber. Daher möchte ich hier an die Services verweisen.
Server
bool cPluginSvcSvr::Service(const char *Id, void *Data) { if (strcmp(Id,"ReportBoredPlugin-v1.0") == 0) { if (Data) { ReportBoredPlugin_v1_0 *rbp = (ReportBoredPlugin_v1_0*)Data; char s[128]; snprintf(s, sizeof(s), "Plugin %s informed server that it is bored.", rbp->BoredPlugin->Name()); Interface->Confirm(s); } return true; } if (strcmp(Id,"AddService-v1.0") == 0) { if (Data) { AddService_v1_0 *data = (AddService_v1_0*)Data; data->sum = data->a + data->b; } return true; } return false; }
Client
bool cPluginSvcCli::Service(const char *Id, void *Data) { if (strcmp(Id, "ReportBoredPlugin-v1.0") == 0) { if (Data) { ReportBoredPlugin_v1_0 *rbp = (ReportBoredPlugin_v1_0*)Data; char s[128]; snprintf(s, sizeof(s), "Plugin %s informed client that it is bored.", rbp->BoredPlugin->Name()); Interface->Confirm(s); } return true; } return false; }