Add option to capture hardware accelerated overlays (#1066)

* Add option to capture hardware accelerated overlays

* PR updates

* One more variable name change
pull/1089/head
Ryan Loebs 4 years ago committed by GitHub
parent f608ec3918
commit bde88a946e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewTest.java
  2. 22
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  3. 14
      cameraview/src/main/java/com/otaliastudios/cameraview/overlay/Overlay.java
  4. 8
      cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayDrawer.java
  5. 15
      cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayLayout.java
  6. 2
      cameraview/src/main/res/values/attrs.xml
  7. 16
      docs/_docs/watermarks-and-overlays.md

@ -913,6 +913,14 @@ public class CameraViewTest extends BaseTest {
cameraView.setFrameProcessingExecutors(0); cameraView.setFrameProcessingExecutors(0);
} }
@Test
public void testDrawHardwareOverlays() {
cameraView.setDrawHardwareOverlays(true);
assertTrue(cameraView.getDrawHardwareOverlays());
cameraView.setDrawHardwareOverlays(false);
assertFalse(cameraView.getDrawHardwareOverlays());
}
//endregion //endregion
//region Lists of listeners and processors //region Lists of listeners and processors

@ -227,6 +227,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
int frameExecutors = a.getInteger(R.styleable.CameraView_cameraFrameProcessingExecutors, int frameExecutors = a.getInteger(R.styleable.CameraView_cameraFrameProcessingExecutors,
DEFAULT_FRAME_PROCESSING_EXECUTORS); DEFAULT_FRAME_PROCESSING_EXECUTORS);
boolean drawHardwareOverlays = a.getBoolean(R.styleable.CameraView_cameraDrawHardwareOverlays, false);
// Size selectors and gestures // Size selectors and gestures
SizeSelectorParser sizeSelectors = new SizeSelectorParser(a); SizeSelectorParser sizeSelectors = new SizeSelectorParser(a);
GestureParser gestures = new GestureParser(a); GestureParser gestures = new GestureParser(a);
@ -260,6 +262,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
setUseDeviceOrientation(useDeviceOrientation); setUseDeviceOrientation(useDeviceOrientation);
setGrid(controls.getGrid()); setGrid(controls.getGrid());
setGridColor(gridColor); setGridColor(gridColor);
setDrawHardwareOverlays(drawHardwareOverlays);
// Apply camera engine params // Apply camera engine params
// Adding new ones? See setEngine(). // Adding new ones? See setEngine().
@ -2156,6 +2159,25 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
return mCameraEngine.isTakingPicture(); return mCameraEngine.isTakingPicture();
} }
/**
* Sets the overlay layout hardware canvas capture mode to allow hardware
* accelerated views to be captured in snapshots
*
* @param on true if enabled
*/
public void setDrawHardwareOverlays(boolean on) {
mOverlayLayout.setHardwareCanvasEnabled(on);
}
/**
* Returns true if the overlay layout is set to capture the hardware canvas
* of child views
*
* @return boolean indicating hardware canvas capture is enabled
*/
public boolean getDrawHardwareOverlays() {
return mOverlayLayout.getHardwareCanvasEnabled();
}
//endregion //endregion
//region Callbacks and dispatching //region Callbacks and dispatching

@ -30,4 +30,18 @@ public interface Overlay {
* @return true to draw on it * @return true to draw on it
*/ */
boolean drawsOn(@NonNull Target target); boolean drawsOn(@NonNull Target target);
/**
* Sets the overlay renderer to lock and capture the hardware canvas in order
* to capture hardware accelerated views such as video players
*
* @param on enabled
*/
void setHardwareCanvasEnabled(boolean on);
/**
* Returns true if hardware canvas capture is enabled, false by default
* @return true if capturing hardware surfaces
*/
boolean getHardwareCanvasEnabled();
} }

