Add thread annotations

v2
Mattia Iavarone 6 years ago
parent fa899437ca
commit 5b303f0522
  1. 8
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/GlCameraPreviewTest.java
  2. 5
      cameraview/src/main/gles/com/otaliastudios/cameraview/AudioMediaEncoder.java
  3. 5
      cameraview/src/main/gles/com/otaliastudios/cameraview/MediaEncoder.java
  4. 11
      cameraview/src/main/gles/com/otaliastudios/cameraview/MediaEncoderEngine.java
  5. 4
      cameraview/src/main/gles/com/otaliastudios/cameraview/OldMediaEncoder.java
  6. 8
      cameraview/src/main/gles/com/otaliastudios/cameraview/TextureMediaEncoder.java
  7. 9
      cameraview/src/main/gles/com/otaliastudios/cameraview/VideoMediaEncoder.java
  8. 12
      cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java
  9. 3
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  10. 21
      cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotPictureRecorder.java
  11. 8
      cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java
  12. 15
      cameraview/src/main/views/com/otaliastudios/cameraview/GlCameraPreview.java

@ -10,20 +10,20 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
public class GLCameraPreviewTest extends CameraPreviewTest { public class GlCameraPreviewTest extends CameraPreviewTest {
@Override @Override
protected CameraPreview createPreview(Context context, ViewGroup parent, CameraPreview.SurfaceCallback callback) { protected CameraPreview createPreview(Context context, ViewGroup parent, CameraPreview.SurfaceCallback callback) {
return new GLCameraPreview(context, parent, callback); return new GlCameraPreview(context, parent, callback);
} }
@Override @Override
protected float getCropScaleY() { protected float getCropScaleY() {
return 1F / ((GLCameraPreview) preview).mScaleY; return 1F / ((GlCameraPreview) preview).mScaleY;
} }
@Override @Override
protected float getCropScaleX() { protected float getCropScaleX() {
return 1F / ((GLCameraPreview) preview).mScaleX; return 1F / ((GlCameraPreview) preview).mScaleX;
} }
} }

