Android 计算视频的fps

Posted 乔彦华

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 计算视频的fps相关的知识,希望对你有一定的参考价值。

监控 游戏 fps 调研

adb shell dumpsys gfxinfo

这种方式反回的数据太大,还监控不到游戏的pfs.,是必须是 android M 版本以上才支持,而且需要拖动屏幕产生的数据才比较准确

dumpsys是一款运行在设备上的Android工具,将 gfxinfo命令传递给dumpsys可在logcat中提供输出,其中包含各阶段发生的动画以及帧相关的性能信息。但是gfxinfo不统计SurfaceView。


dumpsys SurfaceFlinger --latency【这个只支持安卓6以下】(https://wizzie.top/Blog/2020/03/31/2020/200330_android_getFPS/)
命令主要用于获取游戏/视频应用的fps数据。
返回的是安卓当前activity的fps,清楚数据之后,不滑动屏幕是没有数据的,
计算方式   https://www.jianshu.com/p/280ec5c566ea
计算方法比较简单,一般打印出来的数据是129行(部分机型打印两次257行,但是第一部分是无效数据,取后半部分),取len-2的第一列数据为end_time,取len-128的第一列数据为start_time
fps = 127/((end_time - start_time) / 1000000.0)
自己在手机上测试之后发现数据有点出入,每次第一列和第三列数据都是一样得,没法计算
还有一个问题就是怎么把执行完adb 得数据拿出来,只取用到得数据,怎么计算
怎么实时显示数据,计算,延迟怎么处理,

在Android 6系统直接就是SurfaceView
在Android 7系统中可以通过 dumpsys window windows | grep mSurface | grep SurfaceView 然后通过数据截取到
在Android 8系统中可以通过 dumpsys SurfaceFlinger | grep android包名获取到
在这个命令下,执行完得数据不对,没有提示所需要得数据, 正常数据应该是128行数据

版本不同执行得命令也不同,grep 是Linux grep 命令(这个有点不懂)


目前只能使用这个办法,但是获取得数据只有一行,使用java实现得没有,大部分都是C++ ,python

fpsviewer—实时显示fps    https://www.jianshu.com/p/ba1cd424901d     计算出来好像不对,正常设置30帧得话,他一秒就是渲染30帧,但是现在算出来还是60,有点问题(是根据屏幕得刷)
fpsviewer 特点无损FPS实时显示,一段时间的平均帧率和帧率占比
利用Choreographer.FrameCallback的fun doFrame(frameTimeNanos: Long)方法回调里获取数据计算每帧消耗的时长,实时性高且不需要额外的数据获取无其他性能消耗,开启和关闭fpsviewer对帧率的影响远小于1帧。支持一段时间的平均帧率和帧率占比显示,可用于性能优化前后的对比。


使用腾讯的wetest助手
腾讯云测平台提供的客户端FPS方法较上面两种简单,可以直接生成测试报告,缺点是必须要在手机上安装wetest助手的客户端并且手机要root后才能获取到。

FrameLayout
前面几种方式都不合适,需要在调研其他的方法,

大部分方法都是测试app性能得测试,在抓取视频得fps得暂时没有合适得


其他得方式就是通过脚本来抓取数据分析

perfdog   获取fps是通过   adb shell dumpsys SurfaceFlinger --latency 图层名  得到数据里面得第一列  【desiredPresentTime:应用期望提交的时间】 来计算得

 处理128行数据   这个用到得主要是第二列数据

目前找到一种合适得方法,需要先执行adb shell 进入到shell  里面
以综合测试apk为例,执行   dumpsys SurfaceFlinger | grep 包名+activity  得到 SurfaceView命令

在执行   dumpsys SurfaceFlinger --latency "SurfaceView[包名+activity](BLAST)#0"
得到所有得数据128行  其中第一行为  刷新周期   剩下得127行为帧数据

用T2中的数据 每次都是下一行减去上一行得值,最后总和。  转换成秒  用127/转换出来的数据  = fps

多次计算之后,这个公式是可以计算出帧数的,因为计算器算的是整数,精度可能差一点
把小数保留两位之后,得到的数据跟系统,so返回的数据,在截图看来大致是一样的

先把数据保存到本地文件里(因为adb现在执行不了,只能先用死数据),在用的时候取出来,再取的时候,只取中间一列的数据。在遍历计算的时候要考虑他的无效数据,和最后一行不计算的问题,有几行无效数据,在那个坐标下面,把算到的值都加一起除以1000000000,保留两位小数,拿有效数据的总个数除以刚计算出的数据,就是fps.
在计算fps的时候,因为现在会有一个无效数据,需要处理,在循环遍历的时候需要判断是否有无效数据
目前测试的时候,发现每次无效数据只会有一个,在最后一行,不排除有其他的,可能算法还需要在完善


现在又发现一个问题,在小米8se手机上,上面这套adb执行完的结果是跟小米10手机上不一样的,他只有一行,如果按照第一个命令行执行完的结果来执行最后一个adb的时候,他只有127行数据,第一列跟第三列 都为零,在红米K40手机上,执行完最后一个adb 他出来的结果有129行,第一行为刷新率,第二行 是执行的命令,后面127才是帧数据   在vivo手机上出现的是,在刚进入游戏的时候。抓取的是数据是128行数据,但是他前边有好多条数据都是零,在启动游戏过一会后,才能都抓到数据,在其前面刚开始的时候计算会有问题。
在vivo手机上确认是数据再有0  0  0 的时候,数据都是一样的,都当无效数据处理,但是在计算的时候他不需要跟其他手机一样,使用有效数据的行数/计算得出的数据 ,这样得出的结果不对,还需在找其他计算方式 。和其他手机发生冲突,需要解决

jank  计算   
t3-t1>16.7ms,则认为发生一次卡顿

FrameTime  两帧画面间隔耗时

1秒内的卡顿次数
 
PerfDog Jank计算方法:
 
同时满足两条件,则认为是一次卡顿Jank.
 
    ①Display FrameTime>前三帧平均耗时2倍。
    
    ②Display FrameTime>两帧电影帧耗时 (1000ms/24*2=84ms)。
    
 
同时满足两条件,则认为是一次严重卡顿BigJank.
 
    ①Display FrameTime >前三帧平均耗时2倍。
    
    ②Display FrameTime >三帧电影帧耗时(1000ms/24*3=125ms)。

因为这个我是使用的终端进行操作的,每次复制出来在进行计算的,可能需要用python来计算

python tools:计算视频的 FPS,以及总帧数

如何计算一个视频中的总帧数呢,最简单的还是用 FFmpeg,命令如下:

$ffmpeg -i test.avi -vcodec copy -f rawvideo -y /dev/null 2>&1 | tr ^M '\\n' | awk '/^frame=/ print $2'|tail -n 1

这个命令也是粘贴的 stackoverflow 上的(很奇怪的一行命令),结果如下:

或者,我更偏向于第二种方法,用 opencv 来做。

import os
import cv2

video_cap = cv2.VideoCapture('ffmpeg_test.avi')

frame_count = 0
all_frames = []
while(True):
    ret, frame = video_cap.read()
    if ret is False:
        break
    all_frames.append(frame)
    frame_count = frame_count + 1

# The value below are both the number of frames
print frame_count
print len(all_frames)

下面一个问题,如何知道一个视频中的 FPS,即:每秒传输帧数(Frames Per Second))。还是用 cv2 来解决:

import cv2
if __name__ == '__main__' :

    video = cv2.VideoCapture("video.mp4");

    # Find OpenCV version
    (major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')

    if int(major_ver)  < 3 :
        fps = video.get(cv2.cv.CV_CAP_PROP_FPS)
        print "Frames per second using video.get(cv2.cv.CV_CAP_PROP_FPS): 0".format(fps)
    else :
        fps = video.get(cv2.CAP_PROP_FPS)
        print "Frames per second using video.get(cv2.CAP_PROP_FPS) : 0".format(fps)

   video.release(); 

结果如下:

这个更详细的参考:How to find frame rate of a video in OpenCV ?

以上是关于Android 计算视频的fps的主要内容,如果未能解决你的问题,请参考以下文章

android形状属性锁屏密码动态模糊kotlin项目抖音动画记账app视频播放器等源码

Android技术分享| ViewPager2离屏加载,实现抖音上下视频滑动

Android 学习之跳转抖音账号主页或者某一视频页

Android 学习之跳转抖音账号主页或者某一视频页

Android 学习之跳转抖音账号主页或者某一视频页

Android技术分享| ViewPager2离屏加载,实现抖音上下视频滑动