折腾了几天,终于有结果了,Qt对android开发的支持还可以,就是Qt进行android开发没有anroid studio主流,用Qt进行android开发,基本都是在写C++ ,还蛮棒的。

网上找了好一会才找到参考文献5,问题得到解决。

文件目录如下:

完整代码如下:

camera_widgets_display.pro

QT       += core gui multimedia multimediawidgetsgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use# any Qt feature that has been marked deprecated (the exact warnings# depend on your compiler). Please consult the documentation of the# deprecated API in order to know how to port your code away from it.DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs.# In order to do so, uncomment the following line.# You can also select to disable deprecated APIs only up to a certain version of Qt.#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \    main.cpp \    myvideosurface.cpp \    widget.cppHEADERS += \    myvideosurface.h \    widget.hFORMS += \    widget.ui# Default rules for deployment.qnx: target.path = /tmp/$${TARGET}/binelse: unix:!android: target.path = /opt/$${TARGET}/bin!isEmpty(target.path): INSTALLS += target

myvideosurface.h

#ifndef MYVIDEOSURFACE_H#define MYVIDEOSURFACE_H#include #include #include #include class MyVideoSurface : public QAbstractVideoSurface{    Q_OBJECTpublic:    MyVideoSurface();    QList supportedPixelFormats(QAbstractVideoBuffer::HandleType type = QAbstractVideoBuffer::NoHandle) const Q_DECL_OVERRIDE;    bool isFormatSupported(const QVideoSurfaceFormat &) const Q_DECL_OVERRIDE;    //将视频流中像素格式转换成格式对等的图片格式,若无对等的格式,返回QImage::Format_Invalid    bool start(const QVideoSurfaceFormat &) Q_DECL_OVERRIDE;                       //只要摄像头开,就会调用    bool present(const QVideoFrame &) Q_DECL_OVERRIDE;                             //每一帧画面将回到这里处理    void stop() Q_DECL_OVERRIDE;signals:    void frameAvailable(QVideoFrame cloneFrame);};#endif // MYVIDEOSURFACE_H

widget.h

#ifndef WIDGET_H#define WIDGET_H#include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACEnamespace Ui { class Widget; }QT_END_NAMESPACEclass Widget : public QWidget{    Q_OBJECTpublic:    Widget(QWidget *parent = nullptr);    ~Widget();void NV21_T_RGB(unsigned int width , unsigned int height , unsigned char *yuyv , unsigned char *rgb);private:    Ui::Widget *ui;    QCamera *camera;    QCameraImageCapture *capture;    QCameraViewfinder *viewfinder;    MyVideoSurface *mySurface;    QImage videoImg;public slots:    void displayImage(int ,QImage image);    void rcvFrame(QVideoFrame);                            //接收图像帧数据    void paintEvent(QPaintEvent *event);private slots:    void on_pushButton_clicked();};#endif // WIDGET_H

main.cpp

#include "widget.h"#include int main(int argc, char *argv[]){    QApplication a(argc, argv);    Widget w;    w.show();    return a.exec();}

myvideosurface.cpp

#include "myvideosurface.h"MyVideoSurface::MyVideoSurface(){}//支持的像素格式QList MyVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const{    if(handleType == QAbstractVideoBuffer::NoHandle){        return QList() << QVideoFrame::Format_RGB32                                                 << QVideoFrame::Format_ARGB32                                                 << QVideoFrame::Format_ARGB32_Premultiplied                                                 << QVideoFrame::Format_RGB565                                                 << QVideoFrame::Format_NV21                                                 << QVideoFrame::Format_RGB555;    }    else {        return QList();    }}//将视频流中像素格式转换成格式对等的图片格式,若无对等的格式,返回QImage::Format_Invalidbool MyVideoSurface::isFormatSupported(const QVideoSurfaceFormat &videoformat) const{    //imageFormatFromPixelFormat()-----返回与视频帧像素格式等效的图像格式    //pixelFormat()-----返回视频流中帧的像素格式    return QVideoFrame::imageFormatFromPixelFormat(videoformat.pixelFormat()) != QImage::Format_Invalid;}//这些虚函数,会自动被调用,start检测图像是否可以对等转换,每一帧有没有bool MyVideoSurface::start(const QVideoSurfaceFormat &videoformat){//    qDebug() << QVideoFrame::imageFormatFromPixelFormat(videoformat.pixelFormat());              //格式是RGB32//    if(QVideoFrame::imageFormatFromPixelFormat(videoformat.pixelFormat()) != QImage::Format_Invalid && !videoformat.frameSize().isEmpty()){//        QAbstractVideoSurface::start(videoformat);//        return true;//    }    QAbstractVideoSurface::start(videoformat);    return false;}bool MyVideoSurface::present(const QVideoFrame &frame){//    qDebug() << frame.size();    if (frame.isValid()){        QVideoFrame cloneFrame(frame);                                      //每一帧视频都会进入present中,内部机制        emit frameAvailable(cloneFrame);                                    //直接把视频帧发送出去        return true;    }    stop();    return false;}void MyVideoSurface::stop(){    QAbstractVideoSurface::stop();}

