MediaProjection 和 MediaProjectionManager 是 Android 5.0 开放的屏幕截图与录制视频的接口,它可以用来对 surfaceview 进行截图,解决以前 surfaceview 截图出现黑屏的问题(就是问了这个问题来的,5.0以下没找到方法)。

MediaProjectionManager 是一个系统级的服务,可以通过 getSystemService 来获取实例:

MediaProjectionManager mMediaProjectionManager = (MediaProjectionManager)                getSystemService(Context.MEDIA_PROJECTION_SERVICE);

然后调用mMediaProjectionManager.createScreenCaptureIntent(),这里会弹出授权的dialog:

startActivityForResult(                    mMediaProjectionManager.createScreenCaptureIntent(),                    REQUEST_MEDIA_PROJECTION);

重写onActivityResult()方法,获取授权结果:

    @Override    public void onActivityResult(int requestCode, int resultCode, Intent data) {        if (requestCode == REQUEST_MEDIA_PROJECTION) {            if (resultCode != Activity.RESULT_OK) {                Log.d(TAG, "User cancelled");                Toast.makeText(this, "User cancelled", Toast.LENGTH_SHORT).show();                return;            }            if (this == null) {                return;            }            Log.d(TAG, "Starting screen capture");            mResultCode = resultCode;            mResultData = data;            setUpMediaProjection();            setUpVirtualDisplay();            //继续执行截图或者录屏操作            // do somthing...        }    }

然后创建MediaProjection 的实例:

    private void setUpMediaProjection() {        mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, mResultData);    }

截图

接着创建VirtualDisplay实例:

    private void setUpVirtualDisplay() {            mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture",                    mWindowWidth, mWindowHeight, mScreenDensity,                    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,                    mImageReader.getSurface(), null, null);    }

此处是截图时的代码,所以上面surface参数传入的是:
mImageReader.getSurface()

ImageReader 的创建:

    ImageReader mImageReader = ImageReader.newInstance(mWindowWidth, mWindowHeight, 0x1, 2);

截图是通过ImageReader.acquireLatestImage() 获取当前屏幕的Image, 然后再获取Bitmap保存:

    private void startCapture() {        mImageName = System.currentTimeMillis() + ".png";        Log.i(TAG, "image name is : " + mImageName);        Image image = mImageReader.acquireLatestImage();        if (image == null) {            Log.e(TAG, "image is null.");            return;        }        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;        mBitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);        mBitmap.copyPixelsFromBuffer(buffer);        mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height);        image.close();        if (mBitmap != null) {            // 保存或者显示...        }    }

录屏

录屏是通过MediaCadec, 初始化MediaCadec:

    private void configureMedia() {        MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", mWindowWidth, mWindowHeight);        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 6000000);        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);        mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);        mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);        try {            mMediaCodec = MediaCodec.createEncoderByType("video/avc");        } catch (IOException e) {            e.printStackTrace();        }        mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);        mSurface = mMediaCodec.createInputSurface();        mMediaCodec.start();    }

创建VirtualDisplay实例:

            mVirtualDisplay = mMediaProjection.createVirtualDisplay("record_screen",                    mWindowWidth, mWindowHeight, mScreenDensity,                    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,                    mSurface, null, null);

此处与截图方法出入的surface参数不一样。
开始录屏:

    private void startRecord() {        try {            mMuxer = new MediaMuxer(mVideoPath + System.currentTimeMillis() + ".mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);            recordVirtualDisplay();        } catch (IOException e) {            e.printStackTrace();        } finally {            release();        }    }    private void recordVirtualDisplay() {        while (!mIsQuit.get()) {            int index = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 10000);            Log.d(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 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.d(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);    }    private void encodeToVideoTrack(int index) {        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 recordStop() {        mIsQuit.set(true);    }    private void release() {        mIsQuit.set(false);        mMuxerStarted = false;        Log.i(TAG, " release() ");        if (mMediaCodec != null) {            mMediaCodec.stop();            mMediaCodec.release();            mMediaCodec = null;        }        if (mVirtualDisplay != null) {            mVirtualDisplay.release();            mVirtualDisplay = null;        }        if (mMuxer != null) {            mMuxer.stop();            mMuxer.release();            mMuxer = null;        }    }

这样录屏文件就会保存的指定路径。

部分代码参考他人,不喜可以喷~~

Github:Demo

Android MediaProjection截屏与录屏(ScreenCapture Library 的使用)(二)

更多相关文章

  1. android 广播详解与实例(Broad Receiver)
  2. [转]activity的启动方式(launch mode)
  3. Android(安卓)从源码的角度分析——为什么要用newInstance来实例
  4. ScrollView嵌套RecyclerView出现item显示不全的问题
  5. Android(安卓)三种动画详解及简单实例
  6. android 获取进程、服务、任务列表
  7. Activity 的四种启动模式(launchMode)
  8. Android(安卓)UI 之 获取组件或者元素的坐标
  9. 基于Android中获取资源的id和url方法总结

随机推荐

  1. Android(安卓)打印堆栈
  2. Android(安卓)实现再按一次后退键退出应
  3. asynchttpclient post方法使用
  4. android 多点触摸 实现图片缩放 Image Zo
  5. How to set up a link betwteen a real A
  6. android 按钮的文字显示不全
  7. JS怎样调用Android本地原生方法
  8. Android安装APK时出现Local path doesn't
  9. android activity 相互传值
  10. android 保存bitmap到指定文件