Android 录屏(录像)录制视频自定义输出视频分辨率,设置最合适尺寸;Android Mediacodec 录屏输出视频被缩小,Android 录屏全屏,录屏自定义尺寸,录屏录像黑边

      1.问题:

      首先我的应用场景Mediacodec ,使用了摄像头流与录屏流,中间会进行切换,然后录出来一个完整的视频,也就是从摄像到录屏再到摄像再录屏,需求比较。。。因为要录像又要录屏,所以不可能直接用手机屏幕的实际分辨率。所以从camera.getParameters()获取宽高并设置为输出的视频的分辨率。现象是很多手机上看录制好的视频录屏那块被缩小了,其实是因为有黑边造成的。因此问题其实是基于录屏的输出视频分辨率为核心的,其他录屏方案也大多适用。

     2.分析

     大多数手机获取的camera的分辨率与屏幕的分辨率不一致,重要的是长宽比不一样,比如说。相机获取了1920*1080的分辨率,而你的手机是2340*1080的分辨率,在录屏的时候输出视频,第一录屏要全屏录,也就是宽是2340,第二视频不会裁剪,所以你最后要输出1920*1080,他的宽自然要缩小,高度也就跟着等比缩小,然后上下会有黑边填充。也就是其实视频最后输出的是1920*1080,之所以看起来小了是上下填充了黑边。

       所以你要做的就是一个断点一个断点的去看相机支持的分辨率,然后一个一个去算比例,然后发现一些规律,然后换一部手机,然后再执行这一套操作,然后再换一步手机。。。

      好在这些我都替你做了。

     3.处理     

      查找camera支持的分辨率中最接近手机实际屏幕比例的值

其实是从手机支持的视频分辨率中找,不过因为也要用摄像头,视频支持的包括摄像头支持且比摄像头支持的多,所以要从摄像头支持的里找。即List<Camera.Size> prviewSizeList = myParameters.getSupportedPreviewSizes();不开摄像头的可以试着从List<Camera.Size> videoSizeList = myParameters.getSupportedVideoSizes();里找。下面是核心代码

public void initCamera() {
    getScreenSize();
    //注:摄像头相关的设置不写了,省的看混
    ............
    Camera.Parameters myParameters = myCamera.getParameters();
    //获取摄像头支持的分辨率
    List<Camera.Size> prviewSizeList = myParameters.getSupportedPreviewSizes();
    //获取手机支持的视频分辨率
    //List<Camera.Size> videoSizeList = myParameters.getSupportedVideoSizes();
    //获取最接近的分辨的索引
    int selectIndex = bestVideoSize(prviewSizeList);

    ............
    //设置相机预览尺寸
    //TODO 在你设置视频大小的地方也是用这里计算出来的值,以为我设置录制视频分辨率的地方不在,
//这,不过也是取得这里的值,所以就不写了                               
myParameters.setPreviewSize(prviewSizeList.get(selectIndex).width,prviewSizeList.get(selectIndex).height);

}

int mRealSizeWidth;//手机屏幕真实宽度
int mRealSizeHeight;//手机屏幕真实高度

 /**
   * 查找最接近屏幕宽高比的参数
   * @param cameraSizeList
   * @return
   */
public int bestVideoSize(List<Camera.Size> cameraSizeList) {
        if (cameraSizeList == null) {
            return -1;
        }
        //计算屏幕的实际分辨率的比值
        float realRatio = ((float) mRealSizeWidth / (float) mRealSizeHeight);
        int index = 0;//目标索引
        float outRatio = -1f;
        for (int i = 0; i < cameraSizeList.size(); i++) {
            if (cameraSizeList.get(i).height <= mRealSizeHeight) {//取的值高度不能高于屏
//幕真实高度
                float ratio = (float) (cameraSizeList.get(i).width) / (float) (cameraSizeList.get(i).height);
                if (outRatio == -1f) {
                    outRatio = Math.abs(ratio / realRatio - 1);
                    index = i;
                } else {
                    if (outRatio > Math.abs(ratio / realRatio - 1)) {
                        //取绝对值小的值,即选择与屏幕分辨率最接近的值
                        index = i;
                        outRatio = Math.abs(ratio / realRatio - 1);
                    }else if (outRatio == Math.abs(ratio / realRatio - 1)) {
                        //如果有两组长宽比完全一样的,选择height比较大,小的可能会视频模糊
                        if (cameraSizeList.get(i).height >= cameraSizeList.get(index).height) {
                            index = i;
                            outRatio = Math.abs(ratio / realRatio - 1);
                        }
                    }
                }

            }
        }
        return index;
    }


