android通过MediaProjectionManager录屏关联MediaCodec获取h264数据

android 5.0增加了MediaProjectionManager,通过它我们可以简单的完成录屏的需求。

本文会简单介绍MediaProjectionManager的使用流程,通过MediaCodec获取到的264数据

MediaProjectionManager的用法

1.获取MediaProjectionManager实例

     通过调用getSystemService方法获取MediaProjectionManager的实例

/**
     * 初始化MediaProjectionManager
     * **/
    private void InitMPManager(){
        mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
    }

2.创建屏幕捕捉的Intent

    获取到MediaProjectionManager的实例后,通过createScreenCaptureIntent方法获取Intnent,通过startActivityForResult启动Intent

/**
     * 开始截屏
     * **/
    private void StartScreenCapture(){
        Intent captureIntent = mMediaProjectionManager.createScreenCaptureIntent();
        startActivityForResult(captureIntent, REQUEST_CODE_A);
    }

3.在onActivityResult中获取MediaProjection实例

        通过startActivityForResult启动intent后,在onActivityResult的回掉中获取MediaProjection的实例,这时候要开始初始化MediaCodec了,通过MediaCodec可以拿到Surface对像,通过MediaProjection对象的createVirtualDisplay方法,拿到VirtureDisplay对象,拿这个对象的时候,需要把Surface对象传进去。
  • 获取MediaProjection
@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
        try {
            MediaProjection mediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data);
        }
        catch (Exception e){

        }
    }

  • 初始化MediaCodec,获取Surface对象
try{
            MediaFormat format = MediaFormat.createVideoFormat(Constant.MIME_TYPE, Constant.VIDEO_WIDTH, Constant.VIDEO_HEIGHT);
            format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
                    MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
            format.setInteger(MediaFormat.KEY_BIT_RATE, Constant.VIDEO_BITRATE);
            format.setInteger(MediaFormat.KEY_FRAME_RATE, Constant.VIDEO_FRAMERATE);
            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, Constant.VIDEO_IFRAME_INTER);
            mEncoder = MediaCodec.createEncoderByType(Constant.MIME_TYPE);
            mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            mSurface = mEncoder.createInputSurface();
            mEncoder.start();
        }catch (IOException e){

        }

  • 获取VirtureDisplay对象
mVirtualDisplay =mMediaProjection.createVirtualDisplay(TAG + "-display", Constant.VIDEO_WIDTH, Constant.VIDEO_HEIGHT, Constant.VIDEO_DPI, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
                mSurface, null, null);

4.通过MediaCodec获取h264数据

通过MediaCodec获取264的代码,可以参考我的这个项目:Github

或者参考我之前的博客内容:android编码h264(二):MediaCodec 硬编码 h264(硬编码)

MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();
                int outputBufferIndex  = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
                while (outputBufferIndex >= 0){
                    ByteBuffer outputBuffer = mEncoder.getOutputBuffers()[outputBufferIndex];
                    byte[] outData = new byte[mBufferInfo.size];
                    outputBuffer.get(outData);
                    if(mBufferInfo.flags == 2){
                        configbyte = new byte[mBufferInfo.size];
                        configbyte = outData;
                    }else if(mBufferInfo.flags == 1){
                        byte[] keyframe = new byte[mBufferInfo.size + configbyte.length];
                        System.arraycopy(configbyte, 0, keyframe, 0, configbyte.length);
                        System.arraycopy(outData, 0, keyframe, configbyte.length, outData.length);
                        if(outputStream != null){
                            outputStream.write(keyframe, 0, keyframe.length);
                        }
                    }else{
                        if(outputStream != null){
                            outputStream.write(outData, 0, outData.length);
                        }
                    }
                    mEncoder.releaseOutputBuffer(outputBufferIndex, false);
                    outputBufferIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
                }

到此,就基本结束了,写这个是为了一个项目做基础准备的,这个项目要解决如下问题:

不知道大家有没有遇到过,app开发完成后要给领导或者客户演示,如果领导在还好,如果不在,那么就会通过本地录像的方式来演示,我像通过rtsp或者rtmp流媒体的方式,将屏幕内容来实时的演示,目前项目才开始,代码会慢慢提交的。

项目地址:GitHub

这篇博客的代码也在这个工程里

  • 7
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
是的,您可以使用AndroidMediaProjectionManager API来获取幕捕获的权限,然后使用MediaCodec API将捕获的数据编码为H.264格式。具体步骤如下: 1. 创建一个MediaProjectionManager对象并请求幕捕获的权限: ``` MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); Intent permissionIntent = mediaProjectionManager.createScreenCaptureIntent(); startActivityForResult(permissionIntent, REQUEST_CODE); ``` 2. 在onActivityResult()方法中获取MediaProjection对象: ``` @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE) { if (resultCode != Activity.RESULT_OK) { // 用户拒绝了幕共享请求 return; } // 获取MediaProjection对象 MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data); } } ``` 3. 创建一个MediaCodec对象并配置编码器: ``` MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height); format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate); format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval); MediaCodec codec = MediaCodec.createEncoderByType("video/avc"); codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); codec.start(); ``` 4. 在幕捕获回调中获取数据,并将数据编码后写入到输出流: ``` class ScreenCaptureCallback extends MediaProjection.Callback { private Surface surface; private MediaCodec codec; public ScreenCaptureCallback(Surface surface, MediaCodec codec) { this.surface = surface; this.codec = codec; } @Override public void onStop() { codec.stop(); codec.release(); } @Override public void onScreenCaptureStarted(MediaProjection projection) { // 创建一个虚拟幕Surface DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE); Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); VirtualDisplay virtualDisplay = mediaProjection.createVirtualDisplay( "ScreenCapture", width, height, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY, surface, null, null); // 开始幕捕获 codec.setCallback(new MediaCodec.Callback() { @Override public void onInputBufferAvailable(MediaCodec codec, int index) { // do nothing } @Override public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info) { ByteBuffer buffer = codec.getOutputBuffer(index); // 将编码后的数据写入到输出流 outputStream.write(buffer.array(), info.offset, info.size); codec.releaseOutputBuffer(index, false); } @Override public void onError(MediaCodec codec, MediaCodec.CodecException e) { // do nothing } @Override public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) { // do nothing } }); codec.getInputBuffers(); } } ``` 注意:需要在AndroidManifest.xml文件中添加权限: ``` <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" /> <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" /> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值