Android 13 录屏流程

简介: Android 13 录屏流程

在Android13 中录屏有个专门的类 ScreenMediaRecorder.java。我们先看ScreenMediaRecorder#start()方法:

// ScreenMediaRecorder.java
    void start() throws IOException, RemoteException, RuntimeException {
        Log.d(TAG, "start recording");
        // 准备录屏
        prepare();
        // 开始录屏
        mMediaRecorder.start();
        // 开始内部音频录制
        recordInternalAudio();
    }

这个 ScreenMediaRecorder#start()RecordingService.java 的 onStartCommand() 方法里被调用。

接着看 ScreenMediaRecorder#prepare() 准备录屏:

// ScreenMediaRecorder.java
    private void prepare() throws IOException, RemoteException, RuntimeException {
        //Setup media projection
        // 拉起 MEDIA_PROJECTION_SERVICE
        IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
        IMediaProjectionManager mediaService =
                IMediaProjectionManager.Stub.asInterface(b);
        IMediaProjection proj = null;
        proj = mediaService.createProjection(mUser, mContext.getPackageName(),
                    MediaProjectionManager.TYPE_SCREEN_CAPTURE, false);
        IBinder projection = proj.asBinder();
        mMediaProjection = new MediaProjection(mContext,
                IMediaProjection.Stub.asInterface(projection));
        // 创建文件、设置格式
        File cacheDir = mContext.getCacheDir();
        cacheDir.mkdirs();
        mTempVideoFile = File.createTempFile("temp", ".mp4", cacheDir);
        // 设置媒体记录器
        // MediaRecorde 主要提供了一些方法用来支持录屏录音
        mMediaRecorder = new MediaRecorder();
        // 设置音频源
        if (mAudioSource == MIC) {
            // 设置声音来源,一般传入 MediaRecorder. AudioSource.MIC参数指定录制来自麦克风的声音。(这里如果只录屏可以不设置)
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
        }
        // 设置用于录制的视频来源。如屏幕等
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        // 设置所录制的音视频文件的格式。
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        // 设置视频
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        wm.getDefaultDisplay().getRealMetrics(metrics);
        int refreshRate = (int) wm.getDefaultDisplay().getRefreshRate();
        int[] dimens = getSupportedSize(metrics.widthPixels, metrics.heightPixels, refreshRate);
        int width = dimens[0];
        int height = dimens[1];
        refreshRate = dimens[2];
        int vidBitRate = width * height * refreshRate / VIDEO_FRAME_RATE
                * VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO;
        // 设置视频的编码格式
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mMediaRecorder.setVideoEncodingProfileLevel(
                MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
                MediaCodecInfo.CodecProfileLevel.AVCLevel3);
        // 设置要拍摄的宽度和视频的高度,最高只能设置640x480
        mMediaRecorder.setVideoSize(width, height);
        // 设置录制视频的捕获帧速率
        mMediaRecorder.setVideoFrameRate(refreshRate);
        // 设置所录制视频的编码位率
        mMediaRecorder.setVideoEncodingBitRate(vidBitRate);
        // 设置录制会话的最长持续时间(以ms为单位)
        mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
        // 设置最大文件大小
        mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
        // 设置音频
        if (mAudioSource == MIC) {
            // 设置音频编码格式
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
            mMediaRecorder.setAudioChannels(TOTAL_NUM_TRACKS);
            // 设置所录制视频的编码位率
            mMediaRecorder.setAudioEncodingBitRate(AUDIO_BIT_RATE);
            mMediaRecorder.setAudioSamplingRate(AUDIO_SAMPLE_RATE);
        }
        // 设置录制的音频文件的保存位置
        mMediaRecorder.setOutputFile(mTempVideoFile);
        // 准备录制
        mMediaRecorder.prepare();
        // Create surface
        mInputSurface = mMediaRecorder.getSurface();
        // VirtualDisplay类代表一个虚拟显示器,需要调用DisplayManager 类的 createVirtualDisplay()方法,
        // 将虚拟显示器的内容渲染在一个Surface控件上,即 捕捉屏幕了。
        mVirtualDisplay = mMediaProjection.createVirtualDisplay(
                "Recording Display",    // 实际的流媒体显示实体名字,不能为null;
                width,                  // 实际的流媒体显示实体的宽度,单位为像素,必须大于0
                height,                 // 实际的流媒体显示实体的高度,单位为像素,必须大于0;
                metrics.densityDpi,     // 实际的流媒体显示实体的像素密度,单位为dp,必须大于0;
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,    // 实际的流媒体显示实体标志的结合
                mInputSurface,          // 播放流媒体的surface实例,可为null,
                null,                   // 实际的流媒体显示实体状态改变时的回调方法,可能为null;
                null);                  // 调用第 7 个参数回调方法的handler
        mMediaRecorder.setOnInfoListener(mListener);
        if (mAudioSource == INTERNAL ||
                mAudioSource == MIC_AND_INTERNAL) {
            mTempAudioFile = File.createTempFile("temp", ".aac",
                    mContext.getCacheDir());
            mAudio = new ScreenInternalAudioRecorder(mTempAudioFile.getAbsolutePath(),
                    mMediaProjection, mAudioSource == MIC_AND_INTERNAL);
        }
    }

