zoukankan      html  css  js  c++  java
  • Android高帧率手机引发的省电需求

    随着高帧率手机的普及,在很多APP内需要限制手机的帧率来进行省电优化。今天的例子就是视频(直播/点播)播放的软件。

    推流优化

    首先我们说,在视频采集时,有两种采集方式:屏幕采集和camera采集。

    camera采集

    这里我们可以直接限制camera的采集频率。这里有几个优化方案供参考

    android.hardware.camera2.params.StreamConfigurationMap

    现在的很多手机采集一般为50HZ-60HZ,部分低端机前置为30HZ(** 也有部分安卓机器的Camera接口无法实现30FPS及以上的数据采集频率,导致FPS始终为20,这里可以灵活判断当前帧率采取优化 **),所以这里需要手动设置StreamConfigurationMap的采集帧率为30HZ,注意:这里设置采集范围的时,fpsMax需要大于fpsMin,且需要是30的倍数。

    不仅需要优化帧率,在采集视频时推荐采集低分辨率的视频。CameraX 会自动选择内部 Camera2 界面分辨率,默认目标分辨率设置为 640x480,Camera最大支持1080P的视频输出。( ** 如果你希望采集的视频值大于640x480时,那么你需要参考使用 setTargetResolution 或者 settargetaspectratio 这两个方法 **)。这里推荐你使用360*640或更低的分辨率,设置方法为

    val imageAnalysis = ImageAnalysis.Builder()
        .setTargetResolution(Size(640, 360))
        .build()
    

    另外,你可以在你的推流SDK中打开硬件支持,如果你是手动推流,你可以自己打开硬件支持(APP中是默认开启的,但是推流的SDK貌似都不是)

    //下面三种方式任选其一即可。
    //在清单文件的application或者activityzhong
    <application android:hardwareAccelerated="true" ...>
    //你的activity中
    window.setFlags(
           WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
           WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
    )
    //在你的view中
    myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
    

    或者你可以使用MediaCodec,具体参考这篇文章,写的很不错:Android 用MediaCodec实现视频硬解码

    MediaCodec官方文档:https://developer.android.com/reference/android/media/MediaCodec

    屏幕采集:

    这里我就简单说一下通过MediaProjectionManager采集视频的方案,简单多了:

            //设置音频来源
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            //设置视频来源
            mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
            //输出的录屏文件格式
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            //录屏文件路径
            mMediaRecorder.setOutputFile( mRecordFilePath );
            //视频尺寸
            mMediaRecorder.setVideoSize(mRecordWidth, mRecordHeight);
            //音视频编码器
            mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            //比特率
            mMediaRecorder.setVideoEncodingBitRate((int) (mRecordWidth * mRecordHeight * 3.6));
            //视频帧率
            mMediaRecorder.setVideoFrameRate(20);
    

    这是MediaProjectionManager的一些属性,在开始录制之前你设置其中的一些属性即可。例如分辨率,比特率,以及帧率。

    一般如果是人直播,可以设置为25FPS,游戏直播可以设置为35-45,具体可以自行判断。比特率是影响速度的一大因素,也是直接影响画质的一大因素。如果是画面变化快的游戏或者人物直播,可以适当调低。

    播放优化

    视频播放就简单多了。如果是你自定义的播放view,我们只需要限制view的帧率即可。在上面的方法中,我们看到mMediaRecorder.setVideoFrameRate(20);这样限制帧率的方法存在,那么在我们自定义的view中有没有这样的方法?答案是有

    推荐setFrameRate()方法

    首先,这是一个API29以上的方法…,如果你的兼容用户低于30,那么请暂时忽略这部分。

    1. Surface.setFrameRate()
    2. SurfaceControl.Transaction.setFrameRate()
    3. ANativeWindow_setFrameRate()
    4. ASurfaceTransaction_setFrameRate()

    使用方法:

    1 public void setFrameRate (float frameRate, int compatibility)
    
    2 public SurfaceControl.Transaction setFrameRate (SurfaceControl sc, float frameRate, int compatibility)
    
    ///------------------NDK------------------///
    
    3 int32_t ANativeWindow_setFrameRate(
      ANativeWindow *window,
      float frameRate,
      int8_t compatibility
    )
    
    4 void ASurfaceTransaction_setFrameRate(
      ASurfaceTransaction *transaction,
      ASurfaceControl *surface_control,
      float frameRate,
      int8_t compatibility
    )
    

    c++中(有问题,在改)

    
    SDL_Event event;
    
    static int time = 0;//时间记录
    static float fps=20;//你需要的fps
    
    //time = SDL_GetTicks() 或者你给一个初始值,在开始之前设置最好
    
    while(running){
    
            while (SDL_PollEvent(&event)) 
            {
                SDL_WaitEvent(&event);
                OnEvent(&event);
                time = SDL_GetTicks();
            }
    
            if(SDL_GetTicks()-time>(1000/fps))
            {
                time = SDL_GetTicks();
                OnUpdate();
                OnRender();
            }
    
    }
    
    

    native中

    话不多说,直接上代码:

    //自定义surfaceview,然后在绘制方法中
    long time = System.currentTimeMillis();
    drow或者其他的绘制方法
    //这里的30是1000/30约等于33帧的意思
    while((System.currentTimeMillis() - time) <= 30) {    
    	Thread.yield();  //yield我个人感觉是最佳选择,但是没法控制,类似你一直Thread.Sleep(0)一样,精细的同学可以考虑Thread.sleep(30-(System.currentTimeMillis() - time));不过因为这里是动态方法,你需要考虑到可能造成超时的问题,我的方案是直接在catch中也写上刷新方法…
    }
    
    

    以上就是大致的意思。总的来说,无非就集中方案,就是分用处去限制罢了。

  • 相关阅读:
    字符串补充、计算属性、监听属性、vue的项目开发
    斗篷指令、属性指令、表单指令、条件指令、循环指令、js的Array操作、前台数据库、
    Vue框架、挂载点el、插值表达式、过滤器、文本指令、事件指令、js对象补充、js函数补充
    浅谈Mysql和Redis区别
    asyncio
    塞班
    使用conda安装包时出现CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://repo.anaconda.com/pkgs/free/win-64/repodata.json.bz2>
    Anaconda 安装出现的conda无法使用问题
    广度优先搜索与网络爬虫
    loadrunner安装常见问题
  • 原文地址:https://www.cnblogs.com/frrj/p/14239439.html
Copyright © 2011-2022 走看看