summaryrefslogtreecommitdiff
path: root/dvbapi.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-11-04 18:00:00 +0100
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-11-04 18:00:00 +0100
commit6e1fd835558b4e70ad94a280a209f050ec0f7a75 (patch)
treec7807d423152fecf6e7fd98aaa6fb69324238431 /dvbapi.c
parent8465398c6d2a57bc30a07fb61353a7c8ba6db574 (diff)
downloadvdr-patch-lnbsharing-6e1fd835558b4e70ad94a280a209f050ec0f7a75.tar.gz
vdr-patch-lnbsharing-6e1fd835558b4e70ad94a280a209f050ec0f7a75.tar.bz2
Version 0.98vdr-0.98
- Completed storing the current audio volume in the setup.conf file (thanks to Andy Grobb). - Fixed closing the progress display with the "Back" key when in trick mode and Setup.ShowReplayMode is enabled (thanks to Stefan Huelswitt). - New SVDRP commands LSTR and DELR to list and delete recordings (thanks to Thomas Heiligenmann). - Fixed a crash when pressing the '2' button while replaying a DVD. - Updated 'channels.conf' for the "Bundesliga" channels of Premiere World (thanks to Mel Schächner). - Changed the tuning code to use FrontendInfo to detect the type of DVB card. - Removed the recursion stuff from cThread (cMutex already does this). - Fixed handling the repeat function in the channel display. - Avoiding multiple EPG entries for the same event (thanks to Rolf Hakenes for some valuable information on how to do this). - A recording on the primary interface can now be stopped to make it continue on an other free DVB card (if one is free at the moment). See MANUAL for details. - Added some missing teletext PIDs (thanks to Norbert Schmidt). - Added PTS to the converted PCM audio when replaying a DVD (thanks to Andreas Schultz). Now the audio and video of a DVD replayed over the DVB card's A/V out should always be in sync. - Fixed handling the "Power" key in case Setup.MinUserInactivity is set to 0 to disable automatic shutdown. - Added a fifth parameter to the 'shutdown' call that indicates the reason for this shutdown request (see INSTALL). - Fixed releasing 'index' memory after recording or playback. - Fixed ejecting a DVD while it is being replayed. - Removed all video overlay stuff from cDvbApi and SVDRP. Guido Fiala's new 'kvdr' version 0.4 now does these things itself. As a consequence of this you will now need to use kvdr 0.4 or later. - The device /dev/video is now opened only if necessary (to GRAB an image), allowing other programs (like 'kvdr', for instance) to use that device.
Diffstat (limited to 'dvbapi.c')
-rw-r--r--dvbapi.c941
1 files changed, 412 insertions, 529 deletions
diff --git a/dvbapi.c b/dvbapi.c
index 786dff7..f72782b 100644
--- a/dvbapi.c
+++ b/dvbapi.c
@@ -7,7 +7,7 @@
* DVD support initially written by Andreas Schultz <aschultz@warp10.net>
* based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si>
*
- * $Id: dvbapi.c 1.132 2001/10/21 13:36:27 kls Exp $
+ * $Id: dvbapi.c 1.137 2001/11/04 12:05:36 kls Exp $
*/
//#define DVDDEBUG 1
@@ -200,6 +200,7 @@ cIndexFile::~cIndexFile()
if (f >= 0)
close(f);
delete fileName;
+ delete index;
}
bool cIndexFile::CatchUp(int Index)
@@ -713,7 +714,10 @@ protected:
void TrickSpeed(int Increment);
virtual void Empty(bool Block = false);
virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00) {}
+ virtual void PlayExternalDolby(const uchar *b, int MaxLength);
virtual void Output(void);
+ void putFrame(cFrame *Frame);
+ void putFrame(unsigned char *Data, int Length, eFrameType Type = ftUnknown);
public:
cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev);
virtual ~cPlayBuffer();
@@ -759,6 +763,28 @@ cPlayBuffer::~cPlayBuffer()
{
}
+void cPlayBuffer::PlayExternalDolby(const uchar *b, int MaxLength)
+{
+ if (dolbyDev) {
+ if (b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01) {
+ if (b[3] == 0xBD) { // dolby
+ int l = b[4] * 256 + b[5] + 6;
+ int written = b[8] + 9; // skips the PES header
+ int n = min(l - written, MaxLength);
+ while (n > 0) {
+ int w = fwrite(&b[written], 1, n, dolbyDev);
+ if (w < 0) {
+ LOG_ERROR;
+ break;
+ }
+ n -= w;
+ written += w;
+ }
+ }
+ }
+ }
+}
+
void cPlayBuffer::Output(void)
{
dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid());
@@ -771,24 +797,28 @@ void cPlayBuffer::Output(void)
}
const cFrame *frame = Get();
if (frame) {
- StripAudioPackets((uchar *)frame->Data(), frame->Count(), (playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX
- const uchar *p = frame->Data();
- int r = frame->Count();
- while (r > 0 && Busy() && !blockOutput) {
- cFile::FileReadyForWriting(videoDev, 100);
- int w = write(videoDev, p, r);
- if (w > 0) {
- p += w;
- r -= w;
- }
- else if (w < 0 && FATALERRNO) {
- LOG_ERROR;
- Stop();
- return;
+ if (frame->Type() == ftDolby)
+ PlayExternalDolby(frame->Data(), frame->Count());
+ else {
+ StripAudioPackets((uchar *)frame->Data(), frame->Count(), (playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX
+ const uchar *p = frame->Data();
+ int r = frame->Count();
+ while (r > 0 && Busy() && !blockOutput) {
+ cFile::FileReadyForWriting(videoDev, 100);
+ int w = write(videoDev, p, r);
+ if (w > 0) {
+ p += w;
+ r -= w;
+ }
+ else if (w < 0 && FATALERRNO) {
+ LOG_ERROR;
+ Stop();
+ return;
+ }
}
- }
- writeIndex = frame->Index();
- backTrace.Add(frame->Index(), frame->Count());
+ writeIndex = frame->Index();
+ backTrace.Add(frame->Index(), frame->Count());
+ }
Drop(frame);
}
}
@@ -796,6 +826,20 @@ void cPlayBuffer::Output(void)
dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid());
}
+void cPlayBuffer::putFrame(cFrame *Frame)
+{
+ while (Busy() && !blockInput) {
+ if (Put(Frame))
+ return;
+ }
+ delete Frame; // caller relies on frame being put, otherwise this would be a memory leak!
+}
+
+void cPlayBuffer::putFrame(unsigned char *Data, int Length, eFrameType Type)
+{
+ putFrame(new cFrame(Data, Length, Type));
+}
+
void cPlayBuffer::TrickSpeed(int Increment)
{
int nts = trickSpeed + Increment;
@@ -1089,11 +1133,8 @@ void cReplayBuffer::Input(void)
}
else // allows replay even if the index file is missing
r = read(replayFile, b, sizeof(b));
- if (r > 0) {
- cFrame *frame = new cFrame(b, r, readIndex);
- while (Busy() && !blockInput && !Put(frame))
- ;
- }
+ if (r > 0)
+ putFrame(new cFrame(b, r, ftUnknown, readIndex));
else if (r == 0)
eof = true;
else if (r < 0 && FATALERRNO) {
@@ -1117,19 +1158,8 @@ void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except)
int l = b[i + 4] * 256 + b[i + 5] + 6;
switch (c) {
case 0xBD: // dolby
- if (Except && dolbyDev) {
- int written = b[i + 8] + 9; // skips the PES header
- int n = l - written;
- while (n > 0) {
- int w = fwrite(&b[i + written], 1, n, dolbyDev);
- if (w < 0) {
- LOG_ERROR;
- break;
- }
- n -= w;
- written += w;
- }
- }
+ if (Except && dolbyDev)
+ PlayExternalDolby(&b[i], Length - i);
// continue with deleting the data - otherwise it disturbs DVB replay
case 0xC0 ... 0xC1: // audio
if (c == 0xC1)
@@ -1290,10 +1320,166 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)
}
#ifdef DVDSUPPORT
+
+#define SYSTEM_HEADER 0xBB
+#define PROG_STREAM_MAP 0xBC
+#ifndef PRIVATE_STREAM1
+#define PRIVATE_STREAM1 0xBD
+#endif
+#define PADDING_STREAM 0xBE
+#ifndef PRIVATE_STREAM2
+#define PRIVATE_STREAM2 0xBF
+#endif
+#define AUDIO_STREAM_S 0xC0
+#define AUDIO_STREAM_E 0xDF
+#define VIDEO_STREAM_S 0xE0
+#define VIDEO_STREAM_E 0xEF
+#define ECM_STREAM 0xF0
+#define EMM_STREAM 0xF1
+#define DSM_CC_STREAM 0xF2
+#define ISO13522_STREAM 0xF3
+#define PROG_STREAM_DIR 0xFF
+
+#define cOPENDVD 0
+#define cOPENTITLE 1
+#define cOPENCHAPTER 2
+#define cOUTCELL 3
+#define cREADFRAME 4
+#define cOUTPACK 5
+#define cOUTFRAMES 6
+
+#define aAC3 0x80
+#define aLPCM 0xA0
+
+// --- cAC3toPCM -------------------------------------------------------------
+
+class cAC3toPCM {
+private:
+ enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat;
+ uchar *ac3data;
+ int ac3inp;
+ int ac3outp;
+public:
+ cAC3toPCM(void);
+ ~cAC3toPCM();
+ void Clear(void);
+ void Put(unsigned char *sector, int length);
+ cFrame *Get(int size, uchar PTSflags = 0, uchar *PTSdata = 0);
+ };
+
+cAC3toPCM::cAC3toPCM(void)
+{
+ ac3dec_init();
+ ac3data = new uchar[AC3_BUFFER_SIZE];
+ Clear();
+}
+
+cAC3toPCM::~cAC3toPCM()
+{
+ delete ac3data;
+}
+
+void cAC3toPCM::Clear(void)
+{
+ ac3stat = AC3_START;
+ ac3outp = ac3inp = 0;
+}
+
+void cAC3toPCM::Put(unsigned char *sector, int length)
+{
+ ac3dec_decode_data(sector, sector + length, ac3stat == AC3_START, &ac3inp, &ac3outp, (char *)ac3data);
+ ac3stat = AC3_PLAY;
+}
+
+// data=PCM samples, 16 bit, LSB first, 48kHz, stereo
+cFrame *cAC3toPCM::Get(int size, uchar PTSflags, uchar *PTSdata)
+{
+ if (ac3inp == ac3outp)
+ return NULL;
+
+#define MAXSIZE 2022
+
+ uchar buffer[2048];
+ uchar *data;
+
+ if (size > 0) {
+ int p_size = (size > MAXSIZE) ? MAXSIZE : size;
+ int length = 10; // default header bytes
+ int header = 0;
+ int stuffb = 0;
+
+ switch (PTSflags) {
+ case 2: header = 5; // additional header bytes
+ stuffb = 1;
+ break;
+ case 3: header = 10;
+ break;
+ default: header = 0;
+ }
+
+ // header = 0; //XXX ???
+ stuffb = 0; //XXX ???
+
+ length += header;
+ length += stuffb;
+
+ buffer[0] = 0x00;
+ buffer[1] = 0x00;
+ buffer[2] = 0x01;
+ buffer[3] = PRIVATE_STREAM1;
+
+ buffer[6] = 0x80;
+ buffer[7] = PTSflags << 6;
+ buffer[8] = header + stuffb;
+
+ if (header)
+ memcpy(&buffer[9], (void *)PTSdata, header);
+
+ // add stuffing
+ data = buffer + 9 + header;
+ for (int cnt = 0; cnt < stuffb; cnt++)
+ data[cnt] = 0xff;
+ length += stuffb;
+
+ // add data
+ data = buffer + 9 + header + stuffb + 7;
+ int cnt = 0;
+ while (p_size) {
+ if (ac3outp != ac3inp) { // data in the buffer
+ data[cnt ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder (the "xor" (^) is a swab!)
+ p_size--;
+ cnt++;
+ length++;
+ ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE;
+ }
+ else
+ break;
+ }
+
+ data = buffer + 9 + header + stuffb;
+ data[0] = aLPCM; // substream ID
+ data[1] = 0x00; // other stuff (see DVB specs), ignored by driver
+ data[2] = 0x00;
+ data[3] = 0x00;
+ data[4] = 0x00;
+ data[5] = 0x00;
+ data[6] = 0x00;
+
+ buffer[4] = (length >> 8) & 0xff;
+ buffer[5] = length & 0xff;
+
+ length += 6;
+
+ return new cFrame(buffer, length);
+ }
+ return NULL;
+}
+
// --- cDVDplayBuffer --------------------------------------------------------
class cDVDplayBuffer : public cPlayBuffer {
private:
+ cAC3toPCM AC3toPCM;
uchar audioTrack;
cDVD *dvd;//XXX necessary???
@@ -1308,7 +1494,6 @@ private:
int doplay;
int cyclestate;
int prevcycle;
- int brakeCounter;
int skipCnt;
tt_srpt_t *tt_srpt;
@@ -1335,11 +1520,6 @@ private:
int logAudioTrack;
int maxAudioTrack;
- enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat;
- uchar *ac3data;
- int ac3inp;
- int ac3outp;
- int lpcm_count;
int is_nav_pack(unsigned char *buffer);
void Close(void);
virtual void Empty(bool Block = false);
@@ -1350,10 +1530,7 @@ private:
int GetStuffingLen(const uchar *Data);
int GetPacketLength(const uchar *Data);
int GetPESHeaderLength(const uchar *Data);
- int SendPCM(int size);
- void playDecodedAC3(void);
- void handleAC3(unsigned char *sector, int length);
- void putFrame(unsigned char *sector, int length);
+ void handleAC3(unsigned char *sector, int length, uchar PTSflags, uchar *PTSdata);
unsigned int getAudioStream(unsigned int StreamId);
void setChapid(void);
void NextState(int State) { prevcycle = cyclestate; cyclestate = State; }
@@ -1369,17 +1546,6 @@ public:
virtual void ToggleAudioTrack(void);
};
-#define cOPENDVD 0
-#define cOPENTITLE 1
-#define cOPENCHAPTER 2
-#define cOUTCELL 3
-#define cREADFRAME 4
-#define cOUTPACK 5
-#define cOUTFRAMES 6
-
-#define aAC3 0x80
-#define aLPCM 0xA0
-
cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title)
:cPlayBuffer(DvbApi, VideoDev, AudioDev)
{
@@ -1389,15 +1555,10 @@ cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD
angle = 0;
cyclestate = cOPENDVD;
prevcycle = 0;
- brakeCounter = 0;
skipCnt = 0;
logAudioTrack = 0;
canToggleAudioTrack = true;//XXX determine from cDVD!
- ac3dec_init();
data = new uchar[1024 * DVD_VIDEO_LB_LEN];
- ac3data = new uchar[AC3_BUFFER_SIZE];
- ac3inp = ac3outp = 0;
- ac3stat = AC3_START;
canDoTrickMode = true;
dvbApi->SetModeReplay();
Start();
@@ -1408,7 +1569,6 @@ cDVDplayBuffer::~cDVDplayBuffer()
Stop();
Close();
dvbApi->SetModeNormal(false);
- delete ac3data;
delete data;
}
@@ -1449,8 +1609,7 @@ void cDVDplayBuffer::ToggleAudioTrack(void)
#ifdef DVDDEBUG
dsyslog(LOG_INFO, "DVB: Audio Stream ID changed to: %x", audioTrack);
#endif
- ac3stat = AC3_START;
- ac3outp = ac3inp;
+ AC3toPCM.Clear();
}
}
@@ -1869,141 +2028,21 @@ int cDVDplayBuffer::ScanVideoPacket(const uchar *Data, int Count, uchar *Picture
return -1;
}
-#define SYSTEM_HEADER 0xBB
-#define PROG_STREAM_MAP 0xBC
-#ifndef PRIVATE_STREAM1
-#define PRIVATE_STREAM1 0xBD
-#endif
-#define PADDING_STREAM 0xBE
-#ifndef PRIVATE_STREAM2
-#define PRIVATE_STREAM2 0xBF
-#endif
-#define AUDIO_STREAM_S 0xC0
-#define AUDIO_STREAM_E 0xDF
-#define VIDEO_STREAM_S 0xE0
-#define VIDEO_STREAM_E 0xEF
-#define ECM_STREAM 0xF0
-#define EMM_STREAM 0xF1
-#define DSM_CC_STREAM 0xF2
-#define ISO13522_STREAM 0xF3
-#define PROG_STREAM_DIR 0xFF
-
-// data=PCM samples, 16 bit, LSB first, 48kHz, stereo
-int cDVDplayBuffer::SendPCM(int size)
-{
-
-#define MAXSIZE 2032
-
- uchar buffer[MAXSIZE + 16];
- int length = 0;
- int p_size;
-
- if (ac3inp == ac3outp)
- return 1;
-
- while (size > 0) {
- if (size >= MAXSIZE)
- p_size = MAXSIZE;
- else
- p_size = size;
- length = 10;
-
- while (p_size) {
- if (ac3outp != ac3inp) { // data in the buffer
- buffer[(length + 6) ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder
- // XXX there is no 'swab' here??? (kls)
- p_size--;
- length++;
- ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE;
- }
- else
- break;
- }
-
- buffer[0] = 0x00;
- buffer[1] = 0x00;
- buffer[2] = 0x01;
- buffer[3] = PRIVATE_STREAM1;
-
- buffer[4] = (length >> 8) & 0xff;
- buffer[5] = length & 0xff;
-
- buffer[6] = 0x80;
- buffer[7] = 0x00;
- buffer[8] = 0x00;
-
- buffer[9] = aLPCM; // substream ID
- buffer[10] = 0x00; // other stuff (see DVD specs), ignored by driver
- buffer[11] = 0x00;
- buffer[12] = 0x00;
- buffer[13] = 0x00;
- buffer[14] = 0x00;
- buffer[15] = 0x00;
-
- length += 6;
-
- putFrame(buffer, length);
- size -= MAXSIZE;
- }
- return 0;
-}
-
-void cDVDplayBuffer::playDecodedAC3(void)
+void cDVDplayBuffer::handleAC3(unsigned char *sector, int length, uchar PTSflags, uchar *PTSdata)
{
- int ac3_datasize = (AC3_BUFFER_SIZE + ac3inp - ac3outp) % AC3_BUFFER_SIZE;
-
- if (ac3_datasize) {
- if (ac3_datasize > 1024 * 48)
- SendPCM(3096);
- else if (ac3_datasize > 1024 * 32)
- SendPCM(1536);
- else if (ac3_datasize > 1024 * 16 && !(lpcm_count % 2))
- SendPCM(1536);
- else if (ac3_datasize && !(lpcm_count % 4))
- SendPCM(1536);
- lpcm_count++;
- }
- else
- lpcm_count=0;
-}
-
-void cDVDplayBuffer::handleAC3(unsigned char *sector, int length)
-{
- if (dolbyDev) {
- while (length > 0) {
- int w = fwrite(sector, 1, length , dolbyDev);
- if (w < 0) {
- LOG_ERROR;
- break;
- }
- length -= w;
- sector += w;
- }
- }
- else {
- if (ac3stat == AC3_PLAY)
- ac3dec_decode_data(sector, sector + length, 0, &ac3inp, &ac3outp, (char *)ac3data);
- else if (ac3stat == AC3_START) {
- ac3dec_decode_data(sector, sector + length, 1, &ac3inp, &ac3outp, (char *)ac3data);
- ac3stat = AC3_PLAY;
- }
- }
- //playDecodedAC3();
-}
-
-void cDVDplayBuffer::putFrame(unsigned char *sector, int length)
-{
- cFrame *frame = new cFrame(sector, length);
- while (Busy() && !blockInput && !Put(frame))
- ;
+#define PCM_FRAME_SIZE 1536
+ AC3toPCM.Put(sector, length);
+ cFrame *frame;
+ if ((frame = AC3toPCM.Get(PCM_FRAME_SIZE, PTSflags, PTSdata)) != NULL)
+ putFrame(frame);
+ while ((frame = AC3toPCM.Get(PCM_FRAME_SIZE)) != NULL)
+ putFrame(frame);
}
int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
{
+ //XXX kls 2001-11-03: do we really need all these different return values?
uchar pt = 1;
-#if 0
- uchar *osect = sector;
-#endif
//make sure we got a PS packet header
if (!PacketStart(&sector, DVD_VIDEO_LB_LEN) && GetPacketType(sector) != 0xBA) {
@@ -2017,6 +2056,8 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
int datalen = r;
sector[6] &= 0x8f;
+ uchar PTSflags = sector[7] >> 6;
+ uchar *PTSdata = sector + 9;
uchar *data = sector;
switch (GetPacketType(sector)) {
@@ -2025,6 +2066,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
ScanVideoPacket(sector, r, &pt);
if (trickMode && pt != 1)
return pt;
+ putFrame(sector, r, ftVideo);
break;
}
case AUDIO_STREAM_S ... AUDIO_STREAM_E: {
@@ -2033,6 +2075,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
return 1;
if (audioTrack != GetPacketType(sector))
return 5;
+ putFrame(sector, r, ftAudio);
break;
}
case PRIVATE_STREAM1:
@@ -2060,14 +2103,15 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
if (audioTrack == *data) {
switch (audioTrack & 0xF8) {
case aAC3:
+ if (dolbyDev)
+ putFrame(sector, r, ftDolby);
data += 4;
- // correct a3 data lenght - FIXME: why 13 ???
- datalen -= 13;
- handleAC3(data, datalen);
+ datalen -= 13; // 3 (mandatory header) + 6 (PS header) + 4 (AC3 header) = 13
+ handleAC3(data, datalen, PTSflags, PTSdata);
break;
case aLPCM:
// write(audio, sector+14 , sector[19]+(sector[18]<<8)+6);
- putFrame(sector, GetPacketLength(sector));
+ putFrame(sector, GetPacketLength(sector), ftAudio);
break;
default:
break;
@@ -2096,9 +2140,6 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, bool trickMode)
return pt;
}
}
- putFrame(sector, r);
- if ((audioTrack & 0xF8) == aAC3)
- playDecodedAC3();
return pt;
}
@@ -2106,8 +2147,7 @@ void cDVDplayBuffer::Empty(bool Block)
{
if (!(blockInput || blockOutput)) {
cPlayBuffer::Empty(true);
- ac3stat = AC3_START;
- ac3outp = ac3inp;
+ AC3toPCM.Clear();
}
if (!Block)
cPlayBuffer::Empty(false);
@@ -2149,9 +2189,7 @@ void cDVDplayBuffer::SkipSeconds(int Seconds)
Empty(true);
chapid = newchapid;
NextState(cOPENCHAPTER);
- if (ac3stat != AC3_STOP)
- ac3stat = AC3_START;
- ac3outp = ac3inp;
+ AC3toPCM.Clear();
Empty(false);
Play();
}
@@ -2488,6 +2526,7 @@ char *cDvbApi::audioCommand = NULL;
cDvbApi::cDvbApi(int n)
{
+ frontendType = FrontendType(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
vPid = aPid1 = aPid2 = dPid1 = dPid2 = 0;
siProcessor = NULL;
recordBuffer = NULL;
@@ -2518,10 +2557,6 @@ cDvbApi::cDvbApi(int n)
fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK);
fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK);
- // Devices that may not be available, and are not necessary for normal operation:
-
- videoDev = OstOpen(DEV_VIDEO, n, O_RDWR);
-
// Devices that will be dynamically opened and closed when necessary:
fd_dvr = -1;
@@ -2536,15 +2571,14 @@ cDvbApi::cDvbApi(int n)
siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n));
if (!dvbApi[0]) // only the first one shall set the system time
siProcessor->SetUseTSTime(Setup.SetSystemTime);
+ FrontendInfo feinfo;
+ CHECK(ioctl(fd_frontend, FE_GET_INFO, &feinfo));
+ frontendType = feinfo.type;
}
else
esyslog(LOG_ERR, "ERROR: can't open video device %d", n);
cols = rows = 0;
- ovlGeoSet = ovlStat = ovlFbSet = false;
- ovlBrightness = ovlColour = ovlHue = ovlContrast = 32768;
- ovlClipCount = 0;
-
#if defined(DEBUG_OSD) || defined(REMOTE_KBD)
initscr();
keypad(stdscr, true);
@@ -2573,7 +2607,6 @@ cDvbApi::~cDvbApi()
StopReplay();
StopRecord();
StopTransfer();
- OvlO(false); //Overlay off!
// We're not explicitly closing any device files here, since this sometimes
// caused segfaults. Besides, the program is about to terminate anyway...
#if defined(DEBUG_OSD) || defined(REMOTE_KBD)
@@ -2688,255 +2721,96 @@ const cSchedules *cDvbApi::Schedules(cThreadLock *ThreadLock) const
bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
{
- if (videoDev < 0)
- return false;
int result = 0;
- // just do this once?
- struct video_mbuf mbuf;
- result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf);
- int msize = mbuf.size;
- // gf: this needs to be a protected member of cDvbApi! //XXX kls: WHY???
- unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
- if (!mem || mem == (unsigned char *)-1)
- return false;
- // set up the size and RGB
- struct video_capability vc;
- result |= ioctl(videoDev, VIDIOCGCAP, &vc);
- struct video_mmap vm;
- vm.frame = 0;
- if ((SizeX > 0) && (SizeX <= vc.maxwidth) &&
- (SizeY > 0) && (SizeY <= vc.maxheight)) {
- vm.width = SizeX;
- vm.height = SizeY;
- }
- else {
- vm.width = vc.maxwidth;
- vm.height = vc.maxheight;
- }
- vm.format = VIDEO_PALETTE_RGB24;
- // this needs to be done every time:
- result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm);
- result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame);
- // make RGB out of BGR:
- int memsize = vm.width * vm.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 = 255; //XXX is this 'best'???
-
- isyslog(LOG_INFO, "grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
- FILE *f = fopen(FileName, "wb");
- if (f) {
- if (Jpeg) {
- // write JPEG file:
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_compress(&cinfo);
- jpeg_stdio_dest(&cinfo, f);
- cinfo.image_width = vm.width;
- cinfo.image_height = vm.height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
-
- jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo, Quality, true);
- jpeg_start_compress(&cinfo, true);
-
- int rs = vm.width * 3;
- JSAMPROW rp[vm.height];
- for (int k = 0; k < vm.height; k++)
- rp[k] = &mem[rs * k];
- jpeg_write_scanlines(&cinfo, rp, vm.height);
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
- }
- else {
- // write PNM file:
- if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 ||
- fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) {
- LOG_ERROR_STR(FileName);
- result |= 1;
+ int videoDev = OstOpen(DEV_VIDEO, CardIndex(), O_RDWR);
+ if (videoDev >= 0) {
+ struct video_mbuf mbuf;
+ result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf);
+ if (result == 0) {
+ int msize = mbuf.size;
+ unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
+ if (mem && mem != (unsigned char *)-1) {
+ // set up the size and RGB
+ struct video_capability vc;
+ result |= ioctl(videoDev, VIDIOCGCAP, &vc);
+ struct video_mmap vm;
+ vm.frame = 0;
+ if ((SizeX > 0) && (SizeX <= vc.maxwidth) &&
+ (SizeY > 0) && (SizeY <= vc.maxheight)) {
+ vm.width = SizeX;
+ vm.height = SizeY;
+ }
+ else {
+ vm.width = vc.maxwidth;
+ vm.height = vc.maxheight;
+ }
+ vm.format = VIDEO_PALETTE_RGB24;
+ result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm);
+ result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame);
+ // make RGB out of BGR:
+ int memsize = vm.width * vm.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 = 255; //XXX is this 'best'???
+
+ isyslog(LOG_INFO, "grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
+ FILE *f = fopen(FileName, "wb");
+ if (f) {
+ if (Jpeg) {
+ // write JPEG file:
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+ jpeg_stdio_dest(&cinfo, f);
+ cinfo.image_width = vm.width;
+ cinfo.image_height = vm.height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, Quality, true);
+ jpeg_start_compress(&cinfo, true);
+
+ int rs = vm.width * 3;
+ JSAMPROW rp[vm.height];
+ for (int k = 0; k < vm.height; k++)
+ rp[k] = &mem[rs * k];
+ jpeg_write_scanlines(&cinfo, rp, vm.height);
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ }
+ else {
+ // write PNM file:
+ if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 ||
+ fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) {
+ LOG_ERROR_STR(FileName);
+ result |= 1;
+ }
+ }
+ fclose(f);
+ }
+ else {
+ LOG_ERROR_STR(FileName);
+ result |= 1;
+ }
+ munmap(mem, msize);
}
+ else
+ result |= 1;
}
- fclose(f);
- }
- else {
- LOG_ERROR_STR(FileName);
- result |= 1;
- }
-
- if (ovlStat && ovlGeoSet) {
- // switch the Overlay on again (gf: why have i to do anything again?)
- OvlG(ovlSizeX, ovlSizeY, ovlPosX, ovlPosY);
- }
- if (ovlFbSet)
- OvlP(ovlBrightness, ovlColour, ovlHue, ovlContrast);
-
- munmap(mem, msize);
- return result == 0;
-}
-
-bool cDvbApi::OvlF(int SizeX, int SizeY, int FbAddr, int Bpp, int Palette)
-{
- if (videoDev < 0)
- return false;
- int result = 0;
- // get the actual X-Server settings???
- // plausibility-check problem: can't be verified w/o X-server!!!
- if (SizeX <= 0 || SizeY <= 0 || FbAddr == 0 || Bpp / 8 > 4 ||
- Bpp / 8 <= 0 || Palette <= 0 || Palette > 13 || ovlClipCount < 0 ||
- SizeX > 4096 || SizeY > 4096) {
- ovlFbSet = ovlGeoSet = false;
- OvlO(false);
- return false;
- }
- else {
- dsyslog(LOG_INFO, "OvlF: %d %d %x %d %d", SizeX, SizeY, FbAddr, Bpp, Palette);
- // this is the problematic part!
- struct video_buffer vb;
- result |= ioctl(videoDev, VIDIOCGFBUF, &vb);
- vb.base = (void*)FbAddr;
- vb.depth = Bpp;
- vb.height = SizeY;
- vb.width = SizeX;
- vb.bytesperline = ((vb.depth + 1) / 8) * vb.width;
- //now the real thing: setting the framebuffer
- result |= ioctl(videoDev, VIDIOCSFBUF, &vb);
- if (result) {
- ovlFbSet = ovlGeoSet = false;
- ovlClipCount = 0;
- OvlO(false);
- return false;
- }
- else {
- ovlFbSizeX = SizeX;
- ovlFbSizeY = SizeY;
- ovlBpp = Bpp;
- ovlPalette = Palette;
- ovlFbSet = true;
- return true;
- }
- }
-}
-
-bool cDvbApi::OvlG(int SizeX, int SizeY, int PosX, int PosY)
-{
- if (videoDev < 0)
- return false;
- int result = 0;
- // get the actual X-Server settings???
- struct video_capability vc;
- result |= ioctl(videoDev, VIDIOCGCAP, &vc);
- if (!ovlFbSet)
- return false;
- if (SizeX < vc.minwidth || SizeY < vc.minheight ||
- SizeX > vc.maxwidth || SizeY>vc.maxheight
-// || PosX > FbSizeX || PosY > FbSizeY
-// PosX < -SizeX || PosY < -SizeY ||
- ) {
- ovlGeoSet = false;
- OvlO(false);
- return false;
- }
- else {
- struct video_window vw;
- result |= ioctl(videoDev, VIDIOCGWIN, &vw);
- vw.x = PosX;
- vw.y = PosY;
- vw.width = SizeX;
- vw.height = SizeY;
- vw.chromakey = ovlPalette;
-#ifndef VID_TYPE_CHROMAKEY // name changed somewhere down the road in kernel 2.4.x
-#define VID_TYPE_CHROMAKEY VIDEO_WINDOW_CHROMAKEY
-#endif
- vw.flags = VID_TYPE_CHROMAKEY; // VIDEO_WINDOW_INTERLACE; //VIDEO_CLIP_BITMAP;
- vw.clips = ovlClipRects;
- vw.clipcount = ovlClipCount;
- result |= ioctl(videoDev, VIDIOCSWIN, &vw);
- if (result) {
- ovlGeoSet = false;
- ovlClipCount = 0;
- return false;
- }
- else {
- ovlSizeX = SizeX;
- ovlSizeY = SizeY;
- ovlPosX = PosX;
- ovlPosY = PosY;
- ovlGeoSet = true;
- ovlStat = true;
- return true;
- }
+ close(videoDev);
}
-}
-
-bool cDvbApi::OvlC(int ClipCount, CRect *cr)
-{
- if (videoDev < 0)
- return false;
- if (ovlGeoSet && ovlFbSet) {
- for (int i = 0; i < ClipCount; i++) {
- ovlClipRects[i].x = cr[i].x;
- ovlClipRects[i].y = cr[i].y;
- ovlClipRects[i].width = cr[i].width;
- ovlClipRects[i].height = cr[i].height;
- ovlClipRects[i].next = &(ovlClipRects[i + 1]);
- }
- ovlClipCount = ClipCount;
- //use it:
- return OvlG(ovlSizeX, ovlSizeY, ovlPosX, ovlPosY);
- }
- return false;
-}
-
-bool cDvbApi::OvlP(__u16 Brightness, __u16 Colour, __u16 Hue, __u16 Contrast)
-{
- if (videoDev < 0)
- return false;
- int result = 0;
- ovlBrightness = Brightness;
- ovlColour = Colour;
- ovlHue = Hue;
- ovlContrast = Contrast;
- struct video_picture vp;
- if (!ovlFbSet)
- return false;
- result |= ioctl(videoDev, VIDIOCGPICT, &vp);
- vp.brightness = Brightness;
- vp.colour = Colour;
- vp.hue = Hue;
- vp.contrast = Contrast;
- vp.depth = ovlBpp;
- vp.palette = ovlPalette; // gf: is this always ok? VIDEO_PALETTE_RGB565;
- result |= ioctl(videoDev, VIDIOCSPICT, &vp);
return result == 0;
}
-bool cDvbApi::OvlO(bool Value)
-{
- if (videoDev < 0)
- return false;
- int result = 0;
- if (!ovlGeoSet && Value)
- return false;
- int one = 1;
- int zero = 0;
- result |= ioctl(videoDev, VIDIOCCAPTURE, Value ? &one : &zero);
- ovlStat = Value;
- if (result) {
- ovlStat = false;
- return false;
- }
- return true;
-}
-
#ifdef DEBUG_OSD
void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg)
{
@@ -3257,97 +3131,106 @@ eSetChannelResult cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char
bool ChannelSynced = false;
- if (fd_sec >= 0) { // DVB-S
+ switch (frontendType) {
+ case FE_QPSK: { // DVB-S
- // Frequency offsets:
+ // Frequency offsets:
- unsigned int freq = FrequencyMHz;
- int tone = SEC_TONE_OFF;
+ unsigned int freq = FrequencyMHz;
+ int tone = SEC_TONE_OFF;
- if (freq < (unsigned int)Setup.LnbSLOF) {
- freq -= Setup.LnbFrequLo;
- tone = SEC_TONE_OFF;
- }
- else {
- freq -= Setup.LnbFrequHi;
- tone = SEC_TONE_ON;
- }
+ if (freq < (unsigned int)Setup.LnbSLOF) {
+ freq -= Setup.LnbFrequLo;
+ tone = SEC_TONE_OFF;
+ }
+ else {
+ freq -= Setup.LnbFrequHi;
+ tone = SEC_TONE_ON;
+ }
- FrontendParameters Frontend;
- Frontend.Frequency = freq * 1000UL;
- Frontend.Inversion = INVERSION_AUTO;
- Frontend.u.qpsk.SymbolRate = Srate * 1000UL;
- Frontend.u.qpsk.FEC_inner = FEC_AUTO;
+ FrontendParameters Frontend;
+ Frontend.Frequency = freq * 1000UL;
+ Frontend.Inversion = INVERSION_AUTO;
+ Frontend.u.qpsk.SymbolRate = Srate * 1000UL;
+ Frontend.u.qpsk.FEC_inner = FEC_AUTO;
- int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
+ int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
- // DiseqC:
+ // DiseqC:
- secCommand scmd;
- scmd.type = 0;
- scmd.u.diseqc.addr = 0x10;
- scmd.u.diseqc.cmd = 0x38;
- scmd.u.diseqc.numParams = 1;
- scmd.u.diseqc.params[0] = 0xF0 | ((Diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0);
+ secCommand scmd;
+ scmd.type = 0;
+ scmd.u.diseqc.addr = 0x10;
+ scmd.u.diseqc.cmd = 0x38;
+ scmd.u.diseqc.numParams = 1;
+ scmd.u.diseqc.params[0] = 0xF0 | ((Diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0);
- secCmdSequence scmds;
- scmds.voltage = volt;
- scmds.miniCommand = SEC_MINI_NONE;
- scmds.continuousTone = tone;
- scmds.numCommands = Setup.DiSEqC ? 1 : 0;
- scmds.commands = &scmd;
+ secCmdSequence scmds;
+ scmds.voltage = volt;
+ scmds.miniCommand = SEC_MINI_NONE;
+ scmds.continuousTone = tone;
+ scmds.numCommands = Setup.DiSEqC ? 1 : 0;
+ scmds.commands = &scmd;
- CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds));
+ CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds));
- // Tuning:
+ // Tuning:
- CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
+ CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
- // Wait for channel sync:
+ // Wait for channel sync:
- if (cFile::FileReady(fd_frontend, 5000)) {
- FrontendEvent event;
- int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
- if (res >= 0)
- ChannelSynced = event.type == FE_COMPLETION_EV;
- else
- esyslog(LOG_ERR, "ERROR %d in frontend get event", res);
- }
- else
- esyslog(LOG_ERR, "ERROR: timeout while tuning");
- }
- else if (fd_frontend >= 0) { // DVB-C
+ if (cFile::FileReady(fd_frontend, 5000)) {
+ FrontendEvent event;
+ int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
+ if (res >= 0)
+ ChannelSynced = event.type == FE_COMPLETION_EV;
+ else
+ esyslog(LOG_ERR, "ERROR %d in frontend get event", res);
+ }
+ else
+ esyslog(LOG_ERR, "ERROR: timeout while tuning");
+ }
+ break;
+ case FE_QAM: { // DVB-C
- // Frequency and symbol rate:
+ // Frequency and symbol rate:
- FrontendParameters Frontend;
- Frontend.Frequency = FrequencyMHz * 1000000UL;
- Frontend.Inversion = INVERSION_AUTO;
- Frontend.u.qam.SymbolRate = Srate * 1000UL;
- Frontend.u.qam.FEC_inner = FEC_AUTO;
- Frontend.u.qam.QAM = QAM_64;
+ FrontendParameters Frontend;
+ Frontend.Frequency = FrequencyMHz * 1000000UL;
+ Frontend.Inversion = INVERSION_AUTO;
+ Frontend.u.qam.SymbolRate = Srate * 1000UL;
+ Frontend.u.qam.FEC_inner = FEC_AUTO;
+ Frontend.u.qam.QAM = QAM_64;
- // Tuning:
+ // Tuning:
- CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
+ CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
- // Wait for channel sync:
+ // Wait for channel sync:
- if (cFile::FileReady(fd_frontend, 5000)) {
- FrontendEvent event;
- int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
- if (res >= 0)
- ChannelSynced = event.type == FE_COMPLETION_EV;
- else
- esyslog(LOG_ERR, "ERROR %d in frontend get event", res);
- }
- else
- esyslog(LOG_ERR, "ERROR: timeout while tuning");
- }
- else {
- esyslog(LOG_ERR, "ERROR: attempt to set channel without DVB-S or DVB-C device");
- return scrFailed;
- }
+ if (cFile::FileReady(fd_frontend, 5000)) {
+ FrontendEvent event;
+ int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
+ if (res >= 0)
+ ChannelSynced = event.type == FE_COMPLETION_EV;
+ else
+ esyslog(LOG_ERR, "ERROR %d in frontend get event", res);
+ }
+ else
+ esyslog(LOG_ERR, "ERROR: timeout while tuning");
+ }
+ break;
+ case FE_OFDM: { // DVB-T
+ //XXX TODO: implement DVB-T tuning (anybody with a DVB-T card out there?)
+ esyslog(LOG_ERR, "ERROR: DVB-T tuning support not yet implemented");
+ return scrFailed;
+ }
+ break;
+ default:
+ esyslog(LOG_ERR, "ERROR: attempt to set channel with unknown DVB frontend type");
+ return scrFailed;
+ }
if (!ChannelSynced) {
esyslog(LOG_ERR, "ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1);