Update MediaClient
173
MediaClient/MediaClientForMobile/FileListModel.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/***************************************************************************************
|
||||
*
|
||||
* 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 "FileListModel.h"
|
||||
#include "utils.h"
|
||||
#include <QApplication>
|
||||
#include <QBrush>
|
||||
#include <QDir>
|
||||
#include <QPalette>
|
||||
|
||||
|
||||
FileListModel::FileListModel(int fileFormat, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_bCheckable(false)
|
||||
, m_fileFormat(fileFormat)
|
||||
{
|
||||
}
|
||||
|
||||
int FileListModel::rowCount(const QModelIndex & /* parent */) const
|
||||
{
|
||||
return m_fileCount;
|
||||
}
|
||||
|
||||
QVariant FileListModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (index.row() >= m_fileList.size() || index.row() < 0)
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
return m_fileList.at(index.row());
|
||||
}
|
||||
else if (role == Qt::DecorationRole && m_fileFormat == FILE_FORMAT_PIC)
|
||||
{
|
||||
QString file = m_basePath + "/" + m_fileList.at(index.row());
|
||||
QPixmap pixmap(file);
|
||||
pixmap = pixmap.scaled(60, 40);
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
else if (role == Qt::CheckStateRole && m_bCheckable)
|
||||
{
|
||||
return m_boolList.at(index.row()) ? Qt::Checked : Qt::Unchecked;
|
||||
}
|
||||
else if (role == Qt::SizeHintRole && m_fileFormat == FILE_FORMAT_VIDEO)
|
||||
{
|
||||
return QSize(100, 40);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::ItemFlags FileListModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
if (index.row() >= m_fileList.size() || index.row() < 0)
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
if (m_bCheckable)
|
||||
{
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileListModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (role != Qt::CheckStateRole)
|
||||
return false;
|
||||
|
||||
if (index.row() >= m_fileList.size() || index.row() < 0)
|
||||
return false;
|
||||
|
||||
m_boolList.replace(index.row(), value.toBool());
|
||||
|
||||
emit dataChanged(index, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileListModel::canFetchMore(const QModelIndex & /* index */) const
|
||||
{
|
||||
if (m_fileCount < m_fileList.size())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileListModel::fetchMore(const QModelIndex & /* index */)
|
||||
{
|
||||
int remainder = m_fileList.size() - m_fileCount;
|
||||
int itemsToFetch = qMin(100, remainder);
|
||||
|
||||
beginInsertRows(QModelIndex(), m_fileCount, m_fileCount+itemsToFetch-1);
|
||||
|
||||
m_fileCount += itemsToFetch;
|
||||
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void FileListModel::setNameFilters(const QStringList &filters)
|
||||
{
|
||||
m_nameFilters = filters;
|
||||
}
|
||||
|
||||
bool FileListModel::removeRows(int pos, int count, const QModelIndex &parent)
|
||||
{
|
||||
if (pos >= m_fileList.size() || pos < 0)
|
||||
return false;
|
||||
|
||||
beginRemoveRows(parent, pos, pos);
|
||||
m_fileList.removeAt(pos);
|
||||
m_boolList.removeAt(pos);
|
||||
endRemoveRows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileListModel::setDirPath(const QString &path)
|
||||
{
|
||||
QDir dir(path);
|
||||
|
||||
m_basePath = path;
|
||||
dir.setNameFilters(m_nameFilters);
|
||||
|
||||
beginResetModel();
|
||||
|
||||
m_fileList = dir.entryList();
|
||||
m_fileCount = 0;
|
||||
|
||||
for (int i = 0; i < m_fileList.size(); i++)
|
||||
{
|
||||
m_boolList.push_back(false);
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void FileListModel::setCheckable(bool checkable)
|
||||
{
|
||||
m_bCheckable = checkable;
|
||||
|
||||
if (m_fileCount > 0)
|
||||
{
|
||||
emit dataChanged(index(0), index(m_fileCount-1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
68
MediaClient/MediaClientForMobile/FileListModel.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/***************************************************************************************
|
||||
*
|
||||
* 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 FILELISTMODEL_H
|
||||
#define FILELISTMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
|
||||
|
||||
#define FILE_FORMAT_PIC 0
|
||||
#define FILE_FORMAT_VIDEO 1
|
||||
|
||||
|
||||
typedef QList<bool> QBoolList;
|
||||
|
||||
class FileListModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FileListModel(int fileFormat, QObject *parent = 0);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role);
|
||||
void setCheckable(bool checkable);
|
||||
void setNameFilters(const QStringList &filters);
|
||||
bool removeRows(int pos, int count, const QModelIndex &parent = QModelIndex());
|
||||
|
||||
public slots:
|
||||
void setDirPath(const QString &path);
|
||||
|
||||
protected:
|
||||
bool canFetchMore(const QModelIndex &parent) const;
|
||||
void fetchMore(const QModelIndex &parent);
|
||||
|
||||
private:
|
||||
QStringList m_nameFilters;
|
||||
QStringList m_fileList;
|
||||
QBoolList m_boolList;
|
||||
int m_fileCount;
|
||||
bool m_bCheckable;
|
||||
QString m_basePath;
|
||||
int m_fileFormat;
|
||||
};
|
||||
|
||||
#endif // FILELISTMODEL_H
|
||||
|
||||
|
||||
220
MediaClient/MediaClientForMobile/MediaClient.pro
Normal file
@@ -0,0 +1,220 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2019-07-04T09:50:05
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui widgets multimedia openglwidgets
|
||||
|
||||
TARGET = MediaClient
|
||||
TEMPLATE = app
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which has been marked as deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
DEFINES += __STDC_CONSTANT_MACROS
|
||||
DEFINES += HTTPS
|
||||
DEFINES += REPLAY
|
||||
DEFINES += OVER_HTTP
|
||||
DEFINES += OVER_WEBSOCKET
|
||||
|
||||
ios {
|
||||
DEFINES += IOS
|
||||
}
|
||||
|
||||
android {
|
||||
DEFINES += EPOLL
|
||||
DEFINES += BACKCHANNEL
|
||||
}
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
CONFIG += c++11
|
||||
ios:CONFIG += sdk_no_version_check
|
||||
|
||||
INCLUDEPATH += ./formClass
|
||||
INCLUDEPATH += ./media
|
||||
INCLUDEPATH += ./ui
|
||||
INCLUDEPATH += ../MediaClient/bm
|
||||
INCLUDEPATH += ../MediaClient/http
|
||||
INCLUDEPATH += ../MediaClient/librtmp
|
||||
INCLUDEPATH += ../MediaClient/rtmp
|
||||
INCLUDEPATH += ../MediaClient/rtp
|
||||
INCLUDEPATH += ../MediaClient/rtsp
|
||||
INCLUDEPATH += ../MediaClient/srt
|
||||
INCLUDEPATH += ../MediaClient/ffmpeg/include
|
||||
INCLUDEPATH += ../MediaClient/libsrt/include
|
||||
INCLUDEPATH += ../MediaClient/openssl/include
|
||||
|
||||
SOURCES += \
|
||||
formClass/About.cpp \
|
||||
formClass/FileBrowse.cpp \
|
||||
formClass/InstMsgDialog.cpp \
|
||||
formClass/MediaClient.cpp \
|
||||
formClass/OpenMedia.cpp \
|
||||
formClass/SystemSetting.cpp \
|
||||
formClass/VideoWidget.cpp \
|
||||
media/audio_capture.cpp \
|
||||
media/audio_decoder.cpp \
|
||||
media/audio_encoder.cpp \
|
||||
media/audio_play.cpp \
|
||||
media/audio_play_qt.cpp \
|
||||
media/avcodec_mutex.cpp \
|
||||
media/avi_write.cpp \
|
||||
media/file_player.cpp \
|
||||
media/http_flv_player.cpp \
|
||||
media/http_mjpeg_player.cpp \
|
||||
media/media_codec.cpp \
|
||||
media/media_parse.cpp \
|
||||
media/media_util.cpp \
|
||||
media/rtmp_player.cpp \
|
||||
media/rtsp_player.cpp \
|
||||
media/srt_player.cpp \
|
||||
media/video_decoder.cpp \
|
||||
media/video_player.cpp \
|
||||
FileListModel.cpp \
|
||||
main.cpp \
|
||||
utils.cpp \
|
||||
../MediaClient/bm/base64.cpp \
|
||||
../MediaClient/bm/hqueue.cpp \
|
||||
../MediaClient/bm/linked_list.cpp \
|
||||
../MediaClient/bm/ppstack.cpp \
|
||||
../MediaClient/bm/rfc_md5.cpp \
|
||||
../MediaClient/bm/sha1.cpp \
|
||||
../MediaClient/bm/sha256.cpp \
|
||||
../MediaClient/bm/sys_buf.cpp \
|
||||
../MediaClient/bm/sys_log.cpp \
|
||||
../MediaClient/bm/sys_os.cpp \
|
||||
../MediaClient/bm/util.cpp \
|
||||
../MediaClient/bm/word_analyse.cpp \
|
||||
../MediaClient/http/http_cln.cpp \
|
||||
../MediaClient/http/http_flv_cln.cpp \
|
||||
../MediaClient/http/http_mjpeg_cln.cpp \
|
||||
../MediaClient/http/http_parse.cpp \
|
||||
../MediaClient/http/http_test.cpp \
|
||||
../MediaClient/librtmp/amf.c \
|
||||
../MediaClient/librtmp/hashswf.c \
|
||||
../MediaClient/librtmp/log.c \
|
||||
../MediaClient/librtmp/parseurl.c \
|
||||
../MediaClient/librtmp/rtmp.c \
|
||||
../MediaClient/rtmp/rtmp_cln.cpp \
|
||||
../MediaClient/rtp/aac_rtp_rx.cpp \
|
||||
../MediaClient/rtp/h264_rtp_rx.cpp \
|
||||
../MediaClient/rtp/h264_util.cpp \
|
||||
../MediaClient/rtp/h265_rtp_rx.cpp \
|
||||
../MediaClient/rtp/h265_util.cpp \
|
||||
../MediaClient/rtp/mjpeg_rtp_rx.cpp \
|
||||
../MediaClient/rtp/mjpeg_tables.cpp \
|
||||
../MediaClient/rtp/mpeg4.cpp \
|
||||
../MediaClient/rtp/mpeg4_rtp_rx.cpp \
|
||||
../MediaClient/rtp/pcm_rtp_rx.cpp \
|
||||
../MediaClient/rtp/rtp.cpp \
|
||||
../MediaClient/rtp/rtp_rx.cpp \
|
||||
../MediaClient/rtp/ts_parser.cpp \
|
||||
../MediaClient/rtsp/rtsp_backchannel.cpp \
|
||||
../MediaClient/rtsp/rtsp_cln.cpp \
|
||||
../MediaClient/rtsp/rtsp_parse.cpp \
|
||||
../MediaClient/rtsp/rtsp_rcua.cpp \
|
||||
../MediaClient/rtsp/rtsp_util.cpp \
|
||||
../MediaClient/rtsp/rtsp_ws.cpp \
|
||||
../MediaClient/srt/srt_cln.cpp
|
||||
|
||||
ios {
|
||||
SOURCES += \
|
||||
ios/file_view_controller.mm \
|
||||
ios/ios_launcher.mm \
|
||||
}
|
||||
|
||||
android {
|
||||
SOURCES += \
|
||||
media/audio_capture_android.cpp \
|
||||
media/gles_engine.cpp \
|
||||
media/gles_input.cpp \
|
||||
}
|
||||
|
||||
HEADERS += \
|
||||
formClass/About.h \
|
||||
formClass/FileBrowse.h \
|
||||
formClass/InstMsgDialog.h \
|
||||
formClass/MediaClient.h \
|
||||
formClass/OpenMedia.h \
|
||||
formClass/SystemSetting.h \
|
||||
formClass/VideoWidget.h \
|
||||
media/audio_play_qt.h \
|
||||
media/file_player.h \
|
||||
media/http_flv_player.h \
|
||||
media/http_mjpeg_player.h \
|
||||
media/rtmp_player.h \
|
||||
media/rtsp_player.h \
|
||||
media/srt_player.h \
|
||||
media/video_player.h \
|
||||
FileListModel.h \
|
||||
|
||||
FORMS += \
|
||||
ui/About.ui \
|
||||
ui/FileBrowse.ui \
|
||||
ui/InstMsgDialog.ui \
|
||||
ui/MediaClient.ui \
|
||||
ui/OpenMedia.ui \
|
||||
ui/SystemSetting.ui
|
||||
|
||||
ios {
|
||||
LIBS += -L$$PWD/lib/ios-armv8a
|
||||
}
|
||||
|
||||
android {
|
||||
LIBS += -L$$PWD/lib/$$ANDROID_TARGET_ARCH
|
||||
ANDROID_EXTRA_LIBS += $$PWD/lib/$$ANDROID_TARGET_ARCH/libcrypto.so
|
||||
ANDROID_EXTRA_LIBS += $$PWD/lib/$$ANDROID_TARGET_ARCH/libssl.so
|
||||
}
|
||||
|
||||
LIBS += -lavformat
|
||||
LIBS += -lswscale
|
||||
LIBS += -lavcodec
|
||||
LIBS += -lswresample
|
||||
LIBS += -lavutil
|
||||
LIBS += -lx264
|
||||
LIBS += -lx265
|
||||
LIBS += -lsrt
|
||||
LIBS += -lcrypto
|
||||
LIBS += -lssl
|
||||
|
||||
ios {
|
||||
LIBS += -lbz2
|
||||
LIBS += -liconv
|
||||
LIBS += -framework AudioToolbox
|
||||
LIBS += -framework VideoToolbox
|
||||
}
|
||||
|
||||
android {
|
||||
LIBS += -lopus
|
||||
LIBS += -lOpenSLES
|
||||
}
|
||||
|
||||
RESOURCES += MediaClient.qrc
|
||||
|
||||
ios {
|
||||
QMAKE_INFO_PLIST = ios/Info.plist
|
||||
}
|
||||
|
||||
android {
|
||||
DISTFILES += \
|
||||
android/AndroidManifest.xml \
|
||||
android/build.gradle \
|
||||
android/gradle.properties \
|
||||
android/gradle/wrapper/gradle-wrapper.jar \
|
||||
android/gradle/wrapper/gradle-wrapper.properties \
|
||||
android/gradlew \
|
||||
android/gradlew.bat \
|
||||
android/res/values/libs.xml \
|
||||
android/res/xml/filepaths.xml
|
||||
|
||||
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
|
||||
}
|
||||
|
||||
21
MediaClient/MediaClientForMobile/MediaClient.qrc
Normal file
@@ -0,0 +1,21 @@
|
||||
<RCC>
|
||||
<qresource prefix="/res">
|
||||
<file>Resources/btn_pause.png</file>
|
||||
<file>Resources/btn_play.png</file>
|
||||
<file>Resources/btn_stop.png</file>
|
||||
<file>Resources/mic.png</file>
|
||||
<file>Resources/mute.png</file>
|
||||
<file>Resources/snapshot.png</file>
|
||||
<file>Resources/stop_record.png</file>
|
||||
<file>Resources/video_record.png</file>
|
||||
<file>Resources/volume.png</file>
|
||||
<file>Resources/stopmic.png</file>
|
||||
<file>Resources/1.png</file>
|
||||
<file>Resources/4.png</file>
|
||||
<file>Resources/2.png</file>
|
||||
<file>Resources/back.png</file>
|
||||
<file>Resources/delete.png</file>
|
||||
<file>Resources/6.png</file>
|
||||
<file>Resources/9.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
BIN
MediaClient/MediaClientForMobile/Resources/1.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/2.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/4.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/6.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/9.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/back.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/btn_pause.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/btn_play.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/btn_stop.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/delete.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/main.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/mic.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/mute.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/snapshot.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/stop_record.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/stopmic.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/video_record.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
MediaClient/MediaClientForMobile/Resources/volume.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
30
MediaClient/MediaClientForMobile/android/AndroidManifest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.happytimesoft.mediaclient" android:installLocation="auto" android:versionCode="22" android:versionName="3.2">
|
||||
|
||||
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/>
|
||||
|
||||
<application android:name="org.qtproject.qt.android.bindings.QtApplication" android:hardwareAccelerated="true" android:requestLegacyExternalStorage="true" android:allowNativeHeapPointerTagging="false" android:label="@string/app_name" android:allowBackup="false" android:fullBackupOnly="false" android:icon="@drawable/icon">
|
||||
|
||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:launchMode="singleTop" android:screenOrientation="unspecified" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
|
||||
<meta-data android:name="android.app.arguments" android:value="-- %%INSERT_APP_ARGUMENTS%% --"/>
|
||||
<meta-data android:name="android.app.extract_android_style" android:value="default"/>
|
||||
</activity>
|
||||
|
||||
<provider android:name="androidx.core.content.FileProvider" android:authorities="org.happytimesoft.mediaclient.fileprovider" android:grantUriPermissions="true" android:exported="false">
|
||||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths"/>
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.DEVICE_POWER"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
</manifest>
|
||||
87
MediaClient/MediaClientForMobile/android/build.gradle
Normal file
@@ -0,0 +1,87 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.1'
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation "androidx.security:security-crypto:1.1.0-alpha03"
|
||||
implementation "androidx.security:security-identity-credential:1.0.0-alpha02"
|
||||
}
|
||||
|
||||
android {
|
||||
/*******************************************************
|
||||
* The following variables:
|
||||
* - androidBuildToolsVersion,
|
||||
* - androidCompileSdkVersion
|
||||
* - qtAndroidDir - holds the path to qt android files
|
||||
* needed to build any Qt application
|
||||
* on Android.
|
||||
*
|
||||
* are defined in gradle.properties file. This file is
|
||||
* updated by QtCreator and androiddeployqt tools.
|
||||
* Changing them manually might break the compilation!
|
||||
*******************************************************/
|
||||
|
||||
compileSdkVersion androidCompileSdkVersion
|
||||
buildToolsVersion androidBuildToolsVersion
|
||||
ndkVersion androidNdkVersion
|
||||
|
||||
// Extract native libraries from the APK
|
||||
packagingOptions.jniLibs.useLegacyPackaging true
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = [qtAndroidDir + '/src', 'src', 'java']
|
||||
aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl']
|
||||
res.srcDirs = [qtAndroidDir + '/res', 'res']
|
||||
resources.srcDirs = ['resources']
|
||||
renderscript.srcDirs = ['src']
|
||||
assets.srcDirs = ['assets']
|
||||
jniLibs.srcDirs = ['libs']
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.incremental = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
// Do not compress Qt binary resources file
|
||||
aaptOptions {
|
||||
noCompress 'rcc'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
resConfig "en"
|
||||
minSdkVersion 24
|
||||
targetSdkVersion qtTargetSdkVersion
|
||||
ndk.abiFilters = qtTargetAbiList.split(",")
|
||||
}
|
||||
}
|
||||
16
MediaClient/MediaClientForMobile/android/gradle.properties
Normal file
@@ -0,0 +1,16 @@
|
||||
# Project-wide Gradle settings.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2500m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
# Enable building projects in parallel
|
||||
org.gradle.parallel=true
|
||||
|
||||
# Gradle caching allows reusing the build artifacts from a previous
|
||||
# build with the same inputs. However, over time, the cache size will
|
||||
# grow. Uncomment the following line to enable it.
|
||||
#org.gradle.caching=true
|
||||
|
||||
android.useAndroidX=true
|
||||
BIN
MediaClient/MediaClientForMobile/android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
5
MediaClient/MediaClientForMobile/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
234
MediaClient/MediaClientForMobile/android/gradlew
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
MediaClient/MediaClientForMobile/android/gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 37 KiB |
21
MediaClient/MediaClientForMobile/android/res/values/libs.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<!-- DO NOT EDIT THIS: This file is populated automatically by the deployment tool. -->
|
||||
|
||||
<array name="bundled_libs">
|
||||
<!-- %%INSERT_EXTRA_LIBS%% -->
|
||||
</array>
|
||||
|
||||
<array name="qt_libs">
|
||||
<!-- %%INSERT_QT_LIBS%% -->
|
||||
</array>
|
||||
|
||||
<array name="load_local_libs">
|
||||
<!-- %%INSERT_LOCAL_LIBS%% -->
|
||||
</array>
|
||||
|
||||
<string name="static_init_classes"><!-- %%INSERT_INIT_CLASSES%% --></string>
|
||||
<string name="use_local_qt_libs"><!-- %%USE_LOCAL_QT_LIBS%% --></string>
|
||||
<string name="bundle_local_qt_libs"><!-- %%BUNDLE_LOCAL_QT_LIBS%% --></string>
|
||||
<string name="system_libs_prefix"><!-- %%SYSTEM_LIBS_PREFIX%% --></string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<external-path path="." name="external" />
|
||||
<files-path path="." name="path" />
|
||||
</paths>
|
||||
@@ -0,0 +1,142 @@
|
||||
|
||||
package org.happytimesoft.util;
|
||||
|
||||
import java.io.File;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.net.wifi.WifiManager.MulticastLock;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.os.Build;
|
||||
import android.os.StrictMode;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import android.content.ActivityNotFoundException;
|
||||
|
||||
|
||||
public class HtUtil
|
||||
{
|
||||
private static MulticastLock m_wifiLock;
|
||||
private static WakeLock m_wakeLock;
|
||||
|
||||
public HtUtil()
|
||||
{
|
||||
}
|
||||
|
||||
public static void enableMulticast(Context context)
|
||||
{
|
||||
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||
m_wifiLock = wm.createMulticastLock("htutil");
|
||||
|
||||
if (m_wifiLock != null)
|
||||
{
|
||||
m_wifiLock.setReferenceCounted(true);
|
||||
m_wifiLock.acquire();
|
||||
}
|
||||
}
|
||||
|
||||
public static void disableMulticast()
|
||||
{
|
||||
if (m_wifiLock != null)
|
||||
{
|
||||
m_wifiLock.release();
|
||||
m_wifiLock = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getMIMEType(String filename)
|
||||
{
|
||||
if (filename.endsWith(".jpg") ||
|
||||
filename.endsWith(".jpeg") ||
|
||||
filename.endsWith(".JPG") ||
|
||||
filename.endsWith(".JPEG"))
|
||||
return "image/jpeg";
|
||||
if (filename.endsWith(".mp4") || filename.endsWith(".MP4"))
|
||||
return "video/mp4";
|
||||
if (filename.endsWith(".avi") || filename.endsWith(".AVI"))
|
||||
return "video/x-msvideo";
|
||||
if (filename.endsWith(".txt") || filename.endsWith(".TXT"))
|
||||
return "text/plain";
|
||||
else
|
||||
return "*/*";
|
||||
}
|
||||
|
||||
public static void openFile(Context context, String path, String provider)
|
||||
{
|
||||
Uri uri;
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
File file = new File(path);
|
||||
String type = getMIMEType(path);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
{
|
||||
uri = FileProvider.getUriForFile(context, provider, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = Uri.fromFile(file);
|
||||
}
|
||||
|
||||
try {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.setDataAndType(uri, type);
|
||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
|
||||
context.startActivity(intent);
|
||||
}
|
||||
catch (ActivityNotFoundException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static void disableLockScreen(Context context)
|
||||
{
|
||||
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
m_wakeLock = pm.newWakeLock(pm.SCREEN_BRIGHT_WAKE_LOCK | pm.ON_AFTER_RELEASE, "htutil");
|
||||
|
||||
if (m_wakeLock != null)
|
||||
{
|
||||
m_wakeLock.acquire();
|
||||
}
|
||||
}
|
||||
|
||||
public static void enableLockScreen()
|
||||
{
|
||||
if (null != m_wakeLock && m_wakeLock.isHeld())
|
||||
{
|
||||
m_wakeLock.release();
|
||||
m_wakeLock = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static int requestPermission(Context context, String permission)
|
||||
{
|
||||
int r = ContextCompat.checkSelfPermission(context, permission);
|
||||
if (r != PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
ActivityCompat.requestPermissions((Activity)context, new String[]{permission}, 10000);
|
||||
|
||||
r = ContextCompat.checkSelfPermission(context, permission);
|
||||
if (r != PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
63
MediaClient/MediaClientForMobile/config.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/***************************************************************************************
|
||||
*
|
||||
* 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 CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include "sys_inc.h"
|
||||
#include <QString>
|
||||
|
||||
#define VERSION_STRING "V3.2"
|
||||
|
||||
#define LANG_SYS 0 // system language
|
||||
#define LANG_ENG 1 // english
|
||||
#define LANG_ZH 2 // chinese
|
||||
|
||||
#define FILE_PROVIDER "org.happytimesoft.mediaclient.fileprovider"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BOOL enableLog; // enable log
|
||||
BOOL rtpMulticast; // whether enable rtp multicast via rtsp
|
||||
BOOL rtpOverUdp; // prefer to use RTP OVER UDP
|
||||
BOOL rtspOverHttp; // rtsp over http
|
||||
BOOL rtspOverWs; // rtsp over websocket
|
||||
|
||||
int videoRenderMode; // 0 - Keep the original aspect ratio, 1 - Filling the whole window
|
||||
int logLevel; // log level, reference sys_log.h
|
||||
int rtspOverHttpPort; // rtsp over http port
|
||||
int rtspOverWsPort; // rtsp over websocket port
|
||||
int sysLang; // system language
|
||||
int recordSize; // max video recording size, kb
|
||||
int recordTime; // max video recording time, second
|
||||
int hwDecoding; // hardware-acceleration decoding
|
||||
int layoutMode; // layout mode
|
||||
} SysConfig;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QString url; // url
|
||||
QString user; // login user
|
||||
QString pass; // login pass
|
||||
} CHANNEL;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
43
MediaClient/MediaClientForMobile/formClass/About.cpp
Normal 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()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
41
MediaClient/MediaClientForMobile/formClass/About.h
Normal 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
|
||||
|
||||
|
||||
186
MediaClient/MediaClientForMobile/formClass/FileBrowse.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
60
MediaClient/MediaClientForMobile/formClass/FileBrowse.h
Normal 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
|
||||
|
||||
|
||||
50
MediaClient/MediaClientForMobile/formClass/InstMsgDialog.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
43
MediaClient/MediaClientForMobile/formClass/InstMsgDialog.h
Normal 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
|
||||
|
||||
|
||||
863
MediaClient/MediaClientForMobile/formClass/MediaClient.cpp
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
90
MediaClient/MediaClientForMobile/formClass/MediaClient.h
Normal 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
|
||||
|
||||
|
||||
69
MediaClient/MediaClientForMobile/formClass/OpenMedia.cpp
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
49
MediaClient/MediaClientForMobile/formClass/OpenMedia.h
Normal 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
|
||||
|
||||
128
MediaClient/MediaClientForMobile/formClass/SystemSetting.cpp
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
56
MediaClient/MediaClientForMobile/formClass/SystemSetting.h
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
732
MediaClient/MediaClientForMobile/formClass/VideoWidget.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
117
MediaClient/MediaClientForMobile/formClass/VideoWidget.h
Normal 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
|
||||
|
||||
|
||||
52
MediaClient/MediaClientForMobile/ios/Info.plist
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleAllowMixedLocalizations</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${QMAKE_SHORT_VERSION}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${QMAKE_FULL_VERSION}</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NOTE</key>
|
||||
<string>This file was generated by Qt/QMake.</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>connect to server</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen.storyboard</string>
|
||||
<key>UIRequiresPersistentWiFi</key>
|
||||
<true/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,3 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
@interface DocViewController : UIViewController <UIDocumentInteractionControllerDelegate>
|
||||
@end
|
||||
20
MediaClient/MediaClientForMobile/ios/file_view_controller.mm
Normal file
@@ -0,0 +1,20 @@
|
||||
#import "file_view_controller.h"
|
||||
@interface DocViewController ()
|
||||
@end
|
||||
@implementation DocViewController
|
||||
#pragma mark -
|
||||
#pragma mark View Life Cycle
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
}
|
||||
#pragma mark -
|
||||
#pragma mark Document Interaction Controller Delegate Methods
|
||||
- (UIViewController *) documentInteractionControllerViewControllerForPreview: (UIDocumentInteractionController *) controller {
|
||||
//return [[[[UIApplication sharedApplication]windows] firstObject]rootViewController];
|
||||
return self;
|
||||
}
|
||||
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller
|
||||
{
|
||||
[self removeFromParentViewController];
|
||||
}
|
||||
@end
|
||||
8
MediaClient/MediaClientForMobile/ios/ios_launcher.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef IOS_LAUNCHER_H
|
||||
#define IOS_LAUNCHER_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
bool iosLaunchFile(QString file);
|
||||
|
||||
#endif // IOS_LAUNCHER_H
|
||||
31
MediaClient/MediaClientForMobile/ios/ios_launcher.mm
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "ios_launcher.h"
|
||||
#include "file_view_controller.h"
|
||||
#include <QString>
|
||||
#import <UIKit/UIDocumentInteractionController.h>
|
||||
|
||||
bool iosLaunchFile(QString file)
|
||||
{
|
||||
NSString* url = file.toNSString();
|
||||
NSURL* fileURL = [NSURL fileURLWithPath:url];
|
||||
static DocViewController* mtv = nil;
|
||||
if (mtv!=nil)
|
||||
{
|
||||
[mtv removeFromParentViewController];
|
||||
[mtv release];
|
||||
}
|
||||
|
||||
UIDocumentInteractionController* documentInteractionController = nil;
|
||||
documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
|
||||
|
||||
UIViewController* rootv = [[[[UIApplication sharedApplication]windows] firstObject]rootViewController];
|
||||
if (rootv!=nil)
|
||||
{
|
||||
mtv = [[DocViewController alloc] init];
|
||||
[rootv addChildViewController:mtv];
|
||||
documentInteractionController.delegate = mtv;
|
||||
[documentInteractionController presentPreviewAnimated:NO];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||