JavaCV FFmpeg采集摄像头YUV数据
前阵子使用利用树莓派搭建了一个视频监控平台(传送门),不过使用的是JavaCV封装好的OpenCVFrameGrabber和FFmpegFrameRecorder。
其实在javacpp项目集中有提供FFmpeg的JNI封装,可以直接使用FFmpeg API的来处理音视频数据,下面是一个简单的案例,通过FFmpeg API采集摄像头的YUV数据。
javacpp-ffmpeg依赖:
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>ffmpeg</artifactId>
<version>${ffmpeg.version}</version>
</dependency>
1. 查找摄像头设备
要采集摄像头的YUV数据,首先得知道摄像头的设备名称,可以通过FFmpeg来查找摄像头设备。
ffmpeg.exe -list_devices true -f dshow -i dummy
在我的电脑上结果显示如下:

其中 “Integrated Camera” 就是摄像头的设备名称。
2. 利用FFmpeg解码
采集摄像头数据即将摄像头作为视频流输入,通过FFmpeg解码获取视频帧,然后将视频帧转为YUV格式,最后将数据写入文件即可。
下面是FFmpeg解码的流程:

3. 开发视频帧采集器
根据FFmpeg的解码流程,实现视频帧采集器大概需要经过以下几个步骤:
FFmpeg初始化
首先需要使用av_register_all()这个函数完成编码器和解码器的初始化,只有初始化了编码器和解码器才能正常使用;另外要采集的是设备,所以还需要调用avdevice_register_all()完成初始化。
分配AVFormatContext
接着需要分配一个AVFormatContext,可以通过avformat_alloc_context()来分配AVFormatContext。
pFormatCtx = avformat_alloc_context();
打开视频流
通过avformat_open_input()来打开视频流,这里需要注意的是input format要指定为dshow,可以通过av_find_input_format("dshow")获取AVInputFormat对象。
ret = avformat_open_input(pFormatCtx, String.format("video=%s", input), av_find_input_format("dshow"), (AVDictionary) null);
查找视频流
需要注意的是,查找视频流之前需要调用avformat_find_stream_info(),下面是查找视频流的代码:
ret = avformat_find_stream_info(pFormatCtx, (AVDictionary) null);
for (int i = 0; i < pFormatCtx.nb_streams(); i++) {
if (pFormatCtx.streams(i).codec().codec_type() == AVMEDIA_TYPE_VIDEO) {
videoIdx = i;
break;
}
}
打开解码器
可以通过视频流来查找解码器,然后打开解码器,对视频流进行解码,Java代码如下:
pCodecCtx = pFormatCtx.streams(videoIdx).codec();
pCodec = avcodec_find_decoder(pCodecCtx.codec_id());
if (pCodec == null) {
throw new FFmpegException("没有找到合适的解码器:" + pCodecCtx.codec_id());
}
// 打开解码器
ret = avcodec_open2(pCodecCtx, pCodec, (AVDictionary) null);
if (ret != 0) {
throw new FFmpegException(ret, "avcodec_open2 解码器打开失败");
}
采集视频帧
最后就是采集视频帧了,这里需要注意的是采集摄像头的视频流解码得到的不一定是YUV格式的视频帧,所以需要对视频帧进行转化一下(videoConverter.scale(pFrame))。
public AVFrame grab() throws FFmpegException {
if (av_read_frame(pFormatCtx, pkt) >= 0 && pkt.stream_index() == videoIdx) {
ret = avcodec_decode_video2(pCodecCtx, pFrame, got, pkt);
if (ret < 0) {
throw new FFmpegException(ret, "avcodec_decode_video2 解码失败");
}
if (got[0] != 0) {
return videoConverter.scale(pFrame);
}
av_packet_unref(pkt);
}
return null;
}
4. 将视频帧数据写入文件
通过视频解码之后可以得到YUV格式的视频帧,只需要将视频帧的数据写入文件就可以完成整个摄像头YUV数据的采集流程,RGB数据是存在AVFrame.data[0]中,而YUV格式的数据分三个地方存储,Y数据存在AVFrame.data[0],U数据存在AVFrame.data[1],V数据存在AVFrame.data[2],其中U、V的数量是Y的1/4。
所以只需要根据YUV存储的位置和容量取出数据即可:
int fps = 25;
Yuv420PGrabber g = new Yuv420PGrabber();
g.open("Integrated Camera");
byte[] y = new byte[g.getVideoWidth() * g.getVideoHeight()];
byte[] u = new byte[g.getVideoWidth() * g.getVideoHeight() / 4];
byte[] v = new byte[g.getVideoWidth() * g.getVideoHeight() / 4];
// 1280x720
OutputStream fos = new FileOutputStream("yuv420p.yuv");
for (int i = 0; i < 200; i ++) {
AVFrame avFrame = g.grab();
avFrame.data(0).get(y);
avFrame.data(1).get(u);
avFrame.data(2).get(v);
fos.write(y);
fos.write(u);
fos.write(v);
Thread.sleep(1000 / fps);
}
fos.flush();
fos.close();
g.close();
5. 播放采集的YUV数据
采集的YUV数据可以通过YUV Player Deluxe,效果如下:

也可以通过ffplay来播放,命令如下
ffplay.exe -f rawvideo -video_size 1280x720 yuv420p.yuv
效果如下:

