Android平台如何不推RTMP|不发布RTSP流|不实时录像|不回传GB28181数据时实时快照?

news2024/9/25 17:19:46

技术背景

我们知道,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平台推送端实时快照的大概设计逻辑,感兴趣的开发者,可以单独跟我沟通讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1989081.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv8由pt文件中读取模型信息

Pytorch的pt模型文件中保存了许多模型信息&#xff0c;如模型结构、模型参数、任务类型、批次、数据集等 在先前的YOLOv8实验中&#xff0c;博主发现YOLOv8在预测时并不需要指定任务类型&#xff0c;因为这些信息便保存在pt模型中&#xff0c;那么&#xff0c;今天我们便来看看…

SpringBoot外部配置文件来修改jar包属性

在jar包所在的文件夹内创建application.yml配置文件&#xff1a; 在yml文件内部添加想要修改的属性值就可以了。 随后输入下面命令来运行jar包&#xff1a; java -jar Big-Deal-Boot-0.0.1-SNAPSHOT.jar 下图是优先级顺序&#xff0c;从上往下依次变高&#xff1a;

Linux Shell编程--变量

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 变量&#xff1a; bash作为程序设计语言和其它高级语言一样也提供使用和定义变量的功能 预定义变量、环境变量、自定义变量、位置变量 一、自定义变…

【Java 第十二篇章】SpringMVC 呜呜,为啥现在面试会问呢

一、简介 Spring MVC 是 Spring 框架的一个模块&#xff0c;用于构建 Web 应用程序&#xff0c;它遵循模型 - 视图 - 控制器&#xff08;MVC&#xff09;设计模式。 二、Spring MVC 的核心组件 1、DispatcherServlet 这是 Spring MVC 的前端控制器&#xff0c;它是整个框架…

Spring Boot获取Bean的三种方式

​ 博客主页: 南来_北往 系列专栏&#xff1a;Spring Boot实战 引言 在Spring Boot中&#xff0c;Bean是一个由Spring IoC容器管理的对象。 Spring Bean是在Spring IoC容器中被实例化、组装和管理的对象&#xff0c;可以视为Spring应用的构建块。它通过提供一套丰富的注…

Centos7安装Zabbix5.0的yum安装失败的解决方案

目前由于Centos7停服以及Zabbix官方限制了其5.0版本在Centos7上安装服务版本&#xff0c;因此可能会导致安装Zabbix5.0的一些组件无法正常安装。 zabbix5.0安装参考&#xff1a;一、zabbix 5.0 部署_zabbix5.0部署-CSDN博客 问题现象 当安装到zabbix的GUI包时报如下错误&…

护眼灯真的可以护眼吗?五款专业护眼灯品牌在线分析

很多新手小白在选购护眼台灯前&#xff0c;都会思考哪个护眼台灯的效果比较好这个问题&#xff0c;因为有的无良商家因为想要降低成本&#xff0c;使用一些廉价低劣的处理器&#xff0c;台灯的电压和功率都难以保证&#xff0c;有的甚至会产生有害的辐射&#xff0c;对人体的健…

Unity入门3——脚本入门

本文使用的代码编辑器为VSCode 安装接口有&#xff1a; 通过将变量设置为public&#xff0c;可以直接在unity的Inspector面板中看到相关变量。此时可直接将需要的素材拖拽到变量处。 Awake()方法 只要物体被加到场景就会执行一次

【vue3】【elementPlus】【国际化】

1.如需从0-1开始&#xff0c;请参考 https://blog.csdn.net/Timeguys/article/details/140995569 2.使用 vue-i18n 模块&#xff1a; npm i vue-i18n3.在 src 目录下创建 locales 目录&#xff0c;里面创建文件&#xff1a;en.js、zh-cn.js、index.js 语言js文件&#xff1a;…

ICC2:检查漏tree的脚本

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 前面写了innovus检查clock 漏tree的脚本&#xff0c;ICC2的脚本也相差不多&#xff0c;只需要替换少部分命令就行。原理就是检查clock pin有没有clock 定义。 foreach pin [ge…

