http://blog.csdn.net/wds1181977/article/details/52174840

MediaProjection介绍

MediaProjection可以用来捕捉屏幕,具体来说可以截取当前屏幕和录制屏幕视频。MediaProjection由MediaProjectionManager来管理和获取。

使用步骤

首先获取MediaProjectionManager,和其他的Manager一样通过 Context.getSystemService() 传入参数MEDIA_PROJECTION_SERVICE获得实例。

接着调用MediaProjectionManager.createScreenCaptureIntent()弹出dialog询问用户是否授权应用捕捉屏幕,同时覆写onActivityResult()获取授权结果。

如果授权成功,通过MediaProjectionManager.getMediaProjection(int resultCode, Intent resultData)获取MediaProjection实例,通过MediaProjection.createVirtualDisplay(String name, int width, int height, int dpi, int flags, Surface surface, VirtualDisplay.Callback callback, Handler handler)创建VirtualDisplay实例。实际上在上述方法中传入的surface参数,是真正用来截屏或者录屏的。

截屏

截屏这里用到ImageReader类,这个类的getSurface()方法获取到surface直接传入MediaProjection.createVirtualDisplay()方法中,此时就可以执行截取。通过ImageReader.acquireLatestImage()方法即可获取当前屏幕的Image,经过简单处理之后即可保存为Bitmap。

           private void startCapture() {

            mImageName = System.currentTimeMillis() + ".png";

            Log.e(TAG, "image name is : " + mImageName);

            Image image = mImageReader.acquireLatestImage();

            int width = image.getWidth();

            int height = image.getHeight();

            final Image.Plane[] planes = image.getPlanes();

            final ByteBuffer buffer = planes[0].getBuffer();

            int pixelStride = planes[0].getPixelStride();

            int rowStride = planes[0].getRowStride();

            int rowPadding = rowStride - pixelStride * width;

            Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);

            bitmap.copyPixelsFromBuffer(buffer);

            bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);

            image.close();

            if (bitmap != null) {

                Log.e(TAG, "bitmap  create success ");

                try {

                    File fileFolder = new File(mImagePath);

                    if (!fileFolder.exists())

                        fileFolder.mkdirs();

                    File file = new File(mImagePath, mImageName);

                    if (!file.exists()) {

                        Log.e(TAG, "file create success ");

                        file.createNewFile();

                    }

                    FileOutputStream out = new FileOutputStream(file);

                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);

                    out.flush();

                    out.close();

                    Log.e(TAG, "file save success ");

                    Toast.makeText(this.getApplicationContext(), "截图成功", Toast.LENGTH_SHORT).show();

                } catch (IOException e) {

                    Log.e(TAG, e.toString());

                    e.printStackTrace();

                }

            }

        }

录屏

录屏需要用到上篇博文中的MediaCadec,这个类将原始的屏幕数据编码,在通过MediaMuxer分装为mp4格式保存。MediaCodec.createInputSurface()获取一个surface对象讲起传入MediaProjection.createVirtualDisplay()即可获取屏幕原始多媒体数据,之后读取MediaCodec编码输出数据经过MediaMuxer封装处理为mp4即可播放,实现录屏。

       private void recordVirtualDisplay() {//循环多去编解码器输出数据经过处理保存为mp4

        while (!mIsQuit.get()) {

            int index = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 10000);

            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);

                mMediaCodec.releaseOutputBuffer(index, false);

            }

        }

    }

        private void encodeToVideoTrack(int index) {//输出数据为mp4文件

        ByteBuffer encodedData = mMediaCodec.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) {//存在编码数据

            encodedData.position(mBufferInfo.offset);

            encodedData.limit(mBufferInfo.offset + mBufferInfo.size);

            mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);//写入

            Log.i(TAG, "sent " + mBufferInfo.size + " bytes to muxer...");

        }

    }

        private void resetOutputFormat() {

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

        if (mMuxerStarted) {

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

        }

        MediaFormat newFormat = mMediaCodec.getOutputFormat();

        Log.i(TAG, "output format changed.\n new format: " + newFormat.toString());

        mVideoTrackIndex = mMuxer.addTrack(newFormat);

        mMuxer.start();

        mMuxerStarted = true;

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

    }

附录参考

官方文档

Android视频录制

Android 5.0截屏

Android录屏代码 
本文Demo

 
 

