camera:一个基于QT+Weston的Camera应用
基于QT UI框架编写camera,作为Wayland Client运行。
QT Multimedia自带的camera示例程序位于examples/multimediawidgets/camera。
Camera Example | Qt Multimedia 5.15.16
1 camera框架
2 camera的mk文件
camera.mk配置:TEMPLATE = app TARGET = camera QT += multimedia multimediawidgets--依赖的QT模块。 HEADERS = \--依赖的头文件,需要经过moc编译。 camera.h \ imagesettings.h \ videosettings.h SOURCES = \ main.cpp \ camera.cpp \ imagesettings.cpp \ videosettings.cpp FORMS += \-- camera.ui \ videosettings.ui \ imagesettings.ui RESOURCES += camera.qrc target.path = $$[QT_INSTALL_EXAMPLES]/multimediawidgets/camera INSTALLS += target QT+=widgets include(../../multimedia/shared/shared.pri)
执行如下命令生成Makefile:
output/rockchip_rk3588/host/bin/qmake -o Makefile camera.pro -spec devices/linux-buildroot-g++ QMAKE_CXXFLAGS+=-DENABLE_WAYLAND_PLATFORM QMAKE_LFLAGS+=-lwayland-client
qmake-package是通过qmake统一处理生成Makefile,参考《Infrastructure for QMake-based packages》。qmake-package的实现位于package/pkg-qmake.mk。
3 camera代码
moc(Meta Object Compiler)元对象编译器:把QT扩展的C++语法编译成标准C++代码。
rcc(Resource Compiler):把.qrc(QML的UI资源和图片等)文件编译成标准C++代码。
uic(UI Compiler):把.ui文件编译成标准C++代码。
QT代码的生成、编译过程如下:
以camera为例:
examples/multimediawidgets/camera/ ├── camera--可执行文件。 ├── camera.cpp--Camera类的实现。 ├── camera.h--Camera类的定义。 ├── camera.pro--camera工程配置文件,参考《Qt开发中如何正确的编写.pro文件及详细说明》。 ├── camera.qrc--camera资源文件。 ├── camera.ui--camera应用UI配置文件。经过uic编译生成。 ├── doc │ ├── images │ │ └── camera-example.png │ └── src │ └── camera.qdoc ├── images │ └── shutter.svg ├── imagesettings.cpp--ImageSettings类的实现。 ├── imagesettings.h--ImageSettings类的定义。 ├── imagesettings.ui--拍照窗口UI配置文件。 ├── main.cpp--camera程序主入口。 ├── Makefile--根据camera.pro生成的Makefile。 ├── .moc │ ├── moc_camera.cpp--moc编译带关键字Q_OBJECT的camera.h得到moc_camera.cpp。 │ ├── moc_imagesettings.cpp--moc编译带关键字Q_OBJECT的imagesettings.h得到moc_imagesettings.cpp。 │ ├── moc_predefs.h--预定义的宏。 │ └── moc_videosettings.cpp--moc编译带关键字Q_OBJECT的videosettings.h得到moc_videosettings.cpp。 ├── .obj │ ├── camera.o │ ├── imagesettings.o │ ├── main.o │ ├── moc_camera.o │ ├── moc_imagesettings.o │ ├── moc_videosettings.o │ ├── qrc_camera.o │ └── videosettings.o ├── .pch ├── .rcc │ └── qrc_camera.cpp--rcc编译camera.qrc得到qrc_camera.cpp。 ├── .uic │ ├── ui_camera.h--uic编译camera.ui得到ui_camera.h。 │ ├── ui_imagesettings.h--uic编译imagesettings.ui得到ui_imagesettings.h。 │ └── ui_videosettings.h--uic编译videosettings.ui得到ui_imagesettings.h。 ├── videosettings.cpp--VideoSettings类的实现。 ├── videosettings.h--VideoSettings类的定义。 └── videosettings.ui--录像窗口的配置文件。
3.1 ui文件
ui文件定义了应用界面、Action、Slot/Signal及函数对应关系。
ui文件经过uic编译生成ui_*.h文件(参考Using a Designer UI File in Your C++ Application),包括:
- 生成指向包含Widget、Action、Layout、Button等结构体。
- setupUI()函数创建Widget树,即函数和Signal等关联操作。
- retranslateUi()进行字符串资源处理。
使用QT Creator打开Camera如下图:
《Qt中的UI文件介绍_.ui文件》《Qt的信号与槽_qt 信号槽》
3.2 moc
moc 全称是 Meta-Object Compiler,也就是“元对象编译器”,它主要用于处理C++源文件中的非标准C++代码。Qt 程序在交由标准编译器编译之前,先要使用 moc 分析 C++ 源文件。如果它发现在一个头文件中包含了宏 Q_OBJECT,则会生成另外一个 C++ 源文件。这个源文件中包含了 Q_OBJECT 宏的实现代码。这个新的文件名字将会是原文件名前面加上 moc_ 构成。这个新的文件同样将进入编译系统,最终被链接到二进制代码中去。因此我们可以知道,这个新的文件不是“替换”掉旧的文件,而是与原文件一起参与编译。另外,我们还可以看出一点,moc 的执行是在预处理器之前。因为预处理器执行之后,Q_OBJECT 宏就不存在了。
参考《Qt信号与槽机制的基石-MOC详解》。
3.3 qrc文件
qrc文件是基于XML格式的资源系统配置文件(注意是配置文件而不是资源文件本身),其中指定了各种资源的信息。
将资源文件打包为二进制数据的流程是:写qrc文件 → 用rcc编译 → 二进制数据。
3.4 QCamera、QCameraInfo、QCameraExposure、QCameraFocus、QCameraFocusZone、QCameraViewfinder、QCameraViewfinderSettinfs
QCamera:系统摄像头设备接口。
QCameraInfo:有关相机设备的一般信息。
QCameraExposure:曝光相关相机设置界面。
QCameraFocus:用于对焦和变焦相关相机设置的界面。
QCameraFocusZone:有关用于相机自动对焦区域的信息。
QCameraViewfinder:用于显示摄像头实时预览。
QCameraViewfinderSettings:取景器设置。
3.5 QCameraImageCapture、QImageEncoderSettings、QCameraImageProcessing
QCameraImageCapture:拍摄照片。
QImageEncoderSettings:图像编码器设置。
QCameraImageProcessing:图像处理相关相机设置接口。
3.6 QMediaRecoder、QAudioEncoderSettings、QVideoEncoderSettings
QMediaRecoder:音视频录像。
QAudioEncoderSettings:音频编码器设置。
QVideoEncoderSettings:视频编码器设置。
3.7 camera主程序
新建的Camera,继承关系如下:Camera->QMainWindow->QWidget。
QMainWindow是一个为用户提供主窗口程序的类,包含一个菜单栏(menu bar)、多个工具栏(tool bars)、多个锚接部件(dock widgets)、一个状态栏(status bar)及一个中心部件(central widget),是许多应用程序的基础,如文本编辑器,图片编辑器等。
代码流程如下:
main
QApplication app--
new Camera--生成一个QtCamera实例。
->ui->setupUi--调用camera.ui生成的函数,初始化Widget Layout、Button行为等等。
->QCameraInfo::availableCameras--获取当前可用camera列表。
->setCamera--打开默认Camera,注册一系列事件、错误处理函数。
->updateCameraState
->updateRecorderState
->updateCaptureMode--使用mplane插件。
->camera.show
->app.exec
class Camera中定义了一系列Button/Action对应Signal函数:
class Camera : public QMainWindow { Q_OBJECT public: Camera(); private slots: void setCamera(const QCameraInfo &cameraInfo);--设置当前camera。 void startCamera();--Start Camera菜单点击函数。 void stopCamera();--Stop Camera菜单点击函数。 void record();--Record按钮点击函数。 void pause();--Pause按钮点击函数。 void stop();--Stop按钮点击函数。 void setMuted(bool);--Mute点击函数。 void toggleLock(); void takeImage();--Capture Photo按钮点击函数。 void displayCaptureError(int, QCameraImageCapture::Error, const QString &errorString); void configureCaptureSettings();--Image/Video菜单点击函数。Image创建class ImageSettings实例;Video创建class VideoSettings实例。 void configureVideoSettings(); void configureImageSettings(); void displayRecorderError(); void displayCameraError(); void updateCameraDevice(QAction *action); void updateCameraState(QCamera::State); void updateCaptureMode(); void updateRecorderState(QMediaRecorder::State state); void setExposureCompensation(int index);--Exposure Compensation滑动条值改变函数。 void updateRecordTime();--更新Video Record时间。 void processCapturedImage(int requestId, const QImage &img); void updateLockStatus(QCamera::LockStatus, QCamera::LockChangeReason); void displayViewfinder(); void displayCapturedImage(); void readyForCapture(bool ready); void imageSaved(int id, const QString &fileName); protected: void keyPressEvent(QKeyEvent *event) override; void keyReleaseEvent(QKeyEvent *event) override; void closeEvent(QCloseEvent *event) override; private: Ui::Camera *ui; QScopedPointer<QCamera> m_camera; QScopedPointer<QCameraImageCapture> m_imageCapture; QScopedPointer<QMediaRecorder> m_mediaRecorder; QImageEncoderSettings m_imageSettings; QAudioEncoderSettings m_audioSettings; QVideoEncoderSettings m_videoSettings; QString m_videoContainerFormat; bool m_isCapturingImage = false; bool m_applicationExiting = false; }