Search code examples
c++qtrtspqmediaplayer

Qt::QMediaPlayer: how to disable frame buffering to reduce the RTSP streaming delay or latency?


When I use QMediaPlayer of Qt with C++ to play a RTSP stream, it always shows frames only after the buffer state is up to 100 frames. This normally make 3~5 seconds delay.

How to disable buffering or set the buffer to zero to deduce the latency? There is nothing I can do with QMediaPlayer about this issue.

Need your help...

The cpp code:

#include "stdafx.h"
#include <QVideoSurfaceFormat>
//#include "Qxtglobalshortcut/QxtGlobalShortcut.h"
#include "qnetworkinterface.h"
#include "AmbaRemoteCam.h"
#include "controls/AliceMessageBox.hpp"

#include "cam_cali/cam_cali.h"
#include "camera/camera.h"
using namespace Cam;

AmbaRemoteCam::AmbaRemoteCam(QWidget* parent)
    : QMainWindow(parent)
    , m_titleBar(nullptr)
    , m_trayIcon(nullptr)
{
    // layout
    m_mainLayout = new(std::nothrow) QVBoxLayout();
    m_mainLayout->setContentsMargins(20, 20, 20, 20);
    m_mainLayout->setSpacing(10);

    // Settings
    m_mainLayout->addWidget(new MLabel(tr("Settings:")));
    m_video_view = nullptr;
    {
        MLabel* label = new MLabel(tr("RTSP Video:"));
        m_mediaUrl = new MEditor(CAM_DEFAULT_RTSP);
        m_btnConnectRtsp = new QPushButton(tr("Connect"));
        m_btnConnectRtsp->setObjectName("normal_button");
        m_btnConnectRtsp->setFixedSize(100, 30);
        connect(m_btnConnectRtsp, SIGNAL(clicked()), this, SLOT(slot_btnConnectRtsp_Clicked()));

        QHBoxLayout* layout0 = new QHBoxLayout();
        layout0->setContentsMargins(20, 0, 0, 0);
        layout0->setSpacing(10);
        layout0->addWidget(label);
        layout0->addWidget(m_mediaUrl);
        layout0->addWidget(m_btnConnectRtsp);

        m_video_view = new QVideoWidget();
        m_video_view->setObjectName("video_widget");
        m_video_view->setFixedSize(1280, 724);
        m_video_view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        m_player = new QMediaPlayer(/*m_video_view, QMediaPlayer::LowLatency*/);
        m_player->setVideoOutput(m_video_view);
        connect(m_player, &QMediaPlayer::mediaStatusChanged, this, &AmbaRemoteCam::slot_mediaStateChanged);
        connect(m_player, &QMediaPlayer::positionChanged, this, &AmbaRemoteCam::slot_positionChanged);

        m_mainLayout->addLayout(layout0);
        m_mainLayout->addWidget(m_video_view);
    }

    m_msgPos = nullptr;
    {
        QHBoxLayout* layout = new QHBoxLayout();
        layout->setSpacing(10);

        m_msgStat = new MLabel("");
        layout->addWidget(new MLabel(tr("Play State: ")));
        layout->addWidget(m_msgStat);

        m_msgPos = new MLabel("");
        layout->addWidget(new MLabel(tr("Play Pos: ")));
        layout->addWidget(m_msgPos);

        m_msgRate = new MLabel("");
        layout->addWidget(new MLabel(tr("Rate: ")));
        layout->addWidget(m_msgRate);

        m_msgBufferStatus = new MLabel("");
        layout->addWidget(new MLabel(tr("BufferStatus: ")));
        layout->addWidget(m_msgBufferStatus);

        m_msgError = new MLabel("");
        layout->addWidget(new MLabel(tr("Error: ")));
        layout->addWidget(m_msgError);

        layout->addStretch();

        m_mainLayout->addLayout(layout);
    }

    m_mainLayout->addStretch();

    // UI
    ui.setupUi(this);

    // Set the mainLayout as the root layout
    ui.centralWidget->setObjectName("widget_main_window");
    ui.centralWidget->setLayout(m_mainLayout);

    // windows icon
    setWindowIcon(QIcon(":/AmbaRemoteCam/Resources/alice.png"));

    retranslateUi();
}

AmbaRemoteCam::~AmbaRemoteCam()
{
}

void AmbaRemoteCam::retranslateUi()
{
    //m_fullScreenBtn->setToolTip(tr("Full Screen")); 
}

void AmbaRemoteCam::slot_mediaStateChanged(QMediaPlayer::MediaStatus state)
{
    const char* MediaStatusString[]=
    {
        "UnknownMediaStatus",
        "NoMedia",
        "LoadingMedia",
        "LoadedMedia",
        "StalledMedia",
        "BufferingMedia",
        "BufferedMedia",
        "EndOfMedia",
        "InvalidMedia"
    };

    printf("slot_mediaStateChanged, MediaStatus:%s\n", MediaStatusString[state]);
    m_msgStat->setText(QString(MediaStatusString[state]));
    m_msgError->setText(m_player->errorString());
}

void AmbaRemoteCam::slot_positionChanged(qint64 position)
{
    printf("slot_positionChanged, position: %ld\n", position);
    m_msgPos->setText(QString::number(position));
    m_msgRate->setText(QString::number(m_player->playbackRate()));
    m_msgBufferStatus->setText(QString::number(m_player->bufferStatus()));
}

void AmbaRemoteCam::slot_btnConnectRtsp_Clicked()
{
    m_player->setMedia(QUrl(m_mediaUrl->text()));
    m_player->setPlaybackRate(60);
    m_player->play();
}

The .h file:

#ifndef AMBAREMOTECAM_H
#define AMBAREMOTECAM_H

#include <QtWidgets/QMainWindow>
#include <QtWidgets>
#include <QLayout>
#include <QToolBar>
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QVideoWidget>
#include "ui_AmbaRemoteCam.h"
#include "MEditor.hpp"
#include "mlabel.hpp"

#include "_inl.hpp"

class AmbaRemoteCam : public QMainWindow
{
    Q_OBJECT
public:
    AmbaRemoteCam(QWidget *parent = 0);
    ~AmbaRemoteCam();

signals:

public slots:
    void slot_mediaStateChanged(QMediaPlayer::MediaStatus state);
    void slot_positionChanged(qint64 position);
    void slot_btnConnectRtsp_Clicked();

private:
    void retranslateUi();

private:
    QVBoxLayout* m_mainLayout;
    Ui::AmbaRemoteCamClass ui;

    QVideoWidget* m_video_view;
    QMediaPlayer* m_player;
    MEditor* m_mediaUrl;
    QPushButton* m_btnConnectRtsp;
    MLabel* m_msgStat;
    MLabel* m_msgRate;
    MLabel* m_msgBufferStatus;
    MLabel* m_msgPos;
    MLabel* m_msgError;
};

#endif


Solution

  • Finally!

    After a lots of seaching and trying, I finally found a kind of weird way to fix this issue:

    Using 'setPlaybackRate()' to set playback rate to zero, other then a value bigger than the real fps to prevent the RTSP buffering.

    void AmbaRemoteCam::slot_btnConnectRtsp_Clicked()
    {
        m_player->setMedia(QUrl(m_mediaUrl->text()));
        m_player->setPlaybackRate(0);
        m_player->play();
    }
    

    Nobody would think of using this method to prevent the RTSP buffering.

    Hope next version of QMediaPlayer has a more humane interface to fix this issue.