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有一个更人性化的界面来解决这个问题。
当我用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有一个更人性化的界面来解决这个问题。