本文总结三种用于安卓录屏的解决方案:

adb shell命令screenrecord

MediaRecorder, MediaProjection

MediaProjection , MediaCodec和MediaMuxer

screenrecord命令

screenrecord是一个shell命令,支持Android4.4(API level 19)以上,录制的视频格式为mp4 ,存放到手机sd卡里,默认录制时间为180s

adb shell screenrecord --size 1280*720 --bit-rate 6000000 --time-limit 30 /sdcard/demo.mp4

--size 指定视频分辨率;

--bit-rate 指定视频比特率,默认为4M,该值越小,保存的视频文件越小;

--time-limit 指定录制时长,若设定大于180,命令不会被执行;

MediaRecorder

MediaProjection是Android5.0后才开放的屏幕采集接口,通过系统级服务MediaProjectionManager进行管理。

录屏过程可以分成两个部分,即通过MediaProjectionManage申请录屏权限,用户允许后开始录制屏幕;然后通过MediaRecorder对音视频数据进行处理。

获取MediaProjectionManager实例

MediaProjectionManager mProjectionManager = (MediaProjectionManager) getSystemService("media_projection");

申请权限

Intent captureIntent = mProjectionManager.createScreenCaptureIntent();

startActivityForResult(captureIntent, LOCAL_REQUEST_CODE);

createScreenCaptureIntent()这个方法会返回一个intent,你可以通过startActivityForResult方法来传递这个intent,为了能开始屏幕捕捉,activity会提示用户是否允许屏幕捕捉(为了防止开发者做一个木马,来捕获用户私人信息),你可以通过getMediaProjection来获取屏幕捕捉的结果。

在onActivityResult中获取结果

@Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {

MediaProjection mediaProjection = mProjectionManager.getMediaProjection(resultCode, data);

if (mediaProjection == null) {

Log.e(TAG, "media projection is null");

return;

}

File file = new File("xx.mp4"); //录屏生成文件

mediaRecord = new MediaRecordService(displayWidth, displayHeight, 6000000, 1,

mediaProjection, file.getAbsolutePath());

mediaRecord.start();

}

创建MediaRecorder进程

package com.unionpay.service;

import android.hardware.display.DisplayManager;

import android.hardware.display.VirtualDisplay;

import android.media.MediaRecorder;

import android.media.projection.MediaProjection;

import android.util.Log;

public class MediaRecordService extends Thread {

private static final String TAG = "MediaRecordService";

private int mWidth;

private int mHeight;

private int mBitRate;

private int mDpi;

private String mDstPath;

private MediaRecorder mMediaRecorder;

private MediaProjection mMediaProjection;

private static final int FRAME_RATE = 60; // 60 fps

private VirtualDisplay mVirtualDisplay;

public MediaRecordService(int width, int height, int bitrate, int dpi, MediaProjection mp, String dstPath) {

mWidth = width;

mHeight = height;

mBitRate = bitrate;

mDpi = dpi;

mMediaProjection = mp;

mDstPath = dstPath;

}

@Override

public void run() {

try {

initMediaRecorder();

//在mediarecorder.prepare()方法后调用

mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG + "-display", mWidth, mHeight, mDpi,

DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mMediaRecorder.getSurface(), null, null);

Log.i(TAG, "created virtual display: " + mVirtualDisplay);

mMediaRecorder.start();

Log.i(TAG, "mediarecorder start");

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 初始化MediaRecorder

*

* @return

*/

public void initMediaRecorder() {

mMediaRecorder = new MediaRecorder();

mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);

mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

mMediaRecorder.setOutputFile(mDstPath);

mMediaRecorder.setVideoSize(mWidth, mHeight);

mMediaRecorder.setVideoFrameRate(FRAME_RATE);

mMediaRecorder.setVideoEncodingBitRate(mBitRate);

mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);

mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

try {

mMediaRecorder.prepare();

} catch (Exception e) {

e.printStackTrace();

}

Log.i(TAG, "media recorder" + mBitRate + "kps");

}

public void release() {

if (mVirtualDisplay != null) {

mVirtualDisplay.release();

mVirtualDisplay = null;

}

if (mMediaRecorder != null) {

mMediaRecorder.setOnErrorListener(null);

mMediaProjection.stop();

mMediaRecorder.reset();

mMediaRecorder.release();

}

if (mMediaProjection != null) {

mMediaProjection.stop();

mMediaProjection = null;

}

Log.i(TAG, "release");

}

}

MediaCodec与MediaMuxer

MediaCodec提供对音视频压缩编码和解码功能,MediaMuxer可以将音视频混合生成多媒体文件,生成MP4文件。

与MediaRecorder类似,都需要先通过MediaProjectionManager获取录屏权限,在回调中进行屏幕数据处理。

这里创建另一个进程:

package com.unionpay.service;

import java.io.IOException;

import java.nio.ByteBuffer;

import java.util.concurrent.atomic.AtomicBoolean;

