VDR logo VDR - The Video Disk Recorder
Change Log
VDR on facebook
stop software patents

© 2018 KLS

This is a summary of the changes in VDR 2.4.0 since the last stable version 2.2.0. It only contains things that are of actual importance to the user and doesn't mention the many fixes and improvements that have been made "behind the scenes". See the file HISTORY that comes with the VDR source for a detailed list of all changes.


  • If there is more than one VDR in the local network, they can now form a peer-to-peer network, so that timers can be moved freely between them. The following changes have been made to implement this:
    • VDR now sends out a broadcast to port 6419/udp, which was assigned to 'svdrp-disc' by the IANA. VDRs listening on that port will automatically initiate an SVDRP connection to the broadcasting VDR, and in turn send out a broadcast to make other VDRs connect to them. That way all VDRs within the local network will have permanent "peer-to-peer" SVDRP connections between each other. The configuration in the svdrphosts.conf file is taken into account when considering whether or not to respond to an SVDRP discover broadcast.
    • The new SVDRP command PING is used by automatically established peer-to-peer connections to keep them alive.
    • The new function GetSVDRPServerNames() can be used to get a list of all VDRs this VDR is connected to via SVDRP.
    • The new function ExecSVDRPCommand() can be used to execute an SVDRP command on one of the servers this VDR is connected to, and retrieve the result. The helper functions SVDRPCode() and SVDRPValue() can be used to easily access the codes and values returned by ExecSVDRPCommand().
    • The new SVDRP command POLL is used by automatically established peer-to-peer connections to trigger fetching remote timers.
    • The new options "Setup/Miscellaneous/SVDRP peering", ".../SVDRP host name" and ".../SVDRP default host" can be used to configure automatic peering between VDRs in the same network. Peering is disabled by default and can be enabled by setting "SVDRP peering" to "yes".
    • The "Edit timer" menu now has a new parameter "Record on", which can be used to select the VDR on which this timer shall record. Timers can be freely moved between connected VDRs by simply selecting the desired machine in this field.
    • The cTimer class now has a new member named 'remote', which holds the name of the remote server this timer will record on. If this is NULL, it is a local timer.
    • Added a note to the "Pausing live video" section of the MANUAL, stating that the timer for paused live video will always record on the local VDR, even if an "SVDRP default host" has been set for normal timer recordings.
    • The Perl script 'peerdemo' shows how one can find all the VDRs in the local network using the peer connection mechanism.
