From 93a94b18b540fbcb9bcdaaea9abd26cdf23d6ee6 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 4 Jan 2004 18:00:00 +0100 Subject: Version 1.3.0 - Changed thread handling to make it work with NPTL ("Native Posix Thread Library"). Thanks to Jon Burgess, Andreas Schultz, Werner Fink and Stefan Huelswitt. - The cThread class now accepts a 'Description' parameter, which is used to log the beginning and end of the thread, together with its process and thread id. For descriptions that need additional parameters you can use the function cThread::SetDescription(), which accepts 'printf()' like arguments. Existing plugins that use threads should be changed to use this functionality instead of explicit 'dsyslog()' calls inside their Action() function in order to support logging the thread ids. - Added "Slovak Link" and "Czech Link" to 'ca.conf' (thanks to Emil Petersky). However, 'ca.conf' is now pretty much obsolete due to the automatic CA handling. - Mutexes are now created with PTHREAD_MUTEX_ERRORCHECK_NP, which makes the 'lockingTid' stuff obsolete (thanks to Stefan Huelswitt). - Changed font handling to allow language specific character sets. - Adopted the small font character set from the "Elchi" patch (originally provided by Alessio Sangalli). - Greek language texts now use iso8859-7 character set (thanks to Dimitrios Dimitrakos). - Rearranged section data handling, so that the actual data handling can be done separately, even from within plugins. - The EPG data structures have been moved from eit.[hc] to epg.[hc] and have been adapted to the general VDR coding style. Plugins that use these data structures may need to change some function names (which should be obvious). The name 'subtitle' has been changed to 'shortText' to avoid clashes with actual subtitles that are part of a movie. The name 'extendedDescription' has been shortened to 'description'. - Replaced 'libdtv' with 'libsi' (thanks to Marcel Wiesweg), which is thread safe and can be used by multiple section filters simultaneously. - Added 'cRwLock' to 'thread.[hc]'. Note that all plugin Makefiles need to define _GNU_SOURCE for this to work (see the example plugin Makefiles and 'newplugin'). - Fixed a problem with crc32 in SI handling on 64bit systems (thanks to Pedro Miguel Sequeira de Justo Teixeira for reporting this one). - Fixed an alignment problem in CAM access on 64bit systems (thanks to Pedro Miguel Sequeira de Justo Teixeira for reporting this one). - Added 'StreamType' setting to CAM communication, which is important for Aston/SECA CAMs (thanks to Antonino Sergi). - Now the CA descriptors are sent to the CAM in the 'program' or 'ES level' sections, depending on where they are found in the PMT (thanks to Hans-Peter Raschke for reporting this one). This should make SkyCrypt CAMs work. - Now using the 'version number' of EPG events to avoid unnecessary work. - Channel data is now automatically derived from the DVB data stream (inspired by the 'autopid' patch from Andreas Schultz). - The current channel is now automatically re-tuned if the PIDs or other settings change. If a recording is going on on a channel that has a change in its settings, the recording will be stopped and immediately restarted to use the new channel settings. - EPG events now use the complete channel ID with NID, TID and SID. - Channel names in 'channels.conf' can now have a short form, as provided by some tv stations (see man vdr(5)). Currently channels that provide short names in addition to long ones are listed in the OSD as "short,long name", as in "RTL,RTL Television". The short names will be used explicitly later. - The Ca parameter in 'channels.conf' has been extended and now contains all the CA system ids for the given channel. When switching to a channel VDR now tests for a device that provides one of these CA system ids. The devices automatically get their supported ids from the CI handler. - The values in 'ca.conf' are currently without any real meaning. Whether or not a channel with conditional access can be received is now determined automatically by evaluating its CA descriptors and comparing them to the CA system ids provided by the installed CAM. Only the special values 1-16 are used to assign a channel to a particular device. - Increased the maximum number of possible OSD colors to 256. - Limited the line length in the EPG bugfix report, which appears to fix a buffer overflow that caused a crash when cleaning up the EPG data (at 05:00 in the morning). --- PLUGINS.html | 223 ++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 151 insertions(+), 72 deletions(-) (limited to 'PLUGINS.html') diff --git a/PLUGINS.html b/PLUGINS.html index 95ba5d7..d13ca4a 100644 --- a/PLUGINS.html +++ b/PLUGINS.html @@ -6,7 +6,7 @@

