资讯动态

Qt Onboard开发套件实战(3): 多媒体与摄像头集成

发布时间:2026/10/23 4:57:17 来源:尧图企业网站定制
前言边缘AI应用往往离不开多媒体能力像摄像头采集图像、麦克风采集语音、扬声器播放TTS结果。在FactoryPulse方案中Qt Onboard针对高通跃龙IQ-9075做了多项多媒体定制优化音频用ALSA替换PulseAudio支持USB音频驱动降低资源占用视频增加GStreamer插件支持QML中的VideoOutput集成摄像头新增定制化USB摄像头驱动满足Edge Impulse平台要求本文带你实战玩转Qt Onboard的多媒体子系统从视频播放、音频播放到摄像头采集全部走一遍。1、多媒体子系统架构先看整体架构图理清各层关系架构图说明Qt应用层Qt Multimedia模块MediaPlayer、VideoOutput、Camera多媒体框架层GStreamer 1.x视频/流媒体 ALSA音频替换PulseAudio内核驱动与硬件层V4L2子系统、USB摄像头驱动、CSI接口、VPU硬件编解码器 ALSA SoC驱动、USB音频、I2S/PCM接口、Codec芯片关键定制点FactoryPulse镜像中用ALSA直接替换了PulseAudio原因有两个一是嵌入式场景下资源更紧张ALSA比PulseAudio更轻量二是USB音频设备在ALSA下延迟更低、更稳定。2、多媒体处理流程图下面这张Mermaid图展示了视频采集、播放和音频处理的完整管线媒体播放 Media Playback音频管线 Audio Pipeline视频管线 Video PipelineUSB/CSI 摄像头V4L2 子系统GStreamer v4l2src视频处理ivapostproc硬件解码 VPUQt VideoOutputHDMI 显示输出USB 麦克风ALSA 驱动GStreamer alsasrc音频处理Qt AudioInput应用层处理Qt AudioOutputGStreamer alsasinkALSA 驱动USB 扬声器/耳机Qt MediaPlayerGStreamer playbindemux 解复用视频解码 VPU音频解码3、实战视频播放GStreamer Qt Multimedia3.1 环境确认首先登录到IQ-9075开发板确认GStreamer环境sshroot设备IP# 检查GStreamer版本gst-launch-1.0--version# 输出: gst-launch-1.0 version 1.22.x# 检查可用的插件gst-inspect-1.0|grep-Ev4l2|alsa|vpudec|qtwidget# 检查Qt Multimedia是否可用ls/usr/lib/qt6/plugins/multimedia/ 你应该能看到gstreamermediaplugin.so这是Qt Multimedia的GStreamer后端插件。3.2 命令行测试GStreamer在写代码之前先用命令行测试GStreamer管线是否正常# 测试视频测试源 显示gst-launch-1.0 videotestsrc!videoconvert!qtv4l2sink# 测试本地视频文件播放如果有的话gst-launch-1.0 filesrclocation/usr/share/sample.mp4!\qtdemux!h264parse!vpudec!videoconvert!qtv4l2sink# 测试音频播放gst-launch-1.0 audiotestsrc!audioconvert!alsasink如果能看到测试视频画面或听到测试音频说明GStreamer环境正常。3.3 Qt Quick视频播放器实战创建一个Qt Quick项目实现一个简单的视频播放器。步骤1创建项目文件 → 新建 → Qt Quick Application (Empty) 项目名称VideoPlayerDemo步骤2修改CMakeLists.txt添加 Multimedia 模块依赖cmake_minimum_required(VERSION 3.16) project(VideoPlayerDemo VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 6.11 REQUIRED COMPONENTS Quick Multimedia) qt_standard_project_setup(REQUIRES 6.5) qt_add_executable(appVideoPlayerDemo main.cpp ) qt_add_qml_module(appVideoPlayerDemo URI VideoPlayerDemo VERSION 1.0 QML_FILES Main.qml ) target_link_libraries(appVideoPlayerDemo PRIVATE Qt6::Quick Qt6::Multimedia ) include(GNUInstallDirs) install(TARGETS appVideoPlayerDemo BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )步骤3编写Main.qmlimport QtQuick import QtQuick.Window import QtQuick.Controls import QtQuick.Layouts import QtMultimedia Window { width: 800 height: 500 visible: true title: Qt Onboard 视频播放器 color: #0F172A // 媒体播放器 MediaPlayer { id: mediaPlayer source: file:///usr/share/sample.mp4 videoOutput: videoOutput onError: { console.log(播放错误:, errorString) } } ColumnLayout { anchors.fill: parent spacing: 0 // 视频输出区域 VideoOutput { id: videoOutput Layout.fillWidth: true Layout.fillHeight: true fillMode: VideoOutput.PreserveAspectFit } // 控制栏 Rectangle { Layout.fillWidth: true Layout.preferredHeight: 60 color: #1E293B border.color: #334155 RowLayout { anchors.fill: parent anchors.leftMargin: 15 anchors.rightMargin: 15 spacing: 12 // 播放/暂停按钮 Button { text: mediaPlayer.playbackState MediaPlayer.PlayingState ? ⏸ 暂停 : ▶ 播放 Layout.preferredWidth: 100 Layout.preferredHeight: 36 onClicked: { if (mediaPlayer.playbackState MediaPlayer.PlayingState) mediaPlayer.pause() else mediaPlayer.play() } } // 进度条 Slider { id: progressBar Layout.fillWidth: true from: 0 to: mediaPlayer.duration value: mediaPlayer.position onMoved: mediaPlayer.seek(value) } // 时间显示 Label { text: formatTime(mediaPlayer.position) / formatTime(mediaPlayer.duration) color: #94A3B8 Layout.preferredWidth: 110 font.pixelSize: 12 } // 音量控制 Slider { Layout.preferredWidth: 100 from: 0 to: 100 value: mediaPlayer.volume * 100 onMoved: mediaPlayer.volume value / 100 } Label { text: font.pixelSize: 16 } } } } function formatTime(ms) { let totalSec Math.floor(ms / 1000); let min Math.floor(totalSec / 60); let sec totalSec % 60; return min.toString().padStart(2, 0) : sec.toString().padStart(2, 0); } Component.onCompleted: { console.log(视频播放器就绪); // 自动播放 mediaPlayer.play(); } }步骤4准备测试视频将一个H.264编码的MP4视频文件复制到开发板# 在电脑上scptest_video.mp4 root192.168.1.100:/usr/share/sample.mp4⚠️注意IQ-9075支持硬件解码H.264/H.265等格式建议使用硬件支持的编码格式以获得最佳性能。步骤5编译部署运行选择QtOnboard Kit点击运行。你应该能在HDMI显示器上看到视频播放界面支持播放/暂停、进度条拖拽、音量调节。观察在应用输出面板查看播放状态如果GStreamer管线正常建立你会看到类似Pipeline is PREROLLED的日志。4、实战音频播放与录制ALSA4.1 为什么用ALSA而不是PulseAudio在FactoryPulse定制镜像中Qt Multimedia的音频后端从PulseAudio切换到了ALSA原因如下特性PulseAudioALSA (直接使用)资源占用较高需要守护进程低直接操作硬件延迟较高更低混音能力强多应用同时播放有限硬件混音适用场景桌面Linux嵌入式/工业场景对于嵌入式边缘AI应用低延迟、低资源占用比多应用混音更重要所以选择ALSA更合适。4.2 命令行测试ALSA音频# 查看音频设备aplay-l# 输出类似:# card 0: audiocodec [audiocodec], device 0: ...# card 1: USB [USB Audio Device], device 0: USB Audio ...# 查看录音设备arecord-l# 播放测试音频aplay /usr/share/sounds/alsa/Front_Left.wav# 录音测试10秒arecord-Dplughw:1,0-d10-fS16_LE-r44100-c2test.wav# 播放录制的音频aplay test.wavUSB音频设备USB麦克风和USB扬声器通常会识别为card 1而板载Codec是card 0。使用plughw:1,0指定USB设备。4.3 Qt Quick音频播放器import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtMultimedia Window { width: 400 height: 300 visible: true title: ALSA 音频播放器 color: #0F172A MediaPlayer { id: audioPlayer source: file:///usr/share/sounds/alsa/Front_Left.wav audioOutput: AudioOutput {} } ColumnLayout { anchors.centerIn: parent spacing: 20 Text { text: ALSA 音频测试 font.pixelSize: 22 color: #F8FAFC Layout.alignment: Qt.AlignHCenter } Row { Layout.alignment: Qt.AlignHCenter spacing: 10 Button { text: ▶ 播放 onClicked: audioPlayer.play() } Button { text: ⏸ 暂停 onClicked: audioPlayer.pause() } Button { text: ⏹ 停止 onClicked: audioPlayer.stop() } } Text { text: 状态: (audioPlayer.playbackState MediaPlayer.PlayingState ? 播放中 : 已停止) color: #94A3B8 Layout.alignment: Qt.AlignHCenter } } }5、实战USB摄像头采集5.1 确认摄像头设备将USB摄像头插入IQ-9075的USB 3.0接口然后检查设备# 检查V4L2设备ls/dev/video*# 输出: /dev/video0 /dev/video1# 查看摄像头能力v4l2-ctl--device/dev/video0--all# 列出支持的格式和分辨率v4l2-ctl--device/dev/video0 --list-formats-extFactoryPulse定制原文提到按照Edge Impulse平台的要求增加了适用于定制化USB摄像头的全新驱动程序。这意味着Qt Onboard的FactoryPulse镜像中内置了特定USB摄像头的驱动支持确保与Edge Impulse的AI模型兼容。5.2 命令行测试摄像头# 使用GStreamer采集摄像头画面并显示gst-launch-1.0 v4l2srcdevice/dev/video0!\videoconvert!\video/x-raw,width640,height480!\qtv4l2sink# 录制摄像头视频gst-launch-1.0 v4l2srcdevice/dev/video0 num-buffers300!\videoconvert!x264enc!mp4mux!\filesinklocationcamera_test.mp45.3 Qt Quick摄像头预览应用import QtQuick import QtQuick.Window import QtQuick.Controls import QtQuick.Layouts import QtMultimedia Window { width: 720 height: 560 visible: true title: USB 摄像头采集 color: #0F172A // 摄像头 Camera { id: camera cameraDevice: MediaDevices.defaultVideoInput } // 捕获会话 CaptureSession { id: captureSession camera: camera videoOutput: videoOutput } ColumnLayout { anchors.fill: parent spacing: 10 // 视频预览 VideoOutput { id: videoOutput Layout.fillWidth: true Layout.preferredHeight: 420 fillMode: VideoOutput.PreserveAspectFit } // 控制栏 RowLayout { Layout.alignment: Qt.AlignHCenter spacing: 10 Button { text: camera.active ? ⏹ 停止 : ▶ 开始预览 onClicked: camera.start() } Button { text: 拍照 onClicked: { // 捕获静态图片 let imgCapture imageCapture imgCapture.capture() } } ComboBox { id: resolutionCombo Layout.preferredWidth: 150 model: [640x480, 1280x720, 1920x1080] onActivated: { let sizes [640x480, 1280x720, 1920x1080] let res sizes[currentIndex].split(x) camera.setResolution(Qt.size(parseInt(res[0]), parseInt(res[1]))) } } } // 摄像头信息 Text { text: 设备: camera.cameraDevice.description | 分辨率: camera.resolution.width x camera.resolution.height color: #94A3B8 font.pixelSize: 11 Layout.alignment: Qt.AlignHCenter } } ImageCapture { id: imageCapture } Component.onCompleted: { console.log(摄像头设备列表:, MediaDevices.videoInputs.length) camera.start() } }性能优化提示在IQ-9075上摄像头采集建议使用硬件加速路径。GStreamer的ivapostproc和ivacompositor插件可以利用硬件进行颜色转换和缩放降低CPU占用。6、实战进阶音视频同步录制做一个更完整的例子同时采集摄像头画面和麦克风声音录制为MP4文件。关键代码片段// main.cpp - 主程序#includeQGuiApplication#includeQQmlApplicationEngine#includeQtMultimediaintmain(intargc,char*argv[]){QGuiApplicationapp(argc,argv);QQmlApplicationEngine engine;qmlRegisterTypeQCamera(QtMultimedia,6,0,Camera);qmlRegisterTypeQMediaCaptureSession(QtMultimedia,6,0,CaptureSession);qmlRegisterTypeQImageCapture(QtMultimedia,6,0,ImageCapture);qmlRegisterTypeQMediaRecorder(QtMultimedia,6,0,MediaRecorder);qmlRegisterTypeQAudioInput(QtMultimedia,6,0,AudioInput);engine.load(QUrl(QStringLiteral(qrc:/Main.qml)));returnapp.exec();}// Main.qml 中的录制部分 MediaRecorder { id: recorder captureSession: captureSession outputLocation: file:///tmp/recording.mp4 quality: MediaRecorder.HighQuality } Button { text: recorder.recorderState MediaRecorder.RecordingState ? ⏹ 停止录制 : ⏺ 开始录制 onClicked: { if (recorder.recorderState MediaRecorder.RecordingState) recorder.stop() else recorder.record() } }7、常见问题与排错Q1VideoOutput黑屏没有画面排查步骤检查Qt Multimedia插件是否存在ls /usr/lib/qt6/plugins/multimedia/检查GStreamer Qt插件gst-inspect-1.0 qt用命令行测试GStreamer管线是否正常检查环境变量exportQT_QPA_PLATFORMeglfsexportGST_DEBUG2# 查看GStreamer调试信息Q2USB摄像头不识别排查步骤检查USB设备是否枚举lsusb检查V4L2设备ls /dev/video*查看内核日志dmesg | grep -i usb确认摄像头驱动是否加载lsmod | grep uvcvideo⚠️FactoryPulse镜像说明如果你的摄像头是特殊型号可能需要在Yocto中添加对应的驱动。但Qt Onboard的FactoryPulse定制镜像已经包含了常用USB摄像头的驱动。Q3ALSA音频播放没有声音排查步骤确认音频设备aplay -l指定设备播放aplay -D plughw:1,0 test.wav检查音量alsamixer确保没有静音查看Qt Multimedia音频后端qDebug()QMediaDevices::audioOutputs();Q4视频CPU占用过高优化方法使用硬件解码确保使用vpudec而不是软件解码使用零拷贝尽量减少内存拷贝降低分辨率/帧率如果不需要1080p用720p使用GStreamer硬件加速插件ivapostproc、ivacompositor8、性能对比与最佳实践8.1 视频播放性能对比IQ-9075上1080p H.264解码方式CPU占用帧率延迟软件解码 (avdec_h264)~85%~25fps高硬件解码 (vpudec)~15%60fps低✅结论一定要使用硬件解码插件vpudec性能差距非常大8.2 音频延迟对比音频后端典型延迟资源占用PulseAudio50-100ms较高ALSA (直接)10-30ms低✅结论对实时性要求高的场景如语音交互、AI对话ALSA直接访问是更好的选择。8.3 最佳实践总结视频优先用硬件加速VPU解码、IVA后处理音频优先用ALSA嵌入式场景延迟更低摄像头用V4L2标准接口兼容性好资源监控使用top、gst-top监控性能分辨率按需选择不要盲目追求最高分辨率9、总结本篇我们深入实战了Qt Onboard的多媒体子系统核心要点回顾功能技术栈关键组件视频播放GStreamer VPUvpudec、ivapostproc音频播放ALSAalsasink、USB Audio摄像头采集V4L2 GStreamerv4l2src、uvcvideoQt集成Qt MultimediaMediaPlayer、Camera、VideoOutput本篇核心收获✅ 理解多媒体子系统的三层架构✅ 掌握GStreamer命令行调试技巧✅ 学会使用Qt Multimedia实现视频播放✅ 理解ALSA替换PulseAudio的原因与优势✅ 掌握USB摄像头采集与预览方法✅ 了解硬件加速的重要性与性能优化方向在下一篇也是本系列的最后一篇中我们将进入边缘AI应用的实战讲解如何在Qt Onboard中集成Genie大模型库和ONNX运行时构建完整的FactoryPulse式边缘AI应用这也是Qt Onboard最核心的价值所在。系列索引一环境搭建全攻略 · 二Qt Creator交叉编译与一键部署实战 · 三多媒体与摄像头集成· 四边缘AI应用如果本文对你有帮助欢迎点赞、收藏、关注有问题也欢迎在评论区交流~

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