diff options
Diffstat (limited to 'PLUGINS')
-rw-r--r-- | PLUGINS/src/dvbsddevice/COPYING (renamed from PLUGINS/src/sky/COPYING) | 0 | ||||
-rw-r--r-- | PLUGINS/src/dvbsddevice/HISTORY | 12 | ||||
-rw-r--r-- | PLUGINS/src/dvbsddevice/Makefile (renamed from PLUGINS/src/sky/Makefile) | 43 | ||||
-rw-r--r-- | PLUGINS/src/dvbsddevice/README | 20 | ||||
-rw-r--r-- | PLUGINS/src/dvbsddevice/dvbsddevice.c | 35 | ||||
-rw-r--r-- | PLUGINS/src/dvbsddevice/dvbsdffdevice.c | 799 | ||||
-rw-r--r-- | PLUGINS/src/dvbsddevice/dvbsdffdevice.h | 107 | ||||
-rw-r--r-- | PLUGINS/src/dvbsddevice/dvbsdffosd.c | 213 | ||||
-rw-r--r-- | PLUGINS/src/dvbsddevice/dvbsdffosd.h | 22 | ||||
-rw-r--r-- | PLUGINS/src/hello/HISTORY | 6 | ||||
-rw-r--r-- | PLUGINS/src/hello/hello.c | 6 | ||||
-rw-r--r-- | PLUGINS/src/pictures/HISTORY | 4 | ||||
-rw-r--r-- | PLUGINS/src/pictures/pictures.c | 6 | ||||
-rw-r--r-- | PLUGINS/src/skincurses/HISTORY | 5 | ||||
-rw-r--r-- | PLUGINS/src/skincurses/skincurses.c | 26 | ||||
-rw-r--r-- | PLUGINS/src/sky/HISTORY | 70 | ||||
-rw-r--r-- | PLUGINS/src/sky/README | 49 | ||||
-rw-r--r-- | PLUGINS/src/sky/channels.conf.sky | 34 | ||||
-rwxr-xr-x | PLUGINS/src/sky/getskyepg.pl | 260 | ||||
-rw-r--r-- | PLUGINS/src/sky/lircd.conf.sky | 299 | ||||
-rw-r--r-- | PLUGINS/src/sky/sky.c | 303 |
21 files changed, 1288 insertions, 1031 deletions
diff --git a/PLUGINS/src/sky/COPYING b/PLUGINS/src/dvbsddevice/COPYING index f90922e..f90922e 100644 --- a/PLUGINS/src/sky/COPYING +++ b/PLUGINS/src/dvbsddevice/COPYING diff --git a/PLUGINS/src/dvbsddevice/HISTORY b/PLUGINS/src/dvbsddevice/HISTORY new file mode 100644 index 0000000..18cd625 --- /dev/null +++ b/PLUGINS/src/dvbsddevice/HISTORY @@ -0,0 +1,12 @@ +VDR Plugin 'dvbsddevice' Revision History +----------------------------------------- + +2009-12-28: Version 0.0.1 + +- Initial revision. + +2010-01-04: Version 0.0.2 + +- Calling the MakePrimaryDevice() function of the base class to allow + the cDevice to stop displaying subtitles. +- Added support for DVB cards with multiple fontends. diff --git a/PLUGINS/src/sky/Makefile b/PLUGINS/src/dvbsddevice/Makefile index 87fbcba..8ef273c 100644 --- a/PLUGINS/src/sky/Makefile +++ b/PLUGINS/src/dvbsddevice/Makefile @@ -1,13 +1,15 @@ # # Makefile for a Video Disk Recorder plugin # -# $Id: Makefile 2.0 2008/01/13 13:00:16 kls Exp $ +# $Id: Makefile 1.1 2009/12/29 11:53:18 kls Exp $ # The official name of this plugin. # This name will be used in the '-P...' option of VDR to load the plugin. # By default the main source file also carries this name. +# IMPORTANT: the presence of this macro is important for the Make.config +# file. So it must be defined, even if it is not used here! # -PLUGIN = sky +PLUGIN = dvbsddevice ### The version number of this plugin (taken from the main source file): @@ -43,28 +45,55 @@ INCLUDES += -I$(VDRDIR)/include DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' +DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE + ### The object files (add further files here): -OBJS = $(PLUGIN).o +OBJS = $(PLUGIN).o dvbsdffdevice.o dvbsdffosd.o ### The main target: -all: libvdr-$(PLUGIN).so +all: libvdr-$(PLUGIN).so i18n ### Implicit rules: %.o: %.c $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< -# Dependencies: +### Dependencies: -MAKEDEP = g++ -MM -MG +MAKEDEP = $(CXX) -MM -MG DEPFILE = .dependencies $(DEPFILE): Makefile @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ -include $(DEPFILE) +### Internationalization (I18N): + +PODIR = po +LOCALEDIR = $(VDRDIR)/locale +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Npot = $(PODIR)/$(PLUGIN).pot + +%.mo: %.po + msgfmt -c -o $@ $< + +$(I18Npot): $(wildcard *.c) + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='<see README>' -o $@ $^ + +%.po: $(I18Npot) + msgmerge -U --no-wrap --no-location --backup=none -q $@ $< + @touch $@ + +$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + @mkdir -p $(dir $@) + cp $< $@ + +.PHONY: i18n +i18n: $(I18Nmsgs) $(I18Npot) + ### Targets: libvdr-$(PLUGIN).so: $(OBJS) @@ -80,4 +109,4 @@ dist: clean @echo Distribution package created as $(PACKAGE).tgz clean: - @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot diff --git a/PLUGINS/src/dvbsddevice/README b/PLUGINS/src/dvbsddevice/README new file mode 100644 index 0000000..9b1280f --- /dev/null +++ b/PLUGINS/src/dvbsddevice/README @@ -0,0 +1,20 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Klaus Schmidinger <Klaus.Schmidinger@tvdr.de> + +Project's homepage: http://www.tvdr.de + +Latest version available at: ftp://ftp.tvdr.de/vdr + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +See the file COPYING for more information. + +Description: + +The 'dvbsddevice' plugin implements the output device for the +"Full Featured" DVB cards based on the TechnoTrend/Fujitsu-Siemens +design. This code was originally part of the core VDR source, and +was moved into this plugin in VDR version 1.7.11. diff --git a/PLUGINS/src/dvbsddevice/dvbsddevice.c b/PLUGINS/src/dvbsddevice/dvbsddevice.c new file mode 100644 index 0000000..e2248e9 --- /dev/null +++ b/PLUGINS/src/dvbsddevice/dvbsddevice.c @@ -0,0 +1,35 @@ +/* + * dvbsddevice.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: dvbsddevice.c 1.2 2010/01/01 15:01:01 kls Exp $ + */ + +#include <vdr/plugin.h> +#include "dvbsdffdevice.h" + +static const char *VERSION = "0.0.2"; +static const char *DESCRIPTION = "SD Full Featured DVB device"; + +class cPluginDvbsddevice : public cPlugin { +private: + cDvbSdFfDeviceProbe *probe; +public: + cPluginDvbsddevice(void); + virtual ~cPluginDvbsddevice(); + virtual const char *Version(void) { return VERSION; } + virtual const char *Description(void) { return DESCRIPTION; } + }; + +cPluginDvbsddevice::cPluginDvbsddevice(void) +{ + probe = new cDvbSdFfDeviceProbe; +} + +cPluginDvbsddevice::~cPluginDvbsddevice() +{ + delete probe; +} + +VDRPLUGINCREATOR(cPluginDvbsddevice); // Don't touch this! diff --git a/PLUGINS/src/dvbsddevice/dvbsdffdevice.c b/PLUGINS/src/dvbsddevice/dvbsdffdevice.c new file mode 100644 index 0000000..21a60a5 --- /dev/null +++ b/PLUGINS/src/dvbsddevice/dvbsdffdevice.c @@ -0,0 +1,799 @@ +/* + * dvbsdffdevice.h: The DVB SD Full Featured device interface + * + * See the README file for copyright information and how to reach the author. + * + * $Id: dvbsdffdevice.c 2.25 2010/01/04 12:56:56 kls Exp $ + */ + +#include "dvbsdffdevice.h" +#include <errno.h> +#include <limits.h> +#include <linux/videodev2.h> +#include <linux/dvb/audio.h> +#include <linux/dvb/dmx.h> +#include <linux/dvb/video.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include "dvbsdffosd.h" +#include "vdr/eitscan.h" +#include "vdr/transfer.h" + +// --- cDvbSdFfDevice -------------------------------------------------------- + +int cDvbSdFfDevice::devVideoOffset = -1; + +cDvbSdFfDevice::cDvbSdFfDevice(int Adapter, int Frontend) +:cDvbDevice(Adapter, Frontend) +{ + spuDecoder = NULL; + digitalAudio = false; + playMode = pmNone; + + // Devices that are only present on cards with decoders: + + fd_osd = DvbOpen(DEV_DVB_OSD, adapter, frontend, O_RDWR); + fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK); + fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK); + fd_stc = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR); + + // The offset of the /dev/video devices: + + if (devVideoOffset < 0) { // the first one checks this + FILE *f = NULL; + char buffer[PATH_MAX]; + for (int ofs = 0; ofs < 100; ofs++) { + snprintf(buffer, sizeof(buffer), "/proc/video/dev/video%d", ofs); + if ((f = fopen(buffer, "r")) != NULL) { + if (fgets(buffer, sizeof(buffer), f)) { + if (strstr(buffer, "DVB Board")) { // found the _first_ DVB card + devVideoOffset = ofs; + dsyslog("video device offset is %d", devVideoOffset); + break; + } + } + else + break; + fclose(f); + } + else + break; + } + if (devVideoOffset < 0) + devVideoOffset = 0; + if (f) + fclose(f); + } + devVideoIndex = devVideoOffset >= 0 ? devVideoOffset++ : -1; + + // Video format: + + SetVideoFormat(Setup.VideoFormat); +} + +cDvbSdFfDevice::~cDvbSdFfDevice() +{ + delete spuDecoder; + // We're not explicitly closing any device files here, since this sometimes + // caused segfaults. Besides, the program is about to terminate anyway... +} + +void cDvbSdFfDevice::MakePrimaryDevice(bool On) +{ + if (On) + new cDvbOsdProvider(fd_osd); + cDvbDevice::MakePrimaryDevice(On); +} + +bool cDvbSdFfDevice::HasDecoder(void) const +{ + return true; +} + +cSpuDecoder *cDvbSdFfDevice::GetSpuDecoder(void) +{ + if (!spuDecoder && IsPrimaryDevice()) + spuDecoder = new cDvbSpuDecoder(); + return spuDecoder; +} + +uchar *cDvbSdFfDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY) +{ + if (devVideoIndex < 0) + return NULL; + char buffer[PATH_MAX]; + snprintf(buffer, sizeof(buffer), "%s%d", DEV_VIDEO, devVideoIndex); + int videoDev = open(buffer, O_RDWR); + if (videoDev >= 0) { + uchar *result = NULL; + // set up the size and RGB + v4l2_format fmt; + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = SizeX; + fmt.fmt.pix.height = SizeY; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24; + fmt.fmt.pix.field = V4L2_FIELD_ANY; + if (ioctl(videoDev, VIDIOC_S_FMT, &fmt) == 0) { + v4l2_requestbuffers reqBuf; + memset(&reqBuf, 0, sizeof(reqBuf)); + reqBuf.count = 2; + reqBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqBuf.memory = V4L2_MEMORY_MMAP; + if (ioctl(videoDev, VIDIOC_REQBUFS, &reqBuf) >= 0) { + v4l2_buffer mbuf; + memset(&mbuf, 0, sizeof(mbuf)); + mbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mbuf.memory = V4L2_MEMORY_MMAP; + if (ioctl(videoDev, VIDIOC_QUERYBUF, &mbuf) == 0) { + int msize = mbuf.length; + unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0); + if (mem && mem != (unsigned char *)-1) { + v4l2_buffer buf; + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = 0; + if (ioctl(videoDev, VIDIOC_QBUF, &buf) == 0) { + v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl (videoDev, VIDIOC_STREAMON, &type) == 0) { + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = 0; + if (ioctl(videoDev, VIDIOC_DQBUF, &buf) == 0) { + if (ioctl(videoDev, VIDIOC_STREAMOFF, &type) == 0) { + // make RGB out of BGR: + int memsize = fmt.fmt.pix.width * fmt.fmt.pix.height; + unsigned char *mem1 = mem; + for (int i = 0; i < memsize; i++) { + unsigned char tmp = mem1[2]; + mem1[2] = mem1[0]; + mem1[0] = tmp; + mem1 += 3; + } + + if (Quality < 0) + Quality = 100; + + dsyslog("grabbing to %s %d %d %d", Jpeg ? "JPEG" : "PNM", Quality, fmt.fmt.pix.width, fmt.fmt.pix.height); + if (Jpeg) { + // convert to JPEG: + result = RgbToJpeg(mem, fmt.fmt.pix.width, fmt.fmt.pix.height, Size, Quality); + if (!result) + esyslog("ERROR: failed to convert image to JPEG"); + } + else { + // convert to PNM: + char buf[32]; + snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", fmt.fmt.pix.width, fmt.fmt.pix.height); + int l = strlen(buf); + int bytes = memsize * 3; + Size = l + bytes; + result = MALLOC(uchar, Size); + if (result) { + memcpy(result, buf, l); + memcpy(result + l, mem, bytes); + } + else + esyslog("ERROR: failed to convert image to PNM"); + } + } + else + esyslog("ERROR: video device VIDIOC_STREAMOFF failed"); + } + else + esyslog("ERROR: video device VIDIOC_DQBUF failed"); + } + else + esyslog("ERROR: video device VIDIOC_STREAMON failed"); + } + else + esyslog("ERROR: video device VIDIOC_QBUF failed"); + munmap(mem, msize); + } + else + esyslog("ERROR: failed to memmap video device"); + } + else + esyslog("ERROR: video device VIDIOC_QUERYBUF failed"); + } + else + esyslog("ERROR: video device VIDIOC_REQBUFS failed"); + } + else + esyslog("ERROR: video device VIDIOC_S_FMT failed"); + close(videoDev); + return result; + } + else + LOG_ERROR_STR(buffer); + return NULL; +} + +void cDvbSdFfDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) +{ + cDevice::SetVideoDisplayFormat(VideoDisplayFormat); + if (Setup.VideoFormat) { + CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_LETTER_BOX)); + } + else { + switch (VideoDisplayFormat) { + case vdfPanAndScan: + CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_PAN_SCAN)); + break; + case vdfLetterBox: + CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_LETTER_BOX)); + break; + case vdfCenterCutOut: + CHECK(ioctl(fd_video, VIDEO_SET_DISPLAY_FORMAT, VIDEO_CENTER_CUT_OUT)); + break; + default: esyslog("ERROR: unknown video display format %d", VideoDisplayFormat); + } + } +} + +void cDvbSdFfDevice::SetVideoFormat(bool VideoFormat16_9) +{ + CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, VideoFormat16_9 ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3)); + SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat)); +} + +eVideoSystem cDvbSdFfDevice::GetVideoSystem(void) +{ + eVideoSystem VideoSystem = vsPAL; + if (fd_video >= 0) { + video_size_t vs; + if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) { + if (vs.h == 480 || vs.h == 240) + VideoSystem = vsNTSC; + } + else + LOG_ERROR; + } + return VideoSystem; +} + +void cDvbSdFfDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect) +{ + if (fd_video >= 0) { + video_size_t vs; + if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) { + Width = vs.w; + Height = vs.h; + switch (vs.aspect_ratio) { + default: + case VIDEO_FORMAT_4_3: VideoAspect = 4.0 / 3.0; break; + case VIDEO_FORMAT_16_9: VideoAspect = 16.0 / 9.0; break; + case VIDEO_FORMAT_221_1: VideoAspect = 2.21; break; + } + return; + } + else + LOG_ERROR; + } + cDevice::GetVideoSize(Width, Height, VideoAspect); +} + +void cDvbSdFfDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect) +{ + if (fd_video >= 0) { + video_size_t vs; + if (ioctl(fd_video, VIDEO_GET_SIZE, &vs) == 0) { + Width = 720; + if (vs.h != 480 && vs.h != 240) + Height = 576; // PAL + else + Height = 480; // NTSC + switch (Setup.VideoFormat ? vs.aspect_ratio : VIDEO_FORMAT_4_3) { + default: + case VIDEO_FORMAT_4_3: PixelAspect = 4.0 / 3.0; break; + case VIDEO_FORMAT_221_1: // FF DVB cards only distinguish between 4:3 and 16:9 + case VIDEO_FORMAT_16_9: PixelAspect = 16.0 / 9.0; break; + } + PixelAspect /= double(Width) / Height; + return; + } + else + LOG_ERROR; + } + cDevice::GetOsdSize(Width, Height, PixelAspect); +} + +bool cDvbSdFfDevice::SetAudioBypass(bool On) +{ + if (setTransferModeForDolbyDigital != 1) + return false; + return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0; +} + +// ptAudio ptVideo ptPcr ptTeletext ptDolby ptOther +static dmx_pes_type_t PesTypes[] = { DMX_PES_AUDIO, DMX_PES_VIDEO, DMX_PES_PCR, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER }; + +bool cDvbSdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On) +{ + if (Handle->pid) { + dmx_pes_filter_params pesFilterParams; + memset(&pesFilterParams, 0, sizeof(pesFilterParams)); + if (On) { + if (Handle->handle < 0) { + Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true); + if (Handle->handle < 0) { + LOG_ERROR; + return false; + } + } + pesFilterParams.pid = Handle->pid; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = (Type <= ptTeletext && Handle->used <= 1) ? DMX_OUT_DECODER : DMX_OUT_TS_TAP; + pesFilterParams.pes_type= PesTypes[Type < ptOther ? Type : ptOther]; + pesFilterParams.flags = DMX_IMMEDIATE_START; + if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { + LOG_ERROR; + return false; + } + } + else if (!Handle->used) { + CHECK(ioctl(Handle->handle, DMX_STOP)); + if (Type <= ptTeletext) { + pesFilterParams.pid = 0x1FFF; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_DECODER; + pesFilterParams.pes_type= PesTypes[Type]; + pesFilterParams.flags = DMX_IMMEDIATE_START; + CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams)); + if (PesTypes[Type] == DMX_PES_VIDEO) // let's only do this once + SetPlayMode(pmNone); // necessary to switch a PID from DMX_PES_VIDEO/AUDIO to DMX_PES_OTHER + } + close(Handle->handle); + Handle->handle = -1; + } + } + return true; +} + +void cDvbSdFfDevice::TurnOffLiveMode(bool LiveView) +{ + if (LiveView) { + // Avoid noise while switching: + CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); + CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); + CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); + CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); + } + + // Turn off live PIDs: + + DetachAll(pidHandles[ptAudio].pid); + DetachAll(pidHandles[ptVideo].pid); + DetachAll(pidHandles[ptPcr].pid); + DetachAll(pidHandles[ptTeletext].pid); + DelPid(pidHandles[ptAudio].pid); + DelPid(pidHandles[ptVideo].pid); + DelPid(pidHandles[ptPcr].pid, ptPcr); + DelPid(pidHandles[ptTeletext].pid); + DelPid(pidHandles[ptDolby].pid); +} + +bool cDvbSdFfDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) +{ + int apid = Channel->Apid(0); + int vpid = Channel->Vpid(); + int dpid = Channel->Dpid(0); + + bool DoTune = !IsTunedToTransponder(Channel); + + bool pidHandlesVideo = pidHandles[ptVideo].pid == vpid; + bool pidHandlesAudio = pidHandles[ptAudio].pid == apid; + + bool TurnOffLivePIDs = DoTune + || !IsPrimaryDevice() + || LiveView // for a new live view the old PIDs need to be turned off + || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER + ; + + bool StartTransferMode = IsPrimaryDevice() && !DoTune + && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER + || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER + ); + if (CamSlot() && !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlot()->SlotNumber())) + StartTransferMode |= LiveView && IsPrimaryDevice() && Channel->Ca() >= CA_ENCRYPTED_MIN; + + bool TurnOnLivePIDs = !StartTransferMode && LiveView; + + // Turn off live PIDs if necessary: + + if (TurnOffLivePIDs) + TurnOffLiveMode(LiveView); + + // Set the tuner: + + if (!cDvbDevice::SetChannelDevice(Channel, LiveView)) + return false; + + // If this channel switch was requested by the EITScanner we don't wait for + // a lock and don't set any live PIDs (the EITScanner will wait for the lock + // by itself before setting any filters): + + if (EITScanner.UsesDevice(this)) //XXX + return true; + + // PID settings: + + if (TurnOnLivePIDs) { + SetAudioBypass(false); + if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo) && AddPid(apid, ptAudio))) { + esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1); + return false; + } + if (IsPrimaryDevice()) + AddPid(Channel->Tpid(), ptTeletext); + CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); // actually one would expect 'false' here, but according to Marco Schlüßler <marco@lordzodiac.de> this works + // to avoid missing audio after replaying a DVD; with 'false' there is an audio disturbance when switching + // between two channels on the same transponder on DVB-S + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); + } + else if (StartTransferMode) + cControl::Launch(new cTransferControl(this, Channel->GetChannelID(), vpid, Channel->Apids(), Channel->Dpids(), Channel->Spids())); + + return true; +} + +int cDvbSdFfDevice::GetAudioChannelDevice(void) +{ + audio_status_t as; + CHECK(ioctl(fd_audio, AUDIO_GET_STATUS, &as)); + return as.channel_select; +} + +void cDvbSdFfDevice::SetAudioChannelDevice(int AudioChannel) +{ + CHECK(ioctl(fd_audio, AUDIO_CHANNEL_SELECT, AudioChannel)); +} + +void cDvbSdFfDevice::SetVolumeDevice(int Volume) +{ + if (digitalAudio) + Volume = 0; + audio_mixer_t am; + // conversion for linear volume response: + am.volume_left = am.volume_right = 2 * Volume - Volume * Volume / 255; + CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am)); +} + +void cDvbSdFfDevice::SetDigitalAudioDevice(bool On) +{ + if (digitalAudio != On) { + if (digitalAudio) + cCondWait::SleepMs(1000); // Wait until any leftover digital data has been flushed + digitalAudio = On; + SetVolumeDevice(On || IsMute() ? 0 : CurrentVolume()); + } +} + +void cDvbSdFfDevice::SetAudioTrackDevice(eTrackType Type) +{ + const tTrackId *TrackId = GetTrack(Type); + if (TrackId && TrackId->id) { + SetAudioBypass(false); + if (IS_AUDIO_TRACK(Type) || (IS_DOLBY_TRACK(Type) && SetAudioBypass(true))) { + if (pidHandles[ptAudio].pid && pidHandles[ptAudio].pid != TrackId->id) { + DetachAll(pidHandles[ptAudio].pid); + if (CamSlot()) + CamSlot()->SetPid(pidHandles[ptAudio].pid, false); + pidHandles[ptAudio].pid = TrackId->id; + SetPid(&pidHandles[ptAudio], ptAudio, true); + if (CamSlot()) { + CamSlot()->SetPid(pidHandles[ptAudio].pid, true); + CamSlot()->StartDecrypting(); + } + } + } + else if (IS_DOLBY_TRACK(Type)) { + if (setTransferModeForDolbyDigital == 0) + return; + // Currently this works only in Transfer Mode + ForceTransferMode(); + } + } +} + +bool cDvbSdFfDevice::CanReplay(void) const +{ + return cDevice::CanReplay(); +} + +bool cDvbSdFfDevice::SetPlayMode(ePlayMode PlayMode) +{ + if (PlayMode != pmExtern_THIS_SHOULD_BE_AVOIDED && fd_video < 0 && fd_audio < 0) { + // reopen the devices + fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK); + fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK); + SetVideoFormat(Setup.VideoFormat); + } + + switch (PlayMode) { + case pmNone: + // special handling to return from PCM replay: + CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); + CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); + CHECK(ioctl(fd_video, VIDEO_PLAY)); + + CHECK(ioctl(fd_video, VIDEO_STOP, true)); + CHECK(ioctl(fd_audio, AUDIO_STOP, true)); + CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); + CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); + CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX)); + CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX)); + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); + CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); + break; + case pmAudioVideo: + case pmAudioOnlyBlack: + if (playMode == pmNone) + TurnOffLiveMode(true); + CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); + CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, PlayMode == pmAudioVideo)); + CHECK(ioctl(fd_audio, AUDIO_PLAY)); + CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); + CHECK(ioctl(fd_video, VIDEO_PLAY)); + break; + case pmAudioOnly: + CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); + CHECK(ioctl(fd_audio, AUDIO_STOP, true)); + CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); + CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); + CHECK(ioctl(fd_audio, AUDIO_PLAY)); + CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); + break; + case pmVideoOnly: + CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); + CHECK(ioctl(fd_video, VIDEO_STOP, true)); + CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX)); + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); + CHECK(ioctl(fd_audio, AUDIO_PLAY)); + CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); + CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); + CHECK(ioctl(fd_video, VIDEO_PLAY)); + break; + case pmExtern_THIS_SHOULD_BE_AVOIDED: + close(fd_video); + close(fd_audio); + fd_video = fd_audio = -1; + break; + default: esyslog("ERROR: unknown playmode %d", PlayMode); + } + playMode = PlayMode; + return true; +} + +int64_t cDvbSdFfDevice::GetSTC(void) +{ + if (fd_stc >= 0) { + struct dmx_stc stc; + stc.num = 0; + if (ioctl(fd_stc, DMX_GET_STC, &stc) == -1) { + esyslog("ERROR: stc %d: %m", CardIndex() + 1); + return -1; + } + return stc.stc / stc.base; + } + return -1; +} + +void cDvbSdFfDevice::TrickSpeed(int Speed) +{ + if (fd_video >= 0) + CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed)); +} + +void cDvbSdFfDevice::Clear(void) +{ + if (fd_video >= 0) + CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); + if (fd_audio >= 0) + CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); + cDevice::Clear(); +} + +void cDvbSdFfDevice::Play(void) +{ + if (playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) { + if (fd_audio >= 0) + CHECK(ioctl(fd_audio, AUDIO_CONTINUE)); + } + else { + if (fd_audio >= 0) { + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); + CHECK(ioctl(fd_audio, AUDIO_CONTINUE)); + } + if (fd_video >= 0) + CHECK(ioctl(fd_video, VIDEO_CONTINUE)); + } + cDevice::Play(); +} + +void cDvbSdFfDevice::Freeze(void) +{ + if (playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) { + if (fd_audio >= 0) + CHECK(ioctl(fd_audio, AUDIO_PAUSE)); + } + else { + if (fd_audio >= 0) { + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); + CHECK(ioctl(fd_audio, AUDIO_PAUSE)); + } + if (fd_video >= 0) + CHECK(ioctl(fd_video, VIDEO_FREEZE)); + } + cDevice::Freeze(); +} + +void cDvbSdFfDevice::Mute(void) +{ + if (fd_audio >= 0) { + CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); + CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); + } + cDevice::Mute(); +} + +void cDvbSdFfDevice::StillPicture(const uchar *Data, int Length) +{ + if (!Data || Length < TS_SIZE) + return; + if (Data[0] == 0x47) { + // TS data + cDevice::StillPicture(Data, Length); + } + else if (Data[0] == 0x00 && Data[1] == 0x00 && Data[2] == 0x01 && (Data[3] & 0xF0) == 0xE0) { + // PES data + char *buf = MALLOC(char, Length); + if (!buf) + return; + int i = 0; + int blen = 0; + while (i < Length - 6) { + if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) { + int len = Data[i + 4] * 256 + Data[i + 5]; + if ((Data[i + 3] & 0xF0) == 0xE0) { // video packet + // skip PES header + int offs = i + 6; + // skip header extension + if ((Data[i + 6] & 0xC0) == 0x80) { + // MPEG-2 PES header + if (Data[i + 8] >= Length) + break; + offs += 3; + offs += Data[i + 8]; + len -= 3; + len -= Data[i + 8]; + if (len < 0 || offs + len > Length) + break; + } + else { + // MPEG-1 PES header + while (offs < Length && len > 0 && Data[offs] == 0xFF) { + offs++; + len--; + } + if (offs <= Length - 2 && len >= 2 && (Data[offs] & 0xC0) == 0x40) { + offs += 2; + len -= 2; + } + if (offs <= Length - 5 && len >= 5 && (Data[offs] & 0xF0) == 0x20) { + offs += 5; + len -= 5; + } + else if (offs <= Length - 10 && len >= 10 && (Data[offs] & 0xF0) == 0x30) { + offs += 10; + len -= 10; + } + else if (offs < Length && len > 0) { + offs++; + len--; + } + } + if (blen + len > Length) // invalid PES length field + break; + memcpy(&buf[blen], &Data[offs], len); + i = offs + len; + blen += len; + } + else if (Data[i + 3] >= 0xBD && Data[i + 3] <= 0xDF) // other PES packets + i += len + 6; + else + i++; + } + else + i++; + } + video_still_picture sp = { buf, blen }; + CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp)); + free(buf); + } + else { + // non-PES data + video_still_picture sp = { (char *)Data, Length }; + CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp)); + } +} + +bool cDvbSdFfDevice::Poll(cPoller &Poller, int TimeoutMs) +{ + Poller.Add((playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) ? fd_audio : fd_video, true); + return Poller.Poll(TimeoutMs); +} + +bool cDvbSdFfDevice::Flush(int TimeoutMs) +{ + //TODO actually this function should wait until all buffered data has been processed by the card, but how? + return true; +} + +int cDvbSdFfDevice::PlayVideo(const uchar *Data, int Length) +{ + return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); +} + +int cDvbSdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id) +{ + return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); +} + +int cDvbSdFfDevice::PlayTsVideo(const uchar *Data, int Length) +{ + return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); +} + +int cDvbSdFfDevice::PlayTsAudio(const uchar *Data, int Length) +{ + return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); +} + +// --- cDvbSdFfDeviceProbe --------------------------------------------------- + +bool cDvbSdFfDeviceProbe::Probe(int Adapter, int Frontend) +{ + static uint32_t SubsystemIds[] = { + 0x110A0000, // Fujitsu Siemens DVB-C + 0x13C20000, // Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C + 0x13C20001, // Technotrend/Hauppauge WinTV DVB-T rev1.X + 0x13C20002, // Technotrend/Hauppauge WinTV DVB-C rev2.X + 0x13C20003, // Technotrend/Hauppauge WinTV Nexus-S rev2.X + 0x13C20004, // Galaxis DVB-S rev1.3 + 0x13C20006, // Fujitsu Siemens DVB-S rev1.6 + 0x13C20008, // Technotrend/Hauppauge DVB-T + 0x13C2000A, // Technotrend/Hauppauge WinTV Nexus-CA rev1.X + 0x13C2000E, // Technotrend/Hauppauge WinTV Nexus-S rev2.3 + 0x13C21002, // Technotrend/Hauppauge WinTV DVB-S rev1.3 SE + 0x00000000 + }; + cString FileName; + cReadLine ReadLine; + FILE *f = NULL; + uint32_t SubsystemId = 0; + FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_vendor", Adapter, Frontend); + if ((f = fopen(FileName, "r")) != NULL) { + if (char *s = ReadLine.Read(f)) + SubsystemId = strtoul(s, NULL, 0) << 16; + fclose(f); + } + FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_device", Adapter, Frontend); + if ((f = fopen(FileName, "r")) != NULL) { + if (char *s = ReadLine.Read(f)) + SubsystemId |= strtoul(s, NULL, 0); + fclose(f); + } + for (uint32_t *sid = SubsystemIds; *sid; sid++) { + if (*sid == SubsystemId) { + dsyslog("creating cDvbSdFfDevice"); + new cDvbSdFfDevice(Adapter, Frontend); + return true; + } + } + return false; +} diff --git a/PLUGINS/src/dvbsddevice/dvbsdffdevice.h b/PLUGINS/src/dvbsddevice/dvbsdffdevice.h new file mode 100644 index 0000000..b382bf6 --- /dev/null +++ b/PLUGINS/src/dvbsddevice/dvbsdffdevice.h @@ -0,0 +1,107 @@ +/* + * dvbsdffdevice.h: The DVB SD Full Featured device interface + * + * See the README file for copyright information and how to reach the author. + * + * $Id: dvbsdffdevice.h 2.11 2010/01/04 11:01:14 kls Exp $ + */ + +#ifndef __DVBSDFFDEVICE_H +#define __DVBSDFFDEVICE_H + +#include "vdr/dvbdevice.h" +#include "vdr/dvbspu.h" + +/// The cDvbSdFfDevice implements a DVB device which can be accessed through the Linux DVB driver API. + +class cDvbSdFfDevice : public cDvbDevice { +private: + int fd_osd, fd_audio, fd_video, fd_stc; +protected: + virtual void MakePrimaryDevice(bool On); +public: + cDvbSdFfDevice(int Adapter, int Frontend); + virtual ~cDvbSdFfDevice(); + virtual bool HasDecoder(void) const; + +// SPU facilities + +private: + cDvbSpuDecoder *spuDecoder; +public: + virtual cSpuDecoder *GetSpuDecoder(void); + +// Channel facilities + +private: + void TurnOffLiveMode(bool LiveView); +protected: + virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); + +// PID handle facilities + +private: + bool SetAudioBypass(bool On); +protected: + virtual bool SetPid(cPidHandle *Handle, int Type, bool On); + +// Image Grab facilities + +private: + static int devVideoOffset; + int devVideoIndex; +public: + virtual uchar *GrabImage(int &Size, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1); + +// Video format facilities + +public: + virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat); + virtual void SetVideoFormat(bool VideoFormat16_9); + virtual eVideoSystem GetVideoSystem(void); + virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect); + virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect); + +// Track facilities + +protected: + virtual void SetAudioTrackDevice(eTrackType Type); + +// Audio facilities + +private: + bool digitalAudio; +protected: + virtual int GetAudioChannelDevice(void); + virtual void SetAudioChannelDevice(int AudioChannel); + virtual void SetVolumeDevice(int Volume); + virtual void SetDigitalAudioDevice(bool On); + +// Player facilities + +protected: + ePlayMode playMode; + virtual bool CanReplay(void) const; + virtual bool SetPlayMode(ePlayMode PlayMode); + virtual int PlayVideo(const uchar *Data, int Length); + virtual int PlayAudio(const uchar *Data, int Length, uchar Id); + virtual int PlayTsVideo(const uchar *Data, int Length); + virtual int PlayTsAudio(const uchar *Data, int Length); +public: + virtual int64_t GetSTC(void); + virtual void TrickSpeed(int Speed); + virtual void Clear(void); + virtual void Play(void); + virtual void Freeze(void); + virtual void Mute(void); + virtual void StillPicture(const uchar *Data, int Length); + virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); + virtual bool Flush(int TimeoutMs = 0); + }; + +class cDvbSdFfDeviceProbe : public cDvbDeviceProbe { +public: + virtual bool Probe(int Adapter, int Frontend); + }; + +#endif //__DVBSDFFDEVICE_H diff --git a/PLUGINS/src/dvbsddevice/dvbsdffosd.c b/PLUGINS/src/dvbsddevice/dvbsdffosd.c new file mode 100644 index 0000000..4ff8db9 --- /dev/null +++ b/PLUGINS/src/dvbsddevice/dvbsdffosd.c @@ -0,0 +1,213 @@ +/* + * dvbsdffosd.c: Implementation of the DVB SD Full Featured On Screen Display + * + * See the README file for copyright information and how to reach the author. + * + * $Id: dvbsdffosd.c 2.1 2009/12/29 11:52:48 kls Exp $ + */ + +#include "dvbsdffosd.h" +#include <linux/dvb/osd.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/unistd.h> +#include "vdr/tools.h" + +// --- cDvbSdFfOsd ----------------------------------------------------------- + +#define MAXNUMWINDOWS 7 // OSD windows are counted 1...7 +#define MAXOSDMEMORY 92000 // number of bytes available to the OSD (for unmodified DVB cards) + +class cDvbSdFfOsd : public cOsd { +private: + int osdDev; + int osdMem; + bool shown; + void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL); +protected: + virtual void SetActive(bool On); +public: + cDvbSdFfOsd(int Left, int Top, int OsdDev, uint Level); + virtual ~cDvbSdFfOsd(); + virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas); + virtual eOsdError SetAreas(const tArea *Areas, int NumAreas); + virtual void Flush(void); + }; + +cDvbSdFfOsd::cDvbSdFfOsd(int Left, int Top, int OsdDev, uint Level) +:cOsd(Left, Top, Level) +{ + osdDev = OsdDev; + shown = false; + if (osdDev < 0) + esyslog("ERROR: invalid OSD device handle (%d)!", osdDev); + else { + osdMem = MAXOSDMEMORY; +#ifdef OSD_CAP_MEMSIZE + // modified DVB cards may have more OSD memory: + osd_cap_t cap; + cap.cmd = OSD_CAP_MEMSIZE; + if (ioctl(osdDev, OSD_GET_CAPABILITY, &cap) == 0) + osdMem = cap.val; +#endif + } +} + +cDvbSdFfOsd::~cDvbSdFfOsd() +{ + SetActive(false); +} + +void cDvbSdFfOsd::SetActive(bool On) +{ + if (On != Active()) { + cOsd::SetActive(On); + if (On) { + // must clear all windows here to avoid flashing effects - doesn't work if done + // in Flush() only for the windows that are actually used... + for (int i = 0; i < MAXNUMWINDOWS; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_Clear); + } + if (GetBitmap(0)) // only flush here if there are already bitmaps + Flush(); + } + else if (shown) { + cBitmap *Bitmap; + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_Close); + } + shown = false; + } + } +} + +eOsdError cDvbSdFfOsd::CanHandleAreas(const tArea *Areas, int NumAreas) +{ + eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas); + if (Result == oeOk) { + if (NumAreas > MAXNUMWINDOWS) + return oeTooManyAreas; + int TotalMemory = 0; + for (int i = 0; i < NumAreas; i++) { + if (Areas[i].bpp != 1 && Areas[i].bpp != 2 && Areas[i].bpp != 4 && Areas[i].bpp != 8) + return oeBppNotSupported; + if ((Areas[i].Width() & (8 / Areas[i].bpp - 1)) != 0) + return oeWrongAlignment; + if (Areas[i].Width() < 1 || Areas[i].Height() < 1 || Areas[i].Width() > 720 || Areas[i].Height() > 576) + return oeWrongAreaSize; + TotalMemory += Areas[i].Width() * Areas[i].Height() / (8 / Areas[i].bpp); + } + if (TotalMemory > osdMem) + return oeOutOfMemory; + } + return Result; +} + +eOsdError cDvbSdFfOsd::SetAreas(const tArea *Areas, int NumAreas) +{ + if (shown) { + cBitmap *Bitmap; + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_Close); + } + shown = false; + } + return cOsd::SetAreas(Areas, NumAreas); +} + +void cDvbSdFfOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) +{ + if (osdDev >= 0) { + osd_cmd_t dc; + dc.cmd = cmd; + dc.color = color; + dc.x0 = x0; + dc.y0 = y0; + dc.x1 = x1; + dc.y1 = y1; + dc.data = (void *)data; + ioctl(osdDev, OSD_SEND_CMD, &dc); + } +} + +void cDvbSdFfOsd::Flush(void) +{ + if (!Active()) + return; + cBitmap *Bitmap; + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + if (!shown) + Cmd(OSD_Open, Bitmap->Bpp(), Left() + Bitmap->X0(), Top() + Bitmap->Y0(), Left() + Bitmap->X0() + Bitmap->Width() - 1, Top() + Bitmap->Y0() + Bitmap->Height() - 1, (void *)1); // initially hidden! + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; + if (!shown || Bitmap->Dirty(x1, y1, x2, y2)) { + if (!shown) { + x1 = y1 = 0; + x2 = Bitmap->Width() - 1; + y2 = Bitmap->Height() - 1; + } + //TODO Workaround: apparently the bitmap sent to the driver always has to be a multiple + //TODO of 8 bits wide, and (dx * dy) also has to be a multiple of 8. + //TODO Fix driver (should be able to handle any size bitmaps!) + while ((x1 > 0 || x2 < Bitmap->Width() - 1) && ((x2 - x1) & 7) != 7) { + if (x2 < Bitmap->Width() - 1) + x2++; + else if (x1 > 0) + x1--; + } + //TODO "... / 2" <==> Bpp??? + while ((y1 > 0 || y2 < Bitmap->Height() - 1) && (((x2 - x1 + 1) * (y2 - y1 + 1) / 2) & 7) != 0) { + if (y2 < Bitmap->Height() - 1) + y2++; + else if (y1 > 0) + y1--; + } + while ((x1 > 0 || x2 < Bitmap->Width() - 1) && (((x2 - x1 + 1) * (y2 - y1 + 1) / 2) & 7) != 0) { + if (x2 < Bitmap->Width() - 1) + x2++; + else if (x1 > 0) + x1--; + } + // commit colors: + int NumColors; + const tColor *Colors = Bitmap->Colors(NumColors); + if (Colors) { + //TODO this should be fixed in the driver! + tColor colors[NumColors]; + for (int i = 0; i < NumColors; i++) { + // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): + colors[i] = (Colors[i] & 0xFF000000) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); + } + Colors = colors; + //TODO end of stuff that should be fixed in the driver + Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); + } + // commit modified data: + Cmd(OSD_SetBlock, Bitmap->Width(), x1, y1, x2, y2, Bitmap->Data(x1, y1)); + } + Bitmap->Clean(); + } + if (!shown) { + // Showing the windows in a separate loop to avoid seeing them come up one after another + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + Cmd(OSD_MoveWindow, 0, Left() + Bitmap->X0(), Top() + Bitmap->Y0()); + } + shown = true; + } +} + +// --- cDvbOsdProvider ------------------------------------------------------- + +cDvbOsdProvider::cDvbOsdProvider(int OsdDev) +{ + osdDev = OsdDev; +} + +cOsd *cDvbOsdProvider::CreateOsd(int Left, int Top, uint Level) +{ + return new cDvbSdFfOsd(Left, Top, osdDev, Level); +} diff --git a/PLUGINS/src/dvbsddevice/dvbsdffosd.h b/PLUGINS/src/dvbsddevice/dvbsdffosd.h new file mode 100644 index 0000000..8a1bc62 --- /dev/null +++ b/PLUGINS/src/dvbsddevice/dvbsdffosd.h @@ -0,0 +1,22 @@ +/* + * dvbsdffosd.h: Implementation of the DVB SD Full Featured On Screen Display + * + * See the README file for copyright information and how to reach the author. + * + * $Id: dvbsdffosd.h 2.1 2009/12/29 11:52:05 kls Exp $ + */ + +#ifndef __DVBSDFFODF_H +#define __DVBSDFFODF_H + +#include "vdr/osd.h" + +class cDvbOsdProvider : public cOsdProvider { +private: + int osdDev; +public: + cDvbOsdProvider(int OsdDev); + virtual cOsd *CreateOsd(int Left, int Top, uint Level); + }; + +#endif //__DVBSDFFODF_H diff --git a/PLUGINS/src/hello/HISTORY b/PLUGINS/src/hello/HISTORY index 14e78f6..9adeab9 100644 --- a/PLUGINS/src/hello/HISTORY +++ b/PLUGINS/src/hello/HISTORY @@ -63,6 +63,10 @@ VDR Plugin 'hello' Revision History - Updated the Croatian language texts (thanks to Adrian Caval). -2008-009-06 Version 0.2.3 +2008-09-06: Version 0.2.3 - Updated the Turkish language texts (thanks to Oktay Yolgeçen). + +2009-12-06: Version 0.2.4 + +- Several code modifications to avoid compiler warnings (thanks to Winfried Köhler). diff --git a/PLUGINS/src/hello/hello.c b/PLUGINS/src/hello/hello.c index 86adee6..32a74e3 100644 --- a/PLUGINS/src/hello/hello.c +++ b/PLUGINS/src/hello/hello.c @@ -3,7 +3,7 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: hello.c 2.1 2008/09/06 15:07:12 kls Exp $ + * $Id: hello.c 2.2 2009/12/06 12:30:15 kls Exp $ */ #include <getopt.h> @@ -12,7 +12,7 @@ #include <vdr/interface.h> #include <vdr/plugin.h> -static const char *VERSION = "0.2.3"; +static const char *VERSION = "0.2.4"; static const char *DESCRIPTION = trNOOP("A friendly greeting"); static const char *MAINMENUENTRY = trNOOP("Hello"); @@ -96,7 +96,7 @@ bool cPluginHello::ProcessArgs(int argc, char *argv[]) static struct option long_options[] = { { "aaa", required_argument, NULL, 'a' }, { "bbb", no_argument, NULL, 'b' }, - { NULL } + { NULL, no_argument, NULL, 0 } }; int c; diff --git a/PLUGINS/src/pictures/HISTORY b/PLUGINS/src/pictures/HISTORY index 5f24a74..34da938 100644 --- a/PLUGINS/src/pictures/HISTORY +++ b/PLUGINS/src/pictures/HISTORY @@ -33,3 +33,7 @@ VDR Plugin 'pictures' Revision History 2008-03-14: Version 0.0.7 - Added Russian translations (thanks to Alexander Gross). + +2009-12-06: Version 0.0.8 + +- Several code modifications to avoid compiler warnings (thanks to Winfried Köhler). diff --git a/PLUGINS/src/pictures/pictures.c b/PLUGINS/src/pictures/pictures.c index 9c4e515..9de6889 100644 --- a/PLUGINS/src/pictures/pictures.c +++ b/PLUGINS/src/pictures/pictures.c @@ -3,7 +3,7 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: pictures.c 2.0 2008/03/14 12:57:19 kls Exp $ + * $Id: pictures.c 2.1 2009/12/06 12:30:21 kls Exp $ */ #include <getopt.h> @@ -11,7 +11,7 @@ #include "menu.h" #include "player.h" -static const char *VERSION = "0.0.7"; +static const char *VERSION = "0.0.8"; static const char *DESCRIPTION = trNOOP("A simple picture viewer"); static const char *MAINMENUENTRY = trNOOP("Pictures"); @@ -82,7 +82,7 @@ bool cPluginPictures::ProcessArgs(int argc, char *argv[]) // Implement command line argument processing here if applicable. static struct option long_options[] = { { "dir", required_argument, NULL, 'd' }, - { NULL } + { NULL, no_argument, NULL, 0 } }; int c; diff --git a/PLUGINS/src/skincurses/HISTORY b/PLUGINS/src/skincurses/HISTORY index cf793cd..ca820f9 100644 --- a/PLUGINS/src/skincurses/HISTORY +++ b/PLUGINS/src/skincurses/HISTORY @@ -79,3 +79,8 @@ VDR Plugin 'skincurses' Revision History 2008-03-14: Version 0.1.7 - Added Russian translations (thanks to Alexander Gross). + +2010-01-03: Version 0.1.8 + +- Displaying "genre" in event descriptions. +- Displaying "parental rating" in event descriptions. diff --git a/PLUGINS/src/skincurses/skincurses.c b/PLUGINS/src/skincurses/skincurses.c index 8a7a846..d8134f6 100644 --- a/PLUGINS/src/skincurses/skincurses.c +++ b/PLUGINS/src/skincurses/skincurses.c @@ -3,7 +3,7 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: skincurses.c 2.0 2008/03/14 12:57:14 kls Exp $ + * $Id: skincurses.c 2.3 2010/01/03 14:59:16 kls Exp $ */ #include <ncurses.h> @@ -11,7 +11,7 @@ #include <vdr/plugin.h> #include <vdr/skins.h> -static const char *VERSION = "0.1.7"; +static const char *VERSION = "0.1.8"; static const char *DESCRIPTION = trNOOP("A text only skin"); static const char *MAINMENUENTRY = NULL; @@ -402,6 +402,10 @@ void cSkinCursesDisplayMenu::SetEvent(const cEvent *Event) osd->DrawText(ScOsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font); } y += ts.Height(); + if (Event->ParentalRating()) { + cString buffer = cString::sprintf(" %s ", *Event->GetParentalRatingString()); + osd->DrawText(ScOsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font); + } y += 1; ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Event->Title(), &Font, clrCyan, clrBackground); y += ts.Height(); @@ -409,6 +413,13 @@ void cSkinCursesDisplayMenu::SetEvent(const cEvent *Event) ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Event->ShortText(), &Font, clrYellow, clrBackground); y += ts.Height(); } + for (int i = 0; Event->Contents(i); i++) { + const char *s = Event->ContentToString(Event->Contents(i)); + if (!isempty(s)) { + ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, s, &Font, clrYellow, clrBackground); + y += 1; + } + } y += 1; if (!isempty(Event->Description())) { textScroller.Set(osd, 0, y, ScOsdWidth - 2, ScOsdHeight - y - 2, Event->Description(), &Font, clrCyan, clrBackground); @@ -427,6 +438,10 @@ void cSkinCursesDisplayMenu::SetRecording(const cRecording *Recording) snprintf(t, sizeof(t), "%s %s", *DateString(Recording->start), *TimeString(Recording->start)); ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, t, &Font, clrYellow, clrBackground); y += ts.Height(); + if (Info->GetEvent()->ParentalRating()) { + cString buffer = cString::sprintf(" %s ", *Info->GetEvent()->GetParentalRatingString()); + osd->DrawText(ScOsdWidth - Utf8StrLen(buffer), y, buffer, clrBlack, clrYellow, &Font); + } y += 1; const char *Title = Info->Title(); if (isempty(Title)) @@ -437,6 +452,13 @@ void cSkinCursesDisplayMenu::SetRecording(const cRecording *Recording) ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, Info->ShortText(), &Font, clrYellow, clrBackground); y += ts.Height(); } + for (int i = 0; Info->GetEvent()->Contents(i); i++) { + const char *s = Info->GetEvent()->ContentToString(Info->GetEvent()->Contents(i)); + if (!isempty(s)) { + ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, s, &Font, clrYellow, clrBackground); + y += 1; + } + } y += 1; if (!isempty(Info->Description())) { textScroller.Set(osd, 0, y, ScOsdWidth - 2, ScOsdHeight - y - 2, Info->Description(), &Font, clrCyan, clrBackground); diff --git a/PLUGINS/src/sky/HISTORY b/PLUGINS/src/sky/HISTORY deleted file mode 100644 index 25b8fc8..0000000 --- a/PLUGINS/src/sky/HISTORY +++ /dev/null @@ -1,70 +0,0 @@ -VDR Plugin 'sky' Revision History ---------------------------------- - -2002-12-01: Version 0.0.1 - -- Initial revision. - -2002-12-13: Version 0.1.0 - -- Changed setting of CXX and CXXFLAGS variables in Makefile. - -2003-05-09: Version 0.1.1 - -- Changed Start() to Initialize(). - -2004-01-04: Version 0.2.0 - -- Implemented automatic PID switching and channel detection - -2004-02-15: Version 0.3.0 - -- Now using the actual channel IDs a derived from the data stream. -- Switched EPG data retrieval to http://www.bleb.org. -- Added automatic DST detection to getskyepg.pl. -- Fixed handling receivers, so that a recording on the same channel - won't interrupt an ongoing Transfer mode. - -2004-10-16: Version 0.3.1 - -- Improved buffer handling. - -2004-12-12: Version 0.3.2 - -- Changed Apid access in cChannel. - -2004-12-19: Version 0.3.3 - -- Made several functions threadsafe. -- Removed delay_ms(), using cCondWait::SleepMs() instead. - -2005-09-17: Version 0.3.4 - -- Added a missing include statement. - -2006-03-26: Version 0.3.5 - -- Fixed format string handling. - -2006-12-02: Version 0.3.5 (version number not increased) - -- Made the getskyepg.pl script send a user agent message to - the server, according to the rules at http://bleb.org/tv/data/listings. - If your version of 'wget' doesn't support the -U option to set the user agent, - use the new option -U of getskyepg.pl to have the information added to the URL - as a query string. -- The getskyepg.pl script now replaces "&" with "&". - -2007-08-15: Version 0.3.6 - -- Moved the "all" target in the Makefile before the "Implicit rules", - so that a plain "make" will compile everything. - -2008-03-22: Version 0.3.7 - -- Removed the full path from the 'logger' call in the getskyepg.pl script (this - program is apparently "on the move" through the file system...). - -2008-09-07: Version 0.3.8 - -- Fixed renamed constants (thanks to Udo Richter). diff --git a/PLUGINS/src/sky/README b/PLUGINS/src/sky/README deleted file mode 100644 index 19d5d98..0000000 --- a/PLUGINS/src/sky/README +++ /dev/null @@ -1,49 +0,0 @@ -This is a "plugin" for the Video Disk Recorder (VDR). - -Written by: Klaus Schmidinger <kls@tvdr.de> - -Project's homepage: http://www.tvdr.de - -Latest version available at: http://www.tvdr.de - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. -See the file COPYING for more information. - -Description: - -The 'sky' plugin implements a new device for VDR, which is based on the -MPEG2 encoder card described at linuxtv.org/mpeg2/kfir.xml. It -allows you to connect the analog a/v output of your Sky Digibox to VDR, -so that you can enjoy the full recording flexibility of VDR with your -Sky subscription. Note that this is NOT something that does anything -illegal, like decrypting the Sky programme without a subscription. You -will need a Sky Digibox and a valid subscription in order to use this -plugin. - -The 'kfir' module must be loaded with the option 'streamtype=4' to make it -produce a Transport Stream. - -The Digibox is remotely controlled through VDR via LIRC (see lirc.org). -The file lircd.conf.sky contains the remote control codes necessary to -control the Digibox. - -In order to access the Sky channels VDR needs to know the channel number -under which each channel is stored in the Sky Digibox. These numbers are -stored in the file 'channels.conf.sky', together with the channel IDs as -derived from the actual channel data and the names under which the EPG -data for each channel can be found (see below). Copy this file to your -plugins config directory, in a subdirectory named 'sky', as in - -/video/plugins/sky/channels.conf.sky - -The Sky EPG is available on the Internet at http://www.bleb.org. -The Perl script getskyepg.pl extracts the EPG data from these pages -and sends it to VDR via an SVDRP connection. The channel names as -used on the bleb.org pages are defined in the channels.conf.sky file. -You can keep your EPG data up-to-date by entering a call to getskyepg.pl -into your /etc/crontab. Call 'getskyepg.pl -h' for a list of options. -The getskyepg.pl script requires the programs /usr/bin/wget and /usr/bin/logger -to be installed on your system. diff --git a/PLUGINS/src/sky/channels.conf.sky b/PLUGINS/src/sky/channels.conf.sky deleted file mode 100644 index 5f0b773..0000000 --- a/PLUGINS/src/sky/channels.conf.sky +++ /dev/null @@ -1,34 +0,0 @@ -# Sky channel definitions -# -# Syntax: -# -# ChannelID:ChannelNumber:EPGname -# -# where -# -# ChannelID is the channel ID as derived from the actual channel -# data as broadcast in the data stream (see man vdr(5)). -# -# ChannelNumber is the number of this channel as you have to -# enter it on the DigiBox remote control. -# -# EPGname is the name of the page at www.bleb.org that has EPG -# data for this channel (without the '.xml'). If no such -# page exists, 'x' is entered. -# -S28.2E-2-2027-4705:106:sky_one -S28.2E-2-2027-5104:107:sky_two -S28.2E-2-2044-10070:118:itv2 -S28.2E-2-2023-4905:130:scifi -S28.2E-2-2025-5904:127:paramount -S28.2E-2-2009-6201:551:discovery -S28.2E-2-2030-4809:310:sky_cinema -S28.2E-2-2007-4303:301:sky_movies1 -S28.2E-2-2007-4302:302:sky_movies2 -S28.2E-2-2007-4403:303:sky_movies3 -S28.2E-2-2011-4402:304:sky_movies4 -S28.2E-2-2011-4503:305:sky_movies5 -S28.2E-2-2011-4502:306:sky_movies6 -S28.2E-2-2030-4603:307:sky_movies7 -S28.2E-2-2007-5502:308:sky_movies8 -S28.2E-2-2030-4602:309:sky_movies9 diff --git a/PLUGINS/src/sky/getskyepg.pl b/PLUGINS/src/sky/getskyepg.pl deleted file mode 100755 index dfca96a..0000000 --- a/PLUGINS/src/sky/getskyepg.pl +++ /dev/null @@ -1,260 +0,0 @@ -#!/usr/bin/perl - -# getskyepg.pl: Get EPG data for Sky channels from the Internet -# -# Connects to a running VDR instance via SVDRP, gets the channel data -# for the Sky channels and connects to Internet web pages to extract the -# EPG data for these channels. The result is sent to VDR via SVDRP. -# -# See the README file for copyright information and how to reach the author. -# -# $Id: getskyepg.pl 2.1 2009/10/18 14:05:47 kls Exp $ - -use Getopt::Std; -use Time::Local; - -$Usage = qq{ -Usage: $0 [options] - -Options: -c filename channel config file name (default: channels.conf.sky) - -d hostname destination hostname (default: localhost) - -p port SVDRP port number (default: 2001) - -S source channel source (default: S28.2E) - -D days days to get EPG for (1..7, default: 2) - -U use this if your version of 'wget' doesn't support -U -}; - -die $Usage if (!getopts("c:d:D:hp:S:U") || $opt_h); - -$Conf = $opt_c || "channels.conf.sky"; -$Dest = $opt_d || "localhost"; -$Port = $opt_p || 2001; -$Source = $opt_S || "S28.2E"; -$Days = $opt_D || 2; -$User = $opt_U; - -# See "Rules for using this data" on http://bleb.org/tv/data/listings. -# In case you modify this script in a way that changes its behavior -# towards the www.bleb.org website, please replace 'vdr-bugs@tvdr.de' -# with your own email address! That way Andrew Flegg <andrew@bleb.org>, -# who runs that web site, can contact you in case of problems. -$IDENT = "VDR::getskyepg.pl, http://www.tvdr.de - vdr-bugs\@tvdr.de"; -$GAP = 2; - -$SkyWebPage = "www.bleb.org/tv/data/listings"; -$WGET = "/usr/bin/wget -q -O-"; -$WGET .= " -U '$IDENT'" unless $User; -$LOGGER = "logger -t SKYEPG"; - -$DST = -3600; # Daylight Saving Time offset -$SecsInDay = 86400; - -@Channels = (); - -$idxSource = 0; -$idxNumber = 1; -$idxName = 2; - -Error("days out of range: $Days") unless (1 <= $Days && $Days <= 7); - -sub Log -{ - system("$LOGGER '@_'"); -} - -sub Error -{ - Log(@_); - die "$0: @_\n"; -} - -sub GetChannels -{ - open(CHANNELS, $Conf) || Error("$Conf: $!"); - while (<CHANNELS>) { - chomp; - next if (/^#/); - my @a = split(":"); - push(@Channels, [@a]) unless ($a[$idxName] eq "x"); - } - close(CHANNELS); -} - -GetChannels(); - -sub GetPage -{ - my $channel = shift; - my $day = shift; - $day--; - my $url = "http://$SkyWebPage/$day/$channel.xml"; - $url .= "?$IDENT" if $User; - Log("reading $url"); - my @page = split("\n", `$WGET '$url'`); - Log("received " . ($#page + 1) . " lines"); - return @page; -} - -sub ReplaceTags -{ - my $s = shift; - $s =~ s/&/&/g; - return $s; -} - -sub StripWhitespace -{ - my $s = shift; - $s =~ s/\s*(.*)\s*/$1/; - $s =~ s/\s+/ /g; - return $s; -} - -sub Extract -{ - my $s = shift; - my $t = shift; - $s =~ /<$t>([^<]*)<\/$t>/; - return ReplaceTags(StripWhitespace($1)); -} - -# In order to get the duration we need to buffer the last event: -$Id = ""; -$Time = 0; -$Title = ""; -$Subtitle = ""; -$Desc = ""; - -sub GetEpgData -{ - my ($channel, $channelID) = @_; - my $numEvents = 0; - SVDRPsend("C $channelID"); - $Time = 0; - for $day (1 .. $Days) { - my $dt = 0; - my @page = GetPage($channel, $day); - my $data = ""; - for $line (@page) { - chomp($line); - if ($line =~ /<programme>/) { - $data = ""; - } - elsif ($line =~ /<\/programme>/) { - my $title = Extract($data, "title"); - my $subtitle = Extract($data, "subtitle"); - my $desc = Extract($data, "desc"); - my $start = Extract($data, "start"); - # 'end' is useless, because it is sometimes missing :-( - # my $end = Extract($data, "end"); - if (!$subtitle) { - # They sometimes write all info into the description, as in - # Episode: some description. - # Why don't they just fill in the data correctly? - my ($s, $d) = ($desc =~ /([^:]*)[:](.*)/); - if ($s && $d) { - $subtitle = $s; - $desc = $d; - } - } - # 'start' and 'end' as time of day isn't of much use here, since - # the page for one day contains data that actually belongs to the - # next day (after midnight). Oh well, lets reconstruct the missing - # information: - $start = "0" . $start if (length($start) < 4); - my ($h, $m) = ($start =~ /(..)(..)/); - $dt = $SecsInDay if ($h > 12); - # convert to time_t: - my @gmt = gmtime; - $gmt[0] = 0; # seconds - $gmt[1] = $m; # minutes - $gmt[2] = $h; # hours - $time = timegm(@gmt) + ($day - 1) * $SecsInDay + ($h < 12 ? $dt : 0); - # compensate for DST: - $time += $DST if (localtime($time))[8]; - # create EPG data: - if ($Time) { - $duration = $time - $Time; - SVDRPsend("E $Id $Time $duration"); - SVDRPsend("T $Title"); - SVDRPsend("S $Subtitle"); - SVDRPsend("D $Desc"); - SVDRPsend("e"); - $numEvents++; - } - # buffer the last event: - $Id = $time / 60 % 0xFFFF; # this gives us unique ids for every minute of over 6 weeks - $Time = $time; - $Title = $title; - $Subtitle = $subtitle; - $Desc = $desc; - } - else { - $data .= $line; - } - } - sleep($GAP); - } - SVDRPsend("c"); - Log("generated $numEvents EPG events"); -} - -sub ProcessEpg -{ - for (@Channels) { - my $channel = @$_[$idxName]; - my $channelID = @$_[$idxSource]; - Log("processing channel $channel - $channelID"); - SVDRPsend("PUTE"); - SVDRPreceive(354); - GetEpgData($channel, $channelID); - SVDRPsend("."); - SVDRPreceive(250); - } - Log("done"); -} - -#--------------------------------------------------------------------------- -# TODO: make this a Perl module??? What about Error()??? - -use Socket; - -$Timeout = 300; # max. seconds to wait for response - -$SIG{ALRM} = sub { Error("timeout"); }; -alarm($Timeout); - -$iaddr = inet_aton($Dest) || Error("no host: $Dest"); -$paddr = sockaddr_in($Port, $iaddr); - -$proto = getprotobyname('tcp'); -socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!"); -connect(SOCK, $paddr) || Error("connect: $!"); -select(SOCK); $| = 1; -SVDRPreceive(220); -ProcessEpg(); -SVDRPsend("QUIT"); - -sub SVDRPsend -{ - my $s = shift; - print SOCK "$s\r\n"; -} - -sub SVDRPreceive -{ - my $expect = shift | 0; - my @a = (); - while (<SOCK>) { - s/\s*$//; # 'chomp' wouldn't work with "\r\n" - push(@a, $_); - if (substr($_, 3, 1) ne "-") { - my $code = substr($_, 0, 3); - Error("expected SVDRP code $expect, but received $code") if ($code != $expect); - last; - } - } - return @a; -} - -#--------------------------------------------------------------------------- diff --git a/PLUGINS/src/sky/lircd.conf.sky b/PLUGINS/src/sky/lircd.conf.sky deleted file mode 100644 index 191dcb5..0000000 --- a/PLUGINS/src/sky/lircd.conf.sky +++ /dev/null @@ -1,299 +0,0 @@ -# Copyright (C) 1999 Christoph Bartelmus -# -# You may only use this file if you make it available to others, -# i.e. if you send it to <lirc@bartelmus.de> -# -# this config file was automatically generated -# using lirc-0.6.4-CVS(serial) on Mon Jul 9 08:14:04 2001 -# -# contributed by Steve Davies <steve@daviesfam.org> -# -# brand: sky -# model no. of remote control: -# supported devices: 34000 20 -# -# - -begin remote - - name SKY - flags CONST_LENGTH|RAW_CODES - eps 30 - aeps 100 - ptrail 0 - repeat 0 0 - gap 149692 - frequency 36000 - duty_cycle 50 - - begin raw_codes - - name 0 - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 - - name 1 - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 888 - - name 2 - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 888 888 - 444 - - name 3 - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 888 444 - 444 - - name 4 - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 888 888 444 444 - 444 - - name 5 - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 888 888 888 - - name 6 - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 888 444 444 888 - 444 - - name 7 - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 888 444 444 444 - 444 - - name 8 - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 888 888 444 444 444 444 - 444 - - name 9 - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 888 888 444 444 888 - - name RED - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 888 444 444 888 888 444 444 888 888 - - name GREEN - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 888 444 444 888 888 444 444 444 444 888 444 - - name YELLOW - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 888 444 444 888 888 444 444 444 444 444 444 - - name BLUE - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 888 444 444 444 444 888 444 444 444 444 444 444 - 444 - - name TEXT - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 888 444 444 444 444 444 444 888 444 444 - 444 - - name BACKUP - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 888 888 444 444 444 444 444 444 444 444 888 444 444 - - name HELP - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 888 888 444 444 444 444 444 444 444 444 444 444 888 - - name CURSOR-LEFT - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 888 888 888 444 444 888 888 888 444 - - name CURSOR-DOWN - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 888 888 888 444 444 888 444 444 888 - - name CURSOR-RIGHT - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 888 888 888 444 444 888 888 444 444 - - name CURSOR-UP - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 888 888 888 444 444 888 444 444 444 444 444 - - name SELECT - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 888 888 888 444 444 444 444 888 444 444 444 - - name CHANNEL-DOWN - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 888 888 444 444 444 444 444 444 888 - - name CHANNEL-UP - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 888 888 444 444 444 444 444 444 444 444 - 444 - - name I - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 888 444 444 888 444 444 888 888 888 444 444 - - name ONOFF - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 888 444 444 888 444 444 - 444 - - name SKY - 2664 888 444 444 444 444 444 888 444 888 888 444 444 444 444 444 - 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 444 - 444 444 888 888 444 444 444 444 444 444 444 444 444 444 444 444 - 444 - - name TV - 2830 724 583 333 553 339 - 548 791 543 795 977 357 - 527 364 524 367 524 368 - 522 369 521 370 520 371 - 519 372 519 372 519 372 - 518 372 518 374 963 818 - 516 376 510 381 509 382 - 954 828 508 407 481 - - name SKY - 2829 726 580 336 551 340 - 547 791 540 798 977 366 - 519 364 523 367 521 370 - 521 370 520 371 520 371 - 520 371 519 372 518 373 - 517 374 517 374 957 825 - 512 379 512 380 513 377 - 511 381 506 410 477 413 - 483 - - name MUTE - 2567 429 751 447 743 456 - 1335 464 734 466 1325 496 - 697 504 693 506 1284 513 - 681 518 681 517 679 520 - 678 26288 2533 462 734 489 - 705 470 1323 501 695 503 - 1287 511 683 516 683 518 - 1277 522 676 521 678 521 - 675 523 675 26286 2533 465 - 731 491 702 499 1293 504 - 692 507 1280 518 683 516 - 679 524 1272 522 675 529 - 670 523 682 517 675 26286 - 2532 465 729 493 702 473 - 1318 506 688 509 1282 517 - 680 519 677 524 1274 523 - 676 - - name VOLUME-UP - 2568 430 766 433 1342 456 - 734 489 708 466 1326 497 - 699 505 686 508 1286 512 - 688 510 683 516 682 516 - 681 26284 2540 481 711 488 - 1301 498 703 495 695 504 - 1284 516 682 516 684 515 - 1276 522 675 523 675 524 - 674 524 675 26286 2532 490 - 709 489 1300 500 689 509 - 695 517 1270 516 683 520 - 675 519 1274 529 668 525 - 675 524 673 526 672 26288 - 2532 466 731 491 1300 499 - 695 503 692 509 1277 520 - 681 518 679 519 1278 520 - 675 - - name VOLUME-DOWN - 2562 434 1348 451 1332 465 - 733 489 704 496 1296 504 - 690 507 694 511 1281 511 - 683 523 677 515 679 520 - 680 25687 2533 464 1330 491 - 1295 505 693 506 689 510 - 1293 505 684 516 678 520 - 1276 523 677 520 675 524 - 673 526 674 25686 2531 467 - 1324 498 1292 506 691 509 - 683 515 1280 518 678 521 - 675 523 1273 525 674 527 - 672 525 673 527 671 25685 - 2531 467 1320 501 1288 511 - 687 511 688 512 1282 516 - 678 521 675 524 1273 - - name TVGUIDE - 2834 720 586 330 554 338 - 548 794 539 796 975 360 - 528 363 521 371 519 371 - 520 371 519 375 514 374 - 517 374 516 375 513 379 - 511 380 510 381 949 387 - 500 836 505 387 945 391 - 493 868 469 422 468 - - name BOXOFFICE - 2833 745 564 329 555 338 - 548 790 545 793 982 352 - 529 362 526 365 522 370 - 519 371 519 372 519 372 - 518 373 517 374 513 378 - 515 376 507 384 506 385 - 945 390 496 396 498 392 - 496 419 468 847 936 - - name SERVICES - 2829 725 585 330 555 338 - 548 798 537 794 979 356 - 528 368 522 363 523 369 - 521 370 521 370 520 370 - 520 371 520 371 520 371 - 519 372 519 372 518 373 - 964 371 517 375 513 377 - 511 404 489 402 485 828 - 514 - - name INTERACTIVE - 2829 726 591 324 553 340 - 550 788 542 796 981 354 - 532 359 522 369 522 369 - 520 372 518 373 518 373 - 516 375 515 375 513 379 - 515 375 510 381 948 389 - 498 392 504 412 470 867 - 916 866 913 - - end raw_codes - -end remote diff --git a/PLUGINS/src/sky/sky.c b/PLUGINS/src/sky/sky.c deleted file mode 100644 index 75bd9ec..0000000 --- a/PLUGINS/src/sky/sky.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * sky.c: A plugin for the Video Disk Recorder - * - * See the README file for copyright information and how to reach the author. - * - * $Id: sky.c 2.1 2008/09/07 11:54:07 kls Exp $ - */ - -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/un.h> -#include <unistd.h> -#include <vdr/device.h> -#include <vdr/plugin.h> -#include <vdr/sources.h> - -static const char *VERSION = "0.3.8"; -static const char *DESCRIPTION = "Sky Digibox interface"; - -// --- cDigiboxDevice -------------------------------------------------------- - -#define DUMMYAPID 80 -#define DUMMYVPID 160 - -class cSkyChannel : public cListObject { -public: - tChannelID channelID; - int digiboxChannelNumber; - bool Parse(const char *s); - }; - -bool cSkyChannel::Parse(const char *s) -{ - char *id = NULL; - if (2 == sscanf(s, "%a[^:]:%d", &id, &digiboxChannelNumber)) - channelID = tChannelID::FromString(id); - free(id); - return digiboxChannelNumber && channelID.Valid(); -} - -class cSkyChannels : public cConfig<cSkyChannel> { -public: - cSkyChannel *GetSkyChannel(const cChannel *Channel); - }; - -cSkyChannel *cSkyChannels::GetSkyChannel(const cChannel *Channel) -{ - tChannelID ChannelID = Channel->GetChannelID(); - for (cSkyChannel *sc = First(); sc; sc = Next(sc)) { - if (ChannelID == sc->channelID) - return sc; - } - return NULL; -} - -cSkyChannels SkyChannels; - -class cDigiboxDevice : public cDevice { -private: - int source; - int digiboxChannelNumber; - int fd_dvr; - int apid, vpid; - cTSBuffer *tsBuffer; - int fd_lirc; - void LircSend(const char *s); - void LircSend(int n); -protected: - virtual bool SetPid(cPidHandle *Handle, int Type, bool On); - virtual bool OpenDvr(void); - virtual void CloseDvr(void); - virtual bool GetTSPacket(uchar *&Data); -public: - cDigiboxDevice(void); - virtual ~cDigiboxDevice(); - virtual bool ProvidesSource(int Source) const; - virtual bool ProvidesTransponder(const cChannel *Channel) const; - virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSetChannel = NULL) const; - virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); - }; - -cDigiboxDevice::cDigiboxDevice(void) -{ - source = cSource::FromString("S28.2E");//XXX parameter??? - digiboxChannelNumber = 0; - fd_dvr = -1; - apid = vpid = 0; - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - strn0cpy(addr.sun_path, "/dev/lircd", sizeof(addr.sun_path));//XXX parameter??? - fd_lirc = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd_lirc >= 0) { - if (connect(fd_lirc, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - LOG_ERROR; - close(fd_lirc); - } - } - else - LOG_ERROR; -} - -cDigiboxDevice::~cDigiboxDevice() -{ - if (fd_lirc >= 0) - close(fd_lirc); -} - -void cDigiboxDevice::LircSend(const char *s) -{ - char buf[100]; - snprintf(buf, sizeof(buf), "SEND_ONCE SKY %s\n", s); - dsyslog(buf);//XXX - if (write(fd_lirc, buf, strlen(buf)) < 0) - LOG_ERROR;//XXX _STR - cCondWait::SleepMs(200); -} - -void cDigiboxDevice::LircSend(int n) -{ - char buf[10]; - snprintf(buf, sizeof(buf), "%d", n); - char *p = buf; - while (*p) { - char q[10]; - sprintf(q, "%c", *p); - LircSend(q); - p++; - } -} - -bool cDigiboxDevice::SetPid(cPidHandle *Handle, int Type, bool On) -{ - //dsyslog("SetPid %d %d", Handle->pid, On); - return true; -} - -bool cDigiboxDevice::OpenDvr(void) -{ - CloseDvr(); - fd_dvr = open("/dev/video2", O_RDONLY | O_NONBLOCK);//XXX parameter??? - if (fd_dvr >= 0) - tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(2), CardIndex() + 1); - return fd_dvr >= 0; -} - -void cDigiboxDevice::CloseDvr(void) -{ - if (fd_dvr >= 0) { - close(fd_dvr); - fd_dvr = -1; - delete tsBuffer; - tsBuffer = NULL; - } -} - -bool cDigiboxDevice::GetTSPacket(uchar *&Data) -{ - if (tsBuffer) { - Data = tsBuffer->Get(); - if (Data) { - // insert the actual PIDs: - int Pid = (((uint16_t)Data[1] & TS_PID_MASK_HI) << 8) | Data[2]; - if (Pid == DUMMYAPID) - Pid = apid; - else if (Pid == DUMMYVPID) - Pid = vpid; - Data[1] = ((Pid >> 8) & 0xFF) | (Data[1] & ~TS_PID_MASK_HI); - Data[2] = Pid & 0xFF; - } - return true; - } - return false; -} - -bool cDigiboxDevice::ProvidesSource(int Source) const -{ - return source == Source; -} - -bool cDigiboxDevice::ProvidesTransponder(const cChannel *Channel) const -{ - return false; // can't provide any actual transponder -} - -bool cDigiboxDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const -{ - bool result = false; - bool hasPriority = Priority < 0 || Priority > this->Priority(); - bool needsDetachReceivers = true; - - cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel); - if (SkyChannel) { - if (Receiving(true)) { - if (digiboxChannelNumber == SkyChannel->digiboxChannelNumber) { - needsDetachReceivers = false; - result = true; - } - else - result = hasPriority; - } - else - result = hasPriority; - } - if (NeedsDetachReceivers) - *NeedsDetachReceivers = needsDetachReceivers; - return result; -} - -bool cDigiboxDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) -{ - if (fd_lirc >= 0 && !Receiving(true)) { // if we are receiving the channel is already set! - cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel); - if (SkyChannel) { - digiboxChannelNumber = SkyChannel->digiboxChannelNumber; - apid = Channel->Apid(0); - vpid = Channel->Vpid(); - //XXX only when recording??? -> faster channel switching! - LircSend("SKY"); // makes sure the Digibox is "on" - //XXX lircprint(fd_lirc, "BACKUP"); - //XXX lircprint(fd_lirc, "BACKUP"); - //XXX lircprint(fd_lirc, "BACKUP"); - LircSend(digiboxChannelNumber); - } - } - return true; -} - -// --- cPluginSky ------------------------------------------------------------ - -class cPluginSky : public cPlugin { -private: - // Add any member variables or functions you may need here. -public: - cPluginSky(void); - virtual ~cPluginSky(); - virtual const char *Version(void) { return VERSION; } - virtual const char *Description(void) { return DESCRIPTION; } - virtual const char *CommandLineHelp(void); - virtual bool ProcessArgs(int argc, char *argv[]); - virtual bool Initialize(void); - virtual void Housekeeping(void); - virtual cMenuSetupPage *SetupMenu(void); - virtual bool SetupParse(const char *Name, const char *Value); - }; - -cPluginSky::cPluginSky(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! -} - -cPluginSky::~cPluginSky() -{ - // Clean up after yourself! -} - -const char *cPluginSky::CommandLineHelp(void) -{ - // Return a string that describes all known command line options. - return NULL; -} - -bool cPluginSky::ProcessArgs(int argc, char *argv[]) -{ - // Implement command line argument processing here if applicable. - return true; -} - -bool cPluginSky::Initialize(void) -{ - // Initialize any background activities the plugin shall perform. - const char *ConfigDir = ConfigDirectory(Name()); - if (ConfigDir) { - if (SkyChannels.Load(AddDirectory(ConfigDir, "channels.conf.sky"), true)) { - new cDigiboxDevice; - return true; - } - } - else - esyslog("ERROR: can't get config directory"); - return false; -} - -void cPluginSky::Housekeeping(void) -{ - // Perform any cleanup or other regular tasks. -} - -cMenuSetupPage *cPluginSky::SetupMenu(void) -{ - // Return a setup menu in case the plugin supports one. - return NULL; -} - -bool cPluginSky::SetupParse(const char *Name, const char *Value) -{ - // Parse your own setup parameters and store their values. - return false; -} - -VDRPLUGINCREATOR(cPluginSky); // Don't touch this! |