Update MediaClient

This commit is contained in:
2026-03-28 11:39:04 +11:00
parent 24dc6c7cd0
commit f3266566eb
1284 changed files with 462406 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "About.h"
#include "config.h"
About::About(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
ui.labVersion->setText(QString("Happytime Media Client %1").arg(VERSION_STRING));
connect(ui.btnOK, SIGNAL(clicked()), this, SLOT(close()));
showMaximized();
}
About::~About()
{
}

View File

@@ -0,0 +1,41 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#ifndef _ABOUT_H_
#define _ABOUT_H_
#include <QDialog>
#include "ui_About.h"
class About : public QDialog
{
Q_OBJECT
public:
About(QWidget *parent = 0);
~About();
private:
Ui::About ui;
};
#endif

View File

@@ -0,0 +1,186 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "FileBrowse.h"
#include "ui_FileBrowse.h"
#include "utils.h"
#include "config.h"
#include <QUrl>
#include <QDesktopServices>
#include <QMessageBox>
#include <QFile>
#include <QDir>
#include <QProcess>
#include <QScreen>
#include <QApplication>
#if defined(ANDROID)
#include <QJniObject>
#elif defined(IOS)
#include <ios/ios_launcher.h>
#endif
FileBrowse::FileBrowse(int fileFormat, QWidget *parent)
: QDialog(parent)
, ui(new Ui::FileBrowse)
, m_bEditing(false)
, m_fileFormat(fileFormat)
{
ui->setupUi(this);
initDialog();
connSignalSlot();
}
FileBrowse::~FileBrowse()
{
delete ui;
}
void FileBrowse::initDialog()
{
QStringList filters;
if (m_fileFormat == FILE_FORMAT_PIC)
{
filters << "*.jpg";
m_basePath = getSnapshotPath();
ui->labTips->setText(tr("Album"));
}
else
{
filters << "*.mp4";
filters << "*.avi";
m_basePath = getRecordPath();
ui->labTips->setText(tr("Video"));
}
ui->labPath->setText(tr("Path") + QString(" : ") + m_basePath);
m_pModel = new FileListModel(m_fileFormat, this);
m_pModel->setNameFilters(filters);
m_pModel->setDirPath(m_basePath);
ui->chkAll->setVisible(false);
ui->fileList->setModel(m_pModel);
showMaximized();
}
void FileBrowse::connSignalSlot()
{
QObject::connect(ui->btnBack, SIGNAL(clicked()), this, SLOT(slotBack()));
QObject::connect(ui->btnEdit, SIGNAL(clicked()), this, SLOT(slotEdit()));
QObject::connect(ui->chkAll, SIGNAL(clicked(bool)), this, SLOT(slotCheckAll(bool)));
QObject::connect(ui->fileList, SIGNAL(clicked(QModelIndex)), this, SLOT(slotItemClicked(QModelIndex)));
}
void FileBrowse::slotBack()
{
close();
}
void FileBrowse::slotEdit()
{
if (!m_bEditing)
{
m_bEditing = true;
ui->chkAll->setVisible(true);
m_pModel->setCheckable(true);
}
else
{
deleteSelectedFiles();
m_bEditing = false;
ui->chkAll->setVisible(false);
m_pModel->setCheckable(false);
}
}
void FileBrowse::slotCheckAll(bool flag)
{
int row = m_pModel->rowCount();
QModelIndex index;
for (int i = 0; i < row; i++)
{
index = m_pModel->index(i);
m_pModel->setData(index, flag, Qt::CheckStateRole);
}
}
void FileBrowse::slotItemClicked(QModelIndex index)
{
if (m_bEditing)
{
int flag = m_pModel->data(index, Qt::CheckStateRole).toInt();
if (flag == Qt::Checked)
{
m_pModel->setData(index, false, Qt::CheckStateRole);
}
else
{
m_pModel->setData(index, true, Qt::CheckStateRole);
}
}
else
{
QString name = m_pModel->data(index, Qt::DisplayRole).toString();
QString path = m_basePath + "/" + name;
#if defined(ANDROID)
QJniObject str = QJniObject::fromString(path);
QJniObject provider = QJniObject::fromString(FILE_PROVIDER);
QJniObject::callStaticMethod<void>("org/happytimesoft/util/HtUtil",
"openFile",
"(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V",
QNativeInterface::QAndroidApplication::context(),
str.object<jstring>(),
provider.object<jstring>());
#elif defined(IOS)
iosLaunchFile(path);
#endif
}
}
void FileBrowse::deleteSelectedFiles()
{
int flag;
int row = m_pModel->rowCount();
QModelIndex index;
for (int i = row - 1; i >= 0; i--)
{
index = m_pModel->index(i);
flag = m_pModel->data(index, Qt::CheckStateRole).toInt();
if (flag == Qt::Checked)
{
QString name = m_pModel->data(index, Qt::DisplayRole).toString();
QString path = m_basePath + "/" + name;
QFile::remove(path);
m_pModel->removeRows(i, 1, index.parent());
}
}
}

View File

@@ -0,0 +1,60 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#ifndef FILEBROWSE_H
#define FILEBROWSE_H
#include <QDialog>
#include "FileListModel.h"
namespace Ui {
class FileBrowse;
}
class FileBrowse : public QDialog
{
Q_OBJECT
public:
explicit FileBrowse(int fileFormat, QWidget *parent = 0);
~FileBrowse();
private slots:
void slotBack();
void slotEdit();
void slotCheckAll(bool flag);
void slotItemClicked(QModelIndex);
private:
void initDialog();
void connSignalSlot();
void deleteSelectedFiles();
private:
Ui::FileBrowse *ui;
QString m_basePath;
bool m_bEditing;
FileListModel * m_pModel;
int m_fileFormat;
};
#endif // FILEBROWSE_H

View File

@@ -0,0 +1,50 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "InstMsgDialog.h"
#include "ui_InstMsgDialog.h"
#include <QTimer>
#include <QGuiApplication>
#include <QScreen>
#include "utils.h"
InstMsgDialog::InstMsgDialog(QString msg, int timelen, QWidget *parent)
: QDialog(parent)
, ui(new Ui::InstMsgDialog)
{
ui->setupUi(this);
QRect rect = this->rect();
rect.setWidth(QGuiApplication::primaryScreen()->geometry().width());
rect.setHeight(40);
setGeometry(rect);
ui->labMsg->setText(msg);
QTimer::singleShot(timelen, this, SLOT(close()));
}
InstMsgDialog::~InstMsgDialog()
{
delete ui;
}

View File

@@ -0,0 +1,43 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#ifndef INSTMSGDIALOG_H
#define INSTMSGDIALOG_H
#include <QDialog>
namespace Ui {
class InstMsgDialog;
}
class InstMsgDialog : public QDialog
{
Q_OBJECT
public:
explicit InstMsgDialog(QString msg, int timelen, QWidget *parent = 0);
~InstMsgDialog();
private:
Ui::InstMsgDialog *ui;
};
#endif // INSTMSGDIALOG_H

View File

