如何从QCamera/QVideoWidget获取帧字节数组?present方法未调用排查
问题解答
1. present方法未被调用的排查与修复
(1)未将自定义视频表面关联到QCamera
摄像头不会自动把帧投递到你的自定义表面,必须显式将QMyAbstractVideoSurface实例绑定到QCamera:
QCamera *camera = new QCamera(this); QMyAbstractVideoSurface *mySurface = new QMyAbstractVideoSurface(this); camera->setVideoSurface(mySurface); camera->start();
(2)start方法未做格式校验
你的start方法直接调用父类实现,但未先确认当前格式是否被表面支持。若格式不匹配,表面启动失败,present自然不会被触发。修改start方法:
bool QMyAbstractVideoSurface::start(const QVideoSurfaceFormat& format) { if (supportedPixelFormats(format.handleType()).contains(format.pixelFormat())) { return QAbstractVideoSurface::start(format); } return false; }
(3)QCamera未正确初始化或启动
确保已选择有效摄像头设备,且调用了camera->start()。若摄像头因权限、设备占用等原因启动失败,不会有帧投递。
(4)忽略视频缓冲的HandleType
你的supportedPixelFormats方法忽略了handleType参数,部分平台的摄像头可能使用特定类型缓冲(如纹理缓冲),若表面未对应支持,也会导致无法接收帧。可针对不同类型返回对应格式:
QList<QVideoFrame::PixelFormat> QMyAbstractVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const { if (handleType == QAbstractVideoBuffer::NoHandle) { return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_ARGB32 << QVideoFrame::Format_RGB24 << QVideoFrame::Format_YUV420P; // 按需添加其他格式 } else { return {}; // 不支持的handleType返回空列表 } }
2. 与QCameraViewfinder的配合方式
QCameraViewfinder自带内部视频表面用于显示画面,若要同时显示画面并处理帧,有两种常用方案:
方案一:自定义表面处理后转发给Viewfinder
- 保存Viewfinder的内部表面
- 在自定义
present方法中处理帧后,将帧转发给Viewfinder表面
示例代码:
// 自定义表面类添加成员变量保存Viewfinder表面 class QMyAbstractVideoSurface : public QAbstractVideoSurface { Q_OBJECT private: QAbstractVideoSurface *m_viewfinderSurface = nullptr; public: void setViewfinderSurface(QAbstractVideoSurface *surface) { m_viewfinderSurface = surface; } // 其他方法... }; // present方法处理并转发帧 bool QMyAbstractVideoSurface::present(const QVideoFrame& frame) { // 处理帧逻辑(如编码、TCP传输) QVideoFrame cloneFrame(frame); if (cloneFrame.map(QAbstractVideoBuffer::ReadOnly)) { QByteArray data((char*)cloneFrame.bits(), cloneFrame.mappedBytes()); // 这里添加数据处理、TCP发送逻辑 cloneFrame.unmap(); } // 转发给Viewfinder显示 if (m_viewfinderSurface) { m_viewfinderSurface->present(frame); } return true; } // 初始化关联 QCameraViewfinder *viewfinder = new QCameraViewfinder(this); QMyAbstractVideoSurface *mySurface = new QMyAbstractVideoSurface(this); mySurface->setViewfinderSurface(viewfinder->videoSurface()); QCamera *camera = new QCamera(this); camera->setVideoSurface(mySurface); camera->start();
方案二:使用视频过滤器拦截帧
通过QAbstractVideoFilter拦截摄像头帧进行处理,Viewfinder负责显示,这种方式更简洁:
// 自定义视频过滤器 class MyVideoFilter : public QAbstractVideoFilter { Q_OBJECT public: QVideoFilterRunnable *createFilterRunnable() override { return new MyFilterRunnable(this); } }; class MyFilterRunnable : public QVideoFilterRunnable { public: QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) override { // 处理帧逻辑 if (input->map(QAbstractVideoBuffer::ReadOnly)) { QByteArray data((char*)input->bits(), input->mappedBytes()); // 添加数据处理、TCP发送逻辑 input->unmap(); } return *input; // 返回原帧给Viewfinder显示 } }; // 使用方式 QCamera *camera = new QCamera(this); QCameraViewfinder *viewfinder = new QCameraViewfinder(this); MyVideoFilter *filter = new MyVideoFilter(this); camera->setViewfinder(viewfinder); camera->setVideoFilter(filter); camera->start();
内容的提问来源于stack exchange,提问作者zabitstack
相关产品推荐
相关产品推荐

