Qt从5.0开始支持android摄像头,但是目前还没有做到统一完全跨平台API。还需要根据不同的平台系统来处理。这是因为Qt中QImage支持格式不全,现在不支持YUV格式。
Qt中捕获视频流用两种方式:
一、用QCamera::setViewfinder(QAbstractVideoSurface *surface)
先从QAbstractVideoSurface派生子类:
class MyVideoSurface : public QAbstractVideoSurface
{
QList<QVideoFrame::PixelFormat> supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const
{
Q_UNUSED(handleType);
// 返回你将处理的格式
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_RGB32 //windows 平台、linux 平台默认都支持 RGB32 格式
<< QVideoFrame::Format_RGB24
<< QVideoFrame::Format_ARGB32
<< QVideoFrame::Format_ARGB32_Premultiplied
<< QVideoFrame::Format_RGB565
<< QVideoFrame::Format_RGB555
//android支持的格式
<< QVideoFrame::Format_NV21
<< QVideoFrame::Format_YV12
<< QVideoFrame::Format_RGB565
<< QVideoFrame::Format_YUV420P
<< QVideoFrame::Format_YUYV
<< QVideoFrame::Format_AYUV444
<< QVideoFrame::Format_Jpeg
;
}
bool present(const QVideoFrame &frame)
{
Q_UNUSED(frame); // 处理捕获的帧
return true;
}
};
MyVideoSurface surface;
QCamera m_Camera;
m_Camera.setCaptureMode(QCamera::CaptureMode::CaptureVideo);
m_Camera.setViewfinder(&surface);
二、用QVideoProbe
camera = new QCamera;
viewfinder = new QCameraViewfinder();
camera->setViewfinder(viewfinder);
camera->setCaptureMode(QCamera::CaptureVideo);
videoProbe = new QVideoProbe(this);
if (videoProbe->setSource(camera)) {
// Probing succeeded, videoProbe->isValid() should be true.
connect(videoProbe, SIGNAL(videoFrameProbed(QVideoFrame)),
this, SLOT(detectBarcodes(QVideoFrame)));
}
camera->start();
// Viewfinder frames should now also be emitted by
// the video probe, even in still image capture mode.
// Another alternative is to install the probe on a
// QMediaRecorder connected to the camera to get the
// recorded frames, if they are different from the
// viewfinder frames.
windows支持格式为RGB24、RGB32;android支持格式为NV21
下面我对捕获和显示进行了封装:
CaptureVideoFrame.h
/*
* 作者:康林(msn、email: kl222@126.com)
*
* 从摄像头(QCarmera)或者(Player)中捕获视频帧。
* 注意:android后景摄像头捕获的视频翻转-90度,前景摄像头翻转90度。
* 用法:
* QCamera m_Camera;
* m_Camera.setCaptureMode(QCamera::CaptureVideo);
* CCaptureVideoFrame videoFrame;
* videoFrame.setSource(&m_Camera);
* 注册SLOT:
* connect(&videoFrame, SIGNAL(CaptureFrame(const QVideoFrame&)),
* SLOT(CaptureVideoFrame(const QVideoFrame&)));
* 在SLOT 中 CaptureVideoFrame(const QVideoFrame&) 处理捕获到的视频帧。
*
* 示例代码:
* QList<QByteArray> device = QCamera::availableDevices();
* QList<QByteArray>::iterator it;
* for(it = device.begin(); it != device.end(); it++)
* {
* qDebug("Camera:%s", qPrintable(QCamera::deviceDescription(*it)));
* }
*
* QCamera camera(QCamera::availableDevices().at(1));
* camera.setCaptureMode(QCamera::CaptureVideo);
* CFrmPlayer player;
* CCaptureVideoFrame captureVideoFrame;
* if(captureVideoFrame.setSource(&camera))
* {
* qDebug("probe.setSource is ok");
* player.connect(&captureVideoFrame, SIGNAL(CaptureFrame(QVideoFrame)),
* SLOT(present(QVideoFrame)));
* }
*
* player.show();
* player.activateWindow();
* camera.start();
*/
#ifndef CAPTUREVIDEOFRAME_H
#define CAPTUREVIDEOFRAME_H
#include <QAbstractVideoSurface>
#include <QCamera>
class CCaptureVideoFrame : public QAbstractVideoSurface
{
Q_OBJECT
public:
explicit CCaptureVideoFrame(QObject *parent = 0);
virtual QList<QVideoFrame::PixelFormat> supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const;
bool setSource(QCamera *pCamera);
signals:
//视频帧捕获信号
void CaptureFrame(const QVideoFrame &frame);
private slots:
virtual bool present(const QVideoFrame &frame);
};
#endif // CAPTUREVIDEOFRAME_H
CaptureVideoFrame.cpp
/** 作者:康林(msn、email: kl222@126.com)*/
#include "CaptureVideoFrame.h"
#include <QCamera>
CCaptureVideoFrame::CCaptureVideoFrame(QObject *parent) :
QAbstractVideoSurface(parent)
{
}
QList<QVideoFrame::PixelFormat> CCaptureVideoFrame::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
{
Q_UNUSED(handleType);
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_RGB32 //windows 平台、linux 平台默认都支持 RGB32 格式
<< QVideoFrame::Format_RGB24
<< QVideoFrame::Format_ARGB32
<< QVideoFrame::Format_ARGB32_Premultiplied
<< QVideoFrame::Format_RGB565
<< QVideoFrame::Format_RGB555
//android支持的格式
<< QVideoFrame::Format_NV21
<< QVideoFrame::Format_YV12
<< QVideoFrame::Format_RGB565
<< QVideoFrame::Format_YUV420P
<< QVideoFrame::Format_YUYV
<< QVideoFrame::Format_AYUV444
<< QVideoFrame::Format_Jpeg
;
}
//捕获视频帧。windows下格式是RGB32;android下是NV21bool
CCaptureVideoFrame::present(const QVideoFrame &frame){
qDebug("CCaptureVideoFrame::present format:%d", frame.pixelFormat());
emit CaptureFrame(frame);
return true;
}
//根据不同的平台,设置捕获方式bool
CCaptureVideoFrame::setSource(QCamera *pCamera){
bool ret = true;
//捕获视频
pCamera->setViewfinder(this);
return ret;
}
源码:https://github.com/KangLin/FaceRecognizer/blob/master/Src/CameraQtCaptureVideoFrame.h
或者:https://github.com/KangLin/RabbitIm/tree/master/Media/Camera
QT对摄像头的支持存在的一些问题:
QT得到到捕获帧相关的参数
QT 在windows、linux下捕获视频只有5帧/秒左右,在我的电脑上用时 240ms 左右。在Android手机上可达到15帧/s(60ms左右)。
QT 在 windows、linux下多个摄像头切换正常,但在 android 手机上,前后摄像头不能切换。代码如下:
void CFrmVideo::on_cmbCamera_currentIndexChanged(int index)
{
LOG_MODEL_DEBUG("Video", "CFrmVideo::on_cmbCamera_currentIndexChanged");
m_CameraPostition = QCamera::availableDevices().at(index);
OpenCamera();
LOG_MODEL_DEBUG("Video", "CFrmVideo::on_cmbCamera_currentIndexChanged end");
}
int CFrmVideo::OpenCamera()
{
if(!m_pCall)
{
LOG_MODEL_ERROR("Video", "CFrmVideo::OpenCamera m_pCall is null");
return -1;
}
if(m_pCamera)
{
CloseCamera();
}
m_pCamera = new QCamera(m_CameraPostition);
if(!m_pCamera)
{
LOG_MODEL_WARNING("Video", "Open carmera fail");
return -1;
}
m_pCamera->setCaptureMode(QCamera::CaptureVideo);
m_CaptureVideoFrame.setSource(m_pCamera);
//m_pCamera->load();
m_pCamera->start();
return 0;
}
int CFrmVideo::CloseCamera()
{
if(m_pCamera)
{
m_pCamera->stop();
//m_pCamera->unload();
delete m_pCamera;
m_pCamera = NULL;
}
return 0;
}