0
0
mirror of https://git.code.sf.net/p/opencamera/code.git synced 2024-09-19 19:42:29 +02:00

Smoother zoom for Camera2 API - both more zoom entries, and supporting smooth zoom for pinch zoom.

This commit is contained in:
Mark Harman 2024-02-25 16:26:59 +00:00
parent c42ac38fc5
commit a041de3ef1
6 changed files with 66 additions and 11 deletions

View File

@ -61,6 +61,7 @@ FIXED Long pressing on the shutter button in video mode meant nothing happened
ADDED Camera vendor extensions show percentage progress on supported Android 14 devices.
ADDED Long press on switch camera icons now bring up a menu to jump to any camera (for devices
that expose multiple cameras).
UPDATED Smoother zoom for Camera2 API.
UPDATED Improvements for loading thumbnails for gallery icon (including fixing orientation for
X-NIGHT portrait images on Pixel 6 Pro).
UPDATED Improvements for popup menu and exposure UI when using large font sizes.

View File

@ -5479,7 +5479,9 @@ public class MainActivity extends AppCompatActivity implements PreferenceFragmen
Log.d(TAG, "zoom onProgressChanged: " + progress);
// note we zoom even if !fromUser, as various other UI controls (multitouch, volume key zoom, -/+ zoomcontrol)
// indirectly set zoom via this method, from setting the zoom slider
preview.zoomTo(preview.getMaxZoom() - progress);
// if hasSmoothZoom()==true, then the preview already handled zooming to the current value
if( !preview.hasSmoothZoom() )
preview.zoomTo(preview.getMaxZoom() - progress, false);
}
@Override

View File

