Home

Dokumentation

Impressum

Dokumentation VDR
 

Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

transfer.c

Go to the documentation of this file.
00001 /*
00002  * transfer.c: Transfer mode
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: transfer.c 1.8 2002/12/14 13:14:53 kls Exp $
00008  */
00009 
00010 #include "transfer.h"
00011 
00012 //XXX+ also used in recorder.c - find a better place???
00013 // The size of the array used to buffer video data:
00014 // (must be larger than MINVIDEODATA - see remux.h)
00015 #define VIDEOBUFSIZE  MEGABYTE(1)
00016 
00017 // --- cTransfer -------------------------------------------------------------
00018 
00019 cTransfer::cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2)
00020 :cReceiver(0, -1, 5, VPid, APid1, APid2, DPid1, DPid2)
00021 {
00022   ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, true);
00023   remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2);
00024   canToggleAudioTrack = false;
00025   audioTrack = 0xC0;
00026   gotBufferReserve = false;
00027   active = false;
00028 }
00029 
00030 cTransfer::~cTransfer()
00031 {
00032   cReceiver::Detach();
00033   cPlayer::Detach();
00034   delete remux;
00035   delete ringBuffer;
00036 }
00037 
00038 void cTransfer::Activate(bool On)
00039 {
00040   if (On) {
00041      if (!active)
00042         Start();
00043      }
00044   else if (active) {
00045      active = false;
00046      Cancel(3);
00047      }
00048 }
00049 
00050 void cTransfer::Receive(uchar *Data, int Length)
00051 {
00052   if (IsAttached()) {
00053      int p = ringBuffer->Put(Data, Length);
00054      if (p != Length && active)
00055         esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p);
00056      }
00057 }
00058 
00059 void cTransfer::Action(void)
00060 {
00061   dsyslog("transfer thread started (pid=%d)", getpid());
00062 
00063   uchar b[MINVIDEODATA];
00064   int r = 0;
00065   active = true;
00066   while (active) {
00067 
00068         //XXX+ Maybe we need this to avoid "buffer empty" log messages from the driver.
00069         //XXX+ But then again, it appears to play just fine without this...
00070         /*
00071         if (!gotBufferReserve) {
00072            if (ringBuffer->Available() < 4 * MAXFRAMESIZE) {
00073               usleep(100000); // allow the buffer to collect some reserve
00074               continue;
00075               }
00076            else
00077               gotBufferReserve = true;
00078            }
00079            */
00080 
00081         // Get data from the buffer:
00082 
00083         int g = ringBuffer->Get(b + r, sizeof(b) - r);
00084         if (g > 0)
00085            r += g;
00086 
00087         // Play the data:
00088 
00089         if (r > 0) {
00090            int Count = r, Result;
00091            uchar *p = remux->Process(b, Count, Result);
00092            if (p) {
00093               StripAudioPackets(p, Result, audioTrack);
00094               while (Result > 0 && active) {
00095                     int w = PlayVideo(p, Result);
00096                     if (w > 0) {
00097                        p += w;
00098                        Result -= w;
00099                        }
00100                     else if (w < 0 && FATALERRNO) {
00101                        LOG_ERROR;
00102                        break;
00103                        }
00104                     }
00105               }
00106            if (Count > 0) {
00107               r -= Count;
00108               if (r > 0)
00109                  memmove(b, b + Count, r);
00110               }
00111            }
00112         else
00113            usleep(1); // this keeps the CPU load low
00114         }
00115 
00116   dsyslog("transfer thread ended (pid=%d)", getpid());
00117 }
00118 
00119 void cTransfer::StripAudioPackets(uchar *b, int Length, uchar Except)
00120 {
00121   for (int i = 0; i < Length - 6; i++) {
00122       if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
00123          uchar c = b[i + 3];
00124          int l = b[i + 4] * 256 + b[i + 5] + 6;
00125          switch (c) {
00126            case 0xBD: // dolby
00127                 if (Except)
00128                    PlayAudio(&b[i], l);
00129                 // continue with deleting the data - otherwise it disturbs DVB replay
00130            case 0xC0 ... 0xC1: // audio
00131                 if (c == 0xC1)
00132                    canToggleAudioTrack = true;
00133                 if (!Except || c != Except) {
00134                    int n = l;
00135                    for (int j = i; j < Length && n--; j++)
00136                        b[j] = 0x00;
00137                    }
00138                 break;
00139            case 0xE0 ... 0xEF: // video
00140                 break;
00141            default:
00142                 //esyslog("ERROR: unexpected packet id %02X", c);
00143                 l = 0;
00144            }
00145          if (l)
00146             i += l - 1; // the loop increments, too!
00147          }
00148       /*XXX
00149       else
00150          esyslog("ERROR: broken packet header");
00151          XXX*/
00152       }
00153 }
00154 
00155 int cTransfer::NumAudioTracks(void) const
00156 {
00157   return canToggleAudioTrack ? 2 : 1;
00158 }
00159 
00160 const char **cTransfer::GetAudioTracks(int *CurrentTrack) const
00161 {
00162   if (NumAudioTracks()) {
00163      if (CurrentTrack)
00164         *CurrentTrack = (audioTrack == 0xC0) ? 0 : 1;
00165      static const char *audioTracks1[] = { "Audio 1", NULL };
00166      static const char *audioTracks2[] = { "Audio 1", "Audio 2", NULL };
00167      return NumAudioTracks() > 1 ? audioTracks2 : audioTracks1;
00168      }
00169   return NULL;
00170 }
00171 
00172 void cTransfer::SetAudioTrack(int Index)
00173 {
00174   if ((audioTrack == 0xC0) != (Index == 0)) {
00175      audioTrack = (Index == 1) ? 0xC1 : 0xC0;
00176      DeviceClear();
00177      }
00178 }
00179 
00180 // --- cTransferControl ------------------------------------------------------
00181 
00182 cTransferControl::cTransferControl(cDevice *ReceiverDevice, int VPid, int APid1, int APid2, int DPid1, int DPid2)
00183 :cControl(transfer = new cTransfer(VPid, APid1, APid2, DPid1, DPid2), true)
00184 {
00185   ReceiverDevice->AttachReceiver(transfer);
00186 }
00187 
00188 cTransferControl::~cTransferControl()
00189 {
00190   delete transfer;
00191 }

Generated on Wed Feb 5 23:30:12 2003 for VDR by doxygen1.3-rc2