193 | | if (!useSectionReader) |
194 | | { |
195 | | struct dmx_pes_filter_params pesFilterParams; |
196 | | bzero(&pesFilterParams, sizeof(struct dmx_pes_filter_params)); |
197 | | pesFilterParams.pid = (__u16) pid; |
198 | | pesFilterParams.input = DMX_IN_FRONTEND; |
199 | | pesFilterParams.output = DMX_OUT_TS_TAP; |
200 | | pesFilterParams.flags = DMX_IMMEDIATE_START; |
201 | | pesFilterParams.pes_type = DMX_PES_OTHER; |
202 | | |
203 | | if (ioctl(mux_fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) |
204 | | { |
205 | | VERBOSE(VB_IMPORTANT, LOC_ERR + |
206 | | QString("Failed to set TS filter (pid %1)").arg(pid)); |
207 | | close(mux_fd); |
208 | | return false; |
209 | | } |
210 | | } |
211 | | else |
212 | | { |
213 | | struct dmx_sct_filter_params sctFilterParams; |
214 | | bzero(&sctFilterParams, sizeof(struct dmx_sct_filter_params)); |
| 192 | struct dmx_sct_filter_params sctFilterParams; |
| 193 | bzero(&sctFilterParams, sizeof(struct dmx_sct_filter_params)); |
218 | | switch ( (__u16) pid ) |
219 | | { |
220 | | case 0x0: // PAT |
221 | | sctFilterParams.filter.filter[0] = 0; |
222 | | break; |
223 | | case 0x0010: // assume this is for an NIT |
224 | | // With this filter we can only ever get NIT for this network |
225 | | // because other networks nit need a filter of 0x41 |
226 | | sctFilterParams.filter.filter[0] = 0x40; |
227 | | break; |
228 | | case 0x0011: // assume this is for an SDT |
229 | | sctFilterParams.filter.filter[0] = 0x42; |
230 | | break; |
231 | | case 0x1ffb: // assume this is for a MGT or VCT |
232 | | // MGT 0xc7, terrestrial VCT 0xc8, cable VCT 0xc9 |
233 | | sctFilterParams.filter.filter[0] = 0xc0; |
234 | | sctFilterParams.filter.mask[0] = 0xf0; |
235 | | default: // otherwise assume we are looking for a PMT or EIT |
236 | | sctFilterParams.filter.filter[0] = 0x00; |
237 | | sctFilterParams.filter.mask[0] = 0x00; |
238 | | break; |
239 | | } |
240 | | sctFilterParams.pid = (__u16) pid; |
241 | | sctFilterParams.timeout = 0; |
242 | | sctFilterParams.flags = DMX_IMMEDIATE_START; |
243 | | |
244 | | if (ioctl(mux_fd, DMX_SET_FILTER, &sctFilterParams) < 0) |
245 | | { |
246 | | VERBOSE(VB_IMPORTANT, LOC_ERR + |
247 | | "Failed to set \"section\" filter " + |
248 | | QString("(pid %1) (filter %2)").arg(pid) |
249 | | .arg(sctFilterParams.filter.filter[0])); |
250 | | close(mux_fd); |
251 | | return false; |
252 | | } |
| 197 | switch ( (__u16) pid ) |
| 198 | { |
| 199 | case 0x0: // PAT |
| 200 | sctFilterParams.filter.filter[0] = 0; |
| 201 | break; |
| 202 | case 0x0010: // assume this is for an NIT |
| 203 | // With this filter we can only ever get NIT for this network |
| 204 | // because other networks nit need a filter of 0x41 |
| 205 | sctFilterParams.filter.filter[0] = 0x40; |
| 206 | break; |
| 207 | case 0x0011: // assume this is for an SDT |
| 208 | sctFilterParams.filter.filter[0] = 0x42; |
| 209 | break; |
| 210 | case 0x1ffb: // assume this is for a MGT or VCT |
| 211 | // MGT 0xc7, terrestrial VCT 0xc8, cable VCT 0xc9 |
| 212 | sctFilterParams.filter.filter[0] = 0xc0; |
| 213 | sctFilterParams.filter.mask[0] = 0xf0; |
| 214 | default: // otherwise assume we are looking for a PMT or EIT |
| 215 | sctFilterParams.filter.filter[0] = 0x00; |
| 216 | sctFilterParams.filter.mask[0] = 0x00; |
| 217 | break; |
| 218 | } |
| 219 | sctFilterParams.pid = (__u16) pid; |
| 220 | sctFilterParams.timeout = 0; |
| 221 | sctFilterParams.flags = DMX_IMMEDIATE_START; |
| 222 | |
| 223 | if (ioctl(mux_fd, DMX_SET_FILTER, &sctFilterParams) < 0) |
| 224 | { |
| 225 | VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set \"section\" filter " + |
| 226 | QString("(pid %1) (filter %2)").arg(pid) |
| 227 | .arg(sctFilterParams.filter.filter[0])); |
| 228 | close(mux_fd); |
| 229 | return false; |
324 | | int remainder = 0; |
325 | | int buffer_size = TSPacket::SIZE * 15000; |
326 | | unsigned char *buffer = new unsigned char[buffer_size]; |
327 | | if (!buffer) |
328 | | return; |
329 | | bzero(buffer, buffer_size); |
330 | | |
331 | | QString dvr_fname = CardUtil::GetDeviceName(DVB_DEV_DVR, GetDVBCardNum()); |
332 | | int dvr_fd = open(dvr_fname.ascii(), O_RDONLY | O_NONBLOCK); |
333 | | if (dvr_fd < 0) |
334 | | { |
335 | | VERBOSE(VB_IMPORTANT, LOC + |
336 | | QString("Failed to open DVR device %1 : %2") |
337 | | .arg(dvr_fname).arg(strerror(errno))); |
338 | | delete[] buffer; |
339 | | return; |
340 | | } |
341 | | |
342 | | VERBOSE(VB_CHANNEL, LOC + "RunTableMonitorTS(): " + |
343 | | QString("begin (# of pids %1)") |
344 | | .arg(GetStreamData()->ListeningPIDs().size())); |
345 | | |
346 | | fd_set fd_select_set; |
347 | | FD_ZERO( &fd_select_set); |
348 | | FD_SET (dvr_fd, &fd_select_set); |
349 | | while (dtvMonitorRunning && GetStreamData()) |
350 | | { |
351 | | RetuneMonitor(); |
352 | | UpdateFiltersFromStreamData(); |
353 | | |
354 | | // timeout gets reset by select, so we need to create new one |
355 | | struct timeval timeout = { 0, 50 /* ms */ * 1000 /* -> usec */ }; |
356 | | select(dvr_fd+1, &fd_select_set, NULL, NULL, &timeout); |
357 | | |
358 | | long long len = read( |
359 | | dvr_fd, &(buffer[remainder]), buffer_size - remainder); |
360 | | |
361 | | if ((0 == len) || (-1 == len)) |
362 | | { |
363 | | usleep(100); |
364 | | continue; |
365 | | } |
366 | | |
367 | | len += remainder; |
368 | | |
369 | | if (len < 10) // 10 bytes = 4 bytes TS header + 6 bytes PES header |
370 | | { |
371 | | remainder = len; |
372 | | continue; |
373 | | } |
374 | | |
375 | | remainder = GetStreamData()->ProcessData(buffer, len); |
376 | | if (remainder > 0 && (len > remainder)) // leftover bytes |
377 | | memmove(buffer, &(buffer[len - remainder]), remainder); |
378 | | } |
379 | | VERBOSE(VB_CHANNEL, LOC + "RunTableMonitorTS(): " + "shutdown"); |
380 | | |
381 | | if (GetStreamData()) |
382 | | { |
383 | | vector<int> del_pids; |
384 | | FilterMap::iterator it = filters.begin(); |
385 | | for (; it != filters.end(); ++it) |
386 | | del_pids.push_back(it.key()); |
387 | | |
388 | | vector<int>::iterator dit = del_pids.begin(); |
389 | | for (; dit != del_pids.end(); ++dit) |
390 | | RemovePIDFilter(*dit); |
391 | | } |
392 | | |
393 | | close(dvr_fd); |
394 | | delete[] buffer; |
395 | | |
396 | | VERBOSE(VB_CHANNEL, LOC + "RunTableMonitorTS(): " + "end"); |
397 | | } |
| 295 | dtvMonitorRunning = true; |
460 | | // for caching TS monitoring supported value. |
461 | | static QMap<uint,bool> _rec_supports_ts_monitoring; |
462 | | static QMutex _rec_supports_ts_monitoring_lock; |
463 | | |
464 | | /** \fn DVBSignalMonitor::SupportsTSMonitoring(void) |
465 | | * \brief Returns true if TS monitoring is supported. |
466 | | * |
467 | | * NOTE: If you are using a DEC2000-t device you need to |
468 | | * apply the patches provided by Peter Beutner for it, see |
469 | | * http://www.gossamer-threads.com/lists/mythtv/dev/166172 |
470 | | * These patches should make it in to Linux 2.6.15 or 2.6.16. |
471 | | */ |
472 | | bool DVBSignalMonitor::SupportsTSMonitoring(void) |
473 | | { |
474 | | const uint pat_pid = 0x0; |
475 | | |
476 | | { |
477 | | QMutexLocker locker(&_rec_supports_ts_monitoring_lock); |
478 | | QMap<uint,bool>::const_iterator it; |
479 | | it = _rec_supports_ts_monitoring.find(GetDVBCardNum()); |
480 | | if (it != _rec_supports_ts_monitoring.end()) |
481 | | return *it; |
482 | | } |
483 | | |
484 | | QString dvr_fname = CardUtil::GetDeviceName(DVB_DEV_DVR, GetDVBCardNum()); |
485 | | int dvr_fd = open(dvr_fname.ascii(), O_RDONLY | O_NONBLOCK); |
486 | | if (dvr_fd < 0) |
487 | | { |
488 | | QMutexLocker locker(&_rec_supports_ts_monitoring_lock); |
489 | | _rec_supports_ts_monitoring[GetDVBCardNum()] = false; |
490 | | return false; |
491 | | } |
492 | | |
493 | | bool supports_ts = false; |
494 | | if (AddPIDFilter(pat_pid)) |
495 | | { |
496 | | supports_ts = true; |
497 | | RemovePIDFilter(pat_pid); |
498 | | } |
499 | | |
500 | | close(dvr_fd); |
501 | | |
502 | | QMutexLocker locker(&_rec_supports_ts_monitoring_lock); |
503 | | _rec_supports_ts_monitoring[GetDVBCardNum()] = supports_ts; |
504 | | return supports_ts; |
505 | | } |
506 | | |