=========================================================
视频帧采集器源码可关注公众号 “HiIT青年” 发送 “ffmpeg-yuv” 获取。

关注公众号,阅读更多文章。
JavaCV FFmpeg采集摄像头YUV数据的更多相关文章
- JavaCV FFmpeg采集麦克风PCM音频数据
前阵子用一个JavaCV的FFmpeg库实现了YUV视频数据地采集,同样的采集PCM音频数据也可以采用JavaCV的FFmpeg库. 传送门:JavaCV FFmpeg采集摄像头YUV数据 首先引入 ...
- FFmpeg采集音视频数据命令
文章转自:https://www.jianshu.com/p/4709ccbda3f9 1.ffmpeg 把文件当做直播推送至服务器 (RTMP + FLV) ffmpeg - re -i demo. ...
- FFMPEG采集摄像头数据并切片为iPhone的HTTP Stream流
一.Windows下面编译ffmpeg 首先需要解决的问题是:在windows下面编译 ffmpeg, 并让其支持dshow, 本人把ffmpeg编译成功了, 但是编译出来的ffmpeg不支持dsho ...
- JavaCV FFmpeg H264编码
上次成功通过FFmpeg采集摄像头的YUV数据,这次针对上一次的程序进行了改造,使用H264编码采集后的数据. (传送门) JavaCV FFmpeg采集摄像头YUV数据 采集摄像头数据是一个解码过程 ...
- JavaCV 采集摄像头及桌面视频数据
javacv 封装了javacpp-presets库很多native API,简化了开发,对java程序员来说比较友好. 之前使用JavaCV库都是使用ffmpeg native API开发,这种方式 ...
- 如何用FFmpeg API采集摄像头视频和麦克风音频,并实现录制文件的功能
之前一直用Directshow技术采集摄像头数据,但是觉得涉及的细节比较多,要开发者比较了解Directshow的框架知识,学习起来有一点点难度.最近发现很多人问怎么用FFmpeg采集摄像头图像,事实 ...
- JavaCV FFmpeg AAC编码
上次成功通过FFmpeg采集麦克风的PCM数据,这次针对上一次的程序进行了改造,使用AAC编码采集后的数据. (传送门) JavaCV FFmpeg采集麦克风PCM音频数据 采集麦克风数据是一个解码过 ...
- JavaCV 采集摄像头和麦克风数据推送到流媒体服务器
越来越觉得放弃JavaCV FFmpeg native API,直接使用JavaCV二次封装的API开发是很明智的选择,使用JavaCV二次封装的API开发避免了各种内存操作不当引起的crash. 上 ...
- ffmpeg Windows下采集摄像头一帧数据,并保存为bmp图片
这里请注意,在编译ffmpeg时,不要使用--disable-devices选项. 使用 --enable-encoder=rawvideo --enable-decoder=rawvideo 启用r ...
随机推荐
- Matrix4x4
Unity3D开发之Matrix4x4矩阵变换 https://www.cnblogs.com/hewei2012/p/4190282.html Matrix4x4 4x4矩阵 http://wiki ...
- 剑指 Offer 45. 把数组排成最小的数
题目描述 输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个. 示例 1: 输入: [10,2] 输出: "102" 示例 2: 输入: ...
- 在Oracle中十分钟内创建一张千万级别的表
小表不会产生性能问题,大表才会.要练习SQL调优,还非得有大表不可.但数据不会自然产生,没有数据时如何创建一张千万级别的大表呢? 之前,我想用Oracle的批量插入语法去插入数据,此语法如下: INS ...
- Zookeeper启动流程分析
前言 之前的Zookeeper协议篇-Paxos算法与ZAB协议通过了解Paoxs算法开始,到Zab协议的两大特性:崩溃恢复和消息广播,学习了Zookeeper是如何通过Zab协议实现高可用,本篇主要 ...
- Python爬取NBA虎扑球员数据
虎扑是一个认真而有趣的社区,每天有众多JRs在虎扑分享自己对篮球.足球.游戏电竞.运动装备.影视.汽车.数码.情感等一切人和事的见解,热闹.真实.有温度. 受害者地址 https://nba.hupu ...
- linux定时删除过期文件
需求说明 每日凌晨0点定时删除/temp目录下的所有一个月未被访问的文件. 脚本实现 linux 终端输入crontab -e,添加定时任务脚本命令 [root@localhost ~]# cront ...
- 软件测试----xml文件介绍
软件测试 目录 软件测试 一.什么是XML?: 二.XML和HTML的差异: 三.XML的特点 1.XML可以自定义标签 2.XML必须包含根元素 如上所示, 3.XML标签对大小写敏感 4.XML ...
- MIPS 架构流水线处理器
该项目系笔者大二时计算机组成课的课程设计,源代码及完整文档请移步 Github 仓库.
- 复习 | 重温jQuery和Zepto的API
jq和zepto很相似有许多共同的api,zepto也出了很多与jq不一样的api,总的来说,两者更相似,但是zepto更轻量一点,正好公司也在用,复习这两个没错 jq中的zepto的事件和ajax我 ...
- JVM运行时数据区--纵向补充--对象的实例化内存布局与访问定位
对象的实例化 创建对象的方式 1.new:最常见的方式(本质是构造器) 变形1 : Xxx的静态方法 变形2 : XxBuilder/XxoxFactory的静态方法 2.Class的newInsta ...