QML中单个Camera源绑定多个VideoOutput仅单个显示的解决方案
原因说明
Qt 5.x 版本的Qt Multimedia模块中,Camera作为视频源底层采用单消费者管线设计,同一时间仅支持绑定一个VideoOutput作为视频帧的输出sink。直接给两个VideoOutput设置同一个Camera源时,后绑定的组件会覆盖前一个的sink连接,因此只会有一个能正常显示内容。
可行实现方案
轻量纯QML方案(适配原始/预处理双显示需求)
不需要额外绑定多个VideoOutput到Camera,只需要保留一个隐藏的VideoOutput接收摄像头帧,通过ShaderEffectSource共享纹理后,分别做原始显示和预处理后显示即可,全程纯QML实现,无C++侵入。
示例代码:
import QtQuick 2.9 import QtMultimedia 5.9 Item { width: 800 height: 600 Camera { id: camera active: true } // 仅用于接收Camera帧的隐藏VideoOutput,不参与显示 VideoOutput { id: hiddenOutput source: camera visible: false autoOrientation: true } // 捕获隐藏Output的纹理,作为全局共享的视频源纹理 ShaderEffectSource { id: sharedVideoTexture sourceItem: hiddenOutput hideSource: true live: true } // 左侧显示原始视频 Rectangle { id: originalDisplay width: 380 height: 580 anchors.left: parent.left anchors.top: parent.top anchors.margins: 10 ShaderEffect { anchors.fill: parent texture: sharedVideoTexture vertexShader: " uniform highp mat4 qt_Matrix; attribute highp vec4 qt_Vertex; attribute highp vec2 qt_MultiTexCoord0; varying highp vec2 texCoord; void main() { texCoord = qt_MultiTexCoord0; gl_Position = qt_Matrix * qt_Vertex; } " fragmentShader: " varying highp vec2 texCoord; uniform sampler2D texture; void main() { gl_FragColor = texture2D(texture, texCoord); } " } } // 右侧显示预处理后视频,此处以灰度化为例 Rectangle { id: processedDisplay width: 380 height: 580 anchors.right: parent.right anchors.top: parent.top anchors.margins: 10 ShaderEffect { anchors.fill: parent texture: sharedVideoTexture vertexShader: " uniform highp mat4 qt_Matrix; attribute highp vec4 qt_Vertex; attribute highp vec2 qt_MultiTexCoord0; varying highp vec2 texCoord; void main() { texCoord = qt_MultiTexCoord0; gl_Position = qt_Matrix * qt_Vertex; } " fragmentShader: " varying highp vec2 texCoord; uniform sampler2D texture; void main() { vec4 rawColor = texture2D(texture, texCoord); // 自定义预处理逻辑可替换此处代码 float gray = dot(rawColor.rgb, vec3(0.299, 0.587, 0.114)); gl_FragColor = vec4(gray, gray, gray, 1.0); } " } } }
需要多独立VideoOutput的场景
如果必须使用两个独立的VideoOutput组件(例如有其他逻辑绑定了VideoOutput的接口),则需要自定义继承自QAbstractVideoSurface的C++中介类:
- 将
Camera的输出绑定到这个中介surface,而非直接绑定到VideoOutput - 中介类收到摄像头帧后,将帧包装为可复用的纹理或数据,分发给两个下游的
VideoOutput对应的sink - 该方案需要C++扩展开发,性能开销略高于纯QML纹理共享方案
注意事项
- 上述纯QML方案适配Qt 5.9及以上版本,利用GPU纹理复用,避免了重复的帧拷贝和摄像头管线重复初始化,性能最优
- 预处理逻辑完全在Shader中实现,可灵活替换为任意图像算法,不需要修改底层管线
内容的提问来源于stack exchange,提问作者LeXela-ED
相关产品推荐
相关产品推荐

