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; }
bool V4L2encStreamHandler::StartEncoding(void) { LOG(VB_RECORD, LOG_INFO, LOC + "StartEncoding() -- begin"); int old_cnt; QMutexLocker lock(&m_stream_lock); if (!IsOpen()) { LOG(VB_GENERAL, LOG_ERR, LOC + "V4L2 recorder not initialized."); return false; } if ((old_cnt = m_streaming_cnt.load()) == 0) { // Start encoding LOG(VB_GENERAL, LOG_INFO, LOC + QString("Streaming mode %1. Not using it.") .arg(m_v4l2.HasStreaming() ? "available" : "not available")); if (!m_v4l2.UserAdjustableResolution()) { for (int idx = 0; idx < 10; ++idx) { if (SetBitrateForResolution()) break; } } if (m_pause_encoding_allowed) m_pause_encoding_allowed = m_v4l2.ResumeEncoding(); if (!m_pause_encoding_allowed) m_v4l2.StartEncoding(); // (at least) with the 3.10 kernel, the V4L2_ENC_CMD_START does // not reliably start the data flow from a HD-PVR. A read() seems // to work, though. int idx = 1; for ( ; idx < 50; ++idx) { uint8_t dummy; int len = read(m_fd, &dummy, 0); if (len >= 0) { LOG(VB_GENERAL, LOG_WARNING, LOC + QString("StartEncoding read %1 bytes").arg(len)); break; } if (idx == 20) { LOG(VB_GENERAL, LOG_ERR, LOC + "StartEncoding: read failing, re-opening device: " + ENO); close(m_fd); std::this_thread::sleep_for(std::chrono::milliseconds(2)); m_fd = open(_device.toLatin1().constData(), O_RDWR | O_NONBLOCK); if (m_fd < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "StartEncoding: Can't open video device." + ENO); m_error = "Failed to start recording"; return false; } } else { LOG(VB_GENERAL, LOG_ERR, LOC + QString("StartEncoding: read failed, retry in %1 msec:") .arg(100 * idx) + ENO); std::this_thread::sleep_for(std::chrono::microseconds(idx * 100)); } } if (idx == 50) { LOG(VB_GENERAL, LOG_ERR, LOC + "StartEncoding: read from video device failed." + ENO); m_error = "Failed to start recording"; close(m_fd); m_fd = -1; return false; } if (idx > 0) { LOG(VB_RECORD, LOG_WARNING, LOC + QString("%1 read attempts required to start encoding").arg(idx)); } if (m_drb) { m_drb->SetRequestPause(false); m_drb->Start(); } } else LOG(VB_RECORD, LOG_INFO, LOC + "Already encoding"); QMutexLocker listen_lock(&_listener_lock); m_streaming_cnt.ref(); LOG(VB_RECORD, LOG_INFO, LOC + QString("StartEncoding() -- %1->%2 listeners") .arg(old_cnt).arg(m_streaming_cnt.load())); LOG(VB_RECORD, LOG_INFO, LOC + "StartEncoding() -- end"); return true; }