Buildroot+Qt实现摄像头视频h264编码和拍照功能

https://gitee.com/zy853728579/video_test_app.git

实现h264硬编码+拍照功能,以下为关健代码

videodevice.h

#ifndef VIDEODEVICE_H
#define VIDEODEVICE_H#include <QWidget>
#include <QTimer>
#include <QDebug>
#include <QReadWriteLock>#include <QCamera>
#include <QCameraInfo>
#include <QVideoProbe>
#include <QVideoFrame>
#include <QCameraViewfinder>
#include <QCameraViewfinderSettings>#define VIDEO_FPS               (30)#define CAMERA_PIXEL_WIDE       (1920)
#define CAMERA_PIXEL_HIGH       (1080)class VideoDevice : public QWidget
{Q_OBJECT
public:explicit VideoDevice(QSize showSize, QWidget *parent = nullptr);~VideoDevice(void);void openCamera(bool reboot = false);void closeCamera(void);void showViewfinder(int x, int y);void hideViewfinder(void) { if (m_viewFinder != nullptr) m_viewFinder->hide(); }//获取摄像头配置参数int getFrameRate(void) { return VIDEO_FPS; }QSize getPixelSize(void) { return QSize(CAMERA_PIXEL_WIDE, CAMERA_PIXEL_HIGH);}//获取每帧数据void getFrameData(void * pData);void getFrameData(QByteArray & pArray);public slots:void setProbeStatus(bool status) { m_probeStatus = status; }private:void setCamera(const QCameraInfo &cameraInfo);private slots:void updateCameraState(QCamera::State);void showCameraError(void);void onProbeFrameSlot(const QVideoFrame &frame);void cameraTimeoutSlot(void);signals:void videoFrameSingal(void);private:QCamera * m_camera;QVideoProbe * m_videoProbe;QCameraViewfinder * m_viewFinder = nullptr;QTimer * m_cameraTimer = nullptr;QByteArray * m_frameData;QReadWriteLock m_frameRWLock;int m_cameraCnt = 0;quint8 m_cameraCntPlus = 1;bool isCameraOpen = false;bool m_probeStatus = false;
};#endif // VIDEODEVICE_H

videodevice.cpp(使用QT类打开摄像头进行获取图像和显示)

#include "videodevice.h"Q_DECLARE_METATYPE(QCameraInfo)VideoDevice::VideoDevice(QSize showSize, QWidget *parent) :QWidget(parent)
{m_frameData = new QByteArray();m_cameraTimer = new QTimer(this);QObject::connect(m_cameraTimer, &QTimer::timeout, this, &VideoDevice::cameraTimeoutSlot);m_viewFinder = new QCameraViewfinder(parent);m_viewFinder->setWindowFlag(Qt::FramelessWindowHint);m_viewFinder->setFixedSize(showSize.width(), showSize.height());setCamera(QCameraInfo::defaultCamera());
}VideoDevice::~VideoDevice()
{closeCamera();m_frameData->clear();delete m_frameData;delete m_videoProbe;delete m_camera;
}void VideoDevice::setCamera(const QCameraInfo &cameraInfo)
{//初始化摄像头m_camera = new QCamera(cameraInfo, this);connect(m_camera, &QCamera::stateChanged, this, &VideoDevice::updateCameraState);connect(m_camera, QOverload<QCamera::Error>::of(&QCamera::error), this, &VideoDevice::showCameraError);updateCameraState(m_camera->state());/** QVideoFrame::Format_YUV420P* YYYYYY* YYYYYY* YYYYYY* UUUUUU* VVVVVV*/QCameraViewfinderSettings settings;settings.setPixelFormat(QVideoFrame::Format_YUV420P);settings.setMinimumFrameRate(VIDEO_FPS);settings.setMaximumFrameRate(VIDEO_FPS);settings.setResolution(QSize(CAMERA_PIXEL_WIDE, CAMERA_PIXEL_HIGH));m_camera->setViewfinderSettings(settings);m_videoProbe = new QVideoProbe(this);m_videoProbe->setSource(m_camera);connect(m_videoProbe, &QVideoProbe::videoFrameProbed, this, &VideoDevice::onProbeFrameSlot);
}void VideoDevice::openCamera(bool reboot)
{if (isCameraOpen && !reboot)return ;m_camera->stop();m_camera->unload();m_camera->setCaptureMode(QCamera::CaptureVideo);m_camera->start();isCameraOpen = true;if (!m_cameraTimer->isActive())m_cameraTimer->start(10);
}void VideoDevice::closeCamera()
{isCameraOpen = false;m_camera->stop();m_camera->unload();m_cameraTimer->stop();
}void VideoDevice::showViewfinder(int x, int y)
{if (m_viewFinder == nullptr)return ;m_camera->setViewfinder(m_viewFinder);m_viewFinder->move(x, y);m_viewFinder->show();
}void VideoDevice::updateCameraState(QCamera::State state)
{switch (state){case QCamera::ActiveState: break;case QCamera::UnloadedState:case QCamera::LoadedState: break;}
}void VideoDevice::showCameraError(void)
{qDebug()<<"Camera error:"<<m_camera->errorString();
}void VideoDevice::getFrameData(void * pData)
{QReadLocker readLock(&m_frameRWLock);memcpy(pData, m_frameData->data(), m_frameData->length());
}void VideoDevice::getFrameData(QByteArray &pArray)
{QReadLocker readLock(&m_frameRWLock);pArray.append(*m_frameData);
}void VideoDevice::onProbeFrameSlot(const QVideoFrame &frame)
{m_cameraCnt     = 0;m_cameraCntPlus = 1;if (!m_probeStatus)return ;QVideoFrame cloneFrame(frame);if (!cloneFrame.map(QAbstractVideoBuffer::ReadOnly)) {return ;}{QWriteLocker writeLock(&m_frameRWLock);m_frameData->clear();m_frameData->append((const char *)cloneFrame.bits(), cloneFrame.mappedBytes());}cloneFrame.unmap();emit videoFrameSingal();
}void VideoDevice::cameraTimeoutSlot()
{m_cameraCnt++;//800msif (m_cameraCnt > (m_cameraCntPlus * 80)){qDebug()<<"camera is timeout!";m_cameraCntPlus++;m_cameraCnt = 0;openCamera(true);}
}

