ShareREC for Android全系统手机录屏软件原理解析
当录制完毕时,需要关闭MediaRecorder,并释放VirtualDisplay和MediaProjection,上面代码中的MediaProjection.Callback实例正是为了这个而界说的。下面的代码演示了怎样制止录制操作:
private void stop() {
if (mp != null) {
mp.stop();
if (cb != null) {
mp.unregisterCallback(cb);
}
mp = null;
}
}
方案二:自行实现媒体编码和输出
看完简朴的方案,现在来看一下庞大的方案。ShareREC在这个方案上的实现流程如下图:
移除点击此处添加图片说明文字
ShareREC将全系统录屏功效拆分为抓图、编码和输出3部门。在用户授权抓屏之后,抓图模块率先汇海,建立虚拟屏幕、建立图形缓存、建立回调等等。这内里的图形缓存是自安卓4.4以后提供的ImageReader。和MediaRecorder一样,它也提供了getSurface要领,返回用于更新缓存的surface实例。而且在缓存发生变换时,通过acquireLatestImage要领来获取最新的图片数据。不外由于我们并不知道什么时间缓存会发生变换,因此需要再挪用setOnImageAvailableListener要领设置一个OnImageAvailableListener实例,并通过它的onImageAvailable要领实时获得缓存更新的通知:
private MediaProjectionManager mpm;
private ImageReader ir;
private MediaProjection mp;
private VirtualDisplay vd;
/**
* @param screenSize 屏幕的现实分辨率
* @param videoSize 抓取图片的分辨率
*/
public void startCapturer(final int[] screenSize, final int[] videoSize, final Intent data) {
try {
float densityDpi = getResources().getDisplayMetrics().densityDpi;
int densityDpi = (int) (densityDpi * screenSize[0] / videoSize[0] + 0.5f);
ir = ImageReader.newInstance(videoSize[0], videoSize[1], PixelFormat.RGBA_8888, 4);
ir.setOnImageAvailableListener(this, null);
mp = mpm.getMediaProjection(Activity.RESULT_OK, data);
vd = mp.createVirtualDisplay("ShareREC",
videoSize[0], videoSize[1], (int) densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
ir.getSurface(), null, null);
} catch (Throwable t) {
t.printStackTrace();
}
}
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
if (image != null) {
Image.Plane[] planes = image.getPlanes();
if (planes != null && planes.length > 0) {
int rowStride = planes[0].getRowStride();
ByteBuffer rgba = planes[0].getBuffer();
if (rgba != null) {
// 将rgba数据运送给编码器
offerFrame(rgba, rowStride);
}
}
image.close();
}
}
上面的代码演示了怎样通过组合VirtualDisplay和ImageReader来实现一连抓图。需要注重的一点是,凭据surface内部的实现原理(逾越本文的领域),我们获得的rgba数据,多数时间不仅包罗屏幕上的像素数据,还在图片的右侧包罗一条黑边,因此我们在将像素数据发送给编码器之前,还需要见告编码器,每一行有用像素的个数(本例子中用了字节数)。
然后说一下编码器MediaCodec。这工具从安卓4.1最先就有,一样平常是用来实现音视频编解码的。在它之前,市面上早已经有ffmpeg之类的工具,但MediaCodec的优势在于它还能调起硬件编解码模块,性能更高、效果更好。但它的早期版本功效很弱,只能支持像素数据作为输入源,而且多数是YUV花样数据,故而输入前还需要做一次RGB转YUV的操作。自安卓4.3最先,它支持surface作为输入源,因此这内里临一个看似理所应当的问题:既然我们的全系统手机录屏软件抓屏是基于安卓5.1的,而从安卓4.3最先,MediaCodec就支持以surface作为输入,那为什么不直接组合VirtualDisplay和MediaCodec就好,要中心插入一个ImageReader?这个问题怎么说呢,这是由于ShareREC不仅支持全系统录屏,还支持其它的应用内的录屏方式,如基于Cocos2d-x,Unity3D、libGDX等等引擎来做的录屏功效。而这些应用内的录屏方式,其抓取模块只能抓取到像素数据,思量到编码模块在ShareREC内是一个通用的模块,故而全系统录屏也将抓图输出处置惩罚为像素数据输出。
private BufferInfo bufferInfo;
private MediaCodec encoder;
public void startEncoder() throws Throwable {
// 获取硬件编码器支持的颜色花样,一样平常是I420或者NV12
int pixelFormat = getHWColorFormat();
MediaFormat format = MediaFormat.createVideoFormat(MIME, 1280, 720);
format.setInteger(MediaFormat.KEY_BIT_RATE, 1 * 1024 * 1024);
“沈阳软件公司”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与
我们联系删除或处理,客服QQ:55506560,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同
其观点或证实其内容的真实性。
热门文章
使用“扫一扫”即可将网页分享至朋友圈。