Create Engine class

pull/493/head
Mattia Iavarone 5 years ago
parent e7727fb65c
commit e2e3054a77
  1. 9
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewCallbacksTest.java
  2. 12
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewTest.java
  3. 3
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/IntegrationTest.java
  4. 6
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java
  5. 114
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  6. 6
      cameraview/src/main/java/com/otaliastudios/cameraview/controls/ControlParser.java
  7. 48
      cameraview/src/main/java/com/otaliastudios/cameraview/controls/Engine.java
  8. 6
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java
  9. 5
      cameraview/src/main/res/values/attrs.xml

@ -10,6 +10,8 @@ import androidx.test.filters.MediumTest;
import android.view.ViewGroup;
import com.otaliastudios.cameraview.controls.Audio;
import com.otaliastudios.cameraview.controls.Engine;
import com.otaliastudios.cameraview.controls.Preview;
import com.otaliastudios.cameraview.engine.CameraEngine;
import com.otaliastudios.cameraview.frame.Frame;
import com.otaliastudios.cameraview.frame.FrameProcessor;
@ -37,7 +39,6 @@ import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyFloat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.floatThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@ -70,14 +71,14 @@ public class CameraViewCallbacksTest extends BaseTest {
@NonNull
@Override
protected CameraEngine instantiateCameraController(@NonNull CameraEngine.Callback callback) {
protected CameraEngine instantiateCameraEngine(@NonNull Engine engine, @NonNull CameraEngine.Callback callback) {
mockController = new MockCameraEngine(callback);
return mockController;
}
@NonNull
@Override
protected CameraPreview instantiatePreview(@NonNull Context context, @NonNull ViewGroup container) {
protected CameraPreview instantiatePreview(@NonNull Preview preview, @NonNull Context context, @NonNull ViewGroup container) {
mockPreview = new MockCameraPreview(context, container);
return mockPreview;
}
@ -87,7 +88,7 @@ public class CameraViewCallbacksTest extends BaseTest {
return true;
}
};
camera.instantiatePreview();
camera.doInstantiatePreview();
camera.addCameraListener(listener);
camera.addFrameProcessor(processor);
task = new Task<>(true);

@ -13,8 +13,10 @@ import android.view.ViewGroup;
import com.otaliastudios.cameraview.controls.Audio;
import com.otaliastudios.cameraview.controls.ControlParser;
import com.otaliastudios.cameraview.controls.Engine;
import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.controls.Preview;
import com.otaliastudios.cameraview.engine.CameraEngine;
import com.otaliastudios.cameraview.frame.Frame;
import com.otaliastudios.cameraview.frame.FrameProcessor;
@ -40,14 +42,10 @@ import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.cameraview.size.SizeSelector;
import com.otaliastudios.cameraview.size.SizeSelectors;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@ -77,14 +75,14 @@ public class CameraViewTest extends BaseTest {
@NonNull
@Override
protected CameraEngine instantiateCameraController(@NonNull CameraEngine.Callback callback) {
protected CameraEngine instantiateCameraEngine(@NonNull Engine engine, @NonNull CameraEngine.Callback callback) {
mockController = spy(new MockCameraEngine(callback));
return mockController;
}
@NonNull
@Override
protected CameraPreview instantiatePreview(@NonNull Context context, @NonNull ViewGroup container) {
protected CameraPreview instantiatePreview(@NonNull Preview preview, @NonNull Context context, @NonNull ViewGroup container) {
mockPreview = spy(new MockCameraPreview(context, container));
return mockPreview;
}
@ -95,7 +93,7 @@ public class CameraViewTest extends BaseTest {
}
};
// Instantiate preview now.
cameraView.instantiatePreview();
cameraView.doInstantiatePreview();
}
});
}

