技术背景
我们在做Android平台GB28181设备接入模块、轻量级RTSP服务模块和RTMP推流模块的时候,遇到这样的技术诉求,开发者希望把实时CPU占用、电池电量信息等叠加在视频界面。
获取CPU占用率
Android平台获取CPU占用情况,可以读取/proc/stat
文件,解析出各个 CPU 时间参数,然后计算出 CPU 的使用率,示例代码如下:
import android.app.Activity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Process
import android.util.Log
import java.io.BufferedReader
import java.io.FileReader
import java.io.IOException
public class MainActivity extends Activity {
private Handler handler = new Handler(Looper.getMainLooper())
private Runnable runnable
private long prevTotalCpuTime = 0
private long prevIdleCpuTime = 0
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runnable = new Runnable() {
@Override
public void run() {
try {
// 读取 /proc/stat 文件获取 CPU 时间信息
BufferedReader reader = new BufferedReader(new FileReader("/proc/stat"))
String line = reader.readLine()
reader.close()
String[] tokens = line.split("\s+")
long user = Long.parseLong(tokens[2])
long nice = Long.parseLong(tokens[3])
long system = Long.parseLong(tokens[4])
long idle = Long.parseLong(tokens[5])
long iowait = Long.parseLong(tokens[6])
long irq = Long.parseLong(tokens[7])
long softirq = Long.parseLong(tokens[8])
long totalCpuTime = user + nice + system + idle + iowait + irq + softirq
long idleCpuTime = idle
// 计算 CPU 使用率
if (prevTotalCpuTime!= 0 && prevIdleCpuTime!= 0) {
long diffTotalCpuTime = totalCpuTime - prevTotalCpuTime
long diffIdleCpuTime = idleCpuTime - prevIdleCpuTime
float cpuUsage = ((diffTotalCpuTime - diffIdleCpuTime) / (float) diffTotalCpuTime) * 100
Log.d("CPU_USAGE", "CPU Usage: " + cpuUsage + "%")
}
prevTotalCpuTime = totalCpuTime
prevIdleCpuTime = idleCpuTime
} catch (IOException e) {
e.printStackTrace()
}
// 延迟一段时间后再次执行
handler.postDelayed(this, 1000)
}
}
// 启动获取 CPU 使用率的任务
handler.post(runnable)
}
@Override
protected void onDestroy() {
super.onDestroy()
// 停止任务
handler.removeCallbacks(runnable)
}
}
使用BatteryManager类获取电池电量
在 Android 中,可以使用BatteryManager
类来获取电池电量信息。以下是具体步骤:
一、注册广播接收器
在你的 Android 组件(如 Activity 或 Service)中注册一个广播接收器来监听电池状态变化的广播。可以在onCreate
方法中进行注册。
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(batteryReceiver, filter);
这里创建了一个IntentFilter
来指定要监听的广播为电池状态变化广播(Intent.ACTION_BATTERY_CHANGED
),然后使用registerReceiver
方法注册广播接收器。
二、创建广播接收器
创建一个广播接收器类来处理电池状态变化的广播,如下所示:
private BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
int batteryPercentage = (level / (float)scale) * 100
// 这里可以根据获取到的电池电量信息进行相应的处理
}
}
在广播接收器的onReceive
方法中,可以从广播意图中获取电池电量的级别(BatteryManager.EXTRA_LEVEL
)和总刻度(BatteryManager.EXTRA_SCALE
),然后计算出电池电量的百分比。
三、取消注册广播接收器
在适当的时候,如组件的onDestroy
方法中,取消注册广播接收器,以避免资源泄漏:
unregisterReceiver(batteryReceiver);
这样,当电池状态发生变化时,你的广播接收器将会收到通知,并可以获取到电池电量信息进行相应的处理。
需要注意的是,获取电池电量信息可能需要相应的权限。在 AndroidManifest.xml 文件中添加以下权限声明:
name="android.permission.BATTERY_STATS" />
场景应用
以大牛直播SDK的GB28181设备接入模块为例,摄像头实时视频采集,可以叠加上实时CPU占用和实时电量信息,亦或实时时间信息,会对场景带来很大益处,比如CPU占用率或电量信息,简单来说可以通过bitmap把文字读取下来,投递到底层比如jni层即可,非常方便。下面就文字和图片水印做个简短的技术普及。
文字水印
文字水印不再赘述,主要注意的是文字的大小、颜色、位置。
private int postText1Layer(int index, int left, int top) {
Bitmap text_bitmap = makeTextBitmap("文本水印一", getFontSize()+8,
Color.argb(255, 200, 250, 0),
false, 0,false)
if (null == text_bitmap)
return 0
ByteBuffer buffer = ByteBuffer.allocateDirect(text_bitmap.getByteCount())
text_bitmap.copyPixelsToBuffer(buffer)
libPublisher.PostLayerImageRGBA8888ByteBuffer(handle_, index, left, top, buffer, 0,
text_bitmap.getRowBytes(), text_bitmap.getWidth(), text_bitmap.getHeight(),
0, 0, 0, 0, 0,0)
int ret = text_bitmap.getHeight()
text_bitmap.recycle()
return ret
}
png水印
png水印,除了常规的位置需要注意之外,还涉及到logo水印的大小问题,为此,我们添加了缩放效果,可以缩放后,再贴到图层,确保以更合适的比例展示在图层期望位置。
private int postPictureLayer(int index, int left, int top) {
Bitmap bitmap = getAssetsBitmap()
if (null == bitmap) {
Log.e(TAG, "postPitcureLayer getAssetsBitmap is null")
return 0
}
if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
Log.e(TAG, "postPitcureLayer config is not ARGB_8888, config:" + Bitmap.Config.ARGB_8888)
return 0
}
ByteBuffer buffer = ByteBuffer.allocateDirect(bitmap.getByteCount())
bitmap.copyPixelsToBuffer(buffer)
final int w = bitmap.getWidth()
final int h = bitmap.getHeight()
if ( w < 2 || h < 2 )
return 0
int scale_w = 0, scale_h = 0, scale_filter_mode = 0
final float r_w = width_ - left
final float r_h = height_ - top
if (w > r_w || h > r_h) {
float s_w = w
float s_h = h
// 0.85的10次方是0.19687, 缩放到0.2倍差不多了
for ( int i = 0
s_w *= 0.85f
s_h *= 0.85f
if (s_w < r_w && s_h < r_h )
break
}
if (s_w > r_w || s_h > r_h)
return 0
// 如果小于16就算了,太小看也看不见
if (s_w < 16.0f || s_h < 16.0f)
return 0
scale_w = align((int)(s_w + 0.5f), 2)
scale_h = align( (int)(s_h + 0.5f), 2)
scale_filter_mode = 3
}
/*
if ( scale_w > 0 && scale_h > 0)
Log.i(TAG, "postTextLayer scale_w:" + scale_w + ", scale_h:" + scale_h + " w:" + w + ", h:" + h)
libPublisher.PostLayerImageRGBA8888ByteBuffer(handle_, index, left, top, buffer, 0, bitmap.getRowBytes(), w, h,
0, 0, scale_w, scale_h, scale_filter_mode,0)
int ret = scale_h > 0 ? scale_h : bitmap.getHeight()
bitmap.recycle()
return ret
}
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/22329,转载请注明出处。
评论0