之前用directshow做视频采集,虽然可以通过预览窗口进行视频预览,但是灵活性不好,无法对视频数据进行其他编码等(当时尝试过很多次,没成功

),现在使用FFmpeg进行采集视频,主要是可以对视频进行再编码,操作比较方便。下面附上主要部分的源代码:

#include "video.h"

videoMgr::videoMgr()
{
m_url = "";
m_shortName = "";
CoInitialize(NULL);
}
videoMgr::~videoMgr()
{
clearVideoFrames(m_RGBFrames);
clearVideoFrames(m_YUVFrames);
CoUninitialize();
}
void videoMgr::VFWCapture(int nVideoID)
{
}
void videoMgr::dshowCapture(const char *videoName)
{
}
void videoMgr::dshowDeviceOption()
{
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVDictionary* options = NULL;
av_dict_set(&options, "list_options", "true", 0);
AVInputFormat *iformat = av_find_input_format("dshow");
printf("\n=====Device Option Info=====\n");
avformat_open_input(&pFormatCtx, "video=Integrated Camera", iformat, &options);
}
void videoMgr::dshowDevice()
{
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVDictionary* options = NULL;
av_dict_set(&options,"list_devices","true",0);
AVInputFormat *iformat = av_find_input_format("dshow");
printf("\n=====dshow Device Info======\n");
avformat_open_input(&pFormatCtx,"video=dummy", iformat, &options);
}
void videoMgr::VFWDevice()
{
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVInputFormat *iformat = av_find_input_format("vfwcap");
printf("\n=====VFW Device Info========\n");
avformat_open_input(&pFormatCtx, "list", iformat, NULL);
}
int videoMgr::EnumDevices()
{
ICreateDevEnum *pDevEnum = NULL;
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pDevEnum);
if(pDevEnum == NULL)
return 0;
ULONG cFetched = 0;
IMoniker *pMoniker = NULL;
IEnumMoniker *pClassEnum = NULL;
pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
if(pClassEnum == NULL)
return 0;
while(pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag* pProp= NULL;
pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pProp);
if(pProp != NULL)
{
VARIANT varName;
varName.vt = VT_BSTR;
pProp->Read(L"FriendlyName", &varName, 0);
char name[MAX_PATH] = {0};
unicode_ansi(name, MAX_PATH, varName.bstrVal);
string str(name);
m_videoNames.push_back(str);
VariantClear(&varName);
pProp->Release();
}
pMoniker->Release();
pMoniker = NULL;
}
pClassEnum->Release();
pDevEnum->Release();
return m_videoNames.size();
}
void scaleCov(AVPicture* src, int srcFmt, int srcW, int srcH, AVPicture* dst, int dstFmt, int dstW, int dstH)
{
SwsContext* m_pSws = sws_getContext(srcW, srcH, (AVPixelFormat)srcFmt, dstW, dstH, (AVPixelFormat)dstFmt, SWS_BICUBIC, NULL, NULL, NULL);
int res = sws_scale(m_pSws, src->data, src->linesize, 0, srcH, dst->data, dst->linesize);
sws_freeContext(m_pSws);
}
DWORD WINAPI videoMgr::startCapping(void *param)
{
videoMgr *This = (videoMgr*)param;
AVFormatContext *pFormatCtx;
AVCodecContext  *pCodecCtx;
AVCodec         *pCodec;
av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();
//Register Device
avdevice_register_all();
AVInputFormat *ifmt=av_find_input_format(This->m_shortName.c_str());
if(avformat_open_input(&pFormatCtx, This->m_url.c_str(), ifmt, NULL) != 0)
{
printf("Couldn't open input stream.\n");
return -1;
}
if(avformat_find_stream_info(pFormatCtx, NULL)<0)
{
printf("Couldn't find stream information.\n");
return -1;
}
int videoindex = -1;
for(int i=0; i<pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoindex = i;
break;
}
}
if(videoindex == -1)
{
printf("Couldn't find a video stream.\n");
return -1;
}
pCodecCtx = pFormatCtx->streams[videoindex]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec == NULL)
{
printf("Codec not found.\n");
return -1;
}
if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
{
printf("Could not open codec.\n");
return -1;
}
int ret, got_picture;
av_dump_format(pFormatCtx,0,NULL,0);
#if OUTPUT_YUV420P
FILE *fp_yuv=fopen("output.yuv","wb+");
#endif
while(1)
{
AVPacket packet;
av_init_packet(&packet);
if(av_read_frame(pFormatCtx, &packet)>=0)
{
if(packet.stream_index == videoindex)
{
AVFrame *m_pVideoFrame = av_frame_alloc();
ret = avcodec_decode_video2(pCodecCtx, m_pVideoFrame, &got_picture, &packet);
if(ret < 0)
{
printf("Decode Error.\n");
return -1;
}
if(got_picture)
{
MediaFrame forEncFrm = {0};
static AVRational time_base = {1, 1000};
if(m_pVideoFrame->pkt_pts == AV_NOPTS_VALUE)
m_pVideoFrame->pkt_pts = m_pVideoFrame->pkt_dts;
forEncFrm.pts = av_rescale_q(m_pVideoFrame->pkt_pts, pFormatCtx->streams[videoindex]->time_base, time_base);
forEncFrm.fmt = AV_PIX_FMT_BGR24;
forEncFrm.w = (m_pVideoFrame->width) & 0xFFFFFFF8;
forEncFrm.h = (m_pVideoFrame->height) & 0xFFFFFFF8;
AVFrame *YUVframe = av_frame_alloc();
if(m_pVideoFrame->format != AV_PIX_FMT_BGR24)
{
int numBytes = avpicture_get_size((AVPixelFormat)forEncFrm.fmt, forEncFrm.w, forEncFrm.h);
forEncFrm.buf.resize(numBytes*sizeof(char));
av_image_fill_arrays(YUVframe->data, YUVframe->linesize, (uint8_t*)forEncFrm.buf.data(), (AVPixelFormat)forEncFrm.fmt, forEncFrm.w, forEncFrm.h, 1);
scaleCov((AVPicture*)m_pVideoFrame, m_pVideoFrame->format, forEncFrm.w, forEncFrm.h, (AVPicture*)YUVframe, forEncFrm.fmt, forEncFrm.w, forEncFrm.h);
}else
{
forEncFrm.buf.append((char*)m_pVideoFrame->data[0]);
}
forEncFrm.size = forEncFrm.buf.size();
This->append2VideoBuf(forEncFrm, This->m_RGBFrames, This->m_uiFrmMutex);
av_frame_free(&YUVframe);
}
}
}
av_free_packet(&packet);
Sleep(40);
}
#if OUTPUT_YUV420P
fclose(fp_yuv);
#endif
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return 0;
}
void videoMgr::showCurrentDevice(const string &curVideo)
{
if(m_videoNames.size() <= 0)
return;
bool bFind = false;
list<string>::iterator it = m_videoNames.begin();
for(; it != m_videoNames.end(); it++)
{
string &video = *it;
if(video.compare(curVideo) == 0)
{
string head = "video=";
m_url = head.append(video);
m_shortName = "dshow";
bFind = true;
break;
}
}
if(bFind)
{
startCapture();
}else
{
m_videoNames.clear();
EnumDevices();
showCurrentDevice(curVideo);
}
}
void videoMgr::append2VideoBuf(const MediaFrame &frm,  std::map<int64_t,MediaFrame> &buf, Mutex &mutex)
{
CLock locker(mutex);
buf[frm.pts] = frm;
}
bool videoMgr::getUIFrame(MediaFrame &frame)
{
if ( !getVideoData(frame, m_RGBFrames, m_uiFrmMutex) )
return false;
//实际界面显示的pts应为播放pts
m_playPTS = frame.pts;
return true;
}
void videoMgr::clearVideoFrames(std::map<int64_t, MediaFrame> &pkts)
{
if(pkts.size() <= 0)
return;
std::map<int64_t, MediaFrame>::iterator it=pkts.begin();
for(; it!=pkts.end();)
{
pkts.erase(it++);
}
pkts.clear();
}
bool videoMgr::getVideoData(MediaFrame &frame, std::map<int64_t,MediaFrame> &buf, Mutex &mutex)
{
frame.pts = -1;
CLock locker(mutex);
std::map<int64_t,MediaFrame>::iterator it;
for(it=buf.begin(); it!=buf.end(); it++)
{
MediaFrame &itFrame = it->second;
frame = itFrame;
buf.erase(it++);
break;
}
return (frame.pts>=0);
}
int videoMgr::startCapture()
{
CreateThread(NULL, 0, startCapping, this, 0, NULL);
return 0;
}