widget.cpp

#include "widget.h"#include "ui_widget.h"Widget::Widget(QWidget *parent)    : QWidget(parent)    , ui(new Ui::Widget){    ui->setupUi(this);    camera=new QCamera;//摄像头    capture = new QCameraImageCapture(camera);    viewfinder=new QCameraViewfinder(this);//取景器    QObject::connect(capture, SIGNAL(imageCaptured(int,QImage)), this, SLOT(displayImage(int,QImage)));    camera->setCaptureMode(QCamera::CaptureStillImage);//    camera->setViewfinder(viewfinder);    mySurface = new MyVideoSurface();    camera->setViewfinder(mySurface);    //处理myvideosurface中每一帧视频    connect(mySurface, SIGNAL(frameAvailable(QVideoFrame)), this, SLOT(rcvFrame(QVideoFrame)), Qt::DirectConnection);    camera->start(); //启动摄像头    //获取摄像头支持的分辨率、帧率等参数//    QList ViewSets = camera->supportedViewfinderSettings();//    int i = 0;//    qDebug() << "viewfinderResolutions sizes.len = " << ViewSets.length();//    foreach (QCameraViewfinderSettings ViewSet, ViewSets) {//        qDebug() << i++ <<" max rate = " << ViewSet.maximumFrameRate() << "min rate = "<< ViewSet.minimumFrameRate() << "resolution "<setViewfinderSettings(camerasettings);}Widget::~Widget(){    delete ui;}void Widget::displayImage(int ,QImage image){    image=image.convertToFormat(QImage::Format_RGB888);    ui->label->setPixmap(QPixmap::fromImage(image));    qDebug() << image.size();}void Widget::rcvFrame(QVideoFrame m_currentFrame){    qDebug() << "received" << m_currentFrame.size();    m_currentFrame.map(QAbstractVideoBuffer::ReadOnly);//    unsigned char *pix_ptr = m_currentFrame.bits();//    qDebug("%d %d %d %d", *pix_ptr, *(pix_ptr+1), *(pix_ptr+2), *(pix_ptr+3));        //将视频帧转化成QImage,devicePixelRatio设备像素比,bytesPerLine一行的像素字节(1280*4=5120)    videoImg = QImage(m_currentFrame.width(), m_currentFrame.height(), QImage::Format_RGB888);    NV21_T_RGB(m_currentFrame.width(), m_currentFrame.height(), m_currentFrame.bits(), videoImg.bits());//    videoImg =  QImage(m_currentFrame.bits(),//                   m_currentFrame.width(),//                   m_currentFrame.height(),//                   QImage::Format_Grayscale8).copy();       //这里要做一个copy,因为char* pdata在emit后释放了//    videoImg = videoImg.mirrored(true, false);                          //水平翻转,原始图片是反的//    qDebug() <<  "image" << videoImg;  //可以看看输出啥东西//    QString currentTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");//    QString savefile = QString("E:/study/QT/opencamera/opencamera/%1.jpg").arg(currentTime);//    qDebug() << videoImg.save(savefile);    m_currentFrame.unmap();                                         //释放map拷贝的内存    QCameraInfo cameraInfo(*camera); // needed to get the camera sensor position and orientation//    // Get the current display orientation//    const QScreen *screen = QGuiApplication::primaryScreen();//    const int screenAngle = screen->angleBetween(screen->nativeOrientation(), screen->orientation());//    int rotation;//    if (cameraInfo.position() == QCamera::BackFace) {//        rotation = (cameraInfo.orientation() - screenAngle) % 360;//    } else {//        // Front position, compensate the mirror//        rotation = (360 - cameraInfo.orientation() + screenAngle) % 360;//    }//    // Rotate the frame so it always shows in the correct orientation    videoImg = videoImg.transformed(QTransform().rotate(90));    QWidget::update();                                              //更新了,就会触发paintEvent画图}void Widget::paintEvent(QPaintEvent *event){    QPainter painter(this);    QRect rect(0, 0, 480, 640);    //设置画笔    QPen pen;    pen.setWidth(5);                    //线宽    pen.setColor(Qt::red);    pen.setStyle(Qt::SolidLine);        //实线    pen.setCapStyle(Qt::FlatCap);       //线端点样式    pen.setJoinStyle(Qt::BevelJoin);    //线连接点样式    painter.setPen(pen);    painter.drawRect(rect);    //qDebug() <<  "image" << videoImg;     //第一次输出的QImage(null)    //只要窗口启动,就会触发paintEvent,所以第一次是null,不可以画图。    if(videoImg != QImage(nullptr)){        painter.drawImage(rect, videoImg);    }}void Widget::on_pushButton_clicked(){    capture->capture();}void Widget::NV21_T_RGB(unsigned int width , unsigned int height , unsigned char *yuyv , unsigned char *rgb){    const int nv_start = width * height ;    unsigned int i, j, index = 0, rgb_index = 0;    unsigned char y, u, v;    int r, g, b, nv_index = 0;    for(i = 0; i < height; i++){        for(j = 0; j < width; j ++){            //nv_index = (rgb_index / 2 - width / 2 * ((i + 1) / 2)) * 2;            nv_index = i / 2  * width + j - j % 2;            y = yuyv[rgb_index];            u = yuyv[nv_start + nv_index ];            v = yuyv[nv_start + nv_index + 1];            r = y + (140 * (v-128))/100;  //r            g = y - (34 * (u-128))/100 - (71 * (v-128))/100; //g            b = y + (177 * (u-128))/100; //b            if(r > 255)   r = 255;            if(g > 255)   g = 255;            if(b > 255)   b = 255;            if(r < 0)     r = 0;            if(g < 0)     g = 0;            if(b < 0)     b = 0;            index = rgb_index % width + (height - i - 1) * width;            //rgb[index * 3+0] = b;            //rgb[index * 3+1] = g;            //rgb[index * 3+2] = r;            //颠倒图像            //rgb[height * width * 3 - i * width * 3 - 3 * j - 1] = b;            //rgb[height * width * 3 - i * width * 3 - 3 * j - 2] = g;            //rgb[height * width * 3 - i * width * 3 - 3 * j - 3] = r;            //正面图像            rgb[i * width * 3 + 3 * j + 0] = b;            rgb[i * width * 3 + 3 * j + 1] = g;            rgb[i * width * 3 + 3 * j + 2] = r;            rgb_index++;        }    }//    return 0;}