@ -17,26 +17,31 @@ class AudioMediaEncoder extends MediaEncoder {
} }
@EncoderThread
@Override @Override
void prepare(MediaEncoderEngine.Controller controller) { void prepare(MediaEncoderEngine.Controller controller) {
super.prepare(controller); super.prepare(controller);
} }
@EncoderThread
@Override @Override
void start() { void start() {
} }
@EncoderThread
@Override @Override
void notify(String event, Object data) { void notify(String event, Object data) {
} }
@EncoderThread
@Override @Override
void stop() { void stop() {
} }
@EncoderThread
@Override @Override
void release() { void release() {

@ -21,17 +21,22 @@ abstract class MediaEncoder {
private MediaEncoderEngine.Controller mController; private MediaEncoderEngine.Controller mController;
private int mTrackIndex; private int mTrackIndex;
@EncoderThread
void prepare(MediaEncoderEngine.Controller controller) { void prepare(MediaEncoderEngine.Controller controller) {
mController = controller; mController = controller;
mBufferInfo = new MediaCodec.BufferInfo(); mBufferInfo = new MediaCodec.BufferInfo();
} }
@EncoderThread
abstract void start(); abstract void start();
@EncoderThread
abstract void notify(String event, Object data); abstract void notify(String event, Object data);
@EncoderThread
abstract void stop(); abstract void stop();
@EncoderThread
abstract void release(); abstract void release();
/** /**

@ -15,6 +15,8 @@ import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@interface EncoderThread {}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
class MediaEncoderEngine { class MediaEncoderEngine {
@ -60,6 +62,7 @@ class MediaEncoderEngine {
mMediaMuxerStartCount++; mMediaMuxerStartCount++;
if (mMediaMuxerStartCount == mEncoders.size()) { if (mMediaMuxerStartCount == mEncoders.size()) {
mMediaMuxer.start(); mMediaMuxer.start();
mMediaMuxerStarted = true;
} }
return track; return track;
} }
@ -110,9 +113,11 @@ class MediaEncoderEngine {
encoder.release(); encoder.release();
} }
if (mMediaMuxer != null) { if (mMediaMuxer != null) {
// TODO: stop() throws an exception if you haven't fed it any data. Keep track // stop() throws an exception if you haven't fed it any data.
// of frames submitted, and don't call stop() if we haven't written anything. // We can just swallow I think.
mMediaMuxer.stop(); try {
mMediaMuxer.stop();
} catch (Exception e) {};
mMediaMuxer.release(); mMediaMuxer.release();
mMediaMuxer = null; mMediaMuxer = null;
} }

@ -327,7 +327,7 @@ class OldMediaEncoder implements Runnable {
long timestamp = (((long) inputMessage.arg1) << 32) | (((long) inputMessage.arg2) & 0xffffffffL); long timestamp = (((long) inputMessage.arg1) << 32) | (((long) inputMessage.arg2) & 0xffffffffL);
float[] transform = (float[]) obj; float[] transform = (float[]) obj;
// We must scale this matrix like GLCameraPreview does, because it might have some cropping. // We must scale this matrix like GlCameraPreview does, because it might have some cropping.
// Scaling takes place with respect to the (0, 0, 0) point, so we must apply a Translation to compensate. // Scaling takes place with respect to the (0, 0, 0) point, so we must apply a Translation to compensate.
float scaleX = encoder.mTransformationScaleX; float scaleX = encoder.mTransformationScaleX;
@ -337,7 +337,7 @@ class OldMediaEncoder implements Runnable {
Matrix.translateM(transform, 0, scaleTranslX, scaleTranslY, 0); Matrix.translateM(transform, 0, scaleTranslX, scaleTranslY, 0);
Matrix.scaleM(transform, 0, scaleX, scaleY, 1); Matrix.scaleM(transform, 0, scaleX, scaleY, 1);
// We also must rotate this matrix. In GLCameraPreview it is not needed because it is a live // We also must rotate this matrix. In GlCameraPreview it is not needed because it is a live
// stream, but the output video, must be correctly rotated based on the device rotation at the moment. // stream, but the output video, must be correctly rotated based on the device rotation at the moment.
// Rotation also takes place with respect to the origin (the Z axis), so we must // Rotation also takes place with respect to the origin (the Z axis), so we must
// translate to origin, rotate, then back to where we were. // translate to origin, rotate, then back to where we were.

@ -48,6 +48,7 @@ class TextureMediaEncoder extends VideoMediaEncoder<TextureMediaEncoder.Config>
super(config); super(config);
} }
@EncoderThread
@Override @Override
void prepare(MediaEncoderEngine.Controller controller) { void prepare(MediaEncoderEngine.Controller controller) {
super.prepare(controller); super.prepare(controller);
@ -58,6 +59,7 @@ class TextureMediaEncoder extends VideoMediaEncoder<TextureMediaEncoder.Config>
mViewport = new EglViewport(); mViewport = new EglViewport();
} }
@EncoderThread
@Override @Override
void release() { void release() {
super.release(); super.release();
@ -75,12 +77,14 @@ class TextureMediaEncoder extends VideoMediaEncoder<TextureMediaEncoder.Config>
} }
} }
@EncoderThread
@Override @Override
void start() { void start() {
super.start(); super.start();
// Nothing to do here. Waiting for the first frame. // Nothing to do here. Waiting for the first frame.
} }
@EncoderThread
@Override @Override
void notify(String event, Object data) { void notify(String event, Object data) {
if (event.equals(FRAME_EVENT)) { if (event.equals(FRAME_EVENT)) {
@ -99,7 +103,7 @@ class TextureMediaEncoder extends VideoMediaEncoder<TextureMediaEncoder.Config>
long timestamp = (((long) arg1) << 32) | (((long) arg2) & 0xffffffffL); long timestamp = (((long) arg1) << 32) | (((long) arg2) & 0xffffffffL);
float[] transform = frame.transform; float[] transform = frame.transform;
// We must scale this matrix like GLCameraPreview does, because it might have some cropping. // We must scale this matrix like GlCameraPreview does, because it might have some cropping.
// Scaling takes place with respect to the (0, 0, 0) point, so we must apply a Translation to compensate. // Scaling takes place with respect to the (0, 0, 0) point, so we must apply a Translation to compensate.
float scaleX = mConfig.scaleX; float scaleX = mConfig.scaleX;
@ -109,7 +113,7 @@ class TextureMediaEncoder extends VideoMediaEncoder<TextureMediaEncoder.Config>
Matrix.translateM(transform, 0, scaleTranslX, scaleTranslY, 0); Matrix.translateM(transform, 0, scaleTranslX, scaleTranslY, 0);
Matrix.scaleM(transform, 0, scaleX, scaleY, 1); Matrix.scaleM(transform, 0, scaleX, scaleY, 1);
// We also must rotate this matrix. In GLCameraPreview it is not needed because it is a live // We also must rotate this matrix. In GlCameraPreview it is not needed because it is a live
// stream, but the output video, must be correctly rotated based on the device rotation at the moment. // stream, but the output video, must be correctly rotated based on the device rotation at the moment.
// Rotation also takes place with respect to the origin (the Z axis), so we must // Rotation also takes place with respect to the origin (the Z axis), so we must
// translate to origin, rotate, then back to where we were. // translate to origin, rotate, then back to where we were.

@ -13,6 +13,11 @@ import android.view.Surface;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/**
* This alone does nothing.
* Subclasses must make sure they write each frame onto the given Surface {@link #mSurface}.
* @param <C> the config object.
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
abstract class VideoMediaEncoder<C extends VideoMediaEncoder.Config> extends MediaEncoder { abstract class VideoMediaEncoder<C extends VideoMediaEncoder.Config> extends MediaEncoder {
@ -42,6 +47,7 @@ abstract class VideoMediaEncoder<C extends VideoMediaEncoder.Config> extends Med
mConfig = config; mConfig = config;
} }
@EncoderThread
@Override @Override
void prepare(MediaEncoderEngine.Controller controller) { void prepare(MediaEncoderEngine.Controller controller) {
super.prepare(controller); super.prepare(controller);
@ -67,18 +73,21 @@ abstract class VideoMediaEncoder<C extends VideoMediaEncoder.Config> extends Med
mMediaCodec.start(); mMediaCodec.start();
} }
@EncoderThread
@Override @Override
void start() { void start() {
// Nothing to do here. Waiting for the first frame. // Nothing to do here. Waiting for the first frame.
mFrameNum = 0; mFrameNum = 0;
} }
@EncoderThread
@Override @Override
void stop() { void stop() {
mFrameNum = -1; mFrameNum = -1;
drain(true); drain(true);
} }
@EncoderThread
@Override @Override
void release() { void release() {
if (mMediaCodec != null) { if (mMediaCodec != null) {

@ -6,18 +6,14 @@ import android.graphics.ImageFormat;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.Camera; import android.hardware.Camera;
import android.location.Location; import android.location.Location;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread; import android.support.annotation.WorkerThread;
import android.support.media.ExifInterface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -645,8 +641,8 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Override @Override
void takeVideoSnapshot(@NonNull final File file) { void takeVideoSnapshot(@NonNull final File file) {
if (!(mPreview instanceof GLCameraPreview)) { if (!(mPreview instanceof GlCameraPreview)) {
throw new IllegalStateException("Video snapshots are only supported with GLCameraPreview."); throw new IllegalStateException("Video snapshots are only supported with GlCameraPreview.");
} }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
throw new IllegalStateException("Video snapshots are only supported starting from API 18."); throw new IllegalStateException("Video snapshots are only supported starting from API 18.");
@ -663,7 +659,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
videoResult.codec = mVideoCodec; videoResult.codec = mVideoCodec;
videoResult.location = mLocation; videoResult.location = mLocation;
// What matters as size here is the preview size, which is passed to the GLCameraPreview // What matters as size here is the preview size, which is passed to the GlCameraPreview
// surface texture, which is then passed to the encoder. The view size has no influence. // surface texture, which is then passed to the encoder. The view size has no influence.
// CROPPING: We must make sure that the encoder applies our special transformation // CROPPING: We must make sure that the encoder applies our special transformation
@ -700,7 +696,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
videoResult.maxSize = mVideoMaxSize; videoResult.maxSize = mVideoMaxSize;
videoResult.maxDuration = mVideoMaxDuration; videoResult.maxDuration = mVideoMaxDuration;
GLCameraPreview cameraPreview = (GLCameraPreview) mPreview; GlCameraPreview cameraPreview = (GlCameraPreview) mPreview;
mVideoRecorder = new SnapshotVideoRecorder(videoResult, Camera1.this, cameraPreview); mVideoRecorder = new SnapshotVideoRecorder(videoResult, Camera1.this, cameraPreview);
mVideoRecorder.start(); mVideoRecorder.start();
} }

@ -7,7 +7,6 @@ import android.app.Activity;
import android.arch.lifecycle.Lifecycle; import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver; import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.LifecycleOwner; import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.Lifecycling;
import android.arch.lifecycle.OnLifecycleEvent; import android.arch.lifecycle.OnLifecycleEvent;
import android.content.Context; import android.content.Context;
import android.content.ContextWrapper; import android.content.ContextWrapper;
@ -240,7 +239,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
} }
case GL_SURFACE: default: { case GL_SURFACE: default: {
return new GLCameraPreview(context, container, null); return new GlCameraPreview(context, container, null);
} }
} }
} }

@ -1,7 +1,6 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.ImageFormat; import android.graphics.ImageFormat;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
@ -9,19 +8,9 @@ import android.graphics.YuvImage;
import android.hardware.Camera; import android.hardware.Camera;
import android.opengl.EGL14; import android.opengl.EGL14;
import android.opengl.EGLContext; import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLSurface;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix; import android.opengl.Matrix;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/** /**
* A {@link PictureResult} that uses standard APIs. * A {@link PictureResult} that uses standard APIs.
@ -50,21 +39,22 @@ class SnapshotPictureRecorder extends PictureRecorder {
@Override @Override
void take() { void take() {
if (mPreview instanceof GLCameraPreview) { if (mPreview instanceof GlCameraPreview) {
takeGl((GLCameraPreview) mPreview); takeGl((GlCameraPreview) mPreview);
} else { } else {
takeLegacy(); takeLegacy();
} }
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
private void takeGl(final GLCameraPreview preview) { private void takeGl(final GlCameraPreview preview) {
preview.addRendererFrameCallback(new GLCameraPreview.RendererFrameCallback() { preview.addRendererFrameCallback(new GlCameraPreview.RendererFrameCallback() {
int mTextureId; int mTextureId;
SurfaceTexture mSurfaceTexture; SurfaceTexture mSurfaceTexture;
float[] mTransform; float[] mTransform;
@RendererThread
public void onRendererTextureCreated(int textureId) { public void onRendererTextureCreated(int textureId) {
mTextureId = textureId; mTextureId = textureId;
mSurfaceTexture = new SurfaceTexture(mTextureId, true); mSurfaceTexture = new SurfaceTexture(mTextureId, true);
@ -75,6 +65,7 @@ class SnapshotPictureRecorder extends PictureRecorder {
mTransform = new float[16]; mTransform = new float[16];
} }
@RendererThread
@Override @Override
public void onRendererFrame(SurfaceTexture surfaceTexture, final float scaleX, final float scaleY) { public void onRendererFrame(SurfaceTexture surfaceTexture, final float scaleX, final float scaleY) {
preview.removeRendererFrameCallback(this); preview.removeRendererFrameCallback(this);

@ -14,7 +14,7 @@ import android.support.annotation.RequiresApi;
* TODO when cropping is huge, the first frame of the video result, noticeably, has no transformation applied. Don't know why. * TODO when cropping is huge, the first frame of the video result, noticeably, has no transformation applied. Don't know why.
*/ */
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
class SnapshotVideoRecorder extends VideoRecorder implements GLCameraPreview.RendererFrameCallback { class SnapshotVideoRecorder extends VideoRecorder implements GlCameraPreview.RendererFrameCallback {
private static final String TAG = SnapshotVideoRecorder.class.getSimpleName(); private static final String TAG = SnapshotVideoRecorder.class.getSimpleName();
private static final CameraLogger LOG = CameraLogger.create(TAG); private static final CameraLogger LOG = CameraLogger.create(TAG);
@ -25,13 +25,13 @@ class SnapshotVideoRecorder extends VideoRecorder implements GLCameraPreview.Ren
private OldMediaEncoder mEncoder; private OldMediaEncoder mEncoder;
private MediaEncoderEngine mEncoderEngine; private MediaEncoderEngine mEncoderEngine;
private GLCameraPreview mPreview; private GlCameraPreview mPreview;
private int mCurrentState = STATE_NOT_RECORDING; private int mCurrentState = STATE_NOT_RECORDING;
private int mDesiredState = STATE_NOT_RECORDING; private int mDesiredState = STATE_NOT_RECORDING;
private int mTextureId = 0; private int mTextureId = 0;
SnapshotVideoRecorder(VideoResult stub, VideoResultListener listener, GLCameraPreview preview) { SnapshotVideoRecorder(VideoResult stub, VideoResultListener listener, GlCameraPreview preview) {
super(stub, listener); super(stub, listener);
if (USE_OLD_ENCODER) { if (USE_OLD_ENCODER) {
mEncoder = new OldMediaEncoder(); mEncoder = new OldMediaEncoder();
@ -60,11 +60,13 @@ class SnapshotVideoRecorder extends VideoRecorder implements GLCameraPreview.Ren
mDesiredState = STATE_NOT_RECORDING; mDesiredState = STATE_NOT_RECORDING;
} }
@RendererThread
@Override @Override
public void onRendererTextureCreated(int textureId) { public void onRendererTextureCreated(int textureId) {
mTextureId = textureId; mTextureId = textureId;
} }
@RendererThread
@Override @Override
public void onRendererFrame(SurfaceTexture surfaceTexture, float scaleX, float scaleY) { public void onRendererFrame(SurfaceTexture surfaceTexture, float scaleX, float scaleY) {
if (mCurrentState == STATE_NOT_RECORDING && mDesiredState == STATE_RECORDING) { if (mCurrentState == STATE_NOT_RECORDING && mDesiredState == STATE_RECORDING) {

@ -21,6 +21,9 @@ import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface; import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL10;
@interface RendererThread {}
/** /**
* - The android camera will stream image to the given {@link SurfaceTexture}. * - The android camera will stream image to the given {@link SurfaceTexture}.
* *
@ -53,7 +56,7 @@ import javax.microedition.khronos.opengles.GL10;
* Callbacks are guaranteed to be called on the renderer thread, which means that we can fetch * Callbacks are guaranteed to be called on the renderer thread, which means that we can fetch
* the GL context that was created and is managed by the {@link GLSurfaceView}. * the GL context that was created and is managed by the {@link GLSurfaceView}.
*/ */
class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> implements GLSurfaceView.Renderer { class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> implements GLSurfaceView.Renderer {
private boolean mDispatched; private boolean mDispatched;
private final float[] mTransformMatrix = new float[16]; private final float[] mTransformMatrix = new float[16];
@ -64,7 +67,7 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
/* for tests */ float mScaleX = 1F; /* for tests */ float mScaleX = 1F;
/* for tests */ float mScaleY = 1F; /* for tests */ float mScaleY = 1F;
GLCameraPreview(Context context, ViewGroup parent, SurfaceCallback callback) { GlCameraPreview(Context context, ViewGroup parent, SurfaceCallback callback) {
super(context, parent, callback); super(context, parent, callback);
} }
@ -119,7 +122,7 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
} }
} }
// Renderer thread @RendererThread
@Override @Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) { public void onSurfaceCreated(GL10 gl, EGLConfig config) {
mOutputViewport = new EglViewport(); mOutputViewport = new EglViewport();
@ -144,7 +147,7 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
}); });
} }
// Renderer thread @RendererThread
@SuppressWarnings("StatementWithEmptyBody") @SuppressWarnings("StatementWithEmptyBody")
@Override @Override
public void onSurfaceChanged(GL10 gl, final int width, final int height) { public void onSurfaceChanged(GL10 gl, final int width, final int height) {
@ -170,7 +173,7 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
} }
} }
// Renderer thread @RendererThread
@Override @Override
public void onDrawFrame(GL10 gl) { public void onDrawFrame(GL10 gl) {
// Latch the latest frame. If there isn't anything new, // Latch the latest frame. If there isn't anything new,
@ -255,6 +258,7 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
* *
* @param textureId the GL texture linked to the image stream * @param textureId the GL texture linked to the image stream
*/ */
@RendererThread
void onRendererTextureCreated(int textureId); void onRendererTextureCreated(int textureId);
/** /**
@ -266,6 +270,7 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
* @param scaleX the scaleX (in REF_VIEW) value * @param scaleX the scaleX (in REF_VIEW) value
* @param scaleY the scaleY (in REF_VIEW) value * @param scaleY the scaleY (in REF_VIEW) value
*/ */
@RendererThread
void onRendererFrame(SurfaceTexture surfaceTexture, float scaleX, float scaleY); void onRendererFrame(SurfaceTexture surfaceTexture, float scaleX, float scaleY);
} }
Loading…
Cancel
Save