附上效果截图:

使用FFmpeg进行摄像头视频采集相关推荐

  1. 摄像头视频采集压缩及传输

    摄像头视频采集压缩及传输 引言: 摄像头基本的功能还是视频传输,那么它是依靠怎样的原理来实现的呢?所谓视频传输: 就是将图片一张张传到屏幕,由于传输速度很快,所以可以让大家看到连续动态的画面,就像放电 ...

  2. ROS安装与Rviz的摄像头视频采集与标定

    文章目录 一.ROS的安装与配置 1.添加 ROS 软件源,将下列命令输入到 Ubuntu 的终端执行 2.添加密钥,将下列命令输入到 Ubuntu 的终端执行 3.安装desktop-full 4. ...

  3. Rviz2 摄像头视频采集与图像标定

    Rviz2 摄像头视频采集与图像标定 准备摄像头 有摄像头的可以直接设置虚拟机的 USB 兼容性来设置即可,但是由于我们的设备没有摄像头,所以这里我们要安装一些摄像头驱动来通过手机摄像头做外设进行使用 ...

  4. 摄像头视频采集压缩及传输 1

    引言 : 摄像头基本的功能还是视频传输,那么它是依靠怎样的原理来实现的呢?所谓视频传输: 就是将图片一张张传到屏幕,由于传输速度很快,所以可以让大家看到连续动态的画面,就像放电影一样.一般当画面的传输 ...

  5. FPGA USB FX2 ov5640摄像头视频采集 驱动CY7C68013A实现 提供2套工程源码和技术支持

    目录 1.前言 2.我这儿已有的 FPGA USB 通信方案 3.CY7C68013A芯片解读和硬件设计 FX2 简介 SlaveFIFO模式及其配置 4.工程详细设计方案 5.vivado工程 6. ...

  6. linux 远程挂载摄像头_如何实现嵌入式Linux下USB摄像头视频采集

    展开全部 在linux下所e5a48de588b662616964757a686964616f31333337613134有设备都是文件.所以对摄像头的操作其实就是对文件的操作.USB摄像头的设备文件 ...

  7. linux下基于qt和v4l2驱动的usb摄像头视频采集与显示,用v4l2和framebuffer实现usb摄像头视频采集并显示...

    Windows程序是基于消息的,不管其封装形式如何,最后都要包含如下代码MSG msg;while(GetMesssage(msg)){TranslateMessage(msg);DispatchMe ...

  8. Linux 下摄像头视频采集与显示

    说明: 1.本文所提及的摄像头不是zc0301p,使用的API不是V4L,显示所使用的上位机不是QT,特此说明. 2.UVC只是一个驱动,如果它能成功驱动摄像头,会在/dev目录下出现video(或v ...

  9. Linux下Qt5: QMediaRecorder的问题,以及使用QCamera相关类进行摄像头视频采集

    版本信息: Qt 5.8.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 5.3.1 20160406 (Red ...

  10. V4L2+Qt5实现摄像头视频采集以及参数控制

    这一段时间在做摄像头控制方面的工作,需要在Linux下实现对摄像头名称和分辨率的获取,同时对亮度.对比度.曝光值等参数进行控制,同时还需要对获取的帧画面进行处理.目前除了图像处理方面,简单的使用V4l ...

最新文章

  1. sql server修改字段编码格式_原理:一条 sql 的执行过程详解
  2. Windows 10第四个大补丸来啦
  3. 【Python-ML】SKlearn库感知器(perceptron) 使用
  4. 万字长文 | 新零售的五重境界
  5. 修改Cmder命令提示符
  6. Spring 事务core 模块-RowMapper
  7. springboot事务回滚源码_002 | 搭上SpringBoot事务源码分析专车
  8. [bbk5307]第76集 第9章 -数据库性能维护 03
  9. 【自用】Android 切割Bitmap为多个小的Bitmap
  10. IntelliJ IDEA 12.0.3 更新版发布
  11. ESP8266串口转wifi/wifi转串口模块
  12. 如何用Vegas制作故障特效
  13. c语言英语教学大纲,C语言教学大纲.doc
  14. CES 2017 DAY1:自动驾驶延续昨日热潮,其他产品更强调实用
  15. linux apache 配置文件位置,Apache主配置文件httpd.conf 详解
  16. pe怎么安装kali linux,U盘+kali+pe三合一教程!装机,存储,渗透,persistence存储问题解决!...
  17. ARP和RARP协议工作原理
  18. 字节跳动最常问的前端面试题:Node.js 基础
  19. 设置图片格式为php,php实现图片格式转换
  20. Java集成SOX开发

热门文章

  1. 手机浏览器调用摄像头扫码
  2. 如何修改服务器的dns,如何修改服务器dns地址
  3. html获取本机ip,获取本机IP地址的实例(JavaScript / Node.js)
  4. Flask 上传自定义头像_1 使用Flask Uploads
  5. imple introduction to LDD
  6. es进行curl请求时报错:missing authentication token for REST request
  7. 关于网络促销活动对大学生购物的影响的调研报告
  8. VLAN-TAG 知识相关
  9. 信号与系统——抽样信号的傅里叶变换
  10. 在抖音做电商:是赚是赔,往往取决于几分钱的算计