@@ -0,0 +1,863 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "MediaClient.h"
#include "InstMsgDialog.h"
#include "OpenMedia.h"
#include "config.h"
#include "FileBrowse.h"
#include "About.h"
#include "utils.h"
#include "SystemSetting.h"
#include "rtsp_cln.h"
#include "rtmp_cln.h"
#include "http_flv_cln.h"
#include "http_mjpeg_cln.h"
#include "srt_cln.h"
#include <QScreen>
#include <QTransform>
#include <QMessageBox>
#include <QDesktopServices>
#include <QStandardPaths>
#if defined(ANDROID)
#include <QJniObject>
#endif
MediaClient::MediaClient(QWidget *parent, Qt::WindowFlags flags)
: QDialog(parent, flags)
, m_curWidget(NULL)
, m_recvBytes(0)
{
ui.setupUi(this);
initDialog();
connSignalSlot();
}
MediaClient::~MediaClient()
{
QList<CHANNEL> channels;
saveChannel(channels, ui.videoWidget1);
saveChannel(channels, ui.videoWidget2);
saveChannel(channels, ui.videoWidget3);
saveChannel(channels, ui.videoWidget4);
saveChannel(channels, ui.videoWidget5);
saveChannel(channels, ui.videoWidget6);
saveChannel(channels, ui.videoWidget7);
saveChannel(channels, ui.videoWidget8);
saveChannel(channels, ui.videoWidget9);
saveChannels(channels);
saveLayoutMode(m_layoutMode);
ui.videoWidget1->stop();
ui.videoWidget2->stop();
ui.videoWidget3->stop();
ui.videoWidget4->stop();
ui.videoWidget5->stop();
ui.videoWidget6->stop();
ui.videoWidget7->stop();
ui.videoWidget8->stop();
ui.videoWidget9->stop();
#if defined(ANDROID)
QJniObject::callStaticMethod<void>("org/happytimesoft/util/HtUtil", "enableLockScreen");
#endif
log_close();
QDesktopServices::openUrl(QUrl("https://www.happytimesoft.com/", QUrl::TolerantMode));
}
void MediaClient::saveChannel(QList<CHANNEL> &channels, VideoWidget * widget)
{
CHANNEL channel;
if (widget->isPlaying())
{
channel.url = widget->getUrl();
channel.user = widget->getUser();
channel.pass = widget->getPass();
}
else
{
channel.url = "";
channel.user = "";
channel.pass = "";
}
channels.append(channel);
}
void MediaClient::closeEvent(QCloseEvent * event)
{
if (QMessageBox::Yes == QMessageBox::question(this, tr("Quit"), tr("Are you sure want to quit?")))
{
event->accept();
}
else
{
event->ignore();
}
}
void MediaClient::initLog()
{
char file[512] = {'\0'};
QString path = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).last();
sprintf(file, "%s/mediaclient.log", path.toStdString().c_str());
log_init(file);
}
void MediaClient::initDialog()
{
setWindowTitle(QString("Happytime media client %1").arg(VERSION_STRING));
#if defined(ANDROID)
QJniObject str = QJniObject::fromString("android.permission.WRITE_EXTERNAL_STORAGE");
QJniObject::callStaticMethod<jint>("org/happytimesoft/util/HtUtil",
"requestPermission",
"(Landroid/content/Context;Ljava/lang/String;)I",
QNativeInterface::QAndroidApplication::context(),
str.object<jstring>());
#endif
loadSystemConfig();
if (m_syscfg.enableLog)
{
initLog();
log_set_level(m_syscfg.logLevel);
}
ui.labTipInfo->setText("");
ui.labStatistics->setText("");
ui.cmbLayout->addItem(QIcon(":/res/Resources/1.png"), "1", 1);
ui.cmbLayout->addItem(QIcon(":/res/Resources/2.png"), "2", 2);
ui.cmbLayout->addItem(QIcon(":/res/Resources/4.png"), "4", 4);
ui.cmbLayout->addItem(QIcon(":/res/Resources/6.png"), "6", 6);
ui.cmbLayout->addItem(QIcon(":/res/Resources/9.png"), "9", 9);
QScreen * pScreen = QApplication::primaryScreen();
setupLayout(pScreen->orientation());
connect(pScreen, SIGNAL(orientationChanged(Qt::ScreenOrientation)),
this, SLOT(slotOrientationChanged(Qt::ScreenOrientation)));
if (1 == m_syscfg.layoutMode)
{
slotLayoutOne();
ui.cmbLayout->setCurrentIndex(0);
}
else if (2 == m_syscfg.layoutMode)
{
slotLayoutTwo();
ui.cmbLayout->setCurrentIndex(1);
}
else if (6 == m_syscfg.layoutMode)
{
slotLayoutSix();
ui.cmbLayout->setCurrentIndex(3);
}
else if (9 == m_syscfg.layoutMode)
{
slotLayoutNine();
ui.cmbLayout->setCurrentIndex(4);
}
else
{
slotLayoutFour();
ui.cmbLayout->setCurrentIndex(2);
}
m_curWidget = ui.videoWidget1;
m_curWidget->parentWidget()->setStyleSheet("background-color: blue;");
// when video playing, prevent auto lock screen
#if defined(ANDROID)
QJniObject::callStaticMethod<void>("org/happytimesoft/util/HtUtil",
"disableLockScreen",
"(Landroid/content/Context;)V",
QNativeInterface::QAndroidApplication::context());
#endif
loadChannels();
#ifndef IOS
ui.btnQuit->hide();
#endif
}
void MediaClient::connSignalSlot()
{
connect(ui.cmbLayout, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLayoutChanged(int)));
connect(ui.btnPlay, SIGNAL(clicked()), this, SLOT(slotPlay()));
connect(ui.btnPause, SIGNAL(clicked()), this, SLOT(slotPause()));
connect(ui.btnStop, SIGNAL(clicked()), this, SLOT(slotStop()));
connect(ui.btnSnapshot, SIGNAL(clicked()), this, SLOT(slotSnapshot()));
connect(ui.btnRecord, SIGNAL(clicked()), this, SLOT(slotRecord()));
connect(ui.btnVolume, SIGNAL(clicked()), this, SLOT(slotVolume()));
connect(ui.btnSetting, SIGNAL(clicked()), this, SLOT(slotSystemSetting()));
connect(ui.btnOpenSnapshot, SIGNAL(clicked()), this, SLOT(slotOpenSnapshot()));
connect(ui.btnOpenRecord, SIGNAL(clicked()), this, SLOT(slotOpenRecording()));
connect(ui.btnAbout, SIGNAL(clicked()), this, SLOT(slotAbout()));
connect(ui.btnQuit, SIGNAL(clicked()), this, SLOT(close()));
connVideoWidget(ui.videoWidget1);
connVideoWidget(ui.videoWidget2);
connVideoWidget(ui.videoWidget3);
connVideoWidget(ui.videoWidget4);
connVideoWidget(ui.videoWidget5);
connVideoWidget(ui.videoWidget6);
connVideoWidget(ui.videoWidget7);
connVideoWidget(ui.videoWidget8);
connVideoWidget(ui.videoWidget9);
}
void MediaClient::connVideoWidget(VideoWidget * widget)
{
connect(widget, SIGNAL(snapshotResult(bool)), this, SLOT(slotSnapshotResult(bool)));
connect(widget, SIGNAL(recordResult(bool)), this, SLOT(slotRecordResult(bool)));
connect(widget, SIGNAL(updateStatistics(int)), this, SLOT(slotUpdateStatistics(int)));
connect(widget, SIGNAL(widgetSelecting(QWidget*)), this, SLOT(slotWidgetSelecting(QWidget*)));
connect(widget, SIGNAL(callState(QWidget*,int)), this, SLOT(slotCallState(QWidget*,int)));
}
void MediaClient::loadSystemConfig()
{
m_syscfg.enableLog = getEnableLogFlag();
m_syscfg.videoRenderMode = getVideoRenderMode();
m_syscfg.rtpMulticast = getRtpMulticast();
m_syscfg.rtpOverUdp = getRtpOverUdp();
m_syscfg.rtspOverHttp = getRtspOverHttp();
m_syscfg.rtspOverHttpPort = getRtspOverHttpPort();
m_syscfg.rtspOverWs = getRtspOverWs();
m_syscfg.rtspOverWsPort = getRtspOverWsPort();
m_syscfg.logLevel = getLogLevel();
m_syscfg.hwDecoding = getHWDecoding();
m_syscfg.layoutMode = getLayoutMode();
m_syscfg.recordTime = getRecordTime();
m_syscfg.recordSize = getRecordSize();
}
void MediaClient::loadChannels()
{
QList<CHANNEL> channels;
getChannels(channels);
if (channels.size() > 0 && !channels[0].url.isEmpty())
{
ui.videoWidget1->play(channels[0].url, channels[0].user, channels[0].pass);
}
if (channels.size() > 1 && !channels[1].url.isEmpty())
{
ui.videoWidget2->play(channels[1].url, channels[1].user, channels[1].pass);
}
if (channels.size() > 2 && !channels[2].url.isEmpty())
{
ui.videoWidget3->play(channels[2].url, channels[2].user, channels[2].pass);
}
if (channels.size() > 3 && !channels[3].url.isEmpty())
{
ui.videoWidget4->play(channels[3].url, channels[3].user, channels[3].pass);
}
if (channels.size() > 4 && !channels[4].url.isEmpty())
{
ui.videoWidget5->play(channels[4].url, channels[4].user, channels[4].pass);
}
if (channels.size() > 5 && !channels[5].url.isEmpty())
{
ui.videoWidget6->play(channels[5].url, channels[5].user, channels[5].pass);
}
if (channels.size() > 6 && !channels[6].url.isEmpty())
{
ui.videoWidget7->play(channels[6].url, channels[6].user, channels[6].pass);
}
if (channels.size() > 7 && !channels[7].url.isEmpty())
{
ui.videoWidget8->play(channels[7].url, channels[7].user, channels[7].pass);
}
if (channels.size() > 8 && !channels[8].url.isEmpty())
{
ui.videoWidget9->play(channels[8].url, channels[8].user, channels[8].pass);
}
}
void MediaClient::slotLayoutOne()
{
ui.widget1->show();
ui.widget2->hide();
ui.widget3->hide();
ui.widget4->hide();
ui.widget5->hide();
ui.widget6->hide();
ui.widget7->hide();
ui.widget8->hide();
ui.widget9->hide();
m_layoutMode = 1;
}
void MediaClient::slotLayoutTwo()
{
QScreen * pScreen = QApplication::primaryScreen();
Qt::ScreenOrientation orientation = pScreen->orientation();
if (orientation == Qt::LandscapeOrientation ||
orientation == Qt::InvertedLandscapeOrientation) // width > height
{
ui.widget1->show();
ui.widget2->show();
ui.widget3->hide();
ui.widget4->hide();
ui.widget5->hide();
ui.widget6->hide();
ui.widget7->hide();
ui.widget8->hide();
ui.widget9->hide();
}
else
{
ui.widget1->show();
ui.widget2->hide();
ui.widget3->hide();
ui.widget4->show();
ui.widget5->hide();
ui.widget6->hide();
ui.widget7->hide();
ui.widget8->hide();
ui.widget9->hide();
}
m_layoutMode = 2;
}
void MediaClient::slotLayoutFour()
{
ui.widget1->show();
ui.widget2->show();
ui.widget3->hide();
ui.widget4->show();
ui.widget5->show();
ui.widget6->hide();
ui.widget7->hide();
ui.widget8->hide();
ui.widget9->hide();
m_layoutMode = 4;
}
void MediaClient::slotLayoutSix()
{
QScreen * pScreen = QApplication::primaryScreen();
Qt::ScreenOrientation orientation = pScreen->orientation();
if (orientation == Qt::LandscapeOrientation ||
orientation == Qt::InvertedLandscapeOrientation) // width > height
{
ui.widget1->show();
ui.widget2->show();
ui.widget3->show();
ui.widget4->show();
ui.widget5->show();
ui.widget6->show();
ui.widget7->hide();
ui.widget8->hide();
ui.widget9->hide();
}
else
{
ui.widget1->show();
ui.widget2->show();
ui.widget3->hide();
ui.widget4->show();
ui.widget5->show();
ui.widget6->hide();
ui.widget7->show();
ui.widget8->show();
ui.widget9->hide();
}
m_layoutMode = 6;
}
void MediaClient::slotLayoutNine()
{
ui.widget1->show();
ui.widget2->show();
ui.widget3->show();
ui.widget4->show();
ui.widget5->show();
ui.widget6->show();
ui.widget7->show();
ui.widget8->show();
ui.widget9->show();
m_layoutMode = 9;
}
void MediaClient::slotLayoutChanged(int index)
{
if (0 == index)
{
slotLayoutOne();
}
else if (1 == index)
{
slotLayoutTwo();
}
else if (2 == index)
{
slotLayoutFour();
}
else if (3 == index)
{
slotLayoutSix();
}
else if (4 == index)
{
slotLayoutNine();
}
}
void MediaClient::slotWidgetSelecting(QWidget * pWidget)
{
if (m_curWidget != pWidget)
{
m_curWidget->parentWidget()->setStyleSheet("background-color: white;");
m_curWidget = (VideoWidget *) pWidget;
m_curWidget->parentWidget()->setStyleSheet("background-color: blue;");
if (m_curWidget->isRecording())
{
ui.labTipInfo->setText(tr("Recording ..."));
QIcon icon;
icon.addFile(QString(":/res/Resources/stop_record.png"));
ui.btnRecord->setIcon(icon);
}
else
{
ui.labTipInfo->setText("");
QIcon icon;
icon.addFile(QString(":/res/Resources/video_record.png"));
ui.btnRecord->setIcon(icon);
}
if (m_curWidget->isMute())
{
ui.btnVolume->setIcon(QIcon(QString::fromUtf8(":/res/Resources/mute.png")));
}
else
{
ui.btnVolume->setIcon(QIcon(QString::fromUtf8(":/res/Resources/volume.png")));
}
}
}
void MediaClient::slotPlay()
{
QString url = m_curWidget->getUrl();
QString user = m_curWidget->getUser();
QString pass = m_curWidget->getPass();
if (url.isEmpty())
{
url = m_url;
user = m_user;
pass = m_pass;
}
OpenMedia dlg(url, user, pass, this);
dlg.resize(width(), dlg.height());
if (QDialog::Accepted == dlg.exec())
{
m_url = dlg.getUrl();
m_user = dlg.getUser();
m_pass = dlg.getPass();
m_curWidget->play(m_url, m_user, m_pass);
}
}
void MediaClient::slotPause()
{
m_curWidget->pause();
}
void MediaClient::slotStop()
{
m_curWidget->stop();
ui.labTipInfo->setText(tr(""));
ui.btnVolume->setIcon(QIcon(QString::fromUtf8(":/res/Resources/volume.png")));
ui.btnRecord->setIcon(QIcon(QString::fromUtf8(":/res/Resources/video_record.png")));
}
void MediaClient::slotCallState(QWidget* pWidget, int event)
{
if (m_curWidget != pWidget)
{
return;
}
if (event == RTSP_EVE_CONNECTING ||
event == RTMP_EVE_CONNECTING ||
event == HTTP_FLV_EVE_CONNECTING ||
event == MJPEG_EVE_CONNECTING ||
event == SRT_EVE_CONNECTING)
{
ui.labTipInfo->setText(tr("Connecting..."));
}
else if (event == RTSP_EVE_CONNFAIL ||
event == RTMP_EVE_CONNFAIL ||
event == HTTP_FLV_EVE_CONNFAIL ||
event == MJPEG_EVE_CONNFAIL ||
event == SRT_EVE_CONNFAIL)
{
ui.labTipInfo->setText(tr("Connect failed"));
}
else if (event == RTSP_EVE_CONNSUCC ||
event == MJPEG_EVE_CONNSUCC ||
event == RTMP_EVE_VIDEOREADY ||
event == RTMP_EVE_AUDIOREADY ||
event == HTTP_FLV_EVE_VIDEOREADY ||
event == HTTP_FLV_EVE_AUDIOREADY ||
event == SRT_EVE_VIDEOREADY ||
event == SRT_EVE_AUDIOREADY)
{
ui.labTipInfo->setText(tr(""));
}
else if (event == RTSP_EVE_NOSIGNAL ||
event == RTMP_EVE_NOSIGNAL ||
event == HTTP_FLV_EVE_NOSIGNAL ||
event == MJPEG_EVE_NOSIGNAL ||
event == SRT_EVE_NOSIGNAL)
{
ui.labTipInfo->setText(tr("NO Signal"));
}
else if (event == RTSP_EVE_NODATA ||
event == RTMP_EVE_NODATA ||
event == HTTP_FLV_EVE_NODATA ||
event == MJPEG_EVE_NODATA ||
event == SRT_EVE_NODATA)
{
ui.labTipInfo->setText(tr("No Data"));
}
else if (event == RTSP_EVE_RESUME ||
event == RTMP_EVE_RESUME ||
event == HTTP_FLV_EVE_RESUME ||
event == MJPEG_EVE_RESUME ||
event == SRT_EVE_RESUME)
{
ui.labTipInfo->setText(tr(""));
}
else if (event == RTSP_EVE_AUTHFAILED ||
event == RTMP_EVE_AUTHFAILED||
event == HTTP_FLV_EVE_AUTHFAILED ||
event == MJPEG_EVE_AUTHFAILED ||
event == SRT_EVE_AUTHFAILED)
{
ui.labTipInfo->setText(tr("Authenticate failed"));
}
}
void MediaClient::slotSnapshot()
{
m_curWidget->snapshot();
}
void MediaClient::slotRecord()
{
m_curWidget->record();
if (m_curWidget->isRecording())
{
ui.labTipInfo->setText(tr(" Recording ..."));
ui.btnRecord->setIcon(QIcon(QString::fromUtf8(":/res/Resources/stop_record.png")));
}
else
{
ui.labTipInfo->setText("");
ui.btnRecord->setIcon(QIcon(QString::fromUtf8(":/res/Resources/video_record.png")));
}
}
void MediaClient::slotSnapshotResult(bool ret)
{
QString msg;
if (ret)
{
msg = tr("Snapshot success");
}
else
{
msg = tr("Snapshot failed");
}
InstMsgDialog dlg(msg, 2000);
dlg.exec();
}
void MediaClient::slotRecordResult(bool ret)
{
ui.btnRecord->setIcon(QIcon(QString::fromUtf8(":/res/Resources/video_record.png")));
QString msg;
if (ret)
{
msg = tr("Video recording success");
}
else
{
msg = tr("Video recording failed");
}
InstMsgDialog dlg(msg, 2000);
dlg.exec();
}
void MediaClient::slotVolume()
{
if (!m_curWidget->isPlaying())
{
return;
}
if (m_curWidget->isMute())
{
ui.btnVolume->setIcon(QIcon(QString::fromUtf8(":/res/Resources/volume.png")));
m_curWidget->setMute(FALSE);
}
else
{
ui.btnVolume->setIcon(QIcon(QString::fromUtf8(":/res/Resources/mute.png")));
m_curWidget->setMute(TRUE);
}
}
void MediaClient::slotUpdateStatistics(int bytes)
{
int kb = 0, mb = 0;
char buff[100];
m_recvBytes += bytes;
if (m_recvBytes >= 1000)
{
kb = m_recvBytes / 1000;
}
if (kb >= 1000)
{
mb = kb / 1000;
kb = kb % 1000;
kb = kb / 10;
sprintf(buff, " %d.%02d MB", mb, kb);
}
else
{
sprintf(buff, " %d KB", kb);
}
ui.labStatistics->setText(tr("RX:") + buff);
}
void MediaClient::slotOrientationChanged(Qt::ScreenOrientation orientation)
{
setupLayout(orientation);
}
void MediaClient::setupLayout(Qt::ScreenOrientation orientation)
{
log_print(HT_LOG_DBG, "setupLayout, orientation = %d\r\n", orientation);
if (orientation == Qt::LandscapeOrientation ||
orientation == Qt::InvertedLandscapeOrientation) // width > height
{
ui.infoWidget->layout()->removeWidget(ui.cmbLayout);
ui.infoWidget->layout()->removeWidget(ui.labTipInfo);
ui.infoWidget->layout()->removeWidget(ui.labStatistics);
ui.infoWidget->hide();
ui.toolWidget->layout()->removeItem(ui.horizontalSpacer1);
ui.toolWidget->layout()->removeWidget(ui.btnPlay);
ui.toolWidget->layout()->removeWidget(ui.btnPause);
ui.toolWidget->layout()->removeWidget(ui.btnStop);
ui.toolWidget->layout()->removeItem(ui.horizontalSpacer2);
ui.toolWidget->layout()->removeWidget(ui.btnVolume);
ui.toolWidget->layout()->removeWidget(ui.btnSnapshot);
ui.toolWidget->layout()->removeWidget(ui.btnRecord);
ui.toolWidget->layout()->removeItem(ui.horizontalSpacer3);
ui.toolWidget->layout()->addWidget(ui.cmbLayout);
ui.toolWidget->layout()->addItem(ui.horizontalSpacer1);
ui.toolWidget->layout()->addWidget(ui.btnPlay);
ui.toolWidget->layout()->addWidget(ui.btnPause);
ui.toolWidget->layout()->addWidget(ui.btnStop);
ui.toolWidget->layout()->addItem(ui.horizontalSpacer2);
ui.toolWidget->layout()->addWidget(ui.btnVolume);
ui.toolWidget->layout()->addWidget(ui.btnSnapshot);
ui.toolWidget->layout()->addWidget(ui.btnRecord);
ui.toolWidget->layout()->addItem(ui.horizontalSpacer3);
ui.toolWidget->layout()->addWidget(ui.labStatistics);
}
else // height > width
{
ui.infoWidget->layout()->removeWidget(ui.cmbLayout);
ui.infoWidget->layout()->removeWidget(ui.labTipInfo);
ui.infoWidget->layout()->removeWidget(ui.labStatistics);
ui.toolWidget->layout()->removeWidget(ui.labTipInfo);
ui.toolWidget->layout()->removeWidget(ui.labStatistics);
ui.toolWidget->layout()->removeWidget(ui.btnPlay);
ui.toolWidget->layout()->removeWidget(ui.btnPause);
ui.toolWidget->layout()->removeWidget(ui.btnStop);
ui.toolWidget->layout()->removeWidget(ui.btnVolume);
ui.toolWidget->layout()->removeWidget(ui.btnSnapshot);
ui.toolWidget->layout()->removeWidget(ui.btnRecord);
ui.toolWidget->layout()->removeItem(ui.horizontalSpacer1);
ui.toolWidget->layout()->removeItem(ui.horizontalSpacer2);
ui.toolWidget->layout()->removeItem(ui.horizontalSpacer3);
ui.infoWidget->layout()->addWidget(ui.cmbLayout);
ui.infoWidget->layout()->addWidget(ui.labTipInfo);
ui.infoWidget->layout()->addWidget(ui.labStatistics);
ui.infoWidget->show();
ui.toolWidget->layout()->addItem(ui.horizontalSpacer1);
ui.toolWidget->layout()->addWidget(ui.btnPlay);
ui.toolWidget->layout()->addWidget(ui.btnPause);
ui.toolWidget->layout()->addWidget(ui.btnStop);
ui.toolWidget->layout()->addItem(ui.horizontalSpacer2);
ui.toolWidget->layout()->addWidget(ui.btnVolume);
ui.toolWidget->layout()->addWidget(ui.btnSnapshot);
ui.toolWidget->layout()->addWidget(ui.btnRecord);
ui.toolWidget->layout()->addItem(ui.horizontalSpacer3);
}
if (m_layoutMode == 2)
{
slotLayoutTwo();
}
else if (m_layoutMode == 6)
{
slotLayoutSix();
}
}
void MediaClient::slotSystemSetting()
{
SystemSetting dlg(m_syscfg, this);
if (QDialog::Accepted == dlg.exec())
{
SysConfig config = dlg.getSysConfig();
/* apply system config parameter */
if (m_syscfg.enableLog != config.enableLog)
{
if (m_syscfg.enableLog)
{
log_close();
}
else
{
initLog();
}
}
log_set_level(config.logLevel);
/* update system config parameter */
m_syscfg.enableLog = config.enableLog;
m_syscfg.videoRenderMode = config.videoRenderMode;
m_syscfg.rtpMulticast = config.rtpMulticast;
m_syscfg.rtpOverUdp = config.rtpOverUdp;
m_syscfg.rtspOverHttp = config.rtspOverHttp;
m_syscfg.rtspOverHttpPort = config.rtspOverHttpPort;
m_syscfg.rtspOverWs = config.rtspOverWs;
m_syscfg.rtspOverWsPort = config.rtspOverWsPort;
m_syscfg.logLevel = config.logLevel;
m_syscfg.hwDecoding = config.hwDecoding;
m_syscfg.recordTime = config.recordTime;
m_syscfg.recordSize = config.recordSize;
}
}
void MediaClient::slotOpenSnapshot()
{
FileBrowse * pDlg = new FileBrowse(FILE_FORMAT_PIC, this);
pDlg->exec();
delete pDlg;
}
void MediaClient::slotOpenRecording()
{
FileBrowse * pDlg = new FileBrowse(FILE_FORMAT_VIDEO, this);
pDlg->exec();
delete pDlg;
}
void MediaClient::slotAbout()
{
About dlg(this);
dlg.exec();
}

