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帧中的最大有效帧作为预览图。这种设计的好处是避免了第一帧是黑色或者不清楚,从而使得用户看起来比较清晰,更好辨别出所录的视频内容;

相关画作

移动式美甲彩绘机
如何下载365app软件

移动式美甲彩绘机

📅 09-24 👁️ 428
DNF天空套找回指南:常见问题及解决方案
365足球

DNF天空套找回指南:常见问题及解决方案

📅 08-15 👁️ 8848
梦幻西游普陀山怎么去
如何下载365app软件

梦幻西游普陀山怎么去

📅 07-13 👁️ 5379