MediaCodec MediaCodecInfo 编码问题总结

项目设计需要视频分割,无缝循环录制;

问题1:

在android系统原有基础上,通过mediaRecoder类的startRecord 和stopRecord实现, 视频分割时,会有200--2000毫秒的缝隙;

因此系统mediaRecoder方法放弃;


问题2:

由于问题1;实现方案修改为

setPreviewFormat(ImageFormat.YV12);
....................................
int bufferSize = getBufferSize(); 
for(int i = 0; i<3;i++){ 
previewCallbackbuffer = new byte[bufferSize]; 
//mCurCameraDevice.getCameraDevice().setPreviewCallbackWithBuffer(null); 
mCurCameraDevice.getCameraDevice().addCallbackBuffer(previewCallbackbuffer); 
} 
mCurCameraDevice.getCameraDevice().setPreviewCallbackWithBuffer(mPreviewCallback);

通过onPreviewFrame函数获取camera帧yuv数据byte[] data,然后针对data进行编码;

设备横屏录制视频ok,但是竖屏录制的视频,播放的时候,发现旋转了90度(由于camera模组角度固定导致,具体也不清楚啦,就是取景方向和屏幕角度被固定啦)


问题3:

在问题2的基础上, 竖屏录像时,旋转帧数据(通过yuvlib开源库实现,前面博客有介绍),注意,(初步怀疑yuvlib库旋转90度,或者270度,会导致uv顺序颠倒,而180度不会).再编码成视频;ok

但是发现录像旋转后编码视频颜色不对(具体原因不明,通过打印一帧数据分析,初步怀疑yuvlib库旋转90度,或者270度,会导致uv顺序颠倒,而180度不会),  在编码前针对旋转后的数据做uv顺序切换;

	private byte[] g_SwapCache = null;
	private void swapYV12toI420(byte[] YV12Bytes, int YSize) {
		if (g_SwapCache == null) {
			g_SwapCache = new byte[YSize / 4];
		}
		System.arraycopy(YV12Bytes, YSize, g_SwapCache, 0, g_SwapCache.length);
		System.arraycopy(YV12Bytes, YSize + YSize / 4, YV12Bytes, YSize, YSize / 4);
		System.arraycopy(g_SwapCache, 0, YV12Bytes, YSize + YSize / 4, g_SwapCache.length);
	}

最后ok.


问题4:

测试过程中,640x480  1280x720 录制都ok, 发现针对1080p(1920x1080)视频编码有问题(不旋转帧数据录制无问题,旋转后录制视频花屏,切屏)

排查很久,打印一帧数据到txt用yuv工具查看,  旋转接口实现没有问题;  最后修改分辨率1920x1088,  旋转录制依然ok,(怀疑原因);大功告成!


1,中间还有一些小插曲,  都是辛酸史.  

2,图片旋转后,图片宽高和原图宽高已经颠倒;

3,camera中录制视频,每次录制视频停止时,都需要特别注意;不能在onPreviewFrame中继续调用

addCallbackBuffer(data)

不然onPreviewFrame函数会不停执行; 

更可怕的是,当你修改分辨率后,callback的数据大小依然是前面的buffer大小;

如果stoppreview(未close camera),后再次

mCurCameraDevice.getCameraDevice().addCallbackBuffer(previewCallbackbuffer);
onPreviewFrame(byte [] data,Camera camera)中data的长度会交替执行;
private PreviewCallback mPreviewCallback = new PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            //Log.d(TAG, "[mPreviewCallback.onPreviewFrame]");
            if(mModuleManager.canRecorder()){
                //releaseRotateOutputBuffter();
                getRotateOutputBuffter(ZfRecorderUtils.ZfRecorderParam.videoFrameWidth, ZfRecorderUtils.ZfRecorderParam.videoFrameHeight);
                StartAudioRecordingZF();
                StartRecordingZF(data);
                if(mCurCameraDevice != null &&mCurCameraDevice.getCameraDevice()!= null){
                    mCurCameraDevice.getCameraDevice().addCallbackBuffer(data);
                }
            }else{
                if (avcCodec != null) {
                    avcCodec.stopThread();
                    avcCodec = null;
                }
                releaseRotateOutputBuffter();

                /*if(mCurCameraDevice != null &&mCurCameraDevice.getCameraDevice()!= null){
                    mCurCameraDevice.getCameraDevice().addCallbackBuffer(data);
                }*/
            }
        }

    };
我是在系统camera模块的基础上,直接把原来的videomode修改了,就是不用他的录像,用自己的录像,  借用了他的框架,包括UI.

你可能感兴趣的:(MediaCodec MediaCodecInfo 编码问题总结)