widget.ui

<?xml version="1.0" encoding="UTF-8"?> Widget          0    0    1080    1920          Widget                0     640     480     640              Image                   40     1520     281     291              PushButton        

 

参考文献:

1.NV21与I420

2.C++ NV21转RGB

3.Camera Overview

4.QAbstractVideoSurface Class

5.Qt使用QAbstractVideoSurface捕获视频帧(信号槽方式),并用QPainter画出来

 

 

更多相关文章

  1. android AV同步详解
  2. 图像库 libpng 编译与实践
  3. Android(安卓)data分区格式F2FS改为EXT4
  4. android获取视频每一帧
  5. Android应用实例之----MifareUltralight格式的nfc标签读写
  6. Android(安卓)显示SVG格式图片
  7. Android(安卓)布局单位转换
  8. PX(像素)转换工具类
  9. Android(安卓)使用ThumbnailUtils类获取视频的缩略图

随机推荐

  1. [置顶] Android学习路线指南
  2. android优化 清除无效代码 UCDetector
  3. android下使用gdb调试工具笔记
  4. android启动过程详解(一)——解析init.rc
  5. android notification通知栏及8.0适配
  6. 修正Android摄像头API
  7. 通过Ant将android project打包成apk并安
  8. android按键驱动开发实例1(修改一个按键)
  9. android的学习记录-包括android的安装、
  10. Android Studio安装配置(详细版)