videothread.h

#ifndef VIDEOTHREAD_H
#define VIDEOTHREAD_H#include <QObject>
#include <QSemaphore>
#include <QThread>
#include <QMutex>
#include <QReadWriteLock>
#include <QFileInfo>
#include <QTime>#include "videodevice.h"
#include "mppencoder.h"/***************************************************************************  录像**/class VideoThread : public QThread
{Q_OBJECTpublic:enum RecordStatus{RECORD_NULL,RECORD_STOP,RECORD_START,RECORD_PAUSE,RECORD_SIZEOVER,RECORDING};explicit VideoThread(VideoDevice* vd, QObject *parent = nullptr);~VideoThread();//停止该线程运行void stop(void);//设置录像视频保存路经void setRecordPath(const QString & path);/*设置录像状态*          当前状态                        可改变状态* RECORD_NULL/RECORD_STOP     --->      RECORD_START* RECORD_START                --->      RECORD_STOP* RECORDING/RECORD_SIZEOVER   --->      RECORD_PAUSE/RECORD_STOP* RECORD_PAUSE                --->      RECORD_STOP/RECORDING*/void setRecordStatus(RecordStatus status);public slots:void videoFrameSlot(void);signals://录像完成信号void videoFinishSignal();/* 编码完成后数据* head == true : 表示数据包头*/void encodeDataSignal(bool head, const QByteArray & pData);//录像时间//格式:HH:mm:ssvoid videoTimeSignal(const QString & time);protected:void run();private slots:void startRecord(void);void endRecord(void);void videoSave(const QByteArray & pArray);//录像计时void recordTiming();void checkRecordSizeSlot(void);void setStatus(RecordStatus s){QWriteLocker write(&m_statusRWLock);m_recordStatus = s;}RecordStatus getStatus(void){QReadLocker read(&m_statusRWLock);return m_recordStatus;}private:bool isStop = false;QSemaphore m_semVideo;VideoDevice * m_videoDevice = nullptr;quint64 m_frameCnt          = 0;quint64 m_frameTimeSave     = 0;QString m_recordPath        = "";QString m_recordFile        = "";QReadWriteLock m_statusRWLock;RecordStatus m_recordStatus = RECORD_NULL;//编码MppEncoder * m_mppEncode    = nullptr;QTimer * m_checkSizeTimer   = nullptr;QSize m_videoSize;//图像大小int m_videoFps              = 0;//帧率int m_frameTime             = 0;//ms
};/***************************************************************************  拍照**/
#include "videoffmpeg.h"class PictureThread : public QThread
{Q_OBJECT
public:enum PictureStatus{PICTURE_NULL,PICTURE_START};explicit PictureThread(VideoDevice* vd, QObject *parent = nullptr);void stop(void);void setPicturePath(const QString & path);void setPictureStatus(PictureStatus status);public slots:void pictureFrameSlot(void);signals:void pictureFinishSignal(void);protected:void run();private:QString openPictureFile(void);private:bool isStop = false;QSemaphore m_semPicture;VideoDevice * m_videoDevice     = nullptr;QString m_picturePath           = "";PictureStatus m_pictureStatus   = PICTURE_NULL;
};#endif // VIDEOTHREAD_H