//计算屏幕真实分辨率
public void getScreenSize() {
        WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        Point outPoint = new Point();
        if (Build.VERSION.SDK_INT >= 19) {
            // 可能有虚拟按键的情况
            display.getRealSize(outPoint);
        } else {
            // 不可能有虚拟按键
            display.getSize(outPoint);
        }

        mRealSizeHeight = outPoint.y;
        mRealSizeWidth = outPoint.x;
    }

注意:我录的是横屏,所以我比较的都是高度height,如果是竖屏,最好是用宽度width。

      安卓手机的各种各样的分辨率问题不再多说了,没办法把所有的都测一遍,从我手里的一批手机测过后都是达到了比较完美的效果(除非你手机的相机有支持与屏幕比例一模一样的分辨率,否则几乎不会是完全的全屏,最终的效果也会因手机不同有些许差异),如果有不合适的,可以在bestVideoSize()方法里通过限制你要取值的height的高度范围这个方向考虑。

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
要在Android中使用MediaCodec录制屏幕和音频,可以使用MediaProjection API和AudioRecord API。 首先,需要获取MediaProjection对象来捕获屏幕内容。可以使用MediaProjectionManager来请求用户授权并获取MediaProjection对象。例如: ```java MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); Intent intent = mediaProjectionManager.createScreenCaptureIntent(); startActivityForResult(intent, REQUEST_CODE_SCREEN_CAPTURE); ``` 在onActivityResult回调方法中获取MediaProjection对象: ```java @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_SCREEN_CAPTURE && resultCode == RESULT_OK) { mMediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data); } } ``` 接下来,需要创建一个AudioRecord对象来录制音频。可以使用MediaRecorder.AudioSource.MIC作为音频来源。例如: ```java int audioSource = MediaRecorder.AudioSource.MIC; int sampleRate = 44100; int channelCount = AudioFormat.CHANNEL_IN_MONO; int audioFormat = AudioFormat.ENCODING_PCM_16BIT; int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelCount, audioFormat); mAudioRecord = new AudioRecord(audioSource, sampleRate, channelCount, audioFormat, bufferSize); ``` 在录制音频时,需要以相同的速率将音频数据传递给编码器。可以使用线程循环读取音频数据并将其传递给编码器。例如: ```java mAudioRecord.startRecording(); while (!mStopRecording) { int numBytesRead = mAudioRecord.read(mAudioBuffer, 0, mAudioBuffer.length); if (numBytesRead > 0) { ByteBuffer inputBuffer = mAudioEncoder.getInputBuffer(inputBufferIndex); inputBuffer.clear(); inputBuffer.put(mAudioBuffer, 0, numBytesRead); mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, numBytesRead, presentationTimeUs, 0); presentationTimeUs += 1000000L / sampleRate; } } mAudioRecord.stop(); ``` 在编码视频和音频后,需要将它们合并为一个视频文件。可以使用MediaMuxer将它们合并在一起。例如: ```java mMediaMuxer = new MediaMuxer(outputFile.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); int audioTrackIndex = -1; while (true) { MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); int trackIndex = mAudioEncoder.dequeueOutputBuffer(bufferInfo, 0); if (trackIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { break; } else if (trackIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat audioFormat = mAudioEncoder.getOutputFormat(); audioTrackIndex = mMediaMuxer.addTrack(audioFormat); mMediaMuxer.start(); } else if (trackIndex >= 0) { ByteBuffer outputBuffer = mAudioEncoder.getOutputBuffer(trackIndex); outputBuffer.position(bufferInfo.offset); outputBuffer.limit(bufferInfo.offset + bufferInfo.size); bufferInfo.presentationTimeUs = presentationTimeUs; mMediaMuxer.writeSampleData(audioTrackIndex, outputBuffer, bufferInfo); mAudioEncoder.releaseOutputBuffer(trackIndex, false); } } ``` 这样,你就可以使用MediaCodec同时录制屏幕和音频了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

break妖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值