* Use CopyOnWrite set in GL preview (Fix #626)

* Demo app - do not add frame processor when opening (Fix #628)

* Add comments

* Create EngineThread annotation

* Fix onVideoResult crash for snapshots

* Catch IllegalStateExceptions in applyRepeatingRequestBuilder

* Add exception to LOG.e

* Add changelog

* Release v2.3.1

* Move snapshot logs to verbose
pull/659/head v2.3.1
Mattia Iavarone 5 years ago committed by GitHub
parent 19f607a959
commit 55e7a26278
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      README.md
  2. 2
      cameraview/build.gradle
  3. 21
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java
  4. 45
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java
  5. 52
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java
  6. 7
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/EngineThread.java
  7. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayLayout.java
  8. 16
      cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java
  9. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/video/SnapshotVideoRecorder.java
  10. 10
      cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/AudioMediaEncoder.java
  11. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoder.java
  12. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoderEngine.java
  13. 6
      cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/TextureMediaEncoder.java
  14. 5
      demo/build.gradle
  15. 6
      demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java
  16. 10
      docs/_posts/2018-12-20-changelog.md
  17. 2
      docs/_posts/2018-12-20-install.md

@ -22,7 +22,7 @@ CameraView is a well documented, high-level library that makes capturing picture
addressing most of the common issues and needs, and still leaving you with flexibility where needed.
```groovy
api 'com.otaliastudios:cameraview:2.3.0'
api 'com.otaliastudios:cameraview:2.3.1'
```
- Fast & reliable

@ -3,7 +3,7 @@ apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
// Required by bintray
version = '2.3.0'
version = '2.3.1'
group = 'com.otaliastudios'
//region android dependencies

@ -97,6 +97,7 @@ public class Camera1Engine extends CameraEngine implements
//region Protected APIs
@EngineThread
@NonNull
@Override
protected List<Size> getPreviewStreamAvailableSizes() {
@ -110,12 +111,13 @@ public class Camera1Engine extends CameraEngine implements
return result;
}
@WorkerThread
@EngineThread
@Override
protected void onPreviewStreamSizeChanged() {
restartPreview();
}
@EngineThread
@Override
protected boolean collectCameraInfo(@NonNull Facing facing) {
int internalFacing = mMapper.mapFacing(facing);
@ -140,7 +142,7 @@ public class Camera1Engine extends CameraEngine implements
//region Start
@NonNull
@WorkerThread
@EngineThread
@Override
protected Task<Void> onStartEngine() {
try {
@ -164,6 +166,7 @@ public class Camera1Engine extends CameraEngine implements
return Tasks.forResult(null);
}
@EngineThread
@NonNull
@Override
protected Task<Void> onStartBind() {
@ -187,6 +190,7 @@ public class Camera1Engine extends CameraEngine implements
return Tasks.forResult(null);
}
@EngineThread
@NonNull
@Override
protected Task<Void> onStartPreview() {
@ -238,6 +242,7 @@ public class Camera1Engine extends CameraEngine implements
//region Stop
@EngineThread
@NonNull
@Override
protected Task<Void> onStopPreview() {
@ -256,6 +261,7 @@ public class Camera1Engine extends CameraEngine implements
return Tasks.forResult(null);
}
@EngineThread
@NonNull
@Override
protected Task<Void> onStopBind() {
@ -275,8 +281,8 @@ public class Camera1Engine extends CameraEngine implements
return Tasks.forResult(null);
}
@EngineThread
@NonNull
@WorkerThread
@Override
protected Task<Void> onStopEngine() {
LOG.i("onStopEngine:", "About to clean up.");
@ -306,7 +312,7 @@ public class Camera1Engine extends CameraEngine implements
//region Pictures
@WorkerThread
@EngineThread
@Override
protected void onTakePicture(@NonNull PictureResult.Stub stub, boolean doMetering) {
stub.rotation = getAngles().offset(Reference.SENSOR, Reference.OUTPUT,
@ -316,7 +322,7 @@ public class Camera1Engine extends CameraEngine implements
mPictureRecorder.take();
}
@WorkerThread
@EngineThread
@Override
protected void onTakePictureSnapshot(@NonNull PictureResult.Stub stub,
@NonNull AspectRatio outputRatio,
@ -337,6 +343,7 @@ public class Camera1Engine extends CameraEngine implements
//region Videos
@EngineThread
@Override
protected void onTakeVideo(@NonNull VideoResult.Stub stub) {
stub.rotation = getAngles().offset(Reference.SENSOR, Reference.OUTPUT,
@ -357,7 +364,7 @@ public class Camera1Engine extends CameraEngine implements
}
@SuppressLint("NewApi")
@WorkerThread
@EngineThread
@Override
protected void onTakeVideoSnapshot(@NonNull VideoResult.Stub stub,
@NonNull AspectRatio outputRatio) {
@ -765,7 +772,7 @@ public class Camera1Engine extends CameraEngine implements
}
@NonNull
@WorkerThread
@EngineThread
private static List<Camera.Area> computeMeteringAreas(double viewClickX, double viewClickY,
int viewWidth, int viewHeight,
int sensorToDisplay) {

@ -28,7 +28,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.TaskCompletionSource;
@ -246,6 +245,17 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
mRepeatingRequestCallback, null);
} catch (CameraAccessException e) {
throw new CameraException(e, errorReason);
} catch (IllegalStateException e) {
// mSession is invalid - has been closed. This is extremely worrying because
// it means that the session state and getPreviewState() are not synced.
// This probably signals an error in the setup/teardown synchronization.
LOG.e("applyRepeatingRequestBuilder: session is invalid!", e,
"checkStarted:", checkStarted,
"currentThread:", Thread.currentThread().getName(),
"previewState:", getPreviewState(),
"bindState:", getBindState(),
"engineState:", getEngineState());
throw new CameraException(CameraException.REASON_DISCONNECTED);
}
}
}
@ -286,6 +296,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
//region Protected APIs
@EngineThread
@NonNull
@Override
protected List<Size> getPreviewStreamAvailableSizes() {
@ -310,12 +321,13 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
}
}
@WorkerThread
@EngineThread
@Override
protected void onPreviewStreamSizeChanged() {
restartBind();
}
@EngineThread
@Override
protected final boolean collectCameraInfo(@NonNull Facing facing) {
int internalFacing = mMapper.mapFacing(facing);
@ -353,6 +365,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
//region Start
@EngineThread
@SuppressLint("MissingPermission")
@NonNull
@Override
@ -402,6 +415,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
return task.getTask();
}
@EngineThread
@NonNull
@Override
protected Task<Void> onStartBind() {
@ -525,6 +539,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
return task.getTask();
}
@EngineThread
@NonNull
@Override
protected Task<Void> onStartPreview() {
@ -569,6 +584,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
//region Stop
@EngineThread
@NonNull
@Override
protected Task<Void> onStopPreview() {
@ -598,7 +614,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
return Tasks.forResult(null);
}
@EngineThread
@NonNull
@Override
protected Task<Void> onStopBind() {
@ -627,7 +643,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
return Tasks.forResult(null);
}
@EngineThread
@NonNull
@Override
protected Task<Void> onStopEngine() {
@ -660,7 +676,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
//region Pictures
@WorkerThread
@EngineThread
@Override
protected void onTakePictureSnapshot(@NonNull final PictureResult.Stub stub,
@NonNull final AspectRatio outputRatio,
@ -692,6 +708,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
}
}
@EngineThread
@Override
protected void onTakePicture(@NonNull final PictureResult.Stub stub, boolean doMetering) {
if (doMetering) {
@ -752,7 +769,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
//region Videos
@WorkerThread
@EngineThread
@Override
protected void onTakeVideo(@NonNull VideoResult.Stub stub) {
LOG.i("onTakeVideo", "called.");
@ -787,7 +804,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
}
}
@WorkerThread
@EngineThread
@Override
protected void onTakeVideoSnapshot(@NonNull VideoResult.Stub stub,
@NonNull AspectRatio outputRatio) {
@ -832,7 +849,9 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
@Override
public void onVideoRecordingEnd() {
super.onVideoRecordingEnd();
boolean needsIssue549Workaround = (mVideoRecorder instanceof Full2VideoRecorder) ||
// SnapshotRecorder will invoke this on its own thread which is risky, but if it was a
// snapshot, this function returns early so its safe.
boolean needsIssue549Workaround = (mVideoRecorder instanceof Full2VideoRecorder) &&
(readCharacteristic(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL, -1)
== CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY);
if (needsIssue549Workaround) {
@ -843,8 +862,17 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
@Override
public void onVideoResult(@Nullable VideoResult.Stub result, @Nullable Exception exception) {
super.onVideoResult(result, exception);
// SnapshotRecorder will invoke this on its own thread, so let's post in our own thread
// and check camera state before trying to restore the preview. Engine might have been
// torn down in the engine thread while this was still being called.
mHandler.run(new Runnable() {
@Override
public void run() {
if (getBindState() < STATE_STARTED) return;
maybeRestorePreviewTemplateAfterVideo();
}
});
}
/**
* Video recorders might change the camera template to {@link CameraDevice#TEMPLATE_RECORD}.
@ -854,6 +882,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv
* This method avoids doing this twice by checking the request tag, as set by
* the {@link #createRepeatingRequestBuilder(int)} method.
*/
@EngineThread
private void maybeRestorePreviewTemplateAfterVideo() {
int template = (int) mRepeatingRequestBuilder.build().getTag();
if (template != CameraDevice.TEMPLATE_PREVIEW) {

@ -47,7 +47,6 @@ import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import java.io.File;
import java.util.ArrayList;
@ -303,7 +302,7 @@ public abstract class CameraEngine implements
final CameraException cameraException = (CameraException) throwable;
LOG.e("uncaughtException:", "Got CameraException:", cameraException,
"on engine state:", getEngineStateName());
"on engine state:", getEngineState());
if (fromExceptionHandler) {
// Got to restart the handler.
thread.interrupt();
@ -336,11 +335,6 @@ public abstract class CameraEngine implements
return mPreviewStep.getState();
}
@NonNull
private String getEngineStateName() {
return mEngineStep.getStateName();
}
private boolean canStartEngine() {
return mEngineStep.isStoppingOrStopped();
}
@ -375,7 +369,7 @@ public abstract class CameraEngine implements
//region Start & Stop the engine
@NonNull
@WorkerThread
@EngineThread
private Task<Void> startEngine() {
if (canStartEngine()) {
mEngineStep.doStart(false, new Callable<Task<Void>>() {
@ -398,7 +392,7 @@ public abstract class CameraEngine implements
}
@NonNull
@WorkerThread
@EngineThread
private Task<Void> stopEngine(boolean swallowExceptions) {
if (needsStopEngine()) {
mEngineStep.doStop(swallowExceptions, new Callable<Task<Void>>() {
@ -421,7 +415,7 @@ public abstract class CameraEngine implements
* @return a task
*/
@NonNull
@WorkerThread
@EngineThread
protected abstract Task<Void> onStartEngine();
/**
@ -431,7 +425,7 @@ public abstract class CameraEngine implements
* @return a task
*/
@NonNull
@WorkerThread
@EngineThread
protected abstract Task<Void> onStopEngine();
//endregion
@ -439,7 +433,7 @@ public abstract class CameraEngine implements
//region Start & Stop binding
@NonNull
@WorkerThread
@EngineThread
private Task<Void> startBind() {
if (canStartBind()) {
mBindStep.doStart(false, new Callable<Task<Void>>() {
@ -453,7 +447,7 @@ public abstract class CameraEngine implements
}
@NonNull
@WorkerThread
@EngineThread
private Task<Void> stopBind(boolean swallowExceptions) {
if (needsStopBind()) {
mBindStep.doStop(swallowExceptions, new Callable<Task<Void>>() {
@ -471,7 +465,7 @@ public abstract class CameraEngine implements
* @return a task
*/
@NonNull
@WorkerThread
@EngineThread
protected abstract Task<Void> onStartBind();
/**
@ -481,7 +475,7 @@ public abstract class CameraEngine implements
* @return a task
*/
@NonNull
@WorkerThread
@EngineThread
protected abstract Task<Void> onStopBind();
@SuppressWarnings("WeakerAccess")
@ -522,7 +516,7 @@ public abstract class CameraEngine implements
//region Start & Stop preview
@NonNull
@WorkerThread
@EngineThread
private Task<Void> startPreview() {
LOG.i("startPreview", "canStartPreview:", canStartPreview());
if (canStartPreview()) {
@ -537,7 +531,7 @@ public abstract class CameraEngine implements
}
@NonNull
@WorkerThread
@EngineThread
private Task<Void> stopPreview(boolean swallowExceptions) {
LOG.i("stopPreview",
"needsStopPreview:", needsStopPreview(),
@ -571,7 +565,7 @@ public abstract class CameraEngine implements
* @return a task
*/
@NonNull
@WorkerThread
@EngineThread
protected abstract Task<Void> onStartPreview();
/**
@ -581,7 +575,7 @@ public abstract class CameraEngine implements
* @return a task
*/
@NonNull
@WorkerThread
@EngineThread
protected abstract Task<Void> onStopPreview();
//endregion
@ -643,7 +637,7 @@ public abstract class CameraEngine implements
*
* It basically depends on the step at which the preview stream size is actually used.
*/
@WorkerThread
@EngineThread
protected abstract void onPreviewStreamSizeChanged();
@Override
@ -676,7 +670,7 @@ public abstract class CameraEngine implements
* that would cause deadlocks due to us awaiting for {@link #stop()} to return.
*/
public void destroy() {
LOG.i("destroy:", "state:", getEngineStateName(), "thread:", Thread.currentThread());
LOG.i("destroy:", "state:", getEngineState(), "thread:", Thread.currentThread());
// Prevent CameraEngine leaks. Don't set to null, or exceptions
// inside the standard stop() method might crash the main thread.
mHandler.getThread().setUncaughtExceptionHandler(new NoOpExceptionHandler());
@ -710,7 +704,7 @@ public abstract class CameraEngine implements
@NonNull
public Task<Void> start() {
LOG.i("Start:", "posting runnable. State:", getEngineStateName());
LOG.i("Start:", "posting runnable. State:", getEngineState());
final TaskCompletionSource<Void> outTask = new TaskCompletionSource<>();
mHandler.run(new Runnable() {
@Override
@ -765,7 +759,7 @@ public abstract class CameraEngine implements
@NonNull
private Task<Void> stop(final boolean swallowExceptions) {
LOG.i("Stop:", "posting runnable. State:", getEngineStateName());
LOG.i("Stop:", "posting runnable. State:", getEngineState());
final TaskCompletionSource<Void> outTask = new TaskCompletionSource<>();
mHandler.run(new Runnable() {
@Override
@ -1077,6 +1071,7 @@ public abstract class CameraEngine implements
* @param facing the facing value
* @return true if we have one
*/
@EngineThread
protected abstract boolean collectCameraInfo(@NonNull Facing facing);
/**
@ -1256,6 +1251,7 @@ public abstract class CameraEngine implements
});
}
@EngineThread
@SuppressWarnings("WeakerAccess")
protected void onStopVideo() {
if (mVideoRecorder != null) {
@ -1289,19 +1285,19 @@ public abstract class CameraEngine implements
mCallback.dispatchOnVideoRecordingEnd();
}
@WorkerThread
@EngineThread
protected abstract void onTakePicture(@NonNull PictureResult.Stub stub, boolean doMetering);
@WorkerThread
@EngineThread
protected abstract void onTakePictureSnapshot(@NonNull PictureResult.Stub stub,
@NonNull AspectRatio outputRatio,
boolean doMetering);
@WorkerThread
@EngineThread
protected abstract void onTakeVideoSnapshot(@NonNull VideoResult.Stub stub,
@NonNull AspectRatio outputRatio);
@WorkerThread
@EngineThread
protected abstract void onTakeVideo(@NonNull VideoResult.Stub stub);
//endregion
@ -1430,9 +1426,11 @@ public abstract class CameraEngine implements
* we can be sure that the camera is available (engineState == STARTED).
* @return a list of available sizes for preview
*/
@EngineThread
@NonNull
protected abstract List<Size> getPreviewStreamAvailableSizes();
@EngineThread
@NonNull
@SuppressWarnings("WeakerAccess")
protected final Size computePreviewStreamSize() {

@ -0,0 +1,7 @@
package com.otaliastudios.cameraview.engine;
/**
* Indicates that some action is being executed on the {@link CameraEngine} thread.
*/
@SuppressWarnings("WeakerAccess")
public @interface EngineThread {}

@ -127,7 +127,7 @@ public class OverlayLayout extends FrameLayout implements Overlay {
// to apply some scale (typically > 1).
float widthScale = canvas.getWidth() / (float) getWidth();
float heightScale = canvas.getHeight() / (float) getHeight();
LOG.i("draw",
LOG.v("draw",
"target:", target,
"canvas:", canvas.getWidth() + "x" + canvas.getHeight(),
"view:", getWidth() + "x" + getHeight(),

@ -23,6 +23,7 @@ import com.otaliastudios.cameraview.size.AspectRatio;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
@ -69,8 +70,9 @@ public class GlCameraPreview extends FilterCameraPreview<GLSurfaceView, SurfaceT
private int mOutputTextureId = 0;
private SurfaceTexture mInputSurfaceTexture;
private EglViewport mOutputViewport;
private final Set<RendererFrameCallback> mRendererFrameCallbacks
= Collections.synchronizedSet(new HashSet<RendererFrameCallback>());
// A synchronized set was not enough to avoid crashes, probably due to external classes
// removing the callback while this set is being iterated. CopyOnWriteArraySet solves this.
private final Set<RendererFrameCallback> mRendererFrameCallbacks = new CopyOnWriteArraySet<>();
@VisibleForTesting float mCropScaleX = 1F;
@VisibleForTesting float mCropScaleY = 1F;
private View mRootView;
@ -156,13 +158,10 @@ public class GlCameraPreview extends FilterCameraPreview<GLSurfaceView, SurfaceT
getView().queueEvent(new Runnable() {
@Override
public void run() {
// Need to synchronize when iterating the Collections.synchronizedSet
synchronized (mRendererFrameCallbacks) {
for (RendererFrameCallback callback : mRendererFrameCallbacks) {
callback.onRendererTextureCreated(mOutputTextureId);
}
}
}
});
// Since we are using GLSurfaceView.RENDERMODE_WHEN_DIRTY, we must notify
@ -225,14 +224,11 @@ public class GlCameraPreview extends FilterCameraPreview<GLSurfaceView, SurfaceT
}
mOutputViewport.drawFrame(mInputSurfaceTexture.getTimestamp() / 1000L,
mOutputTextureId, mTransformMatrix);
synchronized (mRendererFrameCallbacks) {
// Need to synchronize when iterating the Collections.synchronizedSet
for (RendererFrameCallback callback : mRendererFrameCallbacks) {
callback.onRendererFrame(mInputSurfaceTexture, mCropScaleX, mCropScaleY);
}
}
}
}
@NonNull
@Override
@ -353,14 +349,10 @@ public class GlCameraPreview extends FilterCameraPreview<GLSurfaceView, SurfaceT
if (mOutputViewport != null) {
mOutputViewport.setFilter(filter);
}
// Need to synchronize when iterating the Collections.synchronizedSet
synchronized (mRendererFrameCallbacks) {
for (RendererFrameCallback callback : mRendererFrameCallbacks) {
callback.onRendererFilterChanged(filter);
}
}
}
});
}
}

@ -241,7 +241,9 @@ public class SnapshotVideoRecorder extends VideoRecorder implements RendererFram
@Override
public void onEncodingStart() {
//do nothing
// This would be the most correct place to call dispatchVideoRecordingStart. However,
// after this we'll post the call on the UI thread which can take some time. To compensate
// this, we call dispatchVideoRecordingStart() a bit earlier in this class (onStart()).
}
@Override

@ -231,11 +231,11 @@ public class AudioMediaEncoder extends MediaEncoder {
} else {
mCurrentReadBytes = mAudioRecord.read(mCurrentBuffer, mConfig.frameSize());
}
LOG.i("read thread - eos:", endOfStream, "- Read new audio frame. Bytes:",
LOG.v("read thread - eos:", endOfStream, "- Read new audio frame. Bytes:",
mCurrentReadBytes);
if (mCurrentReadBytes > 0) { // Good read: increase PTS.
increaseTime(mCurrentReadBytes, endOfStream);
LOG.i("read thread - eos:", endOfStream, "- mLastTimeUs:", mLastTimeUs);
LOG.v("read thread - eos:", endOfStream, "- mLastTimeUs:", mLastTimeUs);
mCurrentBuffer.limit(mCurrentReadBytes);
enqueue(mCurrentBuffer, mLastTimeUs, endOfStream);
} else if (mCurrentReadBytes == AudioRecord.ERROR_INVALID_OPERATION) {
@ -358,7 +358,7 @@ public class AudioMediaEncoder extends MediaEncoder {
if (mInputBufferQueue.isEmpty()) {
skipFrames(2);
} else {
LOG.i("encoding thread - performing", mInputBufferQueue.size(),
LOG.v("encoding thread - performing", mInputBufferQueue.size(),
"pending operations.");
InputBuffer inputBuffer;
while ((inputBuffer = mInputBufferQueue.peek()) != null) {
@ -408,7 +408,7 @@ public class AudioMediaEncoder extends MediaEncoder {
private void encode(@NonNull InputBuffer buffer) {
long executeStart = System.nanoTime() / 1000000;
LOG.i("encoding thread - performing pending operation for timestamp:",
LOG.v("encoding thread - performing pending operation for timestamp:",
buffer.timestamp, "- encoding.");
// NOTE: this copy is prob. the worst part here for performance
buffer.data.put(buffer.source);
@ -417,7 +417,7 @@ public class AudioMediaEncoder extends MediaEncoder {
encodeInputBuffer(buffer);
boolean eos = buffer.isEndOfStream;
mInputBufferPool.recycle(buffer);
LOG.i("encoding thread - performing pending operation for timestamp:",
LOG.v("encoding thread - performing pending operation for timestamp:",
buffer.timestamp, "- draining.");
// NOTE: can consider calling this drainOutput on yet another thread, which would let us
// use an even smaller BUFFER_POOL_MAX_SIZE without losing audio frames. But this way

@ -397,7 +397,7 @@ public abstract class MediaEncoder {
@SuppressLint("LogNotTimber")
@SuppressWarnings("WeakerAccess")
protected final void drainOutput(boolean drainAll) {
LOG.i(mName, "DRAINING - EOS:", drainAll);
LOG.v(mName, "DRAINING - EOS:", drainAll);
if (mMediaCodec == null) {
LOG.e("drain() was called before prepare() or after releasing.");
return;
@ -459,7 +459,7 @@ public abstract class MediaEncoder {
+ mLastTimeUs - mFirstTimeUs;
// Write.
LOG.i(mName, "DRAINING - About to write(). Adjusted presentation:",
LOG.v(mName, "DRAINING - About to write(). Adjusted presentation:",
mBufferInfo.presentationTimeUs);
OutputBuffer buffer = mOutputBufferPool.get();
//noinspection ConstantConditions

@ -186,7 +186,7 @@ public class MediaEncoderEngine {
*/
@SuppressWarnings("SameParameterValue")
public final void notify(final String event, final Object data) {
LOG.i("Passing event to encoders:", event);
LOG.v("Passing event to encoders:", event);
for (MediaEncoder encoder : mEncoders) {
encoder.notify(event, data);
}

@ -124,7 +124,7 @@ public class TextureMediaEncoder extends VideoMediaEncoder<TextureConfig> {
// Always render the first few frames, or muxer fails.
return true;
} else if (getPendingEvents(FRAME_EVENT) > 2) {
LOG.w("shouldRenderFrame - Dropping, we already have too many pending events:",
LOG.v("shouldRenderFrame - Dropping, we already have too many pending events:",
getPendingEvents(FRAME_EVENT));
return false;
} else {
@ -177,14 +177,14 @@ public class TextureMediaEncoder extends VideoMediaEncoder<TextureConfig> {
}
// First, drain any previous data.
LOG.i("onEvent -",
LOG.v("onEvent -",
"frameNumber:", mFrameNumber,
"timestampUs:", frame.timestampUs(),
"- draining.");
drainOutput(false);
// Then draw on the surface.
LOG.i("onEvent -",
LOG.v("onEvent -",
"frameNumber:", mFrameNumber,
"timestampUs:", frame.timestampUs(),
"- rendering.");

@ -2,7 +2,6 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
// buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.otaliastudios.cameraview.demo"
@ -23,6 +22,6 @@ android {
dependencies {
implementation project(':cameraview')
implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'com.google.android.material:material:1.1.0-alpha09'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0-beta01'
}

@ -190,12 +190,6 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
OptionView view = (OptionView) group.getChildAt(i);
view.onCameraOpened(camera, options);
}
camera.addFrameProcessor(new FrameProcessor() {
@Override
public void process(@NonNull Frame frame) {
}
});
}
@Override

@ -8,6 +8,13 @@ order: 3
New versions are released through GitHub, so the reference page is the [GitHub Releases](https://github.com/natario1/CameraView/releases) page.
### v2.3.1
- [Video] Improvement: better timing for `onVideoRecordingStart()` thanks to [@agrawalsuneet][agrawalsuneet] ([#632][632])
- [Video, Camera1] Fix: fixed video errors when starting on specific devices ([#617][617])
- [Video] Fix: fixed crash when closing the app during video snapshots ([#630][630])
- [Preview] Fix: fixed crash when using `GL_SURFACE` ([#630][630])
## v2.3.0
- [Camera2, Metering] New: `startAutoFocus` is much more powerful and does 3A metering (AF, AE, AWB) ([#574][574])
@ -320,3 +327,6 @@ https://github.com/natario1/CameraView/compare/v1.2.3...v1.3.0
[574]: https://github.com/natario1/CameraView/pull/574
[580]: https://github.com/natario1/CameraView/pull/580
[588]: https://github.com/natario1/CameraView/pull/588
[617]: https://github.com/natario1/CameraView/pull/617
[630]: https://github.com/natario1/CameraView/pull/630
[632]: https://github.com/natario1/CameraView/pull/632

@ -24,7 +24,7 @@ allprojects {
Then simply download the latest version:
```groovy
api 'com.otaliastudios:cameraview:2.3.0'
api 'com.otaliastudios:cameraview:2.3.1'
```
No other configuration steps are needed.
Loading…
Cancel
Save