pull/559/head
Mattia Iavarone 6 years ago
parent 2af34efb5b
commit 7bfaffb85b
  1. 209
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/filter/MultiFilterTest.java
  2. 8
      cameraview/src/main/java/com/otaliastudios/cameraview/filter/MultiFilter.java

@ -0,0 +1,209 @@
package com.otaliastudios.cameraview.filter;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.otaliastudios.cameraview.BaseEglTest;
import com.otaliastudios.cameraview.filters.AutoFixFilter;
import com.otaliastudios.cameraview.filters.BrightnessFilter;
import com.otaliastudios.cameraview.filters.DuotoneFilter;
import com.otaliastudios.cameraview.filters.VignetteFilter;
import com.otaliastudios.cameraview.internal.GlUtils;
import com.otaliastudios.cameraview.internal.egl.EglViewport;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MultiFilterTest extends BaseEglTest {
@Test
public void testConstructor1() {
MultiFilter multiFilter = new MultiFilter(
new DuotoneFilter(),
new AutoFixFilter()
);
assertEquals(2, multiFilter.filters.size());
}
@Test
public void testConstructor2() {
List<Filter> filters = new ArrayList<>();
filters.add(new DuotoneFilter());
filters.add(new AutoFixFilter());
MultiFilter multiFilter = new MultiFilter(filters);
assertEquals(2, multiFilter.filters.size());
}
@Test
public void testAddFilter() {
MultiFilter multiFilter = new MultiFilter();
assertEquals(0, multiFilter.filters.size());
multiFilter.addFilter(new DuotoneFilter());
assertEquals(1, multiFilter.filters.size());
multiFilter.addFilter(new AutoFixFilter());
assertEquals(2, multiFilter.filters.size());
}
@Test
public void testAddFilter_multi() {
MultiFilter multiFilter = new MultiFilter(new DuotoneFilter());
assertEquals(1, multiFilter.filters.size());
MultiFilter other = new MultiFilter(
new AutoFixFilter(),
new BrightnessFilter(),
new VignetteFilter());
multiFilter.addFilter(other);
assertEquals(4, multiFilter.filters.size());
}
@Test
public void testSetSize() {
DuotoneFilter filter = new DuotoneFilter();
MultiFilter multiFilter = new MultiFilter(filter);
MultiFilter.State state = multiFilter.states.get(filter);
assertNotNull(state);
assertNull(state.size);
multiFilter.setSize(WIDTH, HEIGHT);
assertNotNull(state.size);
}
@Test
public void testCopy() {
DuotoneFilter filter = spy(new DuotoneFilter());
MultiFilter multiFilter = new MultiFilter(filter);
MultiFilter multiFilterCopy = (MultiFilter) multiFilter.copy();
assertEquals(1, multiFilterCopy.filters.size());
verify(filter, times(1)).onCopy();
}
@Test
public void testParameter1() {
DuotoneFilter filter = new DuotoneFilter();
MultiFilter multiFilter = new MultiFilter(filter);
float desired = 0.21582F; // whatever
multiFilter.setParameter1(desired);
assertEquals(desired, multiFilter.getParameter1(), 0.001F);
assertEquals(desired, filter.getParameter1(), 0.001F);
}
@Test
public void testParameter2() {
DuotoneFilter filter = new DuotoneFilter();
MultiFilter multiFilter = new MultiFilter(filter);
float desired = 0.21582F; // whatever
multiFilter.setParameter2(desired);
assertEquals(desired, multiFilter.getParameter2(), 0.001F);
assertEquals(desired, filter.getParameter2(), 0.001F);
}
@Test
public void testOnCreate_isLazy() {
DuotoneFilter filter = spy(new DuotoneFilter());
MultiFilter multiFilter = new MultiFilter(filter);
int program = GlUtils.createProgram(multiFilter.getVertexShader(),
multiFilter.getFragmentShader());
multiFilter.onCreate(program);
verify(filter, never()).onCreate(anyInt());
multiFilter.onDestroy();
GLES20.glDeleteProgram(program);
verify(filter, never()).onDestroy();
}
@Test
public void testDraw_simple() {
DuotoneFilter filter = spy(new DuotoneFilter());
MultiFilter multiFilter = new MultiFilter(filter);
multiFilter.setSize(WIDTH, HEIGHT);
EglViewport viewport = new EglViewport(multiFilter);
int texture = viewport.createTexture();
float[] matrix = new float[16];
viewport.drawFrame(texture, matrix);
viewport.release();
// The child should have experienced the whole lifecycle.
verify(filter, atLeastOnce()).getVertexShader();
verify(filter, atLeastOnce()).getFragmentShader();
verify(filter, atLeastOnce()).setSize(anyInt(), anyInt());
verify(filter, times(1)).onCreate(anyInt());
verify(filter, times(1)).draw(matrix);
verify(filter, times(1)).onDestroy();
}
@Test
public void testDraw_multi() {
// Want to test that when filter1 is drawn, the current framebuffer is a
// non-default one. When filter2 is drawn, the current framebuffer is 0.
final DuotoneFilter filter1 = spy(new DuotoneFilter());
final DuotoneFilter filter2 = spy(new DuotoneFilter());
final MultiFilter multiFilter = new MultiFilter(filter1, filter2);
multiFilter.setSize(WIDTH, HEIGHT);
float[] matrix = new float[16];
final int[] result = new int[1];
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) {
MultiFilter.State state = multiFilter.states.get(filter1);
assertNotNull(state);
assertTrue(state.framebufferId != -1);
assertTrue(state.textureId != -1);
GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, result, 0);
assertTrue(result[0] != 0);
return null;
}
}).when(filter1).draw(matrix);
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) {
// The last filter has no FBO / texture.
MultiFilter.State state = multiFilter.states.get(filter2);
assertNotNull(state);
assertEquals(-1, state.framebufferId);
assertEquals(-1, state.textureId);
GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, result, 0);
assertEquals(0, result[0]);
return null;
}
}).when(filter2).draw(matrix);
EglViewport viewport = new EglViewport(multiFilter);
int texture = viewport.createTexture();
viewport.drawFrame(texture, matrix);
viewport.release();
// Verify that both are drawn.
verify(filter1, times(1)).draw(matrix);
verify(filter2, times(1)).draw(matrix);
}
}