View File

@@ -0,0 +1,90 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#ifndef MEDIACLIENT_H
#define MEDIACLIENT_H
#include <QDialog>
#include "ui_MediaClient.h"
#include "config.h"
class MediaClient : public QDialog
{
Q_OBJECT
public:
MediaClient(QWidget *parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::Widget);
~MediaClient();
private slots:
void slotLayoutOne();
void slotLayoutTwo();
void slotLayoutFour();
void slotLayoutSix();
void slotLayoutNine();
void slotLayoutChanged(int index);
void slotPlay();
void slotPause();
void slotStop();
void slotCallState(QWidget* pWidget, int event);
void slotSnapshot();
void slotRecord();
void slotVolume();
void slotSnapshotResult(bool ret);
void slotRecordResult(bool ret);
void slotUpdateStatistics(int bytes);
void slotOrientationChanged(Qt::ScreenOrientation orientation);
void slotWidgetSelecting(QWidget * pWidget);
void slotSystemSetting();
void slotOpenSnapshot();
void slotOpenRecording();
void slotAbout();
protected:
void closeEvent(QCloseEvent * event);
private:
void initLog();
void initDialog();
void connSignalSlot();
void saveChannel(QList<CHANNEL> &channels, VideoWidget * widget);
void connVideoWidget(VideoWidget * widget);
void showBitrate(int bitrate);
void setupLayout(Qt::ScreenOrientation orientation);
void loadSystemConfig();
void loadChannels();
private:
Ui::MediaClient ui;
VideoWidget * m_curWidget;
int m_layoutMode;
uint64 m_recvBytes;
QString m_url;
QString m_user;
QString m_pass;
SysConfig m_syscfg;
};
#endif

