一、读取摄像头的基础知识

1、读取摄像头用到的类库Libavdevice:可以读取电脑(或者其他设备上)的多媒体设备的数据,或者输出数据到指定的多媒体设备上等。

这个库支持以下设备作为输入端:avfoundation、bktr、dshow(本文使用)、fbdev、gdigrab、jack、lavfi、libcdio、openal、vfwcap等

支持以下设备作为输出端:alsa、caca、decklink、fbdev、opengl、sndio、xv等

2、libavdevice使用

头文件:#include "libavdevice/avdevice.h"

注册:libavdevice:avdevice_register_all()

2.1使用libavdevice读取数据和直接打开视频文件类似。因为系统的设备也被FFmpeg认为是一种输入的格式(即AVInputFormat)。使用FFmpeg打开一个普通的视频文件如下:

AVFormatContext *formatContext = avformat_alloc_context();
avformat_open_input(&formatContext , "Warcraft3_End.avi",nullptr,nullptr);

2.2使用libavdevice,唯一的不同在于需要首先查找用于输入的设备。(av_find_input_format())

AVFormatContext *formatContext = avformat_alloc_context();
AVInputFormat *ifmt=av_find_input_format("dshow");//windows上视频的推流格式
avformat_open_input(&formatContext , "video=Integrated Camera", ifmt,NULL);

注:1、如果是指定了vfwcap设备作为输入设备,在URL中指定打开第0个摄像头设备如下

avformat_open_input(&formatContext , 0, ifmt,NULL);

2、URL的格式是"video={设备名称}",设备名称外面不能加引号,注意空格。

3、dshow的设备名称必须要提前获取

2.3可以在   我的电脑--》管理--》设备管理器   中查找本机摄像头名称也可以通过代码获取

获取摄像头数量和名称

.pro文件中添加如下:

QT         +=   multimedia
QT         +=  multimediawidgets
    //头文件QCameraInfo、QCameraQList<QCameraInfo> cameraList = QCameraInfo::availableCameras();qDebug()<<cameraList.size()<<endl;for(int i=0;i<cameraList.size();i++){qDebug()<<cameraList.at(i).description();}

本文实现的是读取摄像头生成yuv和rgb数据两份数据,利用解码线程类实现边解码生成rgb数据边在窗口类播放,利用生成的yuv数据进行编码生成h264文件(可播放)

二、实现效果

1、读取摄像头:

2、摄像头数据解码生成YUV数据后再编码生成.h264文件,可播放

用eseye_u.exe 打开.h264文件如下图:

三、代码

解码类cpp文件如下:

关于编码类(yuv—>h264)的博客和源码请看文末链接