@ -6,6 +6,7 @@ import android.graphics.PorterDuff;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.opengl.GLES11Ext; import android.opengl.GLES11Ext;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.os.Build;
import android.view.Surface; import android.view.Surface;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -63,7 +64,12 @@ public class OverlayDrawer {
*/ */
public void draw(@NonNull Overlay.Target target) { public void draw(@NonNull Overlay.Target target) {
try { try {
final Canvas surfaceCanvas = mSurface.lockCanvas(null); final Canvas surfaceCanvas;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mOverlay.getHardwareCanvasEnabled()) {
surfaceCanvas = mSurface.lockHardwareCanvas();
} else {
surfaceCanvas = mSurface.lockCanvas(null);
}
surfaceCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); surfaceCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
mOverlay.drawOn(target, surfaceCanvas); mOverlay.drawOn(target, surfaceCanvas);
mSurface.unlockCanvasAndPost(surfaceCanvas); mSurface.unlockCanvasAndPost(surfaceCanvas);

@ -26,6 +26,8 @@ public class OverlayLayout extends FrameLayout implements Overlay {
@VisibleForTesting Target currentTarget = Target.PREVIEW; @VisibleForTesting Target currentTarget = Target.PREVIEW;
private boolean mHardwareCanvasEnabled;
/** /**
* We set {@link #setWillNotDraw(boolean)} to false even if we don't draw anything. * We set {@link #setWillNotDraw(boolean)} to false even if we don't draw anything.
* This ensures that the View system will call {@link #draw(Canvas)} on us instead * This ensures that the View system will call {@link #draw(Canvas)} on us instead
@ -99,6 +101,16 @@ public class OverlayLayout extends FrameLayout implements Overlay {
return false; return false;
} }
@Override
public void setHardwareCanvasEnabled(boolean on) {
mHardwareCanvasEnabled = on;
}
@Override
public boolean getHardwareCanvasEnabled() {
return mHardwareCanvasEnabled;
}
/** /**
* For {@link Target#PREVIEW}, this method is called by the View hierarchy. We will * For {@link Target#PREVIEW}, this method is called by the View hierarchy. We will
* just forward the call to super. * just forward the call to super.
@ -132,7 +144,8 @@ public class OverlayLayout extends FrameLayout implements Overlay {
"canvas:", canvas.getWidth() + "x" + canvas.getHeight(), "canvas:", canvas.getWidth() + "x" + canvas.getHeight(),
"view:", getWidth() + "x" + getHeight(), "view:", getWidth() + "x" + getHeight(),
"widthScale:", widthScale, "widthScale:", widthScale,
"heightScale:", heightScale "heightScale:", heightScale,
"hardwareCanvasMode:", mHardwareCanvasEnabled
); );
canvas.scale(widthScale, heightScale); canvas.scale(widthScale, heightScale);
dispatchDraw(canvas); dispatchDraw(canvas);

@ -169,6 +169,8 @@
<attr name="cameraRequestPermissions" format="boolean|reference"/> <attr name="cameraRequestPermissions" format="boolean|reference"/>
<attr name="cameraExperimental" format="boolean|reference" /> <attr name="cameraExperimental" format="boolean|reference" />
<attr name="cameraDrawHardwareOverlays" format="boolean"/>
</declare-styleable> </declare-styleable>
<declare-styleable name="CameraView_Layout"> <declare-styleable name="CameraView_Layout">

@ -82,3 +82,19 @@ params.drawOnVideoSnapshot = false; // do not draw on video snapshots
// When done, apply // When done, apply
overlay.setLayoutParams(params); overlay.setLayoutParams(params);
``` ```
To capture a hardware rendered View such as a video rendered to a TextureView, enable the
`cameraDrawHardwareOverlays` flag:
```xml
<com.otaliastudios.cameraview.CameraView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cameraDrawHardwareOverlays="true"/>
```
Alternatively you can enable it in code with `setDrawHardwareOverlays()`:
```java
cameraView.setDrawHardwareOverlays(true);
```
Loading…
Cancel
Save