Conditional Access
  • Implemented support for MTD ("Multi Transponder Decryption"). This allows a CAM that is capable of decrypting more than one channel ("Multi Channel Decryption") to decrypt channels from different transponders. See the remarks in mtd.h on what a derived cCamSlot class needs to do in order to activate MTD.
  • The Setup/CAM menu now displays which device an individual CAM is currently assigned to.
  • The channel/CAM relations (i.e. the information which CAM can decrypt a given channel) are now stored in the file 'cam.data' in the cache directory. This speeds up switching to encrypted channels after newly starting VDR, in case there is more than one CAM in the system. The file 'cam.data' is not written if it is read-only.
  • The mechanism of trying different CAMs when switching to an encrypted channel is now only triggered if there acually is more than one CAM in the system.
  • CAMs that can handle multiple devices at the same time can now indicate this by creating the first cCamSlot as usual, and every other cCamSlot by giving it the first one as its "MasterSlot". To VDR this means that when searching for a CAM that can decrypt a particular channel, it only needs to ask the master CAM slot whether it is suitable for decrypting, and can skip all the other slots belonging to the same master. This can greatly speed up channel switching on systems with more than one CAM (that can handle multiple devices).
  • The LCARS skin now displays the master CAM's number when a device is tuned to an encrypted channel.
  • The Setup/CAM menu now only displays master CAMs.
  • Detecting whether a particular CAM actually decrypts a given channel is now done separately for each receiver.
  • The function cCamSlot::Decrypt() can now also be called with Data == NULL. This is necessary to allow CAMs that copy the incoming data into a separate buffer to return previously received and decrypted TS packets. See ci.h for details. Plugins that implement a derived cCamSlot need to properly handle this case, and plugins that implement a derived cDevice need to call Decrypt() in their GetTSPacket() function even if the incoming buffer is currently empty (see cDvbDevice::GetTSPacket()).
  • CAMs are now sent a generated EIT packet that contains a single 'present event' for the current SID, in order to avoid any parental rating dialogs.
  • When selecting a device/CAM combination for live viewing, CAMs that are known to decrypt the requested channel are now given a higher priority than prefering the primary device.
  • Extended the CI API to allow plugins to implement additional CAM resources.
  • The new configuration file 'camresponses.conf' can be used to define automatic responses to CAM menus, for instance to avoid annyoing popup messages or entering the parental rating PIN. See vdr.5 for details.
  • The cTimer class now has a new member named 'remote', which holds the name of the remote server this timer will record on. If this is NULL, it is a local timer.
  • Timers from other VDRs that are connected to this VDR via SVDRP are now automatically fetched and stored in the global Timers list. In order for this to work, all of the channels used by timers on the remote VDR must also be defined on the local VDR (however, not necessarily in the same sequence).
  • Accessing the global Timers list now has to be protected by proper locking, because SVDRP commands are now executed in a separate thread. The introduction of this locking mechanism required the following changes:
    • The new classes cStateLock and cStateKey are used to implement locking with quick detection of state changes.
    • cConfig::cConfig() now has a parameter that indicates whether this list requires locking.
    • The global lists of Timers, Channels, Schedules and Recordings are no longer static variables. They are now pointers that need to be retrieved through a call to cTimers::GetTimersRead/Write(), cChannels::GetChannelsRead/Write(), cSchedules::GetSchedulesRead/Write() and cRecordings::GetRecordingsRead/Write(), respectively.
    • References from/to link channels are now removed in cChannels::Del() rather than cChannel::~cChannel(), to make sure the caller holds a proper lock.
    • cChannel::HasTimer() has been removed. This information is now retrieved via cSchedule::HasTimer().
    • Several member functions of cChannel, cTimer, cMarks and cRecording have been made 'const', and some of them are now available as both 'const' and 'non-const' versions.
    • The cChannel::Set...() functions are now 'bool' and return true if they have actually changed any of the channels's members.
    • cChannels::SetModified() has been renamed to cChannels::SetModifiedByUser().
    • cChannels::Modified() has been renamed to cChannels::ModifiedByUser(), and now has a 'State' parameter that allows the caller to see whether a channel has been modified since the last call to this function with the same State variable.
    • The macros CHANNELSMOD_NONE/_AUTO/_USER have been removed.
    • cMarks now requires locking via cStateKey.
    • cSortedTimers now requires a pointer to the list of timers.
    • cEvent::HasTimer() no longer scans the list of timers to check whether an event is referenced by a timer, but rather keeps score of how many timers reference it. This was necessary in order to avoid having to lock the list of timers from within a cEvent.
    • The new class cListGarbageCollector is used to temporary store any objects deleted from cLists that require locking. This allows pointers to such objects to be dereferenced even if the objects are no longer part of the list.
    • cListBase::Contains() can be used to check whether a particular object is still contained in that list.
    • Outdated events are no longer "phased out", but rather deleted right away and thus taken care of by the new "garbage collector" of the list.
    • Deleted cRecording objects are no longer kept in a list of "vanished" recordings, but are rather taken care of by the new "garbage collector" of the list.
    • cSchedules::ClearAll() has been removed. The functionality is now implemented directly in cSVDRPServer::CmdCLRE().
    • cSchedule now has a member Modified(), which can be used with a State variable to quickly determine whether this schedule has been modified since the last call to this function with the same State variable.
    • cSchedulesLock has been removed. Locking the list of schedules is now done via the cList's new locking mechanism.
    • The 'OnlyRunningStatus' parameters in cEpgHandler::BeginSegmentTransfer() and cEpgHandler::EndSegmentTransfer() are now obsolete. They are still present in the interface for backward compatibility, but may be removed in a future version. Their value is always 'false'.
    • The constant tcMod is no longer used in cStatus::TimerChange(). The definition is still there for backward compatibility.
  • Plugins that access the global lists of Timers, Channels, Recordings or Schedules will need to be adapted as follows:
    • Instead of directly accessing the global variables Timers, Channels or Recordings, they need to set up a cStateKey variable and call the proper getter function, as in cStateKey StateKey; if (const cTimers *Timers = cTimers::GetTimersRead(StateKey)) { // access the timers StateKey.Remove(); } and cStateKey StateKey; if (cTimers *Timers = cTimers::GetTimersWrite(StateKey)) { // access the timers StateKey.Remove(); } See timers.h, thread.h and tools.h for details on this new locking mechanism.
    • There are convenience macros for easily accessing these lists without having to explicitly set up a cStateKey and calling its Remove() function. These macros have the form LOCK_*_READ/WRITE (with '*' being TIMERS, CHANNELS, SCHEDULES or RECORDINGS). Simply put such a macro before the point where you need to access the respective list, and there will be a pointer named Timers, Channels, Schedules or Recordings, respectively, which is valid until the end of the current block.
    • If a plugin needs to access several of the global lists in parallel, locking must always be done in the sequence Timers, Channels, Recordings, Schedules. This is necessary to make sure that different threads that need to lock several lists at the same time don't end up in a deadlock.
    • Some pointer variables may need to be made 'const'. The compiler will tell you about these.
  • If a timer is newly created with the Red button in the Schedule menu, and the timer is presented to the user in the "Edit timer" menu because it will start immediately, it now *must* be confirmed with "Ok" to set the timer. Otherwise the timer will not be created.
  • The function cTimer::ToText() no longer returns a newline character at the end of the string. The newline is now added by the caller as necessary. This was changed because cTimer::ToText() is now also needed in a context where the terminating newline can't be used. Consequently, cChannel::ToText() and cMark::ToText() have been modified accordingly.
  • Timers now have unique ids instead of numbers, which remain valid as long as this instance of VDR is running. This means that timers are no longer continuously numbered from 1 to N in LSTT. There may be gaps in the sequence, in case timers have been deleted.
  • Timers are now linked to EPG events even if they are inactive. By default Events that are linked to inactive timers are marked with 'I' and 'i', depending on whether the timer would record the entire Event or only part of it. The function cSkinDisplayMenu::SetItemEvent() now has an additional parameter named TimerActive, which indicates whether the timer that would record this event (if any) is active. A plugin may react on this when displaying a menu line for an event. The old version of cSkinDisplayMenu::SetItemEvent() (without the TimerActive parameter) is still there for backwards compatibility. It may be removed in a future version, so plugin authors should switch to the new one.
  • Improved handling VPS timers to better react to EPG changes during an ongoing recording.
  • The dvbhddevice plugin is no longer part of the VDR source archive. You can get the latest version of this plugin from the author's repository at https://bitbucket.org/powARman/dvbhddevice.
  • The dvbsddevice and rcu plugins are no longer part of the VDR source archive. You can get the latest versions of these plugins from ftp://ftp.tvdr.de/vdr/Plugins.
  • The -V and -h options now list the plugins in alphabetical order.
  • Added some guidelines and recommendations to the 'Logging' section of PLUGINS.html. The most important being: implement a command line option to control the level of logging (in particular allow turning off logging completely!) and never print anything to stdout or stderr (unless one of the listed exceptions applies).
  • Added a note to PLUGINS.html about writing log messages in English.
  • The new function cStatus::MarksModified() can be implemented by plugins to get informed about any modifications to the editing marks of the currently played recording.
  • The main menu of the LCARS skin now displays a small rectangle on the left side of a timer if this is a remote timer. The color of that rectangle changes if the timer is currently recording on the remote VDR.
  • Skins can now implement cSkinDisplayMenu::MenuOrientation() to display horizontal menus.
  • The LCARS skin now displays the master CAM's number when a device is tuned to an encrypted channel.
Remote control
  • The new setup option "Recording/Record key handling" can be used to define what happens if the Record key on the remote control is pressed during live tv.
  • If the Channel+/- keys are pressed while in the Schedules menu, the menu is now switched to the EPG of the new current channel.
  • The command line option -D now accepts the value '-' (as in -D-), which prevents VDR from using any DVB devices.
  • The function cDevice::SetCurrentChannel(const cChannel *Channel) is now deprecated and may be removed in a future version. Use SetCurrentChannel(int ChannelNumber) instead.
  • Signal strength and quality (CNR) are now determined via DVB API 5 (if available). Fallback is the old DVB API 3 method.
  • The new function cDevice::SignalStats() (if implemented by an actual device) returns statistics about the currently received signal.
  • The function cDevice::GetVideoSystem() (which has been deprecated since version 2.1.6) has been finally removed.
  • Switching the primary device is no longer done via osSwitchDvb (which has been removed), but rather by the main program loop reacting to changes in Setup.PrimaryDVB.
  • The character 0x0D is now stripped from EPG texts.
  • The EPG scanner no longer moves the dish if there is a positioner.
  • The function cEpgHandlers::BeginSegmentTransfer() is now boolean. See the description in epg.h for the meaning of the return value.
  • The cEvent class now has a new member 'aux', in which external applications can store auxiliary information with an event. This string has no meaning whatsoever to VDR itself, and it will not be written into the info file of a recording that is made for such an event.
  • Changed the default return value of cEpgHandler::BeginSegmentTransfer() to true, to avoid problems with derived classes that don't implement this function.
  • The EIT filter no longer parses data from "other TS", to avoid problems with broadcasters who transmit faulty EIT data.
  • The new function cOsd::MaxPixmapSize() can be called to determine the maximum size a cPixmap may have on the current OSD. The 'osddemo' example has been modified accordingly. Plugin authors may want to use this function in case they use pixmaps that are larger than the full OSD size. The default implementation sets this limit to 2048x2048 pixel.
  • Added some comment to cPixmap about the relation between OSD, ViewPort and DrawPort.
  • The new setup option "OSD/Default sort mode for recordings" can be used to define how recordings shall be sorted by default (either by time or by name, with "by time" being the default). If a particular sort mode has been selected for a folder by pressing '0', the default no longer applies to that folder. Repeating timers no longer write a ".sort" file into a recordings folder to have the recordings sorted by time.
  • The function cOsd::GetBitmap() is now 'protected'. If a plugin doesn't compile with this version of VDR, you can uncomment the line //#define DEPRECATED_GETBITMAP in osd.h as a quick workaround. In the long run the plugin will need to be adapted.
  • Background modifications of channels, timers and events are now displayed immediately in the corresponding menus.
  • The Timers menu now displays the name of the remote VDR in front of the timer's file name, if this is a remote timer.
  • The width and height of the OSD are now limited to the actual maximum dimensions of the output device, taking into account the top and left offset.
  • Added a note to the description of cFont::Size(), regarding possible differences between it and cFont::Height().
  • Added cFont::Width(void) to get the default character width and allow stretched font drawing in high level OSDs.
  • cOsdMenu::Display() now checks whether the OSD size has changed and if so calls SetDisplayMenu().
  • The option "Setup/Miscellaneous/Show channel names with source" can now be set to "type" or "full" to show either the type or the full name of the source.
  • The "Channels" menu now indicates whether a channel is encrypted ('X') or a radio channel ('R').
  • The timeout for the channel display is now reset whenever the channel or EPG data changes.
  • OSD menus now try to keep the offset of the list cursor at a constant position on the screen, even if the list is modified while being displayed.
  • If an event in the Schedules menu is marked with a 'T' or 'I' and the user presses the Red button to edit the timer, local timers are now preferred over remote timers in case there is more than one timer that will record that event.
  • The new setup option "OSD/Sorting direction for recordings" can be used to switch the sequence in which recordings are presented in the "Recordings" menu between ascending (oldest first) and descendeng (newest first).
  • When selecting a folder for a recording or timer, it is now possible to open a folder even if it doesn't contain any subfolders.
  • Recordings now have unique ids instead of numbers, which remain valid as long as this instance of VDR is running. This means that recordings are no longer continuously numbered from 1 to N in LSTR. There may be gaps in the sequence, in case recordings have been deleted, and they are not necessarily listed in numeric order.
  • Added detection of 24fps.
  • The script that gets called for recordings is now also called right before a recording is edited, with the first parameter being "editing".
  • Implemented a frame parser for H.265 (HEVC) recordings.
  • When moving recordings between volumes, the "Recordings" menu now displays those items that have not yet been moved completely as non-selectable. This avoids situations where trying to play such a recording might fail.
  • When moving a recording to a different folder, the cursor is no longer placed on the new location of the recording, but rather stays in the original folder. If the original folder got empty by moving away the last recording it contained, the cursor is moved up until a non empty folder is found.
  • The SVDRP port now accepts multiple concurrent connections. You can now keep an SVDRP connection open as long as you wish, without preventing others from connecting. Note, though, that SVDRP connections still get closed automatically if there has been no activity for 300 seconds (configurable via "Setup/Miscellaneous/SVDRP timeout (s)").
  • The SVDRP log messages have been unified and now always contain the IP and port number of the remote host.
  • SVDRP connections are now handled in a separate "SVDRP server handler" thread, which makes them more responsive. Note that there is only one thread that handles all concurrent SVDRP connections. That way each SVDRP command is guaranteed to be processed separately, without interfering with any other SVDRP commands that might be issued at the same time. Plugins that implement SVDRP commands may need to take care of proper locking if the commands access global data.
  • You can now set DumpSVDRPDataTransfer in svdrp.c to true to have all SVDRP communication printed to the console for debugging.
  • The SVDRP commands that deal with timers (DELT, LSTT, MODT, NEWT, NEXT and UPDT) as well as any log messages that refer to timers, now use a unique id for each timer, which remains valid as long as this instance of VDR is running. This means that timers are no longer continuously numbered from 1 to N in LSTT. There may be gaps in the sequence, in case timers have been deleted.
  • All timer related response strings from SVDRP commands now use the channel ID instead of channel numbers.
  • The SVDRP command DELT no longer checks whether the timer that shall be deleted is currently recording.
  • The SVDRP command DELC now refuses to delete the very last channel in the list, to avoid ending up with an empty channel list.
  • The SVDRP commands that deal with recordings (DELR, EDIT, LSTR, MOVR, and PLAY) now use a unique id for each recording, which remains valid as long as this instance of VDR is running. This means that recordings are no longer continuously numbered from 1 to N in LSTR. There may be gaps in the sequence, in case recordings have been deleted, and they are not necessarily listed in numeric order.
  • Changed 'number' to 'id' in the help texts of SVDRP commands that deal with timers.
  • The SVDRP command LSTC can now list the channels with channel ids if the option ':ids' is given.
  • If 0 is given as the channel number in the SVDRP command LSTC, the data of the current channel is listed.
  • The new SVDRP commands 'LSTD' and 'PRIM' can be used to list all available devices and to switch the primary device.
  • Added a section about Output Devices to the INSTALL file.
  • The -u option now also accepts a numerical user id.
  • The cRwLock class now allows nested read locks within a write lock from the same thread. This fixes possible crashes when moving or deleting channels in the menu or through SVDRP (as well as other operations that try to acquire a read lock within a write lock).
  • Added support for the systemd watchdog.
  • PIDs can now be added to and deleted from a cReceiver while it is attached to a cDevice, without having to detach it first and re-attach it afterwards.
  • Log messages about switching channels now include the channel ID.
  • The constructor of cHash (via cHashBase) now has an additional parameter (OwnObjects) which, if set to true, makes the hash take ownership of the hashed objects, so that they are deleted when the hash is cleared or destroyed.
  • cListObject now implements a private copy constructor and assignment operator, to keep derived objects from calling them implicitly.
  • The Makefiles have been modified so that during the build process they no longer display the actual (lengthy) commands, but rather just the name of the file that is being built, as in CC vdr.o The first two characters indicate the kind of operation (CC=compile, LD=link, AR=archive, MO=msgfmt, GT=xgettext, PO=msgmerge, IN=install). This way it is much easier to spot error messages and warnings, since they are not buried under tons of text. Add VERBOSE=1 to the 'make' call in the VDR source directory to see the actual commands that are executed. Plugin authors should modify their makefiles accordingly, by simply preceeding the respective commands with '$(Q)' and inserting '@echo XX $@' (where XX is one of the character combinations listed above) before the command. The newplugin script has also been modified accordingly. Note that if you build a plugin directly in the plugin's own source directory, the $(Q) macro won't be defined and commands will be displayed. You can add Q=@ to the make call to have it less verbose (provided the plugin's Makefile was modified as described above).
  • Added backtrace functions for debugging (see cBackTrace in thread.h).
  • Added checking the correct sequence of locking global lists. At the first occurrence of an invalid locking sequence, the 20 most recent locks will be written to the log file, followed by a backtrace that led to the call in question. This code can be activated by defining the macro DEBUG_LOCKSEQ in thread.c (which is on by default). When debugging an actual invalid locking sequence, you can additionally define the macro DEBUG_LOCKCALL in thread.c, which will add information about the caller of each lock. Note that this may cause some stress on the CPU, therefore it is off by default.
  • The file Make.config.template now reacts on DEBUG=1 in the 'make' command line, and disables code optimizations by setting -O0. This can be helpful when backtracing highly optimized code. You may want to 'make distclean' before running 'make' with a modified setting of DEBUG, to make sure all object files are newly compiled.
  • Introduced the new macro DISABLE_TEMPLATES_COLLIDING_WITH_STL, which can be defined before including tools.h in case some plugin needs to use the STL and gets error messages regarding one of the template functions defined in tools.h.
  • The macros used to control deprecated code or functions have been changed to hold numeric values (0 and 1), so that they can be controlled at compile time, without having to edit the actual source code.
  • The default for DEPRECATED_VDR_CHARSET_OVERRIDE has been set to 0, which means VDR no longer reacts on the environment variable VDR_CHARSET_OVERRIDE. You can add 'DEPRECATED_VDR_CHARSET_OVERRIDE=1' when compiling in order to restore this functionality. However, it is recommended to use the command line option --chartab instead.
  • Disabled the use of posix_fadvise() when reading (i.e. replaying), since it caused stuttering replay in fast forward and fast rewind mode in case the video directory is mounted via NFS. You can re-enable it by setting the macro USE_FADVISE_READ to 1 in tools.c.