JavaSE之常用API大全

API大全 一、Object toString 返回这个对象的字符串表示形式 当输入一个引用类型的时候,会自动调用该对象的toString方法 默认的toString方法是: 包名.类名十六进制值 Equals 用于比较两个对象是否相同,默认比较内存地址 “”:比较基本类型的时候,比较的是值的大小,而比较引用…

光伏气象站会对环境产生影响吗?

在探讨光伏气象站对环境的影响时&#xff0c;我们首先要明确其核心功能和运作原理。光伏气象站&#xff0c;作为集光伏发电与气象监测于一体的设备&#xff0c;其主要作用在于为光伏电站提供精准的气象数据支持&#xff0c;并辅助电站优化运行&#xff0c;提高发电效率。 从环境…

互联网之光与人工智能之光交相辉映,如何抓住5G人工智能红利

一、互联网之光闭幕 第六届世界互联网大会“互联网之光”虽然已经闭幕&#xff01;“科学与技术”“产业与经济”“人文与社会”“合作与治理”等4大板块20个分论坛&#xff0c;为5G人工智能时代提出了一个新的问题&#xff1a;5GAI 交相辉映&#xff0c;抓住5G人工智能红利&am…

George Danezis谈Mysticeti的吞吐量和低延迟

Sui的新共识引擎Mysticeti已经在主网上开始分阶段推出。Mysten Labs联合创始人兼首席科学家George Danezis在采访中&#xff0c;解释了吞吐量和延迟的区别&#xff0c;以及Sui上的Mysticeti如何结合这两者。 采访视频&#xff1a;https://youtu.be/A4vtyE8obXQ 中文译文&…

【前缀异或和】力扣2588. 统计美丽子数组数目

给你一个下标从 0 开始的整数数组nums 。每次操作中&#xff0c;你可以&#xff1a; 选择两个满足 0 < i, j < nums.length 的不同下标 i 和 j 。 选择一个非负整数 k &#xff0c;满足 nums[i] 和 nums[j] 在二进制下的第 k 位&#xff08;下标编号从 0 开始&#xff0…

1.数据加载时 暂无数据会晃一下再显示数据 2.判断图片加载失败后渲染占位图

工作中问题小记 这种问题正常来说都没有记录的意义 但是我是强迫症 hhh 1.在正常数据渲染时 如果为空我们会渲染(暂无数据占位图)来提示用户 通常是用数据长度来判断 但是他在刷新的时候会先弹出 <暂无数据> 的提示再显示那个数据 解决方法: 搞个标识符 必须等他请求完接…

【电控笔记z14z16】增加霍尔元件分辨率

霍尔传感器用的不多?实际增量编码器更好 z14 假设60度内速度不变 z16(更简单的方法)BLDC

vue前端项目--路由vue-router

1. 路由介绍 我们可以总结一下从早期网站开发到现代单页应用(SPA)的发展过程及其关键概念&#xff1a; 早期的服务器端渲染 (SSR): 早期的网站开发中&#xff0c;服务器负责生成完整的 HTML 页面&#xff0c;并将其发送给客户端展示。 每个 URL 对应一个特定的控制器(Control…

学习笔记 韩顺平 零基础30天学会Java(2024.8.7)

P481 Math方法 利用random返回一个[2,7]之间的随机数&#xff1a; 因为random只能返回[0,1)之间的随机数&#xff0c;因此做一下处理&#xff1a;[(int)(a), (int) (aMath.random()*(b-a1))]&#xff0c;对于Math.random()*(b-a1)&#xff0c;其中b-a1&#xff0c;它乘上[0,1)相…

PFC+DAB原理介绍

三、PFCDAB原理介绍 1、PFC工作原理 三相交流电网的一个公认拓扑是三相全桥 PFC。此拓扑也称为 B6 或“三段桥”。如图显示此拓扑仅使用三相交流输入运行。如果需要单相工作模式。可以轻松地通过增加中性线实现 三相电源包含三个交流相位&#xff0c;通常用 L1、L2 和 L3 表…