/** \fn DVBStreamHandler::RunSR(void) * \brief Uses "Section" reader to read a DVB device for tables * * This currently only supports DVB streams, ATSC and the raw MPEG * streams used by some cable and satelite providers is not supported. */ void DVBStreamHandler::RunSR(void) { int buffer_size = 4192; // maximum size of Section we handle unsigned char *buffer = new unsigned char[buffer_size]; if (!buffer) { _error = true; return; } SetRunning(true, _needs_buffering, true); LOG(VB_RECORD, LOG_INFO, LOC + "RunSR(): begin"); while (_running_desired && !_error) { RetuneMonitor(); UpdateFiltersFromStreamData(); QMutexLocker read_locker(&_pid_lock); bool readSomething = false; PIDInfoMap::const_iterator fit = _pid_info.begin(); for (; fit != _pid_info.end(); ++fit) { int len = read((*fit)->filter_fd, buffer, buffer_size); if (len <= 0) continue; readSomething = true; const PESPacket pes = PESPacket::ViewData(buffer); const PSIPTable psip(pes); if (psip.SectionSyntaxIndicator()) { _listener_lock.lock(); StreamDataList::const_iterator sit = _stream_data_list.begin(); for (; sit != _stream_data_list.end(); ++sit) sit.key()->HandleTables(fit.key() /* pid */, psip); _listener_lock.unlock(); } } if (!readSomething) usleep(3000); } LOG(VB_RECORD, LOG_INFO, LOC + "RunSR(): " + "shutdown"); RemoveAllPIDFilters(); delete[] buffer; SetRunning(false, _needs_buffering, true); LOG(VB_RECORD, LOG_INFO, LOC + "RunSR(): " + "end"); }
/** \fn DVBStreamHandler::RunSR(void) * \brief Uses "Section" reader to read a DVB device for tables * * This currently only supports DVB streams, ATSC and the raw MPEG * streams used by some cable and satelite providers is not supported. */ void DVBStreamHandler::RunSR(void) { int buffer_size = 4192; // maximum size of Section we handle unsigned char *buffer = new unsigned char[buffer_size]; if (!buffer) return; VERBOSE(VB_RECORD, LOC + "RunSR(): begin"); while (IsRunning()) { RetuneMonitor(); UpdateFiltersFromStreamData(); QMutexLocker read_locker(&_pid_lock); bool readSomething = false; PIDInfoMap::const_iterator fit = _pid_info.begin(); for (; fit != _pid_info.end(); ++fit) { int len = read((*fit)->filter_fd, buffer, buffer_size); if (len <= 0) continue; readSomething = true; const PESPacket pes = PESPacket::ViewData(buffer); const PSIPTable psip(pes); if (psip.SectionSyntaxIndicator()) { _listener_lock.lock(); for (uint i = 0; i < _stream_data_list.size(); i++) { _stream_data_list[i]->HandleTables( fit.key() /* pid */, psip); } _listener_lock.unlock(); } } if (!readSomething) usleep(3000); } VERBOSE(VB_RECORD, LOC + "RunSR(): " + "shutdown"); RemoveAllPIDFilters(); delete[] buffer; VERBOSE(VB_RECORD, LOC + "RunSR(): " + "end"); }
/** \fn DVBStreamHandler::RunTS(void) * \brief Uses TS filtering devices to read a DVB device for tables & data * * This supports all types of MPEG based stream data, but is extreemely * slow with DVB over USB 1.0 devices which for efficiency reasons buffer * a stream until a full block transfer buffer full of the requested * tables is available. This takes a very long time when you are just * waiting for a PAT or PMT table, and the buffer is hundreds of packets * in size. */ void DVBStreamHandler::RunTS(void) { if (_needs_buffering) _device_read_buffer = new DeviceReadBuffer(this); int remainder = 0; int buffer_size = TSPacket::SIZE * 15000; unsigned char *buffer = new unsigned char[buffer_size]; if (!buffer) return; memset(buffer, 0, buffer_size); QByteArray dvr_dev_path = _dvr_dev_path.toAscii(); int dvr_fd; for (int tries = 1; ; ++tries) { dvr_fd = open(dvr_dev_path.constData(), O_RDONLY | O_NONBLOCK); if (dvr_fd >= 0) break; VERBOSE(VB_IMPORTANT, LOC_WARN + QString("Opening DVR device %1 failed : %2") .arg(_dvr_dev_path).arg(strerror(errno))); if (tries >= 20 || (errno != EBUSY && errno != EAGAIN)) { VERBOSE(VB_IMPORTANT, LOC + QString("Failed to open DVR device %1 : %2") .arg(_dvr_dev_path).arg(strerror(errno))); delete[] buffer; return; } usleep(50000); } bool _error = false; if (_device_read_buffer) { bool ok = _device_read_buffer->Setup(_dvb_dev, dvr_fd); if (!ok) { VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to allocate DRB buffer"); _error = true; delete[] buffer; return; } _device_read_buffer->Start(); } VERBOSE(VB_RECORD, LOC + "RunTS(): begin"); fd_set fd_select_set; FD_ZERO( &fd_select_set); FD_SET (dvr_fd, &fd_select_set); while (IsRunning() && !_error) { RetuneMonitor(); UpdateFiltersFromStreamData(); ssize_t len = 0; if (_device_read_buffer) { len = _device_read_buffer->Read( &(buffer[remainder]), buffer_size - remainder); // Check for DRB errors if (_device_read_buffer->IsErrored()) { VERBOSE(VB_IMPORTANT, LOC_ERR + "Device error detected"); _error = true; } if (_device_read_buffer->IsEOF()) { VERBOSE(VB_IMPORTANT, LOC_ERR + "Device EOF detected"); _error = true; } } else { // timeout gets reset by select, so we need to create new one struct timeval timeout = { 0, 50 /* ms */ * 1000 /* -> usec */ }; int ret = select(dvr_fd+1, &fd_select_set, NULL, NULL, &timeout); if (ret == -1 && errno != EINTR) { VERBOSE(VB_IMPORTANT, LOC_ERR + "select() failed" + ENO); } else { len = read(dvr_fd, &(buffer[remainder]), buffer_size - remainder); } } if ((0 == len) || (-1 == len)) { usleep(100); continue; } len += remainder; if (len < 10) // 10 bytes = 4 bytes TS header + 6 bytes PES header { remainder = len; continue; } _listener_lock.lock(); if (_stream_data_list.empty()) { _listener_lock.unlock(); continue; } for (uint i = 0; i < _stream_data_list.size(); i++) { remainder = _stream_data_list[i]->ProcessData(buffer, len); } _listener_lock.unlock(); if (remainder > 0 && (len > remainder)) // leftover bytes memmove(buffer, &(buffer[len - remainder]), remainder); } VERBOSE(VB_RECORD, LOC + "RunTS(): " + "shutdown"); RemoveAllPIDFilters(); if (_device_read_buffer) { if (_device_read_buffer->IsRunning()) _device_read_buffer->Stop(); delete _device_read_buffer; _device_read_buffer = NULL; } close(dvr_fd); delete[] buffer; VERBOSE(VB_RECORD, LOC + "RunTS(): " + "end"); SetRunning(false); }
/** \fn DVBStreamHandler::RunTS(void) * \brief Uses TS filtering devices to read a DVB device for tables & data * * This supports all types of MPEG based stream data, but is extreemely * slow with DVB over USB 1.0 devices which for efficiency reasons buffer * a stream until a full block transfer buffer full of the requested * tables is available. This takes a very long time when you are just * waiting for a PAT or PMT table, and the buffer is hundreds of packets * in size. */ void DVBStreamHandler::RunTS(void) { QByteArray dvr_dev_path = _dvr_dev_path.toAscii(); int dvr_fd; for (int tries = 1; ; ++tries) { dvr_fd = open(dvr_dev_path.constData(), O_RDONLY | O_NONBLOCK); if (dvr_fd >= 0) break; LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Opening DVR device %1 failed : %2") .arg(_dvr_dev_path).arg(strerror(errno))); if (tries >= 20 || (errno != EBUSY && errno != EAGAIN)) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to open DVR device %1 : %2") .arg(_dvr_dev_path).arg(strerror(errno))); _error = true; return; } usleep(50000); } int remainder = 0; int buffer_size = TSPacket::kSize * 15000; unsigned char *buffer = new unsigned char[buffer_size]; if (!buffer) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate memory"); close(dvr_fd); _error = true; return; } memset(buffer, 0, buffer_size); DeviceReadBuffer *drb = NULL; if (_needs_buffering) { drb = new DeviceReadBuffer(this, true, false); if (!drb->Setup(_device, dvr_fd)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate DRB buffer"); delete drb; delete[] buffer; close(dvr_fd); _error = true; return; } drb->Start(); } { // SetRunning() + set _drb QMutexLocker locker(&_start_stop_lock); _running = true; _using_buffering = _needs_buffering; _using_section_reader = false; _drb = drb; } LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): begin"); fd_set fd_select_set; FD_ZERO( &fd_select_set); FD_SET (dvr_fd, &fd_select_set); while (_running_desired && !_error) { RetuneMonitor(); UpdateFiltersFromStreamData(); ssize_t len = 0; if (drb) { len = drb->Read( &(buffer[remainder]), buffer_size - remainder); // Check for DRB errors if (drb->IsErrored()) { LOG(VB_GENERAL, LOG_ERR, LOC + "Device error detected"); _error = true; } if (drb->IsEOF() && _running_desired) { LOG(VB_GENERAL, LOG_ERR, LOC + "Device EOF detected"); _error = true; } } else { // timeout gets reset by select, so we need to create new one struct timeval timeout = { 0, 50 /* ms */ * 1000 /* -> usec */ }; int ret = select(dvr_fd+1, &fd_select_set, NULL, NULL, &timeout); if (ret == -1 && errno != EINTR) { LOG(VB_GENERAL, LOG_ERR, LOC + "select() failed" + ENO); } else { len = read(dvr_fd, &(buffer[remainder]), buffer_size - remainder); } } if ((0 == len) || (-1 == len)) { usleep(100); continue; } len += remainder; if (len < 10) // 10 bytes = 4 bytes TS header + 6 bytes PES header { remainder = len; continue; } _listener_lock.lock(); if (_stream_data_list.empty()) { _listener_lock.unlock(); continue; } StreamDataList::const_iterator sit = _stream_data_list.begin(); for (; sit != _stream_data_list.end(); ++sit) remainder = sit.key()->ProcessData(buffer, len); _listener_lock.unlock(); if (remainder > 0 && (len > remainder)) // leftover bytes memmove(buffer, &(buffer[len - remainder]), remainder); } LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "shutdown"); RemoveAllPIDFilters(); { QMutexLocker locker(&_start_stop_lock); _drb = NULL; } if (drb) { if (drb->IsRunning()) drb->Stop(); delete drb; } close(dvr_fd); delete[] buffer; LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "end"); SetRunning(false, _needs_buffering, false); }