音视频系列--MediaProjection录屏生成H264和H265文件

一、前言


想要分析H264或者H265文件,就需要生成对应文件来分析,当然可以通过FFmpeg来操作,操作命令可以参考这里,这里打算使用MediaProjection录频来生成下H264或H265文件。

二、MediaProjection


2.1、获取MediaProjectionManager

使用之前别忘了申请权限

 public boolean checkPermission() {
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(
             Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
         requestPermissions(new String[]{
                 Manifest.permission.READ_EXTERNAL_STORAGE,
                 Manifest.permission.WRITE_EXTERNAL_STORAGE
         }, 1);

     }
     return false;
 }

获取MediaProjectionManager

this.mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);

2.2、申请录频

Intent captureIntent = mediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(captureIntent, 100);

成功之后会在onActivityResult中回调

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 100 && resultCode == Activity.RESULT_OK) {

        mediaProjection = mediaProjectionManager.getMediaProjection
                (resultCode, data);

        //同意了回调这里
        initMediaCodec();

    }
}


同意之后获取MediaProjection

2.3、使用MediaCodec获取编码h264数据

MediaProjection录频好的数据已经是编码好的,设置好和MediaCodec提供的Surface,就会把数据通过MediaCodec传给DSP芯片,我们就只需要通过MediaCodecDSP中获取编码好的数据。

private void initMediaCodec() {
    try {
        //此处是编码
        mediaCodec = MediaCodec.createEncoderByType("video/avc");
        MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC,
                540, 960);

        format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
                MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
        //帧率
        format.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
        //码率
        format.setInteger(MediaFormat.KEY_BIT_RATE, 1200_000);
        //2秒一个I帧
        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);//2s一个I帧
        //不需要传surface
        mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        //这是MediaCodec 提供的surface
        final Surface surface = mediaCodec.createInputSurface();
        new Thread() {
            @Override
            public void run() {
                //开始编码
                mediaCodec.start();
                //提供的surface  与MediaProjection关联
                mediaProjection.createVirtualDisplay("screen-codec",
                        540, 960, 1,
                        DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
                        surface, null, null);
                MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
                while (isStart) {
//                      录频数据直接会传给dsp编码,源源不断的插叙编码好的数据
                    int index = mediaCodec.dequeueOutputBuffer(bufferInfo, 100000);

                    Log.e(TAG, "run: " + index);
                    if (index >= 0) {
//                            dsp芯片提供的ByteBuffer,不能够直接使用操作
                        ByteBuffer buffer = mediaCodec.getOutputBuffer(index);

                        byte[] outData = new byte[bufferInfo.size];
                        buffer.get(outData);

                        //以字符串的方式写入
                        writeContent(outData);
                        //写成 文件  我们就能够播放起来
                        writeBytes(outData);
                        mediaCodec.releaseOutputBuffer(index, false);
                    }

                }

                mediaCodec.stop();
                mediaCodec.release();

                mediaProjection.stop();

            }
        }.start();

    } catch (Exception e) {
        e.printStackTrace();
    }

}

此处将获取到的编码数据写到了txt文件和h264文件,前者是为了方便后续学习分析,写到txt文件需要将字节进一步转化为byte字符串

public String writeContent(byte[] array) {
    char[] HEX_CHAR_TABLE = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
    };
    StringBuilder sb = new StringBuilder();
    for (byte b : array) {
        sb.append(HEX_CHAR_TABLE[(b & 0xf0) >> 4]);
        sb.append(HEX_CHAR_TABLE[b & 0x0f]);
    }
    Log.i(TAG, "writeContent: "+sb.toString());
    FileWriter writer = null;
    try {
        // 打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件
        writer = new FileWriter(Environment.getExternalStorageDirectory()+"/codec.txt", true);
        writer.write(sb.toString());
        writer.write("\n");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if(writer != null){
                writer.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return sb.toString();
}

此时运行成功就可以在SD卡中生成对应文件

在这里插入图片描述

1.NAL层和VCL层是同步进行的
2.第一帧永远会将sps和pps当成一帧编码出来

三、获取H265文件


只需要改几处地方就可以了

1 .设置编码的type MediaCodec.createEncoderByType("video/hevc");

2 .设置编码器MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_HEVC, 540, 960)

3 . 设置输出的文件格式为.h265文件即可

代码位置

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值