View File

@@ -0,0 +1,69 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "sys_inc.h"
#include "OpenMedia.h"
#include "utils.h"
#include <QMessageBox>
#include <QFileDialog>
OpenMedia::OpenMedia(QString &url, QString &user, QString &pass, QWidget *parent, Qt::WindowFlags flags)
: QDialog(parent, flags)
, m_url(url)
, m_user(user)
, m_pass(pass)
{
ui.setupUi(this);
ui.editUrl->setText(m_url);
ui.editUser->setText(m_user);
ui.editPass->setText(m_pass);
connect(ui.btnCancel, SIGNAL(clicked()), this, SLOT(close()));
connect(ui.btnConfirm, SIGNAL(clicked()), this, SLOT(slotConfirm()));
}
OpenMedia::~OpenMedia()
{
}
void OpenMedia::slotConfirm()
{
m_url = ui.editUrl->text();
m_user = ui.editUser->text();
m_pass = ui.editPass->text();
if (m_url.isEmpty())
{
ui.editUrl->setFocus();
return;
}
else if (!isUrl(m_url))
{
QMessageBox::information(NULL, tr("Tips"), tr("Invalid URL format!"));
ui.editUrl->setFocus();
return;
}
accept();
}

View File

@@ -0,0 +1,49 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#ifndef OPEN_MEDIA_H
#define OPEN_MEDIA_H
#include <QDialog>
#include "ui_OpenMedia.h"
class OpenMedia : public QDialog
{
Q_OBJECT
public:
OpenMedia(QString &url, QString &user, QString &pass, QWidget *parent = 0, Qt::WindowFlags flags = Qt::Widget);
~OpenMedia();
QString getUrl() { return m_url; }
QString getUser() { return m_user; }
QString getPass() { return m_pass; }
public slots:
void slotConfirm();
private:
Ui::OpenMedia ui;
QString m_url;
QString m_user;
QString m_pass;
};
#endif

