Version 1.7.11

- Fixed resetting the file size when regenerating the index file.
- The new function cDevice::PatPmtParser() can be used in derived devices to access
  the PAT/PMT of the currently replayed material.
- Updated the Italian OSD texts (thanks to Diego Pierotto).
- The PCR pid in generated PMTs is now set to 0x1FFF ("no PCR pid") in
  cPatPmtGenerator::GeneratePmt(), because VDR doesn't record the PCR pid.
- Updated the Estonian OSD texts (thanks to Arthur Konovalov).
- The 'sky' plugin is no longer part of the VDR source.
- Improved SPU handling on devices with limited OSD capabilities (thanks to
  Matthieu Castet).
- Several code modifications to avoid compiler warnings (thanks to Winfried Köhler).
- Added stream type 11172 AUDIO to cPatPmtParser::ParsePmt() (thanks to Johann
  Friedrichs).
- Removed debug output of '-' from cTransfer::Receive().
- Added defines for large files to the 'newplugin' script (reported by Udo Richter).
- Removed the workaround for short channel names of "Kabel Deutschland", because
  apparently they now have their data according to the DVB standard (thanks to
  Johann Friedrichs).
- Some fixes to dvbspu.[hc] (thanks to Johann Friedrichs).
- Fixed a busy loop when moving editing marks (thanks to Johann Friedrichs).
- Updated sources.conf (thanks to Derek Kelly).
- Modified cCharSetConv so that it can be used to convert from "whatever VDR uses"
  to a given code (thanks to Joachim Wilke).
- Channel names containing commas are now handled correctly in channels.conf.
  If a channel's short name contains a comma, it is replaced with a '.'.
- cDevice now logs the device number when a new device is created.
- Fixed handling STREAMTYPE_11172_AUDIO in cPatPmtParser::ParsePmt().
- cParsePatPmt now has functions to retrieve the audio, dolby and subtitle pids.
- cPatFilter::Process() now only stores CA descriptors for video and audio pids
  (thanks to Francesco Saverio Schiavarelli for reporting a problem with channels
  that have some encrypted components that VDR doesn't use).
- cDevice::AddPid() now stores the stream type of the given pid (thanks to Andreas
  Regel).
- Added cFont::FontName() and cFont::Size() (thanks to Andreas Regel).
- cPatPmtParser now also stores the audio stream types.
- The support for full featured DVB cards of the TT/FuSi design has been moved
  into the new plugin 'dvbsddevice'. On systems that use such a card as their
  primary device, this plugin now needs to be loaded when running VDR in order
  to view live or recorded video. If the plugin is not loaded, the card will
  be treated like a budget DVB card, and there will be no OSD or viewing
  capability.
- Fixed handling the "CA PMT" generation (revised a change not mentioned in version
  1.7.9's changes, which caused a malfunction with Conax and Viaccess CAMs).
- Fixed stopping subtitle display when switching the primary device (thanks to
  Anssi Hannula).
  IMPORTANT NOTE TO PLUGIN AUTHORS: a plugin that implements a derived cDevice
  class that can replay video must now call the MakePrimaryDevice() function of
  its base class.
- Fixed compiler warnings "format not a string literal and no format arguments"
  in some syslog calls (thanks to Rolf Ahrenberg).
- The new command line options --edit and --genindex can be used to edit a
  recording or generate its index without actually starting the entire VDR
  (based on a patch from Helmut Auer).
- Improved the description of the transponder parameters in vdr.5 (thanks to
  Winfried Köhler).
- Avoiding setting the video stream type to 2 if the vpid is 0 (problem reported
  by Arthur Konovalov).
- Implemented handling the "Content Descriptor" (based on a patch from Rolf
  Ahrenberg). The 'classic', 'sttng' and 'curses' skins display the textual
  representation of the content descriptors as "genre". The epg.data file stores
  the genre using the tag character 'G'.
- Implemented handling the "Parental Rating Descriptor" (based on a patch from Rolf
  Ahrenberg). The 'classic', 'sttng' and 'curses' skins display the parental
  rating (if given) in their event displays. The epg.data file stores
  the parental rating using the tag character 'R'.
  IMPORTANT NOTE: if VDR doesn't display a parental rating, this does not
  necessarily mean that the given programme is suitable for all audiences!
- Rearranged cEvent members to minimize memory waste.
- After a CLRE command, no further EPG processing is now done for 10 seconds,
  so that data sent with subsequent PUTE commands doesn't interfere with data
  from the broadcasters (suggested by Helmut Auer).
- Added support for DVB cards with multiple fontends. Note that this only
  works for DVB cards where each frontend can be used independently of all
  the others on the same adapter.
- Fixed plugin arguments corruption with glibc 2.11 on x86_64 (thanks to
  Anssi Hannula).
This commit is contained in:
Klaus Schmidinger
2010-01-06 13:34:00 +01:00
parent ea01358b3b
commit 939081e274
100 changed files with 8342 additions and 2200 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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!

View File

@@ -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<68><6C>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;
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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<67>en).
2009-12-06: Version 0.2.4
- Several code modifications to avoid compiler warnings (thanks to Winfried K<>hler).

View File

@@ -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;

View File

@@ -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).

View File

@@ -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;

View File

@@ -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.

View File

@@ -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);

View File

@@ -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 "&amp;" 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).

View File

@@ -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.

View File

@@ -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

View File

@@ -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/&amp;/&/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;
}
#---------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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!