diff --git a/README.md b/README.md index bf4d62b5..daed9697 100644 --- a/README.md +++ b/README.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 diff --git a/cameraview/build.gradle b/cameraview/build.gradle index b536ef88..9d0d528a 100644 --- a/cameraview/build.gradle +++ b/cameraview/build.gradle @@ -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 diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java index 11db5d38..60d63cb7 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java @@ -97,6 +97,7 @@ public class Camera1Engine extends CameraEngine implements //region Protected APIs + @EngineThread @NonNull @Override protected List 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 onStartEngine() { try { @@ -164,6 +166,7 @@ public class Camera1Engine extends CameraEngine implements return Tasks.forResult(null); } + @EngineThread @NonNull @Override protected Task onStartBind() { @@ -187,6 +190,7 @@ public class Camera1Engine extends CameraEngine implements return Tasks.forResult(null); } + @EngineThread @NonNull @Override protected Task onStartPreview() { @@ -238,6 +242,7 @@ public class Camera1Engine extends CameraEngine implements //region Stop + @EngineThread @NonNull @Override protected Task onStopPreview() { @@ -256,6 +261,7 @@ public class Camera1Engine extends CameraEngine implements return Tasks.forResult(null); } + @EngineThread @NonNull @Override protected Task onStopBind() { @@ -275,8 +281,8 @@ public class Camera1Engine extends CameraEngine implements return Tasks.forResult(null); } + @EngineThread @NonNull - @WorkerThread @Override protected Task 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 computeMeteringAreas(double viewClickX, double viewClickY, int viewWidth, int viewHeight, int sensorToDisplay) { diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java index 8995b162..a35de766 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java @@ -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 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 onStartBind() { @@ -525,6 +539,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv return task.getTask(); } + @EngineThread @NonNull @Override protected Task onStartPreview() { @@ -569,6 +584,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv //region Stop + @EngineThread @NonNull @Override protected Task onStopPreview() { @@ -598,7 +614,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv return Tasks.forResult(null); } - + @EngineThread @NonNull @Override protected Task onStopBind() { @@ -627,7 +643,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv return Tasks.forResult(null); } - + @EngineThread @NonNull @Override protected Task 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,7 +862,16 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv @Override public void onVideoResult(@Nullable VideoResult.Stub result, @Nullable Exception exception) { super.onVideoResult(result, exception); - maybeRestorePreviewTemplateAfterVideo(); + // 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(); + } + }); } /** @@ -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) { diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java index 6616b0e0..2631b2b9 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java @@ -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 startEngine() { if (canStartEngine()) { mEngineStep.doStart(false, new Callable>() { @@ -398,7 +392,7 @@ public abstract class CameraEngine implements } @NonNull - @WorkerThread + @EngineThread private Task stopEngine(boolean swallowExceptions) { if (needsStopEngine()) { mEngineStep.doStop(swallowExceptions, new Callable>() { @@ -421,7 +415,7 @@ public abstract class CameraEngine implements * @return a task */ @NonNull - @WorkerThread + @EngineThread protected abstract Task onStartEngine(); /** @@ -431,7 +425,7 @@ public abstract class CameraEngine implements * @return a task */ @NonNull - @WorkerThread + @EngineThread protected abstract Task onStopEngine(); //endregion @@ -439,7 +433,7 @@ public abstract class CameraEngine implements //region Start & Stop binding @NonNull - @WorkerThread + @EngineThread private Task startBind() { if (canStartBind()) { mBindStep.doStart(false, new Callable>() { @@ -453,7 +447,7 @@ public abstract class CameraEngine implements } @NonNull - @WorkerThread + @EngineThread private Task stopBind(boolean swallowExceptions) { if (needsStopBind()) { mBindStep.doStop(swallowExceptions, new Callable>() { @@ -471,7 +465,7 @@ public abstract class CameraEngine implements * @return a task */ @NonNull - @WorkerThread + @EngineThread protected abstract Task onStartBind(); /** @@ -481,7 +475,7 @@ public abstract class CameraEngine implements * @return a task */ @NonNull - @WorkerThread + @EngineThread protected abstract Task onStopBind(); @SuppressWarnings("WeakerAccess") @@ -522,7 +516,7 @@ public abstract class CameraEngine implements //region Start & Stop preview @NonNull - @WorkerThread + @EngineThread private Task startPreview() { LOG.i("startPreview", "canStartPreview:", canStartPreview()); if (canStartPreview()) { @@ -537,7 +531,7 @@ public abstract class CameraEngine implements } @NonNull - @WorkerThread + @EngineThread private Task 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 onStartPreview(); /** @@ -581,7 +575,7 @@ public abstract class CameraEngine implements * @return a task */ @NonNull - @WorkerThread + @EngineThread protected abstract Task 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 start() { - LOG.i("Start:", "posting runnable. State:", getEngineStateName()); + LOG.i("Start:", "posting runnable. State:", getEngineState()); final TaskCompletionSource outTask = new TaskCompletionSource<>(); mHandler.run(new Runnable() { @Override @@ -765,7 +759,7 @@ public abstract class CameraEngine implements @NonNull private Task stop(final boolean swallowExceptions) { - LOG.i("Stop:", "posting runnable. State:", getEngineStateName()); + LOG.i("Stop:", "posting runnable. State:", getEngineState()); final TaskCompletionSource 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 getPreviewStreamAvailableSizes(); + @EngineThread @NonNull @SuppressWarnings("WeakerAccess") protected final Size computePreviewStreamSize() { diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/EngineThread.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/EngineThread.java new file mode 100644 index 00000000..8d807c5c --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/EngineThread.java @@ -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 {} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayLayout.java b/cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayLayout.java index bed667da..3b2bd782 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayLayout.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/overlay/OverlayLayout.java @@ -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(), diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java b/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java index 5627303a..4e32e1ef 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java @@ -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 mRendererFrameCallbacks - = Collections.synchronizedSet(new HashSet()); + // 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 mRendererFrameCallbacks = new CopyOnWriteArraySet<>(); @VisibleForTesting float mCropScaleX = 1F; @VisibleForTesting float mCropScaleY = 1F; private View mRootView; @@ -156,11 +158,8 @@ public class GlCameraPreview extends FilterCameraPreview 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 diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoder.java index 8ce51f09..df5d9118 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoder.java @@ -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 diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoderEngine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoderEngine.java index 7ca3eb14..744bf6a6 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoderEngine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoderEngine.java @@ -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); } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/TextureMediaEncoder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/TextureMediaEncoder.java index 4d30dc41..5730d590 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/TextureMediaEncoder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/TextureMediaEncoder.java @@ -124,7 +124,7 @@ public class TextureMediaEncoder extends VideoMediaEncoder { // 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 { } // 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."); diff --git a/demo/build.gradle b/demo/build.gradle index bbf6cff8..fe41eebd 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -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' } diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java index 644afa6c..50508a71 100644 --- a/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java +++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java @@ -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 diff --git a/docs/_posts/2018-12-20-changelog.md b/docs/_posts/2018-12-20-changelog.md index 4e3811d9..6d4850d1 100644 --- a/docs/_posts/2018-12-20-changelog.md +++ b/docs/_posts/2018-12-20-changelog.md @@ -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 diff --git a/docs/_posts/2018-12-20-install.md b/docs/_posts/2018-12-20-install.md index f1eb35d0..6757bc83 100644 --- a/docs/_posts/2018-12-20-install.md +++ b/docs/_posts/2018-12-20-install.md @@ -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. \ No newline at end of file