实例介绍
【实例简介】
Android 5.0 屏幕录制
从 Android 4.4 开始支持手机端本地录屏,但首先需要获取 root 权限才行,Android 5.0 引入 MediaProject, 可以不用 root 就可以录屏,但需要弹权限获取窗口,需要用户允许才行,这里主要介绍 Android 5.0 利用 MediaProject 在非 root 情况下实现屏幕录制。
基本原理
在 Android 5.0,Google 终于开放了视频录制的接口,其实严格来说,是屏幕采集的接口,也就是 MediaProjection 和 MediaProjectionManager。
【实例截图】
【核心代码】
public class MainActivity extends AppCompatActivity { private static final int RECORDER_CODE = 0; private static final String TAG = "TAG"; int width; int height; int dpi; MediaProjectionManager projectionManager; MediaProjection mediaProjection; MediaCodec mediaCodec; MediaMuxer mediaMuxer; Surface surface; VirtualDisplay virtualDisplay; private MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); private int videoTrackIndex = -1; String filePath; private AtomicBoolean mQuit = new AtomicBoolean(false); private boolean muxerStarted = false; @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DisplayMetrics metric = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metric); width = 720; height = 1280; dpi = 1; File file = null; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { file = new File(this.getDataDir().getPath(), "record-" width "x" height "-" System.currentTimeMillis() ".avc"); } filePath = file.getAbsolutePath(); Log.e(TAG, "onCreate: " filePath ); mMP4Path =filePath; projectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { mediaProjection = projectionManager.getMediaProjection(resultCode,data); new Thread() { @Override public void run() { try { try { prepareEncoder(); mediaMuxer = new MediaMuxer(filePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); } catch (IOException e) { throw new RuntimeException(e); } virtualDisplay = mediaProjection.createVirtualDisplay(TAG "-display", width, height, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, surface, null, null); recordVirtualDisplay(); } finally { release(); } } }.start(); Toast.makeText(this, "Recorder is running...", Toast.LENGTH_SHORT).show(); // moveTaskToBack(true); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private void recordVirtualDisplay() { while (!mQuit.get()) { int index = mediaCodec.dequeueOutputBuffer(bufferInfo, 10000); if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { resetOutputFormat(); } else if (index >= 0) { encodeToVideoTrack(index); mediaCodec.releaseOutputBuffer(index, false); } } } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private void encodeToVideoTrack(int index) { ByteBuffer encodedData = mediaCodec.getOutputBuffer(index); if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { bufferInfo.size = 0; } if (bufferInfo.size == 0) { encodedData = null; } if (encodedData != null) { encodedData.position(bufferInfo.offset); encodedData.limit(bufferInfo.offset bufferInfo.size); mediaMuxer.writeSampleData(videoTrackIndex, encodedData, bufferInfo); } } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) private void resetOutputFormat() { MediaFormat newFormat = mediaCodec.getOutputFormat(); videoTrackIndex = mediaMuxer.addTrack(newFormat); mediaMuxer.start(); muxerStarted = true; } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) private void prepareEncoder() throws IOException { MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height); format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); format.setInteger(MediaFormat.KEY_BIT_RATE, 6000000); format.setInteger(MediaFormat.KEY_FRAME_RATE, 30); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10); mediaCodec = MediaCodec.createEncoderByType("video/avc"); mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); surface = mediaCodec.createInputSurface(); mediaCodec.start(); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void StartRecorder(View view) { startActivityForResult(projectionManager.createScreenCaptureIntent(),RECORDER_CODE); } public void StopRecorder(View view) { mQuit.set(true); Toast.makeText(this, "Recorder stop", Toast.LENGTH_SHORT).show(); } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) private void release() { if (mediaCodec != null) { mediaCodec.stop(); mediaCodec.release(); mediaCodec = null; } if (virtualDisplay != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { virtualDisplay.release(); } } if (mediaProjection != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mediaProjection.stop(); } } if (mediaMuxer != null) { mediaMuxer.release(); mediaMuxer = null; } } private static String mMP4Path; VideoView mVideoView; MediaController mMediaController;
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论