Statistics
| Branch: | Tag: | Revision:

dvbd / src / demuxer.cpp @ 2cecea08

History | View | Annotate | Download (4.56 KB)

1
/*
2
  Copyright 2003 John Knottenbelt
3
  
4
  This program is free software; you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation; either version 2 of the License, or
7
  (at your option) any later version.
8
 
9
  This program is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
 
14
  You should have received a copy of the GNU General Public License
15
  along with this program; if not, write to the Free Software
16
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17
*/
18

    
19
#include "config.h"
20
#include "demuxer.h"
21
#include "tuner.h"
22
#include "connection.h"
23

    
24
#include <iostream>
25
#include <cstdlib>
26
#include <climits>
27

    
28
#include <sys/ioctl.h>
29
#include <stdio.h>
30
#include <stdint.h>
31
#include <sys/types.h>
32
#include <sys/stat.h>
33
#include <fcntl.h>
34
#include <time.h>
35
#include <unistd.h>
36

    
37
#include <linux/dvb/dmx.h>
38

    
39
#define IPACKS 2048
40
#define TS_SIZE 188
41

    
42
static void set_ts_filt(int fd,uint16_t pid, dmx_pes_type_t pestype);
43

    
44
Demuxer::Demuxer(Tuner *tuner, int pid, bool convertToPS, Demuxer::PESType pestype)
45
  : tuner(tuner), pid(pid), demuxFD(-1)
46
{
47
  init_ipack(&packer, IPACKS, output, 1);
48

    
49
  switch (pestype) {
50
  case Video: this->pesType = int(DMX_PES_VIDEO); break;
51
  case Audio: this->pesType = int(DMX_PES_AUDIO); break;
52
  case Teletext: this->pesType = int(DMX_PES_TELETEXT); break;
53
  }
54
  packer.data = this;
55
}
56

    
57
Demuxer::~Demuxer()
58
{
59
  unsubscribeAll();
60
  free_ipack(&packer);
61
}
62

    
63
// Static function for use by the ipack code
64
void Demuxer::output(uint8_t *data, int size, void *priv)
65
{
66
  Demuxer *d = (Demuxer *) priv;
67
  d->sendData(data, (unsigned) size);
68
}
69

    
70
bool Demuxer::openDemux()
71
{
72
  std::string demuxDev = tuner->getDemuxerDevice();
73
  demuxFD = open(demuxDev.c_str(), O_RDWR);
74
  return (demuxFD >= 0);
75
}
76

    
77
void Demuxer::closeDemux()
78
{
79
  if (demuxFD >= 0) {
80
    ::close(demuxFD);
81
    demuxFD = -1;
82
  }
83
}
84

    
85
void Demuxer::setTSFilt( bool dmxOther )
86
{
87
  dmx_pes_type_t thePesType = 
88
    (dmxOther ? dmx_pes_type_t(pesType) : DMX_PES_OTHER);
89

    
90
  set_ts_filt(demuxFD, pid, thePesType);
91
}
92

    
93
bool Demuxer::subscribe(Sink *s)
94
{
95
  if (getNumSubscribers() == 0) {
96

    
97
    if (!openDemux()) {
98
      std::cerr << "Failed to open demuxer\n";
99
      return false;
100
    }
101

    
102
    // DVB Seems to like AUDIO / VIDEO only for the first two PIDs
103
    // otherwise OTHER must be used.
104

    
105
    bool dmxOther = (tuner->getNumSubscribers() >= 2);
106

    
107
    if (!tuner->subscribe(this)) {
108
      closeDemux();
109
      return false;
110
    }
111

    
112
    setTSFilt(dmxOther);
113

    
114
  }
115
  return Source::subscribe(s);
116
}
117

    
118
void Demuxer::unsubscribe(Sink *s) 
119
{
120
  Source::unsubscribe(s);
121
  if (getNumSubscribers() == 0) {
122
    close(demuxFD);
123
    tuner->unsubscribe(this);
124
  }
125
}
126

    
127
void Demuxer::notifyUnsubscribe(Source *)
128
{
129
  // This method is called when the tuner manager
130
  // forcefully unsubscribes demuxers from the channel.
131

    
132
  // Since our source is no longer available
133
  // we should unsubscribe the clients.
134

    
135
  unsubscribeAll();
136
}
137

    
138

    
139
void Demuxer::receiveData(unsigned char *data, unsigned size)
140
{
141
  if (convertToPS) {
142
    // adapted from my_ts_to_ps( uint8_t* buf, uint16_t pida, uint16_t pidv)
143
    // in dvbstream.c (Dave Chapman)
144

    
145
    uint16_t pid;
146
    ipack *p = &this->packer;
147
    uint8_t off = 0;
148
    uint8_t *buf = (uint8_t *) data;
149

    
150
    pid = get_pid(buf+1);
151
    if (!(buf[3]&0x10)) // no payload?
152
      return;
153

    
154
    // Is this our packet?
155
    if (pid != this->pid)
156
      return;
157

    
158
    if ( buf[1]&0x40) {
159
      if (p->plength == MMAX_PLENGTH-6){
160
        p->plength = p->found-6;
161
        p->found = 0;
162
        send_ipack(p);
163
        reset_ipack(p);
164
      }
165
    }
166

    
167
    if ( buf[3] & 0x20) {  // adaptation field?
168
      off = buf[4] + 1;
169
    }
170
        
171
    instant_repack(buf+4+off, TS_SIZE-4-off, p);
172
  }
173
  else {
174
    if (get_pid(data + 1) == pid)
175
      sendData(data, (unsigned) size);
176
  }
177
}
178

    
179
static void set_ts_filt(int fd,uint16_t pid, dmx_pes_type_t pestype)
180
{
181
  // From Dave Chapman's dvbstream.c
182
  struct dmx_pes_filter_params pesFilterParams;
183

    
184
  pesFilterParams.pid     = pid;
185
  pesFilterParams.input   = DMX_IN_FRONTEND;
186
  pesFilterParams.output  = DMX_OUT_TS_TAP;
187
#ifdef NEWSTRUCT
188
  pesFilterParams.pes_type = pestype;
189
#else
190
  pesFilterParams.pesType = pestype;
191
#endif
192
  pesFilterParams.flags   = 0;
193

    
194
  if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0)  {
195
    fprintf(stderr,"FILTER %i: ",pid);
196
    perror("DMX SET PES FILTER");
197
  }
198

    
199
  if (ioctl(fd, DMX_START, &pesFilterParams) < 0)  {
200
    fprintf(stderr,"FILTER %i: ",pid);
201
    perror("DMX START");
202
  }
203
}