View File

@@ -0,0 +1,128 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "SystemSetting.h"
#include "utils.h"
#include "video_decoder.h"
#include <QFile>
#include <QMessageBox>
#include <QDesktopServices>
#include <QFileDialog>
#include <QScreen>
SystemSetting::SystemSetting(SysConfig &config, QWidget *parent)
: QDialog(parent)
, m_syscfg(config)
{
ui.setupUi(this);
initDialog();
connSignalSlot();
}
SystemSetting::~SystemSetting()
{
}
void SystemSetting::initDialog()
{
ui.cmbLogLevel->addItem(tr("TRACE"));
ui.cmbLogLevel->addItem(tr("DEBUG"));
ui.cmbLogLevel->addItem(tr("INFO"));
ui.cmbLogLevel->addItem(tr("WARNING"));
ui.cmbLogLevel->addItem(tr("ERROR"));
ui.cmbLogLevel->addItem(tr("FATAL"));
ui.cmbVideoRenderMode->addItem(tr("Keep the original aspect ratio"));
ui.cmbVideoRenderMode->addItem(tr("Fill the whole window"));
#if defined(ANDROID)
ui.cmbHWDecoding->addItem(tr("Automatic"), HW_DECODING_AUTO);
ui.cmbHWDecoding->addItem(tr("Media Codec"), HW_DECODING_MEDIACODEC);
ui.cmbHWDecoding->addItem(tr("Disable"), HW_DECODING_DISABLE);
#elif defined(IOS)
ui.cmbHWDecoding->addItem(tr("Automatic"), HW_DECODING_AUTO);
ui.cmbHWDecoding->addItem(tr("Videotoolbox"), HW_DECODING_VIDEOTOOLBOX);
ui.cmbHWDecoding->addItem(tr("Disable"), HW_DECODING_DISABLE);
#endif
ui.chkEnableLog->setChecked(m_syscfg.enableLog);
ui.chkRtpMulticast->setChecked(m_syscfg.rtpMulticast);
ui.chkRtpOverUdp->setChecked(m_syscfg.rtpOverUdp);
ui.chkRtspOverHttp->setChecked(m_syscfg.rtspOverHttp);
ui.spinHttpPort->setValue(m_syscfg.rtspOverHttpPort);
ui.chkRtspOverWs->setChecked(m_syscfg.rtspOverWs);
ui.spinWsPort->setValue(m_syscfg.rtspOverWsPort);
ui.cmbVideoRenderMode->setCurrentIndex(m_syscfg.videoRenderMode);
ui.cmbLogLevel->setCurrentIndex(m_syscfg.logLevel);
ui.timeRecordTime->setTime(QTime(0,0,0,0).addSecs(m_syscfg.recordTime));
ui.spinRecordSize->setValue(m_syscfg.recordSize);
for (int i = 0; i < ui.cmbHWDecoding->count(); i++)
{
if (ui.cmbHWDecoding->itemData(i).toInt() == m_syscfg.hwDecoding)
{
ui.cmbHWDecoding->setCurrentIndex(i);
break;
}
}
showMaximized();
}
void SystemSetting::connSignalSlot()
{
connect(ui.btnCancel, SIGNAL(clicked()), this, SLOT(close()));
connect(ui.btnConfirm, SIGNAL(clicked()), this, SLOT(slotConfirm()));
}
void SystemSetting::slotConfirm()
{
m_syscfg.enableLog = ui.chkEnableLog->isChecked();
m_syscfg.logLevel = ui.cmbLogLevel->currentIndex();
m_syscfg.rtpMulticast = ui.chkRtpMulticast->isChecked();
m_syscfg.rtpOverUdp = ui.chkRtpOverUdp->isChecked();
m_syscfg.rtspOverHttp = ui.chkRtspOverHttp->isChecked();
m_syscfg.rtspOverHttpPort = ui.spinHttpPort->value();
m_syscfg.rtspOverWs = ui.chkRtspOverWs->isChecked();
m_syscfg.rtspOverWsPort = ui.spinWsPort->value();
m_syscfg.recordTime = QTime(0, 0, 0, 0).secsTo(ui.timeRecordTime->time());
m_syscfg.recordSize = ui.spinRecordSize->value();
m_syscfg.videoRenderMode = ui.cmbVideoRenderMode->currentIndex();
m_syscfg.hwDecoding = ui.cmbHWDecoding->currentData().toInt();
saveEnableLogFlag(m_syscfg.enableLog);
saveLogLevel(m_syscfg.logLevel);
saveRtpMulticast(m_syscfg.rtpMulticast);
saveRtpOverUdp(m_syscfg.rtpOverUdp);
saveRtspOverHttp(m_syscfg.rtspOverHttp);
saveRtspOverHttpPort(m_syscfg.rtspOverHttpPort);
saveRtspOverWs(m_syscfg.rtspOverWs);
saveRtspOverWsPort(m_syscfg.rtspOverWsPort);
saveRecordTime(m_syscfg.recordTime);
saveRecordSize(m_syscfg.recordSize);
saveVideoRenderMode(m_syscfg.videoRenderMode);
saveHWDecoding(m_syscfg.hwDecoding);
accept();
}

