summaryrefslogtreecommitdiff
path: root/transfer.c
blob: 0e0a7083bf40984c13b409b5c25de33a92296dac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
 * transfer.c: Transfer mode
 *
 * See the main source file 'vdr.c' for copyright information and
 * how to reach the author.
 *
 * $Id: transfer.c 1.1 2002/06/22 13:39:23 kls Exp $
 */

#include "transfer.h"

//XXX+ also used in recorder.c - find a better place???
// The size of the array used to buffer video data:
// (must be larger than MINVIDEODATA - see remux.h)
#define VIDEOBUFSIZE  MEGABYTE(1)

// --- cTransfer -------------------------------------------------------------

cTransfer::cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2)
:cReceiver(0, 0, 5, VPid, APid1, APid2, DPid1, DPid2)
{
  ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, true);
  remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2);
  gotBufferReserve = false;
  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)
{
  int p = ringBuffer->Put(Data, Length);
  if (p != Length && active)
     esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p);
}

void cTransfer::Action(void)
{
  dsyslog("transfer thread started (pid=%d)", getpid());

  uchar b[MINVIDEODATA];
  int r = 0;
  active = true;
  while (active) {

        //XXX+ Maybe we need this to avoid "buffer empty" log messages from the driver.
        //XXX+ But then again, it appears to play just fine without this...
        /*
        if (!gotBufferReserve) {
           if (ringBuffer->Available() < 4 * MAXFRAMESIZE) {
              usleep(100000); // allow the buffer to collect some reserve
              continue;
              }
           else
              gotBufferReserve = true;
           }
           */

        // Get data from the buffer:

        int g = ringBuffer->Get(b + r, sizeof(b) - r);
        if (g > 0)
           r += g;

        // Play the data:

        if (r > 0) {
           int Count = r, Result;
           const uchar *p = remux->Process(b, Count, Result);
           if (p) {
              //XXX+ StripAudio???
              while (Result > 0 && active) {
                    int w = PlayVideo(p, Result);
                    if (w > 0) {
                       p += w;
                       Result -= w;
                       }
                    else if (w < 0 && FATALERRNO) {
                       LOG_ERROR;
                       break;
                       }
                    }
              }
           if (Count > 0) {
              r -= Count;
              if (r > 0)
                 memmove(b, b + Count, r);
              }
           }
        }

  dsyslog("transfer thread ended (pid=%d)", getpid());
}

void cTransfer::SetAudioPid(int APid)
{
  /*XXX+
  Clear();
  //XXX we may need to have access to the audio device, too, in order to clear it
  CHECK(ioctl(toDevice, VIDEO_CLEAR_BUFFER));
  gotBufferReserve = false;
  remux.SetAudioPid(APid);
  XXX*/
}