项目设计需要视频分割,无缝循环录制;
问题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.