vdr/transfer.c
Klaus Schmidinger e36fe18c48 Version 1.3.19
- Making sure at least the default skin is available at program start in case a
  plugin needs to issue an error message (thanks to Achim Tuffentshammer for
  reporting a crash in such a case). Also checking if there is a current skin
  in cSkins::Message().
- Completed the Finnish OSD texts and fixed internationalization of the text
  for "Setup/DVB/Audio language(s)" (thanks to Rolf Ahrenberg).
- Completed the Estonian OSD texts and switched to iso8859-13 character set
  (thanks to Arthur Konovalov).
- Made cCondWait::SleepMs() sleep at least 3ms to avoid a possible busy wait.
- Fixed canceling the LIRC thread (thanks to Marco Schlüßler for pointing out
  this one).
- The "Green" button in the "Main" menu is now always "Audio", since the audio
  channel might be changed even if there is only one actual audio PID.
- Fixed handling the '-E' option which was broken in version 1.3.18 (thanks to
  Christian Jacobsen for reporting this one).
- Added 'channels.conf.terr' entries for Mainz (thanks to Michael Heyse).
- Implemented cDolbyRepacker for better handling of Dolby Digital PES packets
  (thanks to Reinhard Nissl).
- Fixed playing files with PES packets longer than 2048 byte through the full
  featured DVB card (thanks to Marco Kremer for reporting this one and providing
  a test sample).
- Recording and Transfer Mode now handle more than 2 audio PIDs. For this the
  interfaces of the following functions have been changed:
  cTransferControl::cTransferControl()
  cTransfer::cTransfer()
  cRecorder::cRecorder()
  cReceiver::cReceiver()
  cRemux::cRemux()
- Fixed a possible race condition in cDevice::Action() and cTSBuffer::Action()
  (thanks to Stefan Huelswitt).
- Extended some buffer sizes to allow handling HDTV streams (thanks to Reinhard
  Nissl).
- Added 'channels.conf.terr' entries for Düsseldorf and Köln (thanks to Walter Koch).
- Falling back to 'stereo' when switching channels in case the user had switched
  to 'left' or 'right' (suggested by Rolf Groppe).
- Completed the Danish OSD texts (thanks to Mogens Elneff).
- Recording and Transfer Mode can now handle up to 8 Dolby Digital tracks (thanks
  to Marco Schlüßler for a patch that implements substream handling into
  cDevice::PlayPesPacket(), and Reinhard Nissl for adding substream handling to
  cDolbyRepacker).
- Added PlayPes(NULL, 0) to cTransfer::Action() when clearing the transfer buffer
  to avoid overflows (thanks to Marco Schlüßler for pointing this out).
2005-01-23 18:00:00 +01:00

159 lines
4.8 KiB
C

/*
* transfer.c: Transfer mode
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: transfer.c 1.25 2005/01/23 14:27:40 kls Exp $
*/
#include "transfer.h"
#define TRANSFERBUFSIZE MEGABYTE(2)
#define POLLTIMEOUTS_BEFORE_DEVICECLEAR 3
// --- cTransfer -------------------------------------------------------------
cTransfer::cTransfer(int VPid, const int *APids, const int *DPids, const int *SPids)
:cReceiver(0, -1, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids)
,cThread("transfer")
{
ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer");
remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids);
needsBufferReserve = Setup.UseDolbyDigital && VPid != 0 && DPids && DPids[0] != 0;
active = false;
}
cTransfer::~cTransfer()
{
cReceiver::Detach();
cPlayer::Detach();
delete remux;
delete ringBuffer;
}
void cTransfer::Activate(bool On)
{
if (On) {
if (!active)
Start();
}
else if (active) {
active = false;
Cancel(3);
}
}
void cTransfer::Receive(uchar *Data, int Length)
{
if (IsAttached() && active) {
int p = ringBuffer->Put(Data, Length);
if (p != Length && active)
ringBuffer->ReportOverflow(Length - p);
return;
}
}
void cTransfer::Action(void)
{
int PollTimeouts = 0;
uchar *p = NULL;
int Result = 0;
#define FW_NEEDS_BUFFER_RESERVE_FOR_AC3
#ifdef FW_NEEDS_BUFFER_RESERVE_FOR_AC3
bool Cleared = false;
bool GotBufferReserve = false;
#endif
active = true;
while (active) {
#ifdef FW_NEEDS_BUFFER_RESERVE_FOR_AC3
if (needsBufferReserve) {
if (IsAttached() && !Cleared) {
PlayPes(NULL, 0);
Cleared = true;
}
//XXX For dolby we've to fill the buffer because the firmware does
//XXX not decode dolby but use a PCM stream for transport, therefore
//XXX the firmware has not enough buffer for noiseless skipping early
//XXX PCM samples (each dolby frame requires 6144 bytes in PCM and
//XXX audio is mostly to early in comparison to video).
//XXX To resolve this, the remuxer or PlayPes() should synchronize
//XXX audio with the video frames. 2004/09/09 Werner
if (!GotBufferReserve) {
if (ringBuffer->Available() < 3 * KILOBYTE(192) / 2) { // used to be MAXFRAMESIZE, but the HDTV value of KILOBYTE(512) is way too much here
cCondWait::SleepMs(20); // allow the buffer to collect some reserve
continue;
}
else
GotBufferReserve = true;
}
}
#endif
int Count;
uchar *b = ringBuffer->Get(Count);
if (b) {
if (ringBuffer->Available() > TRANSFERBUFSIZE * 9 / 10) {
// If the buffer runs full, we have no chance of ever catching up
// since the data comes in at the same rate as it goes out (it's "live").
// So let's clear the buffer instead of suffering from permanent
// overflows.
dsyslog("clearing transfer buffer to avoid overflows");
ringBuffer->Clear();
remux->Clear();
PlayPes(NULL, 0);
p = NULL;
continue;
}
Count = remux->Put(b, Count);
if (Count)
ringBuffer->Del(Count);
}
if (!p)
p = remux->Get(Result);
if (p) {
cPoller Poller;
if (DevicePoll(Poller, 100)) {
PollTimeouts = 0;
int w = PlayPes(p, Result);
if (w > 0) {
p += w;
Result -= w;
remux->Del(w);
if (Result <= 0)
p = NULL;
}
else if (w < 0 && FATALERRNO)
LOG_ERROR;
}
else {
PollTimeouts++;
if (PollTimeouts == POLLTIMEOUTS_BEFORE_DEVICECLEAR) {
dsyslog("clearing device because of consecutive poll timeouts");
DeviceClear();
ringBuffer->Clear();
remux->Clear();
p = NULL;
}
}
}
}
active = false;
}
// --- cTransferControl ------------------------------------------------------
cDevice *cTransferControl::receiverDevice = NULL;
cTransferControl::cTransferControl(cDevice *ReceiverDevice, int VPid, const int *APids, const int *DPids, const int *SPids)
:cControl(transfer = new cTransfer(VPid, APids, DPids, SPids), true)
{
ReceiverDevice->AttachReceiver(transfer);
receiverDevice = ReceiverDevice;
}
cTransferControl::~cTransferControl()
{
receiverDevice = NULL;
delete transfer;
}