Statistics
| Branch: | Tag: | Revision:

dvbd / demuxer.cpp @ bfdb7446

History | View | Annotate | Download (4.41 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, 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
  // adapted from my_ts_to_ps( uint8_t* buf, uint16_t pida, uint16_t pidv)
142
  // in dvbstream.c (Dave Chapman)
143

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

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

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

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

    
166
  if ( buf[3] & 0x20) {  // adaptation field?
167
    off = buf[4] + 1;
168
  }
169
        
170
  instant_repack(buf+4+off, TS_SIZE-4-off, p);
171
}
172

    
173
static void set_ts_filt(int fd,uint16_t pid, dmx_pes_type_t pestype)
174
{
175
  // From Dave Chapman's dvbstream.c
176
  struct dmx_pes_filter_params pesFilterParams;
177

    
178
  pesFilterParams.pid     = pid;
179
  pesFilterParams.input   = DMX_IN_FRONTEND;
180
  pesFilterParams.output  = DMX_OUT_TS_TAP;
181
#ifdef NEWSTRUCT
182
  pesFilterParams.pes_type = pestype;
183
#else
184
  pesFilterParams.pesType = pestype;
185
#endif
186
  pesFilterParams.flags   = 0;
187

    
188
  if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0)  {
189
    fprintf(stderr,"FILTER %i: ",pid);
190
    perror("DMX SET PES FILTER");
191
  }
192

    
193
  if (ioctl(fd, DMX_START, &pesFilterParams) < 0)  {
194
    fprintf(stderr,"FILTER %i: ",pid);
195
    perror("DMX START");
196
  }
197
}