Example #1
0
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;
}