fdecode::fdecode()
{fcode = new fcode_h264;fcode->codecInit();//编码器初始化
}void fdecode::registerFFmpeg()
{av_register_all();//注册所有组件avdevice_register_all();//注册摄像头
}void fdecode::openVideoStream(QString filename)
{//参数1:封装格式上下文->AVFormatContext->包含了视频信息(视频格式、大小等等...)双指针定义一颗星*,//参数2:要打开流的路径(文件名)//AVFormatContext保存视频(视频流)相关信息的结构体AVFormatContext  * formatContent = avformat_alloc_context();/*2、打开摄像头*/AVInputFormat *fmt = av_find_input_format("dshow");//windows上视频的推流格式QString cameraName = QString("video=%1").arg(filename);int res = avformat_open_input(&formatContent,cameraName.toStdString().c_str(),fmt,nullptr);//"video=USB2.0 VGA UVC WebCam"if(res!=0){qDebug()<<"打开摄像头失败";return ;}QList<QCameraInfo> cameraList = QCameraInfo::availableCameras();qDebug()<<cameraList.size()<<endl;for(int i=0;i<cameraList.size();i++){qDebug()<<cameraList.at(i).description();}/*3、打开成功之后相关的结构体信息放在了formatContent里面,接下来获取视频文件信息*/res = avformat_find_stream_info(formatContent,nullptr);if(res<0){qDebug()<<"打开流媒体信息失败";return ;}int videoType = -1;//3.2一个视频中有多股码流(用循环),存在AVFormatContext的streams数组中for(int i=0;i<formatContent->nb_streams;i++){if(formatContent->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)//streams->有AVStream结构体,AVStream->codec{//找到视频流(只有一个)videoType = i;//标识视频流这个类型break;}}if(videoType == -1){qDebug()<<"没有找到视频流相关信息";return;}//3.3根据视频流查找编码器对应的上下文对象结构体,存储编码器以及宽高格式等AVCodecContext *codec = formatContent->streams[videoType]->codec;/*4、有视频流,则查找对应视频流的解码器*/AVCodec *decoder = avcodec_find_decoder(codec->codec_id);//需要解码器的idif(decoder ==nullptr){qDebug()<<"没有找到对应的解码器";return;}/*5、找到解码器后打开解码器*///参数:1.初始化的上下文对象 2.打开的解码器 3.类似目录的东西(没有)res = avcodec_open2(codec,decoder,nullptr);if(res!=0){qDebug()<<"解码器打开失败";return;}/*6、获取到的每一帧码流(视频流)数据写到文件中,进行循环解码*//*6.1写到文件用FILE结构体*/AVPacket *pkt=nullptr;//pkt这时没有指向,要我们给他分配内存空间,希望把读出来的数据放到这块内存去pkt = (AVPacket *)malloc(sizeof(AVPacket));//码流数据是存到buffer里面,也需要我们动态开空间(AVBufferRef *buf;)//开空间不知道一帧的码流数据是多少?其实编解码器告诉了宽高,以此可以计算出给码流数据开多大空间int bufSize = codec->width*codec->height;//计算一帧(图)数据的大小av_new_packet(pkt,bufSize);AVFrame *pictureRGB = av_frame_alloc();;//保存解码及剔除后的像素数据(做准备)pictureRGB->width = codec->width;pictureRGB->height = codec->height;pictureRGB->format = codec->pix_fmt;//格式的设置//要存解码后的像素数据到pictureRGB,那这个数据有多大呢?//获取解码后的一帧像素数据有多大int numByte = avpicture_get_size(AV_PIX_FMT_RGB32,codec->width,codec->height);//开的空间用来保存像素数据的大小uint8_t *buffer = (uint8_t *)av_malloc(numByte*sizeof(uint8_t));//像素数据填充到AVFrame的pictureRGB里avpicture_fill((AVPicture *)pictureRGB,buffer,AV_PIX_FMT_RGB32,codec->width,codec->height);//因为解码之后要伸展,所以先进行转换规则的设置,转换完进入第七步解码SwsContext *swsContent = nullptr;swsContent = sws_getContext(codec->width,codec->height,codec->pix_fmt,codec->width,codec->height,AV_PIX_FMT_RGB32,SWS_BICUBIC,nullptr,nullptr,nullptr);AVFrame *pictureYUV = av_frame_alloc();pictureYUV->width = codec->width;pictureYUV->height = codec->height;pictureYUV->format = codec->pix_fmt;//格式的设置int numByte2 = avpicture_get_size(AV_PIX_FMT_YUV420P,codec->width,codec->height);uint8_t *bufferYUV = (uint8_t *)av_malloc(numByte2*sizeof(uint8_t));avpicture_fill((AVPicture *)pictureYUV,bufferYUV,AV_PIX_FMT_YUV420P,codec->width,codec->height);SwsContext *swsContentYUV = nullptr;swsContentYUV = sws_getContext(codec->width,codec->height,codec->pix_fmt,codec->width,codec->height,AV_PIX_FMT_YUV420P,SWS_BICUBIC,nullptr,nullptr,nullptr);int count = 0;AVFrame *picture = av_frame_alloc();//保存原始RGB、YUV数据while(av_read_frame(formatContent,pkt) >= 0)//成功读到了数据(一帧一帧读(循环):av_read_frame){/*6.2AVPacket->AVStream,要判断读到的每一帧的码流数据是不是视频流*/if(pkt->stream_index == videoType){avcodec_send_packet(codec,pkt);res = avcodec_receive_frame(codec,picture);//把解码得到的损坏的像素数据剔除(存到pictureRGB中)sws_scale(swsContent,(const uint8_t * const *)picture->data,picture->linesize,0,picture->height,pictureRGB->data,pictureRGB->linesize);sws_scale(swsContentYUV,(const uint8_t * const *)picture->data,picture->linesize,0,picture->height,pictureYUV->data,pictureYUV->linesize);count++;QImage desImage = QImage((uchar*)buffer,codec->width,codec->height,QImage::Format_RGB32,nullptr,nullptr); //RGB32emit sendImage(desImage);//得到图片的时候触发信号msleep(25);fcode->codecFrame(pictureYUV);//解码得到一帧像素数据后调用编码函数(YUV-H264)if(count ==400)//录制400帧结束循环{break;}}//每次都存在同一块内存空间里,要清空上一次的操作av_packet_unref(pkt);//不是free}qDebug()<<"保存码流数据和像素数据成功";fcode->writeEndFrame();//写入尾巴帧}void fdecode::run()
{this->fileName="USB2.0 VGA UVC WebCam";//摄像头名称this->registerFFmpeg();//注册this->openVideoStream(this->fileName);
}

注意点:

要进行录像多少帧就结束的判断,否则当直接关掉运行窗口,尾巴帧都没有写入,导致生成h264文件时为0kb

有关编码类(yuv—>h264),请读者参考我的博客:

https://blog.csdn.net/hml111666/article/details/122571168

演示用的eseye_u.exe破解版免安装包:

eseye_u.exe破解版免安装包-编解码文档类资源-CSDN下载

演示用的视频下载链接:

ffmpeg(h264、yuv、rgb)演示视频-C/C++文档类资源-CSDN下载

源码下载链接:

Qt基于FFmpeg读取摄像头并进行H264编码-编解码文档类资源-CSDN下载

Qt基于FFmpeg读取摄像头并进行H264编码相关推荐

  1. Qt基于FFmpeg实现视频转码

    一.简述转码 转码的作用:封装格式的实现.(h264->mov.mp4.flv.avi(封装格式)等) 之前博客中提到如何把像素数据编码得到 H264 的压缩码流数据,但是一般的播放工具是没法直 ...

  2. Qt基于FFmpeg播放本地 H.264(H264)文件

    最近在弄H264的硬件编解码,基于DM3730,但是为了调试方便,在小红帽上用FFmpeg实现了H264的软件编解码.现在弄了一个Windows的例子,给需要的同学参考一下,如果大家觉得有帮助,可以小 ...

  3. 基于FFMPEG采集摄像头图像编码MP4视频+时间水印

    1.硬件平台 操作系统:Ubuntu18.04 ffmpeg版本:ffmpeg4.2.5 摄像头:电脑自带或USB免驱摄像头 水印处理:avfilter 图像渲染:SDL库   摄像头图像采集+MP4 ...

  4. 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

    本文介绍一个最简单的基于FFMPEG的音频编码器.该编码器实现了PCM音频采样数据编码为AAC的压缩编码数据.编码器代码十分简单,但是每一行代码都很重要.通过看本编码器的源代码,可以了解FFMPEG音 ...

  5. 最简单的基于FFMPEG的图像编码器(YUV编码为JPEG)

    伴随着毕业论文的完成,这两天终于腾出了空闲,又有时间搞搞FFMPEG的研究了.想着之前一直搞的都是FFMPEG解码方面的工作,很少涉及到FFMPEG编码方面的东西,于是打算研究一下FFMPEG的编码. ...

  6. python ffmpeg读取摄像头_使用ffmpegpython库捕获网络摄像头

    嗨,我正在尝试使用ffmpeg python包装库(https://github.com/kkroening/ffmpeg-python)捕获一个使用python的网络摄像头流 我有一个有效的ffmp ...

  7. 基于OpenCV读取摄像头进行人脸检测和人脸识别

    前段时间使用OpenCV的库函数实现了人脸检测和人脸识别,笔者的实验环境为VS2010+OpenCV2.4.4,OpenCV的环境配置网上有很多,不再赘述.检测的代码网上很多,记不清楚从哪儿copy的 ...

  8. Qt基于ffmpeg的rtsp视频流接收播放工具

    1.效果图 二.工程及ffmpeg库已打包上传:http://download.csdn.net/detail/qq_18854309/9878455

  9. qt读取摄像头数据并显示

    Qt 框架可以使用 Qt Multimedia 模块读取摄像头数据并显示.下面是一个简单的例子: 创建一个 Qt Widgets 项目 在窗口上放置一个 QCameraViewfinder 创建一个 ...

  10. ffmpeg 从mp4上提取H264的nalu

    1.获取数据 ffmpeg读取mp4中的H264数据,并不能直接得到NALU,文件中也没有储存0x00000001的分隔符.下面这张图为packet.data中的数据 从图中可以发现,packet中的 ...

最新文章

  1. 一篇文章讲清楚人工智能、机器学习和深度学习的区别和联系
  2. DNS扫盲系列之五:域名配置ZONE文件
  3. vs 没有足够的内存继续执行程序_科赋内存条:韩国和台湾产的有不同?
  4. wyse WES系统操作
  5. 利用程序动态管理Web.config文件
  6. 无人驾驶(再谈基于camera的高精度地图)
  7. Qt、C++汽车客运公司售票系统
  8. eyoucms表单令牌
  9. linux 磁盘坏道修复,linux系统下检测硬盘上的坏道和坏块
  10. Java实现批量下载《神秘的程序员》漫画
  11. linux逻辑卷管理的创建过程,LVM-逻辑卷管理器创建过程for linux
  12. 用python绘制派大星_1行代码搞定Latex公式编写,这个4.6M的Python小插件,写论文必备...
  13. 从word2vec到node2vec
  14. 【译】Unity3D Shader 新手教程(1/6)
  15. 从文本进度条开始:谈谈自己缺失的Python基础知识
  16. wm_concat和listagg
  17. Windows下载安装Redis
  18. QTextEdit:仅当滚动条位于底部时自动向下滚动
  19. 计算机会议期刊投稿,中国计算机学会推荐的投稿期刊和会议
  20. STM32CubeMX安装及使用教程(一)

热门文章

  1. 网页播放全景视频和全景图片
  2. ctf 网络安全比赛简介
  3. 深度学习项目部署遇到的错误【记录】
  4. SourceTree和Bitbucket使用时的注意事项
  5. arctanx麦克劳林公式推导过程_罗德里格斯公式推导
  6. 标准c语言程序文件名后缀为,CCS_C语言编程
  7. 虚拟机linux ecap文件在,为AM335x移植Linux内核主线代码(30)eCAP的PWM波功能
  8. 使用百度ai识别身份证信息
  9. ubuntu中修改只读文件
  10. 如何构建Birt报表应用程序?