本讲是android camera专题系列的第11讲,我们介绍android camera2 api专题的streamconfigurationmap实战之如何获取预览size和拍照jpeg size。
更多资源:
资源 | 描述 |
---|---|
在线课程 | |
知识星球 | 星球名称:深入浅出android camera 星球id: 17296815 |
极客笔记圈 |
geekcamera2启动时序图
用streamconfigurationmap来做什么
在创建camera capture session前,会先通过streamconfigurationmap获取
- camera支持的预览size列表
- camera支持的拍照size列表
- camera支持的录像size列表
获取预览size
预览组件
- surfaceholder / surfacetexture / imagereader
需要考虑的因素
- 屏幕size、拍照size
-
一般提供三种宽高比:全屏、1:1、4:3
实战
- geekcamera2 如何选择预览size
获取preview size list核心代码
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()));
}
}
}
根据picture size获取preview size核心代码
public cameracontroller.size getoptimalpreviewsize(list 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;
}
获取拍照size
拍照组件
- imagereader(jpeg)
需要考虑的点
- support size list要考虑gethighresolutionoutputsizes
-
拍照使用哪种format(jpeg,yuv_420_888,raw等)
-
宽高比与预览size保持一致
实战
- geekcamera2 如何选择拍照size
获取jpeg size list核心代码
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;
}