上述 prepare() 方法,主要:进行了拉起后台服务,创建VirtualDisplay用于屏幕参数设定、设置录屏问文件路径等操作;

再接着看ScreenMediaRecorder#end()方法:

// ScreenMediaRecorder.java
    void end() {
        //jingtao.guo add try catch for TFBAAA-341 crash
        try {
            mMediaRecorder.stop();
            mMediaRecorder.release();
            mInputSurface.release();
            mVirtualDisplay.release();
            mMediaProjection.stop();
            mMediaRecorder = null;
            mMediaProjection = null;
            stopInternalAudioRecording();
            Log.d(TAG, "end recording");
        } catch (RuntimeException e) {
            Log.e(TAG, "end recording" + e.getMessage());
        }
    }

end() 方法结束录屏,调用了mMediaRecorder的stop与release方法,stopInternalAudioRecording()方法中通过 mAudio.end()方法来停止录音。

缩略图

在谷歌原生设计中,录屏的缩略图并非是视频的第一帧,而是前20帧中的最大有效帧作为预览图。这种设计的好处是避免了第一帧是黑色或者不清楚,从而使得用户看起来比较清晰,更好辨别出所录的视频内容;

相关文章
|
9月前
|
安全 算法 小程序
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
563 28
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
|
8月前
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码android版环境配置流程及功能明细
部署需基于 CentOS 7.9 系统,硬盘不低于 40G,使用宝塔面板安装环境,包括 PHP 7.3(含 Redis、Fileinfo 扩展)、Nginx、MySQL 5.6、Redis 和最新 Composer。Swoole 扩展需按步骤配置。2021.08.05 后部署需将站点目录设为 public 并用 ThinkPHP 伪静态。开发环境建议 Windows 操作系统与最新 Android Studio,基础配置涉及 APP 名称修改、接口域名更换、包名调整及第三方登录分享(如 QQ、微信)的配置,同时需完成阿里云与腾讯云相关设置。
|
10月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
640 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
9月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
10月前
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
315 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
11月前
|
缓存 前端开发 Android开发
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
492 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
|
11月前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
340 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
11月前
|
测试技术 Android开发 开发者
【03】优雅草央千澈详解关于APP签名以及分发-上架完整流程-第三篇安卓APP上架华为商店后面的步骤-华为应用商店相对比较麻烦一些-华为商店安卓上架
【03】优雅草央千澈详解关于APP签名以及分发-上架完整流程-第三篇安卓APP上架华为商店后面的步骤-华为应用商店相对比较麻烦一些-华为商店安卓上架
181 16
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
249 6
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
Android面试高频知识点(4) 详解Activity的启动流程
246 3