Android平台如何不推RTMP|不发布RTSP流|不实时录像|不回传GB28181数据时实时快照?
技术背景
我们知道,Android平台不管RTMP推送、轻量级RTSP服务模块还是GB28181设备接入模块,早期,如果需要实现截图功能,又不想依赖Android系统接口,最好的办法是,在底层实现快照截图。
快照截图,实际上我们2016年就支持了,不过,需要在RTMP推送、轻量级RTSP服务发布RTSP流、开启实时录像或GB28181设备接入侧已经在传数据的时候,有数据下去,才可以实现截图快照。
本次,我们要实现的是,上述条件不满足的情况下,如何让大牛直播SDK的底层模块(libSmartPublisher.so)实时截图。
技术实现
本文以大牛直播SDK的Camera2Demo为例,废话不多说,上方案:

这里,我们专门封装了 SnapShotImpl.java
/** SnapShotImpl.java* Author: daniusdk.com* WeChat: xinsheng120*/
public SnapShotImpl(String dir, Context context, android.os.Handler handler,SmartPublisherJniV2 lib_sdk, LibPublisherWrapper publisher) {this.dir_ = dir;if (context != null)this.context_ = new WeakReference<>(context);if (handler != null)this.os_handler_ = new WeakReference<>(handler);this.lib_sdk_ = lib_sdk;this.publisher_ = publisher;
}
init_sdk_instance()实现:
protected boolean init_sdk_instance() {if (!publisher_.empty())return true;Context context = application_context();if (null == context)return false;if (null == lib_sdk_)return false;long handle = lib_sdk_.SmartPublisherOpen(context, 0, 3, 1920, 1080);if (0 == handle) {Log.e(TAG, "init_sdk_instance sdk open failed!");return false;}lib_sdk_.SetSmartPublisherEventCallbackV2(handle, new SDKEventHandler(this));lib_sdk_.SmartPublisherSetFPS(handle, 4);publisher_.set(lib_sdk_, handle);update_sdk_instance_release_time();Log.i(TAG, "init_sdk_instance ok handle:" + handle);return true;
}
capture()实现:
protected boolean capture(String file_name, boolean is_update_layers, String user_data) {if (is_null_or_empty(file_name)) {Log.e(TAG, "capture file name is null");return false;}if (publisher_.empty()) {if (!init_sdk_instance()) {Log.e(TAG, "init_sdk_instance failed");return false;}}if (is_update_layers && layer_post_thread_ != null)layer_post_thread_.update_layers();boolean ret = publisher_.CaptureImage(0, 100, file_name, user_data);if (ret)update_sdk_instance_release_time();return ret;
}public boolean capture() {if (is_null_or_empty(dir_)) {Log.e(TAG, "capture dir is null");return false;}String file_name = dir_ + File.separatorChar + make_current_date_time_string() + JPEG_SUFFIX;boolean ret = capture(file_name, true, null);Log.i(TAG, "capture ret:" + ret + ", file:" + file_name);return ret;
}
对应的CaptureImge()封装如下:
public boolean CaptureImage(int compress_format, int quality, String file_name, String user_data_string) {if (!check_native_handle())return false;return OK == lib_publisher_.CaptureImage(get(), compress_format, quality, file_name, user_data_string);
}
模块头文件SmartPublisherJniV2.java接口设计如下:
/*** 新的截图接口, 支持JPEG和PNG两种格式* @param compress_format: 压缩格式, 0:JPEG格式, 1:PNG格式, 其他返回错误* @param quality: 取值范围:[0, 100], 值越大图像质量越好, 仅对JPEG格式有效, 若是PNG格式,请填100* @param file_name: 图像文件名, 例如:/dirxxx/test20231113100739.jpeg, /dirxxx/test20231113100739.png* @param user_data_string: 用户自定义字符串* @return {0} if successful*/public native int CaptureImage(long handle, int compress_format, int quality, String file_name, String user_data_string);
最外层MainActivity.java调用示例如下:
private final LibPublisherWrapper snap_shot_publisher_ = new LibPublisherWrapper();private LibPublisherWrapper publisher_array_[] = {stream_publisher_, snap_shot_publisher_};class ButtonCaptureImageListener implements View.OnClickListener {public void onClick(View v) {if (null == snap_shot_impl_) {snap_shot_impl_ = new SnapShotImpl(image_path_, context_, handler_, libPublisher, snap_shot_publisher_);snap_shot_impl_.start();}startLayerPostThread();snap_shot_impl_.set_layer_post_thread(layer_post_thread_);snap_shot_impl_.capture();}
}
记得投递数据,让有截图快照的数据源传递到底层模块:
@Override
public void onCameraImageData(Image image) {Image.Plane[] planes = image.getPlanes();...for (LibPublisherWrapper i : publisher_array_)i.PostLayerImageYUV420888ByteBuffer(0, 0, 0,planes[0].getBuffer(), y_offset, planes[0].getRowStride(),planes[1].getBuffer(), u_offset, planes[1].getRowStride(),planes[2].getBuffer(), v_offset, planes[2].getRowStride(), planes[1].getPixelStride(),w, h, 0, 0,scale_w, scale_h, scale_filter_mode, rotation_degree);}
onDestroy()的时候,记得停掉,并释放资源:
@Override
protected void onDestroy() {Log.i(TAG, "activity destory!");...if (snap_shot_impl_ != null) {snap_shot_impl_.stop();snap_shot_impl_ = null;}snap_shot_publisher_.release();super.onDestroy();
}
总结
市面上,咱们能看到的实时截图快照,大多是要么直接基于Android系统接口实现,要么只能在RTMP推送、实时录像、轻量级RTSP服务发布流数据、GB28181设备接入侧回传音视频数据的时候才可以用,如果想要更灵活的处理快照数据,特别是,实现GB/T28181-2022关于快照的技术规范诉求,灵活的快照模式,需要底层模块设计的非常灵活才行,以上是Android平台推送端实时快照的大概设计逻辑,感兴趣的开发者,可以单独跟我沟通讨论。
相关文章:
Android平台如何不推RTMP|不发布RTSP流|不实时录像|不回传GB28181数据时实时快照?
技术背景 我们知道,Android平台不管RTMP推送、轻量级RTSP服务模块还是GB28181设备接入模块,早期,如果需要实现截图功能,又不想依赖Android系统接口,最好的办法是,在底层实现快照截图。 快照截图ÿ…...
tomcat文件上传漏洞练习
1、靶场账号注册 vulfocus 注册后邮箱中点击激活 2、首页选择并开启靶场 复制映射的ip和端口 在浏览器输入ip和端口 改成put并把1.jsp中内容复制进去 3打开哥斯拉,连接上面的网址...
项目实战_图书管理系统(简易版)
你能学到什么 一个简单的项目——图书管理系统(浏览器:谷歌)基础版我们只做两个功能(因为其它的功能涉及的会比较多,索性就放在升级版里了,基础版先入个门) 登录: ⽤⼾输⼊账号,密码完成登录功…...
Gazebo之MyRobot建立
Gazebo之MyRobot建立 1. 源由2. 示例Step 1: 新建一个简单世界Step 2: 新建一个模型(model)Step 3: 机器人组成链接(Links)Step 3.1: 新增底盘(Links/Chassis)Step 3.1.1: 惯性属性(Inertial properties)Step 3.1.2: 视觉(Visual)Step 3.1.3: 碰撞(Collision) Step 3.2: 新增左…...
WPF学习(5)- Border控件(边框布局)+GridSplitter分割窗口
严格来说,Border并不是一个布局控件,因为它并不是Panel的子类,而是Decorator装饰器的子类,而Decorator继承于FrameworkElement。我们要先看看它的父类Decorator。 public class Decorator : FrameworkElement, IAddChild {public…...
ADAS芯片及方案
一 ADAS芯片及方案 1.1 高通SA8775P Snapdragon Ride Flex(SA8775P)舱驾融合平台可通过单颗SoC同时支持数字座舱和智能驾驶功能,在CPU、GPU、NPU的处理能力方面具备强大的性能表现与领先优势,支持实现复杂的智能座舱功能&#x…...
5 mysql 查询语句
1.DML:对数据进行增删改查 提示:Execute执行 Execute and Suppress 执行并且抑制这个警告 person表的结构 /* DML:Data Manipulation Language 数据操作语言,对数据进行 增删改查操作,因为査询的操作太频繁和复杂,将…...
从网络上下载并展示图像数据
一、代码 from PIL import Image import requests from io import BytesIO import matplotlib.pyplot as pltimage_url "https://www.alleycat.org/wp-content/uploads/2019/03/FELV-cat.jpg" response requests.get(image_url) # response.content 获取 HTTP 响…...
Machine-Learning 机器学习
目录 基本概念与分类 工作原理 应用领域 发展趋势 机器学习中的深度学习是如何工作的,以及它如何影响其他机器学习算法? 在机器学习中,哪些特定的数据预处理技术最有效,特别是在处理大规模数据集时? 强化学习在…...
CSP 2023 普及组第一轮 - CSP/S 2023初试题 基础部分解析
第 1 题 在 C 中,下面哪个关键字用于声明一个变量, 其值不能被修改?(B) A. unsigned B. const C. static D. mutable 【const声明的变量不可修改】 第 2 题 八进制数 12345670(8) 和 07654321(8) 的和为(D) A. 222222…...
解锁IPython的跨平台魔法:深入探索%%script命令的神秘力量
IPython 的 %%script 魔法命令是一种强大的工具,它允许你在 IPython 环境中执行外部脚本。这个特性特别适用于需要在 IPython Notebook 中直接与 Web 技术交互的场景。下面我将为你详细介绍 %%script 命令的使用方法,并通过代码示例展示其强大功能。 一…...
如何避免项目发布后用户从浏览器WebPack中看到源码
打包前在config->index.js中设置productionSourceMap为false productionSourceMap: false,...
java学习19VUE
VUE NPM npm的全称是Node Package Manager 中文名为Node.js包管理器,是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块(包)的标准。NPM可以方便地从一个全球的代码库中获取并安装Node.js模块,这些模块可以用于构建应用程序、…...
Redis7(四)哨兵、集群
哨兵 吹哨人巡查监控后台master主机是否故障,如果故障了根据投票数自动将某一个从库转换为主库,继续对外服务 哨兵的作用: 监控redis运行状态,包括master和slave当master宕机了,能自动将slave转换为master 哨兵的功能…...
校园课程助手【3】-使用枚举类封装异常优雅处理全局异常
接着2中登录模块补充一个点: //可以看到这里返回给前端控制器的是一个类而不是html页面public RespBean doLogin(Valid LoginVo loginVo, HttpServletRequest request,HttpServletResponse response){return userService.doLogin(loginVo, request, response);}首先…...
LeetCode面试150——58最后一个单词的长度
题目难度:简单 默认优化目标:最小化平均时间复杂度。 Python默认为Python3。 目录 1 题目描述 2 题目解析 3 算法原理及代码实现 3.1 反向遍历 参考文献 1 题目描述 给你一个字符串 s,由若干单词组成,单词前后用一些空格字…...
MySQL——数据库的操作,数据类型,表的操作
MySQL——数据库的操作,数据类型,表的操作 1. 数据库的操作1.1 显示当前数据库1.2 创建数据库舍弃当前所写的SQL语句查看当前数据库服务全局的默认字符集 1.3 使用数据库1.4 查看当前操作的数据库查看MySQL的帮助 1.5 删除数据库 2. 常见数据类型2.1 数值…...
Go 临界资源 安全问题
临界资源安全的问题: 临界资源: 指并发环境中多个 进程/线程/协程 可以共享(都可以调用)的资源/变量,如果在并发环境中处理不当,就会造成一些 严重、问题 func main() {//临界资源a : 10go func() {a 100f…...
安卓常用控件(上)
文章目录 TextViewButtonEditText TextView textview主要用于在界面上显示一段文本信息。 属性名描述id给当前控件定义一个唯一的标识符。layout_width给控件指定一个宽度。match_parent:控件大小与父布局一样;wrap_content:控件大小刚好够包…...
基于 RabbitMQ 实现延迟消息的订单处理流程
文章目录 订单创建流程1. 商品查询与订单数据初始化2. 总价计算与订单保存3. 扣减库存与购物车清理4. 延迟消息与支付状态检测 订单延迟消息监听器支付成功与订单取消1. 订单支付成功2. 订单取消与库存恢复 总结 在现代电商系统中,订单处理是一个复杂且关键的环节。…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
ubuntu中安装conda的后遗症
缘由: 在编译rk3588的sdk时,遇到编译buildroot失败,提示如下: 提示缺失expect,但是实测相关工具是在的,如下显示: 然后查找借助各个ai工具,重新安装相关的工具,依然无解。 解决&am…...
Element-Plus:popconfirm与tooltip一起使用不生效?
你们好,我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip,产品要求是两个需要结合一起使用,也就是鼠标悬浮上去有提示文字,并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…...
简单聊下阿里云DNS劫持事件
阿里云域名被DNS劫持事件 事件总结 根据ICANN规则,域名注册商(Verisign)认定aliyuncs.com域名下的部分网站被用于非法活动(如传播恶意软件);顶级域名DNS服务器将aliyuncs.com域名的DNS记录统一解析到shado…...
Python打卡训练营学习记录Day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
关于疲劳分析的各种方法
疲劳寿命预测方法很多。按疲劳裂纹形成寿命预测的基本假定和控制参数,可分为名义应力法、局部应力一应变法、能量法、场强法等。 1名义应力法 名义应力法是以结构的名义应力为试验和寿命估算的基础,采用雨流法取出一个个相互独立、互不相关的应力循环&…...
android关于pthread的使用过程
文章目录 简介代码流程pthread使用hello_test.cppAndroid.bp 编译过程报错处理验证过程 简介 android开发经常需要使用pthread来编写代码实现相关的业务需求 代码流程 pthread使用 需要查询某个linux函数的方法使用,可以使用man 函数名 // $ man pthread_crea…...
code-server安装使用,并配置frp反射域名访问
为什么使用 code-server是VSCode网页版开发软件,可以在浏览器访问编程,可以使用vscode中的插件。如果有自己的服务器,使用frp透传后,域名访问在线编程,使用方便,打开的服务端口不需要单独配置,可…...