@ -15,6 +15,7 @@ import com.otaliastudios.cameraview.PictureResult;
import com.otaliastudios.cameraview.TestActivity;
import com.otaliastudios.cameraview.VideoResult;
import com.otaliastudios.cameraview.controls.Audio;
import com.otaliastudios.cameraview.controls.Engine;
import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.controls.Hdr;
import com.otaliastudios.cameraview.controls.Mode;
@ -87,7 +88,7 @@ public class IntegrationTest extends BaseTest {
@NonNull
@Override
protected CameraEngine instantiateCameraController(@NonNull CameraEngine.Callback callback) {
protected CameraEngine instantiateCameraEngine(@NonNull Engine engine, @NonNull CameraEngine.Callback callback) {
controller = new Camera1Engine(callback);
return controller;
}

@ -5,6 +5,7 @@ import android.hardware.Camera;
import com.otaliastudios.cameraview.controls.Audio;
import com.otaliastudios.cameraview.controls.Control;
import com.otaliastudios.cameraview.controls.Engine;
import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.engine.Mapper;
@ -183,6 +184,8 @@ public class CameraOptions {
return (Collection<T>) Arrays.asList(VideoCodec.values());
} else if (controlClass.equals(WhiteBalance.class)) {
return (Collection<T>) getSupportedWhiteBalance();
} else if (controlClass.equals(Engine.class)) {
return (Collection<T>) Arrays.asList(Engine.values());
}
// Unrecognized control.
return Collections.emptyList();
@ -311,8 +314,7 @@ public class CameraOptions {
/**
* Whether auto focus is supported. This means you can map gestures to
* {@link GestureAction#FOCUS} or {@link GestureAction#FOCUS_WITH_MARKER}
* and focus will be changed on tap.
* {@link GestureAction#AUTO_FOCUS} and focus will be changed on tap.
*
* @return whether auto focus is supported.
*/

@ -33,6 +33,7 @@ import android.widget.FrameLayout;
import com.otaliastudios.cameraview.controls.Audio;
import com.otaliastudios.cameraview.controls.Control;
import com.otaliastudios.cameraview.controls.ControlParser;
import com.otaliastudios.cameraview.controls.Engine;
import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.markers.MarkerLayout;
@ -100,6 +101,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
private boolean mPlaySounds;
private HashMap<Gesture, GestureAction> mGestureMap = new HashMap<>(4);
private Preview mPreview;
private Engine mEngine;
// Components
@VisibleForTesting CameraCallbacks mCameraCallbacks;
@ -148,8 +150,9 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
boolean playSounds = a.getBoolean(R.styleable.CameraView_cameraPlaySounds, DEFAULT_PLAY_SOUNDS);
mExperimental = a.getBoolean(R.styleable.CameraView_cameraExperimental, false);
mPreview = controls.getPreview();
mEngine = controls.getEngine();
// Camera controller params
// Camera engine params
int gridColor = a.getColor(R.styleable.CameraView_cameraGridColor, GridLinesLayout.DEFAULT_COLOR);
long videoMaxSize = (long) a.getFloat(R.styleable.CameraView_cameraVideoMaxSize, 0);
int videoMaxDuration = a.getInteger(R.styleable.CameraView_cameraVideoMaxDuration, 0);
@ -166,7 +169,6 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
// Components
mCameraCallbacks = new CameraCallbacks();
mCameraEngine = instantiateCameraController(mCameraCallbacks);
mUiHandler = new Handler(Looper.getMainLooper());
mFrameProcessorsHandler = WorkerHandler.get("FrameProcessorsWorker");
@ -182,16 +184,20 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
addView(mScrollGestureLayout);
addView(mMarkerLayout);
// Create the engine
doInstantiateEngine();
// Apply self managed
setPlaySounds(playSounds);
setGrid(controls.getGrid());
setGridColor(gridColor);
// Apply camera controller params
// Apply camera engine params
// Adding new ones? See setEngine().
setFacing(controls.getFacing());
setFlash(controls.getFlash());
setMode(controls.getMode());
setWhiteBalance(controls.getWhiteBalance());
setGrid(controls.getGrid());
setGridColor(gridColor);
setHdr(controls.getHdr());
setAudio(controls.getAudio());
setAudioBitRate(audioBitRate);
@ -220,24 +226,33 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
/**
* Instantiates the camera engine.
*
* @param engine the engine preference
* @param callback the engine callback
* @return the engine
*/
@NonNull
protected CameraEngine instantiateCameraController(@NonNull CameraEngine.Callback callback) {
return new Camera1Engine(callback);
protected CameraEngine instantiateCameraEngine(@NonNull Engine engine, @NonNull CameraEngine.Callback callback) {
if (mExperimental && engine == Engine.CAMERA2) {
throw new RuntimeException("TODO");
} else {
mEngine = Engine.CAMERA1;
return new Camera1Engine(callback);
}
}
/**
* Instantiates the camera preview.
*
* @param preview current preview value
* @param context a context
* @param container the container
* @return the preview
*/
@NonNull
protected CameraPreview instantiatePreview(@NonNull Context context, @NonNull ViewGroup container) {
protected CameraPreview instantiatePreview(@NonNull Preview preview, @NonNull Context context, @NonNull ViewGroup container) {
LOG.w("preview:", "isHardwareAccelerated:", isHardwareAccelerated());
switch (mPreview) {
switch (preview) {
case SURFACE:
return new SurfaceCameraPreview(context, container, null);
case TEXTURE: {
@ -254,18 +269,22 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
@VisibleForTesting
void instantiatePreview() {
mCameraPreview = instantiatePreview(getContext(), this);
void doInstantiatePreview() {
mCameraPreview = instantiatePreview(mPreview, getContext(), this);
mCameraEngine.setPreview(mCameraPreview);
}
private void doInstantiateEngine() {
mCameraEngine = instantiateCameraEngine(mEngine, mCameraCallbacks);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mCameraPreview == null) {
// isHardwareAccelerated will return the real value only after we are
// attached. That's why we instantiate the preview here.
instantiatePreview();
doInstantiatePreview();
}
if (!isInEditMode()) {
mOrientationHelper.enable(getContext());
@ -719,10 +738,64 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
setVideoCodec((VideoCodec) control);
} else if (control instanceof Preview) {
setPreview((Preview) control);
} else if (control instanceof Engine) {
setEngine((Engine) control);
}
}
/**
* Controls the preview engine. Should only be called
* if this CameraView was never added to any window
* (like if you created it programmatically).
* Otherwise, it has no effect.
*
* @see Preview#SURFACE
* @see Preview#TEXTURE
* @see Preview#GL_SURFACE
*
* @param preview desired preview engine
*/
public void setPreview(@NonNull Preview preview) {
mPreview = preview;
}
/**
* Controls the core engine. Should only be called
* if this CameraView is closed (open() was never called).
* Otherwise, it has no effect.
*
* @see Engine#CAMERA1
* @see Engine#CAMERA2
*
* @param engine desired engine
*/
public void setEngine(@NonNull Engine engine) {
if (!isClosed()) return;
mEngine = engine;
CameraEngine oldEngine = mCameraEngine;
doInstantiateEngine();
if (mCameraPreview != null) mCameraEngine.setPreview(mCameraPreview);
// Set again all parameters
setFacing(oldEngine.getFacing());
setFlash(oldEngine.getFlash());
setMode(oldEngine.getMode());
setWhiteBalance(oldEngine.getWhiteBalance());
setHdr(oldEngine.getHdr());
setAudio(oldEngine.getAudio());
setAudioBitRate(oldEngine.getAudioBitRate());
setPictureSize(oldEngine.getPictureSizeSelector());
setVideoSize(oldEngine.getVideoSizeSelector());
setVideoCodec(oldEngine.getVideoCodec());
setVideoMaxSize(oldEngine.getVideoMaxSize());
setVideoMaxDuration(oldEngine.getVideoMaxDuration());
setVideoBitRate(oldEngine.getVideoBitRate());
setAutoFocusResetDelay(oldEngine.getAutoFocusResetDelay());
}
/**
* Returns a {@link CameraOptions} instance holding supported options for this camera
* session. This might change over time. It's better to hold a reference from
@ -854,23 +927,6 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
/**
* Controls the preview engine. Should only be called
* if this CameraView was never added to any window
* (like if you created it programmatically).
* Otherwise, it has no effect.
*
* @see Preview#SURFACE
* @see Preview#TEXTURE
* @see Preview#GL_SURFACE
*
* @param preview desired preview engine
*/
public void setPreview(@NonNull Preview preview) {
mPreview = preview;
}
/**
* Gets the current hdr value.
* @return the current hdr value

@ -21,6 +21,7 @@ public class ControlParser {
private int hdr;
private int audio;
private int videoCodec;
private int engine;
public ControlParser(@NonNull Context context, @NonNull TypedArray array) {
this.preview = array.getInteger(R.styleable.CameraView_cameraPreview, Preview.DEFAULT.value());
@ -32,6 +33,7 @@ public class ControlParser {
this.hdr = array.getInteger(R.styleable.CameraView_cameraHdr, Hdr.DEFAULT.value());
this.audio = array.getInteger(R.styleable.CameraView_cameraAudio, Audio.DEFAULT.value());
this.videoCodec = array.getInteger(R.styleable.CameraView_cameraVideoCodec, VideoCodec.DEFAULT.value());
this.engine = array.getInteger(R.styleable.CameraView_cameraEngine, Engine.DEFAULT.value());
}
public Preview getPreview() {
@ -69,4 +71,8 @@ public class ControlParser {
public VideoCodec getVideoCodec() {
return VideoCodec.fromValue(videoCodec);
}
public Engine getEngine() {
return Engine.fromValue(engine);
}
}

@ -0,0 +1,48 @@
package com.otaliastudios.cameraview.controls;
import com.otaliastudios.cameraview.CameraView;
import androidx.annotation.Nullable;
/**
* The engine to be used.
*
* @see CameraView#setEngine(Engine)
*/
public enum Engine implements Control {
/**
* Camera1 based engine.
*/
CAMERA1(0),
/**
* Camera2 based engine. For API versions older than 21,
* the system falls back to {@link #CAMERA1}.
*/
CAMERA2(1);
final static Engine DEFAULT = CAMERA1;
private int value;
Engine(int value) {
this.value = value;
}
int value() {
return value;
}
@Nullable
static Engine fromValue(int value) {
Engine[] list = Engine.values();
for (Engine action : list) {
if (action.value() == value) {
return action;
}
}
return null;
}
}

@ -494,15 +494,13 @@ public abstract class CameraEngine implements
@SuppressWarnings("unused")
@NonNull
@VisibleForTesting
final SizeSelector getPictureSizeSelector() {
public final SizeSelector getPictureSizeSelector() {
return mPictureSizeSelector;
}
@SuppressWarnings("unused")
@NonNull
@VisibleForTesting
final SizeSelector getVideoSizeSelector() {
public final SizeSelector getVideoSizeSelector() {
return mVideoSizeSelector;
}

@ -108,6 +108,11 @@
<enum name="glSurface" value="2" />
</attr>
<attr name="cameraEngine" format="enum">
<enum name="camera1" value="0" />
<enum name="camera2" value="1" />
</attr>
<attr name="cameraPlaySounds" format="boolean" />
<attr name="cameraVideoMaxSize" format="float" />

Loading…
Cancel
Save