-
Notifications
You must be signed in to change notification settings - Fork 9.8k
[Camera] Improved resolution presets #1952
Changes from all commits
9a774a8
1232d22
39c2d0e
dcac87d
018521d
945dc88
0972b28
5f482cc
d376121
875b28e
5d07729
efc525a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,15 +3,14 @@ | |
import android.app.Activity; | ||
import android.content.Context; | ||
import android.graphics.ImageFormat; | ||
import android.graphics.Point; | ||
import android.graphics.SurfaceTexture; | ||
import android.hardware.camera2.CameraAccessException; | ||
import android.hardware.camera2.CameraCharacteristics; | ||
import android.hardware.camera2.CameraManager; | ||
import android.hardware.camera2.CameraMetadata; | ||
import android.hardware.camera2.params.StreamConfigurationMap; | ||
import android.media.CamcorderProfile; | ||
import android.util.Size; | ||
import android.view.Display; | ||
import io.flutter.plugins.camera.Camera.ResolutionPreset; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
|
@@ -25,61 +24,14 @@ public final class CameraUtils { | |
|
||
private CameraUtils() {} | ||
|
||
static Size[] computeBestPreviewAndRecordingSize( | ||
Activity activity, | ||
StreamConfigurationMap streamConfigurationMap, | ||
int minHeight, | ||
int orientation, | ||
Size captureSize) { | ||
Size previewSize, videoSize; | ||
Size[] sizes = streamConfigurationMap.getOutputSizes(SurfaceTexture.class); | ||
|
||
// Preview size and video size should not be greater than screen resolution or 1080. | ||
Point screenResolution = new Point(); | ||
|
||
Display display = activity.getWindowManager().getDefaultDisplay(); | ||
display.getRealSize(screenResolution); | ||
|
||
final boolean swapWH = orientation % 180 == 90; | ||
int screenWidth = swapWH ? screenResolution.y : screenResolution.x; | ||
int screenHeight = swapWH ? screenResolution.x : screenResolution.y; | ||
|
||
List<Size> goodEnough = new ArrayList<>(); | ||
for (Size s : sizes) { | ||
if (minHeight <= s.getHeight() | ||
&& s.getWidth() <= screenWidth | ||
&& s.getHeight() <= screenHeight | ||
&& s.getHeight() <= 1080) { | ||
goodEnough.add(s); | ||
} | ||
static Size computeBestPreviewSize(String cameraName, ResolutionPreset preset) { | ||
if (preset.ordinal() > ResolutionPreset.high.ordinal()) { | ||
preset = ResolutionPreset.high; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you set the preset to high here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think it's that high res previews negatively impact performance. The current code in master is setting previewSize to be the absolute minimum resolution that's the correct aspect ratio, and is also capped at 1080 (line 37 in the original patch). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe you could improve to let the choice to the user here. My current use case need a stream at the highest resolution. And without this clamp, the function startPreviewWithImageStream works perfectly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be acceptable to set the default to |
||
} | ||
|
||
Collections.sort(goodEnough, new CompareSizesByArea()); | ||
|
||
if (goodEnough.isEmpty()) { | ||
previewSize = sizes[0]; | ||
videoSize = sizes[0]; | ||
} else { | ||
float captureSizeRatio = (float) captureSize.getWidth() / captureSize.getHeight(); | ||
|
||
previewSize = goodEnough.get(0); | ||
for (Size s : goodEnough) { | ||
if ((float) s.getWidth() / s.getHeight() == captureSizeRatio) { | ||
previewSize = s; | ||
break; | ||
} | ||
} | ||
|
||
Collections.reverse(goodEnough); | ||
videoSize = goodEnough.get(0); | ||
for (Size s : goodEnough) { | ||
if ((float) s.getWidth() / s.getHeight() == captureSizeRatio) { | ||
videoSize = s; | ||
break; | ||
} | ||
} | ||
} | ||
return new Size[] {videoSize, previewSize}; | ||
CamcorderProfile profile = | ||
getBestAvailableCamcorderProfileForResolutionPreset(cameraName, preset); | ||
return new Size(profile.videoFrameWidth, profile.videoFrameHeight); | ||
} | ||
|
||
static Size computeBestCaptureSize(StreamConfigurationMap streamConfigurationMap) { | ||
|
@@ -118,6 +70,46 @@ public static List<Map<String, Object>> getAvailableCameras(Activity activity) | |
return cameras; | ||
} | ||
|
||
static CamcorderProfile getBestAvailableCamcorderProfileForResolutionPreset( | ||
String cameraName, ResolutionPreset preset) { | ||
int cameraId = Integer.parseInt(cameraName); | ||
switch (preset) { | ||
// All of these cases deliberately fall through to get the best available profile. | ||
case max: | ||
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH)) { | ||
return CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH); | ||
} | ||
case ultraHigh: | ||
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_2160P)) { | ||
return CamcorderProfile.get(CamcorderProfile.QUALITY_2160P); | ||
} | ||
case veryHigh: | ||
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_1080P)) { | ||
return CamcorderProfile.get(CamcorderProfile.QUALITY_1080P); | ||
} | ||
case high: | ||
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P)) { | ||
return CamcorderProfile.get(CamcorderProfile.QUALITY_720P); | ||
} | ||
case medium: | ||
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P)) { | ||
return CamcorderProfile.get(CamcorderProfile.QUALITY_480P); | ||
} | ||
case low: | ||
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_QVGA)) { | ||
return CamcorderProfile.get(CamcorderProfile.QUALITY_QVGA); | ||
} | ||
default: | ||
if (CamcorderProfile.hasProfile( | ||
Integer.parseInt(cameraName), CamcorderProfile.QUALITY_LOW)) { | ||
return CamcorderProfile.get(CamcorderProfile.QUALITY_LOW); | ||
} else { | ||
throw new IllegalArgumentException( | ||
"No capture session available for current capture session."); | ||
} | ||
} | ||
} | ||
|
||
private static class CompareSizesByArea implements Comparator<Size> { | ||
@Override | ||
public int compare(Size lhs, Size rhs) { | ||
|
Uh oh!
There was an error while loading. Please reload this page.