Android5.0录屏
Android L新增了MediaProjection录屏的api,捣鼓了大半天,照着github上的demo撸了一遍代码,梳理梳理。
录屏实现依赖MediaProjectionManager
通过
mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE)
拿到是实例
然后创建intent,并startActivityForResult
Intent intent = mediaProjectionManager.createScreenCaptureIntent();startActivityForResult(intent, 123);
在onActvitiyResult()中拿到MediaProjection实例
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK && requestCode == 123) {mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);if (mediaProjection != null ) {mRecorder = new ScreenRecorder(mWidth, mHeight, mediaProjection, mDensty);}new Thread() {@Overridepublic void run() {mRecorder.startRecorder();}}.start();btnRecorder.setText("停止录屏");moveTaskToBack(true);}}
录屏很消耗资源,另起一个线程操作
前面的这些步骤呢,主要目的就是一个,开启录屏。
然后,通过MediaProjection实例创建一个虚拟屏幕,剩下的工作主要就是通过MediaCodec,MediaMuxer
将virtualDisplay的进行编码输出到MP4文件中。
思路还是比较简短的,但是呢,我也是踩了不少坑,之前完全不熟悉相关的API只能一遍一遍照着demo撸。
归纳一下实现步骤
1.拿到MediaProjectionManager服务 getSystemService();
2.创建intent,并启动 mediaprojectionmanager.createCpatureIntent();
3.初始化编码器 MediaCodec.createEncoderByType(), 并创建一个suface
mEncoder.createInputSuface()
启动编码器,mEncoder.start();
4.使用suface创建虚拟屏幕 mediaprojection.createVirtualDisplay()
5.创建一个混合器,MediaMuxer;
6.编码并输出。
具体代码
1.拿到MediaProjectionManager服务 getSystemService();
mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
2.创建intent,并启动 mediaprojectionmanager.createCpatureIntent();
Intent intent = mediaProjectionManager.createScreenCaptureIntent();startActivityForResult(intent, 123);
拿到mediaprojection对象
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK && requestCode == 123) {mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);if (mediaProjection != null ) {mRecorder = new ScreenRecorder(mWidth, mHeight, mediaProjection, mDensty);}new Thread() {@Overridepublic void run() {mRecorder.startRecorder();}}.start();btnRecorder.setText("停止录屏");moveTaskToBack(true);}}
ScreenRecorder构造方法主要是进行了传值工作
public ScreenRecorder(int mWidth, int mHeight, MediaProjection mediaProjection, int mDensty) {this.mWidth = mWidth;this.mHeight = mHeight;this.mediaProjection = mediaProjection;this.mDensty = mDensty;File file = new File(savePath);if (!file.exists()) {file.mkdirs();}}
在onActivityResult中 另起一个线程调用了startRecorder()方法
看代码
public void startRecorder() {prepareRecorder();startRecording();}
在prepareRecorder()中初始化编码器,并设置一些参数
设置了bit率,影响清晰度的4000000-6000000b比较合适
framerate 帧率 就是常说的fps
其他的设置还是看google文档吧,我也不是特别清楚,还在学习中
private void prepareRecorder() {mBufferInfo = new MediaCodec.BufferInfo(); //元数据,描述bytebuffer的数据,尺寸,偏移//创建格式化对象 MIMI_TYPE 传入的 video/avc 是H264编码格式MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);int frameRate = 45; format.setInteger(MediaFormat.KEY_BIT_RATE, 3000000);format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);format.setInteger(MediaFormat.KEY_CAPTURE_RATE, frameRate);format.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1000000 / frameRate);/*MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);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);*/try {mEncorder = MediaCodec.createEncoderByType(MIME_TYPE);mEncorder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);mInputSurface = mEncorder.createInputSurface();mEncorder.start();} catch (IOException e) {e.printStackTrace();releaseEncorders();}}
将format传给mEncorder,然后调用start,编码器就开始工作了,会自动将数据写入到MediaCodec的缓冲区内,我们拿出缓冲区内编码好的数据,使用MediaMuxer进行混合输出就ok了,看到有大神将,声音和视频的混合之后一起输出,就实现了录屏和录音同步。这个后面可以尝试下的
接着看
private void startRecording() {File saveFile = new File(savePath, System.currentTimeMillis() + ".mp4");try {mMuxer = new MediaMuxer(saveFile.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);Log.e("TAG", "mwidth " + mWidth + " heigh " + mHeight + " mdensty " + mDensty + " Flag "+ DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC + " surface " + String.valueOf(mInputSurface == null));mediaProjection.createVirtualDisplay("SCREENRECORDER", mWidth, mHeight, mDensty, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,mInputSurface, null, null);drainEncoder();} catch (Exception e) {e.printStackTrace();}finally {releaseEncorders();}}
MediaMuxer需要一个文件来保存输出的视频,并传入一个输出格式
MediaMuxer输出格式目前只支持MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4
MUXER_OUTPUT_WEBM两种。
创建虚拟屏幕之后
就开始编码输出了,
private void drainEncoder() {while (!mQuit.get()) {Log.e("TAG", "drain.....");int bufferIndex = mEncorder.dequeueOutputBuffer(mBufferInfo, 0);if (bufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}if (bufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {mTrackIndex = mMuxer.addTrack(mEncorder.getOutputFormat());if (!mMuxerStarted && mTrackIndex >= 0) {mMuxer.start();mMuxerStarted = true;}}if (bufferIndex >= 0) {Log.e("TAG", "drain...write..");ByteBuffer bufferData = mEncorder.getOutputBuffer(bufferIndex);if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {mBufferInfo.size = 0;}if (mBufferInfo.size != 0) {if (mMuxerStarted) {bufferData.position(mBufferInfo.offset);bufferData.limit(mBufferInfo.offset + mBufferInfo.size);mMuxer.writeSampleData(mTrackIndex, bufferData, mBufferInfo);}}mEncorder.releaseOutputBuffer(bufferIndex, false);if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {break;}}}}
这段代码呢先拿到输出buffer的index
index的含义:
MediaCodec.INFO_TRY_AGAIN_LATER 超时
MediaCodec.INFO_OUTPUT_FORMAT_CHANGED 格式改变
我们在MediaCodec.INFO_OUTPUT_FORMAT_CHANGED 这个的时候会开启muxer
if (bufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {mTrackIndex = mMuxer.addTrack(mEncorder.getOutputFormat());if (!mMuxerStarted && mTrackIndex >= 0) {mMuxer.start();mMuxerStarted = true;}}
也比较容易理解
之前是muxer并没有调用start(),所以这个时候是没有输出的,混合也是不能起任何作用的
MediaCodec.BUFFER_FLAG_END_OF_STREAM 输出结尾
MediaCodec.BUFFER_FLAG_CODEC_CONFIG 开始编码 我们需要忽略
index大于0,写数据
if (mBufferInfo.size != 0) {if (mMuxerStarted) {bufferData.position(mBufferInfo.offset);bufferData.limit(mBufferInfo.offset + mBufferInfo.size);mMuxer.writeSampleData(mTrackIndex, bufferData, mBufferInfo);}}
不要忘了释放资源,这个是真消耗资源
我用的三星s6 9200,开始没有处理资源,手机卡死好几次,电量也耗得。。。。
代码就不贴了
好了,就到这里
Android5.0录屏相关推荐
- Android5.0录屏方案
导语 本文主要是围绕android直播助手的功能做了一些研究,因为之前对Android多媒体相关的内容知之甚少,只有概念,于是查阅了相关资料并做以总结. 由于我对音视频相关知识零基础所以补充了一些相关 ...
- android 5.0 录屏代码,Android5.0录屏
Android L新增了MediaProjection录屏的api,捣鼓了大半天,照着github上的demo撸了一遍代码,梳理梳理. 录屏实现依赖MediaProjectionManager 经过 ...
- android 8.0 录屏命令,Android前置摄像头录制的视频介于7.5和8.0之间 – setVideoFrameRate不起作用 – 三星Galaxy S2...
我正在尝试使用前置摄像头录制视频,以下是代码段,我将setVideoFrameRate设置为29,但是录制的视频的fps为7.5到8.我需要录制vidio的视频fps 29. recorder.set ...
- oCam_v520.0 录屏软件 资源下载
有道云笔记http://note.youdao.com/noteshare?id=6379b8ddf60323479b68cc0d6e4e5c0a&sub=FB538535BAA9493397 ...
- android 录屏方案 VFR和CFR
android 5.0录屏的例子网上满天飞,我这里主要是总结一下,如何以VFR和CFR的方式来录屏.写这篇文章主要是因为我在做这个功能的过程中,在网上找了很久也没有找到一个固定帧率录屏的例子,后面还是 ...
- Fundebug录屏插件更新至0.4.0,修复BUG,优化性能
2019独角兽企业重金招聘Python工程师标准>>> 摘要: 录屏功能更加强大,欢迎免费试用! 关于Fundebug录屏功能 Fundebug是专业的程序BUG监控服务,当线上应用 ...
- 压缩过的js代码怎么还原_Fundebug 前端 JS插件更新至 1.7.0,拆分录屏代码,还原部分 Script error....
摘要: BUG 监控插件压缩至 18K. 1.7.0拆分了录屏代码,BUG 监控插件压缩至18K,另外我们还原了部分 Script error,帮助用户更方便地 Debug.请大家及时更新哈~ 拆分录 ...
- jquery 录屏_Fundebug录屏插件更新至0.6.0
摘要: 录屏插件的性能进一步优化,传输的数据体积大幅度减少. 录屏功能介绍 Fundebug提供专业的异常监控服务,当线上应用出现 BUG 的时候,我们可以第一时间报警,帮助开发者及时发现 BUG,提 ...
- iOS 12.0+系统录屏(一)
iOS在录屏功能是走过了长长的一段路,在其他平台尤其是直播平台日益火爆的推动下,iOS12.0终于开放在应用中唤起系统录屏权限给开发者.以下内容以iOS 12.0+为基础,不再讨论之前的版本. 理论准 ...
最新文章
- 深入剖析MobileNet和它的变种
- 如果宁静是 Oracle,万茜、张雨绮、黄圣依是什么?
- qt widget 窗口拉伸_QTDesigner的QVBoxLayout自动随窗口拉伸
- Day 23:使用 TimelineJS 构建精美的时间轴
- linux配置静态ip
- Android线程优先级设置方法技巧
- Linux学习-07-vim编辑器
- python安装教程(Windows最新)
- python的itertools库_Python标准库itertools模块使用方法
- 分享一款好看的城市选择器
- JAVA教程下载-JAVA学习视频教程网盘分享
- 湖北省武汉市谷歌高清卫星地图下载
- 办公软件excel表格_软件和Excel表格管理仓库的区别?
- 何凯明最新一作MAE解读系列1
- GPU编程与CG语言之阳春白雪下里巴人.pdf 分享
- adobe air linux centos,Adobe AIR(跨平台应用)
- 游戏防封技术是学易语言还是学c,易语言写游戏脚本防封执行sqlplus 之后没执行...
- Range fro mac(随机数字生成软件)
- GNS与WireShark安装流程
- 重新认识 Java 的 System.in