Andrew de Quincey schrieb:
Hi, I've just tried my MPEX under 2.6.8.1 - no problems here. I *AM* using my updated patch (which I have attached) but I wouldn't have thought that would fix sound muting problems.
[...]
Hi Andrew,
the list seems to be down, therefore I send this mail to you directly.
I tried your patch, but without success. :-( Maybe I'm doing something wrong.
Please take a look to the attached code. This one was, slightly modificated, running under kernel 2.4.24 to 2.4.26 with the v4l2 patch.
The only thing I have changed is the way how to set uo the video and audio pid's. I hope that you are familar with vdr.
I have some entries in my channels.conf like this:
C-Video:1:h:S28.2E:0:260:256:0:5:1:0:0:0 S-Video:1:h:S28.2E:0:260:256:0:5:2:0:0:0 M-Tuner:1:h:S28.2E:0:260:256:0:5:3:0:0:0
The first parameters are ignored 260 is the video pid (this was 256 before) 256 is the audio pid (this was 259 before) 0 is the nonexisting teletext pid 5 is the ca device number, it directs to my card 1,2,3 are the v4l2-inputs of the card
With the 2.4.x kernels I could adjust the colour, brightness and contrast. Controling the volume or loudness was not possible. I don't have to unmute anything.
In my setup the 1st device was the v4l2-device witch was opend to set up the colour and the second device was the ts-device
With the new kernel everything is working as before but I have no sound. This is also the case if I reboot from 2.6.8.1 to 2.4.26 without switching off. I tried different things (unmuting, input switching, etc) That is the reason why the source is a little bit messed up with comments.
I gave up for now, you are my last hope. :-)
Alfred
/* * mpex.c: A plugin for the Video Disk Recorder * * See the README file for copyright information and how to reach the author. */
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/sysinfo.h>
#include <sys/soundcard.h>
#include <linux/videodev.h>
#include <getopt.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <vdr/plugin.h>
#include <vdr/sources.h>
static const char *VERSION = "0.0.1";
static const char *DESCRIPTION = "MPEX card interface";
static const char *MAINMENUENTRY = NULL; //Hide main menu entry
// Global variables that control the overall behaviour:
int Volume;
int Loudness;
int Brightness;
int Contrast;
int Colour;
// --- cDigiboxDevice --------------------------------------------------------
#define DUMMYVPID 260
#define DUMMYAPID 256
/*
class cMpexChannel : public cListObject {
public:
tChannelID channelID;
int digiboxChannelNumber;
bool Parse(const char *s);
};
bool cMpexChannel::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 cMpexChannels : public cConfig<cMpexChannel> {
public:
cMpexChannel *GetMpexChannel(const cChannel *Channel);
};
cMpexChannel *cMpexChannels::GetMpexChannel(const cChannel *Channel)
{
tChannelID ChannelID = Channel->GetChannelID();
for (cMpexChannel *sc = First(); sc; sc = Next(sc)) {
if (ChannelID == sc->channelID)
return sc;
}
return NULL;
}
cMpexChannels MpexChannels;
*/
class cDigiboxDevice : public cDevice
{
private:
int source;
int digiboxChannelNumber;
int fd_dvr;
int fd;
int apid, vpid, sid, tid;
cTSBuffer *tsBuffer;
static const char *videodevice;
static const char *tsdevice;
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);
static void SetVideoDevice(const char *VideoDevice);
static const char *VideoDevice(void);
static void SetTSDevice(const char *TSDevice);
static const char *TSDevice(void);
};
const char *cDigiboxDevice::tsdevice = "/dev/video1";
const char *cDigiboxDevice::videodevice = "/dev/video0";
cDigiboxDevice::cDigiboxDevice(void)
{
source = cSource::FromString("S28.2E");
digiboxChannelNumber = 0;
fd_dvr = -1;
apid = vpid = 0;
}
cDigiboxDevice::~cDigiboxDevice()
{
// Clean up after yourself!
}
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(tsdevice, O_RDONLY | O_NONBLOCK );
if (fd_dvr >= 0)
tsBuffer = new cTSBuffer(fd_dvr, KILOBYTE(256), 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)
{
int r = tsBuffer->Read();
if (r >= 0)
{
Data = tsBuffer->Get();
//-----------this part is new in 1.3.x
if (Data) {
// insert the actual PIDs:
int Pid = (((uint16_t)Data[1] & PID_MASK_HI) << 8) | Data[2];
if (Pid == DUMMYAPID)
Pid = apid;
else if (Pid == DUMMYVPID)
Pid = vpid;
Data[1] = ((Pid >> 8) & 0xFF) | (Data[1] & ~PID_MASK_HI);
Data[2] = Pid & 0xFF;
}
//---------------------------
return true;
}
else if (FATALERRNO)
{
LOG_ERROR;
return false;
}
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;
// cMpexChannel *MpexChannel = MpexChannels.GetMpexChannel(Channel);
// if (MpexChannel) {
if (ProvidesSource(Channel->Source())) {
if (Receiving(true)) {
// if (digiboxChannelNumber == MpexChannel->digiboxChannelNumber) {
if (digiboxChannelNumber == Channel->Frequency()) {
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 ( !Receiving(true)) { // if we are receiving the channel is already set!
// cMpexChannel *MpexChannel = MpexChannels.GetMpexChannel(Channel);
// if (MpexChannel) {
// digiboxChannelNumber = MpexChannel->digiboxChannelNumber;
digiboxChannelNumber = Channel->Sid();
vpid = Channel->Vpid(); // Video PID (MPEX default = 256)
apid = Channel->Apid1(); // Audio PID (MPEX default = 259)
tid = Channel->Tid(); // TID, used to switch input (0=composite
video, 1=svhs, 2=tuner)
sid = Channel->Sid(); // SID, sended by LIRC
esyslog("Set Channel TID %d SID %d VPID %d APID %d", tid, sid, vpid,
apid);
//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);
//struct v4l2_capability vcap;
//struct v4l2_input input;
//struct v4l2_queryctrl queryctrl;
struct v4l2_control control;
fd = open(videodevice, O_RDWR);
if (ioctl(fd, VIDIOC_S_INPUT, &tid) == -1 ) {
const char *c = "Error: digiboxChannelNumber %s\n";
char buf[100];
sprintf(buf, c, digiboxChannelNumber);
dsyslog(buf);
}
// struct v4l2_audio audio;
// memset (&audio, 0, sizeof (audio)); /* clear audio.mode, audio.reserved */
// audio.index = 0;
// if (ioctl(fd, VIDIOC_S_AUDIO, &audio) == -1 ) {
// perror ("VIDIOC_S AUDIO");
// }
// --- setting brightness ---
control.id = V4L2_CID_BRIGHTNESS;
control.value = Brightness;
if (ioctl (fd, VIDIOC_S_CTRL, &control) == -1) {
perror ("VIDIOC_S_CTRL");
}
// --- setting contrast ---
control.id = V4L2_CID_CONTRAST;
control.value = Contrast;
if (ioctl (fd, VIDIOC_S_CTRL, &control) == -1) {
perror ("VIDIOC_S_CTRL");
}
control.id = V4L2_CID_HUE;
control.value = Colour;
if (ioctl (fd, VIDIOC_S_CTRL, &control) == -1) {
perror ("VIDIOC_S_CTRL");
}
// --- volume setting --- funzt nicht :-(
// control.id = V4L2_CID_AUDIO_VOLUME;
// control.value = Volume;
// if (ioctl (fd, VIDIOC_S_CTRL, &control) == -1) {
// perror ("VIDIOC_S_CTRL");
// }
// control.id = V4L2_CID_AUDIO_LOUDNESS;
// control.value = true;
// if (ioctl (fd, VIDIOC_S_CTRL, &control) == -1) {
// perror ("VIDIOC_S_CTRL");
// }
// control.id = V4L2_CID_AUDIO_MUTE;
// control.value = false;
// if (ioctl (fd, VIDIOC_S_CTRL, &control) == -1) {
// perror ("VIDIOC_S_CTRL");
// }
close(fd);
// }
}
return true;
}
void cDigiboxDevice::SetVideoDevice(const char *VideoDevice)
{
videodevice = strdup(VideoDevice);
}
const char *cDigiboxDevice::VideoDevice(void)
{
return videodevice;
}
void cDigiboxDevice::SetTSDevice(const char *TSDevice)
{
tsdevice = strdup(TSDevice);
}
const char *cDigiboxDevice::TSDevice(void)
{
return tsdevice;
}
// --- cPluginMpex ------------------------------------------------------------
class cPluginMpex : public cPlugin
{
private:
// Add any member variables or functions you may need here.
const char *videodevice;
const char *tsdevice;
public:
cPluginMpex(void);
virtual ~cPluginMpex();
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 bool Start(void);
virtual void Housekeeping(void);
virtual const char *MainMenuEntry(void) { return MAINMENUENTRY; }
virtual cOsdObject *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value);
};
cPluginMpex::cPluginMpex(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!
videodevice = "/dev/video0";
tsdevice = "/dev/video1";
}
cPluginMpex::~cPluginMpex()
{
// Clean up after yourself!
}
const char *cPluginMpex::CommandLineHelp(void)
{
// Return a string that describes all known command line options.
return " -v [dev], --video=[dev] Video-Device (default: /dev/video0\n"
" -t [dev], --ts=[dev] TS-Device (default: /dev/video1\n";
}
bool cPluginMpex::ProcessArgs(int argc, char *argv[])
{
// Implement command line argument processing here if applicable.
static struct option long_options[] =
{
{ "video", required_argument, NULL, 'v'},
{ "ts", required_argument, NULL, 't'},
{ NULL}
};
int c, option_index = 0;
while((c = getopt_long(argc,argv,"v:t:",long_options,&option_index))!=-1)
{
switch(c)
{
case 'v':
videodevice = optarg;
break;
case 't':
tsdevice = optarg;
break;
default:
return false;
}
}
return true;
}
bool cPluginMpex::Initialize(void)
{
// Initialize any background activities the plugin shall perform.
new cDigiboxDevice;
return true;
/*
const char *ConfigDir = ConfigDirectory(Name());
if (ConfigDir) {
if (MpexChannels.Load(AddDirectory(ConfigDir, "channels.conf.mpex"), true)) {
new cDigiboxDevice;
return true;
}
}
else
esyslog("ERROR: can't get config directory");
return false;
*/
}
bool cPluginMpex::Start(void)
{
// Start any background activities the plugin shall perform.
cDigiboxDevice::SetVideoDevice(videodevice);
cDigiboxDevice::SetTSDevice(tsdevice);
//RegisterI18n(Phrases);
return true;
}
void cPluginMpex::Housekeeping(void)
{
// Perform any cleanup or other regular tasks.
}
cOsdObject *cPluginMpex::MainMenuAction(void)
{
// Perform the action when selected from the main VDR menu.
return NULL;
}
class cMenuSetupMpex : public cMenuSetupPage
{
private:
int newVolume;
int newLoudness;
int newBrightness;
int newContrast;
int newColour;
protected:
virtual void Store(void);
public:
cMenuSetupMpex(void);
};
cMenuSetupPage *cPluginMpex::SetupMenu(void)
{
// Return a setup menu in case the plugin supports one.
return new cMenuSetupMpex;
}
cMenuSetupMpex::cMenuSetupMpex(void)
{
// Return a setup menu in case the plugin supports one.
newVolume = Volume;
newLoudness = Loudness;
newBrightness = Brightness;
newContrast = Contrast;
newColour = Colour;
Add(new cMenuEditIntItem(tr("Volume"), &newVolume, 1, 65535));
Add(new cMenuEditIntItem(tr("Loudness"), &newLoudness, 0, 1));
Add(new cMenuEditIntItem(tr("Brightness"), &newBrightness, 1, 65535));
Add(new cMenuEditIntItem(tr("Contrast"), &newContrast, 1, 65535));
Add(new cMenuEditIntItem(tr("Colour"), &newColour, 1, 65535));
}
void cMenuSetupMpex::Store(void)
{
SetupStore("Volume", Volume = newVolume);
SetupStore("Loudness", Loudness = newLoudness);
SetupStore("Brightness", Brightness = newBrightness);
SetupStore("Contrast", Contrast = newContrast);
SetupStore("Colour", Colour = newColour);
}
bool cPluginMpex::SetupParse(const char *Name, const char *Value)
{
// Parse your own setup parameters and store their values.
if (!strcasecmp(Name, "Volume")) Volume = atoi(Value);
else if (!strcasecmp(Name, "Loudness")) Loudness = atoi(Value);
else if (!strcasecmp(Name, "Brightness")) Brightness = atoi(Value);
else if (!strcasecmp(Name, "Contrast")) Contrast = atoi(Value);
else if (!strcasecmp(Name, "Colour")) Colour = atoi(Value);
else
return false;
return true;
}
VDRPLUGINCREATOR(cPluginMpex); // Don't touch this!