@ -60,7 +60,7 @@ public abstract class CameraController {
public static class CameraFeatures {
public boolean is_zoom_supported;
public int max_zoom;
public List<Integer> zoom_ratios;
public List<Integer> zoom_ratios; // list of supported zoom ratios; each value is the zoom multiplied by 100
public boolean supports_face_detection;
public List<CameraController.Size> picture_sizes;
public List<CameraController.Size> video_sizes;
@ -541,8 +541,25 @@ public abstract class CameraController {
public abstract TonemapProfile getTonemapProfile();
public abstract int getJpegQuality();
public abstract void setJpegQuality(int quality);
/** Returns the current zoom. The returned value is an index into the CameraFeatures.zoom_ratios
* array.
*/
public abstract int getZoom();
/** Set the zoom.
* @param value The index into the CameraFeatures.zoom_ratios array.
*/
public abstract void setZoom(int value);
/** Set the zoom. Unlike setZoom(value), this allows specifying any zoom level within the
* supported range.
* @param value The index into the CameraFeatures.zoom_ratios array.
* @param smooth_zoom The desired zoom. With CameraController1 (old Camera API), this is ignored.
* With CameraController2 (Camera2 API), this is used instead of the zoom_ratios
* value. Note that getZoom() will return the value passed to this method, so
* passing an appropriate value (e.g., whatever zoom_ratio is closest to the
* smooth_zoom) is still useful if you want to make use of getZoom().
* smooth_zoom must still be within the supported range of zoom values.
*/
public abstract void setZoom(int value, float smooth_zoom);
public abstract void resetZoom(); // resets to zoom 1x
public abstract int getExposureCompensation();
public abstract boolean setExposureCompensation(int new_exposure);

View File

@ -963,6 +963,11 @@ public class CameraController1 extends CameraController {
}
}
@Override
public void setZoom(int value, float smooth_zoom) {
setZoom(value);
}
@Override
public void resetZoom() {
setZoom(0);

View File

@ -2514,12 +2514,12 @@ public class CameraController2 extends CameraController {
int zoom_value_1x;
// prepare zoom rations > 1x
// set 20 steps per 2x factor
final double scale_factor_c = 1.0352649238413775043477881942112;
// set 40 steps per 2x factor
final double scale_factor_c = 1.0174796921026863936352862847966;
List<Integer> zoom_ratios_above_one = new ArrayList<>();
double zoom = scale_factor_c;
while( zoom < max_zoom - 1.0e-5f ) {
int zoom_ratio = (int)(zoom*100);
int zoom_ratio = (int)(zoom*100+1.0e-5);
zoom_ratios_above_one.add(zoom_ratio);
zoom *= scale_factor_c;
}
@ -4801,6 +4801,11 @@ public class CameraController2 extends CameraController {
@Override
public void setZoom(int value) {
setZoom(value, -1.0f);
}
@Override
public void setZoom(int value, float smooth_zoom) {
if( zoom_ratios == null ) {
if( MyDebug.LOG )
Log.d(TAG, "zoom not supported");
@ -4821,7 +4826,21 @@ public class CameraController2 extends CameraController {
Log.e(TAG, "invalid zoom value" + value);
throw new RuntimeException(); // throw as RuntimeException, as this is a programming error
}
float zoom = zoom_ratios.get(value)/100.0f;
if( smooth_zoom > 0.0f ) {
if( smooth_zoom < zoom_ratios.get(0)/100.0f ) {
if( MyDebug.LOG )
Log.e(TAG, "invalid smooth_zoom: " + smooth_zoom);
throw new RuntimeException("smooth_zoom too small");
}
else if( smooth_zoom > zoom_ratios.get(zoom_ratios.size()-1)/100.0f ) {
if( MyDebug.LOG )
Log.e(TAG, "invalid smooth_zoom: " + smooth_zoom);
throw new RuntimeException("smooth_zoom too large");
}
}
float zoom = smooth_zoom > 0.0f ? smooth_zoom : zoom_ratios.get(value)/100.0f;
if( MyDebug.LOG )
Log.d(TAG, "zoom to: " + zoom);
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ) {
camera_settings.has_control_zoom_ratio = true;

View File

@ -761,6 +761,13 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu
private boolean has_smooth_zoom = false;
private float smooth_zoom = 1.0f;
/** Returns true if the user is currently pinch zooming, and the Preview has already handled setting
* the zoom via Preview.zoomTo().
*/
public boolean hasSmoothZoom() {
return this.has_smooth_zoom;
}
/** Handle multitouch zoom.
*/
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@ -821,7 +828,7 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu
if( MyDebug.LOG )
Log.d(TAG, "snapped pinch zoom to 1x zoom");
int snapped_zoom = find1xZoom();
zoomTo(snapped_zoom);
zoomTo(snapped_zoom, false);
}
}
}
@ -2208,7 +2215,7 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu
if( zoom_pref == -1 ) {
zoom_pref = find1xZoom();
}
zoomTo(zoom_pref);
zoomTo(zoom_pref, false);
if( MyDebug.LOG ) {
Log.d(TAG, "setupCamera: total time after zoomTo: " + (System.currentTimeMillis() - debug_time));
}
@ -4303,7 +4310,9 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu
Log.d(TAG, "scaleZoom() " + scale_factor);
if( this.camera_controller != null && this.has_zoom ) {
int new_zoom_factor = getScaledZoomFactor(scale_factor);
// n.b., don't call zoomTo; this should be called indirectly by applicationInterface.multitouchZoom()
if( has_smooth_zoom )
zoomTo(new_zoom_factor, true);
// else don't call zoomTo; this should be called indirectly by applicationInterface.multitouchZoom()
applicationInterface.multitouchZoom(new_zoom_factor);
}
}
@ -4311,7 +4320,7 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu
/** Zooms to the supplied index (within the zoom_ratios array).
* @param new_zoom_factor The index to zoom to.
*/
public void zoomTo(int new_zoom_factor) {
public void zoomTo(int new_zoom_factor, boolean allow_smooth_zoom) {
if( MyDebug.LOG )
Log.d(TAG, "ZoomTo(): " + new_zoom_factor);
if( new_zoom_factor < 0 )
@ -4322,7 +4331,9 @@ public class Preview implements SurfaceHolder.Callback, TextureView.SurfaceTextu
if( camera_controller != null ) {
if( this.has_zoom ) {
// don't cancelAutoFocus() here, otherwise we get sluggish zoom behaviour on Camera2 API
camera_controller.setZoom(new_zoom_factor);
// if pinch zooming, pass through the "smooth" zoom factor so for Camera2 API we get perfectly smooth zoom, rather than it
// being snapped to the discrete zoom values
camera_controller.setZoom(new_zoom_factor, (allow_smooth_zoom && has_smooth_zoom) ? smooth_zoom : -1.0f);
applicationInterface.setZoomPref(new_zoom_factor);
clearFocusAreas();
}