(原)阅读Android-Camera2Video的demo源码和调试心得

转载请注明出处:http://www.cnblogs.com/lihaiping/p/6142512.html
 
最近因为项目需要使用到camera的功能,所以针对官方的demo源码进行一番阅读,并修改了一个record录像以后程序崩溃的bug。
 
这里主要记录下调试过程的情况:
 
1)打开rk3288-walkera-board上基于android5.1的camera以后,出现无视频画面的黑屏情况。
  经过查找主要是因为camera适用720P打开,而在程序的预览过程中,选择用了1080p打开camera,导致视频画面出不来。
相关代码在opencamera函数中:
            //选择满足4:3的长宽比例的尺寸分辨率
mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
//获取一下摄像头支持的最大分辨率,防止摄像头不支持,导致没有图像
Size cameraLargest= Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),new CompareSizesByArea());
//获取最佳的长宽比预览尺寸
// mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
// width, height, mVideoSize);
//针对rk3288-walkera-board,camera只能打开720p
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
1280, 720, cameraLargest);
我们先看一下chooseVideoSize函数:
//这个函数根据长宽比,选择只支持长宽比为4:3的分辨率,同时宽小于1080p
private static Size chooseVideoSize(Size[] choices) {
for (Size size : choices) {
        if (size.getWidth() == size.getHeight() * 4 / 3 && size.getWidth() <= 1080) {
return size;
}
}
Log.e(TAG, "Couldn't find any suitable video size");
return choices[choices.length - 1];
}
在这个函数执行以后,得到的分辨率为800x600的分辨率。
然后再来看一下chooseOptimalSize 的选择策略:
//这个函数选择长比宽为aspectRotio一样的分辨率,同时如果长宽大于指定的宽高,就选用中间最小的一个,否则选用choices[0]
private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
// Collect the supported resolutions that are at least as big as the preview Surface
//选择合适的长宽比的分辨率
List<Size> bigEnough = new ArrayList<Size>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getHeight() == option.getWidth() * h / w &&
option.getWidth() >= width && option.getHeight() >= height) {
bigEnough.add(option);
}

}

// Pick the smallest of those, assuming we found any
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
}
else {
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}
针对这种选择策略,我个人觉得很不适用。函数执行结果因为找不到满足的分辨率,所以会进入else的选择,最好返回choices[0],即选择1080p的预览分辨率。
所以导致后面打开摄像头会出现无视频画面的情况。
其实我个人的认为,在选择最佳分辨率的情况,应该是当设备支持的分辨率中有比预览指定的分辨率大的集合的时候,选集合中最小的设备分辨率。否则选择比预览分辨率小的集合中最大的分辨率。
 
  
2)点击录像,然后录像停止以后,生成录像文件,但程序崩溃。
出现问题的崩溃点为 startPreview 中从新创建预览请求的函数:
 
  
// 创建预览需要的CaptureRequest.Builder
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
后面经过搜索和查找,解决方法为:
    private void stopRecordingVideo() {
// UI
mIsRecordingVideo = false;
mButtonVideo.setText(R.string.record);
//modefy by lihaiping1603@aliyun.com on20161207
//这个地方需要优化一下,防止录像的时候会崩溃
// try{
// mPreviewSession.abortCaptures();
// }catch (CameraAccessException e) {
// e.printStackTrace();
// }

//试一下使用close方式,在录像stop前,调用关闭也是可以解决崩溃的问题的
closePreviewSession();

// Stop recording
mMediaRecorder.stop();
mMediaRecorder.reset();
//在停止录像以后调用关闭会话,程序会崩溃
// //试一下使用close方式
// closePreviewSession();

Activity activity = getActivity();
if (null != activity) {
Toast.makeText(activity, "Video saved: " + mNextVideoAbsolutePath,
Toast.LENGTH_SHORT).show();
Log.d(TAG, "Video saved: " + mNextVideoAbsolutePath);
}
mNextVideoAbsolutePath = null;
startPreview();
}
后面经过翻看abortCaptures()的官方解释:
public abstract void abortCaptures ()
Added in  API level 21

Discard all captures currently pending and in-progress as fast as possible.

The camera device will discard all of its current work as fast as possible. Some in-flight captures may complete successfully and call onCaptureCompleted(CameraCaptureSession, CaptureRequest, TotalCaptureResult), while others will trigger their onCaptureFailed(CameraCaptureSession, CaptureRequest, CaptureFailure) callbacks. If a repeating request or a repeating burst is set, it will be cleared.

This method is the fastest way to switch the camera device to a new session with createCaptureSession(List, CameraCaptureSession.StateCallback, Handler) orcreateReprocessableCaptureSession(InputConfiguration, List, CameraCaptureSession.StateCallback, Handler), at the cost of discarding in-progress work. It must be called before the new session is created. Once all pending requests are either completed or thrown away, the onReady(CameraCaptureSession) callback will be called, if the session has not been closed. Otherwise, the onClosed(CameraCaptureSession)callback will be fired when a new session is created by the camera device.

Cancelling will introduce at least a brief pause in the stream of data from the camera device, since once the camera device is emptied, the first new request has to make it through the entire camera pipeline before new output buffers are produced.

This means that using abortCaptures() to simply remove pending requests is not recommended; it's best used for quickly switching output configurations, or for cancelling long in-progress requests (such as a multi-second capture).

至于原因,暂时还不是太清楚,但加上我上面几个函数,就可以解决崩溃的问题。
 
  
 
  
 
  
 
  
 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值