import android.hardware.display.DisplayManager;

import android.hardware.display.VirtualDisplay;

import android.media.MediaCodec;

import android.media.MediaCodecInfo;

import android.media.MediaFormat;

import android.media.MediaMuxer;

import android.media.projection.MediaProjection;

import android.util.Log;

import android.view.Surface;

public class ScreenRecordService extends Thread{

private static final String TAG = "ScreenRecordService";

private int mWidth;

private int mHeight;

private int mBitRate;

private int mDpi;

private String mDstPath;

private MediaProjection mMediaProjection;

// parameters for the encoder

private static final String MIME_TYPE = "video/avc"; // H.264 Advanced

// Video Coding

private static final int FRAME_RATE = 30; // 30 fps

private static final int IFRAME_INTERVAL = 10; // 10 seconds between

// I-frames

private static final int TIMEOUT_US = 10000;

private MediaCodec mEncoder;

private Surface mSurface;

private MediaMuxer mMuxer;

private boolean mMuxerStarted = false;

private int mVideoTrackIndex = -1;

private AtomicBoolean mQuit = new AtomicBoolean(false);

private MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();

private VirtualDisplay mVirtualDisplay;

public ScreenRecordService(int width, int height, int bitrate, int dpi, MediaProjection mp, String dstPath) {

super(TAG);

mWidth = width;

mHeight = height;

mBitRate = bitrate;

mDpi = dpi;

mMediaProjection = mp;

mDstPath = dstPath;

}

/**

* stop task

*/

public final void quit() {

mQuit.set(true);

}

@Override

public void run() {

try {

try {

prepareEncoder();

mMuxer = new MediaMuxer(mDstPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

} catch (IOException e) {

throw new RuntimeException(e);

}

mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG + "-display", mWidth, mHeight, mDpi,

DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mSurface, null, null);

Log.d(TAG, "created virtual display: " + mVirtualDisplay);

recordVirtualDisplay();

} finally {

release();

}

}

private void recordVirtualDisplay() {

while (!mQuit.get()) {

int index = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US);

// Log.i(TAG, "dequeue output buffer index=" + index);

if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {

// 后续输出格式变化

resetOutputFormat();

} else if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {

// 请求超时

// Log.d(TAG, "retrieving buffers time out!");

try {

// wait 10ms

Thread.sleep(10);

} catch (InterruptedException e) {

}

} else if (index >= 0) {

// 有效输出

if (!mMuxerStarted) {

throw new IllegalStateException("MediaMuxer dose not call addTrack(format) ");

}

encodeToVideoTrack(index);

mEncoder.releaseOutputBuffer(index, false);

}

}

}

/**

* 硬解码获取实时帧数据并写入mp4文件

*

* @param index

*/

private void encodeToVideoTrack(int index) {

// 获取到的实时帧视频数据

ByteBuffer encodedData = mEncoder.getOutputBuffer(index);

if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {

// The codec config data was pulled out and fed to the muxer

// when we got

// the INFO_OUTPUT_FORMAT_CHANGED status.

// Ignore it.

Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");

mBufferInfo.size = 0;

}

if (mBufferInfo.size == 0) {

Log.d(TAG, "info.size == 0, drop it.");

encodedData = null;

} else {

// Log.d(TAG, "got buffer, info: size=" + mBufferInfo.size + ", presentationTimeUs="

// + mBufferInfo.presentationTimeUs + ", offset=" + mBufferInfo.offset);

}

if (encodedData != null) {

mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);

}

}

private void resetOutputFormat() {

// should happen before receiving buffers, and should only happen

// once

if (mMuxerStarted) {

throw new IllegalStateException("output format already changed!");

}

MediaFormat newFormat = mEncoder.getOutputFormat();

mVideoTrackIndex = mMuxer.addTrack(newFormat);

mMuxer.start();

mMuxerStarted = true;

Log.i(TAG, "started media muxer, videoIndex=" + mVideoTrackIndex);

}

private void prepareEncoder() throws IOException {

MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);

format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);

format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);

format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);

format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);

Log.d(TAG, "created video format: " + format);

mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);

mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

mSurface = mEncoder.createInputSurface();

Log.d(TAG, "created input surface: " + mSurface);

mEncoder.start();

}

private void release() {

if (mEncoder != null) {

mEncoder.stop();

mEncoder.release();

mEncoder = null;

}

if (mVirtualDisplay != null) {

mVirtualDisplay.release();

}

if (mMediaProjection != null) {

mMediaProjection.stop();

}

if (mMuxer != null) {

mMuxer.stop();

mMuxer.release();

mMuxer = null;

}

}

}

该进程只实现了视频录制,调用该进程只需修改主进程中的onActivityResult方法。

总结

MediaProjection似乎只有在屏幕发生变化时才传输,因此录屏推流的画面显得不够流畅

到此这篇关于Android录屏的三种方案的文章就介绍到这了,更多相关Android录屏的三种方案内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