View File

@@ -0,0 +1,56 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#ifndef _SYSTEM_SETTING_H_
#define _SYSTEM_SETTING_H_
#include "sys_inc.h"
#include <QDialog>
#include "ui_SystemSetting.h"
#include "config.h"
class SystemSetting : public QDialog
{
Q_OBJECT
public:
SystemSetting(SysConfig &config, QWidget *parent = 0);
~SystemSetting();
SysConfig getSysConfig(){return m_syscfg;}
private slots:
void slotConfirm();
private:
void initDialog();
void connSignalSlot();
private:
Ui::SystemSetting ui;
SysConfig m_syscfg;
};
#endif

View File

@@ -0,0 +1,732 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "sys_inc.h"
#include "VideoWidget.h"
#include "utils.h"
#include "InstMsgDialog.h"
#include "rtsp_player.h"
#include "rtmp_player.h"
#include "http_flv_player.h"
#include "http_mjpeg_player.h"
#include "srt_player.h"
#include "file_player.h"
#include "http_test.h"
#include <QPainter>
#include <QMessageBox>
#include <QScreen>
#include <QPaintEvent>
#include <QDir>
#include <QFile>
#include <QDateTime>
#include <QApplication>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#if defined(ANDROID)
#include <QJniObject>
#endif
/*********************************************************************************************/
#define VERTEXIN 0
#define TEXTUREIN 1
/*********************************************************************************************/
VideoWidget::VideoWidget(QWidget * parent, Qt::WindowFlags f)
: QOpenGLWidget(parent, f)
, m_pPlayer(NULL)
, m_bMute(FALSE)
, m_bRecording(FALSE)
, m_pRenderFrame(NULL)
#ifdef BACKCHANNEL
, m_nBackChannelFlag(0)
#endif
{
setAttribute(Qt::WA_OpaquePaintEvent);
m_timerReconn.setSingleShot(true);
connect(&m_timerReconn, SIGNAL(timeout()), this, SLOT(slotReconn()));
connect(this, SIGNAL(imageReady()), this, SLOT(update()), Qt::QueuedConnection);
}
VideoWidget::~VideoWidget()
{
closeVideo();
makeCurrent();
vbo.destroy();
textureY->destroy();
textureU->destroy();
textureV->destroy();
doneCurrent();
}
void VideoWidget::play(QString url, QString acct, QString pass)
{
if (m_url == url && m_acct == acct && m_pass == pass)
{
return;
}
closeVideo();
m_url = url;
m_acct = acct;
m_pass = pass;
m_base = getBaseName(url);
if (!m_url.isEmpty())
{
makeCall();
}
}
void VideoWidget::pause()
{
if (m_pPlayer)
{
m_pPlayer->pause();
}
}
void VideoWidget::stop()
{
closeVideo();
}
void VideoWidget::closePlayer()
{
m_timerReconn.stop();
if (m_pPlayer)
{
delete m_pPlayer;
m_pPlayer = NULL;
}
}
void VideoWidget::closeVideo()
{
closePlayer();
m_url = "";
m_acct = "";
m_pass = "";
m_bRecording = FALSE;
QMutexLocker locker(&m_mutex);
if (m_pRenderFrame)
{
av_frame_free(&m_pRenderFrame);
}
update();
}
BOOL VideoWidget::isRecording()
{
if (m_pPlayer)
{
return m_pPlayer->isRecording();
}
return FALSE;
}
void VideoWidget::makeCall()
{
BOOL isFile = 0;
BOOL isRtsp = FALSE;
if (isRtspUrl(m_url))
{
isRtsp = TRUE;
m_pPlayer = new CRtspPlayer(this);
}
else if (isRtmpUrl(m_url))
{
m_pPlayer = new CRtmpPlayer(this);
}
else if (isHttpUrl(m_url))
{
HTTPCTT ctt;
if (http_test(m_url.toStdString().c_str(), m_acct.toStdString().c_str(), m_pass.toStdString().c_str(), &ctt, 2*1000))
{
if (CTT_RTSP_TUNNELLED == ctt)
{
isRtsp = TRUE;
m_pPlayer = new CRtspPlayer(this);
}
else if (CTT_FLV == ctt)
{
m_pPlayer = new CHttpFlvPlayer(this);
}
else if (CTT_MULTIPART == ctt)
{
m_pPlayer = new CHttpMjpegPlayer(this);
}
}
else
{
m_pPlayer = new CHttpFlvPlayer(this);
}
}
else if (isSrtUrl(m_url))
{
m_pPlayer = new CSrtPlayer(this);
}
else
{
isFile = 1;
m_pPlayer = new CFilePlayer(this);
}
if (NULL == m_pPlayer)
{
return;
}
connect(m_pPlayer, SIGNAL(notify(int)), this, SLOT(slotPlayerNotify(int)), Qt::QueuedConnection);
connect(m_pPlayer, SIGNAL(snapshoted(AVFrame*)), this, SLOT(slotSnapshoted(AVFrame*)), Qt::QueuedConnection);
connect(m_pPlayer, SIGNAL(imageReady(AVFrame*)), this, SLOT(slotImageReady(AVFrame*)), Qt::QueuedConnection);
connect(m_pPlayer, SIGNAL(updateStatistics(int)), this, SIGNAL(updateStatistics(int)));
if (m_pPlayer->open(m_url, 0))
{
m_pPlayer->setAuthInfo(m_acct, m_pass);
m_pPlayer->setHWDecoding(getHWDecoding());
if (isRtsp)
{
m_pPlayer->setRtpOverUdp(getRtpOverUdp());
m_pPlayer->setRtpMulticast(getRtpMulticast());
#ifdef OVER_HTTP
m_pPlayer->setRtspOverHttp(getRtspOverHttp(), getRtspOverHttpPort());
#endif
#ifdef OVER_WEBSOCKET
m_pPlayer->setRtspOverWs(getRtspOverWs(), getRtspOverWsPort());
#endif
#ifdef BACKCHANNEL
m_pPlayer->setBCFlag(m_nBackChannelFlag);
#endif
}
else if (isFile)
{
setMute(m_bMute);
}
m_pPlayer->play();
}
else
{
closePlayer();
}
}
void VideoWidget::mousePressEvent(QMouseEvent * event)
{
emit widgetSelecting(this);
}
BOOL VideoWidget::micphone()
{
#ifdef BACKCHANNEL
if (NULL == m_pPlayer)
{
return FALSE;
}
#if defined(ANDROID)
QJniObject str = QJniObject::fromString("android.permission.RECORD_AUDIO");
QJniObject::callStaticMethod<jint>("org/happytimesoft/util/HtUtil",
"requestPermission",
"(Landroid/content/Context;Ljava/lang/String;)I",
QNativeInterface::QAndroidApplication::context(),
str.object<jstring>());
#endif
closePlayer();
if (m_nBackChannelFlag)
{
m_nBackChannelFlag = 0;
}
else
{
m_nBackChannelFlag = 1;
}
makeCall();
if (m_pPlayer)
{
m_pPlayer->setBCDataFlag(m_nBackChannelFlag);
return m_pPlayer->getBCFlag();
}
#endif
return FALSE;
}
void VideoWidget::setMute(BOOL flag)
{
m_bMute = flag;
if (m_pPlayer)
{
m_pPlayer->setVolume(flag ? HTVOLUME_MIN : HTVOLUME_MAX);
}
}
BOOL VideoWidget::isPlaying()
{
if (m_pPlayer)
{
return m_pPlayer->isPlaying() || m_pPlayer->isPaused();
}
return FALSE;
}
void VideoWidget::snapshot()
{
if (m_pPlayer)
{
m_pPlayer->snapshot(VIDEO_FMT_RGB24);
}
}
void VideoWidget::slotSnapshoted(AVFrame * frame)
{
QImage image = QImage(frame->data[0], frame->width, frame->height, frame->linesize[0], QImage::Format_RGB888);
QString file = getSnapshotPath() + "/" + getTempFile(m_base, ".jpg");
if (!image.save(file, "JPG"))
{
emit snapshotResult(false);
}
else
{
emit snapshotResult(true);
}
}
BOOL VideoWidget::record()
{
if (NULL == m_pPlayer)
{
return FALSE;
}
if (m_pPlayer->isRecording())
{
stopRecord();
}
else
{
startRecord();
}
m_bRecording = m_pPlayer->isRecording();
return m_bRecording;
}
void VideoWidget::startRecord()
{
if (NULL == m_pPlayer)
{
return;
}
if (m_pPlayer->isRecording())
{
return;
}
QString file = getRecordPath() + "/" + getTempFile(m_base, ".avi");
m_pPlayer->record(file);
}
void VideoWidget::stopRecord()
{
if (NULL == m_pPlayer)
{
return;
}
if (m_pPlayer->isRecording())
{
m_pPlayer->stopRecord();
emit recordResult(true);
}
}
QRect VideoWidget::getVideoRenderRect(int videoW, int videoH)
{
QRect rect = this->rect();
qreal ratio = QGuiApplication::primaryScreen()->devicePixelRatio();
int w = rect.width() * ratio;
int h = rect.height() * ratio;
if (getVideoRenderMode() == RENDER_MODE_KEEP) // keep the original aspect ratio
{
int iw = videoW;
int ih = videoH;
int nw, nh;
double vratio = iw / (double)ih;
double wratio = w / (double)h;
if (vratio > wratio)
{
nw = w;
nh = w * ih / iw;
}
else
{
nw = h * iw / ih;
nh = h;
}
rect.setLeft((w - nw) / 2);
rect.setTop((h - nh) / 2);
rect.setRight(rect.left() + nw);
rect.setBottom(rect.top() + nh);
}
else // fill the whole window
{
rect.setLeft(0);
rect.setTop(0);
rect.setRight(w);
rect.setBottom(h);
}
return rect;
}
void VideoWidget::slotImageReady(AVFrame * frame)
{
QMutexLocker locker(&m_mutex);
if (m_pRenderFrame)
{
av_frame_free(&m_pRenderFrame);
}
if (m_pPlayer)
{
m_pRenderFrame = frame;
emit imageReady();
}
else
{
av_frame_free(&frame);
}
}
void VideoWidget::slotPlayerNotify(int event)
{
if (event == RTSP_EVE_CONNFAIL ||
event == RTMP_EVE_CONNFAIL ||
event == HTTP_FLV_EVE_CONNFAIL ||
event == MJPEG_EVE_CONNFAIL ||
event == SRT_EVE_CONNFAIL)
{
m_timerReconn.start(5 * 1000);
}
else if (event == RTSP_EVE_CONNSUCC ||
event == MJPEG_EVE_CONNSUCC)
{
setMute(m_bMute);
// Re-record after reconnect
if (m_bRecording)
{
startRecord();
}
}
else if (event == RTMP_EVE_VIDEOREADY ||
event == HTTP_FLV_EVE_VIDEOREADY ||
event == SRT_EVE_VIDEOREADY)
{
// Re-record after reconnect
if (m_bRecording)
{
startRecord();
}
}
else if (event == RTMP_EVE_AUDIOREADY ||
event == HTTP_FLV_EVE_AUDIOREADY ||
event == SRT_EVE_AUDIOREADY)
{
setMute(m_bMute);
}
else if (event == RTSP_EVE_NOSIGNAL ||
event == RTMP_EVE_NOSIGNAL ||
event == HTTP_FLV_EVE_NOSIGNAL ||
event == MJPEG_EVE_NOSIGNAL ||
event == SRT_EVE_NOSIGNAL)
{
m_timerReconn.start(5 * 1000);
}
else if (event == RTSP_EVE_NODATA ||
event == RTMP_EVE_NODATA ||
event == HTTP_FLV_EVE_NODATA ||
event == MJPEG_EVE_NODATA ||
event == SRT_EVE_NODATA)
{
m_timerReconn.start(5 * 1000);
}
else if (event == RTSP_EVE_RESUME ||
event == RTMP_EVE_RESUME ||
event == HTTP_FLV_EVE_RESUME ||
event == MJPEG_EVE_RESUME ||
event == SRT_EVE_RESUME)
{
m_timerReconn.stop();
}
else if (event == RTSP_EVE_STOPPED ||
event == RTMP_EVE_STOPPED ||
event == HTTP_FLV_EVE_STOPPED ||
event == MJPEG_EVE_STOPPED ||
event == SRT_EVE_STOPPED)
{
m_timerReconn.start(5 * 1000);
}
emit callState(this, event);
}
void VideoWidget::slotReconn()
{
closePlayer();
makeCall();
}
QString VideoWidget::getBaseName(QString &url)
{
if (isUrl(url))
{
char host[100] = {'\0'};
url_split(url.toStdString().c_str(), NULL, 0, NULL, 0, NULL, 0, host, sizeof(host), NULL, NULL, 0);
return QString(host);
}
else
{
QFileInfo fileInfo(url);
return fileInfo.baseName();
}
}
void VideoWidget::initializeGL()
{
initializeOpenGLFunctions();
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
static const GLfloat vertices[]
{
-1.0f, -1.0f,
-1.0f, +1.0f,
+1.0f, +1.0f,
+1.0f, -1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
};
if (!vbo.create())
{
log_print(HT_LOG_ERR, "%s, vbo.create failed\r\n", __FUNCTION__);
}
if (!vbo.bind())
{
log_print(HT_LOG_ERR, "%s, vbo.bind failed\r\n", __FUNCTION__);
}
vbo.allocate(vertices, sizeof(vertices));
QOpenGLShader * vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
const char * vsrc =
"attribute vec4 vertexIn; \n"
"attribute vec2 textureIn; \n"
"varying highp vec2 textureOut; \n"
"void main(void) \n"
"{ \n"
" gl_Position = vertexIn; \n"
" textureOut = textureIn; \n"
"}";
if (!vshader->compileSourceCode(vsrc))
{
log_print(HT_LOG_ERR, "%s, compile vertex source failed\r\n", __FUNCTION__);
}
QOpenGLShader * fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
const char * fsrc =
"varying highp vec2 textureOut; \n"
"uniform sampler2D tex_y; \n"
"uniform sampler2D tex_u; \n"
"uniform sampler2D tex_v; \n"
"void main(void) \n"
"{ \n"
" lowp vec3 yuv; \n"
" lowp vec3 rgb; \n"
" yuv.x = texture2D(tex_y, textureOut).r; \n"
" yuv.y = texture2D(tex_u, textureOut).r - 0.5; \n"
" yuv.z = texture2D(tex_v, textureOut).r - 0.5; \n"
" rgb = mat3( 1, 1, 1, \n"
" 0, -0.39465, 2.03211, \n"
" 1.13983, -0.58060, 0) * yuv; \n"
" gl_FragColor = vec4(rgb, 1); \n"
"}";
if (!fshader->compileSourceCode(fsrc))
{
log_print(HT_LOG_ERR, "%s, compile fragment source failed\r\n", __FUNCTION__);
}
program = new QOpenGLShaderProgram(this);
if (!program->addShader(vshader))
{
log_print(HT_LOG_ERR, "%s, add vertex shader failed\r\n", __FUNCTION__);
}
if (!program->addShader(fshader))
{
log_print(HT_LOG_ERR, "%s, add fragment shader failed\r\n", __FUNCTION__);
}
program->bindAttributeLocation("vertexIn", VERTEXIN);
program->bindAttributeLocation("textureIn", TEXTUREIN);
if (!program->link())
{
log_print(HT_LOG_ERR, "%s, link failed. %s\r\n", __FUNCTION__, program->log().toStdString().c_str());
}
if (!program->bind())
{
log_print(HT_LOG_ERR, "%s, program bind failed\r\n", __FUNCTION__);
}
program->enableAttributeArray(VERTEXIN);
program->enableAttributeArray(TEXTUREIN);
program->setAttributeBuffer(VERTEXIN, GL_FLOAT, 0, 2, 2*sizeof(GLfloat));
program->setAttributeBuffer(TEXTUREIN, GL_FLOAT, 8*sizeof(GLfloat), 2, 2*sizeof(GLfloat));
textureUniformY = program->uniformLocation("tex_y");
textureUniformU = program->uniformLocation("tex_u");
textureUniformV = program->uniformLocation("tex_v");
textureY = new QOpenGLTexture(QOpenGLTexture::Target2D);
textureU = new QOpenGLTexture(QOpenGLTexture::Target2D);
textureV = new QOpenGLTexture(QOpenGLTexture::Target2D);
if (!textureY->create())
{
log_print(HT_LOG_ERR, "%s, textureY create failed\r\n", __FUNCTION__);
}
if (!textureU->create())
{
log_print(HT_LOG_ERR, "%s, textureU create failed\r\n", __FUNCTION__);
}
if (!textureV->create())
{
log_print(HT_LOG_ERR, "%s, textureV create failed\r\n", __FUNCTION__);
}
idY = textureY->textureId();
idU = textureU->textureId();
idV = textureV->textureId();
glClearColor(0.0, 0.0, 0.0, 1.0f);
}
void VideoWidget::paintGL()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMutexLocker locker(&m_mutex);
if (NULL == m_pRenderFrame)
{
return;
}
int videoW = m_pRenderFrame->width;
int videoH = m_pRenderFrame->height;
QRect rect = getVideoRenderRect(videoW, videoH);
glViewport(rect.left(), rect.top(), rect.width(), rect.height());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, idY);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, videoW, videoH, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pRenderFrame->data[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, idU);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, videoW >> 1, videoH >> 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pRenderFrame->data[1]);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, idV);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, videoW >> 1, videoH >> 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pRenderFrame->data[2]);
glUniform1i(textureUniformY, 0);
glUniform1i(textureUniformU, 1);
glUniform1i(textureUniformV, 2);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}