Android5.0免Root截屏,录屏的更多相关文章

  1. DXGI快速截屏录屏技术

    DXGI快速截屏录屏技术 概述   很多地方都需要用到截屏/录屏技术,比如桌面直播,桌面录制等等.在微软Windows平台,有很多截屏的接口,不过大多数性能并不理想,Windows8以后微软引入了一套 ...

  2. 超便携式截屏录屏软件FastStone Capture

    超便携式截屏录屏软件FastStone Capture

  3. (024)[工具软件]截屏录屏软件FSCapture(转)

    该软件比 Snipaste 增加的功能有滚动截图和屏幕录制. 原文地址:https://www.appcgn.com/faststone-capture.html FastStoneCapture,简 ...

  4. android 调用 screenrecord 实现录屏

    首先要说明的是并未实现,本文讲一下自己的思路. adb 使用shell 命令 screenrecord 可录屏. 自己写了个app,通过Process p = Runtime.getRuntime() ...

  5. iphone手机怎么录屏 两种方法任你挑选

    iphone手机怎么录屏呢?苹果手机拥有独特的Airlay镜像投屏,AirPlay的工作原理是当iPhone或IPAD与支持AirPlay技术的硬件,比如Apple TV等设备处在同一个wife的情况 ...

  6. Android5.0以上版本录屏实现

    我录屏的方式是分别录制音频和视频,最后合并成mp4格式,比较麻烦,因为网上完整的教程比较少,所以我打算写一个完整版的,照着我的代码写完之后,至少是能够实现功能的,而不是简单的介绍下用法. 1既然是录制 ...

  7. android手机截屏、录屏

    1. 手动截屏,通过其他第三方软件发送截图,或者从手机取出截图 2. 使用命令截图,将截图保存到手机,再拉取到电脑 #!/bin/sh #运行 sh screenshot name picName=$ ...

  8. Android 禁止截屏、录屏 — 解决PopupWindow无法禁止录屏问题

    项目开发中,为了用户信息的安全,会有禁止页面被截屏.录屏的需求. 这类资料,在网上有很多,一般都是通过设置Activity的Flag解决,如: //禁止页面被截屏.录屏 getWindow().add ...

  9. 搭建前端监控系统(六)JS截屏和录屏篇

    怎样定位前端线上问题,一直以来,都是很头疼的问题,因为它发生于用户的一系列操作之后.错误的原因可能源于机型,网络环境,接口请求,复杂的操作行为等等,在我们想要去解决的时候很难复现出来,自然也就无法解决 ...

随机推荐

  1. Java三方---->Thumbnailator框架的使用

    Thumbnailator是一个用来生成图像缩略图的 Java类库,通过很简单的代码即可生成图片缩略图,也可直接对一整个目录的图片生成缩略图.有了它我们就不用在费心思使用Image I/O API,J ...

  2. MQTT协议笔记之发布流程

    MQTT协议笔记之发布流程 前言 这次要讲到客户端/服务器的发布消息行为,与PUBLISH相关的消息类型,会在这里看到. PUBLISH 客户端发布消息经由服务器分发到所有对应的订阅者那里.一个订阅者 ...

  3. jQuery的一些小技巧()

    1.判断某元素上是否绑定了某种类型的事件 var $events = $("#foo").data("events"); if( $events &&a ...

  4. EUI组件之EditableText

    一.EditableText常规使用 EditableText是一个可输入文本,例如登陆时输入用户名.密码等. 拖动EditableText到exml即可 实际效果 其他: 1.输入密码框 设置inp ...

  5. [Window] .MUS 0x80070422 Error

    Window Update 服务没有开启.开启后可以执行如下命令: for /f %%i in ('dir D:\Hotfix\*.msu /S /B /ON') do wusa.exe %%i /q ...

  6. Unity3D笔记十一 定制导航菜单栏

    一.定制导航栏 Unity导航菜单栏位于游戏引擎界面的顶部,其中有很多选项且含义各不相同.Unity为开发者提供了导航菜单栏的程序接口,使用代码可以动态添加菜单栏中的选项以及子项 using Unit ...

  7. 【MySQL案例】error.log的Warning:If a crash happens thisconfiguration does not guarantee that the relay lo(转)

    标签: 1.1.1. If a crash happens thisconfiguration does not guarantee that the relay log info will be c ...

  8. stm32的VCC/VDD/VSS/VEE/VBAT的区别

    先看一下stm32vet6的引脚图吧 电路设计以及PCB制作中,经常碰见电源符号:VCC. VDD.VEE.VSS,他们具有什么样的关系那? 一.解释 VCC:C=circuit 表示电路的意思, 即 ...

  9. Nginx降权启动

            给Nginx服务降权,用lol用户跑Nginx,给开发及运维设置普通账号,只要和lol同组即可管理Nginx,该方案解决了Nginx管理问题,防止root分配权限过大. 开发人员使用普 ...

  10. 【转】SQL Server编程游标

    在关系数据库中,我们对于查询的思考是面向集合的.而游标打破了这一规则,游标使得我们思考方式变为逐行进行.对于类C的开发人员来着,这样的思考方式会更加舒服. 正常面向集合的思维方式是: 而对于游标来说: ...