一、模块划分

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

    韦东山嵌入式开发板小结1 一.连接[开发板-win10-虚拟机] 1.播放虚拟机VMware的ubuntu 16.04,设置win10和 虚拟机处于同一网段 >>>ipconfig ...

  2. 【嵌入式Linux(基础篇)】嵌入式Linux底层系统开发流程和应用开发流程

    1.嵌入式Linux系统体系架构 一个完整的嵌入式Linux系统体系架构如图,大概可以分为三步: 硬件PCB板设计 底层系统开发 应用开发 2.硬件PCB设计流程 ① 获取所用芯片芯片手册: ② 建立 ...

  3. 韦东山第1期-学习笔记-3

    韦东山第1期视频-第9课.知识点简单,仅用于回顾.弱点补充.注意Makefile变量.函数的使用,要会分析.更改Makefile. 课表: 1.C语言指针相关 二.Makefile

  4. 韦东山第1期-学习笔记-4

    韦东山第1期视频-第6-7课.上手韦东山JZ2440开发板,配置软硬件环境.另外对几款代码查看软件进行了简要说明(常用,没有罗列) 一.课表: 二.知识图谱:

  5. 韦东山第1期-学习笔记-2

    韦东山第1期视频-第2-4课.知识点简单,仅用于回顾.弱点补充. 课表: 思维导图:

  6. 002_韦东山嵌入式Linux应用开发基础_实操碰到的问题集锦

    嵌入式Linux应用开发基础_韦东山教程思考笔记 配合<嵌入式Linux应用开发完全手册V5.1_IMX6ULL_Pro开发板> 文件目录 访问根/目录下,Filesystem Root目 ...

  7. 用OpenJTAG烧写程序到Flash—— 韦东山嵌入式Linux视频学习笔记03

    说明:本文仅在Windows环境下实验. 韦东山的JZ2440(v2),可以选择从Nor Flash启动,也可以选择从Nand Flash启动,不管从哪里启动,都需要Flash上有程序,没有程序的话, ...

  8. 如何告别半途而废——韦东山嵌入式Linux视频学习笔记00

    今天终于从柜子里翻出了韦东山的板子--JZ2440(V2),又翻出了当时买板子赠送的光盘,是的,我又要重新学习了.其实说"重新"是不对的,我当初就没有学完,学到一半放弃了(惭愧啊) ...

  9. 韦东山 嵌入式Linux应用开发基础知识 下【串口 IIC SPI

    10 串口 因为UART没有时钟信号,无法控制何时发送数据,也无法保证双方按照完全相同的速度接收数据.因此,UART为每个字节添加额外的起始位和停止位,以帮助接收器在数据到达时进行同步: 双方还必须事 ...

  10. 韦东山 嵌入式Linux应用开发基础知识 上【gcc makefile 输入设备

    1 main的输入参数,并且在命令行运行文件的时候输入 我的练习 先写了个单纯输出的hello 按照教程里那样写hello 所以gcc编译过程应该是 先创建一个.c文件 gcc -c -o hello ...

最新文章

  1. 从零开始一起学习SLAM | SLAM有什么用?
  2. (020)java后台开发之JAVA集合中的List接口
  3. exit(0) exit(1) return() 3个的区别
  4. CSS Grid布局(3)
  5. matlab db(X R),matlab操作sqlite数据库
  6. 查看anaconda环境下各个包的版本
  7. 扇贝有道180923每日一句
  8. spring 实现小程序抖音去水印后台
  9. 佳佳mpg格式转换器免费版 v12.4.0.0
  10. 干货!基于语义生成概率的无监督常识问答方法——清华CoAI小组牛艺霖
  11. nginx安装三大的命令的解释./configure make make install
  12. 解压文件到服务器是什么意思,linux中zip文件解压命令是什么
  13. 二维码(微信二维码)缓存问题的解决方法
  14. 我成功转型大厂数据分析师后,总结了这些经验…
  15. 小程序电商商城怎么搭建?
  16. Kotlin协程在项目中的实际应用
  17. 西电保研至东南经验贴
  18. Thinkpad笔记本散热器与风扇的寿命与清理问题
  19. Win7 XP 自动登录(取消每次登录Administration界面)
  20. Ubuntu16.04安装ROS教程

热门文章

  1. WindowsServer2016系统中,快速搭建FTP服务器,作为文件服务器
  2. overleaf中使用orcidlink给 ieee access加ORCID时遇到的tikz问题
  3. Padavan启用ipv6并允许公网访问内网
  4. Ubuntu安装FreeSWITCH亲测
  5. axure element ui素材_Element - 饿了么团队出品的神级桌面 UI 组件库
  6. tomcat 如何查看tomcat版本及位数
  7. hmcl手机版_hmcl启动器手机版下载-hmcl启动器 安卓版v1.1.4-PC6安卓网
  8. Ubuntu 字体安装以及 vscode字体配置
  9. matlab画图标签,Matlab绘图
  10. matlab 机械振动,MATLAB使用教程之用MATLAB仿真机械振动.doc