void StreamHandler::UpdateListeningForEIT(void) { vector<uint> add_eit, del_eit; QMutexLocker read_locker(&_listener_lock); StreamDataList::const_iterator it = _stream_data_list.begin(); for (; it != _stream_data_list.end(); ++it) { MPEGStreamData *sd = it.key(); if (sd->HasEITPIDChanges(_eit_pids) && sd->GetEITPIDChanges(_eit_pids, add_eit, del_eit)) { for (uint i = 0; i < del_eit.size(); i++) { uint_vec_t::iterator it; it = find(_eit_pids.begin(), _eit_pids.end(), del_eit[i]); if (it != _eit_pids.end()) _eit_pids.erase(it); sd->RemoveListeningPID(del_eit[i]); } for (uint i = 0; i < add_eit.size(); i++) { _eit_pids.push_back(add_eit[i]); sd->AddListeningPID(add_eit[i]); } } } }
/** \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"); }
bool StreamHandler::UpdateFiltersFromStreamData(void) { UpdateListeningForEIT(); pid_map_t pids; { QMutexLocker read_locker(&_listener_lock); StreamDataList::const_iterator it = _stream_data_list.begin(); for (; it != _stream_data_list.end(); ++it) it.key()->GetPIDs(pids); } QMap<uint, PIDInfo*> add_pids; vector<uint> del_pids; { QMutexLocker read_locker(&_pid_lock); // PIDs that need to be added.. pid_map_t::const_iterator lit = pids.constBegin(); for (; lit != pids.constEnd(); ++lit) { if (*lit && (_pid_info.find(lit.key()) == _pid_info.end())) { add_pids[lit.key()] = CreatePIDInfo( lit.key(), StreamID::PrivSec, 0); } } // PIDs that need to be removed.. PIDInfoMap::const_iterator fit = _pid_info.begin(); for (; fit != _pid_info.end(); ++fit) { bool in_pids = pids.find(fit.key()) != pids.end(); if (!in_pids) del_pids.push_back(fit.key()); } } // Remove PIDs bool ok = true; vector<uint>::iterator dit = del_pids.begin(); for (; dit != del_pids.end(); ++dit) ok &= RemovePIDFilter(*dit); // Add PIDs QMap<uint, PIDInfo*>::iterator ait = add_pids.begin(); for (; ait != add_pids.end(); ++ait) ok &= AddPIDFilter(*ait); // Cycle filters if it's been a while if (_cycle_timer.elapsed() > 1000) CycleFiltersByPriority(); return ok; }
PIDPriority StreamHandler::GetPIDPriority(uint pid) const { QMutexLocker reading_locker(&_listener_lock); PIDPriority tmp = kPIDPriorityNone; StreamDataList::const_iterator it = _stream_data_list.begin(); for (; it != _stream_data_list.end(); ++it) tmp = max(tmp, it.key()->GetPIDPriority(pid)); return tmp; }
bool ExternalStreamHandler::StartStreaming(bool flush_buffer) { QString result; QMutexLocker locker(&m_stream_lock); LOG(VB_RECORD, LOG_INFO, LOC + QString("StartStreaming with %1 current listeners") .arg(StreamingCount())); if (!IsOpen()) { LOG(VB_GENERAL, LOG_ERR, LOC + "External recorder not started."); return false; } if (StreamingCount() == 0) { if (flush_buffer) { /* If the input is not a 'broadcast' it may only one have * copy of the SPS right at the beginning of the stream, * so make sure we don't miss it! */ QMutexLocker listen_lock(&_listener_lock); if (!_stream_data_list.empty()) { StreamDataList::const_iterator sit = _stream_data_list.begin(); for (; sit != _stream_data_list.end(); ++sit) sit.key()->ProcessData(reinterpret_cast<const uint8_t *> (m_replay_buffer.constData()), m_replay_buffer.size()); } LOG(VB_RECORD, LOG_INFO, LOC + QString("Replayed %1 bytes") .arg(m_replay_buffer.size())); m_replay_buffer.clear(); m_replay = false; } if (!ProcessCommand("StartStreaming", 5000, result)) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("StartStreaming failed: '%1'") .arg(result)); if (!result.startsWith("Warn")) { _error = true; m_error = QString("StartStreaming failed: '%1'").arg(result); } return false; } if (result != "OK:Started") { LOG(VB_GENERAL, LOG_WARNING, LOC + QString("StartStreaming failed: '%1'").arg(result)); return false; } LOG(VB_RECORD, LOG_INFO, LOC + "Streaming started"); } else LOG(VB_RECORD, LOG_INFO, LOC + "Already streaming"); m_streaming_cnt.ref(); LOG(VB_RECORD, LOG_INFO, LOC + QString("StartStreaming %1 listeners") .arg(StreamingCount())); return true; }
void ExternalStreamHandler::run(void) { QString cmd; QString result; QString xon; QByteArray buffer; uint len; RunProlog(); LOG(VB_RECORD, LOG_INFO, LOC + "run(): begin"); SetRunning(true, true, false); if (m_poll_mode) xon = QString("SendBytes:%1").arg(PACKET_SIZE); else xon = "XON"; uint remainder = 0; while (_running_desired && !_error) { if (!IsOpen()) { if (!Open()) { LOG(VB_RECORD, LOG_WARNING, LOC + QString("TS not open yet: %1") .arg(m_error)); usleep(750000); continue; } } if (StreamingCount() == 0) { usleep(5000); continue; } UpdateFiltersFromStreamData(); ProcessCommand(xon, 1000, result); if (result.startsWith("ERR")) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("Aborting: %1 -> %2") .arg(xon).arg(result)); _error = true; } while ((len = m_IO->Read(buffer, PACKET_SIZE, 10)) > 0 || buffer.size() > 188*50) { if (m_IO->Error()) { m_error = m_IO->ErrorString(); _error = true; LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to read from Extern recorder: %1") .arg(m_error)); break; } if (!_running_desired) break; if (!_listener_lock.tryLock()) continue; if (_stream_data_list.empty()) { LOG(VB_GENERAL, LOG_ERR, LOC + "_stream_data_list is empty"); _listener_lock.unlock(); continue; } if (!m_poll_mode) { ProcessCommand(QString("XOFF"), 50, result); if (result.startsWith("ERR")) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("Aborting: %1 -> %2") .arg(xon).arg(result)); _error = true; } } StreamDataList::const_iterator sit = _stream_data_list.begin(); for (; sit != _stream_data_list.end(); ++sit) remainder = sit.key()->ProcessData (reinterpret_cast<const uint8_t *> (buffer.constData()), buffer.size()); _listener_lock.unlock(); len = buffer.size(); if (m_replay) { m_replay_buffer += buffer.left(len - remainder); if (m_replay_buffer.size() > (5000 * PACKET_SIZE)) { m_replay_buffer.remove(0, len - remainder); LOG(VB_RECORD, LOG_WARNING, LOC + QString("Replay size truncated to %1 bytes") .arg(m_replay_buffer.size())); } } if (remainder > 0 && (len > remainder)) // leftover bytes buffer.remove(0, len - remainder); else buffer.clear(); } usleep(10); } LOG(VB_RECORD, LOG_INFO, LOC + "run(): " + "shutdown"); RemoveAllPIDFilters(); SetRunning(false, true, false); LOG(VB_RECORD, LOG_INFO, LOC + "run(): " + "end"); RunEpilog(); }
void CetonStreamHandler::run(void) { RunProlog(); bool _error = false; QFile file(_device_path); CetonRTP rtp(_ip_address, _tuner); if (_using_rtp) { if (!(rtp.Init() && rtp.StartStreaming())) { LOG(VB_RECORD, LOG_ERR, LOC + "Starting recording (RTP initialization failed). Aborting."); _error = true; } } else { if (!file.open(QIODevice::ReadOnly)) { LOG(VB_RECORD, LOG_ERR, LOC + "Starting recording (file open failed). Aborting."); _error = true; } int flags = fcntl(file.handle(), F_GETFL, 0); if (flags == -1) flags = 0; fcntl(file.handle(), F_SETFL, flags | O_NONBLOCK); } if (_error) { RunEpilog(); return; } SetRunning(true, false, false); int buffer_size = (64 * 1024); // read about 64KB buffer_size /= TSPacket::kSize; buffer_size *= TSPacket::kSize; char *buffer = new char[buffer_size]; LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): begin"); _read_timer.start(); int remainder = 0; while (_running_desired && !_error) { int bytes_read; if (_using_rtp) bytes_read = rtp.Read(buffer, buffer_size); else bytes_read = file.read(buffer, buffer_size); if (bytes_read <= 0) { if (_read_timer.elapsed() >= 5000) { LOG(VB_RECORD, LOG_WARNING, LOC + "No data received for 5 seconds...checking tuning"); if (!VerifyTuning()) RepeatTuning(); _read_timer.start(); } usleep(5000); continue; } _read_timer.start(); _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( reinterpret_cast<unsigned char*>(buffer), bytes_read); _listener_lock.unlock(); if (remainder != 0) { LOG(VB_RECORD, LOG_INFO, LOC + QString("RunTS(): bytes_read = %1 remainder = %2") .arg(bytes_read).arg(remainder)); } } LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "shutdown"); if (_using_rtp) rtp.StopStreaming(); else file.close(); delete[] buffer; LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "end"); SetRunning(false, false, false); RunEpilog(); }
/** \fn HDHRStreamHandler::run(void) * \brief Reads HDHomeRun socket for tables & data */ void HDHRStreamHandler::run(void) { RunProlog(); /* Create TS socket. */ if (!hdhomerun_device_stream_start(_hdhomerun_device)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Starting recording (set target failed). Aborting."); _error = true; RunEpilog(); return; } hdhomerun_device_stream_flush(_hdhomerun_device); SetRunning(true, false, false); LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): begin"); int remainder = 0; QTime last_update; while (_running_desired && !_error) { int elapsed = !last_update.isValid() ? -1 : last_update.elapsed(); elapsed = (elapsed < 0) ? 1000 : elapsed; if (elapsed > 100) { UpdateFiltersFromStreamData(); if (_tune_mode != hdhrTuneModeVChannel) UpdateFilters(); last_update.restart(); } size_t read_size = 64 * 1024; // read about 64KB read_size /= VIDEO_DATA_PACKET_SIZE; read_size *= VIDEO_DATA_PACKET_SIZE; size_t data_length; unsigned char *data_buffer = hdhomerun_device_stream_recv( _hdhomerun_device, read_size, &data_length); if (!data_buffer) { usleep(20000); continue; } // Assume data_length is a multiple of 188 (packet size) _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(data_buffer, data_length); _listener_lock.unlock(); if (remainder != 0) { LOG(VB_RECORD, LOG_INFO, LOC + QString("RunTS(): data_length = %1 remainder = %2") .arg(data_length).arg(remainder)); } } LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "shutdown"); RemoveAllPIDFilters(); hdhomerun_device_stream_stop(_hdhomerun_device); LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "end"); SetRunning(false, false, false); RunEpilog(); }
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); }
/** \fn HDHRStreamHandler::run(void) * \brief Reads HDHomeRun socket for tables & data */ void HDHRStreamHandler::run(void) { threadRegister("HDHRStreamHandler"); /* Create TS socket. */ if (!hdhomerun_device_stream_start(_hdhomerun_device)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Starting recording (set target failed). Aborting."); _error = true; threadDeregister(); return; } hdhomerun_device_stream_flush(_hdhomerun_device); SetRunning(true, false, false); /* Calculate buffer size */ uint buffersize = gCoreContext->GetNumSetting( "HDRingbufferSize", 50 * TSPacket::kSize) * 1024; buffersize /= VIDEO_DATA_PACKET_SIZE; buffersize *= VIDEO_DATA_PACKET_SIZE; buffersize = max(49 * TSPacket::kSize * 128, buffersize); LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): begin"); int remainder = 0; while (_running_desired && !_error) { UpdateFiltersFromStreamData(); UpdateFilters(); size_t read_size = 64 * 1024; // read about 64KB read_size /= VIDEO_DATA_PACKET_SIZE; read_size *= VIDEO_DATA_PACKET_SIZE; size_t data_length; unsigned char *data_buffer = hdhomerun_device_stream_recv( _hdhomerun_device, read_size, &data_length); if (!data_buffer) { usleep(5000); continue; } // Assume data_length is a multiple of 188 (packet size) _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(data_buffer, data_length); _listener_lock.unlock(); if (remainder != 0) { LOG(VB_RECORD, LOG_INFO, LOC + QString("RunTS(): data_length = %1 remainder = %2") .arg(data_length).arg(remainder)); } } LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "shutdown"); RemoveAllPIDFilters(); hdhomerun_device_stream_stop(_hdhomerun_device); LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "end"); SetRunning(false, false, false); threadDeregister(); }
void V4L2encStreamHandler::run(void) { RunProlog(); LOG(VB_RECORD, LOG_INFO, LOC + "run() -- begin"); if (!IsOpen()) { LOG(VB_GENERAL, LOG_WARNING, LOC + "Starting stream handler, but v4l2 is not open!"); if (!Open()) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("run() -- Failed to open %1: ") .arg(_device) + ENO); _error = true; return; } } #if 0 // VBI if (m_vbi_fd >= 0) m_vbi_thread = new VBIThread(this); #endif bool good_data = false; bool gap = false; QDateTime gap_start; int len, remainder = 0; QByteArray buffer; char* pkt_buf = new char[PACKET_SIZE + 1]; SetRunning(true, true, false); while (_running_desired && !_error) { // Get V4L2 data if (m_streaming_cnt.load() == 0) { LOG(VB_RECORD, LOG_INFO, LOC + "Waiting for stream start."); QMutexLocker locker(&_start_stop_lock); _running_state_changed.wait(&_start_stop_lock, 5000); continue; } // Check for errors if (!m_drb) break; len = m_drb->Read(reinterpret_cast<unsigned char *>(pkt_buf), PACKET_SIZE); if (m_drb->IsErrored()) { LOG(VB_GENERAL, LOG_ERR, LOC + "run() -- Device error detected"); if (good_data) { if (gap) { /* Already processing a gap, which means * restarting the encoding didn't work! */ m_failing = true; } else gap = true; } RestartEncoding(); } else if (m_drb->IsEOF()) { LOG(VB_GENERAL, LOG_ERR, LOC + "run() -- Device EOF detected"); _error = true; } else { #if 0 // For this to work, the data needs to be propagated back up to // the 'recorder', but there could be multiple rcorders... // If we have seen good data, but now have a gap, note it if (good_data) { if (gap) { QMutexLocker locker(&statisticsLock); QDateTime gap_end(MythDate::current()); for (Irec = m_rec_gaps.begin(); Irec != m_rec_caps.end(); ++Irec) { (*Irec).push_back(RecordingGap (gap_start, gap_end)); } LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Inserted gap %1 dur %2") .arg(recordingGaps.back().toString()) .arg(gap_start.secsTo(gap_end))); gap = false; } else gap_start = MythDate::current(); } else good_data = true; #else good_data = true; #endif } if (len < 0) { if (errno != EAGAIN) LOG(VB_GENERAL, LOG_ERR, LOC + QString("run() -- error reading from: %1") .arg(_device) + ENO); continue; } buffer.append(pkt_buf, len); len = buffer.size(); if (len < static_cast<int>(TSPacket::kSize)) continue; if (!_listener_lock.tryLock()) continue; if (_stream_data_list.empty()) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("run() -- _stream_data_list is empty, %1 buffered") .arg(buffer.size())); _listener_lock.unlock(); continue; } StreamDataList::const_iterator sit = _stream_data_list.begin(); for (; sit != _stream_data_list.end(); ++sit) remainder = sit.key()->ProcessData (reinterpret_cast<const uint8_t *> (buffer.constData()), len); _listener_lock.unlock(); if (remainder > 0 && (len > remainder)) // leftover bytes buffer.remove(0, len - remainder); else buffer.clear(); } QString tmp(_error); LOG(VB_GENERAL, LOG_WARNING, LOC + QString("_running_desired(%1) _error(%2)") .arg(_running_desired).arg(tmp)); LOG(VB_RECORD, LOG_INFO, LOC + "run() -- finishing up"); StopEncoding(); delete[] pkt_buf; SetRunning(false, true, false); RunEpilog(); LOG(VB_RECORD, LOG_INFO, LOC + "run() -- end"); }