View File

@@ -0,0 +1,117 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#ifndef VIDEO_WIDGET_H
#define VIDEO_WIDGET_H
#include "sys_inc.h"
#include "video_player.h"
#include <QWidget>
#include <QMutex>
#include <QSwipeGesture>
#include <QGestureEvent>
#include <QTimer>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QOpenGLShaderProgram>
class VideoWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
VideoWidget(QWidget * parent = 0, Qt::WindowFlags f = Qt::Widget);
~VideoWidget();
void play(QString url, QString user, QString pass);
void pause();
void stop();
void snapshot();
BOOL record();
void stopRecord();
void setMute(BOOL flag);
BOOL micphone();
BOOL isPlaying();
BOOL isMute() {return m_bMute;}
BOOL isRecording();
QString getUrl() { return m_url; }
QString getUser() { return m_acct; }
QString getPass() { return m_pass; }
private slots:
void slotImageReady(AVFrame * frame);
void slotPlayerNotify(int event);
void slotReconn();
void slotSnapshoted(AVFrame * frame);
signals:
void callState(QWidget *, int);
void snapshotResult(bool);
void recordResult(bool);
void updateStatistics(int);
void imageReady();
void widgetSelecting(QWidget *);
protected:
void mousePressEvent(QMouseEvent * event);
void initializeGL();
void paintGL();
private:
void closePlayer();
void closeVideo();
void makeCall();
QRect getVideoRenderRect(int videoW, int videoH);
void startRecord();
QString getBaseName(QString &url);
private:
QString m_url;
QString m_acct;
QString m_pass;
QString m_base;
CVideoPlayer * m_pPlayer;
QTimer m_timerReconn;
BOOL m_bMute;
BOOL m_bRecording;
QMutex m_mutex;
AVFrame * m_pRenderFrame;
#ifdef BACKCHANNEL
int m_nBackChannelFlag;
#endif
QOpenGLShaderProgram * program;
QOpenGLBuffer vbo;
GLuint textureUniformY;
GLuint textureUniformU;
GLuint textureUniformV;
QOpenGLTexture* textureY = nullptr;
QOpenGLTexture* textureU = nullptr;
QOpenGLTexture* textureV = nullptr;
GLuint idY, idU, idV;
};
#endif