@ -4,6 +4,7 @@ import android.opengl.GLES11Ext;
import android.opengl.GLES20; import android.opengl.GLES20;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.otaliastudios.cameraview.internal.GlUtils; import com.otaliastudios.cameraview.internal.GlUtils;
import com.otaliastudios.cameraview.size.Size; import com.otaliastudios.cameraview.size.Size;
@ -40,7 +41,8 @@ public class MultiFilter implements Filter, OneParameterFilter, TwoParameterFilt
private final static int TARGET = GLES20.GL_TEXTURE_2D; private final static int TARGET = GLES20.GL_TEXTURE_2D;
private static class State { @VisibleForTesting
static class State {
boolean isCreated = false; boolean isCreated = false;
int programHandle = -1; int programHandle = -1;
int framebufferId = -1; int framebufferId = -1;
@ -48,8 +50,8 @@ public class MultiFilter implements Filter, OneParameterFilter, TwoParameterFilt
Size size = null; Size size = null;
} }
private final List<Filter> filters = new ArrayList<>(); @VisibleForTesting final List<Filter> filters = new ArrayList<>();
private final Map<Filter, State> states = new HashMap<>(); @VisibleForTesting final Map<Filter, State> states = new HashMap<>();
private final Object lock = new Object(); private final Object lock = new Object();
private Size size = null; private Size size = null;
private float parameter1 = 0F; private float parameter1 = 0F;

Loading…
Cancel
Save