videothread.cpp(录像和拍照线程处理)

#include "videothread.h"
#include <QDebug>
#include <unistd.h>/***************************************************************************  录像**/
#define FILE_SZ_1M      (1024LL*1024LL)
#define FILE_SZ_1G      (1024LL*FILE_SZ_1M)
#define FILE_SZ_3G      (3LL*FILE_SZ_1G)VideoThread::VideoThread(VideoDevice* vd, QObject *parent) :QThread(parent),m_videoDevice(vd)
{m_videoSize = m_videoDevice->getPixelSize();m_videoFps  = m_videoDevice->getFrameRate();m_frameTime = 1000000 / m_videoFps;m_mppEncode = new MppEncoder(m_videoSize.width(), m_videoSize.height(), m_videoFps);m_checkSizeTimer = new QTimer(this);QObject::connect(m_checkSizeTimer, &QTimer::timeout, this, &VideoThread::checkRecordSizeSlot);
}VideoThread::~VideoThread()
{setRecordStatus(RECORD_STOP);endRecord();delete m_mppEncode;
}void VideoThread::stop()
{isStop = true;quit();wait();
}void VideoThread::setRecordPath(const QString &path)
{if (path.isEmpty()){if (m_recordStatus != RECORD_NULL){m_recordStatus = RECORD_NULL;int num = m_semVideo.available();if (num != 0)m_semVideo.acquire(num);}return ;}m_recordPath = path;
}void VideoThread::setRecordStatus(RecordStatus status)
{if (m_recordPath.isEmpty())return ;RecordStatus record = getStatus();switch (record) {case RECORD_NULL:case RECORD_STOP:{if (status == RECORD_START){m_frameCnt = 0;record = status;}}break;case RECORD_START:{if (status == RECORD_STOP)record = status;}break;case RECORDING:case RECORD_SIZEOVER:{if (status == RECORD_PAUSE ||status == RECORD_STOP)record = status;}break;case RECORD_PAUSE:{if (status == RECORD_STOP) {record = status;if (m_semVideo.available() == 0)m_semVideo.release();}else if (status == RECORDING){record = status;}}break;}//定时器处理if (record == RECORD_PAUSE ||record == RECORD_STOP){m_checkSizeTimer->stop();}if (record == RECORD_START ||record == RECORDING){if (!m_checkSizeTimer->isActive())m_checkSizeTimer->start(10000);}setStatus(record);
}void VideoThread::videoFrameSlot(void)
{RecordStatus record = getStatus();if (record == RECORD_NULL){int num = m_semVideo.available();if (num != 0)m_semVideo.acquire(num);return ;}m_semVideo.release();
}void VideoThread::startRecord()
{int videoCnt = 0;QString lo = m_recordPath + "/VIDEO" + QString::number(videoCnt) + ".mp4";QFileInfo fi = QFileInfo(lo);while(fi.isFile()){videoCnt++;lo = m_recordPath + "/VIDEO" + QString::number(videoCnt) + ".mp4";fi = QFileInfo(lo);}QByteArray mp4file(lo.toLocal8Bit());bool ret = MP4_Write_Init(mp4file.data(), m_videoFps);if(ret == false) {qDebug()<<"MP4_Write_Init failed..";return ;}QByteArray array = m_mppEncode->getFrameHeader();if (array.isEmpty())return ;emit encodeDataSignal(true, array);MP4_Write_SPS_PPS((uint8_t*)array.data(), array.length());m_recordFile = lo;
}void VideoThread::endRecord()
{MP4_Write_Exit();sync();
}void VideoThread::videoSave(const QByteArray &pArray)
{int lenght = pArray.length();MP4_Write_Main((uint8_t*)pArray.data(), lenght);
}void VideoThread::recordTiming()
{m_frameCnt++;quint64 time = (m_frameCnt * m_frameTime) / 1000000; //sif (m_frameTimeSave != time){m_frameTimeSave = time;QString timeStr = QTime(0, 0, 0).addSecs(time).toString(QString::fromLatin1("HH:mm:ss"));//qDebug()<<"timeStr="<<timeStr;emit videoTimeSignal(timeStr);}
}void VideoThread::checkRecordSizeSlot()
{if (m_recordFile.isEmpty())return ;RecordStatus record = getStatus();if (record != RECORD_START &&record != RECORDING)return ;QFileInfo fi = QFileInfo(m_recordFile);qint64 size = fi.size();if (size > FILE_SZ_3G){qDebug()<<"size is 3G!";setStatus(RECORD_SIZEOVER);}
}void VideoThread::run()
{msleep(250);for ( ; 1 ;){if(isStop == true)return;if(m_videoDevice == nullptr)continue;m_semVideo.acquire();//数据保存RecordStatus record = getStatus();if (record == RECORD_SIZEOVER){setStatus(RECORD_START);MP4_Write_Exit();}if (record == RECORD_START){setStatus(RECORDING);startRecord();}if (record == RECORDING){//编码void * desBuf = m_mppEncode->getFrameBuffer();m_videoDevice->getFrameData(desBuf);QByteArray encodeArray;m_mppEncode->encode(encodeArray);emit encodeDataSignal(false, encodeArray);recordTiming();videoSave(encodeArray);}if (record == RECORD_STOP){setStatus(RECORD_NULL);endRecord();emit videoFinishSignal();}}
}/***************************************************************************  拍照**/PictureThread::PictureThread(VideoDevice* vd, QObject *parent) :QThread(parent),m_videoDevice(vd)
{}void PictureThread::stop()
{isStop = true;quit();wait();
}void PictureThread::setPicturePath(const QString &path)
{if (path.isEmpty()){if (m_pictureStatus != PICTURE_NULL){m_pictureStatus = PICTURE_NULL;int num = m_semPicture.available();if (num != 0)m_semPicture.acquire(num);}return ;}m_picturePath = path;
}void PictureThread::setPictureStatus(PictureStatus status)
{if (status == PICTURE_NULL)return ;if (m_picturePath.isEmpty())return ;if (m_pictureStatus == PICTURE_NULL)m_pictureStatus = status;
}QString PictureThread::openPictureFile()
{QString lo = "";if (m_picturePath.isEmpty())return lo;int imageCnt = 0;lo = m_picturePath + "/PIC" + QString::number(imageCnt) + ".jpg";QFileInfo fi = QFileInfo(lo);while(fi.isFile()){imageCnt++;lo = m_picturePath + "/PIC" + QString::number(imageCnt) + ".jpg";fi = QFileInfo(lo);}return lo;
}void PictureThread::pictureFrameSlot()
{if (m_pictureStatus == PICTURE_NULL){int num = m_semPicture.available();if (num != 0)m_semPicture.acquire(num);return ;}m_semPicture.release();
}void PictureThread::run()
{msleep(250);VideoFfmpeg ffmpeg(CAMERA_PIXEL_WIDE, CAMERA_PIXEL_HIGH);int rgbLenght = ffmpeg.getNumBytes();for ( ; 1 ;){if(isStop == true)return;if(m_videoDevice == nullptr)continue;m_semPicture.acquire();if (m_pictureStatus != PICTURE_START)continue;m_pictureStatus = PICTURE_NULL;QByteArray array;array.clear();m_videoDevice->getFrameData(array);ffmpeg.setFrameYUV((unsigned char *)array.data());char * dstBuff = (char *)malloc(rgbLenght * sizeof(uint8_t));memset(dstBuff, 0, rgbLenght * sizeof(uint8_t));ffmpeg.setRgbBuffer((unsigned char *)dstBuff);bool isOk = ffmpeg.play();if (isOk == false){qDebug()<<"ffmpeg conversion failed!";delete dstBuff;dstBuff = nullptr;continue;}//获取文件名称QString fileName = openPictureFile();//保存if (!fileName.isEmpty()){QSize s = m_videoDevice->getPixelSize();QImage tmpImg((unsigned char*)dstBuff, s.width(), s.height(), QImage::Format_RGB888);tmpImg.save(fileName);sync();//拍照保存完成emit pictureFinishSignal();}//释放空间delete dstBuff;dstBuff = nullptr;}
}

Qt实现摄像头视频h264编码和拍照功能相关推荐

  1. 基于HTML5实现的超酷摄像头(HTML5 webcam)拍照功能 - photobooth.js

    在线演示  下载 WebRTC可能是明年最受关注的HTML5标准了,Mozilla为此开发了一套帮助你控制硬件的API,例如,摄像头,麦克风,或者是加速表.你可以不依赖其它的插件来调用你需要的本机硬件 ...

  2. iOS音频AAC视频H264编码 推流最佳方案

    1    功能概况 *  实现音视频的数据的采集 *  实现音视频数据的编码,视频编码成h264,音频编码成aac *  实现音视频数据的发布,将编码好的音视频数据传输到服务器 2 视频和音频编码方案 ...

  3. iOS 使用FFmpeg实现视频H264编码

    本文借鉴:https://www.jianshu.com/p/70b0af4d0ec7   以及 https://www.jianshu.com/p/31d1ca4999c6 ffmpeg 相关命令行 ...

  4. QT:在QT中调用摄像头并实现简单的拍照功能

    要在QT中使用摄像头,就要链接多媒体模块以及多媒体工具模块: QT += multimedia QT += multimediawidgets 废话少说,直接上代码,想说的都在代码里面斜体样式: ma ...

  5. java js 打开摄像头_基于HTML5实现的超酷摄像头(HTML5 webcam)拍照功能 - photobooth.js...

    日期:2012-12-10  来源:GBin1.com WebRTC可能是明年最受关注的HTML5标准了,Mozilla为此开发了一套帮助你控制硬件的API,例如,摄像头,麦克风,或者是加速表.你可以 ...

  6. H264编码介绍和参数设置

    视频h264编码流程 宏块划分 Macro Block 帧内预测 I帧 帧间预测和GOP P帧和B帧 DCT离散余弦变换 量化 熵编码 preset 预设编码器 预设编码器 比特率控制 恒定比特率(C ...

  7. 采集音频和摄像头视频并实时H264编码及AAC编码

    0. 前言 我在前两篇文章中写了DirectShow捕获音视频然后生成avi,再进行264编码的方法.那种方法有一些局限性,不适合实时性质的应用,如:视频会议.视频聊天.视频监控等.本文所使用的技术, ...

  8. 采集音频和摄像头视频并实时H264编码及AAC编码[转]

    0. 前言 我在前两篇文章中写了DirectShow捕获音视频然后生成avi,再进行264编码的方法.那种方法有一些局限性,不适合实时性质的应用,如:视频会议.视频聊天.视频监控等.本文所使用的技术, ...

  9. FFmpeg4入门14:Linux下摄像头捕获并编码为h264

    上一篇是将H264流封装到MP4容器中,本篇介绍一个最常用的捕获原始数据的方法:从摄像头获取数据. 因为本人已经放弃windows操作系统,所以使用linux来获取摄像头并编码为H264文件保存. l ...

最新文章

  1. Scanpy(二)对PBMC3k聚类
  2. J2EE 字符 字节 编码知识概念
  3. vmos框架_VMOS虚拟大师独立的安卓虚拟机系统【安卓】
  4. 好玩的deep dream(清晰版,pytorch完整代码)
  5. Java GUI编程:swing创建窗体代码详解
  6. MySQL利用UDF执行命令
  7. java ews_Java---使用EWS 写个ExchangeMailUtil
  8. springmvc流程_基于Spring MVC框架的Http流程分析
  9. npm 与yarn CLI 命令比较
  10. 【Java】字符串String操作
  11. 非极大值抑制(non-maximum suppression)的理解与实现
  12. xv6 - simple modern os for education purpose.
  13. linux 线程同步与互斥:读写锁 线程读操作较多,写操作较少时,使用读写锁
  14. 初中向局里申请计算机报告,物资申请报告格式
  15. VeryCD 电驴(easyMule) 1.1.9 稳定版
  16. 数学建模学习笔记(六):排队论模型
  17. 2022年信息系统管理工程师考试大纲
  18. python判断空行_python判断空行
  19. Eclipse:source 1.5 中不支持 diamond 运算符
  20. 使用JLINK和Jscope遇到的一些问题

热门文章

  1. TMI4054锂电池充电管理IC
  2. ​有礼有趣, 2019数博会你不可错过的六大亮点
  3. 毕业设计:电子设计大赛点阵电子显示屏(A题).pdf
  4. LaTeX公式在括号内换行
  5. 2018.7--2018.9项目一:北京市地税局数据交换平台
  6. 基于“数字孪生”和YoLoV5的AI药物开发(技术理论实践部分)
  7. 诺基亚e63怎么打开java游戏_诺基亚E63手机设置教程(新手必看)
  8. VLSI数字信号处理系统——第五章展开
  9. hugo个人博客 修改主题:颜色,字体,布局
  10. 计算机组成与结构区号怎么求,计算机组成与结构部分习题及答案资料