嵌入式linux摄像头录像存储,韦东山嵌入式Linux_3期之USB摄像头监控_手机App增添录像功效(二)...
一、模块划分
i) (主体模块)视频采集播放
ii) 显示模式切换
iii) 摄影
iv) 录像
v) fps显示
vi) 录像的浏览和删除
二、各模块的实现
2.1(主体模块)视频采集播放
2.1.1 参考资料:
主体框架的流程,可参考雷霄骅的上述博文,这里不再赘述
帧显示的流程,大致如下:
2.2 显示模式切换
实现思绪:行使av_filter的scale和pad功效,对获取到的每一个原始帧举行缩放和需要的四边填充。
至于怎样实现两种显示模式下的scale参数(以及pad参数)的切换, 尚未找到最优方式(经测,av_opt_set()只对draw_text有用(详见下文:2.5 fps显示),而对scale和pad无效),
现在暂时接纳较笨的设施:
1)界说两个filter_descr模板,以及对应的AVFilterGraph、AVFilterContext
/* 用于保持长宽比显示模式 */
const char *m_filter_descr_template = "scale=%d:%d,pad=%d:%d:%d:%d:blue,drawtext=fontfile=/sdcard/data/FreeSerif.ttf:fontsize=20:text=fps:x=(w-tw-%d):y=%d";
char m_filter_descr[200];
/* 用于全屏显示模式 */
const char *m_filter_descr2_template = "scale=%d:%d,pad=%d:%d:%d:%d:blue,drawtext=fontfile=/sdcard/data/FreeSerif.ttf:fontsize=20:text=fps:x=(w-tw-5):y=5";
char m_filter_descr2[200];
/* 用于保持长宽比显示模式 */
AVFilterContext *m_buffersink_ctx1;
AVFilterContext *m_buffersrc_ctx1;
AVFilterGraph *m_filter_graph1;
/* 用于全屏显示模式 */
AVFilterContext *m_buffersink_ctx2;
AVFilterContext *m_buffersrc_ctx2;
AVFilterGraph *m_filter_graph2;
2)初始化时,先挪用keep_img_AR()来预先盘算好两种显示模式对应的filter_descr的值
int keep_img_AR(int nSrcW ,int nSrcH,int nDstW, int nDstH )
{
/* 盘算保持宽高比例后上下有黑边,照样左右有黑边,黑边若干 */
int imgW = 0,imgH = 0;
int padW = 0,padH = 0;
//必须规整为2的倍数,否则ffmpeg盘算pad时会报错:Input area not within the padded area or zero-sized
nDstW = nDstW/2*2;
nDstH = nDstH/2*2;
imgW = nSrcW*nDstH/nSrcH/2*2;
imgH = nSrcH*nDstW/nSrcW/2*2;
if(imgW
padW=(nDstW-imgW)/2;
imgH = nDstH/2*2;
//imgW = -1;
}
else if(imgH
padH=(nDstH-imgH)/2;
imgW = nDstW/2*2;
//imgH = -1;
}
sprintf(m_filter_descr, m_filter_descr_template, imgW, imgH, nDstW, nDstH, padW, padH, padW+5, padH+5);
sprintf(m_filter_descr2, m_filter_descr2_template, nDstW, nDstH, nDstW, nDstH, 0, 0);
return 1 ;
}
3)然后挪用init_filters()来初始化m_filter_graph1、m_buffersink_ctx1、m_buffersrc_ctx1和m_filter_graph2、m_buffersink_ctx2、m_buffersrc_ctx2
4)而切换播放模式,实在就是切换(m_filter_graph1、m_buffersink_ctx1、m_buffersrc_ctx1)和(m_filter_graph2、m_buffersink_ctx2、m_buffersrc_ctx2)三元组
/**
* 播放视频时保持长宽比
*/
void playVideoKeepAspectRatio()
{
m_play_video_mode = PLAY_VIDEO_KEEP_ASPECT_RATIO;
m_filter_graph = m_filter_graph1;
m_buffersrc_ctx = m_buffersrc_ctx1;
m_buffersink_ctx = m_buffersink_ctx1;
}
/**
* 播放视频时填满显示区域
*/
void playVideoFullScreen( )
{
m_play_video_mode = PLAY_VIDEO_FULL_SCREEN;
m_filter_graph = m_filter_graph2;
m_buffersrc_ctx = m_buffersrc_ctx2;
m_buffersink_ctx = m_buffersink_ctx2;
}
注:关于显示模式切换,另一种实现的设施是行使sws_scale()和av_picture_pad(),参考:使用ffmpeg的lib库实现视频窗口 原始宽高比例/拉伸铺满
但代码量较大,而且经测试,发现有些问题,好比:
– 加上av_filter的draw_text后,fps的显示会泛起小幅度的上下跳动,缘故原由待查
– fps的定位较难实现(由于要考虑到pad的宽度)
以是最终没有接纳这个设施(但keep_img_AR()里盘算scale和pad的算法参考了这篇文章)。
2.3 摄影
实现思绪:
1)界说m_pFrameCur代表当前获取到的帧
2)在视频播放函数videoStreamStartPlay()的while循环里,用av_frame_ref(m_pFrameCur, pFrame)使m_pFrameCur指向当前获取到的帧
3)__save_frame_2_jpeg(file_path, m_pFrameCur, m_input_codec_ctx->pix_fmt)实现把当前帧保留到指定的文件中
2.4 录像
该文章的demo里,把录像功效很好的封装在了一个类CAVOutputStream里,我基本上原封不动的拿来用于录像功效的底层实现。
我所添加的事情,是在视频播放函数videoStreamStartPlay()的while循环里,挪用状态机video_capture_state_machine(),代码大致如下:
void video_capture_state_machine(AVFrame *pFrame)
{
switch(m_video_capture_state)
{
case VIDEO_CAPTURE_START:
LOGD("VIDEO_CAPTURE_START");
m_start_time = av_gettime();
m_OutputStream.SetVideoCodec(AV_CODEC_ID_H264); //设置视频编码器属性
if(true == m_OutputStream.OpenOutputStream(m_save_video_path.c_str()))
m_video_capture_state = VIDEO_CAPTURE_IN_PROGRESS;
else
m_video_capture_state = VIDEO_CAPTURE_IDLE;
break;
case VIDEO_CAPTURE_IN_PROGRESS:
LOGD("VIDEO_CAPTURE_IN_PROGRESS");
m_OutputStream.write_video_frame(m_input_format_ctx->streams[m_video_stream_index], m_input_format_ctx->streams[m_video_stream_index]->codec->pix_fmt, pFrame, av_gettime() - m_start_time);
break;
case VIDEO_CAPTURE_STOP:
LOGD("VIDEO_CAPTURE_STOP");
m_OutputStream.CloseOutput();
m_video_capture_state = VIDEO_CAPTURE_IDLE;
break;
default:
if(m_video_capture_state == VIDEO_CAPTURE_IDLE){
LOGD("VIDEO_CAPTURE_IDLE");
}
else{
LOGD("m_video_capture_state: %d", m_video_capture_state);
}
break;
}//eo switch(m_video_capture_state)
}
而native层和JAVA层的接口如下:
/* 最先录像 */
void videoStreamStartCapture(const char* file_path)
{
m_save_video_path = file_path;
m_video_capture_state = VIDEO_CAPTURE_START;
}
/* 住手录像 */
void videoStreamStopCapture( )
{
m_video_capture_state = VIDEO_CAPTURE_STOP;
}
2.5 fps显示
而fps值的动态显示,是行使av_opt_set(filter_ctx_draw_text->priv, “text”, str_fps, 0 )来实现的。
2.6 录像的浏览和删除
实现思绪:基本上行使了app的原框架,只做了少量改动。主要如下:
1) MainActivity.java
当用户点击“照片”按钮后,弹出AlertDialog,提醒选择浏览类型,然后凭据用户的选择,在startActivity(intent)前,挪用
intent.putExtra(“picturePath”, picturePath);
intent.putExtra(“scan_type”, ScanPicActivity.SCAN_TYPE_VIDEO);
或者
intent.putExtra(“picturePath”, videoRecordPath);
intent.putExtra(“scan_type”, ScanPicActivity.SCAN_TYPE_PIC);
2)ScanPicActivity.java
– 在init()函数中,scan_type = getIntent().getIntExtra(“scan_type”, SCAN_TYPE_PIC);保留当前的浏览类型
– 在每一处涉及“jpeg”字符串的地方,都加入scan_type判断。代码从略,详见项目源代码
3)Generic.java
模仿getShrinkedPic(),添加函数getShrinkedPicFromVideo(),焦点是ThumbnailUtils.createVideoThumbnail()。代码从略,详见项目源代码
参考资料:
1)韦东山嵌入式linux培训3期项目实战之usb摄像头监控,手机App源代码
原文链接:https://www.cnblogs.com/normalmanzhao2003/p/12695432.html
本站声明:网站内容来源于网络,若有侵权,请联系我们,我们将及时处理。
嵌入式linux摄像头录像存储,韦东山嵌入式Linux_3期之USB摄像头监控_手机App增添录像功效(二)...相关推荐
- 韦东山嵌入式开发板小结1
韦东山嵌入式开发板小结1 一.连接[开发板-win10-虚拟机] 1.播放虚拟机VMware的ubuntu 16.04,设置win10和 虚拟机处于同一网段 >>>ipconfig ...
- 【嵌入式Linux(基础篇)】嵌入式Linux底层系统开发流程和应用开发流程
1.嵌入式Linux系统体系架构 一个完整的嵌入式Linux系统体系架构如图,大概可以分为三步: 硬件PCB板设计 底层系统开发 应用开发 2.硬件PCB设计流程 ① 获取所用芯片芯片手册: ② 建立 ...
- 韦东山第1期-学习笔记-3
韦东山第1期视频-第9课.知识点简单,仅用于回顾.弱点补充.注意Makefile变量.函数的使用,要会分析.更改Makefile. 课表: 1.C语言指针相关 二.Makefile
- 韦东山第1期-学习笔记-4
韦东山第1期视频-第6-7课.上手韦东山JZ2440开发板,配置软硬件环境.另外对几款代码查看软件进行了简要说明(常用,没有罗列) 一.课表: 二.知识图谱:
- 韦东山第1期-学习笔记-2
韦东山第1期视频-第2-4课.知识点简单,仅用于回顾.弱点补充. 课表: 思维导图:
- 002_韦东山嵌入式Linux应用开发基础_实操碰到的问题集锦
嵌入式Linux应用开发基础_韦东山教程思考笔记 配合<嵌入式Linux应用开发完全手册V5.1_IMX6ULL_Pro开发板> 文件目录 访问根/目录下,Filesystem Root目 ...
- 用OpenJTAG烧写程序到Flash—— 韦东山嵌入式Linux视频学习笔记03
说明:本文仅在Windows环境下实验. 韦东山的JZ2440(v2),可以选择从Nor Flash启动,也可以选择从Nand Flash启动,不管从哪里启动,都需要Flash上有程序,没有程序的话, ...
- 如何告别半途而废——韦东山嵌入式Linux视频学习笔记00
今天终于从柜子里翻出了韦东山的板子--JZ2440(V2),又翻出了当时买板子赠送的光盘,是的,我又要重新学习了.其实说"重新"是不对的,我当初就没有学完,学到一半放弃了(惭愧啊) ...
- 韦东山 嵌入式Linux应用开发基础知识 下【串口 IIC SPI
10 串口 因为UART没有时钟信号,无法控制何时发送数据,也无法保证双方按照完全相同的速度接收数据.因此,UART为每个字节添加额外的起始位和停止位,以帮助接收器在数据到达时进行同步: 双方还必须事 ...
- 韦东山 嵌入式Linux应用开发基础知识 上【gcc makefile 输入设备
1 main的输入参数,并且在命令行运行文件的时候输入 我的练习 先写了个单纯输出的hello 按照教程里那样写hello 所以gcc编译过程应该是 先创建一个.c文件 gcc -c -o hello ...
最新文章
- 从零开始一起学习SLAM | SLAM有什么用?
- (020)java后台开发之JAVA集合中的List接口
- exit(0) exit(1) return() 3个的区别
- CSS Grid布局(3)
- matlab db(X R),matlab操作sqlite数据库
- 查看anaconda环境下各个包的版本
- 扇贝有道180923每日一句
- spring 实现小程序抖音去水印后台
- 佳佳mpg格式转换器免费版 v12.4.0.0
- 干货!基于语义生成概率的无监督常识问答方法——清华CoAI小组牛艺霖
- nginx安装三大的命令的解释./configure make make install
- 解压文件到服务器是什么意思,linux中zip文件解压命令是什么
- 二维码(微信二维码)缓存问题的解决方法
- 我成功转型大厂数据分析师后,总结了这些经验…
- 小程序电商商城怎么搭建?
- Kotlin协程在项目中的实际应用
- 西电保研至东南经验贴
- Thinkpad笔记本散热器与风扇的寿命与清理问题
- Win7 XP 自动登录(取消每次登录Administration界面)
- Ubuntu16.04安装ROS教程
热门文章
- WindowsServer2016系统中,快速搭建FTP服务器,作为文件服务器
- overleaf中使用orcidlink给 ieee access加ORCID时遇到的tikz问题
- Padavan启用ipv6并允许公网访问内网
- Ubuntu安装FreeSWITCH亲测
- axure element ui素材_Element - 饿了么团队出品的神级桌面 UI 组件库
- tomcat 如何查看tomcat版本及位数
- hmcl手机版_hmcl启动器手机版下载-hmcl启动器 安卓版v1.1.4-PC6安卓网
- Ubuntu 字体安装以及 vscode字体配置
- matlab画图标签,Matlab绘图
- matlab 机械振动,MATLAB使用教程之用MATLAB仿真机械振动.doc