Qt::QMediaPlayer: 如何禁用帧缓冲以减少 RTSP 流延迟或等待时间?

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

当我用C++的Qt的QMediaPlayer播放RTSP流时,它总是在缓冲状态达到100帧后才显示帧。这通常会延迟 3~5 秒。

如何禁用缓冲或将缓冲区设置为零以推断延迟?关于这个问题,我无法用 QMediaPlayer 做任何事情。

需要你的帮助...

cpp代码:

#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();
}

.h 文件:

#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

终于!

经过大量的搜索和尝试,我终于找到了一种解决这个问题的奇怪方法:

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();
}

没有人会想到使用这种方法来阻止 RTSP 缓冲。

希望下一个版本的QMediaPlayer有一个更人性化的界面来解决这个问题。