2024年10月24日 第11讲 StreamConfigurationMap实战一 极客笔记
本讲是Android Camera专题系列的第11讲,我们介绍Android Camera2 API专题的StreamConfigurationMap实战之如何获取预览Size和拍照Jpeg Size。
更多资源:
资源 | 描述 |
---|---|
在线课程 | 极客笔记在线课程 |
知识星球 | 星球名称:深入浅出Android Camera 星球ID: 17296815 |
极客笔记圈 |
在创建Camera Capture Session前,会先通过StreamConfigurationMap获取
预览组件
需要考虑的因素
一般提供三种宽高比:全屏、1:1、4:3
实战
private void doInitSupportedPreviewSizes(CameraFeatures camera_features,
StreamConfigurationMap configs) throws CameraControllerException{
android.util.Size [] camera_preview_sizes = configs.getOutputSizes(SurfaceTexture.class);
camera_features.mSupportedPreviewSizes = new ArrayList<>();
Point display_size = new Point();
Activity activity = (Activity)context;
{
Display display = activity.getWindowManager().getDefaultDisplay();
display.getRealSize(display_size);
// getRealSize() is adjusted based on the current rotation, so should already be landscape format, but it
// would be good to not assume Open Camera runs in landscape mode (if we ever ran in portrait mode,
// we'd still want display_size.x > display_size.y as preview resolutions also have width > height)
if( display_size.x < display_size.y ) {
//noinspection SuspiciousNameCombination
display_size.set(display_size.y, display_size.x);
}
if( MyDebug.LOG )
Log.i(TAG, "display_size: " + display_size.x + " x " + display_size.y);
}
if( camera_preview_sizes == null ) {
// camera_preview_sizes is null on Samsung Galaxy Note 10+ and S20 for camera ID 4!
Log.e(TAG, "no preview sizes returned by getOutputSizes");
throw new CameraControllerException();
}
else {
for(android.util.Size camera_size : camera_preview_sizes) {
if( MyDebug.LOG )
Log.i(TAG, "preview size: " + camera_size.getWidth() + " x " + camera_size.getHeight());
if( camera_size.getWidth() > display_size.x || camera_size.getHeight() > display_size.y ) {
// Nexus 6 returns these, even though not supported?! (get green corruption lines if we allow these)
// Google Camera filters anything larger than height 1080, with a todo saying to use device's measurements
continue;
}
camera_features.mSupportedPreviewSizes.add(new CameraController.Size(camera_size.getWidth(), camera_size.getHeight()));
}
}
}
public CameraController.Size getOptimalPreviewSize(List<CameraController.Size> sizes) {
if( MyDebug.LOG )
Log.d(TAG, "getOptimalPreviewSize()");
final double ASPECT_TOLERANCE = 0.05;
if( sizes == null )
return null;
if( is_video && video_high_speed ) {
VideoProfile profile = getVideoProfile();
if( MyDebug.LOG )
Log.d(TAG, "video size: " + profile.videoFrameWidth + " x " + profile.videoFrameHeight);
// preview size must match video resolution for high speed, see doc for CameraDevice.createConstrainedHighSpeedCaptureSession()
return new CameraController.Size(profile.videoFrameWidth, profile.videoFrameHeight);
}
CameraController.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
Point display_size = new Point();
Activity activity = (Activity)this.getContext();
{
Display display = activity.getWindowManager().getDefaultDisplay();
display.getSize(display_size);
// getSize() is adjusted based on the current rotation, so should already be landscape format, but:
// (a) it would be good to not assume Open Camera runs in landscape mode (if we ever ran in portrait mode,
// we'd still want display_size.x > display_size.y as preview resolutions also have width > height,
// (b) on some devices (e.g., Nokia 8), when coming back from the Settings when device is held in Preview,
// display size is returned in portrait format! (To reproduce, enable "Maximise preview size"; or if that's
// already enabled, change the setting off and on.)
if( display_size.x < display_size.y ) {
//noinspection SuspiciousNameCombination
display_size.set(display_size.y, display_size.x);
}
if( MyDebug.LOG )
Log.d(TAG, "display_size: " + display_size.x + " x " + display_size.y);
}
double targetRatio = calculateTargetRatioForPreview(display_size);
int targetHeight = Math.min(display_size.y, display_size.x);
if( targetHeight <= 0 ) {
targetHeight = display_size.y;
}
// Try to find the size which matches the aspect ratio, and is closest match to display height
for(CameraController.Size size : sizes) {
if( MyDebug.LOG )
Log.d(TAG, " supported preview size: " + size.width + ", " + size.height);
double ratio = (double)size.width / size.height;
if( Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE )
continue;
if( Math.abs(size.height - targetHeight) < minDiff ) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if( optimalSize == null ) {
// can't find match for aspect ratio, so find closest one
if( MyDebug.LOG )
Log.d(TAG, "no preview size matches the aspect ratio");
optimalSize = getClosestSize(sizes, targetRatio, null);
}
if( MyDebug.LOG ) {
Log.d(TAG, "chose optimalSize: " + optimalSize.width + " x " + optimalSize.height);
Log.d(TAG, "optimalSize ratio: " + ((double)optimalSize.width / optimalSize.height));
}
return optimalSize;
}
拍照组件
需要考虑的点
拍照使用哪种Format(JPEG,YUV_420_888,RAW等)
宽高比与预览Size保持一致
实战
private void doInitSupportedJpegSizes(CameraFeatures camera_features,
StreamConfigurationMap configs) throws CameraControllerException {
android.util.Size [] camera_picture_sizes = configs.getOutputSizes(ImageFormat.JPEG);
camera_features.mSupportedPictureSizes = new ArrayList<>();
if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M ) {
android.util.Size [] camera_picture_sizes_hires = configs.getHighResolutionOutputSizes(ImageFormat.JPEG);
if( camera_picture_sizes_hires != null ) {
for(android.util.Size camera_size_hr : camera_picture_sizes_hires) {
if( MyDebug.LOG )
Log.i(TAG, "high resolution picture size: " + camera_size_hr.getWidth() + " x " + camera_size_hr.getHeight());
// Check not already listed? If it's listed in both, we'll add it later on when scanning camera_picture_sizes
// (and we don't want to set supports_burst to false for such a resolution).
boolean found = false;
for(android.util.Size sz : camera_picture_sizes) {
if( sz.equals(camera_size_hr) ) {
found = true;
break;
}
}
if( !found ) {
if( MyDebug.LOG )
Log.i(TAG, "doInitSupportedJpegSizes high resolution [non-burst] picture size: " + camera_size_hr.getWidth() + " x " + camera_size_hr.getHeight());
CameraController.Size size = new CameraController.Size(camera_size_hr.getWidth(),
camera_size_hr.getHeight());
size.supports_burst = false;
camera_features.mSupportedPictureSizes.add(size);
}
}
}
}
if( camera_picture_sizes == null ) {
// camera_picture_sizes is null on Samsung Galaxy Note 10+ and S20 for camera ID 4!
Log.e(TAG, "no picture sizes returned by getOutputSizes");
throw new CameraControllerException();
}
else {
for(android.util.Size camera_size : camera_picture_sizes) {
if( MyDebug.LOG )
Log.i(TAG, "doInitSupportedJpegSizes picture size: " + camera_size.getWidth() + " x " + camera_size.getHeight());
camera_features.mSupportedPictureSizes.add(new CameraController.Size(camera_size.getWidth(),
camera_size.getHeight()));
}
}
// sizes are usually already sorted from high to low, but sort just in case
// note some devices do have sizes in a not fully sorted order (e.g., Nokia 8)
Collections.sort(camera_features.mSupportedPictureSizes, new CameraController.SizeSorter());
// test high resolution modes not supporting burst:
//camera_features.picture_sizes.get(0).supports_burst = false;
}
本文链接:http://so.lmcjl.com/news/16108/