void ASIStreamHandler::run(void) { RunProlog(); LOG(VB_RECORD, LOG_INFO, LOC + "run(): begin"); if (!Open()) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to open device %1 : %2") .arg(_device).arg(strerror(errno))); _error = true; return; } DeviceReadBuffer *drb = new DeviceReadBuffer(this, true, false); bool ok = drb->Setup(_device, _fd, _packet_size, _buf_size); if (!ok) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate DRB buffer"); delete drb; drb = NULL; Close(); _error = true; RunEpilog(); return; } uint buffer_size = _packet_size * 15000; unsigned char *buffer = new unsigned char[buffer_size]; if (!buffer) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate buffer"); delete drb; drb = NULL; Close(); _error = true; RunEpilog(); return; } memset(buffer, 0, buffer_size); SetRunning(true, true, false); drb->Start(); { QMutexLocker locker(&_start_stop_lock); _drb = drb; } int remainder = 0; while (_running_desired && !_error) { UpdateFiltersFromStreamData(); ssize_t len = 0; len = drb->Read( &(buffer[remainder]), buffer_size - remainder); if (!_running_desired) break; // Check for DRB errors if (drb->IsErrored()) { LOG(VB_GENERAL, LOG_ERR, LOC + "Device error detected"); _error = true; } if (drb->IsEOF()) { LOG(VB_GENERAL, LOG_ERR, LOC + "Device EOF detected"); _error = true; } 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; } if (!_listener_lock.tryLock()) { remainder = len; continue; } 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); if (_mpts != NULL) _mpts->Write(buffer, len - remainder); _listener_lock.unlock(); if (remainder > 0 && (len > remainder)) // leftover bytes memmove(buffer, &(buffer[len - remainder]), remainder); } LOG(VB_RECORD, LOG_INFO, LOC + "run(): " + "shutdown"); RemoveAllPIDFilters(); { QMutexLocker locker(&_start_stop_lock); _drb = NULL; } if (drb->IsRunning()) drb->Stop(); delete drb; delete[] buffer; Close(); LOG(VB_RECORD, LOG_INFO, LOC + "run(): " + "end"); SetRunning(false, true, false); RunEpilog(); }
/** \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); }