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!