MediaCodec编码变模糊,马赛克问题?
2022-09-20 本文已影响0人
夏木友人
一、预览数据是正常,MediaCodec编码之后出来视频会变模糊,变马赛克?
最近在使用camera2录制视频时,碰到过保存本地视频,一直有马赛克不清晰的问题,但是一直找不到问题所在??本来以为是MediaCodec编码参数设置有问题,但是不管我怎么改,码率调的多大都不管用,还是会糊。后来我把camera回调的数据一帧一帧保存图片在本地,发现图片并没有视频那样模糊。那就排除camera预览数据问题,剩下就是编码问题。
if (rotation == 90 || rotation == 270) {
//设置视频宽高
mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, videoHeight, videoWidth);
} else {
mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, videoWidth, videoHeight);
}
//图像数据格式 YUV420
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
//码率
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, videoWidth * videoHeight * 8);
//每秒30帧
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
//1秒一个关键帧
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
videoMediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
编码时,我会先把nv21数据转成nv12,然后再去编码。
byte[] nv12 = new byte[nv21.length];
byte[] yuvI420 = new byte[nv21.length];
byte[] tempYuvI420 = new byte[nv21.length];
LibyuvUtil.convertNV21ToI420(nv21, yuvI420, videoWidth, videoHeight);
LibyuvUtil.compressI420(yuvI420, videoWidth, videoHeight, tempYuvI420, videoWidth, videoHeight, rotation, isFrontCamera);
LibyuvUtil.convertI420ToNV12(tempYuvI420, nv12, videoWidth, videoHeight);
//得到编码器的输入和输出流, 输入流写入源数据 输出流读取编码后的数据
//得到要使用的缓存序列角标
int inputIndex = videoMediaCodec.dequeueInputBuffer(TIMEOUT_USEC);
if (inputIndex >= 0) {
ByteBuffer inputBuffer = videoMediaCodec.getInputBuffer(inputIndex);
inputBuffer.clear();
//把要编码的数据添加进去
inputBuffer.put(nv12);
//塞到编码序列中, 等待MediaCodec编码
videoMediaCodec.queueInputBuffer(inputIndex, 0, nv12.length, timeData, 0);
}
而在nv21转nv12是会有一个耗时,就造成了此时的时间与原始画面的时间间隔存在差异,如果在此时获取stamptime传入传入queueInputBuffer(...),编码的帧在时间上不连续,形成马赛克
videoMediaCodec.queueInputBuffer(inputIndex, 0, nv12.length, System.currentTimeMillis(), 0);
后来传给编码的时间戳改成预览时摄像头回调的时间戳,这样录制的视频就正常,不会有马赛克
videoMediaCodec.queueInputBuffer(inputIndex, 0, nv12.length, timeData, 0);