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 ...
随机推荐
- Spine学习五- spine动画融合
在许多地方,都需要用到动画融合,unity的新版动画系统已经能够很方便的进行动画融合,那么使用spine的动画状态机的情况下,如何来进行动画融合呢? 官方有两种方案,一种是使用混合动作实现,另一种是使 ...
- 【Gin-API系列】实现路由分组(七)
在之前的文章介绍中我们已经完成了一个API服务的全链路请求设计.调用方式可以看Test目录的代码 // src/test/request_test.go func TestAPI_Request(t ...
- 石子合并2(环形求最优解 区间dp)
题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计算出将N堆石子合并成1 ...
- Resis常用命令及数据类型
1.下载Windows环境redis安装: 2.下载jar包: commons-pool2-2.4.2.jar jedis-2.9.0.jar 3.项目结构: 4.代码说明: package com. ...
- 01 fs模块
1 fs.readFile 异步执行函数 /** fs 读取文件相对路径是相对终端命令行所在的路径 process.cwd()返回终端命令行的绝对路径 * */ fs = require('fs') ...
- 为系统增加删除swap空间
增加 1.创建/home/swap这么一个分区文件.文件大小是512000个block,一般情况下1个block为1k,所以这里空间是512M,这个空间大小自己随意定义. dd if=/dev/zer ...
- 洛谷P1712 [NOI2016]区间 尺取法+线段树+离散化
洛谷P1712 [NOI2016]区间 noi2016第一题(大概是签到题吧,可我还是不会) 链接在这里 题面可以看链接: 先看题意 这么大的l,r,先来个离散化 很容易,我们可以想到一个结论 假设一 ...
- about blog
前言 今天无意中发现了一个小姐姐自己设计的的博客,感觉非常的nice,就随手copy一下,完了感觉效果还蛮好的 end 附上小姐姐的博客以及教程
- JS的全局变量无法给Ajax里的变量赋值
前阶段遇到这么一个问题,在JS定义一个全局变量,JS方法里的其他地方都能使用,偏偏ajax里无法赋值,也不是无法赋值,但赋值总是慢一拍,具体的解决方案如下图所示:
- 本周 GitHub 速览:自动化当道,破密、爬虫各凭本事
作者:HelloGitHub-小鱼干 摘要:安全门外汉,如何在不知道密钥或密码的情况下,破解哈希得到原文,Ciphey 会告诉你当中的密码.说到 auto 智能爬虫会基于上一次的爬虫经历进一步学习以获 ...