android 屏幕录制方案,Android录屏的三种解决方案相关推荐

  1. android 屏幕录制方案,Android录屏的三种方案

    本文总结三种用于安卓录屏的解决方案: adb shell命令screenrecord MediaRecorder, MediaProjection MediaProjection , MediaCod ...

  2. android 屏幕录制方案,Android录制屏幕的实现方法

    原文:Paul Kinlan 翻译:Agora.io 长久以来,我一直希望能够直接从Android屏幕上进行录制并将其编码为多种格式,以便将录制内容嵌入在任意位置,而不需要安装任何软件. 如今,我们已 ...

  3. android 屏幕录制方案,ShareREC for Android全系统录屏原理解析

    本文是Mob开发者平台技术副总监余勋杰基于MediaProjection实现Android全系统录屏功能的原理解析,包括了结合MediaRecorder和MediaCodec两套方案. 文 / 余勋杰 ...

  4. Android音频录制方案,Android录屏的三种方案

    本文总结三种用于安卓录屏的解决方案: adb shell命令screenrecord MediaRecorder, MediaProjection MediaProjection , MediaCod ...

  5. android 盒子录屏apk,三种用于安卓录屏的解决方案

    本文总结三种用于安卓录屏的解决方案: adb shell命令screenrecord MediaRecorder, MediaProjection MediaProjection , MediaCod ...

  6. android屏幕录制功能,Android利用ADB进行屏幕录制

    前言 在写博客时,为了方便大家理解,我们经常需要把一些操作或动画录制成Gif,一般需要下载一个屏幕录制App将手机屏幕录制成视频(可能需要Root权限),然后导出到电脑,再转为Gif.今天就来教大家一 ...

  7. 苹果屏幕录制5831_苹果录屏功能在哪?教你轻松开启iPhone录屏

    苹果录屏功能在哪?很多刚使用苹果手机的小伙伴都不知道苹果手机里的录屏功能怎么使用,今天小编就给大家分享一下苹果手机的录屏功能. 详细操作步骤: 1.打开苹果手机的设置界面 2.下拉找到控制中心的选项进 ...

  8. android屏幕 录制检测,Android 录制屏幕的实现方法

    Android 录制屏幕的实现方法,长久以来,我一直希望能够直接从Android屏幕上进行录制并将其编码为多种格式,以便将录制内容嵌入在任意位置,而不需要安装任何软件. 如今,我们已经接近这个目标.C ...

  9. 电脑上如何进行屏幕录制,笔记本电脑录屏怎么录

    电脑上如何进行屏幕录制?如果你在日常工作娱乐中有录屏的需求,并且想进一步了解电脑录屏的相关操作步骤,请认真看以下内容!小编会给大家分享几种简单的电脑录屏方法. 方法一:PPT屏幕录制 PPT想必大家都 ...

最新文章

  1. python 多维list 排序_人生苦短 | Python列表和元组归纳整理
  2. Docker知识2:安装docker-desktop
  3. 用python搭建个人博客过程_技术分享|利用Python Django一步步搭建个人博客(四)...
  4. DCMTK:将XML文档的内容转换为DICOM结构的报告文件
  5. [TCP/IP]TCP服务端accept发生在三次握手的哪一个阶段
  6. 学习NodeJS第一天:node.js引言
  7. 那些年,画家发明的黑科技
  8. cassandra 备份_使用sstableloader恢复Cassandra Priam备份
  9. 前端学习(3076):vue+element今日头条管理-分支的使用
  10. 杂志订阅管理系统c++_有哪些值得收藏的室内设计杂志?
  11. vue +element 导出多级表头(标题)
  12. 1.OAuth 2实战 --- OAuth 2.0是什么,为什么要关心它
  13. html5里面怎么引入字体
  14. 7-4 统计素数并求和
  15. SpringCloud之实现下载Excel模板文件
  16. UI设计师都在用的4款UI设计软件
  17. C#绘制中国象棋棋盘
  18. 用java在画布上画心形线_Java画心形线
  19. 【区块链开发入门】(四) Truffle详解篇2
  20. 监控车辆的历史行驶轨迹有何意义?TSINGSEE车载监控平台助力运输安全监管

热门文章

  1. 数值转换lexical_cast的使用
  2. 拟牛顿法之DFP算法
  3. Matlab将元胞数组输出到txt或者dat文件中
  4. cloudmersive OCR识别聊天记录图片转文字
  5. 【项目实战课】人人免费可学,基于Pytorch的BCNN鸟类细粒度图像分类实战
  6. 18篇遥感领域经典论文【附PDF】
  7. 多人游戏对战技术(坦克大战、状态同步)
  8. Emeditor Regular Expression
  9. android 布局中绘制语音曲线,基于android平台的老年人用药助手软件的开发-仪器仪表工程专业论文.docx...
  10. 经典格斗游戏《街头霸王》的Javascript实现