The VDR Plugin System

-
Version 1.2.6
+
Version 1.3

Copyright © 2003 Klaus Schmidinger
@@ -14,9 +14,12 @@ Copyright © 2003 Klaus Schmidinger
www.cadsoft.de/vdr

-
  +
  Important modifications introduced in version 1.2.6 are marked like this. -
+
+
  +Important modifications introduced in version 1.3.0 are marked like this. +

VDR provides an easy to use plugin interface that allows additional functionality to be added to the program by implementing a dynamically loadable library file. @@ -64,6 +67,9 @@ structures and allows it to hook itself into specific areas to perform special a

  • Status monitor
  • Players
  • Receivers +
      +
  • Filters +
  • The On Screen Display
  • Devices
  • Dolby Digital @@ -112,7 +118,7 @@ No other characters should be used here.

    A plugin can access its name through the (non virtual) member function -


    +

     const char *Name(void);
     

    @@ -127,7 +133,7 @@ By default plugins are located in a directory named PLUGINS below the VDR source directory. Inside this directory the following subdirectory structure is used: -


    +

     VDR/PLUGINS/src
     VDR/PLUGINS/src/hello
     VDR/PLUGINS/lib
    @@ -172,7 +178,7 @@ To use the plugins and plugins-clean targets from the VDR 
     you need to unpack such an archive into the VDR/PLUGINS/src directory and
     create a symbolic link with the basic plugin name, as in
     
    -


    +

     ln -s hello-0.0.1 hello
     

    @@ -226,7 +232,7 @@ If your plugin shall not be accessible through VDR's main menu, simply remove

    At the end of the plugin's source file you will find a line that looks like this: -


    +

     VDRPLUGINCREATOR(cPluginHello);
     

    @@ -239,7 +245,7 @@ source directory and adjust the Makefile accordingly. Header files usually contain preprocessor statements that prevent the same file (or rather its contents, to be precise) from being included more than once, like -


    +

     #ifndef __I18N_H
     #define __I18N_H
     
    @@ -274,7 +280,7 @@ and two replacing the dot).
     
     The constructor and destructor of a plugin are defined as
     
    -


    +

     cPlugin(void);
     virtual ~cPlugin();
     

    @@ -304,7 +310,7 @@ Every plugin must have a version number of its own, which does not necessarily have to be in any way related to the VDR version number. VDR requests a plugin's version number through a call to the function -


    +

     virtual const char *Version(void) = 0;
     

    @@ -315,7 +321,7 @@ information, like for instance "0.0.1pre2" or the like. The string should only be as long as really necessary, and shall not contain the plugin's name itself. Here's an example: -


    +

     static const char *VERSION = "0.0.1";
     
     const char *cPluginHello::Version(void)
    @@ -347,13 +353,13 @@ would be acceptable.
     
     In order to tell the user what exactly a plugin does, it must implement the function
     
    -


    +

     virtual const char *Description(void) = 0;
     

    which returns a short, one line description of the plugin's purpose: -


    +

     static const char *DESCRIPTION = "A friendly greeting";
     
     virtual const char *Description(void)
    @@ -373,7 +379,7 @@ A VDR plugin can have command line arguments just like any normal program.
     If a plugin wants to react on command line arguments, it needs to implement
     the function
     
    -


    +

     virtual bool ProcessArgs(int argc, char *argv[]);
     

    @@ -390,7 +396,7 @@ these arguments. As with any normal C program, the strings pointed to by arg will survive the entire lifetime of the plugin, so it is safe to store pointers to these values inside the plugin. Here's an example: -


    +

     bool cPluginHello::ProcessArgs(int argc, char *argv[])
     {
       // Implement command line argument processing here if applicable.
    @@ -425,7 +431,7 @@ to exit.
     
     If a plugin accepts command line options, it should implement the function
     
    -


    +

     virtual const char *CommandLineHelp(void);
     

    @@ -433,7 +439,7 @@ which will be called if the user enters the -h option when start The returned string should contain the command line help for this plugin, formatted in the same way as done by VDR itself: -


    +

     const char *cPluginHello::CommandLineHelp(void)
     {
       // Return a string that describes all known command line options.
    @@ -456,7 +462,7 @@ If a plugin implements a function that runs in the background (presumably in a
     thread of its own), or wants to make use of internationalization,
     it needs to implement one of the functions
     
    -


    +

     virtual bool Initialize(void);
     virtual bool Start(void);
     

    @@ -493,7 +499,7 @@ texts, it doesn't need to implement either of these functions. If the plugin implements a feature that the user shall be able to access from VDR's main menu, it needs to implement the function -


    +

     virtual const char *MainMenuEntry(void);
     

    @@ -501,7 +507,7 @@ The default implementation returns a NULL pointer, which means that this plugin will not have an item in the main menu. Here's an example of a plugin that will have a main menu item: -


    +

     static const char *MAINMENUENTRY = "Hello";
     
     const char *cPluginHello::MainMenuEntry(void)
    @@ -520,7 +526,7 @@ in the call to VDR.
     
     If the user selects the main menu entry of a plugin, VDR calls the function
     
    -


    +

     virtual cOsdObject *MainMenuAction(void);
     

    @@ -554,7 +560,7 @@ the plugin should launch a separate thread to do this. From time to time a plugin may want to do some regular tasks, like cleaning up some files or other things. In order to do this it can implement the function -


    +

     virtual void Housekeeping(void);
     

    @@ -579,7 +585,7 @@ the plugin should launch a separate thread to do this. If a plugin requires its own setup parameters, it needs to implement the following functions to handle these parameters: -


    +

     virtual cMenuSetupPage *SetupMenu(void);
     virtual bool SetupParse(const char *Name, const char *Value);
     

    @@ -594,7 +600,7 @@ an error. If false is returned, an error message will be written to the log file (and program execution will continue). A possible implementation of SetupParse() could look like this: -


    +

     bool cPluginHello::SetupParse(const char *Name, const char *Value)
     {
       // Parse your own setup parameters and store their values.
    @@ -620,7 +626,7 @@ plugins need not worry about this.
     

    To store its values in the global setup, a plugin has to call the function -


    +

     void SetupStore(const char *Name, type Value);
     

    @@ -653,7 +659,7 @@ To implement a Setup menu, a plugin needs to derive a class from cMenuSetupPage and implement its constructor and the pure virtual Store() member function: -


    +

     int GreetingTime = 3;
     int UseAlternateGreeting = false;
     
    @@ -714,7 +720,7 @@ configuration file. While the plugin is free to store such files anywhere it
     sees fit, it might be a good idea to put them in a common place, preferably
     where other configuration data already exists. VDR provides the function
     
    -


    +

     const char *ConfigDirectory(const char *PluginName = NULL);
     

    @@ -737,7 +743,7 @@ these in a subdirectory of its own, named after the plugin. To easily get such a the ConfigDirectory() function can be given an additional string that will be appended to the returned directory name, as in -


    +

     const char *MyConfigDir = ConfigDirectory(Name());
     

    @@ -754,7 +760,7 @@ The ConfigDirectory() function is a static member function of the c class. This allows it to be called even from outside any member function of the derived plugin class, by writing -


    +

     const char *MyConfigDir = cPlugin::ConfigDirectory();
     

    @@ -765,7 +771,7 @@ const char *MyConfigDir = cPlugin::ConfigDirectory(); If a plugin displays texts to the user, it should implement internationalized versions of these texts and call the function -


    +

     void RegisterI18n(const tI18nPhrase * const Phrases);
     

    @@ -774,7 +780,7 @@ to register them with VDR's internationalization mechanism. The call to this function must be done in the Initialize() or Start() function of the plugin: -


    +

     const tI18nPhrase Phrases[] = {
       { "Hello world!",
         "Hallo Welt!",
    @@ -815,7 +821,7 @@ you may want to contact the maintainers of these languages (listed in the file
     The actual runtime selection of the texts corresponding to the selected language
     is done by wrapping each internationalized text with the tr() macro:
     
    -


    +

     const char *s = tr("Hello world!");
     

    @@ -833,20 +839,20 @@ core VDR code. Plugins are loaded into VDR using the command line option -P, as in -


    +

     vdr -Phello
     

    If the plugin accepts command line options, they are given as part of the argument to the -P option, which then has to be enclosed in quotes: -


    +

     vdr -P"hello -a abc -b"
     

    Any number of plugins can be loaded this way, each with its own -P option: -


    +

     vdr -P"hello -a abc -b" -Pdvd -Pmp3
     

    @@ -854,7 +860,7 @@ If you are not starting VDR from the VDR source directory (and thus your plugins cannot be found at their default location) you need to tell VDR the location of the plugins through the -L option: -


    +

     vdr -L/usr/lib/vdr -Phello
     

    @@ -879,14 +885,14 @@ provides the target dist, which does this for you.

    Simply change into your source directory and execute make dist: -


    +

     cd VDR/PLUGINS/src/hello
     make dist
     

    After this you should find a file named like -


    +

     vdr-hello-0.0.1.tgz
     

    @@ -902,7 +908,7 @@ plugin's name, and 0.0.1 will be your plugin's current version number. If a plugin wants to get informed on various events in VDR, it can derive a class from cStatus, as in -


    +

     #include <vdr/status.h>
     
     class cMyStatusMonitor : public cStatus {
    @@ -922,7 +928,7 @@ void cMyStatusMonitor::ChannelSwitch(const cDevice *Device, int ChannelNumber)
     An object of this class will be informed whenever the channel is switched on one of
     the DVB devices. It could be used in a plugin like this:
     
    -


    +

     #include <vdr/plugin.h>
     
     class cPluginStatus : public cPlugin {
    @@ -975,7 +981,7 @@ the functions you actually want to use.
     Implementing a player is a two step process.
     First you need the actual player class, which is derived from the abstract cPlayer:
     
    -


    +

     #include <vdr/player.h>
     
     class cMyPlayer : public cPlayer {
    @@ -991,7 +997,7 @@ What exactly you do in this class is entirely up to you. If you want to run a se
     thread which, e.g.,  reads data from a file, you can additionally derive your class from
     cThread and implement the necessary functionality:
     
    -


    +

     #include <vdr/player.h>
     
     class cMyPlayer : public cPlayer, cThread {
    @@ -1009,7 +1015,7 @@ its own player for the VDR recordings.
     

    To play the video data, the player needs to call its member function -


    +

     int PlayVideo(const uchar *Data, int Length);
     

    @@ -1020,7 +1026,7 @@ desired video data stream, and it must be delivered fast enough so that the DVB device doesn't run out of data. To avoid busy loops the player should call its member function -


    +

     bool DevicePoll(cPoller &Poller, int TimeoutMs = 0);
     

    @@ -1029,7 +1035,7 @@ to determine whether the device is ready for further data. If the player can provide more than a single audio track, it can implement the following functions to make them available: -


    +

     virtual int NumAudioTracks(void) const;
     virtual const char **GetAudioTracks(int *CurrentTrack = NULL);
     virtual void SetAudioTrack(int Index);
    @@ -1039,7 +1045,7 @@ virtual void SetAudioTrack(int Index);
     If there is an additional audio track that has to be replayed with external hardware,
     the player shall call its member function
     
    -


    +

     void PlayAudio(const uchar *Data, int Length);
     

    @@ -1048,7 +1054,7 @@ where Data points to a complete audio PES packet of Length byt The second part needed here is a control object that receives user input from the main program loop and reacts on this by telling the player what to do: -


    +

     #include <vdr/player.h>
     
     class cMyControl : public cControl {
    @@ -1066,7 +1072,7 @@ public:
     hand over a pointer to it to the cControl base class, so that it
     can be later attached to the primary DVB device:
     
    -


    +

     cMyControl::cMyControl(void)
     :cControl(player = new cMyPlayer)
     {
    @@ -1093,7 +1099,7 @@ Finally, to get things going, a plugin that implements a player (and the surroun
     infrastructure like displaying a list of playable stuff etc) simply has to call the
     static function cControl::Launch() with the player control object, as in
     
    -


    +

     cControl::Launch(new cMyControl);
     

    @@ -1104,7 +1110,7 @@ use the primary DVB device, or the user decides to start a different replay).

    The cPlayer class has a member function -


    +

     void DeviceStillPicture(const uchar *Data, int Length);
     

    @@ -1149,7 +1155,7 @@ ahead - it's your show... In order to receive any kind of data from a cDevice, a plugin must set up an object derived from the cReceiver class: -


    +

     #include <vdr/receiver.h>
     
     class cMyReceiver : public cReceiver, cThread {
    @@ -1187,7 +1193,7 @@ a cReceiver to be detached from its cDevice at any time.
     Once a cReceiver has been created, it needs to be attached to
     a cDevice:
     
    -


    +

     cMyReceiver *Receiver = new cMyReceiver(123);
     
     cDevice::ActualDevice()->AttachReceiver(Receiver);
    @@ -1201,6 +1207,52 @@ Mode).
     If the cReceiver isn't needed any more, it may simply be deleted
     and will automatically detach itself from the cDevice.
     
    +
      +

    Filters

    + +
    A Fistful of Datas

    + +If you want to receive section data you have to implement a derived cFilter +class which at least implements the Process() function and a constructor +that sets the (initial) filter parameters: + +

    +#include <vdr/filter.h>
    +
    +class cMyFilter : public cFilter {
    +protected:
    +  virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
    +public:
    +  cMyFilter(void);
    +  ...
    +  };
    +
    +cMyFilter::cMyFilter(void)
    +{
    +  Set(0x14, 0x70);        // TDT
    +}
    +
    +void cMyFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
    +{
    +  // do something with the data here
    +}
    +

    + +An instance of such a filter needs to be attached to the device from +which it shall receive data, as in + +

    +cMyFilter Filter;
    +
    +cDevice::ActualDevice()->AttachFilter(Filter);
    +

    + +If the cFilter isn't needed any more, it may simply be deleted +and will automatically detach itself from the cDevice. +

    +See VDR/eit.c or VDR/pat.c to learn how to process filter data. +

    +

    The On Screen Display

    Express yourself

    @@ -1213,7 +1265,7 @@ windows and color depths. If a plugin needs to have total control over the OSD, it can call the static function -


    +

     #include <vdr/osd.h>
     
     cOsdBase *MyOsd = cOsd::OpenRaw(x, y);
    @@ -1223,7 +1275,7 @@ where x and y are the coordinates of the upper left corner
     of the OSD area on the screen. Such a "raw" OSD doesn't display anything
     yet, so you need to at least call the function
     
    -


    +

     MyOsd->Create(...);
     

    @@ -1247,7 +1299,7 @@ stream and displays it, for instance, on an existing graphics adapter.

    To implement an additional device, a plugin must derive a class from cDevice: -


    +

     #include <vdr/device.h>
     
     class cMyDevice : public cDevice {
    @@ -1266,7 +1318,7 @@ the cDvbDevice, which is used to access the DVB PCI cards.
     If the new device can receive, it most likely needs to provide a way of
     selecting which channel it shall tune to:
     
    -


    +

     virtual bool ProvidesSource(int Source) const;
     virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL);
     virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
    @@ -1281,7 +1333,7 @@ repectively.
     If the device can provide more than a single audio track, it can implement the
     following functions to make them available:
     
    -


    +

     virtual int NumAudioTracksDevice(void) const;
     virtual const char **GetAudioTracksDevice(int *CurrentTrack = NULL) const;
     virtual void SetAudioTrackDevice(int Index);
    @@ -1292,7 +1344,7 @@ virtual void SetAudioTrackDevice(int Index);
     

    A device that can be used for recording must implement the functions -


    +

     virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
     virtual bool OpenDvr(void);
     virtual void CloseDvr(void);
    @@ -1308,7 +1360,7 @@ must deliver exactly one such packet (if one is currently available).
     If this device allows receiving several different data streams, it can
     implement
     
    -


    +

     virtual bool CanBeReUsed(int Frequency, int Vpid);
     

    @@ -1318,13 +1370,13 @@ to indicate this to VDR.

    The functions to implement replaying capabilites are -


    +

     virtual bool HasDecoder(void) const;
     virtual bool CanReplay(void) const;
     virtual bool SetPlayMode(ePlayMode PlayMode);
    -
      +
      virtual int64_t GetSTC(void); -
    +
    virtual void TrickSpeed(int Speed); virtual void Clear(void); virtual void Play(void); @@ -1338,12 +1390,39 @@ virtual int PlayVideo(const uchar *Data, int Length); In addition, the following functions may be implemented to provide further functionality: -


    +

     virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int Si
     virtual void SetVideoFormat(bool VideoFormat16_9);
     virtual void SetVolumeDevice(int Volume);
     

    +
      +

    +Section Filtering +

    +If your device provides section filtering capabilities it can implement +the function + +

    +virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
    +

    + +which must open a file handle that delivers section data for the given +filter parameters. +

    +In order to actually start section handling, the +device also needs to call the function + +

    +StartSectionHandler();
    +

    + +from its constructor. +

    +See Filters on how to set up actual filters that can +handle section data. +

    +

    On Screen Display

    @@ -1351,7 +1430,7 @@ If your device provides On Screen Display (OSD) capabilities (which every device that is supposed to be used as a primary device should do), it can implement the function -


    +

     virtual cOsdBase *NewOsd(int x, int y);
     

    @@ -1391,7 +1470,7 @@ audio replay facility. To implement a new audio output facility, simply derive a class from cAudio, as in -


    +

     #include <vdr/audio.h>
     #include <vdr/thread.h>
     
    @@ -1435,7 +1514,7 @@ remote control, so a plugin can use the cRemote class to do that.
     The simplest method for a plugin to issue commands to VDR is to call the
     static function cRemote::Put(eKeys Key), as in
     
    -


    +

     cRemote::Put(kUp);
     

    @@ -1447,7 +1526,7 @@ In cases where the incoming codes are not known, or not all available keys may be supported by the actual remote control in use, you may want to derive your own remote control class from cRemote, as in -


    +

     #include <vdr/remote.h>
     #include <vdr/thread.h>
     
    @@ -1472,7 +1551,7 @@ when the program ends).
     

    The constructor of your remote control class should look like this -


    +

     cMyRemote::cMyRemote(const char *Name)
     :cRemote(Name)
     {
    @@ -1492,7 +1571,7 @@ member variables, you should do so before calling Start().
     If your remote control for some reason can't work (maybe because it was unable to
     open some file handle it requires) it can implement the virtual function
     
    -


    +

     virtual bool Ready(void);
     

    @@ -1513,7 +1592,7 @@ If your remote control class needs some setup data that shall be readily available next time VDR starts (without having to go through the initialization procedure again) it can use the cRemote member functions -


    +

     void PutSetup(const char *Setup);
     const char *GetSetup(void);
     

    @@ -1527,7 +1606,7 @@ The cRemote class assumes that any incoming remote control code can be expressed as a character string. So whatever data your remote control provides needs to be given to the base class by calling -


    +

     Put(const char *Code, bool Repeat = false, bool Release = false);
     

    @@ -1538,7 +1617,7 @@ Since a common case for remote control data is to be given as a numerical value, there is another Put() function available for your convenience, which takes a 64 bit unsigned integer value instead of a character string: -


    +

     Put(uint64 Code, bool Repeat = false, bool Release = false);
     

    -- cgit v1.2.3