diff --git a/QQtExample.pro b/QQtExample.pro index 505c3bc1..9c7b40c3 100644 --- a/QQtExample.pro +++ b/QQtExample.pro @@ -80,10 +80,11 @@ SUBDIRS += test/qqtdicttest2 #SUBDIRS += test/giftest #必开 这个例子是关于LibQQt MultiMedia的最好展示 -# -greaterThan(QT_VERSION, 4.6.0):SUBDIRS += test/voicetest -# -mac:lessThan(QT_MAJOR_VERSION , 5):SUBDIRS -= test/voicetest +SUBDIRS += test/voicetest +SUBDIRS += test/voicetest2 +SUBDIRS += test/videotest +SUBDIRS += test/videotest2 +SUBDIRS += test/videotest3 #这边是个组合项,客户端和服务器一起的。必看 #SUBDIRS += examples/qqtclientexample diff --git a/QQtExample_App.pro b/QQtExample_App.pro index a3b4e23e..31477471 100644 --- a/QQtExample_App.pro +++ b/QQtExample_App.pro @@ -109,10 +109,11 @@ SUBDIRS += test/qqtdicttest2 SUBDIRS += test/giftest #必开 这个例子是关于LibQQt MultiMedia的最好展示 -# -greaterThan(QT_VERSION, 4.6.0):SUBDIRS += test/voicetest -# -mac:lessThan(QT_MAJOR_VERSION , 5):SUBDIRS -= test/voicetest +SUBDIRS += test/voicetest +SUBDIRS += test/voicetest2 +SUBDIRS += test/videotest +SUBDIRS += test/videotest2 +SUBDIRS += test/videotest3 # SUBDIRS += examples/qqtclientexample # diff --git a/README.md b/README.md index 3ccfd734..af4985d3 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ github link: https://github.com/AbelTian/LibQQt - *全在frame文件夹* 8. 支持多页表格 [QQtMultiPageTableWidget](src/widgets/qqtmultipagetablewidget.h) 9. 添加 [QQtApplication](src/frame/qqtapplication.h),支持入门级、通用级、专用级嵌入式App所必须的初始化内容 -5. 支持Qt5.9.2 +5. 支持Qt5.8,Qt5.9.2 - 建议桌面使用这个版本,对三大桌面,和IOS Android e-linux支持都很好。 0. 跨平台支持macOS、iOS、Android、Windows、Linux、MIPS、ARM等。 1. 添加矢量图形widgets @@ -108,9 +108,13 @@ github link: https://github.com/AbelTian/LibQQt - 添加内存服务器(一套Input(Reader),Output(Writer)),处理内存和设备之间的数据交互。(这部分的功能完全按照为内存服务的思路设计研发。) - [QQtAudioManager](src/multimedia/qqtaudiomanager.h)、 - 将 AudioInputDevice 和 AudioOutputDevice 当做一个设备进行读写,App处理获取到的声音。 + - 增加QQtWavAudioManager、QQtWavSoundEffect、QQtWavSound, + - 像操作一个设备一样读、写wav文件。 + - 增加QQtVideoManager、QQtLogicVideoManager, + - 支持桌面摄像头采集画面,支持模拟摄像头采集画面。 6. 添加Http功能支持工具 - QQtWebAccessManager,支持管理Session、Cookies。 - - 添加GumboQuery爬虫工具。 + - 添加GumboQuery爬虫工具,爬取网页信息。 - 支持webservice (QtSoap) 8. 添加Qt没有的组件QQtTitleBar - 可以组完全自定义的Form。 @@ -194,7 +198,7 @@ LibQQt R3支持Qt5,由于使用Multi-link 2,不支持Qt4。 邮箱: tianduanrui@163.com QQ: 2657635903 - +LibQQt技术分享和交流群: 560584206 ======================================================================== # 用户使用协议 diff --git a/demo/QQtRoseMonitor/qqtosdform.cpp b/demo/QQtRoseMonitor/qqtosdform.cpp index 3ec917af..71dfda85 100644 --- a/demo/QQtRoseMonitor/qqtosdform.cpp +++ b/demo/QQtRoseMonitor/qqtosdform.cpp @@ -38,7 +38,7 @@ QQtOsdForm::QQtOsdForm ( QWidget* parent ) : //setWindowFlag ( Qt::WindowSystemMenuHint, true ); //setAttribute ( Qt::WA_DeleteOnClose, true ); - setPixmap ( qrc ( "rose.png" ) ); + setPixmap ( conf_qrc ( "rose.png" ) ); } QQtOsdForm::~QQtOsdForm() diff --git a/examples/qqtaudioexample/AppRoot/res/9763.wav b/examples/qqtaudioexample/AppRoot/res/9763.wav new file mode 100644 index 00000000..91b8faad Binary files /dev/null and b/examples/qqtaudioexample/AppRoot/res/9763.wav differ diff --git a/examples/qqtaudioexample/android/AndroidManifest.xml b/examples/qqtaudioexample/android/AndroidManifest.xml new file mode 100644 index 00000000..75006f8d --- /dev/null +++ b/examples/qqtaudioexample/android/AndroidManifest.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/qqtaudioexample/android/res/drawable-hdpi/icon.png b/examples/qqtaudioexample/android/res/drawable-hdpi/icon.png new file mode 100644 index 00000000..c214b280 Binary files /dev/null and b/examples/qqtaudioexample/android/res/drawable-hdpi/icon.png differ diff --git a/examples/qqtaudioexample/android/res/drawable-ldpi/icon.png b/examples/qqtaudioexample/android/res/drawable-ldpi/icon.png new file mode 100644 index 00000000..e21e1c98 Binary files /dev/null and b/examples/qqtaudioexample/android/res/drawable-ldpi/icon.png differ diff --git a/examples/qqtaudioexample/android/res/drawable-mdpi/icon.png b/examples/qqtaudioexample/android/res/drawable-mdpi/icon.png new file mode 100644 index 00000000..24680bc7 Binary files /dev/null and b/examples/qqtaudioexample/android/res/drawable-mdpi/icon.png differ diff --git a/examples/qqtaudioexample/android/res/values/libs.xml b/examples/qqtaudioexample/android/res/values/libs.xml new file mode 100644 index 00000000..4009a778 --- /dev/null +++ b/examples/qqtaudioexample/android/res/values/libs.xml @@ -0,0 +1,25 @@ + + + + https://download.qt.io/ministro/android/qt5/qt-5.9 + + + + + + + + + + + + + + + + + + + + diff --git a/examples/qqtaudioexample/main.cpp b/examples/qqtaudioexample/main.cpp new file mode 100644 index 00000000..30c9ad7b --- /dev/null +++ b/examples/qqtaudioexample/main.cpp @@ -0,0 +1,12 @@ +#include "mainwindow.h" +#include + +int main ( int argc, char* argv[] ) +{ + QQtApplication a ( argc, argv ); + + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/examples/qqtaudioexample/mainwindow.cpp b/examples/qqtaudioexample/mainwindow.cpp new file mode 100644 index 00000000..3e2b32c6 --- /dev/null +++ b/examples/qqtaudioexample/mainwindow.cpp @@ -0,0 +1,45 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include + +MainWindow::MainWindow ( QWidget* parent ) : + QMainWindow ( parent ), + ui ( new Ui::MainWindow ) +{ + ui->setupUi ( this ); + + //wavManager设置待播放的文件,inputFormat起效 + wavManager.setInputSourceFile ( conf_res ( "9763.wav" ) ); + //audManager设置输出设备,也就是设置输出喇叭,并且,这里的并且很重要,设置输出格式,等于wav里的音频的格式。 + audManager.outputDeviceInfo() = QQtAudioManager::defaultOutputDevice(); + audManager.outputAudioFormat() = wavManager.inputAudioFormat(); + + //连接wavManager的音频帧接收槽,这里其实是个接收器,在接收器里播放。 + connect ( &wavManager, SIGNAL ( readyRead() ), this, SLOT ( on_play_frame() ) ); + ; + + //这个是专门为使用机械硬盘设置的,减慢读取timer,要不有滋滋的噪音。 + wavManager.inputManager()->setTimerInterval ( 100 ); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::on_pushButton_clicked() +{ + wavManager.stopInput(); + audManager.stopOutput(); + + audManager.startDefaultOutput(); + wavManager.startInput(); +} + +void MainWindow::on_play_frame() +{ + //这里readAll就是读一帧,(wavManger内部对音频进行了切帧)。 + QByteArray bytes = wavManager.readAll(); + //播放 + audManager.write ( bytes ); +} diff --git a/examples/qqtaudioexample/mainwindow.h b/examples/qqtaudioexample/mainwindow.h new file mode 100644 index 00000000..fc399e91 --- /dev/null +++ b/examples/qqtaudioexample/mainwindow.h @@ -0,0 +1,34 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +#include "qqtwavaudiomanager.h" +#include "qqtaudiomanager.h" + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow ( QWidget* parent = 0 ); + ~MainWindow(); + +public slots: + void on_play_frame(); + +private slots: + void on_pushButton_clicked(); + +private: + Ui::MainWindow* ui; + + QQtWavAudioManager wavManager; + QQtAudioManager audManager; +}; + +#endif // MAINWINDOW_H diff --git a/examples/qqtaudioexample/mainwindow.ui b/examples/qqtaudioexample/mainwindow.ui new file mode 100644 index 00000000..b6328544 --- /dev/null +++ b/examples/qqtaudioexample/mainwindow.ui @@ -0,0 +1,35 @@ + + + MainWindow + + + + 0 + 0 + 229 + 351 + + + + MainWindow + + + + + + 50 + 50 + 111 + 31 + + + + Play + + + + + + + + diff --git a/examples/qqtaudioexample/qqtaudioexample.pro b/examples/qqtaudioexample/qqtaudioexample.pro new file mode 100644 index 00000000..fcba30ab --- /dev/null +++ b/examples/qqtaudioexample/qqtaudioexample.pro @@ -0,0 +1,69 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-04-19T07:52:51 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = qqtaudioexample +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 + +# 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 + + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +CONFIG += mobility +MOBILITY = + +system(touch main.cpp) + +include(../../multi-link/multi-link/add_base_manager.pri) + + + +contains(QSYS_PRIVATE, Android|AndroidX86) { + CONFIG += mobility + MOBILITY = + DISTFILES += \ + android/AndroidManifest.xml + + ANDROID_PACKAGE_SOURCE_DIR = $${PWD}/android +} + +RESOURCES += \ + qqtaudioexample.qrc + +#这个的设置有特点,要先设置 +add_version (1,0,0,0) + +#先发布App +#app从build到deploy +add_deploy() + +#后发布依赖 +#libQQt从sdk到build和deploy +add_dependent_manager(QQt) + +#发布配置文件 把AppRoot里的配置项目拷贝到运行目录和发布目录 +add_deploy_config($${PWD}/AppRoot) diff --git a/examples/qqtaudioexample/qqtaudioexample.qrc b/examples/qqtaudioexample/qqtaudioexample.qrc new file mode 100644 index 00000000..9062d140 --- /dev/null +++ b/examples/qqtaudioexample/qqtaudioexample.qrc @@ -0,0 +1,5 @@ + + + AppRoot/res/9763.wav + + diff --git a/multi-environ/README.md b/multi-environ/README.md new file mode 100644 index 00000000..a2c58ac4 --- /dev/null +++ b/multi-environ/README.md @@ -0,0 +1,118 @@ +# Multi-environ Technology + +为了方便用户在命令行里工作,我开发了多环境管理器Multi-environ Manager(即PyMake), +在此为LibQQt提供多环境编译支持,具备方便的同时编译能力。 + +# 安装PyMake + +如果电脑上没有PyMake,需要先安装, +PyMake可以帮助用户在命令行里做各种工作,不仅仅限于此处编译,所以,请自行事先安装。 + +#### 下载PyMake安装包 +######国内 +PyMake Gitee Clone:[https://gitee.com/drabel/PyMake.git](https://gitee.com/drabel/PyMake.git) +PyMake V7.8.2 Zip包:[https://gitee.com/drabel/PyMake/repository/archive/v7.8.2](https://gitee.com/drabel/PyMake/repository/archive/v7.8.2) +######国外 +PyMake Github Clone:[https://github.com/AbelTian/PyMake.git](https://github.com/AbelTian/PyMake.git) + +#### 安装PyMake +1. 需要管理员权限,切换到PyMake目录,install.bat %*。Unix系统install.sh。 + +#### 配置PyMake +```bash + +# 更改多环境根目录到自己定义的目录。 +pymake source root + +# 更改环境文件到自己私有的环境配置文件,一般一台电脑用一个环境文件。 +pymake source config + +# 使用我在Windows上的环境配置文件,初始化自己的环境文件。 +pymake port file /example/pymake7-win-tai5.json / + +# 修改/环境文件里的几个命名路径。 +pymake source config --edit + +# 查看一次所有设置 +pymake get all settings -a -r + +# 修改以下字段,不限于这些字段,建议用户一次配置好长期使用。 +# path-assemblage: + # root路径,一系列根路径 + # cc路径,这个路径下有PyMake + # wincc路径,这个路径下有cmake和很多品种语言的解释器 + # qt路径 + # android路径 + # java路径 + # 人工检查配置其他路径 + +# 修改/custom.path+.ini + # ${cmake.bin} 添加一行,用于支持cmake编译。如果需要,还可以增加很多其他路径。 + +# 修改完路径后,查看一下环境,你需要编译几个环境的,就查看几个环境 +pymake env mingw32 +pymake env mingw64 +pymake env android.mobile +pymake env android.x86 +pymake env msvc2015 +pymake env msvc2015.x64 +pymake env mscos +pymake env ios +pymake env gcc +pymake env armhf32 +pymake env mips32 + +# 查看一遍以后,检查一下环境配置的是否正确,如果不正确及时修改,你需要编译几个环境的,就检查几个环境,还可以检查path、cmd配置是否正确 +pymake chk -slc +pymake chk path -a +pymake chk cmd -a +pymake chk mingw32 +pymake chk mingw64 +pymake chk android.mobile +pymake chk android.x86 +pymake chk msvc2015 +pymake chk msvc2015.x64 +pymake chk mscos +pymake chk ios +pymake chk gcc +pymake chk armhf32 +pymake chk mips32 + +``` + +# 使用PyMake开始编译 + +PyMake只需要配置一次,以后,直接开始编译即可。 + +```bash + +# 环境检查无误,修改/里的qqt.build.all命令 +set MODULEARRAY=QQt ...还有其他的库才会需要添加其他的库名,用空格分隔 +set ENVARRAY=mingw32 ...需要编译几个环境的就添加几个环境,用空格分隔 + +# 切换到LibQQt的上一层目录,开始编译 +# 导出qqt.build.all这一个命令 +pymake type here qqt.build.all to qqt.build.all +# 开始 +qqt.build.all.bat +# 如果一切正常,会开启多个编译命令行。实现同时多环境编译。 这个脚本可以多次使用。我测试的开启52个编译环境命令行,正常编译。这取决于你的电脑的能力。 + +# 如果不希望导出这个命令,那么执行以下命令, +pymake system ccvp here qqt.build.all +# 如果一切正常,现象同上。 + +# 如果仅仅编译一个环境的目标,那么执行以下命令, +# 切换到LibQQt源代码目录,编译mingw32环境的目标 +pymake use mingw32 ccvp here build.qmake QQt + +# 如果需要其他功能支持,在/里command组下,添加自己的命令即可。PyMake提供多种模式的ccvp直接执行。 +``` + +# 编译截图 + +![](a0.png) +![](a1.png) +![](b0.png) +![](b1.png) +![](b2.png) +![](c0.png) \ No newline at end of file diff --git a/multi-environ/a0.png b/multi-environ/a0.png new file mode 100644 index 00000000..752dda82 Binary files /dev/null and b/multi-environ/a0.png differ diff --git a/multi-environ/a1.png b/multi-environ/a1.png new file mode 100644 index 00000000..7f0714dd Binary files /dev/null and b/multi-environ/a1.png differ diff --git a/multi-environ/b0.png b/multi-environ/b0.png new file mode 100644 index 00000000..d6fa0a0f Binary files /dev/null and b/multi-environ/b0.png differ diff --git a/multi-environ/b1.png b/multi-environ/b1.png new file mode 100644 index 00000000..782b9796 Binary files /dev/null and b/multi-environ/b1.png differ diff --git a/multi-environ/b2.png b/multi-environ/b2.png new file mode 100644 index 00000000..534ad887 Binary files /dev/null and b/multi-environ/b2.png differ diff --git a/multi-environ/c0.png b/multi-environ/c0.png new file mode 100644 index 00000000..f62d91e1 Binary files /dev/null and b/multi-environ/c0.png differ diff --git a/multi-link b/multi-link index dbb43fa3..131c27f3 160000 --- a/multi-link +++ b/multi-link @@ -1 +1 @@ -Subproject commit dbb43fa39b64a4c1a713edcc8c05dee2a5209e27 +Subproject commit 131c27f39bbffe61498ca33c54e836430122307c diff --git a/project.md b/project.md index 7bcceab4..cde2c88c 100644 --- a/project.md +++ b/project.md @@ -5,11 +5,11 @@ |LibQQt(主库)| [工程链接](https://gitee.com/drabel/LibQQt) |Commercial,GPL Series| |QQtExquisite|[工程链接](https://gitee.com/drabel/QQtExquisite)|Commercial,GPL Series| |QQtHighGrade|[工程链接](https://gitee.com/drabel/QQtHighGrade)|Commercial,GPL Series| -|QQtInput|[工程链接](https://gitee.com/drabel/QQtInput)|Commercial,GPL Series| |QQtRuntimeExtention|[工程链接](https://gitee.com/drabel/QQtRuntimeExtention)|Commercial,GPL Series| |QQtInstallFramework|[工程链接](https://gitee.com/drabel/QQtInstallFramework)|Commercial,GPL Series| |QQtTool|[工程链接](https://gitee.com/drabel/QQtTool)|Commercial,GPL Series| |QQtMediaExtention|[工程链接](https://gitee.com/drabel/QQtMediaExtention)|Commercial| +|QQtInput|[工程链接](https://gitee.com/drabel/QQtInput)|Commercial| |QQtSupport|[工程链接](https://gitee.com/drabel/QQtSupport)|Commercial| |QQtExquisitePlugin|[工程链接](https://gitee.com/drabel/QQtExquisitePlugin)|Commercial| |QQtIndustrialControl|[工程链接](https://gitee.com/drabel/QQtIndustrialControl)|Commercial| diff --git a/src/QQt.pro b/src/QQt.pro index 8d0542e1..943726c3 100644 --- a/src/QQt.pro +++ b/src/QQt.pro @@ -18,7 +18,7 @@ ################################################################# ##Usage ################################################################# -#Suggest Qt 5.9.2/4.8.6/4.8.7 +#Suggest Qt 5.8/5.9.2/4.8.6/4.8.7 #please dont use Qt 5.9.1, it is broken with android and ios. #please dont modify this pro #use LibQQt you need change Qt Creator default build directory: your-pc-build-station/%{CurrentProject:Name}/%{CurrentKit:FileSystemName}/%{Qt:Version}/%{CurrentBuild:Name} (Only Once) diff --git a/src/core/qqtdictionary.cpp b/src/core/qqtdictionary.cpp index d77a6458..295b7028 100644 --- a/src/core/qqtdictionary.cpp +++ b/src/core/qqtdictionary.cpp @@ -533,13 +533,28 @@ void QQtDictionary::parseDictionaryToJsonValue ( const QQtDictionary& node, QJso QList& l = node.getList(); QJsonValue value; parseDictionaryToJsonValue ( l[i], value ); - array.append ( value ); + //array.append ( value ); + array.push_back ( value ); } result = array; break; } case DictMap: + { + //"name": {"a":"b", "a2":"b2", "a3":["b31", "b32"], "a4":{"a41":"b41", "a42":"b42"}, ...} + QJsonObject object; + for ( QMap::Iterator itor = node.getMap().begin(); itor != node.getMap().end(); itor++ ) + { + //QMap& m = node.getMap(); + const QString& key = itor.key(); + const QQtDictionary& srcvalue = itor.value(); + QJsonValue value; + parseDictionaryToJsonValue ( srcvalue, value ); + object.insert ( key, value ); + } + result = object; break; + } case DictMax: default: break; diff --git a/src/core/qqtdictionary.h b/src/core/qqtdictionary.h index 4e34d0e5..d748af37 100644 --- a/src/core/qqtdictionary.h +++ b/src/core/qqtdictionary.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -14,11 +14,11 @@ class QQtDictionary; typedef QMap QQtDictionaryMap; typedef QMapIterator QQtDictionaryMapIterator; -typedef QMutableMapIterator QQtDictionaryMutableMapIterator; +typedef QMutableMapIterator QQtDictionaryMapConstIterator; typedef QList QQtDictionaryList; typedef QListIterator QQtDictionaryListIterator; -typedef QMutableListIterator QQtDictionaryMutableListIterator; +typedef QMutableListIterator QQtDictionaryListConstIterator; /** * @brief The QQtDictionary class @@ -30,8 +30,8 @@ typedef QMutableListIterator QQtDictionaryMutableListIterator; * 接受嵌套访问 操作方式 dict["cccc"][0]["eeeee"] * 通过重载函数来实现类型的变化,不建议使用中更改类型。 * 比json和xml的数据结构要庞大。toJson toXML fromJson fromXML - * QVariant 不能直接获取到真实数据,改变必须使用临时变量。 - * 而且,接口设计也不够灵活,存入和取出都不太方便。 + * QVariant 不能直接获取到真实数据,改变必须使用临时变量,而且,接口设计也不够灵活,存入和取出都不太方便。 + * QQtDictionary封装了QVariant,实现直接操作真实数据。提供大量操作符。存取数据方便快捷,类型多样。 */ class QQTSHARED_EXPORT QQtDictionary { diff --git a/src/core/qqtorderedmap.cpp b/src/core/qqtorderedmap.cpp new file mode 100644 index 00000000..85d6bacb --- /dev/null +++ b/src/core/qqtorderedmap.cpp @@ -0,0 +1 @@ +#include diff --git a/src/core/qqtorderedmap.h b/src/core/qqtorderedmap.h new file mode 100644 index 00000000..30ee6b4d --- /dev/null +++ b/src/core/qqtorderedmap.h @@ -0,0 +1,6 @@ +#ifndef QQTORDEREDMAP_H +#define QQTORDEREDMAP_H + +#include + +#endif // QQTORDEREDMAP_H diff --git a/src/exquisite/qqtpicturetabbar.cpp b/src/exquisite/qqtpicturetabbar.cpp index ad72cd51..5e318aa4 100644 --- a/src/exquisite/qqtpicturetabbar.cpp +++ b/src/exquisite/qqtpicturetabbar.cpp @@ -58,11 +58,11 @@ void QQtPictureTabBar::setSelectedTextColor ( QColor selectedTextColor ) void QQtPictureTabBar::tabPixmap ( int index, QImage& img, QImage& imgSel ) { - if ( index < 0 || index + 1 > count() || index + 1 > imgList.size() ) + if ( index < 0 || index + 1 > count() || index + 1 > dict1["image"].size() ) return; - img = QImage ( imgList[index][BTN_NORMAL] ); - imgSel = QImage ( imgList[index][BTN_PRESS] ); + img = QImage ( dict1["image"][index][BTN_NORMAL].getValue().toString() ); + imgSel = QImage ( dict1["image"][index][BTN_PRESS].getValue().toString() ); return ; } @@ -72,20 +72,20 @@ void QQtPictureTabBar::setTabPixmap ( int index, const QString& img, const QStri if ( index < 0 || index + 1 > count() ) return; - TBtnIconTable table; - table[BTN_NORMAL] = img; - table[BTN_PRESS] = imgSel; - imgList.insert ( index, table ); + dict1["image"][index][BTN_NORMAL] = img; + dict1["image"][index][BTN_PRESS] = imgSel; } void QQtPictureTabBar::tabIcon ( int index, QImage& icon, QImage& iconSel ) { - if ( index < 0 || index + 1 > count() || index + 1 > imgList.size() ) + if ( index < 0 || index + 1 > count() || index + 1 > dict1["icon"].size() ) return; - icon = QImage ( iconList[index][BTN_NORMAL] ); - iconSel = QImage ( iconList[index][BTN_PRESS] ); + icon = QImage ( dict1["icon"][index][BTN_NORMAL].getValue().toString() ); + iconSel = QImage ( dict1["icon"][index][BTN_PRESS].getValue().toString() ); + //pline() << icon; + //pline() << iconSel; return ; } @@ -95,11 +95,13 @@ void QQtPictureTabBar::setTabIcon ( int index, const QString& icon, const QStrin if ( index < 0 || index + 1 > count() ) return; - TBtnIconTable table; - table[BTN_NORMAL] = icon; - table[BTN_PRESS] = iconSel; - iconList.insert ( index, table ); + dict1["icon"][index][BTN_NORMAL] = icon; + dict1["icon"][index][BTN_PRESS] = iconSel; + + //pline() << dict1["icon"][index][BTN_NORMAL]; + //pline() << dict1["icon"][index][BTN_PRESS]; + } void QQtPictureTabBar::setBackgroundColor ( QColor backgroundColor ) @@ -154,20 +156,20 @@ void QQtPictureTabBar::drawPicture ( QPainter* p ) { QRect tRect0 = tabRect ( index ); - if ( imgList.size() > index ) + if ( dict1["image"].size() > index ) { p->save(); int sel = currentIndex() == index ? BTN_PRESS : BTN_NORMAL; #if 1 //tabRect = rect()? - p->drawPixmap ( tRect0, QIcon ( imgList[index][sel] ).pixmap ( tRect0.size(), QIcon::Normal, QIcon::On ) ); + p->drawPixmap ( tRect0, QIcon ( dict1["image"][index][sel].getValue().toString() ).pixmap ( tRect0.size(), QIcon::Normal, QIcon::On ) ); #endif /* * 失真不明显,使用以下方法 */ #if 0 - QImage image ( iconList[index][sel] ); + QImage image ( dict1["image"][index][sel].getValue().toString() ); p.drawItemPixmap ( tabRectValue, Qt::AlignLeft | Qt::AlignTop, QPixmap::fromImage ( image.scaled ( tabRectValue.size(), Qt::KeepAspectRatio ) ) ); #endif @@ -176,7 +178,7 @@ void QQtPictureTabBar::drawPicture ( QPainter* p ) //为什么不用这个呢?因为上边那个QIcon直接缩放到了完整的符合Icon大小的图.直接居中. //这个不需要,多次一举. #if 0 - p->drawItemPixmap ( tRect0, Qt::AlignCenter, QIcon ( imgList[index][sel] ).pixmap ( tRect0.size(), QIcon::Normal, + p->drawItemPixmap ( tRect0, Qt::AlignCenter, QIcon ( dict1["image"][index][sel].getValue().toString() ).pixmap ( tRect0.size(), QIcon::Normal, QIcon::On ) ); #endif p->restore(); @@ -252,17 +254,17 @@ void QQtPictureTabBar::drawIcon ( QPainter* p ) int sel = BTN_NORMAL; sel = currentIndex() == index ? BTN_PRESS : BTN_NORMAL; - //pline() << iconList.size() << index << iconList[index][sel]; + //pline() << dict1["icon"].size() << index << dict1["icon"][index][sel].getValue().toString(); - if ( iconList.size() > index ) + if ( dict1["icon"].size() > index ) { p->save(); //tabRect = rect()? - p->drawPixmap ( tRect0, QIcon ( iconList[index][sel] ).pixmap ( tRect0.size(), mode, QIcon::On ) ); + p->drawPixmap ( tRect0, QIcon ( dict1["icon"][index][sel].getValue().toString() ).pixmap ( tRect0.size(), mode, QIcon::On ) ); /* * 失真不明显,使用以下方法 */ - //QImage image(iconList[index][sel]); + //QImage image(dict1["icon"][index][sel].getValue().toString()); //p.drawItemPixmap(tabRectValue, Qt::AlignLeft |Qt::AlignTop, QPixmap::fromImage(image.scaled(tabRectValue.size(), Qt::KeepAspectRatio))); p->restore(); } diff --git a/src/exquisite/qqtpicturetabbar.h b/src/exquisite/qqtpicturetabbar.h index 9ae6bb72..bf0a6ec7 100644 --- a/src/exquisite/qqtpicturetabbar.h +++ b/src/exquisite/qqtpicturetabbar.h @@ -8,6 +8,7 @@ #include "qqtwidgets.h" #include "qqttabbar.h" #include "qqt-local.h" +#include "qqtdictionary.h" class QQTSHARED_EXPORT QQtPictureTabBar : public QQtTabBar { @@ -27,6 +28,7 @@ public: /* * 依赖iconSize,layoutSpacing设置图片位置 */ + //default IconStyle_Left_And_RightText, IconStyle_Right_And_LeftText, IconStyle_MiddleText, @@ -85,8 +87,7 @@ protected: public slots: private: - QList imgList; - QList iconList; + QQtDictionary dict1; IconStyle iconStyle; QFont textFont; QColor textColor; diff --git a/src/frame/qqtapplication.cpp b/src/frame/qqtapplication.cpp index ccd4461d..3f84c53f 100644 --- a/src/frame/qqtapplication.cpp +++ b/src/frame/qqtapplication.cpp @@ -52,7 +52,7 @@ QQtApplication::QQtApplication ( int& argc, char** argv ) : #endif qDebug() << tr ( "QQt Application Framework Software [LibQQt]" ); - qDebug() << tr ( "Copyright © 2017 Tianduanrui. All rights reserved." ); + qDebug() << tr ( "Copyright (C) 2017 Tianduanrui. All rights reserved." ); qDebug() << tr ( "Assigned by Dezhou." ); pline() << "Qt version:" << QT_VERSION_STR; @@ -165,7 +165,7 @@ void QQtApplication::setHighDpiScaling ( bool open ) { #if QT_VERSION >= QT_VERSION_CHECK(5,6,0) setAttribute ( Qt::AA_EnableHighDpiScaling, open ); - //setAttribute ( Qt::AA_UseHighDpiPixmaps, open ); + setAttribute ( Qt::AA_UseHighDpiPixmaps, open ); #endif } @@ -214,7 +214,7 @@ bool QQtApplication::setTextFont ( QString fontfile, int fontsize ) /*这个函数没有任何问题,检测完毕。过去的报错是工作目录不对,无法加载其他数据库*/ /*此处,改为使用QFontDatabase的经典静态方法调用方式*/ //ignored - QFontDatabase db; + QFontDatabase fontdb0; int fontID = QFontDatabase::addApplicationFont ( fontfile ); pline() << "font file:" << fontfile; @@ -229,8 +229,8 @@ bool QQtApplication::setTextFont ( QString fontfile, int fontsize ) QString ziti = QFontDatabase::applicationFontFamilies ( fontID ).at ( 0 ); pline() << "font name:" << ziti; - QFont font ( ziti, fontsize ); - QApplication::setFont ( font ); + QFont font1 ( ziti, fontsize ); + QApplication::setFont ( font1 ); return true; } diff --git a/src/frame/qqtframe.h b/src/frame/qqtframe.h index 95ac1c4f..9e1a90d9 100644 --- a/src/frame/qqtframe.h +++ b/src/frame/qqtframe.h @@ -22,43 +22,6 @@ extern "C" { #endif /* __cplusplus */ -enum -{ - Lib_Id = 0, - Lib_Name, - Lib_Creater, - Lib_CreateTime, - Lib_Comment, -}; - -enum -{ - Method_Id = 0, - Method_Name, - Method_Type, - Method_Vessel, -}; - -enum -{ - Stage_Id = 0, - Stage_Index, - Stage_Vessel, - Stage_Timeramp, - Stage_Presspsi, - Stage_Tempture, - Stage_Hold, - Stage_MethodId, -}; - -enum -{ - Type_Standard = 0, - Type_Temprature, - Type_Stressure, - Type_Extract, -}; - enum { Login_Request, @@ -73,19 +36,6 @@ enum }; -typedef enum tagSampleEnum -{ - ESampleId, - ESampleMingcheng, - ESampleBianhao, - ESampleYangpinliang, - ESampleYangpindanwei, - ESampleJieguo, - ESampleJieguodanwei, - ESampleCeshiren, - ESampleCeshishijian, -} ESampleColomn; - enum { Language_English, @@ -114,37 +64,42 @@ enum }; -#define CONFIG_ROOT "." -#define CONFIG_PATH "./conf" -#define LOG_PATH "./log" -#define AV_PATH "./res" -#define SKIN_PATH "./skin" +#define CONFIG_ROOT QString(".") +#define CONFIG_PATH QString(CONFIG_ROOT + "/conf") +#define LOG_PATH QString(CONFIG_ROOT + "/log") +#define AV_PATH QString(CONFIG_ROOT + "/res") +#define SKIN_PATH QString(CONFIG_ROOT + "/skin") +#define FONT_PATH QString(CONFIG_ROOT + "/font") +#define DB_PATH QString(CONFIG_ROOT + "/db") +#define LANG_PATH QString(CONFIG_ROOT + "/lang") #if defined (__ANDROIDX86__) -#define qrc(file) QString("%1/%2").arg("assets:/").arg(file) -#define res(file) QString("%1/%2").arg("assets:/res").arg(file) -#define skin(file) QString("%1/%2").arg("assets:/skin").arg(file) +#define conf_qrc(file) QString("%1/%2").arg("assets:/").arg(file) +#define conf_res(file) QString("%1/%2").arg("assets:/res").arg(file) +#define conf_skin(file) QString("%1/%2").arg("assets:/skin").arg(file) +#define conf_font(file) QString("%1/%2").arg("assets:/font").arg(file) +#define conf_db(file) QString("%1/%2").arg("assets:/db").arg(file) +#define conf_lang(file) QString("%1/%2").arg("assets:/lang").arg(file) #elif defined (__ANDROID__) -#define qrc(file) QString("%1/%2").arg("://").arg(file) -#define res(file) QString("%1/%2").arg("://res").arg(file) -#define skin(file) QString("%1/%2").arg("://skin").arg(file) +#define conf_qrc(file) QString("%1/%2").arg("://").arg(file) +#define conf_res(file) QString("%1/%2").arg("://res").arg(file) +#define conf_skin(file) QString("%1/%2").arg("://skin").arg(file) +#define conf_font(file) QString("%1/%2").arg("://font").arg(file) +#define conf_db(file) QString("%1/%2").arg("://db").arg(file) +#define conf_lang(file) QString("%1/%2").arg("://lang").arg(file) #else -#define qrc(file) QDir(qApp->applicationDirPath()).relativeFilePath(QString("%1/%2").arg(CONFIG_ROOT).arg(file)) -#define res(file) QDir(qApp->applicationDirPath()).relativeFilePath(QString("%1/%2").arg(AV_PATH).arg(file)) -#define skin(file) QDir(qApp->applicationDirPath()).relativeFilePath(QString("%1/%2").arg(SKIN_PATH).arg(file)) +#define conf_qrc(file) QDir().absoluteFilePath(QString("%1/%2").arg(CONFIG_ROOT).arg(file)) +#define conf_res(file) QDir().absoluteFilePath(QString("%1/%2").arg(AV_PATH).arg(file)) +#define conf_skin(file) QDir().absoluteFilePath(QString("%1/%2").arg(SKIN_PATH).arg(file)) +#define conf_font(file) QDir().absoluteFilePath(QString("%1/%2").arg(FONT_PATH).arg(file)) +#define conf_db(file) QDir().absoluteFilePath(QString("%1/%2").arg(DB_PATH).arg(file)) +#define conf_lang(file) QDir().absoluteFilePath(QString("%1/%2").arg(LANG_PATH).arg(file)) #endif - -#define TABLE_LIBRARY "Library" -#define TABLE_METHOD "Method" -#define TABLE_STAGE "Stage" -#define TABLE_EVTYPE "Type" - extern QString gUserName; extern QString gPassword; extern int gAuthority; - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/frame/qqtqssmanager.cpp b/src/frame/qqtqssmanager.cpp index 44127b04..02019c81 100644 --- a/src/frame/qqtqssmanager.cpp +++ b/src/frame/qqtqssmanager.cpp @@ -1,6 +1,9 @@ #include "qqtqssmanager.h" +#include "qqtcore.h" +#include +#include -QQtQSSManager::QQtQSSManager ( QObject* parent ) +QQtQSSManager::QQtQSSManager ( QObject* parent ) : QObject ( parent ) { } @@ -14,7 +17,7 @@ QList QQtQSSManager::styleList() { while ( mStyleList.count() > 0 ) mStyleList.removeAt ( 0 ); - QDir d ( SKIN_PATH ); + QDir d ( conf_skin ( "." ) ); foreach ( QFileInfo mfi, d.entryInfoList() ) { if ( mfi.isFile() ) @@ -24,41 +27,52 @@ QList QQtQSSManager::styleList() //不包括default.qss if ( mfi.baseName() == "default" ) continue; + if ( mfi.baseName() == "current" ) + continue; QString styleName = mfi.completeBaseName(); mStyleList.push_back ( styleName ); } } + //pline() << d.absolutePath(); + //pline() << mStyleList; return mStyleList; } void QQtQSSManager::setCurrentStyle ( QString styleName ) { - if ( !QDir ( skin ( "default.qss" ) ).exists() ) - return; - if ( !QDir ( skin ( QString ( "%1.qss" ).arg ( styleName ) ) ).exists() ) - return; + //pline() << "set style"; + //pline() << conf_skin ( "default.qss" ); + //pline() << QFile ( conf_skin ( "default.qss" ) ).exists() << QDir ( conf_skin ( "default.qss" ) ).exists(); + //pline() << conf_skin ( QString ( "%1.qss" ).arg ( styleName ) ); + //pline() << QFile ( conf_skin ( QString ( "%1.qss" ).arg ( styleName ) ) ).exists() << QDir ( conf_skin ( QString ( "%1.qss" ).arg ( styleName ) ) ).exists(); + if ( !QFile ( conf_skin ( "default.qss" ) ).exists() ) + return; + if ( !QFile ( conf_skin ( QString ( "%1.qss" ).arg ( styleName ) ) ).exists() ) + return; + //pline() << "set style 2" << styleName; #ifdef __EMBEDDED_LINUX__ - QString cmd = QString ( "touch %1" ).arg ( skin ( "current.qss" ) ); + QString cmd = QString ( "touch %1" ).arg ( conf_skin ( "current.qss" ) ); system ( cmd.toLocal8Bit().constData() ); #endif QByteArray bytes; - QFile f1 ( skin ( "default.qss" ) ); + QFile f1 ( conf_skin ( "default.qss" ) ); f1.open ( QFile::ReadOnly ); bytes = f1.readAll(); f1.close(); - QFile f2 ( skin ( QString ( "%1.qss" ).arg ( styleName ) ) ); + QFile f2 ( conf_skin ( QString ( "%1.qss" ).arg ( styleName ) ) ); f2.open ( QFile::ReadOnly ); bytes += f2.readAll(); f2.close(); - QFile file ( skin ( "current.qss" ) ); + QFile file ( conf_skin ( "current.qss" ) ); file.open ( QFile::Truncate | QFile::WriteOnly ); file.write ( bytes ); file.close(); - qqtApp->setQSSStyle ( skin ( "current.qss" ) ); + //pline() << conf_skin ( "current.qss" ); + qqtApp->setQSSStyle ( conf_skin ( "current.qss" ) ); } diff --git a/src/multimedia/libqwav/libqwav.cpp b/src/multimedia/libqwav/libqwav.cpp new file mode 100644 index 00000000..875597d2 --- /dev/null +++ b/src/multimedia/libqwav/libqwav.cpp @@ -0,0 +1,202 @@ +#include "libqwav.h" + +#include +#include + +//header data tail +bool addWavHeader ( QIODevice& outputDevice, const QAudioFormat& format ) +{ + // 开始设置WAV的文件头 + // 这里具体的数据代表什么含义请看上一篇文章(Qt之WAV文件解析)中对wav文件头的介绍 + WAVFILEHEADER WavFileHeader; + qstrcpy ( WavFileHeader.RiffName, "RIFF" ); + qstrcpy ( WavFileHeader.WavName, "WAVE" ); + qstrcpy ( WavFileHeader.FmtName, "fmt " ); + qstrcpy ( WavFileHeader.DATANAME, "data" ); + + // 表示 FMT块 的长度 + WavFileHeader.nFmtLength = 16; + + // 表示 按照PCM 编码; + WavFileHeader.nAudioFormat = 1; + // 声道数目; + WavFileHeader.nChannleNumber = format.channelCount(); + // 采样频率; + WavFileHeader.nSampleRate = format.sampleRate(); + //这个地方,int到unsinged int数据没有丢失。 + //pline() << WavFileHeader.nSampleRate << mFormat.sampleRate(); + // 每次采样得到的样本数据位数; + WavFileHeader.nBitsPerSample = format.sampleSize(); + + // nBytesPerSample 和 nBytesPerSecond这两个值通过设置的参数计算得到; + // 数据块对齐单位(每个采样需要的字节数 = 通道数 × 每次采样得到的样本数据位数 / 8 ) + WavFileHeader.nBlockAlign = WavFileHeader.nChannleNumber * WavFileHeader.nBitsPerSample / 8; + // 波形数据传输速率 + // (每秒平均字节数 = 采样频率 × 通道数 × 每次采样得到的样本数据位数 / 8 = 采样频率 × 每个采样需要的字节数 ) + WavFileHeader.nBytesPerSecond = WavFileHeader.nSampleRate * WavFileHeader.nChannleNumber * + WavFileHeader.nBitsPerSample / 8; + + outputDevice.seek ( 0 ); + //riff 8 + 4 + WavFileHeader.nRiffLength = outputDevice.size() - 8; + outputDevice.write ( WavFileHeader.RiffName, sizeof ( WavFileHeader.RiffName ) - 1 ); + outputDevice.write ( ( char* ) &WavFileHeader.nRiffLength, sizeof ( WavFileHeader.nRiffLength ) ); + outputDevice.write ( WavFileHeader.WavName, sizeof ( WavFileHeader.WavName ) - 1 ); + + //fmt 8 + 16 + outputDevice.write ( WavFileHeader.FmtName, 4 ); + outputDevice.write ( ( char* ) &WavFileHeader.nFmtLength, 4 ); + + outputDevice.write ( ( char* ) &WavFileHeader.nAudioFormat, sizeof ( WavFileHeader.nAudioFormat ) ); + outputDevice.write ( ( char* ) &WavFileHeader.nChannleNumber, sizeof ( WavFileHeader.nChannleNumber ) ); + outputDevice.write ( ( char* ) &WavFileHeader.nSampleRate, sizeof ( WavFileHeader.nSampleRate ) ); + outputDevice.write ( ( char* ) &WavFileHeader.nBytesPerSecond, sizeof ( WavFileHeader.nBytesPerSecond ) ); + outputDevice.write ( ( char* ) &WavFileHeader.nBlockAlign, sizeof ( WavFileHeader.nBlockAlign ) ); + outputDevice.write ( ( char* ) &WavFileHeader.nBitsPerSample, sizeof ( WavFileHeader.nBitsPerSample ) ); + + //data 8 + outputDevice.write ( WavFileHeader.DATANAME, 4 ); + outputDevice.write ( ( char* ) &WavFileHeader.nDataLength, 4 ); + + WavFileHeader.fileHeaderSize = outputDevice.pos(); + + //44 + //int headerSize = WavFileHeader.fileHeaderSize; + //qDebug() << headerSize; + return true; +} + +bool addWavTail ( QIODevice& outputDevice ) +{ + QByteArray tailBytes; + tailBytes += "q\xFCq\xFC"; + tailBytes += "a\xFB"; + tailBytes += "a\xFB"; + //8 + //pline() << tailBytes << tailBytes.size(); + outputDevice.write ( tailBytes ); + return true; +} + + +bool addWavDataBytes ( QIODevice& outputDevice, const QByteArray& bytes ) +{ + outputDevice.write ( bytes ); + return true; +} + +bool wavParse ( QString fileName, WAVFILEHEADER& WavFileHeader ) +{ + QFile fileInfo ( fileName ); + + if ( !fileInfo.open ( QIODevice::ReadOnly ) ) + { + return false; + } + + // 警告:每一次读,都不seek的!用户调用了seek不会引发pos变化,read会。 + + // 读取 资源交换文件标志 "RIFF"; + fileInfo.read ( WavFileHeader.RiffName, sizeof ( WavFileHeader.RiffName ) - 1 ); + + // 读取 RIFF 头后字节数; + fileInfo.read ( ( char* ) &WavFileHeader.nRiffLength, sizeof ( WavFileHeader.nRiffLength ) ); + // 读取 波形文件标识符 "WAVE"; + fileInfo.read ( WavFileHeader.WavName, sizeof ( WavFileHeader.WavName ) - 1 ); + + // 警告:每一次读,都不seek的!用户调用了seek不会引发pos变化,read会。 + while ( 1 ) + { + char tempName[5] = {0}; + unsigned int tempSize = 0; + + fileInfo.read ( tempName, 4 ); + fileInfo.read ( ( char* ) &tempSize, 4 ); + + QString strTempName ( tempName ); + + if ( 0 == strTempName.compare ( "fmt ", Qt::CaseInsensitive ) ) + { + strcpy ( WavFileHeader.FmtName, tempName ); + WavFileHeader.nFmtLength = tempSize; + // 读取 格式种类; + fileInfo.read ( ( char* ) &WavFileHeader.nAudioFormat, sizeof ( WavFileHeader.nAudioFormat ) ); + // 读取 音频通道数目; + fileInfo.read ( ( char* ) &WavFileHeader.nChannleNumber, sizeof ( WavFileHeader.nChannleNumber ) ); + // 读取 采样频率; + fileInfo.read ( ( char* ) &WavFileHeader.nSampleRate, sizeof ( WavFileHeader.nSampleRate ) ); + // 读取 波形数据传输速率; + fileInfo.read ( ( char* ) &WavFileHeader.nBytesPerSecond, sizeof ( WavFileHeader.nBytesPerSecond ) ); + // 读取 数据块对齐单位; + fileInfo.read ( ( char* ) &WavFileHeader.nBlockAlign, sizeof ( WavFileHeader.nBlockAlign ) ); + // 读取 每次采样得到的样本数据位数值; + fileInfo.read ( ( char* ) &WavFileHeader.nBitsPerSample, sizeof ( WavFileHeader.nBitsPerSample ) ); + // 如果有扩展字节 + fileInfo.read ( tempSize - 16 ); + } + else if ( 0 == strTempName.compare ( "fact", Qt::CaseInsensitive ) ) + { + // 存在fact块,读取数据; + strcpy ( WavFileHeader.FactName, tempName ); + // fact块长度; + WavFileHeader.nFactLength = tempSize; + // 读取fact块数据;但是不处理 + fileInfo.read ( tempSize ); + qDebug() << "fact data" << tempName << tempSize; + } + else if ( 0 == strTempName.compare ( "data", Qt::CaseInsensitive ) ) + { + strcpy ( WavFileHeader.DATANAME, tempName ); + WavFileHeader.nDataLength = tempSize; + + // 读取 音频数据大小; + WavFileHeader.fileDataSize = tempSize; + //文件头大小; + WavFileHeader.fileHeaderSize = fileInfo.pos(); + + // 注意:这里的总大小,包括结尾8个字节,wav文件有8个结尾字节。"q\xFCq\xFC""a\xFB""a\xFB" + // 文件总大小; + WavFileHeader.fileTotalSize = WavFileHeader.nRiffLength + 8; + + break; + } + else + { + qDebug() << "unhandled chunk" << tempName << tempSize; + fileInfo.read ( tempSize ); + break; + } + } + + //测试OK + // pline() << "filesize" << WavFileHeader.fileTotalSize; + // pline() << "fileheadersize" << WavFileHeader.fileHeaderSize; + // pline() << "filedatasize" << WavFileHeader.fileDataSize; + // pline() << "filetailsize" << WavFileHeader.fileTailSize; + // pline() << WavFileHeader.nChannleNumber << WavFileHeader.nSampleRate << WavFileHeader.nBitsPerSample; + + fileInfo.close(); +} + + +/* + * 解析方法2 支援Qt 资源文件 + */ +bool anlysisWavFileHeader ( QString fileName, QAudioFormat& format, TWavFileInfo& fileinfo ) +{ + WAVFILEHEADER WavFileHeader; + bool ret = wavParse ( fileName, WavFileHeader ); + + format.setChannelCount ( WavFileHeader.nChannleNumber ); + format.setSampleRate ( WavFileHeader.nSampleRate ); + format.setSampleSize ( WavFileHeader.nBitsPerSample ); + format.setByteOrder ( QAudioFormat::LittleEndian ); + format.setCodec ( "audio/pcm" ); + format.setSampleType ( QAudioFormat::SignedInt ); + + fileinfo.fileTotalSize = WavFileHeader.fileTotalSize; + fileinfo.fileHeaderSize = WavFileHeader.fileHeaderSize; + fileinfo.fileDataSize = WavFileHeader.fileDataSize; + fileinfo.fileTailSize = WavFileHeader.fileTailSize; + return true; +} diff --git a/src/multimedia/libqwav/libqwav.h b/src/multimedia/libqwav/libqwav.h new file mode 100644 index 00000000..7df66d44 --- /dev/null +++ b/src/multimedia/libqwav/libqwav.h @@ -0,0 +1,98 @@ +#ifndef LIBQWAV_H +#define LIBQWAV_H + +#include "libqwav_global.h" + +#include "string.h" +#include +#include + +//dll __imp_ lib no __imp_ +//跟这个extern没关系。 +//动态导出、导入时就是有__imp_ +//静态导出、导入时就是没有__imp_,导出的是函数原型。 + +//这个extern的作用是在导出库源文件是.c文件时,使用者必须使用extern "C"包含对应的头文件。 +//就这么一个作用。 + +//#ifdef __cplusplus +//extern "C" { +//#endif + +/* + * 解析方法2 使用QtFile接口,支持Qt资源文件 + */ +// wav文件头信息结构 +struct WAVFILEHEADER +{ + // RIFF 头; + char RiffName[5];//RIFF + int nRiffLength;//fileLen-8 + // 数据类型标识符; + char WavName[5];//WAVE + + // 格式块中的块头; + char FmtName[5];//fmt + int nFmtLength; + // 格式块中的块数据; + short nAudioFormat; + short nChannleNumber; + int nSampleRate; + int nBytesPerSecond; + short nBlockAlign; + short nBitsPerSample; + + // 附加信息(可选),根据 nFmtLength 来判断; + // 扩展域大小; + short nAppendMessage; + + //Fact块,可选字段,一般当wav文件由某些软件转化而成,则包含该Chunk; + char FactName[5]; + int nFactLength; + + // DATA块,数据块中的块头; + char DATANAME[5]; + int nDataLength;//fileDataSize + + // 以下是附加的一些计算信息; + int fileDataSize; // 文件音频数据大小; + int fileHeaderSize; // 文件头大小; + int fileTailSize; // 文件尾大小; 一般忽略。 + int fileTotalSize; // 文件总大小; + + + // 理论上应该将所有数据初始化,这里只初始化可选的数据; + WAVFILEHEADER() { + fileTailSize = 8; + memset ( RiffName, 0, 5 ); + memset ( WavName, 0, 5 ); + memset ( FmtName, 0, 5 ); + memset ( FactName, 0, 5 ); + } + +}; + +//44 固定的 +LIBQWAVSHARED_EXPORT bool addWavHeader ( QIODevice& outputDevice, const QAudioFormat& format ); +//8 固定的 +LIBQWAVSHARED_EXPORT bool addWavTail ( QIODevice& outputDevice ); +LIBQWAVSHARED_EXPORT bool addWavDataBytes ( QIODevice& outputDevice, const QByteArray& bytes ); + + +typedef struct _TWavFileInfo +{ + int fileDataSize; // 文件音频数据大小; + int fileHeaderSize; // 文件头大小; + int fileTailSize; // 文件尾大小; 一般忽略。 + int fileTotalSize; // 文件总大小; +} TWavFileInfo; + + +LIBQWAVSHARED_EXPORT bool wavParse ( QString fileName, WAVFILEHEADER& WavFileHeader ); +LIBQWAVSHARED_EXPORT bool anlysisWavFileHeader ( QString fileName, QAudioFormat& format, TWavFileInfo& fileinfo ); + +//#ifdef __cplusplus +//} +//#endif + +#endif // LIBQWAV_H diff --git a/src/multimedia/libqwav/libqwav_global.h b/src/multimedia/libqwav/libqwav_global.h new file mode 100644 index 00000000..94c8837c --- /dev/null +++ b/src/multimedia/libqwav/libqwav_global.h @@ -0,0 +1,18 @@ +#ifndef LIBQWAV_GLOBAL_H +#define LIBQWAV_GLOBAL_H + +#include + +#ifdef Q_OS_WIN +#if defined(LIBQWAV_LIBRARY) +# define LIBQWAVSHARED_EXPORT Q_DECL_EXPORT +#elif defined(LIBQWAV_STATIC_LIBRARY) +# define LIBQWAVSHARED_EXPORT +#else +# define LIBQWAVSHARED_EXPORT Q_DECL_IMPORT +#endif +#else +# define LIBQWAVSHARED_EXPORT +#endif + +#endif // LIBQWAV_GLOBAL_H diff --git a/src/multimedia/qqtcamera.cpp b/src/multimedia/qqtcamera.cpp new file mode 100644 index 00000000..fe1c8ab1 --- /dev/null +++ b/src/multimedia/qqtcamera.cpp @@ -0,0 +1,646 @@ +#include + +QQtCameraExposure::QQtCameraExposure ( QObject* parent ) : QObject ( parent ) +{ + mExposure = 0; +} + +QQtCameraExposure::~QQtCameraExposure() {} + +void QQtCameraExposure::setCameraExposure ( QCameraExposure* object ) +{ + Q_ASSERT ( object ); + + if ( mExposure ) + { + disconnect ( mExposure, SIGNAL ( flashReady ( bool ) ), this, SIGNAL ( flashReady ( bool ) ) ); + disconnect ( mExposure, SIGNAL ( apertureChanged ( qreal ) ), this, SIGNAL ( apertureChanged ( qreal ) ) ); + disconnect ( mExposure, SIGNAL ( apertureRangeChanged() ), this, SIGNAL ( apertureRangeChanged() ) ); + disconnect ( mExposure, SIGNAL ( shutterSpeedChanged ( qreal ) ), this, SIGNAL ( shutterSpeedChanged ( qreal ) ) ); + disconnect ( mExposure, SIGNAL ( shutterSpeedRangeChanged() ), this, SIGNAL ( shutterSpeedRangeChanged() ) ); + disconnect ( mExposure, SIGNAL ( isoSensitivityChanged ( int ) ), this, SIGNAL ( isoSensitivityChanged ( int ) ) ); + disconnect ( mExposure, SIGNAL ( exposureCompensationChanged ( qreal ) ), this, SIGNAL ( exposureCompensationChanged ( qreal ) ) ); + + mExposure->deleteLater(); + } + + mExposure = object; + + connect ( mExposure, SIGNAL ( flashReady ( bool ) ), this, SIGNAL ( flashReady ( bool ) ) ); + connect ( mExposure, SIGNAL ( apertureChanged ( qreal ) ), this, SIGNAL ( apertureChanged ( qreal ) ) ); + connect ( mExposure, SIGNAL ( apertureRangeChanged() ), this, SIGNAL ( apertureRangeChanged() ) ); + connect ( mExposure, SIGNAL ( shutterSpeedChanged ( qreal ) ), this, SIGNAL ( shutterSpeedChanged ( qreal ) ) ); + connect ( mExposure, SIGNAL ( shutterSpeedRangeChanged() ), this, SIGNAL ( shutterSpeedRangeChanged() ) ); + connect ( mExposure, SIGNAL ( isoSensitivityChanged ( int ) ), this, SIGNAL ( isoSensitivityChanged ( int ) ) ); + connect ( mExposure, SIGNAL ( exposureCompensationChanged ( qreal ) ), this, SIGNAL ( exposureCompensationChanged ( qreal ) ) ); + +} + +QCameraExposure* QQtCameraExposure::exposure() +{ + return mExposure; +} + +bool QQtCameraExposure::isAvailable() const +{ + return mExposure->isAvailable(); +} + +QCameraExposure::FlashModes QQtCameraExposure::flashMode() const +{ + return mExposure->flashMode(); +} + +bool QQtCameraExposure::isFlashModeSupported ( QCameraExposure::FlashModes mode ) const +{ + return mExposure->isFlashModeSupported ( mode ); +} + +bool QQtCameraExposure::isFlashReady() const +{ + return mExposure->isFlashReady(); +} + +QCameraExposure::ExposureMode QQtCameraExposure::exposureMode() const +{ + return mExposure->exposureMode(); +} + +bool QQtCameraExposure::isExposureModeSupported ( QCameraExposure::ExposureMode mode ) const +{ + return mExposure->isExposureModeSupported ( mode ); +} + +qreal QQtCameraExposure::exposureCompensation() const +{ + return mExposure->exposureCompensation(); +} + +QCameraExposure::MeteringMode QQtCameraExposure::meteringMode() const +{ + return mExposure->meteringMode(); +} + +bool QQtCameraExposure::isMeteringModeSupported ( QCameraExposure::MeteringMode mode ) const +{ + return mExposure->isMeteringModeSupported ( mode ); +} + +QPointF QQtCameraExposure::spotMeteringPoint() const +{ + return mExposure->spotMeteringPoint(); +} + +void QQtCameraExposure::setSpotMeteringPoint ( const QPointF& point ) +{ + return mExposure->setSpotMeteringPoint ( point ); +} + +int QQtCameraExposure::isoSensitivity() const +{ + return mExposure->isoSensitivity(); +} + +qreal QQtCameraExposure::aperture() const +{ + return mExposure->aperture(); +} + +qreal QQtCameraExposure::shutterSpeed() const +{ + return mExposure->shutterSpeed(); +} + +int QQtCameraExposure::requestedIsoSensitivity() const +{ + return mExposure->requestedIsoSensitivity(); +} + +qreal QQtCameraExposure::requestedAperture() const +{ + return mExposure->requestedAperture(); +} + +qreal QQtCameraExposure::requestedShutterSpeed() const +{ + return mExposure->requestedShutterSpeed(); +} + +QList QQtCameraExposure::supportedIsoSensitivities ( bool* continuous ) const +{ + return mExposure->supportedIsoSensitivities ( continuous ); +} + +QList QQtCameraExposure::supportedApertures ( bool* continuous ) const +{ + return mExposure->supportedApertures ( continuous ); +} + +QList QQtCameraExposure::supportedShutterSpeeds ( bool* continuous ) const +{ + return mExposure->supportedShutterSpeeds ( continuous ); +} + +void QQtCameraExposure::setFlashMode ( QCameraExposure::FlashModes mode ) +{ + return mExposure->setFlashMode ( mode ); +} + +void QQtCameraExposure::setExposureMode ( QCameraExposure::ExposureMode mode ) +{ + return mExposure->setExposureMode ( mode ); +} + +void QQtCameraExposure::setMeteringMode ( QCameraExposure::MeteringMode mode ) +{ + return mExposure->setMeteringMode ( mode ); +} + +void QQtCameraExposure::setExposureCompensation ( qreal ev ) +{ + return mExposure->setExposureCompensation ( ev ); +} + +void QQtCameraExposure::setManualIsoSensitivity ( int iso ) +{ + return mExposure->setManualIsoSensitivity ( iso ); +} + +void QQtCameraExposure::setAutoIsoSensitivity() +{ + return mExposure->setAutoIsoSensitivity ( ); +} + +void QQtCameraExposure::setManualAperture ( qreal aperture ) +{ + return mExposure->setManualAperture ( aperture ); +} + +void QQtCameraExposure::setAutoAperture() +{ + return mExposure->setAutoAperture ( ); +} + +void QQtCameraExposure::setManualShutterSpeed ( qreal seconds ) +{ + return mExposure->setManualShutterSpeed ( seconds ); +} + +void QQtCameraExposure::setAutoShutterSpeed() +{ + return mExposure->setAutoShutterSpeed ( ); +} + + +QQtCameraFocus::QQtCameraFocus ( QObject* parent ) : QObject ( parent ) +{ + mFocus = 0; +} + +QQtCameraFocus::~QQtCameraFocus() {} + +void QQtCameraFocus::setCameraFocus ( QCameraFocus* object ) +{ + Q_ASSERT ( object ); + + if ( mFocus ) + { + disconnect ( mFocus, SIGNAL ( opticalZoomChanged ( qreal ) ), this, SIGNAL ( opticalZoomChanged ( qreal ) ) ); + disconnect ( mFocus, SIGNAL ( digitalZoomChanged ( qreal ) ), this, SIGNAL ( digitalZoomChanged ( qreal ) ) ); + disconnect ( mFocus, SIGNAL ( focusZonesChanged ( ) ), this, SIGNAL ( focusZonesChanged ( ) ) ); + disconnect ( mFocus, SIGNAL ( maximumOpticalZoomChanged ( qreal ) ), this, SIGNAL ( maximumOpticalZoomChanged ( qreal ) ) ); + disconnect ( mFocus, SIGNAL ( maximumDigitalZoomChanged ( qreal ) ), this, SIGNAL ( maximumDigitalZoomChanged ( qreal ) ) ); + mFocus->deleteLater(); + } + + mFocus = object; + + connect ( mFocus, SIGNAL ( opticalZoomChanged ( qreal ) ), this, SIGNAL ( opticalZoomChanged ( qreal ) ) ); + connect ( mFocus, SIGNAL ( digitalZoomChanged ( qreal ) ), this, SIGNAL ( digitalZoomChanged ( qreal ) ) ); + connect ( mFocus, SIGNAL ( focusZonesChanged ( ) ), this, SIGNAL ( focusZonesChanged ( ) ) ); + connect ( mFocus, SIGNAL ( maximumOpticalZoomChanged ( qreal ) ), this, SIGNAL ( maximumOpticalZoomChanged ( qreal ) ) ); + connect ( mFocus, SIGNAL ( maximumDigitalZoomChanged ( qreal ) ), this, SIGNAL ( maximumDigitalZoomChanged ( qreal ) ) ); + +} + +QCameraFocus* QQtCameraFocus::focus() +{ + return mFocus; +} + +bool QQtCameraFocus::isAvailable() const +{ + return mFocus->isAvailable(); +} + +QCameraFocus::FocusModes QQtCameraFocus::focusMode() const +{ + return mFocus->focusMode(); +} + +void QQtCameraFocus::setFocusMode ( QCameraFocus::FocusModes mode ) +{ + return mFocus->setFocusMode ( mode ); +} + +bool QQtCameraFocus::isFocusModeSupported ( QCameraFocus::FocusModes mode ) const +{ + return mFocus->isFocusModeSupported ( mode ); +} + +QCameraFocus::FocusPointMode QQtCameraFocus::focusPointMode() const +{ + return mFocus->focusPointMode ( ); +} + +void QQtCameraFocus::setFocusPointMode ( QCameraFocus::FocusPointMode mode ) +{ + return mFocus->setFocusPointMode ( mode ); +} + +bool QQtCameraFocus::isFocusPointModeSupported ( QCameraFocus::FocusPointMode mode ) const +{ + return mFocus->isFocusPointModeSupported ( mode ); +} + +QPointF QQtCameraFocus::customFocusPoint() const +{ + return mFocus->customFocusPoint ( ); +} + +void QQtCameraFocus::setCustomFocusPoint ( const QPointF& point ) +{ + return mFocus->setCustomFocusPoint ( point ); +} + +QCameraFocusZoneList QQtCameraFocus::focusZones() const +{ + return mFocus->focusZones ( ); +} + +qreal QQtCameraFocus::maximumOpticalZoom() const +{ + return mFocus->maximumOpticalZoom ( ); +} + +qreal QQtCameraFocus::maximumDigitalZoom() const +{ + return mFocus->maximumDigitalZoom ( ); +} + +qreal QQtCameraFocus::opticalZoom() const +{ + return mFocus->opticalZoom ( ); +} + +qreal QQtCameraFocus::digitalZoom() const +{ + return mFocus->digitalZoom ( ); +} + +void QQtCameraFocus::zoomTo ( qreal opticalZoom, qreal digitalZoom ) +{ + return mFocus->zoomTo ( opticalZoom, digitalZoom ); +} + + +QQtCameraImageProcessing::QQtCameraImageProcessing ( QObject* parent ) : QObject ( parent ) +{ + mImageProcessing = 0; +} + +QQtCameraImageProcessing::~QQtCameraImageProcessing() {} + +void QQtCameraImageProcessing::setCameraImageProcessing ( QCameraImageProcessing* object ) +{ + Q_ASSERT ( object ); + + if ( mImageProcessing ) + { + mImageProcessing->deleteLater(); + } + + mImageProcessing = object; +} + +bool QQtCameraImageProcessing::isAvailable() const +{ + return mImageProcessing->isAvailable(); +} + +QCameraImageProcessing::WhiteBalanceMode QQtCameraImageProcessing::whiteBalanceMode() const +{ + return mImageProcessing->whiteBalanceMode(); +} + +void QQtCameraImageProcessing::setWhiteBalanceMode ( QCameraImageProcessing::WhiteBalanceMode mode ) +{ + return mImageProcessing->setWhiteBalanceMode ( mode ); +} + +bool QQtCameraImageProcessing::isWhiteBalanceModeSupported ( QCameraImageProcessing::WhiteBalanceMode mode ) const +{ + return mImageProcessing->isWhiteBalanceModeSupported ( mode ); +} + +qreal QQtCameraImageProcessing::manualWhiteBalance() const +{ + return mImageProcessing->manualWhiteBalance(); +} + +void QQtCameraImageProcessing::setManualWhiteBalance ( qreal colorTemperature ) +{ + return mImageProcessing->setManualWhiteBalance ( colorTemperature ); +} + +qreal QQtCameraImageProcessing::brightness() const +{ + return mImageProcessing->brightness(); +} + +void QQtCameraImageProcessing::setBrightness ( qreal value ) +{ + return mImageProcessing->setManualWhiteBalance ( value ); +} + +qreal QQtCameraImageProcessing::contrast() const +{ + return mImageProcessing->contrast(); +} + +void QQtCameraImageProcessing::setContrast ( qreal value ) +{ + return mImageProcessing->setContrast ( value ); +} + +qreal QQtCameraImageProcessing::saturation() const +{ + return mImageProcessing->saturation(); +} + +void QQtCameraImageProcessing::setSaturation ( qreal value ) +{ + return mImageProcessing->setSaturation ( value ); +} + +qreal QQtCameraImageProcessing::sharpeningLevel() const +{ + return mImageProcessing->sharpeningLevel(); +} + +void QQtCameraImageProcessing::setSharpeningLevel ( qreal value ) +{ + return mImageProcessing->setSharpeningLevel ( value ); +} + +qreal QQtCameraImageProcessing::denoisingLevel() const +{ + return mImageProcessing->denoisingLevel(); +} + +void QQtCameraImageProcessing::setDenoisingLevel ( qreal value ) +{ + return mImageProcessing->setDenoisingLevel ( value ); +} + +QCameraImageProcessing::ColorFilter QQtCameraImageProcessing::colorFilter() const +{ + return mImageProcessing->colorFilter(); +} + +void QQtCameraImageProcessing::setColorFilter ( QCameraImageProcessing::ColorFilter filter ) +{ + return mImageProcessing->setColorFilter ( filter ); +} + +bool QQtCameraImageProcessing::isColorFilterSupported ( QCameraImageProcessing::ColorFilter filter ) const +{ + return mImageProcessing->isColorFilterSupported ( filter ); +} + +QQtCamera::QQtCamera ( QObject* parent ) : QObject ( parent ) +{ + //初始化Camera。 + mCamera = 0; + //初始化CameraInfo。 + mCameraInfo = QCameraInfo::defaultCamera(); + + //mCamera 句柄持续为真。 + setCameraInfo ( QCameraInfo::defaultCamera() ); +} + +QQtCamera::~QQtCamera() {} + +void QQtCamera::setCameraInfo ( const QCameraInfo& camInfo ) +{ + //更新mCamera + if ( mCamera ) + { + disconnect ( mCamera, SIGNAL ( stateChanged ( QCamera::State ) ), this, SIGNAL ( stateChanged ( QCamera::State ) ) ); + disconnect ( mCamera, SIGNAL ( captureModeChanged ( QCamera::CaptureModes ) ), this, SIGNAL ( captureModeChanged ( QCamera::CaptureModes ) ) ); + disconnect ( mCamera, SIGNAL ( statusChanged ( QCamera::Status ) ), this, SIGNAL ( statusChanged ( QCamera::Status ) ) ); + disconnect ( mCamera, SIGNAL ( locked() ), this, SIGNAL ( locked() ) ); + disconnect ( mCamera, SIGNAL ( lockFailed() ), this, SIGNAL ( lockFailed() ) ); + disconnect ( mCamera, SIGNAL ( lockStatusChanged ( QCamera::LockStatus, QCamera::LockChangeReason ) ), this, SIGNAL ( lockStatusChanged ( QCamera::LockStatus, QCamera::LockChangeReason ) ) ); + disconnect ( mCamera, SIGNAL ( lockStatusChanged ( QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason ) ), this, SIGNAL ( lockStatusChanged ( QCamera::LockType, QCamera::LockStatus, + QCamera::LockChangeReason ) ) ); + disconnect ( mCamera, SIGNAL ( error ( QCamera::Error ) ), this, SIGNAL ( error ( QCamera::Error ) ) ); + mCamera->stop(); + mCamera->deleteLater(); + } + + mCameraInfo = camInfo; + mCamera = new QCamera ( mCameraInfo, this ); + +#if 0 + //更新 Viewfinder + setViewfinder ( m_vw_viewfinder ); + setViewfinder ( m_gv_viewfinder ); + setViewfinder ( m_avs_viewfinder ); + + //更新 ViewfinderSettings + setViewfinderSettings ( mVfSettings ); +#endif + + //更新信号、槽的连接 + connect ( mCamera, SIGNAL ( stateChanged ( QCamera::State ) ), this, SIGNAL ( stateChanged ( QCamera::State ) ) ); + connect ( mCamera, SIGNAL ( captureModeChanged ( QCamera::CaptureModes ) ), this, SIGNAL ( captureModeChanged ( QCamera::CaptureModes ) ) ); + connect ( mCamera, SIGNAL ( statusChanged ( QCamera::Status ) ), this, SIGNAL ( statusChanged ( QCamera::Status ) ) ); + connect ( mCamera, SIGNAL ( locked() ), this, SIGNAL ( locked() ) ); + connect ( mCamera, SIGNAL ( lockFailed() ), this, SIGNAL ( lockFailed() ) ); + connect ( mCamera, SIGNAL ( lockStatusChanged ( QCamera::LockStatus, QCamera::LockChangeReason ) ), this, SIGNAL ( lockStatusChanged ( QCamera::LockStatus, QCamera::LockChangeReason ) ) ); + connect ( mCamera, SIGNAL ( lockStatusChanged ( QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason ) ), this, SIGNAL ( lockStatusChanged ( QCamera::LockType, QCamera::LockStatus, + QCamera::LockChangeReason ) ) ); + connect ( mCamera, SIGNAL ( error ( QCamera::Error ) ), this, SIGNAL ( error ( QCamera::Error ) ) ); + +} + +QCameraInfo QQtCamera::cameraInfo() const +{ + return mCameraInfo; +} + +QCamera* QQtCamera::camera() const +{ + return mCamera; +} + +QMultimedia::AvailabilityStatus QQtCamera::availability() const +{ + return mCamera->availability(); +} + +QCamera::State QQtCamera::state() const +{ + return mCamera->state(); +} + +QCamera::Status QQtCamera::status() const +{ + return mCamera->status(); +} + +QCamera::CaptureModes QQtCamera::captureMode() const +{ + return mCamera->captureMode(); +} + +bool QQtCamera::isCaptureModeSupported ( QCamera::CaptureModes mode ) const +{ + return mCamera->isCaptureModeSupported ( mode ); +} + +QCameraExposure* QQtCamera::exposure() const +{ + return mCamera->exposure(); +} + +QCameraFocus* QQtCamera::focus() const +{ + return mCamera->focus(); +} + +QCameraImageProcessing* QQtCamera::imageProcessing() const +{ + return mCamera->imageProcessing(); +} + +void QQtCamera::setViewfinder ( QVideoWidget* viewfinder ) +{ + mCamera->setViewfinder ( viewfinder ); +} + +void QQtCamera::setViewfinder ( QGraphicsVideoItem* viewfinder ) +{ + mCamera->setViewfinder ( viewfinder ); +} + +void QQtCamera::setViewfinder ( QAbstractVideoSurface* surface ) +{ + mCamera->setViewfinder ( surface ); +} + +QCameraViewfinderSettings QQtCamera::viewfinderSettings() const +{ + return mCamera->viewfinderSettings(); +} + +void QQtCamera::setViewfinderSettings ( const QCameraViewfinderSettings& settings ) +{ + return mCamera->setViewfinderSettings ( settings ); +} + +QList QQtCamera::supportedViewfinderSettings ( const QCameraViewfinderSettings& settings ) const +{ + return mCamera->supportedViewfinderSettings ( settings ); +} + +QList QQtCamera::supportedViewfinderResolutions ( const QCameraViewfinderSettings& settings ) const +{ + return mCamera->supportedViewfinderResolutions ( settings ); +} + +QList QQtCamera::supportedViewfinderFrameRateRanges ( const QCameraViewfinderSettings& settings ) const +{ + return mCamera->supportedViewfinderFrameRateRanges ( settings ); +} + +QList QQtCamera::supportedViewfinderPixelFormats ( const QCameraViewfinderSettings& settings ) const +{ + return mCamera->supportedViewfinderPixelFormats ( settings ); +} + +QCamera::Error QQtCamera::error() const +{ + return mCamera->error ( ); +} + +QString QQtCamera::errorString() const +{ + return mCamera->errorString ( ); +} + +QCamera::LockTypes QQtCamera::supportedLocks() const +{ + return mCamera->supportedLocks ( ); +} + +QCamera::LockTypes QQtCamera::requestedLocks() const +{ + return mCamera->requestedLocks ( ); +} + +QCamera::LockStatus QQtCamera::lockStatus() const +{ + return mCamera->lockStatus ( ); +} + +QCamera::LockStatus QQtCamera::lockStatus ( QCamera::LockType lock ) const +{ + return mCamera->lockStatus ( lock ); +} + +void QQtCamera::setCaptureMode ( QCamera::CaptureModes mode ) +{ + return mCamera->setCaptureMode ( mode ); +} + +void QQtCamera::load() +{ + return mCamera->load(); +} + +void QQtCamera::unload() +{ + return mCamera->unload(); +} + +void QQtCamera::start() +{ + return mCamera->start(); +} + +void QQtCamera::stop() +{ + return mCamera->stop(); +} + +void QQtCamera::searchAndLock() +{ + return mCamera->searchAndLock(); +} + +void QQtCamera::unlock() +{ + return mCamera->unlock(); +} + +void QQtCamera::searchAndLock ( QCamera::LockTypes locks ) +{ + return mCamera->searchAndLock ( locks ); +} + +void QQtCamera::unlock ( QCamera::LockTypes locks ) +{ + return mCamera->unlock ( locks ); +} diff --git a/src/multimedia/qqtcamera.h b/src/multimedia/qqtcamera.h new file mode 100644 index 00000000..2cd39728 --- /dev/null +++ b/src/multimedia/qqtcamera.h @@ -0,0 +1,283 @@ +#ifndef QQTCAMERA_H +#define QQTCAMERA_H + +/** + * 包装类 + * 为QQtVideoManager提供包装类,促使句柄、信号、槽,外部在使用时,不变。 + * 用户感兴趣可以使用。 + */ + +#include +#include + +#include + +/** + * @brief The QQtCameraExposure class + * 为QCameraExposure提供能够保持的句柄。 + * 不应该管理句柄的删除。 + */ +class QQTSHARED_EXPORT QQtCameraExposure : public QObject +{ + Q_OBJECT +public: + QQtCameraExposure ( QObject* parent = 0 ); + virtual ~QQtCameraExposure(); + + //决定exposure句柄 + void setCameraExposure ( QCameraExposure* object ); + QCameraExposure* exposure(); + + bool isAvailable() const; + + QCameraExposure::FlashModes flashMode() const; + bool isFlashModeSupported ( QCameraExposure::FlashModes mode ) const; + bool isFlashReady() const; + + QCameraExposure::ExposureMode exposureMode() const; + bool isExposureModeSupported ( QCameraExposure::ExposureMode mode ) const; + + qreal exposureCompensation() const; + + QCameraExposure::MeteringMode meteringMode() const; + bool isMeteringModeSupported ( QCameraExposure::MeteringMode mode ) const; + + QPointF spotMeteringPoint() const; + void setSpotMeteringPoint ( const QPointF& point ); + + int isoSensitivity() const; + qreal aperture() const; + qreal shutterSpeed() const; + + int requestedIsoSensitivity() const; + qreal requestedAperture() const; + qreal requestedShutterSpeed() const; + + QList supportedIsoSensitivities ( bool* continuous = Q_NULLPTR ) const; + QList supportedApertures ( bool* continuous = Q_NULLPTR ) const; + QList supportedShutterSpeeds ( bool* continuous = Q_NULLPTR ) const; + +public slots: + void setFlashMode ( QCameraExposure::FlashModes mode ); + void setExposureMode ( QCameraExposure::ExposureMode mode ); + void setMeteringMode ( QCameraExposure::MeteringMode mode ); + + void setExposureCompensation ( qreal ev ); + + void setManualIsoSensitivity ( int iso ); + void setAutoIsoSensitivity(); + + void setManualAperture ( qreal aperture ); + void setAutoAperture(); + + void setManualShutterSpeed ( qreal seconds ); + void setAutoShutterSpeed(); + +signals: + void flashReady ( bool ); + + void apertureChanged ( qreal ); + void apertureRangeChanged(); + void shutterSpeedChanged ( qreal ); + void shutterSpeedRangeChanged(); + void isoSensitivityChanged ( int ); + void exposureCompensationChanged ( qreal ); + +private: + QCameraExposure* mExposure; +}; + +/** + * @brief The QQtCameraFocus class + * QCameraFocus的包装,保持句柄。 + */ +class QQTSHARED_EXPORT QQtCameraFocus : public QObject +{ + Q_OBJECT +public: + QQtCameraFocus ( QObject* parent = 0 ); + virtual ~QQtCameraFocus(); + + void setCameraFocus ( QCameraFocus* object ); + QCameraFocus* focus(); + + bool isAvailable() const; + + QCameraFocus::FocusModes focusMode() const; + void setFocusMode ( QCameraFocus::FocusModes mode ); + bool isFocusModeSupported ( QCameraFocus::FocusModes mode ) const; + + QCameraFocus::FocusPointMode focusPointMode() const; + void setFocusPointMode ( QCameraFocus::FocusPointMode mode ); + bool isFocusPointModeSupported ( QCameraFocus::FocusPointMode mode ) const; + QPointF customFocusPoint() const; + void setCustomFocusPoint ( const QPointF& point ); + + QCameraFocusZoneList focusZones() const; + + qreal maximumOpticalZoom() const; + qreal maximumDigitalZoom() const; + qreal opticalZoom() const; + qreal digitalZoom() const; + + void zoomTo ( qreal opticalZoom, qreal digitalZoom ); + +signals: + void opticalZoomChanged ( qreal ); + void digitalZoomChanged ( qreal ); + + void focusZonesChanged(); + + void maximumOpticalZoomChanged ( qreal ); + void maximumDigitalZoomChanged ( qreal ); + +private: + QCameraFocus* mFocus; +}; + +/** + * @brief The QQtCameraImageProcessing class + * QCameraImageProcessing的包装类,保持句柄。 + */ +class QQTSHARED_EXPORT QQtCameraImageProcessing : public QObject +{ + Q_OBJECT +public: + QQtCameraImageProcessing ( QObject* parent = 0 ); + virtual ~QQtCameraImageProcessing(); + + void setCameraImageProcessing ( QCameraImageProcessing* object ); + + bool isAvailable() const; + + QCameraImageProcessing::WhiteBalanceMode whiteBalanceMode() const; + void setWhiteBalanceMode ( QCameraImageProcessing::WhiteBalanceMode mode ); + bool isWhiteBalanceModeSupported ( QCameraImageProcessing::WhiteBalanceMode mode ) const; + + qreal manualWhiteBalance() const; + void setManualWhiteBalance ( qreal colorTemperature ); + + qreal brightness() const; + void setBrightness ( qreal value ); + + qreal contrast() const; + void setContrast ( qreal value ); + + qreal saturation() const; + void setSaturation ( qreal value ); + + qreal sharpeningLevel() const; + void setSharpeningLevel ( qreal value ); + + qreal denoisingLevel() const; + void setDenoisingLevel ( qreal value ); + + QCameraImageProcessing::ColorFilter colorFilter() const; + void setColorFilter ( QCameraImageProcessing::ColorFilter filter ); + bool isColorFilterSupported ( QCameraImageProcessing::ColorFilter filter ) const; + +private: + QCameraImageProcessing* mImageProcessing; +}; + +/** + * @brief The QQtCamera class + * 封装QCamera + * 已预置defaultCamera, + * 句柄保持不变。 + * 包装类的句柄不变,信号和槽就可以持续使用了。 + * 内部句柄在变化,但是从外部看,无所谓,外部使用的句柄、信号、槽都是稳定的。 + * 功能丰富、齐全。 + * 多线程不安全。 + */ +class QQTSHARED_EXPORT QQtCamera : public QObject +{ + Q_OBJECT +public: + QQtCamera ( QObject* parent = 0 ); + virtual ~QQtCamera(); + + //QQt setCameraInfo 决定以下所有关系照相机的操作。 + //更改 CameraInfo,QQtCamera 会切换到新Camera的默认输出设置,用户需要重新设置 ViewfinderSettings 达到输出设置目的。 + //更改 CameraInfo,QQtCamera 会舍弃过去的Viewfinder,用户需要重新设置 Viewfinder。 + void setCameraInfo ( const QCameraInfo& camInfo ); + QCameraInfo cameraInfo() const; + + //optional + //以下函数可选使用,句柄处于持续变动之中。 + QCamera* camera() const; + + QMultimedia::AvailabilityStatus availability() const; + + QCamera::State state() const; + QCamera::Status status() const; + + QCamera::CaptureModes captureMode() const; + bool isCaptureModeSupported ( QCamera::CaptureModes mode ) const; + + QCameraExposure* exposure() const; + QCameraFocus* focus() const; + QCameraImageProcessing* imageProcessing() const; + + void setViewfinder ( QVideoWidget* viewfinder ); + void setViewfinder ( QGraphicsVideoItem* viewfinder ); + void setViewfinder ( QAbstractVideoSurface* surface ); + + QCameraViewfinderSettings viewfinderSettings() const; + void setViewfinderSettings ( const QCameraViewfinderSettings& settings ); + + QList supportedViewfinderSettings ( + const QCameraViewfinderSettings& settings = QCameraViewfinderSettings() ) const; + + QList supportedViewfinderResolutions ( + const QCameraViewfinderSettings& settings = QCameraViewfinderSettings() ) const; + + QList supportedViewfinderFrameRateRanges ( + const QCameraViewfinderSettings& settings = QCameraViewfinderSettings() ) const; + + QList supportedViewfinderPixelFormats ( + const QCameraViewfinderSettings& settings = QCameraViewfinderSettings() ) const; + + QCamera::Error error() const; + QString errorString() const; + + QCamera::LockTypes supportedLocks() const; + QCamera::LockTypes requestedLocks() const; + + QCamera::LockStatus lockStatus() const; + QCamera::LockStatus lockStatus ( QCamera::LockType lock ) const; + +public slots: + void setCaptureMode ( QCamera::CaptureModes mode ); + + void load(); + void unload(); + + void start(); + void stop(); + + void searchAndLock(); + void unlock(); + + void searchAndLock ( QCamera::LockTypes locks ); + void unlock ( QCamera::LockTypes locks ); + +signals: + void stateChanged ( QCamera::State ); + void captureModeChanged ( QCamera::CaptureModes ); + void statusChanged ( QCamera::Status ); + + void locked(); + void lockFailed(); + + void lockStatusChanged ( QCamera::LockStatus, QCamera::LockChangeReason ); + void lockStatusChanged ( QCamera::LockType, QCamera::LockStatus, QCamera::LockChangeReason ); + + void error ( QCamera::Error ); + +private: + QCamera* mCamera; + QCameraInfo mCameraInfo; +}; + +#endif // QQTCAMERA_H diff --git a/src/multimedia/qqtlogicvideomanager.cpp b/src/multimedia/qqtlogicvideomanager.cpp new file mode 100644 index 00000000..6bea5414 --- /dev/null +++ b/src/multimedia/qqtlogicvideomanager.cpp @@ -0,0 +1,342 @@ +#include "qqtlogicvideomanager.h" + +QQtLogicVideoManager::QQtLogicVideoManager ( QWidget* parent ) : + QWidget ( parent ), + ui ( new Ui::QQtLogicVideoManager ) +{ + ui->setupUi ( this ); + + memset ( &sinfo, 0, sizeof ( struct sensor_info ) ); + pre_bpp = 16; + rate = 15; /* default to 15fps */ + addr = 0; + phys = 0; + + pre_size.w = 720; + pre_size.h = 480; + + fd = 0; + + memset ( & pre_memory, 0, sizeof ( struct camera_memory ) ); + memset ( & pre_buf, 0, sizeof ( struct camera_buffer ) ); + memset ( & pre_size, 0, sizeof ( struct frm_size ) ); + + tlb_base_phys = 0; + format = HAL_PIXEL_FORMAT_YCbCr_422_I; + + bFullScreen = false; + m_parent = parent; + + timer = new QTimer ( this ); + timer->setSingleShot ( false ); + connect ( timer, SIGNAL ( timeout() ), this, SLOT ( update() ) ); +} + +QQtLogicVideoManager::~QQtLogicVideoManager() +{ + delete ui; +} + +int QQtLogicVideoManager::play() +{ + /* + * 这块代码放在哪里 + */ + dmmu_init(); + dmmu_get_page_table_base_phys ( &tlb_base_phys ); + + fd = ::open ( "/dev/cim", O_RDWR ); //av + + if ( fd < 0 ) + { + qDebug() << "Open device fail\n"; + } + + ioctl ( fd, CIMIO_SELECT_SENSOR, sinfo.sensor_id ); + + ioctl ( fd, CIMIO_GET_SENSORINFO, &sinfo ); + + ioctl ( fd, CIMIO_SET_TLB_BASE, tlb_base_phys ); //????????? + + int i = 0; + + if ( pre_buf.common && pre_buf.common->data ) + { + dmmu_unmap_user_memory ( & ( pre_buf.dmmu_info ) ); + free ( pre_buf.common->data ); + } + + pre_buf.fd = fd; + pre_buf.nr = 5; + pre_buf.size = pre_size.w * pre_size.h * 3; + pre_buf.common = &pre_memory; + pre_buf.common->size = pre_buf.size * pre_buf.nr; + pre_buf.common->data = memalign ( 4096, pre_buf.size * pre_buf.nr ); + memset ( pre_buf.common->data, 0xa5, ( pre_buf.size * pre_buf.nr ) ); + + if ( pre_buf.common->data == NULL ) + { + printf ( "==<%s L%d: null pointer!\n", __func__, __LINE__ ); + return false; + } + + pre_buf.paddr = 0; + pre_buf.dmmu_info.vaddr = pre_buf.common->data; + pre_buf.dmmu_info.size = pre_buf.common->size; + + for ( i = 0; i < ( int ) ( pre_buf.common->size ); i += 0x1000 ) + { + ( ( uint8_t* ) ( pre_buf.common->data ) ) [i] = 0xff; + } + + ( ( uint8_t* ) ( pre_buf.common->data ) ) [pre_buf.common->size - 1] = 0xff; + dmmu_map_user_memory ( & ( pre_buf.dmmu_info ) ); + + for ( i = 0; i < pre_buf.nr; ++i ) + { + pre_buf.yuvMeta[i].index = i; + pre_buf.yuvMeta[i].width = pre_size.w; + pre_buf.yuvMeta[i].height = pre_size.h; + pre_buf.yuvMeta[i].format = format; + pre_buf.yuvMeta[i].count = pre_buf.nr; +#ifdef __LINUX64__ + pre_buf.yuvMeta[i].yAddr = ( int64_t ) pre_buf.common->data + ( pre_buf.size ) * i; +#else + pre_buf.yuvMeta[i].yAddr = ( int32_t ) pre_buf.common->data + ( pre_buf.size ) * i; +#endif + pre_buf.yuvMeta[i].yPhy = pre_buf.paddr + i * ( pre_buf.size ); + + if ( pre_buf.yuvMeta[i].format == HAL_PIXEL_FORMAT_YCbCr_422_I ) //yuv422 packed + { + pre_buf.yuvMeta[i].uAddr = pre_buf.yuvMeta[i].yAddr; + pre_buf.yuvMeta[i].vAddr = pre_buf.yuvMeta[i].uAddr; + pre_buf.yuvMeta[i].uPhy = pre_buf.yuvMeta[i].yPhy; + pre_buf.yuvMeta[i].vPhy = pre_buf.yuvMeta[i].uPhy; + pre_buf.yuvMeta[i].yStride = pre_buf.yuvMeta[i].width << 1; + pre_buf.yuvMeta[i].uStride = pre_buf.yuvMeta[i].yStride; + pre_buf.yuvMeta[i].vStride = pre_buf.yuvMeta[i].yStride; + } + else if ( pre_buf.yuvMeta[i].format == HAL_PIXEL_FORMAT_JZ_YUV_420_P ) //yuv420 planar + { + pre_buf.yuvMeta[i].uAddr = pre_buf.yuvMeta[i].yAddr + pre_size.w * pre_size.h; + pre_buf.yuvMeta[i].vAddr = pre_buf.yuvMeta[i].uAddr + pre_size.w * pre_size.h / 4; + pre_buf.yuvMeta[i].uPhy = pre_buf.yuvMeta[i].yPhy + pre_size.w * pre_size.h; + pre_buf.yuvMeta[i].vPhy = pre_buf.yuvMeta[i].uPhy + pre_size.w * pre_size.h / 4; + pre_buf.yuvMeta[i].yStride = pre_buf.yuvMeta[i].width << 1; + pre_buf.yuvMeta[i].uStride = pre_buf.yuvMeta[i].width / 2; + pre_buf.yuvMeta[i].vStride = pre_buf.yuvMeta[i].width / 2; + } + else if ( pre_buf.yuvMeta[i].format == HAL_PIXEL_FORMAT_RAW_SENSOR ) //raw bayer + { + pre_buf.yuvMeta[i].uAddr = pre_buf.yuvMeta[i].yAddr + pre_size.w * pre_size.h; + pre_buf.yuvMeta[i].vAddr = pre_buf.yuvMeta[i].uAddr; + pre_buf.yuvMeta[i].uPhy = pre_buf.yuvMeta[i].yPhy; + pre_buf.yuvMeta[i].vPhy = pre_buf.yuvMeta[i].uPhy; + pre_buf.yuvMeta[i].yStride = pre_buf.yuvMeta[i].width; + pre_buf.yuvMeta[i].uStride = pre_buf.yuvMeta[i].yStride; + pre_buf.yuvMeta[i].vStride = pre_buf.yuvMeta[i].yStride; + } + } + + ioctl ( fd, CIMIO_SET_PREVIEW_FMT, format ); + ioctl ( fd, CIMIO_SET_PREVIEW_SIZE, &pre_size ); + + ioctl ( fd, CIMIO_SET_PREVIEW_MEM, ( unsigned long ) ( pre_buf.yuvMeta ) ); + + ioctl ( fd, CIMIO_START_PREVIEW ); + + pp = ( unsigned char* ) malloc ( pre_size.w * pre_size.h * 3 * sizeof ( char ) ); + frame = new QImage ( pp, pre_size.w, pre_size.h, QImage::Format_RGB888 ); + timer->start ( 100 ); + + return fd; +} + +int QQtLogicVideoManager::close() +{ + bool ret = false; + + if ( fd <= 0 ) + printf ( "fd < 0\n" ); + + ret = ioctl ( fd, CIMIO_SHUTDOWN ); + + ::close ( fd ); + fd = 0; + + dmmu_unmap_user_memory ( & ( pre_buf.dmmu_info ) ); + dmmu_deinit(); + + memset ( pre_buf.yuvMeta, 0, pre_buf.nr * sizeof ( CameraYUVMeta ) ); + pre_buf.size = 0; + pre_buf.nr = 0; + pre_buf.paddr = 0; + pre_buf.fd = -1; + + if ( ( pre_buf.common != NULL ) && ( pre_buf.common->data != NULL ) ) + { + free ( pre_buf.common->data ); + pre_buf.common->data = NULL; + } + + phys = 0; + + timer->stop(); + free ( pp ); + delete frame; + + return ret; +} + + +int QQtLogicVideoManager::convert_yuv_to_rgb_pixel ( int y, int u, int v ) +{ + unsigned int pixel32 = 0; + unsigned char* pixel = ( unsigned char* ) &pixel32; + int r, g, b; + b = y + ( ( 443 * ( u - 128 ) ) >> 8 ); + b = ( b < 0 ) ? 0 : ( ( b > 255 ) ? 255 : b ); + g = y - ( ( 179 * ( v - 128 ) + 86 * ( u - 128 ) ) >> 8 ); + g = ( g < 0 ) ? 0 : ( ( g > 255 ) ? 255 : g ); + r = y + ( ( 351 * ( v - 128 ) ) >> 8 ); + r = ( r < 0 ) ? 0 : ( ( r > 255 ) ? 255 : r ); + pixel[0] = r; + pixel[1] = g; + pixel[2] = b; + return pixel32; +} + +int QQtLogicVideoManager::convert_yuv_to_rgb_buffer ( unsigned char* yuv, unsigned char* rgb, unsigned int width, + unsigned int height ) +{ + unsigned int in, out = 0; + unsigned int pixel_16; + unsigned char pixel_24[3]; + unsigned int pixel32; + int y0, u, y1, v; + + for ( in = 0; in < width * height * 2; in += 4 ) + { + pixel_16 = + yuv[in + 3] << 24 | + yuv[in + 2] << 16 | + yuv[in + 1] << 8 | + yuv[in + 0]; + y0 = ( pixel_16 & 0x000000ff ); + u = ( pixel_16 & 0x0000ff00 ) >> 8; + y1 = ( pixel_16 & 0x00ff0000 ) >> 16; + v = ( pixel_16 & 0xff000000 ) >> 24; + pixel32 = convert_yuv_to_rgb_pixel ( y0, u, v ); + pixel_24[0] = ( pixel32 & 0x000000ff ); + pixel_24[1] = ( pixel32 & 0x0000ff00 ) >> 8; + pixel_24[2] = ( pixel32 & 0x00ff0000 ) >> 16; + rgb[out++] = pixel_24[0]; + rgb[out++] = pixel_24[1]; + rgb[out++] = pixel_24[2]; + pixel32 = convert_yuv_to_rgb_pixel ( y1, u, v ); + pixel_24[0] = ( pixel32 & 0x000000ff ); + pixel_24[1] = ( pixel32 & 0x0000ff00 ) >> 8; + pixel_24[2] = ( pixel32 & 0x00ff0000 ) >> 16; + rgb[out++] = pixel_24[0]; + rgb[out++] = pixel_24[1]; + rgb[out++] = pixel_24[2]; + } + + return 0; +} + + +void QQtLogicVideoManager::paintEvent ( QPaintEvent* ) +{ + if ( fd <= 0 ) + return; + + QStylePainter painter ( this ); + + /* + * 此处采集视频为多线程采集 上边的log证明 数据已经被修改 + */ + addr = ioctl ( fd, CIMIO_GET_FRAME ); + p = ( uchar* ) addr; + + /* + * 不具备优化能力,yuv缺少alpha。 + */ + convert_yuv_to_rgb_buffer ( p, pp, pre_size.w, pre_size.h ); + //frame->loadFromData((uchar *)pp, w * h * 3 * sizeof(char)); + /* + * 采集的图像左边上边有黑边 更换摄像头或许回有所改善 待调试 + */ + QRect srcRect ( 2, 6, pre_size.w, pre_size.h ); + QRect dstRect = rect(); + painter.scale ( 1.01, 1.02 ); + /* + * 缩放OK + */ + painter.drawImage ( dstRect, *frame, srcRect ); + //painter.drawPixmap(dstRect,QPixmap::fromImage(*frame,Qt::AutoColor),srcRect);; + /* + * 裁切OK + */ + //painter.drawItemPixmap(srcRect, Qt::AlignCenter, QPixmap::fromImage(*frame,Qt::AutoColor)); + /* + * 30ms 屏幕有闪烁 + */ + //update(); +} + + +void QQtLogicVideoManager::mousePressEvent ( QMouseEvent* e ) +{ + static bool bGInit = false; + + if ( !bGInit && !bFullScreen ) + { + flags = windowFlags(); + flags |= Qt::FramelessWindowHint; + geome = geometry(); + bGInit = true; + } + +#ifdef __EMBEDDED_LINUX__ + + //pline() << e->pos() << e->globalPos(); + if ( e->pos().x() < 0 || e->pos().y() < 0 || + e->pos().x() > geome.width() || e->pos().y() > geome.height() ) + { + //在mips板上,全屏返回的时候,点击其他位置,会多响应一次,在此处过滤。 + pline() << "warning!"; + Q_UNUSED ( e ); + return; + } + +#endif + + setAttribute ( Qt::WA_TranslucentBackground, true ); + setAttribute ( Qt::WA_NoMousePropagation, true ); + setAttribute ( Qt::WA_OpaquePaintEvent, true ); + + if ( bFullScreen ) + { + flags ^= Qt::Window; + flags |= Qt::Widget; + setParent ( m_parent, flags ); + setGeometry ( geome ); + show(); + bFullScreen = false; + } + else + { + int QQT_SCRN_WIDTH = QApplication::desktop()->availableGeometry().width(); + int QQT_SCRN_HEIGHT = QApplication::desktop()->availableGeometry().height(); + flags ^= Qt::Widget; + flags |= Qt::Window; + setParent ( 0, flags ); + setGeometry ( 0, 0, QQT_SCRN_WIDTH, QQT_SCRN_HEIGHT ); + show(); + bFullScreen = true; + } + + pline() << flags; + QWidget::mousePressEvent ( e ); +} diff --git a/src/multimedia/qqtlogicvideomanager.h b/src/multimedia/qqtlogicvideomanager.h new file mode 100644 index 00000000..a05fddd5 --- /dev/null +++ b/src/multimedia/qqtlogicvideomanager.h @@ -0,0 +1,75 @@ + +#ifndef QQTLOGICVIDEOMANAGER_H +#define QQTLOGICVIDEOMANAGER_H + +#include "qqt-qt.h" +#include "qqtlinux.h" +#include "qqtcore.h" +#include "qqt-local.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "graphics.h" +#include "dmmu.h" +#include "hal.h" +#include "jz_cim.h" + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +/** + * @brief The QQtLogicVideoManager class + * QQt模拟摄像头预览控件 + * 省略dmmu的Qt Wrapper类 + */ +class QQTSHARED_EXPORT QQtLogicVideoManager : public QWidget +{ + Q_OBJECT + +public: + explicit QQtLogicVideoManager ( QWidget* parent = 0 ); + ~QQtLogicVideoManager(); + int play(); + int close(); + +private: + Ui::QQtLogicVideoManager* ui; + + struct sensor_info sinfo; + int pre_bpp; + int rate; /* default to 15fps */ + unsigned int addr; + unsigned int phys; + + int fd; + int format; + + struct camera_memory pre_memory; + struct camera_buffer pre_buf; + struct frm_size pre_size; + unsigned int tlb_base_phys; + + uchar* pp; + uchar* p; + QImage* frame; + QTimer* timer; + + bool bFullScreen; + QWidget* m_parent; + QRect geome; + Qt::WindowFlags flags; + + int convert_yuv_to_rgb_pixel ( int y, int u, int v ); + int convert_yuv_to_rgb_buffer ( unsigned char* yuv, unsigned char* rgb, unsigned int width, unsigned int height ); + + // QWidget interface +protected: + void paintEvent ( QPaintEvent* ); + void mousePressEvent ( QMouseEvent* e ); +}; + +#endif // QQTLOGICVIDEOMANAGER_H diff --git a/src/multimedia/qqtvideomanager.cpp b/src/multimedia/qqtvideomanager.cpp new file mode 100644 index 00000000..2a63e697 --- /dev/null +++ b/src/multimedia/qqtvideomanager.cpp @@ -0,0 +1,497 @@ +#include +#include + +QQtCameraVideoSurface::QQtCameraVideoSurface ( QObject* parent ) : QAbstractVideoSurface ( parent ) +{ + +} + +QQtCameraVideoSurface::~QQtCameraVideoSurface() +{ + +} + +QList QQtCameraVideoSurface::supportedPixelFormats ( QAbstractVideoBuffer::HandleType handleType ) const +{ +#ifdef Q_OS_ANDROID + //Android NV21 + return QList() + << QVideoFrame::Format_NV21; +#endif + + //桌面 + return QList() + << QVideoFrame::Format_RGB24 + << QVideoFrame::Format_RGB32; +} + +bool QQtCameraVideoSurface::present ( const QVideoFrame& frame ) +{ + if ( !frame.isValid() ) + return false; + + QVideoFrame cloneFrame ( frame ); + /** + * frame 可读 + */ + if ( !cloneFrame.map ( QAbstractVideoBuffer::ReadOnly ) ) + return false; + + /** + * 处理frame + */ + + //Android下的视频格式是怎么回事?需要转换吗? + + const QImage _image ( cloneFrame.bits(), + cloneFrame.width(), + cloneFrame.height(), + QVideoFrame::imageFormatFromPixelFormat ( cloneFrame.pixelFormat() ) ); + + //需要对水平方向反转。 + //Windows,现在的图像保存能成功,直接显示,程序会异常退出。使用QImage的mirrored函数进行了水平翻转,可以正常显示。 + //水平翻转是为了不崩溃,正常显示图像。必选。 + //垂直翻转是为了上下显示正常。 + const QImage image = _image.mirrored ( true, true ); + + /** + * frame 不可读 + */ + cloneFrame.unmap(); + + emit readyRead ( image ); + return true; +} + +QQtVideoProbe::QQtVideoProbe ( QObject* parent ) : QQtCameraVideoSurface ( parent ) +{ + m_mediaObject = 0; + m_AndroidProber = 0; +} + +QQtVideoProbe::~QQtVideoProbe() +{ +} + +void QQtVideoProbe::setMediaObject ( QMediaObject* mediaObject ) +{ + Q_ASSERT ( mediaObject ); +#ifdef Q_OS_ANDROID + if ( m_AndroidProber ) + { + //m_AndroidProber->setSource ( nullptr ); + disconnect ( m_AndroidProber, SIGNAL ( videoFrameProbed ( const QVideoFrame& ) ), + this, SLOT ( slotVideoFrame ( const QVideoFrame& ) ) ); + m_AndroidProber->deleteLater(); + } + + m_mediaObject = mediaObject; + m_AndroidProber = new QVideoProbe ( this ); + connect ( m_AndroidProber, SIGNAL ( videoFrameProbed ( const QVideoFrame& ) ), + this, SLOT ( slotVideoFrame ( const QVideoFrame& ) ) ); + m_AndroidProber->setSource ( m_mediaObject ); +#endif +} + +QMediaObject* QQtVideoProbe::mediaObject() const +{ + return m_mediaObject; +} + +void QQtVideoProbe::slotVideoFrame ( const QVideoFrame& frame ) +{ + present ( frame ); +} + +QQtVideoInput::QQtVideoInput ( QObject* parent ) : QObject ( parent ) +{ + /** + * 设置视频截图工具 + */ + mSurface = new QQtVideoProbe ( this ); + connect ( mSurface, SIGNAL ( readyRead ( QImage ) ), this, SIGNAL ( readyRead ( QImage ) ) ); + connect ( mSurface, SIGNAL ( readyRead ( QImage ) ), this, SLOT ( slotImageCaptured ( QImage ) ) ); + + /** + * 设置照相机 + */ + mCamera = new QQtCamera ( this ); + + //QQtCamera 默认就是使用默认照相机,所以,这里不必设置了。 + mCamInfo = defaultCamera(); + mCamera->setCameraInfo ( mCamInfo ); + +#ifdef Q_OS_ANDROID + mSurface->setMediaObject ( mCamera->camera() ); +#else + mCamera->setViewfinder ( mSurface ); +#endif + + // + mExposure = new QQtCameraExposure ( this ); + mFocus = new QQtCameraFocus ( this ); + mImageProcessing = new QQtCameraImageProcessing ( this ); + mExposure->setCameraExposure ( mCamera->exposure() ); + mFocus->setCameraFocus ( mCamera->focus() ); + mImageProcessing->setCameraImageProcessing ( mCamera->imageProcessing() ); + + mAutoSearchMilliSeconds = 200; + mAutoSearchTimer = new QTimer ( this ); + connect ( mAutoSearchTimer, SIGNAL ( timeout() ), this, SLOT ( slotTimeout() ) ); + mAutoSearchTimer->setInterval ( mAutoSearchMilliSeconds ); + mAutoSearchTimer->setSingleShot ( false ); + + //默认开启自动对焦 + mAutoSearchFlag = true ; + //默认不截图 + mCaptureFlag = false; +} + +QQtVideoInput::~QQtVideoInput() +{ + +} + +QCameraInfo QQtVideoInput::defaultCamera() +{ + return QCameraInfo::defaultCamera(); +} + +QList QQtVideoInput::availableCameras ( QCamera::Position position ) +{ + return QCameraInfo::availableCameras ( position ); +} + +QCameraInfo& QQtVideoInput::cameraInfo() +{ + return mCamInfo; +} + +QCameraViewfinderSettings QQtVideoInput::viewFinderSettings() +{ + if ( !mCamera ) + return QCameraViewfinderSettings(); + return mCamera->viewfinderSettings(); +} + +void QQtVideoInput::setViewfinderSettings ( const QCameraViewfinderSettings& settings ) +{ + if ( !mCamera ) + return; + mCamera->setViewfinderSettings ( settings ); +} + +QList QQtVideoInput::supportedViewFinderSettings ( const QCameraInfo& camInfo ) +{ + QCamera camera ( camInfo ); + return camera.supportedViewfinderSettings(); +} + +QQtCamera* QQtVideoInput::camera() const +{ + return mCamera; +} + +QQtCameraExposure* QQtVideoInput::expose() const +{ + return mExposure; +} + +QQtCameraFocus* QQtVideoInput::focus() const +{ + return mFocus; +} + +QQtCameraImageProcessing* QQtVideoInput::imageProcessing() const +{ + return mImageProcessing; +} + +void QQtVideoInput::start() +{ + stop(); + + //初始化截图Flag + mCaptureFlag = false; + + //初始化照相机句柄 + mCamera->setCameraInfo ( mCamInfo ); + + //初始化照相机图像控制句柄 + mExposure->setCameraExposure ( mCamera->exposure() ); + mFocus->setCameraFocus ( mCamera->focus() ); + mImageProcessing->setCameraImageProcessing ( mCamera->imageProcessing() ); + + /** + * 设置相机 + * 程序内部持续使用Capture Video。 + */ + //Windows 打印不支持,但是其实支持。 + if ( !mCamera->isCaptureModeSupported ( QCamera::CaptureVideo ) ) + { + pline() << mCamInfo.deviceName(); + //pline() << mCamera << "Camera cannot capture video"; + } + //播放图像 = QCamera::CaptureStillImage + //播放图像 = QCamera::CaptureViewfinder + mCamera->setCaptureMode ( QCamera::CaptureVideo ); + + //设置输出 +#ifdef Q_OS_ANDROID + mSurface->setMediaObject ( mCamera->camera() ); +#else + mCamera->setViewfinder ( mSurface ); +#endif + + //设置ViewfinderSettings + //启动后设置... + + //启动 + mCamera->start(); + pline() << mCamInfo.deviceName(); + pline() << mCamera << "Camera start to capture video"; + + //设置自动对焦 + if ( mAutoSearchFlag ) + mAutoSearchTimer->start(); +} + +void QQtVideoInput::stop() +{ + mAutoSearchTimer->stop(); + + if ( mCamera ) + { + mCamera->stop(); + //mCamera->deleteLater(); + } + + //mCamera = NULL; +} + +void QQtVideoInput::load() +{ + mCamera->load(); +} + +void QQtVideoInput::unload() +{ + mCamera->unload(); +} + +void QQtVideoInput::startDefaultCamera() +{ + mCamInfo = defaultCamera(); + start(); +} + +void QQtVideoInput::setPrepareInterval ( int milliSeconds ) +{ + mAutoSearchMilliSeconds = milliSeconds; +} + +int QQtVideoInput::prepareInterval() const +{ + return mAutoSearchMilliSeconds; +} + +void QQtVideoInput::capture() +{ + //现在使用截图Flag,将来可能要使用ImageCapture类,可以调整Shutter速度。 + //对外提供一个简化的截图功能。 + QMutexLocker locker ( &mMutexCaptureFlag ); + mCaptureFlag = true; +} + +void QQtVideoInput::setAutoPrepare ( bool autosearch ) +{ + mAutoSearchFlag = autosearch; + + if ( autosearch ) + mAutoSearchTimer->start(); + else + mAutoSearchTimer->stop(); +} + +void QQtVideoInput::prepare ( QCamera::LockTypes locks ) +{ + if ( !mCamera ) + return; + mCamera->searchAndLock ( locks ); +} + +void QQtVideoInput::cancelPrepare ( QCamera::LockTypes locks ) +{ + if ( !mCamera ) + return; + mCamera->unlock(); +} + +void QQtVideoInput::slotTimeout() +{ + if ( !mCamera ) + return; + mCamera->searchAndLock(); +} + +void QQtVideoInput::slotImageCaptured ( QImage image ) +{ + QMutexLocker locker ( &mMutexCaptureFlag ); + + if ( !mCaptureFlag ) + return; + mCaptureFlag = false; + + emit readyReadCapture ( image ); +} + +QQtVideoOutput::QQtVideoOutput ( QObject* parent ) : QObject ( parent ) +{ + mWidget = 0; + mStartFlag = false; +} + +QQtVideoOutput::~QQtVideoOutput() {} + +QQtWidget*& QQtVideoOutput::viewFinder() +{ + return mWidget; +} + +void QQtVideoOutput::start() +{ + QMutexLocker locker ( &mMutexStartFlag ); + mStartFlag = true; +} + +void QQtVideoOutput::stop() +{ + QMutexLocker locker ( &mMutexStartFlag ); + mStartFlag = false; +} + +void QQtVideoOutput::setPixmap ( QImage image ) +{ + QMutexLocker locker ( &mMutexStartFlag ); + if ( !mStartFlag ) + return; + if ( !mWidget ) + return; + mWidget->setPixmap ( image ); +} + +QQtVideoManager::QQtVideoManager ( QObject* parent ) : QObject ( parent ) +{ + mInput = new QQtVideoInput ( this ); + mOutput = new QQtVideoOutput ( this ); + + connect ( mInput, SIGNAL ( readyRead ( QImage ) ), this, SIGNAL ( readyRead ( QImage ) ) ); + connect ( mInput, SIGNAL ( readyReadCapture ( QImage ) ), this, SIGNAL ( readyReadCapture ( QImage ) ) ); +} + +QQtVideoManager::~QQtVideoManager() {} + +QCameraInfo QQtVideoManager::defaultCamera() +{ + return QQtVideoInput::defaultCamera(); +} + +QList QQtVideoManager::availableCameras ( QCamera::Position position ) +{ + return QQtVideoInput::availableCameras ( position ); +} + +QCameraInfo& QQtVideoManager::cameraInfo() +{ + return mInput->cameraInfo(); +} + +QQtWidget*& QQtVideoManager::viewFinder() const +{ + return mOutput->viewFinder(); +} + +QCameraViewfinderSettings QQtVideoManager::viewFinderSettings() const +{ + return mInput->viewFinderSettings(); +} + +void QQtVideoManager::setViewfinderSettings ( const QCameraViewfinderSettings& settings ) +{ + return mInput->setViewfinderSettings ( settings ); +} + +QList QQtVideoManager::supportedViewFinderSettings() +{ + return mInput->supportedViewFinderSettings(); +} + +QQtCamera* QQtVideoManager::camera() const +{ + return mInput->camera(); +} + +QQtCameraExposure* QQtVideoManager::expose() const +{ + return mInput->expose(); +} + +QQtCameraFocus* QQtVideoManager::focus() const +{ + return mInput->focus(); +} + +QQtCameraImageProcessing* QQtVideoManager::imageProcessing() const +{ + return mInput->imageProcessing(); +} + +void QQtVideoManager::startInput() +{ + mInput->start(); +} + +void QQtVideoManager::stopInput() +{ + mInput->stop(); +} + +QQtVideoInput* QQtVideoManager::inputManager() +{ + return mInput; +} + +void QQtVideoManager::startOutput() +{ + mOutput->start(); +} + +void QQtVideoManager::stopOutput() +{ + mOutput->stop(); +} + +QQtVideoOutput* QQtVideoManager::outputManager() +{ + return mOutput; +} + +void QQtVideoManager::startDefaultInput() +{ + mInput->startDefaultCamera(); +} + +void QQtVideoManager::startDefaultOutput() +{ + mOutput->start(); +} + +void QQtVideoManager::capture() +{ + mInput->capture(); +} + +void QQtVideoManager::outputImage ( QImage image ) +{ + mOutput->setPixmap ( image ); +} diff --git a/src/multimedia/qqtvideomanager.h b/src/multimedia/qqtvideomanager.h new file mode 100644 index 00000000..bde162ad --- /dev/null +++ b/src/multimedia/qqtvideomanager.h @@ -0,0 +1,300 @@ +#ifndef QQTVIDEOMANAGER_H +#define QQTVIDEOMANAGER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +/** + * --------------------------------------------------------------------------------------------------------------------- + * | 使用方式 | Parent | Property Class | Childen | 备注 + * --------------------------------------------------------------------------------------------------------------------- + * | setViewfinder | QAbstractVideoSurface | QQtCameraVideoSurface | | 视频,快,Buffer + * | | | | QQtVideoProbe | 视频,快,Buffer,+Android支持 + * --------------------------------------------------------------------------------------------------------------------- + * | setViewfinder | QMediaBindableInterface | QGraphicsVideoItem | | QGraphicsItem 系统专用 + * | | | QVideoWidget | QCameraViewfinder | 视频,快,属于输出位置上的 + * --------------------------------------------------------------------------------------------------------------------- + * | setMetaObject | QMediaBindableInterface | QCameraImageCapture | | 截图,慢,默认保存文件 + * | | | QMediaRecorder | QAudioRecorder | 录像,快,保存文件,音视频 + * --------------------------------------------------------------------------------------------------------------------- + */ + +/** + * 功能: + * 对视频设备进行管理。 + * 输入:摄像头 + * 输出:绘图设备(窗口) + */ + +/** + * @brief The QQtVideoSurface class + * 从metaObject获取视频数据,帧。 + * Buffer,快速。 + */ +class QQTSHARED_EXPORT QQtCameraVideoSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + QQtCameraVideoSurface ( QObject* parent = 0 ); + virtual ~QQtCameraVideoSurface(); + +signals: + void readyRead ( QImage ); + + // QAbstractVideoSurface interface +public: + virtual QList supportedPixelFormats ( QAbstractVideoBuffer::HandleType handleType ) const override; + virtual bool present ( const QVideoFrame& frame ) override; +}; + +/** + * @brief The QQtVideoProbe class + * 这是个数字摄像机管理器,这个类是为Android等需要Probe的数字录像设备准备的。 + * 我在VideoManager内部使用这个类来兼容桌面和Android系统, + * 但是我发现,无论如何Probe在Android上都不能正常执行,所以现在暂时不支持Android。 + * Qt5.9.2,何时支持,待定。 + */ +class QQTSHARED_EXPORT QQtVideoProbe : public QQtCameraVideoSurface +{ + Q_OBJECT +public: + QQtVideoProbe ( QObject* parent = 0 ); + virtual ~QQtVideoProbe(); + + void setMediaObject ( QMediaObject* mediaObject ); + QMediaObject* mediaObject() const; + + /** + * 以下与用户无关。 + */ +private slots: + void slotVideoFrame ( const QVideoFrame& frame ); +private: + QMediaObject* m_mediaObject; + QVideoProbe* m_AndroidProber; +}; + +/** + * @brief The QQtVideoInput class + * 图像输入 + * 从照相机输入,输出QImage序。 + * 从照相机输入,支持截图,输出QImage。 + */ +class QQTSHARED_EXPORT QQtVideoInput : public QObject +{ + Q_OBJECT +public: + QQtVideoInput ( QObject* parent = 0 ); + virtual ~QQtVideoInput(); + + /** + * 选择输入设备 + */ + static QCameraInfo defaultCamera(); + static QList availableCameras ( QCamera::Position position = QCamera::UnspecifiedPosition ); + //决定使用哪个Camera + //QQtVideoInput不会立即生效,只有在开启后才会生效。 + QCameraInfo& cameraInfo ( void ); + + /** + * 选择输入格式,启动后设置。 + */ + QCameraViewfinderSettings viewFinderSettings(); + //设置采集的图像的PixFormat,帧率等信息。 + void setViewfinderSettings ( const QCameraViewfinderSettings& settings = QCameraViewfinderSettings() ); + //获取照相机支持的设置。默认查询defaultCamera的。 + static QList supportedViewFinderSettings ( const QCameraInfo& camInfo = defaultCamera() ); + + /** + * 控制输入设备 + */ + QQtCamera* camera() const; + QQtCameraExposure* expose() const; + QQtCameraFocus* focus() const; + QQtCameraImageProcessing* imageProcessing() const; + +public slots: + void start(); + void stop(); + void load(); + void unload(); + + void startDefaultCamera(); + + //自动对焦,手动对焦切换。默认,自动,200ms + void setAutoPrepare ( bool autosearch = true ); + void setPrepareInterval ( int milliSeconds ); + int prepareInterval() const; + +public slots: + //用这个函数手动对焦。 + void prepare ( QCamera::LockTypes locks = QCamera::LockFocus ); + //放弃对焦、对焦停止、对焦完成 + void cancelPrepare ( QCamera::LockTypes locks = QCamera::LockFocus ); + + //截图 + void capture(); + + /** + * 输出图像 + */ +signals: + //输出QImage序 + void readyRead ( QImage ); + //输出QImage + void readyReadCapture ( QImage ); + + /** + * 以下与用户无关 + */ +private slots: + void slotTimeout(); + void slotImageCaptured ( QImage ); +private: + //经过调试,QCamera句柄,一个进程只能存在一个。 + QQtCamera* mCamera; + QCameraInfo mCamInfo; + QQtVideoProbe* mSurface; + QQtCameraExposure* mExposure; + QQtCameraFocus* mFocus; + QQtCameraImageProcessing* mImageProcessing; + + //自动对焦 + bool mAutoSearchFlag; + QTimer* mAutoSearchTimer; + int mAutoSearchMilliSeconds; + + //需要加锁吗?如果用户把这个类 moveToThread,并且不使用信号和槽模式调用 capture,那么需要加锁。 + QMutex mMutexCaptureFlag; + bool mCaptureFlag; +}; + +/** + * @brief The QQtVideoOutput class + * 视频输出 + * 把QImage输出到取景器。 + * QWidget、QQtWidget都能完成。QVideoWidget QCameraViewfinder QGraphicsVideoItem这些需要QCamera。 + * QCamera可以有多个吗?各自设置不同的?不可以。 + */ +class QQTSHARED_EXPORT QQtVideoOutput : public QObject +{ + Q_OBJECT +public: + QQtVideoOutput ( QObject* parent = 0 ); + virtual ~QQtVideoOutput(); + + /** + * 设置输出设备 + */ + QQtWidget*& viewFinder(); + + /** + * 控制输出设备 + */ +public slots: + //开启后才能使用。 + void start(); + //关闭后停止显示。 + void stop(); + //对窗口输出图像。 + void setPixmap ( QImage image ); + +private: + QQtWidget* mWidget; + //需要加锁吗?如果用户把这个类 moveToThread,并且不使用信号和槽模式调用 start stop,那么需要加锁。 + QMutex mMutexStartFlag; + bool mStartFlag; +}; + +/** + * @brief The QQtVideoManager class + * 视频设备管理器 + * 输入:照相机 + * 输出:取景器。 + * + * 功能: + * 获取录像机的每一帧,输出给用户处理, + * 提供输出设备的管理,辅助用户输出到确定的窗口。 + */ +class QQTSHARED_EXPORT QQtVideoManager : public QObject +{ + Q_OBJECT +public: + QQtVideoManager ( QObject* parent = 0 ); + virtual ~QQtVideoManager(); + + /** + * 选择输入、输出设备 + */ + static QCameraInfo defaultCamera(); + static QList availableCameras ( QCamera::Position position = QCamera::UnspecifiedPosition ); + //输入设备信息 + QCameraInfo& cameraInfo ( void ); + //输出设备信息 + QQtWidget*& viewFinder ( void ) const; + + /** + * 设置输入、输出设备格式 + */ + //输入设备设置 + QCameraViewfinderSettings viewFinderSettings() const; + void setViewfinderSettings ( const QCameraViewfinderSettings& settings ); + QList supportedViewFinderSettings(); + //输入设备的格式,决定输出设备的格式。 + + /** + * 控制输入、输出设备 + */ + QQtCamera* camera() const; + QQtCameraExposure* expose() const; + QQtCameraFocus* focus() const; + QQtCameraImageProcessing* imageProcessing() const; + + QQtVideoInput* inputManager(); + QQtVideoOutput* outputManager(); + +public slots: + void startInput(); + void stopInput(); + + void startOutput(); + void stopOutput(); + + void startDefaultInput(); + //等于start()。输出没有默认设备。 + void startDefaultOutput(); + + void capture(); + + /** + * 输出图像 + */ +signals: + //从输入设备获得图像。用户处理这些图像。 + void readyRead ( QImage ); + void readyReadCapture ( QImage ); + +public slots: + //把图像输出到输出设备。 + void outputImage ( QImage ); + +private: + QQtVideoInput* mInput; + QQtVideoOutput* mOutput; +}; + +#endif // QQTVIDEOMANAGER_H diff --git a/src/multimedia/qqtwavaudiomanager.cpp b/src/multimedia/qqtwavaudiomanager.cpp new file mode 100644 index 00000000..3fb52026 --- /dev/null +++ b/src/multimedia/qqtwavaudiomanager.cpp @@ -0,0 +1,317 @@ +#include "qqtwavaudiomanager.h" +#include "libqwav.h" + +QQtWavAudioInput::QQtWavAudioInput ( QObject* parent ) : QObject ( parent ) +{ + mTimer = new QTimer ( this ); + connect ( mTimer, SIGNAL ( timeout() ), SLOT ( slotTimeout() ) ); + + mFileBytes.clear(); + mBytes.clear(); + mBytesBuffer.setBuffer ( &mBytes ); + + mTimerInterval = 20; +} + +QIODevice* QQtWavAudioInput::setSourceFile ( const QString& localFile ) +{ + //如果开着,不管。 + mSourceFile = localFile; + +#if QT_VERSION > QT_VERSION_CHECK(5,0,0) + + //判断文件类型是否接受 + QMimeDatabase mimedb; + QMimeType mimetype = mimedb.mimeTypeForFile ( mSourceFile ); + + if ( !QSoundEffect::supportedMimeTypes().contains ( mimetype.name(), Qt::CaseInsensitive ) ) + { + pline() << "filename" << localFile << "mimetype" << mimetype.name() + << QSoundEffect::supportedMimeTypes().contains ( mimetype.name(), Qt::CaseInsensitive ) ; + pline() << "can't play file"; + return NULL; + } +#endif + + //判断音频具体格式 + //支持qrc文件 + TWavFileInfo info; + bool ret = anlysisWavFileHeader ( mSourceFile, mFormat, info ); + //仅仅支持本地文件 + //bool ret = anlysisWavFileHeader_C ( localFile ); + + if ( !ret ) + { + pline() << "wav format parse fail"; + return NULL; + } + + mFileTotalSize = info.fileTotalSize; + mFileHeaderSize = info.fileHeaderSize; + mFileDataSize = info.fileDataSize; + mFileTailSize = info.fileTailSize; + + return &mBytesBuffer; +} + +void QQtWavAudioInput::setTimerInterval ( int millSecond ) { mTimerInterval = millSecond; } + + +void QQtWavAudioInput::start() +{ + stop(); + + mChannelCount = mFormat.channelCount(); + mSampleSize = mFormat.sampleSize(); + mSampleRate = mFormat.sampleRate(); + + //读取到数据 + QFile f ( mSourceFile ); + f.open ( QFile::ReadOnly ); + QByteArray b = f.read ( mFileHeaderSize ); + //这个地方测试完成:内部解析wav头,两个都很成功。C Qt 都OK. + //pline() << b; + mFileBytes = f.read ( mFileDataSize ); + f.close(); + + mBytesBuffer.open ( QIODevice::ReadWrite ); + mTimer->start ( mTimerInterval ); + return; +} + +void QQtWavAudioInput::stop() +{ + //如果正在播放,先关闭写入音频数据流。 + mTimer->stop(); + //如果存在,则清空。 + //这两个变量Buffer是什么操作关系?QBuffer是QByteArray的QIODevice套。 + //改变QByteArray,会直接影响QBuffer的读写。QBuffer也会影响QByteArray的内容。 + mFileBytes.clear(); + mBytes.clear(); + + if ( mBytesBuffer.isOpen() ) + mBytesBuffer.close(); +} + +int QQtWavAudioInput::fileTotalSize() {return mFileTotalSize;} + +int QQtWavAudioInput::fileHeaderSize() { return mFileHeaderSize; } + +int QQtWavAudioInput::fileDataSize() {return mFileDataSize;} + +int QQtWavAudioInput::fileTailSize() {return mFileTailSize;} + + +void QQtWavAudioInput::slotTimeout() +{ + //1s 字节数 = 采样率 * 采样深度(位宽)* 通道数 / 8 + //mTimerInterval ms 字节数 = 1s 字节数 / (1000/mTimerInterval) + //每个音符 字节数 = 采样深度(位宽)* 通道数 / 8; + int frameSize = mSampleRate * mSampleSize * mChannelCount / 8 / ( 1000 / mTimerInterval ); + QByteArray tempBytes; + + if ( mFileBytes.size() > frameSize ) + { + tempBytes.resize ( frameSize ); + } + else + { + tempBytes.resize ( mFileBytes.size() ); + } + + //pline() << mFileBytes.size() << tempBytes.size() << frameSize; + //mFileBytes 逐渐减少 + mFileBytes >> tempBytes; + //这是给用户的。 + mBytes = tempBytes; + //回到初始位置 + mBytesBuffer.seek ( 0 ); + //激发readyRead信号 + mBytesBuffer.write ( 0 ); + + if ( mFileBytes.isEmpty() ) + { + //pline() << mFileBytes.size() << 0 << frameSize; + //这里不要关闭Buffer,客户一般还没用完。 + mTimer->stop(); + } + + return; +} + +QQtWavAudioOutput::QQtWavAudioOutput ( QObject* parent ) : QObject ( parent ) +{ + mFileBytes.clear(); + mBytesBuffer.setBuffer ( &mFileBytes ); + + mFormat.setByteOrder ( QAudioFormat::LittleEndian ); + mFormat.setChannelCount ( 2 ); + mFormat.setCodec ( "audio/pcm" ); + mFormat.setSampleRate ( 44100 ); + mFormat.setSampleSize ( 16 ); + mFormat.setSampleType ( QAudioFormat::SignedInt ); +} + +QIODevice* QQtWavAudioOutput::setSourceFile ( const QString& localFile ) +{ + mSourceFile = localFile; + return &mBytesBuffer; +} + +QAudioFormat& QQtWavAudioOutput::format() { return mFormat; } + +void QQtWavAudioOutput::start() +{ + if ( mSourceFile.isEmpty() ) + return; + + //这里清空文件,不会发生保存?不会,这里清空Buffer。 + mFileBytes.clear(); + + if ( mBytesBuffer.isOpen() ) + mBytesBuffer.close(); + + mBytesBuffer.open ( QIODevice::WriteOnly ); +} + +void QQtWavAudioOutput::stop() +{ + //在stop的时候,才会把数据全部存储到wav文件 + if ( mSourceFile.isEmpty() ) + return; + + //防止多次关闭导致音频文件被破坏。 + if ( mFileBytes.isEmpty() ) + return; + + QFile file ( mSourceFile ); + file.open ( QFile::Truncate | QFile::WriteOnly ); + + addWavHeader ( file, mFormat ); + file.write ( mFileBytes ); + addWavTail ( file ); + //这个时候,Header里面RiffLength是错误的。改写 + file.seek ( 0 ); + addWavHeader ( file, mFormat ); + //现在纠正好了。 + file.close(); + + mFileBytes.clear(); + + if ( mBytesBuffer.isOpen() ) + mBytesBuffer.close(); +} + + + +QQtWavAudioManager::QQtWavAudioManager ( QObject* parent ) : QObject ( parent ) +{ + mInputManager = new QQtWavAudioInput ( this ); + mOutputManager = new QQtWavAudioOutput ( this ); + + mInputDevice = mInputManager->device(); + mOutputDevice = mOutputManager->device(); + + connect ( mInputDevice, SIGNAL ( readyRead() ), + this, SIGNAL ( readyRead() ) ); + +} + +QQtWavAudioManager::~QQtWavAudioManager() +{ + stopInput(); + stopOutput(); +} + +void QQtWavAudioManager::setInputSourceFile ( const QString& localFile ) +{ + QIODevice* ioDev = mInputManager->setSourceFile ( localFile ); + + if ( !ioDev ) + { + pline() << mInputManager->sourceFile() + << inputAudioFormat().sampleSize() + << inputAudioFormat().sampleRate() + << inputAudioFormat().channelCount() + << "open failed, errcode:" + << "-1"; + return; + } +} + +QString QQtWavAudioManager::inputSourceFile() { return mInputManager->sourceFile(); } + +void QQtWavAudioManager::setOutputSourceFile ( const QString& localFile ) +{ + QIODevice* ioDev = mOutputManager->setSourceFile ( localFile ); + + if ( !ioDev ) + { + pline() << mOutputManager->sourceFile() + << outputAudioFormat().sampleSize() + << outputAudioFormat().sampleRate() + << outputAudioFormat().channelCount() + << "open failed, errcode:" + << "-1"; + return; + } +} + +QString QQtWavAudioManager::outputSourceFile() { return mOutputManager->sourceFile(); } + +const QAudioFormat& QQtWavAudioManager::inputAudioFormat() { return mInputManager->format(); } + +QAudioFormat& QQtWavAudioManager::outputAudioFormat() { return mOutputManager->format(); } + +int QQtWavAudioManager::inputFileTotalSize() { return mInputManager->fileTotalSize(); } + +int QQtWavAudioManager::inputFileHeaderSize() { return mInputManager->fileHeaderSize(); } + +int QQtWavAudioManager::inputFileDataSize() { return mInputManager->fileDataSize(); } + +int QQtWavAudioManager::inputFileTailSize() { return mInputManager->fileTailSize(); } + +QQtWavAudioInput* QQtWavAudioManager::inputManager() { return mInputManager; } + +QIODevice* QQtWavAudioManager::inputDevice() { return mInputDevice; } + +QQtWavAudioOutput* QQtWavAudioManager::outputManager() { return mOutputManager; } + +QIODevice* QQtWavAudioManager::outputDevice() { return mOutputDevice; } + +void QQtWavAudioManager::startInput() +{ + stopInput(); + mInputManager->start(); +} + +void QQtWavAudioManager::stopInput() +{ + mInputManager->stop(); +} + +void QQtWavAudioManager::startOutput() +{ + stopOutput(); + mOutputManager->start(); +} + +void QQtWavAudioManager::stopOutput() +{ + mOutputManager->stop(); +} + +QByteArray QQtWavAudioManager::readAll() +{ + return mInputDevice->readAll(); +} + +QByteArray QQtWavAudioManager::read ( qint64 maxlen ) +{ + return mInputDevice->read ( maxlen ); +} + +void QQtWavAudioManager::write ( const QByteArray& bytes ) +{ + mOutputDevice->write ( bytes ); +} diff --git a/src/multimedia/qqtwavaudiomanager.h b/src/multimedia/qqtwavaudiomanager.h new file mode 100644 index 00000000..952fb36d --- /dev/null +++ b/src/multimedia/qqtwavaudiomanager.h @@ -0,0 +1,220 @@ +#ifndef QQTWAVAUDIOMANAGER_H +#define QQTWAVAUDIOMANAGER_H + +#include +#include +#include + +#if QT_VERSION > QT_VERSION_CHECK(5,0,0) +#include +#include +#include + +#include +#include +#endif + +#include + +//设计思路:QQtWavAudioInput和QQtWavAudioOutput两边都是内存和wav文件,为内存服务。 + +/** + * @brief The QQtWavAudioInput class + * QQtWavAudioInput具备QAudioInput的能力,可以把wav文件的音频帧,通过readyRead输出。 + * 每次/10ms一帧,通过QIODevice readyRead发射给用户。 + * 升级目标:QQtAudioInput里支持的设备比较广泛,文件类型比较多。 + * + * 原理,设置Sourcefile,返回QIODevice,进行读取。一次加载,逐渐读取。 + * + * 不要使用大文件。 + * Qt 中有一个 QBuffer 类,可以将 QByteArray 包装成一个 QIODevice。QMemIODevice = QBuffer + * 如果来的是个QByteArray,那么,用QBuffer封装, + * 在 open 函数中调用 QIODevice::open(mode) + * 要解析wav,用自定义程序,还是用开源Library(libsndfile)?自定义程序 + * 要播放wav,是用wav的音频格式来设定输出设备,还是用个输出设备支持的音频格式,wav里选取进行使用?使用wav的。 + * + * 尝试用QAudioDecoder,解码器不支持x-wav,defaultServiceProvider::requestService(): no service found for - "org.qt-project.qt.audiodecode" + * 为什么QSoundEffect支持那么多wav格式?("audio/x-wav", "audio/wav", "audio/wave", "audio/x-pn-wav") + * LibQQt库 + * QAudioDecoder保存了一个提交,#5643241 + * QWavAudioEffect保存了一个提交,#5f43622 + */ +class QQTSHARED_EXPORT QQtWavAudioInput : public QObject +{ + Q_OBJECT + +public: + explicit QQtWavAudioInput ( QObject* parent = nullptr ); + //自动解析格式,和文件大小 + QIODevice* setSourceFile ( const QString& localFile ); + QString sourceFile() { return mSourceFile; } + + //读取用。这个是个内部公用的,并不是临时的。碰巧了。 + QIODevice* device() { return &mBytesBuffer; } + + //设置读文件的时钟快慢(硬盘快,时钟快,每次读的少;硬盘慢,时钟慢,每次读的多) + //采样间隔 10-100ms default: macOS SSD 20 ms + //windows 机械硬盘 100ms, windows 机械硬盘 is slower than macOS SSD. + int timerInterval() const { return mTimerInterval; } + void setTimerInterval ( int millSecond = 20 ); + //可以频繁开启,tip:用完一定要关闭,系统会自动关闭。 + //已经检查测试,没有文件设备漏开关问题。 + void start(); + void stop(); + + //每次修改SourceFile,这些都会改变。在不改变SourceFile的时候是内部使用的值。 + const QAudioFormat& format() { return mFormat; } + int fileTotalSize(); + int fileHeaderSize(); + int fileDataSize(); + int fileTailSize(); + +signals: + +public slots: + +private slots: + void slotTimeout(); + +private: + QString mSourceFile; + //用于保存文件全部Bytes + QByteArray mFileBytes; + //用于和Buffer联系,给用户提供每次读取的帧。 + QByteArray mBytes; + QBuffer mBytesBuffer; + + //每次设置新Source,会改变这些值。 + QAudioFormat mFormat; + int mFileDataSize; + int mFileHeaderSize; + int mFileTailSize; + int mFileTotalSize; + //这三个不准公开出来啊。 + int mSampleRate; + int mSampleSize; + int mChannelCount; + + QTimer* mTimer; + int mTimerInterval; + +public: +protected: + +public: +protected: + +}; + +class QQTSHARED_EXPORT QQtWavAudioOutput : public QObject +{ + Q_OBJECT + +public: + explicit QQtWavAudioOutput ( QObject* parent = nullptr ); + + QIODevice* setSourceFile ( const QString& localFile ); + QString sourceFile() { return mSourceFile; } + + //写入用 + QIODevice* device() { return &mBytesBuffer; } + + //用户务必设置format,默认值为2 16 44100 + QAudioFormat& format(); + + void start(); + + void stop(); + +protected: + +private: + QString mSourceFile; + QAudioFormat mFormat; + + QBuffer mBytesBuffer; + QByteArray mFileBytes; +}; + +/** + * @brief The QQtWavAudioManager class + * Wav媒体音频管理器 + * + * 这个Wav音频管理器目标为用户提供Wav媒体的音频数据帧,附加音频数据帧输出到Wav媒体的功能。 + */ +class QQTSHARED_EXPORT QQtWavAudioManager : public QObject +{ + Q_OBJECT +public: + explicit QQtWavAudioManager ( QObject* parent = nullptr ); + + ~QQtWavAudioManager(); + + /** + * 选择输入、输出Wav媒体 + */ + //设置输入或者输出wav文件 + void setInputSourceFile ( const QString& localFile ); + QString inputSourceFile(); + void setOutputSourceFile ( const QString& localFile ); + QString outputSourceFile(); + + /** + * 选择音频流的格式 + */ + + //获取输入文件的音频流格式 + const QAudioFormat& inputAudioFormat(); + //设置输出音频流的音频格式,输出保存的时候使用。 + QAudioFormat& outputAudioFormat(); + + //每次修改SourceFile,这些都会改变。 + int inputFileTotalSize(); + int inputFileHeaderSize(); + int inputFileDataSize(); + int inputFileTailSize(); + + + /** + * 操作输入、输出Wav媒体 + */ + + QQtWavAudioInput* inputManager(); + //如果输入,从这里读取帧 + QIODevice* inputDevice(); + + QQtWavAudioOutput* outputManager(); + //如果输出,从这里写入帧,提前设置好格式哦... + QIODevice* outputDevice(); + + void startInput(); + void stopInput(); + + void startOutput(); + void stopOutput(); + + //这两个是方便函数,一般都用这几个进行读写,不使用上边的。 + QByteArray readAll(); + QByteArray read ( qint64 maxlen ); + void write ( const QByteArray& bytes ); + +signals: + /*音频数据准备就绪,readAll即可读取。*/ + void readyRead(); +public slots: + +private: + + QQtWavAudioInput* mInputManager; + QQtWavAudioOutput* mOutputManager; + + QIODevice* mInputDevice; + QIODevice* mOutputDevice; + + //这三个不准公开出来。 + int mSampleRate; + int mSampleSize; + int mChannelCount; +}; + +#endif // QQTWAVAUDIOMANAGER_H diff --git a/src/multimedia/qqtwavsoundeffect.cpp b/src/multimedia/qqtwavsoundeffect.cpp new file mode 100644 index 00000000..5dd2ceda --- /dev/null +++ b/src/multimedia/qqtwavsoundeffect.cpp @@ -0,0 +1,163 @@ +#include "qqtwavsoundeffect.h" + + +QQtWavSoundEffect* QQtWavSoundEffect::msInstance = NULL; + +QQtWavSoundEffect* QQtWavSoundEffect::Instance ( QObject* parent ) +{ + if ( !msInstance ) + msInstance = new QQtWavSoundEffect ( parent ); + + return msInstance; +} + +QQtWavSoundEffect::QQtWavSoundEffect ( QObject* parent ) : QObject ( parent ) +{ + mVolume = 1; + mIOInput = NULL; + mLooping = 1; + mLoops = 1; +} + +void QQtWavSoundEffect::setOutputDevice ( const QAudioDeviceInfo& output ) +{ + if ( output.isNull() ) + manager.outputDeviceInfo() = QQtAudioManager::defaultOutputDevice(); + else + manager.outputDeviceInfo() = output; +} + +void QQtWavSoundEffect::useDefaultOutputDevice() +{ + manager.outputDeviceInfo() = QQtAudioManager::defaultOutputDevice(); +} + +void QQtWavSoundEffect::useCustomOutputDevice ( const QAudioDeviceInfo& output ) +{ + manager.outputDeviceInfo() = output; +} + +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) +QDebug& operator << ( QDebug& dbg, const QAudioFormat& fmt ) +{ + return dbg; +} +#endif + +void QQtWavSoundEffect::play ( QString localFile ) +{ +#if QT_VERSION > QT_VERSION_CHECK(5,0,0) + + //判断文件类型是否接受 + QMimeDatabase mimedb; + QMimeType mimetype = mimedb.mimeTypeForFile ( localFile ); + + if ( !QSoundEffect::supportedMimeTypes().contains ( mimetype.name(), Qt::CaseInsensitive ) ) + { + pline() << "filename" << localFile << "mimetype" << mimetype.name() + << QSoundEffect::supportedMimeTypes().contains ( mimetype.name(), Qt::CaseInsensitive ) ; + pline() << "can't play file"; + return; + } +#endif + + mSourceFile = localFile; + + stop(); + + mIOInput = mWavInput.setSourceFile ( localFile ); + connect ( mIOInput, SIGNAL ( readyRead() ), + this, SLOT ( readyRead() ) ); + + QAudioDeviceInfo& usingOutput = manager.outputDeviceInfo(); + + QAudioFormat fmt = mWavInput.format(); + + //输出设备是否支持格式是否支持 + if ( !usingOutput.isFormatSupported ( fmt ) ) + { + //当前使用设备是否支持 + pline() << "output cant support" << fmt; + fmt = usingOutput.nearestFormat ( fmt ); //转换为最接近格式 + pline() << "use format" << fmt; + } + + manager.outputAudioFormat() = fmt; + + manager.startOutput(); +#if QT_VERSION > QT_VERSION_CHECK(5,0,0) + + //默认是静音的。 + manager.outputManager()->setVolume ( mVolume ); +#endif + + //不响,音频输出设备接受顺序的间隔的输出,不接受一股脑输出。 + //manager.write ( bytes ); + //OK, 达到QSound效果。 + mWavInput.start(); +} + +void QQtWavSoundEffect::stop() +{ + //如果正在播放,先关闭 + if ( mIOInput ) + { + mWavInput.stop(); + manager.stopOutput(); + disconnect ( mIOInput, SIGNAL ( readyRead() ), + this, SLOT ( readyRead() ) ); + mIOInput = NULL; + } + + mLooping = 1; + mDataSize = 0; +} + +void QQtWavSoundEffect::setVolume ( qreal volume ) +{ + mVolume = volume; +#if QT_VERSION > QT_VERSION_CHECK(5,0,0) + + manager.outputManager()->setVolume ( mVolume ); +#endif +} + +int QQtWavSoundEffect::loops() const { return mLoops; } + +int QQtWavSoundEffect::loopsRemaining() const +{ + return mLoops - mLooping; +} + +void QQtWavSoundEffect::setLoops ( int loops ) +{ + mLoops = loops; +} + +void QQtWavSoundEffect::readyRead() +{ + QByteArray bytes = mIOInput->readAll(); + //pline() << bytes.size(); + manager.write ( bytes ); + + mDataSize += bytes.size(); + + if ( mDataSize == mWavInput.fileDataSize() ) + { + int loop = mLooping; + + if ( loop < loops() ) + play ( mSourceFile ); + + mLooping = loop + 1; + } +} + +QQtWavSoundEffect* QQtWavSound ( QString localFile ) +{ + if ( !localFile.isEmpty() ) + QQtWavSoundEffect::Instance ( )->play ( localFile ); + + return QQtWavSoundEffect::Instance(); +} + diff --git a/src/multimedia/qqtwavsoundeffect.h b/src/multimedia/qqtwavsoundeffect.h new file mode 100644 index 00000000..b9501231 --- /dev/null +++ b/src/multimedia/qqtwavsoundeffect.h @@ -0,0 +1,80 @@ +#ifndef QQTAUDIOEFFECT_H +#define QQTAUDIOEFFECT_H + + +#include + +#include +#include +/* + * QQtWavSoundEffect = QSoundEffect + QSound +... + * QQtWavSoundEffect支持从wav获取声音并输出,弥补QSoundEffect(+他的高级点的封装QSound)不能支持选择设备的缺失。 + * QQtWavSoundEffect默认使用默认输出设备。 + */ +class QQTSHARED_EXPORT QQtWavSoundEffect : public QObject +{ + Q_OBJECT + +public: + //这样做的目的,在于使用一个实例去播放音效。 + //如果是个临时变量,函数执行返回了,但是还没播放完,甚至还没来得及开始呢,这时,播放不出来的。 + static QQtWavSoundEffect* Instance ( QObject* parent = nullptr ); + + explicit QQtWavSoundEffect ( QObject* parent = nullptr ); + ~QQtWavSoundEffect() { + stop(); + } + + //设置设备以后,不需要每次都设置 + //更换设备不会引发播放更改,只会更改内部设备记录。调用play才会导致播放更改。 + void setOutputDevice ( const QAudioDeviceInfo& output = QAudioDeviceInfo() ); + + void useDefaultOutputDevice(); + + void useCustomOutputDevice ( const QAudioDeviceInfo& output ); + + void play ( QString localFile ); + + void stop(); + + //设置声音以后,不需要每次都要设置。 + void setVolume ( qreal volume ); + + //设置loop会保存下来,不需要每次设置。 + int loops() const; + int loopsRemaining() const; + void setLoops ( int loops ); + + //设置读文件的时钟快慢(硬盘快,时钟快,每次读的少;硬盘慢,时钟慢,每次读的多) + //默认使用 macOS SSD 20ms + //Windows上,机械硬盘,可能会延迟,可以设置100ms。 + void setTimerInterval ( int millSecond = 20 ) { + mWavInput.setTimerInterval ( millSecond ); + } + +private slots: + void readyRead(); + +private: + //不需要额外初始化的地方 + //mingw32 5.3 静态成员不准导出?作为静态类这块编译出现错误 + //error: definition of static data member 'QQtWavSoundEffect::msInstance' of dllimport'd class + //这个已经查出来了,在qqt_header.pri有一个WIN64的宏缺失,导致QQT_STATIC_LIBRARY缺失,引发QQt在QQTSHAREDEXPORT=import下编译,所以引发这个变量重新定义的错误,而报错是在导入的类里面定义了静态成员,也就是说导入类不准许静态成员的定义初始化代码出现,引入类的静态成员在自己的实现文件里出现了定义。变量重定义了。 + static QQtWavSoundEffect* msInstance; + + QQtWavAudioInput mWavInput; + QIODevice* mIOInput; + QQtAudioManager manager; + QString mSourceFile; + int mDataSize; + //volume会被记住。 + qreal mVolume; + int mLoops; + int mLooping; +}; + +//在使用QQtWavSound等函数之前,调用类的instance函数,+parent 初始化一下实例。 +//=QSound::play() +QQTSHARED_EXPORT QQtWavSoundEffect* QQtWavSound ( QString localFile = "" ); + +#endif // QQTAUDIOEFFECT_H diff --git a/src/qqt_3rdparty.pri b/src/qqt_3rdparty.pri index 198e185f..032dd5e4 100644 --- a/src/qqt_3rdparty.pri +++ b/src/qqt_3rdparty.pri @@ -122,6 +122,11 @@ contains (DEFINES, __MULTIMEDIA__) { $$PWD/multimedia/dmmu/jz_cim.h \ $$PWD/multimedia/dmmu/graphics.h \ $$PWD/multimedia/dmmu/hal.h + + #logic video manager + SOURCES += $$PWD/multimedia/qqtlogicvideomanager.cpp + HEADERS += $$PWD/multimedia/qqtlogicvideomanager.h + SOURCES += $$PWD/multimedia/qqtlogicpreviewwidget.cpp HEADERS += $$PWD/multimedia/qqtlogicpreviewwidget.h FORMS += $$PWD/multimedia/qqtlogicpreviewwidget.ui diff --git a/src/qqt_header.pri b/src/qqt_header.pri index 790b858f..f060d7a2 100644 --- a/src/qqt_header.pri +++ b/src/qqt_header.pri @@ -33,6 +33,7 @@ defineTest(add_include_QQt){ #multimedia command += $${header_path}/multimedia command += $${header_path}/multimedia/dmmu + command += $${header_path}/multimedia/libqwav #charts command += $${header_path}/charts @@ -219,6 +220,22 @@ defineTest(add_defines_QQt){ contains (DEFINES, __MULTIMEDIA__) { QT += multimedia + #AUDIO MODULE + #depend on libqwav + DEFINES += __QQTAUDIOSUPPORT__ + contains(DEFINES, __QQTAUDIOSUPPORT__) { + win32 { + contains (DEFINES, QQT_LIBRARY) { + DEFINES += LIBQWAV_LIBRARY + } else:contains (DEFINES, QQT_STATIC_LIBRARY) { + DEFINES += LIBQWAV_STATIC_LIBRARY + } else { } + } + } + + #VIDEO MODULE + DEFINES += __QQTVIDEOSUPPORT__ + #LOGIC CAMERA PREVIEW #depend on dmmu DEFINES += __LOGICCAMERAMODULE__ diff --git a/src/qqt_source.pri b/src/qqt_source.pri index 0f5cbb88..701dca61 100644 --- a/src/qqt_source.pri +++ b/src/qqt_source.pri @@ -36,10 +36,12 @@ contains (DEFINES, __WIN__) { #core SOURCES += \ $$PWD/core/qqtcore.cpp \ + $$PWD/core/qqtorderedmap.cpp \ $$PWD/core/qqtdictionary.cpp \ $$PWD/core/qqtobjectmanager.cpp HEADERS += \ $$PWD/core/qqtcore.h \ + $$PWD/core/qqtorderedmap.h \ $$PWD/core/qqtdictionary.h \ $$PWD/core/qqtobjectmanager.h @@ -200,8 +202,27 @@ contains (DEFINES, __MULTIMEDIA__) { } #audio - SOURCES += $$PWD/multimedia/qqtaudiomanager.cpp - HEADERS += $$PWD/multimedia/qqtaudiomanager.h + contains (DEFINES, __QQTAUDIOSUPPORT__){ + SOURCES += $$PWD/multimedia/qqtaudiomanager.cpp + HEADERS += $$PWD/multimedia/qqtaudiomanager.h + + #wav audio + SOURCES += $$PWD/multimedia/libqwav/libqwav.cpp + HEADERS += $$PWD/multimedia/libqwav/libqwav.h + HEADERS += $$PWD/multimedia/libqwav/libqwav_global.h + SOURCES += $$PWD/multimedia/qqtwavaudiomanager.cpp + HEADERS += $$PWD/multimedia/qqtwavaudiomanager.h + SOURCES += $$PWD/multimedia/qqtwavsoundeffect.cpp + HEADERS += $$PWD/multimedia/qqtwavsoundeffect.h + } + + #video + contains (DEFINES, __QQTVIDEOSUPPORT__){ + SOURCES += $$PWD/multimedia/qqtcamera.cpp + HEADERS += $$PWD/multimedia/qqtcamera.h + SOURCES += $$PWD/multimedia/qqtvideomanager.cpp + HEADERS += $$PWD/multimedia/qqtvideomanager.h + } } diff --git a/src/sql/qqtsql.cpp b/src/sql/qqtsql.cpp index 54b0bcba..26b18a4b 100644 --- a/src/sql/qqtsql.cpp +++ b/src/sql/qqtsql.cpp @@ -6,59 +6,59 @@ QSqlDatabase newDatabaseConnection() { QUuid uuid = QUuid::createUuid(); //qDebug() << uuid.toString(); - return QSqlDatabase::addDatabase(DB_TYPE, uuid.toString()); + return QSqlDatabase::addDatabase ( DB_TYPE, uuid.toString() ); } //opened //useDatabase -void setDatabaseName(QSqlDatabase& db, QString dbName) +void setDatabaseName ( QSqlDatabase& dbinst, QString dbName ) { - if (db.isOpen()) - db.close(); + if ( dbinst.isOpen() ) + dbinst.close(); - db.setDatabaseName(QString("%1/%2").arg(DB_PATH).arg(dbName)); + dbinst.setDatabaseName ( QString ( "%1" ).arg ( dbName ) ); - if (!db.open()) + if ( !dbinst.open() ) { - QMessageBox::warning(0, QObject::tr("QSQLITE %1 Error").arg(db.databaseName()), - db.lastError().text()); + QMessageBox::warning ( 0, QObject::tr ( "QSQLITE %1 Error" ).arg ( dbinst.databaseName() ), + dbinst.lastError().text() ); return; } } -void openDatabase(QSqlDatabase& db) +void openDatabase ( QSqlDatabase& dbinst ) { - if (db.isOpen()) + if ( dbinst.isOpen() ) return; - if (!db.open()) + if ( !dbinst.open() ) { - QMessageBox::warning(0, QObject::tr("QSQLITE %1 Error").arg(db.databaseName()), - db.lastError().text()); + QMessageBox::warning ( 0, QObject::tr ( "QSQLITE %1 Error" ).arg ( dbinst.databaseName() ), + dbinst.lastError().text() ); return; } } -void closeDatabase(QSqlDatabase& db) +void closeDatabase ( QSqlDatabase& dbinst ) { - db.close(); + dbinst.close(); } -void useDatabase(QSqlDatabase& db, QString dbName) +void useDatabase ( QSqlDatabase& dbinst, QString dbName ) { - setDatabaseName(db, dbName); + setDatabaseName ( dbinst, dbName ); } -void deleteDatabaseConnection(QString connectionName) +void deleteDatabaseConnection ( QString connectionName ) { - QSqlDatabase::removeDatabase(connectionName); + QSqlDatabase::removeDatabase ( connectionName ); } -void deleteDatabaseConnection(QSqlDatabase &db) +void deleteDatabaseConnection ( QSqlDatabase& dbinst ) { - QString connectionName = db.connectionName(); - deleteDatabaseConnection(connectionName); + QString connectionName = dbinst.connectionName(); + deleteDatabaseConnection ( connectionName ); } diff --git a/src/sql/qqtsql.h b/src/sql/qqtsql.h index 46b9c795..fe86148a 100644 --- a/src/sql/qqtsql.h +++ b/src/sql/qqtsql.h @@ -55,16 +55,9 @@ enum }; #define DB_TYPE "QSQLITE" -#define DB_PATH "./db" - #define DB_PINYIN "PinYin.db" #define DB_MANAGER "Manager.db" #define DB_EVENT "SysEvent.db" -#define DB_METHOD_PATH "Method" -#define DB_DATA_PATH "Data" -#define DB_QQT "System.db" -#define DB_USER "User.db" -#define DB_DATA "Data.db" #define TABLE_USERINFO "User" #define TABLE_AUTHORITY "Authority" @@ -81,14 +74,14 @@ typedef QSqlDatabase QQtSqlDatabaseConnection; QQTSHARED_EXPORT QSqlDatabase newDatabaseConnection(); /*已经将数据库打开,不必重复打开*/ -QQTSHARED_EXPORT void setDatabaseName(QSqlDatabase& db, QString dbName); +QQTSHARED_EXPORT void setDatabaseName ( QSqlDatabase& dbinst, QString dbName ); //=setDatabaseName -QQTSHARED_EXPORT void useDatabase(QSqlDatabase& db, QString dbName); +QQTSHARED_EXPORT void useDatabase ( QSqlDatabase& dbinst, QString dbName ); -QQTSHARED_EXPORT void openDatabase(QSqlDatabase& db); -QQTSHARED_EXPORT void closeDatabase(QSqlDatabase& db); +QQTSHARED_EXPORT void openDatabase ( QSqlDatabase& dbinst ); +QQTSHARED_EXPORT void closeDatabase ( QSqlDatabase& dbinst ); -QQTSHARED_EXPORT void deleteDatabaseConnection(QString connectionName); -QQTSHARED_EXPORT void deleteDatabaseConnection(QSqlDatabase& db); +QQTSHARED_EXPORT void deleteDatabaseConnection ( QString connectionName ); +QQTSHARED_EXPORT void deleteDatabaseConnection ( QSqlDatabase& dbinst ); #endif // QQTSQLDEFINE_H diff --git a/src/widgets/qqtwidgets.h b/src/widgets/qqtwidgets.h index 5474f5ac..0b7acadd 100644 --- a/src/widgets/qqtwidgets.h +++ b/src/widgets/qqtwidgets.h @@ -50,7 +50,6 @@ typedef struct QQTSHARED_EXPORT tagBtnIconTable QString& operator [] ( int index ); } TBtnIconTable; - QQTSHARED_EXPORT void moveCenter ( QWidget* w ); QQTSHARED_EXPORT void moveRight ( QWidget* w ); QQTSHARED_EXPORT void moveFull ( QWidget* w ); diff --git a/test/giftest/giftestdialog.cpp b/test/giftest/giftestdialog.cpp index bbd13e1a..e64ea2c9 100644 --- a/test/giftest/giftestdialog.cpp +++ b/test/giftest/giftestdialog.cpp @@ -32,9 +32,9 @@ GifTestDialog::GifTestDialog ( QWidget* parent ) : pline() << res ( "../waiting.gif" ); pline() << QDir ( "." ).relativeFilePath ( "skin/yun.png" ); pline() << QDir ( res ( "../waiting.gif" ) ).absolutePath(); - ui->labelGif->setGifFile ( skin ( "waiting.gif" ) ); - ui->widgetGif->setGifFile ( skin ( "waiting.gif" ) ); - ui->widgetQQt->setPixmap ( skin ( "yun.png" ) ); + ui->labelGif->setGifFile ( conf_skin ( "waiting.gif" ) ); + ui->widgetGif->setGifFile ( conf_skin ( "waiting.gif" ) ); + ui->widgetQQt->setPixmap ( conf_skin ( "yun.png" ) ); pline() << QMovie::supportedFormats(); } diff --git a/test/osdtest/mainwindow.cpp b/test/osdtest/mainwindow.cpp index 102f4cee..03de3b6a 100644 --- a/test/osdtest/mainwindow.cpp +++ b/test/osdtest/mainwindow.cpp @@ -7,7 +7,7 @@ MainWindow::MainWindow ( QWidget* parent ) : ui ( new Ui::MainWindow ) { ui->setupUi ( this ); - ui->widget_2->setPixmap ( qrc ( "a.png" ) ); + ui->widget_2->setPixmap ( conf_qrc ( "a.png" ) ); } MainWindow::~MainWindow() diff --git a/test/svgtest/mainwindow.cpp b/test/svgtest/mainwindow.cpp index 259fb045..5eefd707 100644 --- a/test/svgtest/mainwindow.cpp +++ b/test/svgtest/mainwindow.cpp @@ -13,29 +13,29 @@ MainWindow::MainWindow ( QWidget* parent ) : ui ( new Ui::MainWindow ) { ui->setupUi ( this ); - QString svg = QString ( qrc ( "aa.svg" ) ); + QString svg = QString ( conf_qrc ( "aa.svg" ) ); ui->w->setSvgFile ( svg ); - ui->b0->iconTable() [BTN_NORMAL] = qrc ( "bt_stir.svg" ); - ui->b0->iconTable() [BTN_HOVER] = qrc ( "bt_stir.svg" ); - ui->b0->iconTable() [BTN_PRESS] = qrc ( "bt_stir_press.svg" ); + ui->b0->iconTable() [BTN_NORMAL] = conf_qrc ( "bt_stir.svg" ); + ui->b0->iconTable() [BTN_HOVER] = conf_qrc ( "bt_stir.svg" ); + ui->b0->iconTable() [BTN_PRESS] = conf_qrc ( "bt_stir_press.svg" ); ui->b0->renderToVariable(); - ui->c0->iconTable() [BTN_NORMAL] = qrc ( "bt_stir.svg" ); - ui->c0->iconTable() [BTN_HOVER] = qrc ( "bt_stir.svg" ); - ui->c0->iconTable() [BTN_PRESS] = qrc ( "bt_stir_press.svg" ); + ui->c0->iconTable() [BTN_NORMAL] = conf_qrc ( "bt_stir.svg" ); + ui->c0->iconTable() [BTN_HOVER] = conf_qrc ( "bt_stir.svg" ); + ui->c0->iconTable() [BTN_PRESS] = conf_qrc ( "bt_stir_press.svg" ); ui->c0->renderToVariable(); - ui->r0->iconTable() [BTN_NORMAL] = qrc ( "bt_stir.svg" ); - ui->r0->iconTable() [BTN_HOVER] = qrc ( "bt_stir.svg" ); - ui->r0->iconTable() [BTN_PRESS] = qrc ( "bt_stir_press.svg" ); + ui->r0->iconTable() [BTN_NORMAL] = conf_qrc ( "bt_stir.svg" ); + ui->r0->iconTable() [BTN_HOVER] = conf_qrc ( "bt_stir.svg" ); + ui->r0->iconTable() [BTN_PRESS] = conf_qrc ( "bt_stir_press.svg" ); ui->r0->renderToVariable(); - ui->r1->iconTable() [BTN_NORMAL] = qrc ( "bt_stir.svg" ); - ui->r1->iconTable() [BTN_HOVER] = qrc ( "bt_stir.svg" ); - ui->r1->iconTable() [BTN_PRESS] = qrc ( "bt_stir_press.svg" ); + ui->r1->iconTable() [BTN_NORMAL] = conf_qrc ( "bt_stir.svg" ); + ui->r1->iconTable() [BTN_HOVER] = conf_qrc ( "bt_stir.svg" ); + ui->r1->iconTable() [BTN_PRESS] = conf_qrc ( "bt_stir_press.svg" ); ui->r1->renderToVariable(); - ui->p0->setSvgFile ( qrc ( "bk_progress_background.svg" ), - qrc ( "bk_progress_trunk.svg" ) ); + ui->p0->setSvgFile ( conf_qrc ( "bk_progress_background.svg" ), + conf_qrc ( "bk_progress_trunk.svg" ) ); ui->p0->setRange ( 0, 100 ); ui->p0->setValue ( 60 ); diff --git a/test/videotest/AppRoot/skin/default.qss b/test/videotest/AppRoot/skin/default.qss new file mode 100644 index 00000000..09e37969 --- /dev/null +++ b/test/videotest/AppRoot/skin/default.qss @@ -0,0 +1,24 @@ +/*spinbox 抬起样式*/ +QTimeEdit::up-button,QDoubleSpinBox::up-button,QSpinBox::up-button { + subcontrol-origin:border; + subcontrol-position:right; + width: 12px; +} + +QTimeEdit::down-button,QDoubleSpinBox::down-button,QSpinBox::down-button { + subcontrol-origin:border; + subcontrol-position:left; + width: 12px; +} + +/*按钮按下样式*/ +QTimeEdit::up-button:pressed,QDoubleSpinBox::up-button:pressed,QSpinBox::up-button:pressed{ + subcontrol-origin:border; + subcontrol-position:right; + width: 12px; +} + +QTimeEdit::down-button:pressed,QDoubleSpinBox::down-button:pressed,QSpinBox::down-button:pressed,QSpinBox::down-button:pressed{ + subcontrol-position:left; + width: 12px; +} diff --git a/test/videotest/android/AndroidManifest.xml b/test/videotest/android/AndroidManifest.xml new file mode 100644 index 00000000..44733f0a --- /dev/null +++ b/test/videotest/android/AndroidManifest.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/videotest/android/res/drawable-hdpi/ic_launcher_round.png b/test/videotest/android/res/drawable-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..3e1aeefe Binary files /dev/null and b/test/videotest/android/res/drawable-hdpi/ic_launcher_round.png differ diff --git a/test/videotest/android/res/drawable-hdpi/icon.png b/test/videotest/android/res/drawable-hdpi/icon.png new file mode 100644 index 00000000..85e68717 Binary files /dev/null and b/test/videotest/android/res/drawable-hdpi/icon.png differ diff --git a/test/videotest/android/res/drawable-ldpi/ic_launcher_round.png b/test/videotest/android/res/drawable-ldpi/ic_launcher_round.png new file mode 100644 index 00000000..66178784 Binary files /dev/null and b/test/videotest/android/res/drawable-ldpi/ic_launcher_round.png differ diff --git a/test/videotest/android/res/drawable-ldpi/icon.png b/test/videotest/android/res/drawable-ldpi/icon.png new file mode 100644 index 00000000..88ee6f7d Binary files /dev/null and b/test/videotest/android/res/drawable-ldpi/icon.png differ diff --git a/test/videotest/android/res/drawable-mdpi/ic_launcher_round.png b/test/videotest/android/res/drawable-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..22d1ab6d Binary files /dev/null and b/test/videotest/android/res/drawable-mdpi/ic_launcher_round.png differ diff --git a/test/videotest/android/res/drawable-mdpi/icon.png b/test/videotest/android/res/drawable-mdpi/icon.png new file mode 100644 index 00000000..e5c37c2d Binary files /dev/null and b/test/videotest/android/res/drawable-mdpi/icon.png differ diff --git a/test/videotest/android/res/drawable-xhdpi/ic_launcher_round.png b/test/videotest/android/res/drawable-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..88ee6f7d Binary files /dev/null and b/test/videotest/android/res/drawable-xhdpi/ic_launcher_round.png differ diff --git a/test/videotest/android/res/drawable-xxhdpi/ic_launcher_round.png b/test/videotest/android/res/drawable-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..e5c37c2d Binary files /dev/null and b/test/videotest/android/res/drawable-xxhdpi/ic_launcher_round.png differ diff --git a/test/videotest/android/res/drawable-xxxhdpi/ic_launcher_round.png b/test/videotest/android/res/drawable-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..85e68717 Binary files /dev/null and b/test/videotest/android/res/drawable-xxxhdpi/ic_launcher_round.png differ diff --git a/test/videotest/main.cpp b/test/videotest/main.cpp new file mode 100644 index 00000000..219ca126 --- /dev/null +++ b/test/videotest/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main ( int argc, char* argv[] ) +{ + QQtApplication a ( argc, argv ); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/test/videotest/mainwindow.cpp b/test/videotest/mainwindow.cpp new file mode 100644 index 00000000..d44793b4 --- /dev/null +++ b/test/videotest/mainwindow.cpp @@ -0,0 +1,141 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow ( QWidget* parent ) : + QMainWindow ( parent ), + ui ( new Ui::MainWindow ) +{ + ui->setupUi ( this ); + + QVideoProbe* prob = new QVideoProbe ( this ); + QCamera* camera = new QCamera ( QCameraInfo::defaultCamera() ); + camera->setCaptureMode ( QCamera::CaptureVideo ); + prob->setSource ( camera ); + connect ( prob, SIGNAL ( videoFrameProbed ( const QVideoFrame& ) ), + this, SLOT ( slotTestProbe ( const QVideoFrame& ) ) ); + connect ( ui->pushButton_3, SIGNAL ( released() ), camera, SLOT ( start() ) ); + + return; + + input = new QQtVideoInput ( this ); + pline() << input->defaultCamera(); + pline() << input ->availableCameras(); + + QCameraInfo inf = input->defaultCamera(); + ui->textBrowser->append ( QString ( "Camera:%1 [default]" ).arg ( inf.deviceName() ) ); + ui->textBrowser->append ( QString ( " description:%1" ).arg ( inf.description() ) ); + ui->textBrowser->append ( QString ( " position:%1" ).arg ( inf.position() ) ); + ui->textBrowser->append ( QString ( " orientation:%1" ).arg ( inf.orientation() ) ); + ui->textBrowser->append ( QString ( " isNull:%1" ).arg ( inf.isNull() ) ); + ui->textBrowser->append ( "" ); + + QListIterator itor ( input->availableCameras() ); + while ( itor.hasNext() ) + { + const QCameraInfo& inf = itor.next(); + ui->textBrowser->append ( QString ( "Camera:%1 [index]" ).arg ( inf.deviceName() ) ); + ui->textBrowser->append ( QString ( " description:%1" ).arg ( inf.description() ) ); + ui->textBrowser->append ( QString ( " position:%1" ).arg ( inf.position() ) ); + ui->textBrowser->append ( QString ( " orientation:%1" ).arg ( inf.orientation() ) ); + ui->textBrowser->append ( QString ( " isNull:%1" ).arg ( inf.isNull() ) ); + ui->textBrowser->append ( "" ); + } + + pline() << input->viewFinderSettings().pixelFormat(); + pline() << input->camera()->supportedViewfinderPixelFormats(); + ui->textBrowser->append ( QString ( "Camera PixelFormat: [default]" ) ); + ui->textBrowser->append ( QString ( " %1" ).arg ( input->viewFinderSettings().pixelFormat() ) ); + QListIterator itor1 ( input->camera()->supportedViewfinderPixelFormats() ); + while ( itor1.hasNext() ) + { + const QVideoFrame::PixelFormat& fmt = itor1.next(); + ui->textBrowser->append ( QString ( " %1 [index]" ).arg ( fmt ) ); + } + ui->textBrowser->append ( "" ); + + connect ( input, SIGNAL ( readyRead ( QImage ) ), this, SLOT ( slotImageComing ( QImage ) ) ); + connect ( input, SIGNAL ( readyReadCapture ( QImage ) ), this, SLOT ( slotCapture ( QImage ) ) ); + + //input2 = new QQtVideoInput ( this ); + //connect ( input2, SIGNAL ( readyRead ( QImage ) ), this, SLOT ( slotImageComing2 ( QImage ) ) ); + + //QThread* thread = new QThread(); + //input2->moveToThread ( thread ); + //thread->start(); + + connect ( ui->pushButton_3, SIGNAL ( released() ), input, SLOT ( capture() ) ); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::slotImageComing ( QImage img ) +{ + ui->qqtwidget->setPixmap ( img ); +} + +void MainWindow::slotImageComing2 ( QImage img ) +{ + ui->qqtwidget_2->setPixmap ( img ); + ui->qqtwidget_2->update(); +} + +void MainWindow::slotCapture ( QImage image ) +{ + ui->qqtwidget_3->setPixmap ( image ); +} + +void MainWindow::slotTestProbe ( const QVideoFrame& frame ) +{ + if ( !frame.isValid() ) + return; + + QVideoFrame cloneFrame ( frame ); + /** + * frame 可读 + */ + if ( !cloneFrame.map ( QAbstractVideoBuffer::ReadOnly ) ) + return; + + return; + + /** + * 处理frame + */ + + //Android下的视频格式是怎么回事?需要转换吗? + + const QImage _image ( cloneFrame.bits(), + cloneFrame.width(), + cloneFrame.height(), + QVideoFrame::imageFormatFromPixelFormat ( cloneFrame.pixelFormat() ) ); + + //需要对水平方向反转。 + //Windows,现在的图像保存能成功,直接显示,程序会异常退出。使用QImage的mirrored函数进行了水平翻转,可以正常显示。 + //水平翻转是为了不崩溃,正常显示图像。必选。 + //垂直翻转是为了上下显示正常。 + const QImage image = _image.mirrored ( true, true ); + + /** + * frame 不可读 + */ + cloneFrame.unmap(); + + //emit readyRead ( image ); + slotImageComing ( image ); + return ; +} + +void MainWindow::on_pushButton_clicked() +{ + input->start(); + input2->start(); +} + +void MainWindow::on_pushButton_2_clicked() +{ + input->stop(); + input2->stop(); +} diff --git a/test/videotest/mainwindow.h b/test/videotest/mainwindow.h new file mode 100644 index 00000000..26004c13 --- /dev/null +++ b/test/videotest/mainwindow.h @@ -0,0 +1,37 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow ( QWidget* parent = 0 ); + ~MainWindow(); + +public slots: + void slotImageComing ( QImage ); + void slotImageComing2 ( QImage ); + void slotCapture ( QImage ); + + void slotTestProbe ( const QVideoFrame& frame ); +private slots: + void on_pushButton_clicked(); + + void on_pushButton_2_clicked(); + +private: + Ui::MainWindow* ui; + + QQtVideoInput* input; + QQtVideoInput* input2; +}; + +#endif // MAINWINDOW_H diff --git a/test/videotest/mainwindow.ui b/test/videotest/mainwindow.ui new file mode 100644 index 00000000..dcb15597 --- /dev/null +++ b/test/videotest/mainwindow.ui @@ -0,0 +1,128 @@ + + + MainWindow + + + + 0 + 0 + 475 + 343 + + + + videotest + + + + + + + 0 + + + + Camera Information + + + + + + + + + + Preview + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Preview + + + + + + + + 0 + 0 + + + + Stop + + + + + + + + 0 + 0 + + + + Capture + + + + + + + + + + + + + + + + 0 + 0 + 475 + 17 + + + + + + TopToolBarArea + + + false + + + + + + + + QQtWidget + QWidget +
qqtwidget.h
+
+
+ + +
diff --git a/test/videotest/videotest.pro b/test/videotest/videotest.pro new file mode 100644 index 00000000..fa6d2c93 --- /dev/null +++ b/test/videotest/videotest.pro @@ -0,0 +1,67 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-10-06T08:16:10 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = videotest +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 + +# 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 + + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +include($${PWD}/../../multi-link/add_base_manager.pri) + +#------------------------------------------------- +#用户工程配置 +#------------------------------------------------- +add_version(1,0,0,0) +add_deploy() +add_deploy_config($${PWD}/AppRoot) +add_dependent_manager(QQt) +#add_dependent_manager(QQtMediaExtention) +system(touch main.cpp) + +#------------------------------------------------- +#用户工程配置 +#------------------------------------------------- +equals(QSYS_PRIVATE, macOS) { + CONFIG += app_bundle +} + +contains(QSYS_PRIVATE, Android|AndroidX86) { + CONFIG += mobility + MOBILITY = + DISTFILES += \ + android/AndroidManifest.xml + + ANDROID_PACKAGE_SOURCE_DIR = $${PWD}/android +} + +message ($${TARGET} config $${CONFIG}) +message ($${TARGET} DEFINE $${DEFINES}) +message ($${TARGET} prelink $${QMAKE_PRE_LINK}) +message ($${TARGET} postlink $${QMAKE_POST_LINK}) diff --git a/test/videotest2/AppRoot/skin/default.qss b/test/videotest2/AppRoot/skin/default.qss new file mode 100644 index 00000000..09e37969 --- /dev/null +++ b/test/videotest2/AppRoot/skin/default.qss @@ -0,0 +1,24 @@ +/*spinbox 抬起样式*/ +QTimeEdit::up-button,QDoubleSpinBox::up-button,QSpinBox::up-button { + subcontrol-origin:border; + subcontrol-position:right; + width: 12px; +} + +QTimeEdit::down-button,QDoubleSpinBox::down-button,QSpinBox::down-button { + subcontrol-origin:border; + subcontrol-position:left; + width: 12px; +} + +/*按钮按下样式*/ +QTimeEdit::up-button:pressed,QDoubleSpinBox::up-button:pressed,QSpinBox::up-button:pressed{ + subcontrol-origin:border; + subcontrol-position:right; + width: 12px; +} + +QTimeEdit::down-button:pressed,QDoubleSpinBox::down-button:pressed,QSpinBox::down-button:pressed,QSpinBox::down-button:pressed{ + subcontrol-position:left; + width: 12px; +} diff --git a/test/videotest2/android/AndroidManifest.xml b/test/videotest2/android/AndroidManifest.xml new file mode 100644 index 00000000..0a81f5c7 --- /dev/null +++ b/test/videotest2/android/AndroidManifest.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/videotest2/android/res/drawable-hdpi/ic_launcher_round.png b/test/videotest2/android/res/drawable-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..3e1aeefe Binary files /dev/null and b/test/videotest2/android/res/drawable-hdpi/ic_launcher_round.png differ diff --git a/test/videotest2/android/res/drawable-hdpi/icon.png b/test/videotest2/android/res/drawable-hdpi/icon.png new file mode 100644 index 00000000..85e68717 Binary files /dev/null and b/test/videotest2/android/res/drawable-hdpi/icon.png differ diff --git a/test/videotest2/android/res/drawable-ldpi/ic_launcher_round.png b/test/videotest2/android/res/drawable-ldpi/ic_launcher_round.png new file mode 100644 index 00000000..66178784 Binary files /dev/null and b/test/videotest2/android/res/drawable-ldpi/ic_launcher_round.png differ diff --git a/test/videotest2/android/res/drawable-ldpi/icon.png b/test/videotest2/android/res/drawable-ldpi/icon.png new file mode 100644 index 00000000..88ee6f7d Binary files /dev/null and b/test/videotest2/android/res/drawable-ldpi/icon.png differ diff --git a/test/videotest2/android/res/drawable-mdpi/ic_launcher_round.png b/test/videotest2/android/res/drawable-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..22d1ab6d Binary files /dev/null and b/test/videotest2/android/res/drawable-mdpi/ic_launcher_round.png differ diff --git a/test/videotest2/android/res/drawable-mdpi/icon.png b/test/videotest2/android/res/drawable-mdpi/icon.png new file mode 100644 index 00000000..e5c37c2d Binary files /dev/null and b/test/videotest2/android/res/drawable-mdpi/icon.png differ diff --git a/test/videotest2/android/res/drawable-xhdpi/ic_launcher_round.png b/test/videotest2/android/res/drawable-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..88ee6f7d Binary files /dev/null and b/test/videotest2/android/res/drawable-xhdpi/ic_launcher_round.png differ diff --git a/test/videotest2/android/res/drawable-xxhdpi/ic_launcher_round.png b/test/videotest2/android/res/drawable-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..e5c37c2d Binary files /dev/null and b/test/videotest2/android/res/drawable-xxhdpi/ic_launcher_round.png differ diff --git a/test/videotest2/android/res/drawable-xxxhdpi/ic_launcher_round.png b/test/videotest2/android/res/drawable-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..85e68717 Binary files /dev/null and b/test/videotest2/android/res/drawable-xxxhdpi/ic_launcher_round.png differ diff --git a/test/videotest2/main.cpp b/test/videotest2/main.cpp new file mode 100644 index 00000000..6ea22d25 --- /dev/null +++ b/test/videotest2/main.cpp @@ -0,0 +1,18 @@ +#include "mainwindow.h" +#include + +int main ( int argc, char* argv[] ) +{ + + //高DPI下,需要支持 +#if QT_VERSION >= QT_VERSION_CHECK(5,6,0) + QApplication::setAttribute ( Qt::AA_EnableHighDpiScaling ); + QApplication::setAttribute ( Qt::AA_UseHighDpiPixmaps ); +#endif + + QQtApplication a ( argc, argv ); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/test/videotest2/mainwindow.cpp b/test/videotest2/mainwindow.cpp new file mode 100644 index 00000000..a32e387d --- /dev/null +++ b/test/videotest2/mainwindow.cpp @@ -0,0 +1,38 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow ( QWidget* parent ) : + QMainWindow ( parent ), + ui ( new Ui::MainWindow ) +{ + ui->setupUi ( this ); + + manager = new QQtVideoManager ( this ); + pline() << manager->availableCameras(); + + //设置输入 + connect ( ui->pushButton, SIGNAL ( clicked ( bool ) ), manager, SLOT ( startInput() ) ); + connect ( ui->pushButton_2, SIGNAL ( clicked ( bool ) ), manager, SLOT ( stopInput() ) ); + connect ( ui->pushButton_3, SIGNAL ( clicked ( bool ) ), manager, SLOT ( capture() ) ); + + //设置输出 + manager->viewFinder() = ui->qqtwidget; + + //设置截图输出 + //使用Wrapper建立信号和槽关系...... + QQtVideoOutput* output1 = new QQtVideoOutput ( this ); + output1->viewFinder() = ui->qqtwidget_2; + + //建立输入、输出关系 + connect ( manager, SIGNAL ( readyRead ( QImage ) ), manager, SLOT ( outputImage ( QImage ) ) ); + connect ( manager, SIGNAL ( readyReadCapture ( QImage ) ), output1, SLOT ( setPixmap ( QImage ) ) ); + + //输入由页面控制,这里开启输出 + manager->startOutput(); + output1->start(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} diff --git a/test/videotest2/mainwindow.h b/test/videotest2/mainwindow.h new file mode 100644 index 00000000..8fa58d7e --- /dev/null +++ b/test/videotest2/mainwindow.h @@ -0,0 +1,24 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow ( QWidget* parent = 0 ); + ~MainWindow(); + +private: + Ui::MainWindow* ui; + + QQtVideoManager* manager; +}; + +#endif // MAINWINDOW_H diff --git a/test/videotest2/mainwindow.ui b/test/videotest2/mainwindow.ui new file mode 100644 index 00000000..7f2e0559 --- /dev/null +++ b/test/videotest2/mainwindow.ui @@ -0,0 +1,111 @@ + + + MainWindow + + + + 0 + 0 + 400 + 300 + + + + videotest2 + + + + + + + + + + + + + + 16777215 + 40 + + + + + + 0 + 0 + 81 + 31 + + + + Preview + + + + + + 100 + 0 + 81 + 31 + + + + Stop + + + + + + 200 + 0 + 81 + 31 + + + + + 0 + 0 + + + + Capture + + + + + + + + + + 0 + 0 + 400 + 17 + + + + + + TopToolBarArea + + + false + + + + + + + + QQtWidget + QWidget +
qqtwidget.h
+
+
+ + +
diff --git a/test/videotest2/videotest2.pro b/test/videotest2/videotest2.pro new file mode 100644 index 00000000..c445affc --- /dev/null +++ b/test/videotest2/videotest2.pro @@ -0,0 +1,67 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-10-06T08:16:10 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = videotest2 +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 + +# 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 + + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +include($${PWD}/../../multi-link/add_base_manager.pri) + +#------------------------------------------------- +#用户工程配置 +#------------------------------------------------- +add_version(1,0,0,0) +add_deploy() +add_deploy_config($${PWD}/AppRoot) +add_dependent_manager(QQt) +#add_dependent_manager(QQtMediaExtention) +system(touch main.cpp) + +#------------------------------------------------- +#用户工程配置 +#------------------------------------------------- +equals(QSYS_PRIVATE, macOS) { + CONFIG += app_bundle +} + +contains(QSYS_PRIVATE, Android|AndroidX86) { + CONFIG += mobility + MOBILITY = + DISTFILES += \ + android/AndroidManifest.xml + + ANDROID_PACKAGE_SOURCE_DIR = $${PWD}/android +} + +message ($${TARGET} config $${CONFIG}) +message ($${TARGET} DEFINE $${DEFINES}) +message ($${TARGET} prelink $${QMAKE_PRE_LINK}) +message ($${TARGET} postlink $${QMAKE_POST_LINK}) diff --git a/test/videotest3/AppRoot/skin/default.qss b/test/videotest3/AppRoot/skin/default.qss new file mode 100644 index 00000000..09e37969 --- /dev/null +++ b/test/videotest3/AppRoot/skin/default.qss @@ -0,0 +1,24 @@ +/*spinbox 抬起样式*/ +QTimeEdit::up-button,QDoubleSpinBox::up-button,QSpinBox::up-button { + subcontrol-origin:border; + subcontrol-position:right; + width: 12px; +} + +QTimeEdit::down-button,QDoubleSpinBox::down-button,QSpinBox::down-button { + subcontrol-origin:border; + subcontrol-position:left; + width: 12px; +} + +/*按钮按下样式*/ +QTimeEdit::up-button:pressed,QDoubleSpinBox::up-button:pressed,QSpinBox::up-button:pressed{ + subcontrol-origin:border; + subcontrol-position:right; + width: 12px; +} + +QTimeEdit::down-button:pressed,QDoubleSpinBox::down-button:pressed,QSpinBox::down-button:pressed,QSpinBox::down-button:pressed{ + subcontrol-position:left; + width: 12px; +} diff --git a/test/videotest3/android/AndroidManifest.xml b/test/videotest3/android/AndroidManifest.xml new file mode 100644 index 00000000..dcf0c1e4 --- /dev/null +++ b/test/videotest3/android/AndroidManifest.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/videotest3/android/res/drawable-hdpi/ic_launcher_round.png b/test/videotest3/android/res/drawable-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..3e1aeefe Binary files /dev/null and b/test/videotest3/android/res/drawable-hdpi/ic_launcher_round.png differ diff --git a/test/videotest3/android/res/drawable-hdpi/icon.png b/test/videotest3/android/res/drawable-hdpi/icon.png new file mode 100644 index 00000000..85e68717 Binary files /dev/null and b/test/videotest3/android/res/drawable-hdpi/icon.png differ diff --git a/test/videotest3/android/res/drawable-ldpi/ic_launcher_round.png b/test/videotest3/android/res/drawable-ldpi/ic_launcher_round.png new file mode 100644 index 00000000..66178784 Binary files /dev/null and b/test/videotest3/android/res/drawable-ldpi/ic_launcher_round.png differ diff --git a/test/videotest3/android/res/drawable-ldpi/icon.png b/test/videotest3/android/res/drawable-ldpi/icon.png new file mode 100644 index 00000000..88ee6f7d Binary files /dev/null and b/test/videotest3/android/res/drawable-ldpi/icon.png differ diff --git a/test/videotest3/android/res/drawable-mdpi/ic_launcher_round.png b/test/videotest3/android/res/drawable-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..22d1ab6d Binary files /dev/null and b/test/videotest3/android/res/drawable-mdpi/ic_launcher_round.png differ diff --git a/test/videotest3/android/res/drawable-mdpi/icon.png b/test/videotest3/android/res/drawable-mdpi/icon.png new file mode 100644 index 00000000..e5c37c2d Binary files /dev/null and b/test/videotest3/android/res/drawable-mdpi/icon.png differ diff --git a/test/videotest3/android/res/drawable-xhdpi/ic_launcher_round.png b/test/videotest3/android/res/drawable-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..88ee6f7d Binary files /dev/null and b/test/videotest3/android/res/drawable-xhdpi/ic_launcher_round.png differ diff --git a/test/videotest3/android/res/drawable-xxhdpi/ic_launcher_round.png b/test/videotest3/android/res/drawable-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..e5c37c2d Binary files /dev/null and b/test/videotest3/android/res/drawable-xxhdpi/ic_launcher_round.png differ diff --git a/test/videotest3/android/res/drawable-xxxhdpi/ic_launcher_round.png b/test/videotest3/android/res/drawable-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..85e68717 Binary files /dev/null and b/test/videotest3/android/res/drawable-xxxhdpi/ic_launcher_round.png differ diff --git a/test/videotest3/cameracontrollerform.cpp b/test/videotest3/cameracontrollerform.cpp new file mode 100644 index 00000000..8cfca17a --- /dev/null +++ b/test/videotest3/cameracontrollerform.cpp @@ -0,0 +1,37 @@ +#include "cameracontrollerform.h" +#include "ui_cameracontrollerform.h" +#include + +CameraControllerForm::CameraControllerForm ( QWidget* parent ) : + QWidget ( parent ), + ui ( new Ui::CameraControllerForm ) +{ + ui->setupUi ( this ); + ui->horizontalSlider->setRange ( 0, 10000 ); + ui->horizontalSlider->setSingleStep ( 200 ); +} + +CameraControllerForm::~CameraControllerForm() +{ + delete ui; +} + +void CameraControllerForm::on_radioButton_toggled ( bool checked ) +{ + if ( checked ) + emit isomodel ( false ); + pline() << checked; +} + +void CameraControllerForm::on_radioButton_2_toggled ( bool checked ) +{ + if ( checked ) + emit isomodel ( true ); + pline() << checked; +} + +void CameraControllerForm::on_horizontalSlider_valueChanged ( int value ) +{ + pline() << value; + emit isovalue ( value ); +} diff --git a/test/videotest3/cameracontrollerform.h b/test/videotest3/cameracontrollerform.h new file mode 100644 index 00000000..0ca3034c --- /dev/null +++ b/test/videotest3/cameracontrollerform.h @@ -0,0 +1,34 @@ +#ifndef CAMERACONTROLLERFORM_H +#define CAMERACONTROLLERFORM_H + +#include + +namespace Ui { +class CameraControllerForm; +} + +class CameraControllerForm : public QWidget +{ + Q_OBJECT + +public: + explicit CameraControllerForm ( QWidget* parent = 0 ); + ~CameraControllerForm(); + +signals: + //auto:true, manual:false + void isomodel ( bool ); + void isovalue ( int ); + +private slots: + void on_radioButton_toggled ( bool checked ); + + void on_radioButton_2_toggled ( bool checked ); + + void on_horizontalSlider_valueChanged ( int value ); + +private: + Ui::CameraControllerForm* ui; +}; + +#endif // CAMERACONTROLLERFORM_H diff --git a/test/videotest3/cameracontrollerform.ui b/test/videotest3/cameracontrollerform.ui new file mode 100644 index 00000000..8479e585 --- /dev/null +++ b/test/videotest3/cameracontrollerform.ui @@ -0,0 +1,90 @@ + + + CameraControllerForm + + + + 0 + 0 + 152 + 322 + + + + Form + + + + + + 0 + + + + 曝光 + + + + + + + + ISO + + + + + + + Qt::Horizontal + + + + + + + ManuISO + + + + + + + AutoISO + + + + + + + + + Qt::Vertical + + + + 20 + 225 + + + + + + + + + 对焦 + + + + + 白平衡 + + + + + + + + + diff --git a/test/videotest3/main.cpp b/test/videotest3/main.cpp new file mode 100644 index 00000000..6ea22d25 --- /dev/null +++ b/test/videotest3/main.cpp @@ -0,0 +1,18 @@ +#include "mainwindow.h" +#include + +int main ( int argc, char* argv[] ) +{ + + //高DPI下,需要支持 +#if QT_VERSION >= QT_VERSION_CHECK(5,6,0) + QApplication::setAttribute ( Qt::AA_EnableHighDpiScaling ); + QApplication::setAttribute ( Qt::AA_UseHighDpiPixmaps ); +#endif + + QQtApplication a ( argc, argv ); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/test/videotest3/mainwindow.cpp b/test/videotest3/mainwindow.cpp new file mode 100644 index 00000000..a582a0f1 --- /dev/null +++ b/test/videotest3/mainwindow.cpp @@ -0,0 +1,84 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow ( QWidget* parent ) : + QMainWindow ( parent ), + ui ( new Ui::MainWindow ) +{ + ui->setupUi ( this ); + + manager = new QQtVideoManager ( this ); + + //设置输入 + connect ( ui->pushButton, SIGNAL ( clicked ( bool ) ), manager, SLOT ( startInput() ) ); + connect ( ui->pushButton_2, SIGNAL ( clicked ( bool ) ), manager, SLOT ( stopInput() ) ); + connect ( ui->pushButton_3, SIGNAL ( clicked ( bool ) ), manager, SLOT ( capture() ) ); + + //设置输出 + manager->viewFinder() = ui->qqtwidget; + + //设置截图输出 + //使用Wrapper建立信号和槽关系...... + QQtVideoOutput* output1 = new QQtVideoOutput ( this ); + output1->viewFinder() = ui->qqtwidget_2; + + //建立输入、输出关系 + connect ( manager, SIGNAL ( readyRead ( QImage ) ), manager, SLOT ( outputImage ( QImage ) ) ); + connect ( manager, SIGNAL ( readyReadCapture ( QImage ) ), output1, SLOT ( setPixmap ( QImage ) ) ); + + //建立照相机图像控制关系 + pline() << manager->expose()->supportedIsoSensitivities(); + form = new CameraControllerForm(); + form->show(); + connect ( form, SIGNAL ( isovalue ( int ) ), manager->expose(), SLOT ( setManualIsoSensitivity ( int ) ) ); + connect ( form, SIGNAL ( isomodel ( bool ) ), this, SLOT ( slotISOModelChanged ( bool ) ) ); + + //输入由页面控制,这里开启输出 + manager->startOutput(); + output1->start(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::slotISOModelChanged ( bool iso ) +{ + pline() << iso; + if ( iso ) + { + manager->expose()->setAutoIsoSensitivity(); + } + else + { + + } +} + +void MainWindow::moveEvent ( QMoveEvent* event ) +{ + form->setGeometry ( geometry().left() - 140, geometry().top(), 120, geometry().height() ); +} + +void MainWindow::resizeEvent ( QResizeEvent* event ) +{ + QSize size = event->size(); + form->setFixedHeight ( size.height() ); +} + + +void MainWindow::closeEvent ( QCloseEvent* event ) +{ + form->close(); +} + +void MainWindow::showEvent ( QShowEvent* event ) +{ + form->setGeometry ( geometry().left() - 140, geometry().top(), 120, geometry().height() ); +} + +void MainWindow::hideEvent ( QHideEvent* event ) +{ + form->hide(); +} diff --git a/test/videotest3/mainwindow.h b/test/videotest3/mainwindow.h new file mode 100644 index 00000000..6e077dd0 --- /dev/null +++ b/test/videotest3/mainwindow.h @@ -0,0 +1,41 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow ( QWidget* parent = 0 ); + ~MainWindow(); + +public slots: + void slotISOModelChanged ( bool ); + +private: + Ui::MainWindow* ui; + + QQtVideoManager* manager; + CameraControllerForm* form; + + // QWidget interface +protected: + virtual void moveEvent ( QMoveEvent* event ) override; + virtual void resizeEvent ( QResizeEvent* event ) override; + + // QWidget interface +protected: + virtual void closeEvent ( QCloseEvent* event ) override; + virtual void showEvent ( QShowEvent* event ) override; + virtual void hideEvent ( QHideEvent* event ) override; +}; + +#endif // MAINWINDOW_H diff --git a/test/videotest3/mainwindow.ui b/test/videotest3/mainwindow.ui new file mode 100644 index 00000000..d391d503 --- /dev/null +++ b/test/videotest3/mainwindow.ui @@ -0,0 +1,105 @@ + + + MainWindow + + + + 0 + 0 + 400 + 300 + + + + videotest2 + + + + + + + + + + + + + + 16777215 + 40 + + + + + + 10 + 10 + 71 + 16 + + + + Preview + + + + + + 100 + 10 + 80 + 16 + + + + Stop + + + + + + 200 + 10 + 80 + 16 + + + + Capture + + + + + + + + + + 0 + 0 + 400 + 17 + + + + + + TopToolBarArea + + + false + + + + + + + + QQtWidget + QWidget +
qqtwidget.h
+
+
+ + +
diff --git a/test/videotest3/videotest3.pro b/test/videotest3/videotest3.pro new file mode 100644 index 00000000..f3229f4f --- /dev/null +++ b/test/videotest3/videotest3.pro @@ -0,0 +1,70 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-10-06T08:16:10 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = videotest3 +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 + +# 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 + + +SOURCES += \ + main.cpp \ + mainwindow.cpp \ + cameracontrollerform.cpp + +HEADERS += \ + mainwindow.h \ + cameracontrollerform.h + +FORMS += \ + mainwindow.ui \ + cameracontrollerform.ui + +include($${PWD}/../../multi-link/add_base_manager.pri) + +#------------------------------------------------- +#用户工程配置 +#------------------------------------------------- +add_version(1,0,0,0) +add_deploy() +add_deploy_config($${PWD}/AppRoot) +add_dependent_manager(QQt) +#add_dependent_manager(QQtMediaExtention) +system(touch main.cpp) + +#------------------------------------------------- +#用户工程配置 +#------------------------------------------------- +equals(QSYS_PRIVATE, macOS) { + CONFIG += app_bundle +} + +contains(QSYS_PRIVATE, Android|AndroidX86) { + CONFIG += mobility + MOBILITY = + DISTFILES += \ + android/AndroidManifest.xml + + ANDROID_PACKAGE_SOURCE_DIR = $${PWD}/android +} + +message ($${TARGET} config $${CONFIG}) +message ($${TARGET} DEFINE $${DEFINES}) +message ($${TARGET} prelink $${QMAKE_PRE_LINK}) +message ($${TARGET} postlink $${QMAKE_POST_LINK}) diff --git a/test/voicetest/mainwindow.cpp b/test/voicetest/mainwindow.cpp index d186a46c..57cc75f5 100644 --- a/test/voicetest/mainwindow.cpp +++ b/test/voicetest/mainwindow.cpp @@ -89,11 +89,11 @@ MainWindow::MainWindow ( QWidget* parent ) : //e.play(); //响 - e.setSource ( QUrl::fromLocalFile ( res ( "9733.wav" ) ) ); + e.setSource ( QUrl::fromLocalFile ( conf_res ( "9733.wav" ) ) ); //e.play(); //响 - //QSound::play ( res ( "9733.wav" ) ); + //QSound::play ( conf_res ( "9733.wav" ) ); //响 //QApplication::beep(); diff --git a/test/voicetest2/AppRoot/res/9612.wav b/test/voicetest2/AppRoot/res/9612.wav new file mode 100644 index 00000000..01fa1b13 Binary files /dev/null and b/test/voicetest2/AppRoot/res/9612.wav differ diff --git a/test/voicetest2/AppRoot/res/9733.wav b/test/voicetest2/AppRoot/res/9733.wav new file mode 100644 index 00000000..20a4c68f Binary files /dev/null and b/test/voicetest2/AppRoot/res/9733.wav differ diff --git a/test/voicetest2/AppRoot/res/9763.wav b/test/voicetest2/AppRoot/res/9763.wav new file mode 100644 index 00000000..91b8faad Binary files /dev/null and b/test/voicetest2/AppRoot/res/9763.wav differ diff --git a/test/voicetest2/AppRoot/res/9767.wav b/test/voicetest2/AppRoot/res/9767.wav new file mode 100644 index 00000000..be47993e Binary files /dev/null and b/test/voicetest2/AppRoot/res/9767.wav differ diff --git a/test/voicetest2/android/AndroidManifest.xml b/test/voicetest2/android/AndroidManifest.xml new file mode 100644 index 00000000..6d919dad --- /dev/null +++ b/test/voicetest2/android/AndroidManifest.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/voicetest2/android/res/drawable-hdpi/ic_launcher.png b/test/voicetest2/android/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 00000000..445bb11b Binary files /dev/null and b/test/voicetest2/android/res/drawable-hdpi/ic_launcher.png differ diff --git a/test/voicetest2/android/res/drawable-hdpi/icon.png b/test/voicetest2/android/res/drawable-hdpi/icon.png new file mode 100644 index 00000000..e1aadcbd Binary files /dev/null and b/test/voicetest2/android/res/drawable-hdpi/icon.png differ diff --git a/test/voicetest2/android/res/drawable-ldpi/ic_launcher.png b/test/voicetest2/android/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 00000000..cb129452 Binary files /dev/null and b/test/voicetest2/android/res/drawable-ldpi/ic_launcher.png differ diff --git a/test/voicetest2/android/res/drawable-ldpi/icon.png b/test/voicetest2/android/res/drawable-ldpi/icon.png new file mode 100644 index 00000000..3eaa29bd Binary files /dev/null and b/test/voicetest2/android/res/drawable-ldpi/icon.png differ diff --git a/test/voicetest2/android/res/drawable-mdpi/ic_launcher.png b/test/voicetest2/android/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 00000000..15876f47 Binary files /dev/null and b/test/voicetest2/android/res/drawable-mdpi/ic_launcher.png differ diff --git a/test/voicetest2/android/res/drawable-mdpi/icon.png b/test/voicetest2/android/res/drawable-mdpi/icon.png new file mode 100644 index 00000000..f35a8cb2 Binary files /dev/null and b/test/voicetest2/android/res/drawable-mdpi/icon.png differ diff --git a/test/voicetest2/android/res/drawable-xhdpi/ic_launcher.png b/test/voicetest2/android/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 00000000..3eaa29bd Binary files /dev/null and b/test/voicetest2/android/res/drawable-xhdpi/ic_launcher.png differ diff --git a/test/voicetest2/android/res/drawable-xxhdpi/ic_launcher.png b/test/voicetest2/android/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..f35a8cb2 Binary files /dev/null and b/test/voicetest2/android/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/test/voicetest2/android/res/drawable-xxxhdpi/ic_launcher.png b/test/voicetest2/android/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..e1aadcbd Binary files /dev/null and b/test/voicetest2/android/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/test/voicetest2/main.cpp b/test/voicetest2/main.cpp new file mode 100644 index 00000000..c11c5e09 --- /dev/null +++ b/test/voicetest2/main.cpp @@ -0,0 +1,18 @@ +#include "mainwindow.h" +#include +#include +#include + +int main ( int argc, char* argv[] ) +{ + QQtApplication a ( argc, argv ); + + MainWindow w; + w.show(); + +#ifdef __ANDROID__ + w.showMaximized(); +#endif + + return a.exec(); +} diff --git a/test/voicetest2/mainwindow.cpp b/test/voicetest2/mainwindow.cpp new file mode 100644 index 00000000..36075c47 --- /dev/null +++ b/test/voicetest2/mainwindow.cpp @@ -0,0 +1,598 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include +#include +#include +#include +#include + +MainWindow::MainWindow ( QWidget* parent ) : + QMainWindow ( parent ), + ui ( new Ui::MainWindow ) +{ + ui->setupUi ( this ); + + connect ( &manager, SIGNAL ( readyRead() ), this, SLOT ( readyRead() ) ); + + connect ( &wavRecManager, SIGNAL ( readyRead() ), this, SLOT ( wavRecReadyRead() ) ); + connect ( &wavFileManager, SIGNAL ( readyRead() ), this, SLOT ( wavFileReadyRead() ) ); + + QList ladInfo; + ladInfo = QAudioDeviceInfo::availableDevices ( QAudio::AudioInput ); + QListIterator itor ( ladInfo ); + pline() << "本机音频输入设备列表"; + + while ( itor.hasNext() ) + pline() << itor.next().deviceName(); + + pline() << "默认输入设备" << QAudioDeviceInfo::defaultInputDevice().deviceName(); + pline() << "输入设备详细信息"; + itor.toFront(); + + while ( itor.hasNext() ) + { + QAudioDeviceInfo adInfo = itor.next(); + pline() << adInfo.deviceName(); + pline() << adInfo.supportedByteOrders(); + pline() << adInfo.supportedChannelCounts(); + pline() << adInfo.supportedCodecs(); + pline() << adInfo.supportedSampleRates(); + pline() << adInfo.supportedSampleSizes(); + pline() << adInfo.supportedSampleTypes(); + } + + + QList ladOutputInfo; + ladOutputInfo = QAudioDeviceInfo::availableDevices ( QAudio::AudioOutput ); + QListIterator itor2 ( ladOutputInfo ); + pline() << "本机音频输出设备列表"; + + while ( itor2.hasNext() ) + pline() << itor2.next().deviceName(); + + pline() << "默认输出设备" << QAudioDeviceInfo::defaultOutputDevice().deviceName(); + pline() << "输出设备详细信息"; + itor2.toFront(); + + while ( itor2.hasNext() ) + { + QAudioDeviceInfo adInfo = itor2.next(); + pline() << adInfo.deviceName(); + pline() << adInfo.supportedByteOrders(); + pline() << adInfo.supportedChannelCounts(); + pline() << adInfo.supportedCodecs(); + pline() << adInfo.supportedSampleRates(); + pline() << adInfo.supportedSampleSizes(); + pline() << adInfo.supportedSampleTypes(); + } + + + pline() << ".........................."; + + connect ( ui->inputListWidget->selectionModel(), SIGNAL ( currentRowChanged ( QModelIndex, QModelIndex ) ), + this, SLOT ( currentInputRowChanged ( QModelIndex, QModelIndex ) ) ); + connect ( ui->outputListWidget->selectionModel(), SIGNAL ( currentRowChanged ( QModelIndex, QModelIndex ) ), + this, SLOT ( currentOutputRowChanged ( QModelIndex, QModelIndex ) ) ); + +// on_pushButton_2_clicked(); +// ui->inputListWidget->setCurrentRow ( 0 ); +// ui->outputListWidget->setCurrentRow ( 0 ); +// ui->inputListWidget->setFocus(); + + ui->inHS->setRange ( 0, 100 ); + ui->inHS->setValue ( 100 ); + + ui->outHS->setRange ( 0, 100 ); + ui->outHS->setValue ( 100 ); + + //pline() << QSoundEffect::supportedMimeTypes(); + + QSoundEffect e; + e.setLoopCount ( 1 ); + e.setVolume ( 0.9f ); + e.setMuted ( false ); + + //不响 + QUrl u; + u.setUrl ( "http://xmdx.sc.chinaz.com/Files/DownLoad/sound1/201802/9733.wav" ); + e.setSource ( u ); + //e.play(); + + //响 + e.setSource ( QUrl::fromLocalFile ( conf_res ( "9733.wav" ) ) ); + //e.play(); + + //响 + //QSound::play ( conf_res ( "9733.wav" ) ); + + //响 + QQtWavSoundEffect e1; + //e1.play ( conf_res ( "9733.wav" ) ); + + //响 + //QApplication::beep(); + + //建议初始化 + QQtWavSoundEffect::Instance ( this ); + + //可以多次循环调用。 + QQtWavSound ( conf_res ( "9733.wav" ) ); + + //QQtSleep ( 3000 ); + +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +QAudioDeviceInfo MainWindow::findInputAudioDeviceInfoByName ( QString devName ) +{ + QList ladInfo; + ladInfo = QQtAudioManager::availableInputDevices(); + QListIterator itor ( ladInfo ); + + while ( itor.hasNext() ) + { + QAudioDeviceInfo adInfo = itor.next(); + + if ( devName == adInfo.deviceName() ) + return adInfo; + } +} + +QAudioDeviceInfo MainWindow::findOutputAudioDeviceInfoByName ( QString devName ) +{ + QList ladInfo; + ladInfo = QQtAudioManager::availableOutputDevices(); + QListIterator itor ( ladInfo ); + + while ( itor.hasNext() ) + { + QAudioDeviceInfo adInfo = itor.next(); + + if ( devName == adInfo.deviceName() ) + return adInfo; + } +} + + +void MainWindow::on_pushButton_2_clicked() +{ + ui->inputListWidget->clear(); + + QList ladInfo; + ladInfo = QQtAudioManager::availableInputDevices(); + QListIterator itor ( ladInfo ); + pline() << "本机音频输入设备列表"; + + while ( itor.hasNext() ) + { + QAudioDeviceInfo adInfo = itor.next(); + pline() << adInfo.deviceName(); + ui->inputListWidget->addItem ( adInfo.deviceName() ); + } + + + ui->outputListWidget->clear(); + + QList ladOutputInfo; + ladOutputInfo = QQtAudioManager::availableOutputDevices(); + QListIterator itor2 ( ladOutputInfo ); + pline() << "本机音频输出设备列表"; + + while ( itor2.hasNext() ) + { + QAudioDeviceInfo adInfo = itor2.next(); + pline() << adInfo.deviceName(); + ui->outputListWidget->addItem ( adInfo.deviceName() ); + } + +} + +void MainWindow::currentInputRowChanged ( QModelIndex cur, QModelIndex ) +{ + /*在清空设备列表时,clear函数,会调用多次这个函数。在这里用cur valid加以过滤,否则,程序会崩溃退出。*/ + if ( !cur.isValid() ) + return; + + ui->inBit->clear(); + ui->inChn->clear(); + ui->intRate->clear(); + + + QString name = cur.data().toString(); + QAudioDeviceInfo dev = findInputAudioDeviceInfoByName ( name ); + + if ( dev.isNull() ) + return; + + QList size = dev.supportedSampleSizes(); + QListIterator itor ( size ); + + while ( itor.hasNext() ) + { + QString s0 = QString::number ( itor.next() ); + ui->inBit->addItem ( s0 ); + } + + itor = dev.supportedChannelCounts(); + + while ( itor.hasNext() ) + { + QString s0 = QString::number ( itor.next() ); + ui->inChn->addItem ( s0 ); + } + + itor = dev.supportedSampleRates(); + + while ( itor.hasNext() ) + { + QString s0 = QString::number ( itor.next() ); + ui->intRate->addItem ( s0 ); + } + +} + +void MainWindow::currentOutputRowChanged ( QModelIndex cur, QModelIndex ) +{ + if ( !cur.isValid() ) + return; + + ui->outBit->clear(); + ui->outChn->clear(); + ui->outRate->clear(); + + + QString name = cur.data().toString(); + QAudioDeviceInfo dev = findOutputAudioDeviceInfoByName ( name ); + + if ( dev.isNull() ) + return; + + QList size = dev.supportedSampleSizes(); + QListIterator itor ( size ); + + while ( itor.hasNext() ) + { + QString s0 = QString::number ( itor.next() ); + ui->outBit->addItem ( s0 ); + } + + itor = dev.supportedChannelCounts(); + + while ( itor.hasNext() ) + { + QString s0 = QString::number ( itor.next() ); + ui->outChn->addItem ( s0 ); + } + + itor = dev.supportedSampleRates(); + + while ( itor.hasNext() ) + { + QString s0 = QString::number ( itor.next() ); + ui->outRate->addItem ( s0 ); + } +} + +/* + * 处理声音三要点 + * 声音的格式 ,也就是声音三要素,输入一个、输出一个,manager对其分开管理,但是建议用户合并为一个置等。通道数、采样位宽、采样率 + * 声音设备 ,输入一个、输出一个,manager管理start\stop等接口,manager内部的inputManager和outputManager负责其他接口。 + * 声音设备的读写出入口 ,manager管理,包括可读信号和写入函数。 +*/ +void MainWindow::on_pushButton_clicked() +{ + /*这里是自定义输入、输出设备*/ + QString name = QQtAudioManager::defaultInputDevice().deviceName(); + + if ( ui->inputListWidget->currentIndex().isValid() ) + name = ui->inputListWidget->currentIndex().data().toString(); + + QAudioDeviceInfo dev = findInputAudioDeviceInfoByName ( name ); + + name = QQtAudioManager::defaultOutputDevice().deviceName(); + + if ( ui->outputListWidget->currentIndex().isValid() ) + name = ui->outputListWidget->currentIndex().data().toString(); + + QAudioDeviceInfo devOut = findOutputAudioDeviceInfoByName ( name ); + + /*使用默认输入、输出设备*/ + //如果开启这段代码,页面上的输入、输出设备选择,就仅仅是个显示了,不具备操作能力。 + /* + dev = QQtAudioManager::defaultInputDevice(); + devOut = QQtAudioManager::defaultOutputDevice(); + */ + + //把设备设进manager去 + manager.inputDeviceInfo() = dev; + manager.outputDeviceInfo() = devOut; + + //这里保证输入、输出使用格式相等 或者 不同 + //如果格式不同,在mac电脑上本地输入输出设备是可以使用的,但是对于连接的语音蓝牙话筒,却是不可以使用的,原因未知。 + //格式相同的时候,实在是太好用啦。 + //这个建议默认就相同,但是,在QQtAudioManager当中,并没有直接将其相等处理,如果用户在readyRead槽函数里,可以更改采样率进行某些特殊处理。一般不需要差异处理的,相等就行了。 +// int inBit = ui->inBit->currentIndex().data().toInt(); +// int inChn = ui->inChn->currentIndex().data().toInt(); +// int inRate = ui->intRate->currentIndex().data().toInt(); +// QAudioFormat inFmt; +// inFmt.setChannelCount ( inChn ); +// inFmt.setSampleSize ( inBit ); +// inFmt.setSampleRate ( inRate ); +// inFmt.setCodec ( "audio/pcm" ); +// manager.inputAudioFormat() = inFmt; + + QAudioFormat outFmt = manager.outputDeviceInfo().preferredFormat(); + + int outBit = outFmt.sampleSize(), outChn = outFmt.channelCount(), outRate = outFmt.sampleRate(); + + if ( ui->outBit->currentIndex().isValid() ) + outBit = ui->outBit->currentIndex().data().toInt(); + + if ( ui->outChn->currentIndex().isValid() ) + outChn = ui->outChn->currentIndex().data().toInt(); + + if ( ui->outRate->currentIndex().isValid() ) + outRate = ui->outRate->currentIndex().data().toInt(); + + outFmt.setChannelCount ( outChn ); + outFmt.setSampleSize ( outBit ); + outFmt.setSampleRate ( outRate ); + outFmt.setCodec ( "audio/pcm" ); + + manager.inputAudioFormat() = outFmt; + manager.outputAudioFormat() = outFmt; + + pline() << "in prefer" << dev.preferredFormat().channelCount() << dev.preferredFormat().sampleRate() << + dev.preferredFormat().sampleSize(); + + pline() << "out prefer" << devOut.preferredFormat().channelCount() << devOut.preferredFormat().sampleRate() << + devOut.preferredFormat().sampleSize(); + + pline() << "in" << manager.inputAudioFormat().channelCount() << manager.inputAudioFormat().sampleRate() << + manager.inputAudioFormat().sampleSize(); + + pline() << "out" << manager.outputAudioFormat().channelCount() << manager.outputAudioFormat().sampleRate() << + manager.outputAudioFormat().sampleSize(); + + manager.startInput(); + manager.startOutput(); +} + +void MainWindow::readyRead() +{ + //这里是用户实现,任何用户希望做的事情,都在这里做完。 + //可以 录音、保存文件 + //可以 直接播放 + //可以 混音 +保存 +播放... + //可以 消音 + //可以 将pcm转换为其他格式音频 + //可以 降噪 + //可以 ... + //ptime();//11-12ms 是个10ms timer + QByteArray bytes = manager.readAll(); + manager.write ( bytes ); +} + +void MainWindow::wavRecReadyRead() +{ + QByteArray bytes = wavRecManager.readAll(); + //pline() << "recording:" << bytes.size(); + wavFileManager.write ( bytes ); +} + +void MainWindow::wavFileReadyRead() +{ + QByteArray bytes = wavFileManager.readAll(); + //pline() << "playing:" << bytes.size(); + wavRecManager.write ( bytes ); +} + +void MainWindow::on_pushButton_3_clicked() +{ + manager.stopInput(); + manager.stopOutput(); +} + +/*bug:Qt 设置音量会报错退出*/ +void MainWindow::on_inHS_valueChanged ( int value ) +{ + return; + + if ( !manager.inputDevice() ) + return; + + qreal linearVolume; +// qreal linearVolume = QAudio::convertVolume ( value / qreal ( 100.0 ), +// QAudio::LogarithmicVolumeScale, +// QAudio::LinearVolumeScale ); + +// pline() << "输入音量" << value << linearVolume << qRound ( linearVolume * 100 ) ; + manager.inputManager()->setVolume ( qRound ( linearVolume * 100 ) ); +} + +/*bug:Qt 设置音量会报错退出*/ +void MainWindow::on_outHS_valueChanged ( int value ) +{ + return; + + if ( !manager.outputDevice() ) + return; + + qreal vol = qreal ( value ) / 100; + pline() << "输出音量" << vol ; + manager.outputManager()->setVolume ( vol ); +} + +void MainWindow::on_pushButton_4_clicked() +{ + manager.inputAudioFormat() = QQtAudioManager::defaultOutputDevice().preferredFormat(); + manager.outputAudioFormat() = QQtAudioManager::defaultOutputDevice().preferredFormat(); + + pline() << "in prefer" << QQtAudioManager::defaultInputDevice().preferredFormat().channelCount() << + QQtAudioManager::defaultInputDevice().preferredFormat().sampleRate() << + QQtAudioManager::defaultInputDevice().preferredFormat().sampleSize(); + + pline() << "out prefer" << QQtAudioManager::defaultOutputDevice().preferredFormat().channelCount() << + QQtAudioManager::defaultOutputDevice().preferredFormat().sampleRate() << + QQtAudioManager::defaultOutputDevice().preferredFormat().sampleSize(); + + pline() << "in" << manager.inputAudioFormat().channelCount() << manager.inputAudioFormat().sampleRate() << + manager.inputAudioFormat().sampleSize(); + + pline() << "out" << manager.outputAudioFormat().channelCount() << manager.outputAudioFormat().sampleRate() << + manager.outputAudioFormat().sampleSize(); + + manager.startDefaultInput(); + manager.startDefaultOutput(); +} + +void MainWindow::on_pushButton_5_clicked() +{ + QString name = QQtAudioManager::defaultOutputDevice().deviceName(); + + if ( ui->outputListWidget->currentIndex().isValid() ) + name = ui->outputListWidget->currentIndex().data().toString(); + + QAudioDeviceInfo devOut = findOutputAudioDeviceInfoByName ( name ); + + QQtWavSoundEffect::Instance()->useCustomOutputDevice ( devOut ); + QQtWavSound()->setLoops ( 3 ); + QQtWavSound ( conf_res ( "9733.wav" ) ); +} + +void MainWindow::on_pushButton_6_clicked() +{ + QString name = QQtAudioManager::defaultOutputDevice().deviceName(); + + if ( ui->outputListWidget->currentIndex().isValid() ) + name = ui->outputListWidget->currentIndex().data().toString(); + + QAudioDeviceInfo devOut = findOutputAudioDeviceInfoByName ( name ); + + QQtWavSoundEffect::Instance()->useCustomOutputDevice ( devOut ); + QQtWavSound ( conf_res ( "9763.wav" ) ); + //QSound::play ( conf_res("9763.wav")); +} + +void MainWindow::on_pushButton_7_clicked() +{ + QString name = QQtAudioManager::defaultOutputDevice().deviceName(); + + if ( ui->outputListWidget->currentIndex().isValid() ) + name = ui->outputListWidget->currentIndex().data().toString(); + + QAudioDeviceInfo devOut = findOutputAudioDeviceInfoByName ( name ); + + QQtWavSoundEffect::Instance()->useCustomOutputDevice ( devOut ); + QQtWavSound()->setLoops ( 1 ); + QQtWavSound ( conf_res ( "9612.wav" ) ); +} + +#ifdef __ANDROID__ +#define TMPFILE "/sdcard/temp.wav" +#else +#define TMPFILE "./temp.wav" +#endif + +void MainWindow::on_pushButton_8_clicked() +{ + //不需要停止录音?需要 + //android 不支持./temp.wav.... + + //record + QString name = QQtAudioManager::defaultInputDevice().deviceName(); + if ( ui->inputListWidget->currentIndex().isValid() ) + name = ui->inputListWidget->currentIndex().data().toString(); + QAudioDeviceInfo input = findInputAudioDeviceInfoByName ( name ); + + + QAudioFormat outFmt = input.preferredFormat(); + int outBit = outFmt.sampleSize(), outChn = outFmt.channelCount(), outRate = outFmt.sampleRate(); + if ( ui->inBit->currentIndex().isValid() ) + outBit = ui->inBit->currentIndex().data().toInt(); + if ( ui->inChn->currentIndex().isValid() ) + outChn = ui->inChn->currentIndex().data().toInt(); + if ( ui->intRate->currentIndex().isValid() ) + outRate = ui->intRate->currentIndex().data().toInt(); + + outFmt.setChannelCount ( outChn ); + outFmt.setSampleSize ( outBit ); + outFmt.setSampleRate ( outRate ); + outFmt.setCodec ( "audio/pcm" ); + + wavRecManager.inputDeviceInfo() = input; + wavRecManager.inputAudioFormat() = outFmt; + + //save wav file + wavFileManager.outputAudioFormat() = wavRecManager.inputAudioFormat(); + wavFileManager.setOutputSourceFile ( TMPFILE ); + + pline() << "record:" << wavRecManager.inputDeviceInfo().deviceName() << wavRecManager.inputAudioFormat(); + pline() << "save:" << wavFileManager.outputSourceFile() << wavFileManager.outputAudioFormat(); + + //内部存在自动关停。对wav写自动关停,会导致文件被重写。这个函数是录音重新开始,所以可以自动关停。 + wavFileManager.startOutput(); + wavRecManager.startInput(); +} + +void MainWindow::on_pushButton_9_clicked() +{ + //不需要停止放音?需要 + + //read wav file + wavFileManager.setInputSourceFile ( TMPFILE ); + + //play record + QString name = QQtAudioManager::defaultOutputDevice().deviceName(); + if ( ui->outputListWidget->currentIndex().isValid() ) + name = ui->outputListWidget->currentIndex().data().toString(); + QAudioDeviceInfo devOut = findOutputAudioDeviceInfoByName ( name ); + + QAudioFormat outFmt = devOut.preferredFormat(); + int outBit = outFmt.sampleSize(), outChn = outFmt.channelCount(), outRate = outFmt.sampleRate(); + if ( ui->outBit->currentIndex().isValid() ) + outBit = ui->outBit->currentIndex().data().toInt(); + if ( ui->outChn->currentIndex().isValid() ) + outChn = ui->outChn->currentIndex().data().toInt(); + if ( ui->outRate->currentIndex().isValid() ) + outRate = ui->outRate->currentIndex().data().toInt(); + outFmt.setChannelCount ( outChn ); + outFmt.setSampleSize ( outBit ); + outFmt.setSampleRate ( outRate ); + outFmt.setCodec ( "audio/pcm" ); + + wavRecManager.outputAudioFormat() = outFmt; + wavRecManager.outputDeviceInfo() = devOut; + + pline() << "file:" << wavFileManager.inputSourceFile() << wavFileManager.inputAudioFormat(); + pline() << "play:" << wavRecManager.outputDeviceInfo().deviceName() << wavRecManager.outputAudioFormat(); + + //内部存在自动关停。 + wavRecManager.startOutput(); + wavFileManager.startInput(); +} + +void MainWindow::on_pushButton_10_clicked() +{ + wavRecManager.stopInput(); + wavFileManager.stopOutput(); +} + +void MainWindow::on_pushButton_11_clicked() +{ + wavFileManager.stopInput(); + wavRecManager.stopOutput(); +} + +void MainWindow::on_pushButton_12_clicked() +{ + //android support 16bit but 24bit + QQtWavSoundEffect* e0 = QQtWavSound(); + e0->setTimerInterval ( 100 ); + QQtWavSound ( conf_res ( "9767.wav" ) ); +} diff --git a/test/voicetest2/mainwindow.h b/test/voicetest2/mainwindow.h new file mode 100644 index 00000000..0b513861 --- /dev/null +++ b/test/voicetest2/mainwindow.h @@ -0,0 +1,67 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow ( QWidget* parent = 0 ); + ~MainWindow(); + + QAudioDeviceInfo findInputAudioDeviceInfoByName ( QString devName ); + + QAudioDeviceInfo findOutputAudioDeviceInfoByName ( QString devName ); + +private slots: + void on_pushButton_2_clicked(); + void currentInputRowChanged ( QModelIndex, QModelIndex ); + void currentOutputRowChanged ( QModelIndex, QModelIndex ); + void on_pushButton_clicked(); + void readyRead(); + + //录音到wav + void wavRecReadyRead(); + //读取rec wav播放 + void wavFileReadyRead(); + void on_pushButton_3_clicked(); + + void on_inHS_valueChanged ( int value ); + + void on_outHS_valueChanged ( int value ); + + void on_pushButton_4_clicked(); + + void on_pushButton_5_clicked(); + + void on_pushButton_6_clicked(); + + void on_pushButton_7_clicked(); + + void on_pushButton_8_clicked(); + + void on_pushButton_9_clicked(); + + void on_pushButton_10_clicked(); + + void on_pushButton_11_clicked(); + + void on_pushButton_12_clicked(); + +private: + Ui::MainWindow* ui; + QQtAudioManager manager; + + QQtAudioManager wavRecManager; + QQtWavAudioManager wavFileManager; +}; + +#endif // MAINWINDOW_H diff --git a/test/voicetest2/mainwindow.ui b/test/voicetest2/mainwindow.ui new file mode 100644 index 00000000..96a25a1a --- /dev/null +++ b/test/voicetest2/mainwindow.ui @@ -0,0 +1,273 @@ + + + MainWindow + + + + 0 + 0 + 751 + 367 + + + + MainWindow + + + + + + + 0 + + + + AudioManager + + + + + + + + + + + + + + + + + + + + input format + + + + + + + input device + + + + + + + + + + + + + + + + + + + + + + + output format + + + + + + + output device + + + + + + + + + + + + start take voice and play + + + + + + + start take voice +and play (default device) + + + + + + + stop (optional) + + + + + + + refresh device list + + + + + + + + + + + WavAudioManager + + + + + + + + + sound effect 1 + + + + + + + sound effect 2 + + + + + + + sound effect 3 + + + + + + + sound effect 4 + + + + + + + + + + + + + record 0 + + + + + + + stop record + + + + + + + play record 0 + + + + + + + stop playing + + + + + + + + + + + + + input volume + + + + + + + Qt::Horizontal + + + + + + + output volume + + + + + + + Qt::Horizontal + + + + + + + + + + Qt::Horizontal + + + + 183 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 129 + + + + + + + + + Tab 3 + + + + + + + + + + + diff --git a/test/voicetest2/voicetest.qrc b/test/voicetest2/voicetest.qrc new file mode 100644 index 00000000..3e46be4e --- /dev/null +++ b/test/voicetest2/voicetest.qrc @@ -0,0 +1,8 @@ + + + AppRoot/res/9733.wav + AppRoot/res/9612.wav + AppRoot/res/9763.wav + AppRoot/res/9767.wav + + diff --git a/test/voicetest2/voicetest2.pro b/test/voicetest2/voicetest2.pro new file mode 100644 index 00000000..a2d4e3b1 --- /dev/null +++ b/test/voicetest2/voicetest2.pro @@ -0,0 +1,70 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-02-08T20:04:18 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = voicetest2 +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 + +# 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 + + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +CONFIG += mobility +MOBILITY = + +#这句话很重要 启动拷贝很多东西 +system (touch main.cpp) + +include (../../multi-link/multi-link/add_base_manager.pri) + +contains(QSYS_PRIVATE, Android|AndroidX86) { + CONFIG += mobility + MOBILITY = + DISTFILES += \ + $${PWD}/android/AndroidManifest.xml + + ANDROID_PACKAGE_SOURCE_DIR = $${PWD}/android +} + +RESOURCES += \ + voicetest.qrc + +#这个的设置有特点,要先设置 +add_version (1,0,0,0) + +#先发布App +#app从build到deploy +add_deploy() + +#后发布依赖 +#libQQt从sdk到build和deploy +add_dependent_manager(QQt) + +#发布配置文件 把AppRoot里的配置项目拷贝到运行目录和发布目录 +add_deploy_config($${PWD}/AppRoot) + +message($$ANDROID_EXTRA_LIBS)