summaryrefslogtreecommitdiff
path: root/dvbdevice.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <Klaus (dot) Schmidinger (at) tvdr (dot) de>2010-01-06 13:34:00 +0100
committerKlaus Schmidinger <Klaus (dot) Schmidinger (at) tvdr (dot) de>2010-01-06 13:34:00 +0100
commit939081e274d0a9868e5ba9a7951666ad508afb96 (patch)
treee79853c0ab397e609897a8f9dfc731231ce0aee4 /dvbdevice.c
parentea01358b3bca9d55402ba632c95cdd6458abfdb3 (diff)
downloadvdr-patch-lnbsharing-939081e274d0a9868e5ba9a7951666ad508afb96.tar.gz
vdr-patch-lnbsharing-939081e274d0a9868e5ba9a7951666ad508afb96.tar.bz2
Version 1.7.11vdr-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).
Diffstat (limited to 'dvbdevice.c')
-rw-r--r--dvbdevice.c899
1 files changed, 109 insertions, 790 deletions
diff --git a/dvbdevice.c b/dvbdevice.c
index dd425c8..07e2dbb 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -1,44 +1,22 @@
/*
- * dvbdevice.c: The DVB device interface
+ * dvbdevice.c: The DVB device tuner interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.c 2.21 2009/06/06 11:17:20 kls Exp $
+ * $Id: dvbdevice.c 2.24 2010/01/04 14:06:24 kls Exp $
*/
#include "dvbdevice.h"
#include <errno.h>
#include <limits.h>
-#include <linux/videodev2.h>
-#include <linux/dvb/audio.h>
#include <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h>
-#include <linux/dvb/video.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "channels.h"
#include "diseqc.h"
#include "dvbci.h"
-#include "dvbosd.h"
-#include "eitscan.h"
-#include "player.h"
-#include "receiver.h"
-#include "status.h"
-#include "transfer.h"
-
-#define DO_REC_AND_PLAY_ON_PRIMARY_DEVICE 1
-#define DO_MULTIPLE_RECORDINGS 1
-
-#define DEV_VIDEO "/dev/video"
-#define DEV_DVB_ADAPTER "/dev/dvb/adapter"
-#define DEV_DVB_OSD "osd"
-#define DEV_DVB_FRONTEND "frontend"
-#define DEV_DVB_DVR "dvr"
-#define DEV_DVB_DEMUX "demux"
-#define DEV_DVB_VIDEO "video"
-#define DEV_DVB_AUDIO "audio"
-#define DEV_DVB_CA "ca"
#define DVBS_TUNE_TIMEOUT 9000 //ms
#define DVBS_LOCK_TIMEOUT 2000 //ms
@@ -47,32 +25,13 @@
#define DVBT_TUNE_TIMEOUT 9000 //ms
#define DVBT_LOCK_TIMEOUT 2000 //ms
-class cDvbName {
-private:
- char buffer[PATH_MAX];
-public:
- cDvbName(const char *Name, int n) {
- snprintf(buffer, sizeof(buffer), "%s%d/%s%d", DEV_DVB_ADAPTER, n, Name, 0);
- }
- const char *operator*() { return buffer; }
- };
-
-static int DvbOpen(const char *Name, int n, int Mode, bool ReportError = false)
-{
- const char *FileName = *cDvbName(Name, n);
- int fd = open(FileName, Mode);
- if (fd < 0 && ReportError)
- LOG_ERROR_STR(FileName);
- return fd;
-}
-
// --- cDvbTuner -------------------------------------------------------------
class cDvbTuner : public cThread {
private:
enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked };
int fd_frontend;
- int cardIndex;
+ int adapter, frontend;
int tuneTimeout;
int lockTimeout;
time_t lastTimeoutReport;
@@ -87,17 +46,18 @@ private:
bool SetFrontend(void);
virtual void Action(void);
public:
- cDvbTuner(int Fd_Frontend, int CardIndex, fe_delivery_system FrontendType);
+ cDvbTuner(int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType);
virtual ~cDvbTuner();
bool IsTunedTo(const cChannel *Channel) const;
- void Set(const cChannel *Channel, bool Tune);
+ void Set(const cChannel *Channel);
bool Locked(int TimeoutMs = 0);
};
-cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_delivery_system FrontendType)
+cDvbTuner::cDvbTuner(int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType)
{
fd_frontend = Fd_Frontend;
- cardIndex = CardIndex;
+ adapter = Adapter;
+ frontend = Frontend;
frontendType = FrontendType;
tuneTimeout = 0;
lockTimeout = 0;
@@ -106,7 +66,7 @@ cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_delivery_system Frontend
tunerStatus = tsIdle;
if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2)
CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
- SetDescription("tuner on device %d", cardIndex + 1);
+ SetDescription("tuner on frontend %d/%d", adapter, frontend);
Start();
}
@@ -141,10 +101,10 @@ bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
return true;
}
-void cDvbTuner::Set(const cChannel *Channel, bool Tune)
+void cDvbTuner::Set(const cChannel *Channel)
{
cMutexLock MutexLock(&mutex);
- if (Tune)
+ if (!IsTunedTo(Channel))
tunerStatus = tsSet;
channel = *Channel;
lastTimeoutReport = 0;
@@ -195,7 +155,7 @@ bool cDvbTuner::SetFrontend(void)
#define SETCMD(c, d) { Frontend[CmdSeq.num].cmd = (c);\
Frontend[CmdSeq.num].u.data = (d);\
if (CmdSeq.num++ > MAXFRONTENDCMDS) {\
- esyslog("ERROR: too many tuning commands on frontend %d", cardIndex);\
+ esyslog("ERROR: too many tuning commands on frontend %d/%d", adapter, frontend);\
return false;\
}\
}
@@ -206,7 +166,7 @@ bool cDvbTuner::SetFrontend(void)
CmdSeq.props = Frontend;
SETCMD(DTV_CLEAR, 0);
if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
- esyslog("ERROR: frontend %d: %m", cardIndex);
+ esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
return false;
}
CmdSeq.num = 0;
@@ -238,6 +198,7 @@ bool cDvbTuner::SetFrontend(void)
}
}
break;
+ default: esyslog("ERROR: unknown diseqc command %d", da);
}
}
diseqcCommands = diseqc->Commands();
@@ -279,7 +240,7 @@ bool cDvbTuner::SetFrontend(void)
SETCMD(DTV_ROLLOFF, channel.RollOff());
}
else {
- esyslog("ERROR: frontend %d doesn't provide DVB-S2", cardIndex);
+ esyslog("ERROR: frontend %d/%d doesn't provide DVB-S2", adapter, frontend);
return false;
}
}
@@ -325,7 +286,7 @@ bool cDvbTuner::SetFrontend(void)
}
SETCMD(DTV_TUNE, 0);
if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) {
- esyslog("ERROR: frontend %d: %m", cardIndex);
+ esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
return false;
}
return true;
@@ -353,7 +314,7 @@ void cDvbTuner::Action(void)
tunerStatus = tsSet;
diseqcCommands = NULL;
if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these
- isyslog("frontend %d timed out while tuning to channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder());
+ isyslog("frontend %d/%d timed out while tuning to channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder());
lastTimeoutReport = time(NULL);
}
continue;
@@ -362,13 +323,13 @@ void cDvbTuner::Action(void)
if (Status & FE_REINIT) {
tunerStatus = tsSet;
diseqcCommands = NULL;
- isyslog("frontend %d was reinitialized", cardIndex);
+ isyslog("frontend %d/%d was reinitialized", adapter, frontend);
lastTimeoutReport = 0;
continue;
}
else if (Status & FE_HAS_LOCK) {
if (LostLock) {
- isyslog("frontend %d regained lock on channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder());
+ isyslog("frontend %d/%d regained lock on channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder());
LostLock = false;
}
tunerStatus = tsLocked;
@@ -377,12 +338,14 @@ void cDvbTuner::Action(void)
}
else if (tunerStatus == tsLocked) {
LostLock = true;
- isyslog("frontend %d lost lock on channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder());
+ isyslog("frontend %d/%d lost lock on channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder());
tunerStatus = tsTuned;
Timer.Set(lockTimeout);
lastTimeoutReport = 0;
continue;
}
+ break;
+ default: esyslog("ERROR: unknown tuner status %d", tunerStatus);
}
if (tunerStatus != tsTuned)
@@ -392,7 +355,6 @@ void cDvbTuner::Action(void)
// --- cDvbDevice ------------------------------------------------------------
-int cDvbDevice::devVideoOffset = -1;
int cDvbDevice::setTransferModeForDolbyDigital = 1;
const char *DeliverySystems[] = {
@@ -415,30 +377,22 @@ const char *DeliverySystems[] = {
NULL
};
-cDvbDevice::cDvbDevice(int n)
+cDvbDevice::cDvbDevice(int Adapter, int Frontend)
{
+ adapter = Adapter;
+ frontend = Frontend;
ciAdapter = NULL;
dvbTuner = NULL;
frontendType = SYS_UNDEFINED;
numProvidedSystems = 0;
- spuDecoder = NULL;
- digitalAudio = false;
- playMode = pmNone;
// Devices that are present on all card types:
- int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, n, O_RDWR | O_NONBLOCK);
-
- // Devices that are only present on cards with decoders:
-
- fd_osd = DvbOpen(DEV_DVB_OSD, n, O_RDWR);
- fd_video = DvbOpen(DEV_DVB_VIDEO, n, O_RDWR | O_NONBLOCK);
- fd_audio = DvbOpen(DEV_DVB_AUDIO, n, O_RDWR | O_NONBLOCK);
- fd_stc = DvbOpen(DEV_DVB_DEMUX, n, O_RDWR);
+ int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK);
// Common Interface:
- fd_ca = DvbOpen(DEV_DVB_CA, n, O_RDWR);
+ fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR);
if (fd_ca >= 0)
ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, fd_ca);
@@ -446,39 +400,6 @@ cDvbDevice::cDvbDevice(int n)
fd_dvr = -1;
- // 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 && HasDecoder()) ? devVideoOffset++ : -1;
-
- // Video format:
-
- SetVideoFormat(Setup.VideoFormat);
-
// We only check the devices that must be present - the others will be checked before accessing them://XXX
if (fd_frontend >= 0) {
@@ -488,7 +409,7 @@ cDvbDevice::cDvbDevice(int n)
case FE_OFDM: frontendType = SYS_DVBT; break;
case FE_QAM: frontendType = SYS_DVBC_ANNEX_AC; break;
case FE_ATSC: frontendType = SYS_ATSC; break;
- default: esyslog("ERROR: unknown frontend type %d on device %d", frontendInfo.type, CardIndex() + 1);
+ default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend);
}
}
else
@@ -497,12 +418,12 @@ cDvbDevice::cDvbDevice(int n)
numProvidedSystems++;
if (frontendType == SYS_DVBS2)
numProvidedSystems++;
- isyslog("device %d provides %s (\"%s\")", CardIndex() + 1, DeliverySystems[frontendType], frontendInfo.name);
- dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType);
+ isyslog("frontend %d/%d provides %s (\"%s\")", adapter, frontend, DeliverySystems[frontendType], frontendInfo.name);
+ dvbTuner = new cDvbTuner(fd_frontend, adapter, frontend, frontendType);
}
}
else
- esyslog("ERROR: can't open DVB device %d", n);
+ esyslog("ERROR: can't open DVB device %d/%d", adapter, frontend);
StartSectionHandler();
}
@@ -510,63 +431,86 @@ cDvbDevice::cDvbDevice(int n)
cDvbDevice::~cDvbDevice()
{
StopSectionHandler();
- delete spuDecoder;
delete dvbTuner;
delete ciAdapter;
// We're not explicitly closing any device files here, since this sometimes
// caused segfaults. Besides, the program is about to terminate anyway...
}
-bool cDvbDevice::Probe(const char *FileName)
+cString cDvbDevice::DvbName(const char *Name, int Adapter, int Frontend)
{
+ return cString::sprintf("%s%d/%s%d", DEV_DVB_ADAPTER, Adapter, Name, Frontend);
+}
+
+int cDvbDevice::DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError)
+{
+ cString FileName = DvbName(Name, Adapter, Frontend);
+ int fd = open(FileName, Mode);
+ if (fd < 0 && ReportError)
+ LOG_ERROR_STR(*FileName);
+ return fd;
+}
+
+bool cDvbDevice::Exists(int Adapter, int Frontend)
+{
+ cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend);
if (access(FileName, F_OK) == 0) {
- dsyslog("probing %s", FileName);
int f = open(FileName, O_RDONLY);
if (f >= 0) {
close(f);
return true;
}
else if (errno != ENODEV && errno != EINVAL)
- LOG_ERROR_STR(FileName);
+ LOG_ERROR_STR(*FileName);
}
else if (errno != ENOENT)
- LOG_ERROR_STR(FileName);
+ LOG_ERROR_STR(*FileName);
return false;
}
-bool cDvbDevice::Initialize(void)
+bool cDvbDevice::Probe(int Adapter, int Frontend)
{
- int found = 0;
- int i;
- for (i = 0; i < MAXDVBDEVICES; i++) {
- if (UseDevice(NextCardIndex())) {
- if (Probe(*cDvbName(DEV_DVB_FRONTEND, i))) {
- new cDvbDevice(i);
- found++;
- }
- else
- break;
- }
- else
- NextCardIndex(1); // skips this one
+ cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend);
+ dsyslog("probing %s", *FileName);
+ for (cDvbDeviceProbe *dp = DvbDeviceProbes.First(); dp; dp = DvbDeviceProbes.Next(dp)) {
+ if (dp->Probe(Adapter, Frontend))
+ return true; // a plugin has created the actual device
}
- NextCardIndex(MAXDVBDEVICES - i); // skips the rest
- if (found > 0)
- isyslog("found %d video device%s", found, found > 1 ? "s" : "");
- else
- isyslog("no DVB device found");
- return found > 0;
-}
-
-void cDvbDevice::MakePrimaryDevice(bool On)
-{
- if (On && HasDecoder())
- new cDvbOsdProvider(fd_osd);
+ dsyslog("creating cDvbDevice");
+ new cDvbDevice(Adapter, Frontend); // it's a "budget" device
+ return true;
}
-bool cDvbDevice::HasDecoder(void) const
+bool cDvbDevice::Initialize(void)
{
- return fd_video >= 0 && fd_audio >= 0;
+ int Checked = 0;
+ int Found = 0;
+ for (int Adapter = 0; ; Adapter++) {
+ for (int Frontend = 0; ; Frontend++) {
+ if (Exists(Adapter, Frontend)) {
+ if (Checked++ < MAXDVBDEVICES) {
+ if (UseDevice(NextCardIndex())) {
+ if (Probe(Adapter, Frontend))
+ Found++;
+ }
+ else
+ NextCardIndex(1); // skips this one
+ }
+ }
+ else if (Frontend == 0)
+ goto LastAdapter;
+ else
+ goto NextAdapter;
+ }
+ NextAdapter: ;
+ }
+LastAdapter:
+ NextCardIndex(MAXDVBDEVICES - Checked); // skips the rest
+ if (Found > 0)
+ isyslog("found %d DVB device%s", Found, Found > 1 ? "s" : "");
+ else
+ isyslog("no DVB device found");
+ return Found > 0;
}
bool cDvbDevice::Ready(void)
@@ -576,234 +520,11 @@ bool cDvbDevice::Ready(void)
return true;
}
-cSpuDecoder *cDvbDevice::GetSpuDecoder(void)
-{
- if (!spuDecoder && IsPrimaryDevice())
- spuDecoder = new cDvbSpuDecoder();
- return spuDecoder;
-}
-
bool cDvbDevice::HasCi(void)
{
return ciAdapter;
}
-uchar *cDvbDevice::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 cDvbDevice::SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
-{
- cDevice::SetVideoDisplayFormat(VideoDisplayFormat);
- if (HasDecoder()) {
- 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;
- }
- }
- }
-}
-
-void cDvbDevice::SetVideoFormat(bool VideoFormat16_9)
-{
- if (HasDecoder()) {
- CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, VideoFormat16_9 ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3));
- SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
- }
-}
-
-eVideoSystem cDvbDevice::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 cDvbDevice::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 cDvbDevice::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 cDvbDevice::SetAudioBypass(bool On)
-{
- if (setTransferModeForDolbyDigital != 1)
- return false;
- return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0;
-}
-
-// ptAudio ptVideo ptPcr ptTeletext ptDolby ptOther
-dmx_pes_type_t PesTypes[] = { DMX_PES_AUDIO, DMX_PES_VIDEO, DMX_PES_PCR, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER };
-
bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
{
if (Handle->pid) {
@@ -811,7 +532,7 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
memset(&pesFilterParams, 0, sizeof(pesFilterParams));
if (On) {
if (Handle->handle < 0) {
- Handle->handle = DvbOpen(DEV_DVB_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true);
+ Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true);
if (Handle->handle < 0) {
LOG_ERROR;
return false;
@@ -819,8 +540,8 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
}
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.output = DMX_OUT_TS_TAP;
+ pesFilterParams.pes_type= DMX_PES_OTHER;
pesFilterParams.flags = DMX_IMMEDIATE_START;
if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
LOG_ERROR;
@@ -833,11 +554,9 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
pesFilterParams.pid = 0x1FFF;
pesFilterParams.input = DMX_IN_FRONTEND;
pesFilterParams.output = DMX_OUT_DECODER;
- pesFilterParams.pes_type= PesTypes[Type];
+ pesFilterParams.pes_type= DMX_PES_OTHER;
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;
@@ -848,7 +567,7 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
{
- const char *FileName = *cDvbName(DEV_DVB_DEMUX, CardIndex());
+ cString FileName = DvbName(DEV_DVB_DEMUX, adapter, frontend);
int f = open(FileName, O_RDWR | O_NONBLOCK);
if (f >= 0) {
dmx_sct_filter_params sctFilterParams;
@@ -866,7 +585,7 @@ int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
}
}
else
- esyslog("ERROR: can't open filter handle on '%s'", FileName);
+ esyslog("ERROR: can't open filter handle on '%s'", *FileName);
return -1;
}
@@ -875,29 +594,6 @@ void cDvbDevice::CloseFilter(int Handle)
close(Handle);
}
-void cDvbDevice::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 cDvbDevice::ProvidesSource(int Source) const
{
int type = Source & cSource::st_Mask;
@@ -929,7 +625,6 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
if (Priority >= 0 && Receiving(true)) {
if (dvbTuner->IsTunedTo(Channel)) {
if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0))) {
-#ifdef DO_MULTIPLE_RECORDINGS
if (CamSlot() && Channel->Ca() >= CA_ENCRYPTED_MIN) {
if (CamSlot()->CanDecrypt(Channel))
result = true;
@@ -938,11 +633,8 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
}
else if (!IsPrimaryDevice())
result = true;
-#ifdef DO_REC_AND_PLAY_ON_PRIMARY_DEVICE
else
result = Priority >= Setup.PrimaryLimit;
-#endif
-#endif
}
else
result = !IsPrimaryDevice() || Priority >= Setup.PrimaryLimit;
@@ -968,70 +660,7 @@ bool cDvbDevice::IsTunedToTransponder(const cChannel *Channel)
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
{
- int apid = Channel->Apid(0);
- int vpid = Channel->Vpid();
- int dpid = Channel->Dpid(0);
-
- bool DoTune = !dvbTuner->IsTunedTo(Channel);
-
- bool pidHandlesVideo = pidHandles[ptVideo].pid == vpid;
- bool pidHandlesAudio = pidHandles[ptAudio].pid == apid;
-
- bool TurnOffLivePIDs = HasDecoder()
- && (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 = HasDecoder() && !StartTransferMode && LiveView;
-
-#ifndef DO_MULTIPLE_RECORDINGS
- TurnOffLivePIDs = TurnOnLivePIDs = true;
- StartTransferMode = false;
-#endif
-
- // Turn off live PIDs if necessary:
-
- if (TurnOffLivePIDs)
- TurnOffLiveMode(LiveView);
-
- // Set the tuner:
-
- dvbTuner->Set(Channel, DoTune);
-
- // If this channel switch was requested by the EITScanner we don't wait for
- // a lock and don't set any live PIDs (the EITScanner will wait for the lock
- // by itself before setting any filters):
-
- if (EITScanner.UsesDevice(this)) //XXX
- return true;
-
- // PID settings:
-
- if (TurnOnLivePIDs) {
- SetAudioBypass(false);
- if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(vpid, ptVideo) && AddPid(apid, ptAudio))) {
- esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
- return false;
- }
- if (IsPrimaryDevice())
- AddPid(Channel->Tpid(), ptTeletext);
- CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true)); // actually one would expect 'false' here, but according to Marco Schlüßler <marco@lordzodiac.de> this works
- // to avoid missing audio after replaying a DVD; with 'false' there is an audio disturbance when switching
- // between two channels on the same transponder on DVB-S
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
- }
- else if (StartTransferMode)
- cControl::Launch(new cTransferControl(this, Channel->GetChannelID(), vpid, Channel->Apids(), Channel->Dpids(), Channel->Spids()));
-
+ dvbTuner->Set(Channel);
return true;
}
@@ -1040,339 +669,15 @@ bool cDvbDevice::HasLock(int TimeoutMs)
return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false;
}
-int cDvbDevice::GetAudioChannelDevice(void)
-{
- if (HasDecoder()) {
- audio_status_t as;
- CHECK(ioctl(fd_audio, AUDIO_GET_STATUS, &as));
- return as.channel_select;
- }
- return 0;
-}
-
-void cDvbDevice::SetAudioChannelDevice(int AudioChannel)
-{
- if (HasDecoder())
- CHECK(ioctl(fd_audio, AUDIO_CHANNEL_SELECT, AudioChannel));
-}
-
-void cDvbDevice::SetVolumeDevice(int Volume)
-{
- if (HasDecoder()) {
- 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 cDvbDevice::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 cDvbDevice::SetTransferModeForDolbyDigital(int Mode)
{
setTransferModeForDolbyDigital = Mode;
}
-void cDvbDevice::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 cDvbDevice::CanReplay(void) const
-{
-#ifndef DO_REC_AND_PLAY_ON_PRIMARY_DEVICE
- if (Receiving())
- return false;
-#endif
- return cDevice::CanReplay();
-}
-
-bool cDvbDevice::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, CardIndex(), O_RDWR | O_NONBLOCK);
- fd_audio = DvbOpen(DEV_DVB_AUDIO, CardIndex(), 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;
- }
- playMode = PlayMode;
- return true;
-}
-
-int64_t cDvbDevice::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 cDvbDevice::TrickSpeed(int Speed)
-{
- if (fd_video >= 0)
- CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed));
-}
-
-void cDvbDevice::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 cDvbDevice::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 cDvbDevice::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 cDvbDevice::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 cDvbDevice::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 cDvbDevice::Poll(cPoller &Poller, int TimeoutMs)
-{
- Poller.Add((playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) ? fd_audio : fd_video, true);
- return Poller.Poll(TimeoutMs);
-}
-
-bool cDvbDevice::Flush(int TimeoutMs)
-{
- //TODO actually this function should wait until all buffered data has been processed by the card, but how?
- return true;
-}
-
-int cDvbDevice::PlayVideo(const uchar *Data, int Length)
-{
- return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
-}
-
-int cDvbDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
-{
- return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
-}
-
-int cDvbDevice::PlayTsVideo(const uchar *Data, int Length)
-{
- return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
-}
-
-int cDvbDevice::PlayTsAudio(const uchar *Data, int Length)
-{
- return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
-}
-
bool cDvbDevice::OpenDvr(void)
{
CloseDvr();
- fd_dvr = DvbOpen(DEV_DVB_DVR, CardIndex(), O_RDONLY | O_NONBLOCK, true);
+ fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontend, O_RDONLY | O_NONBLOCK, true);
if (fd_dvr >= 0)
tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(2), CardIndex() + 1);
return fd_dvr >= 0;
@@ -1396,3 +701,17 @@ bool cDvbDevice::GetTSPacket(uchar *&Data)
}
return false;
}
+
+// --- cDvbDeviceProbe -------------------------------------------------------
+
+cList<cDvbDeviceProbe> DvbDeviceProbes;
+
+cDvbDeviceProbe::cDvbDeviceProbe(void)
+{
+ DvbDeviceProbes.Add(this);
+}
+
+cDvbDeviceProbe::~cDvbDeviceProbe()
+{
+ DvbDeviceProbes.Del(this, false);
+}