vdr/transfer.c
Klaus Schmidinger dbacda8274 Version 1.3.21
- Fixed cDvbDevice::SetAudioTrackDevice() to avoid a blank screen after switching
  back to live mode if a recording is currently active on the primary device.
- Fixed a possible freeze in pause mode in case a device's PlayPesPacket() function
  permanently returns 0 (thanks to Reinhard Nissl and Olaf Titz).
- Completed the Finnish OSD texts (thanks to Rolf Ahrenberg).
- Restricted the "setting audio track" log message to automatic changes during replay.
- Fixed handling Transfer Mode for radio channels (thanks to Andreas Regel for
  reporting this one).
- Fixed handling symbolic links in cRecordings::ScanVideoDir() (thanks to Stefan
  Huelswitt).
- Completed the Danish OSD texts (thanks to Mogens Elneff).
- Forcing a new resync after a call to cRemux::Clear() (suggested by Marco Schlüßler).
- The cAudio::Play() function now has an additional parameter 'uchar Id' which tells
  the function the substream id of the given audio packet, so that a plugin can
  take the right action for the various kinds if audio data - which now also includes
  "normal" audio with ids 0xC0...0xDF (based on suggestions by Werner Fink and Macro
  Schlüßler).
- Removed the "Cleared/PlayPes(NULL, 0)" handling from cTransfer::Action(), since this
  is now done when attaching the player to the device (thanks to Marco Schlüßler).
- Making sure the buffer reserve in cTransfer::Action() is re-established after
  clearing the buffer.
- Added DeviceClrAvailableTracks() and DeviceSetCurrentAudioTrack() to cPlayer
  (thanks to Marco Schlüßler).
- Fixed a typo in detecting UTF-8 (thanks to Reinhard Nissl).
- Now using twice the buffer reserve in cTransfer if the primary DVB card is an
  unmodified version with only 2MB of SDRAM, to avoid audio stuttering when
  playing Dolby Digital over the DVB card (thanks to Christian Jacobsen and Chad
  Flynt for suggestions and experiments in that area).
- Making sure the first audio packet is not dropped when switching to "pre 1.3.19
  Dolby Digital compatibility mode".
- The 'plugins-clean' target of the Makefile now only deletes the actual plugin
  library files from this version of VDR (suggested by Andreas Brachold).
- Added a missing 'resultSkipped = 0' to cRemux::Clear() (thanks to Marco Schlüßler
  for reporting this one).
- The new function cDvbDevice::SetTransferModeForDolbyDigital() can be used by
  plugins that implement Dolby Digital output and thus want to prevent the cDvbDevice
  from starting Transfer Mode in order to replay DD over the DVB device.
- Added missing reset of the 'repacker' to cTS2PES::Clear() (thanks to Marco
  Schlüßler for reporting this one).
2005-02-13 18:00:00 +01:00

167 lines
5.1 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.27 2005/02/12 15:54:06 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;
}
}
#define FW_NEEDS_BUFFER_RESERVE_FOR_AC3
#ifdef FW_NEEDS_BUFFER_RESERVE_FOR_AC3
//XXX This is a very ugly hack to allow cDvbOsd to reduce the buffer
//XXX requirements in cTransfer if it detects a 4MB full featured DVB card.
bool DvbCardWith4MBofSDRAM = false;
#endif
void cTransfer::Action(void)
{
int PollTimeouts = 0;
uchar *p = NULL;
int Result = 0;
#ifdef FW_NEEDS_BUFFER_RESERVE_FOR_AC3
bool GotBufferReserve = false;
int RequiredBufferReserve = KILOBYTE(DvbCardWith4MBofSDRAM ? 288 : 576);
#endif
active = true;
while (active) {
#ifdef FW_NEEDS_BUFFER_RESERVE_FOR_AC3
if (needsBufferReserve && !GotBufferReserve) {
//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 (ringBuffer->Available() < RequiredBufferReserve) { // 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");
DeviceClear();
ringBuffer->Clear();
remux->Clear();
PlayPes(NULL, 0);
p = NULL;
#ifdef FW_NEEDS_BUFFER_RESERVE_FOR_AC3
GotBufferReserve = false;
#endif
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();
PlayPes(NULL, 0);
p = NULL;
#ifdef FW_NEEDS_BUFFER_RESERVE_FOR_AC3
GotBufferReserve = false;
#endif
}
}
}
}
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;
}