diff --git a/sdk/android/src/java/org/webrtc/RefCountDelegate.java b/sdk/android/src/java/org/webrtc/RefCountDelegate.java index fc8a1910b4..58be7aa0fb 100644 --- a/sdk/android/src/java/org/webrtc/RefCountDelegate.java +++ b/sdk/android/src/java/org/webrtc/RefCountDelegate.java @@ -29,12 +29,19 @@ class RefCountDelegate implements RefCounted { @Override public void retain() { - refCount.incrementAndGet(); + int updated_count = refCount.incrementAndGet(); + if (updated_count < 2) { + throw new IllegalStateException("retain() called on an object with refcount < 1"); + } } @Override public void release() { - if (refCount.decrementAndGet() == 0 && releaseCallback != null) { + int updated_count = refCount.decrementAndGet(); + if (updated_count < 0) { + throw new IllegalStateException("release() called on an object with refcount < 1"); + } + if (updated_count == 0 && releaseCallback != null) { releaseCallback.run(); } } diff --git a/sdk/android/tests/src/org/webrtc/AndroidVideoDecoderTest.java b/sdk/android/tests/src/org/webrtc/AndroidVideoDecoderTest.java index 693dc6491f..1b9b56608d 100644 --- a/sdk/android/tests/src/org/webrtc/AndroidVideoDecoderTest.java +++ b/sdk/android/tests/src/org/webrtc/AndroidVideoDecoderTest.java @@ -29,7 +29,10 @@ import android.media.MediaCodecInfo.CodecCapabilities; import android.media.MediaFormat; import android.os.Handler; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; import org.chromium.testing.local.LocalRobolectricTestRunner; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -162,6 +165,25 @@ public class AndroidVideoDecoderTest { } } + private static class FakeDecoderCallback implements VideoDecoder.Callback { + public final List decodedFrames; + + public FakeDecoderCallback() { + decodedFrames = new ArrayList<>(); + } + + @Override + public void onDecodedFrame(VideoFrame frame, Integer decodeTimeMs, Integer qp) { + frame.retain(); + decodedFrames.add(frame); + } + + public void release() { + for (VideoFrame frame : decodedFrames) frame.release(); + decodedFrames.clear(); + } + } + private EncodedImage createTestEncodedImage() { return EncodedImage.builder() .setBuffer(ByteBuffer.wrap(ENCODED_TEST_DATA)) @@ -174,6 +196,7 @@ public class AndroidVideoDecoderTest { @Mock private SurfaceTextureHelper mockSurfaceTextureHelper; @Mock private VideoDecoder.Callback mockDecoderCallback; private FakeMediaCodecWrapper fakeMediaCodecWrapper; + private FakeDecoderCallback fakeDecoderCallback; @Before public void setUp() { @@ -183,6 +206,12 @@ public class AndroidVideoDecoderTest { MediaFormat outputFormat = new MediaFormat(); // TODO(sakal): Add more details to output format as needed. fakeMediaCodecWrapper = spy(new FakeMediaCodecWrapper(outputFormat)); + fakeDecoderCallback = new FakeDecoderCallback(); + } + + @After + public void cleanUp() { + fakeDecoderCallback.release(); } @Test @@ -268,7 +297,7 @@ public class AndroidVideoDecoderTest { // Set-up. TestDecoder decoder = new TestDecoderBuilder().setUseSurface(/* useSurface = */ false).build(); - decoder.initDecode(TEST_DECODER_SETTINGS, mockDecoderCallback); + decoder.initDecode(TEST_DECODER_SETTINGS, fakeDecoderCallback); decoder.decode(createTestEncodedImage(), new DecodeInfo(/* isMissingFrames= */ false, /* renderTimeMs= */ 0)); fakeMediaCodecWrapper.addOutputData( @@ -278,13 +307,8 @@ public class AndroidVideoDecoderTest { decoder.waitDeliverDecodedFrame(); // Verify. - ArgumentCaptor videoFrameCaptor = ArgumentCaptor.forClass(VideoFrame.class); - verify(mockDecoderCallback) - .onDecodedFrame(videoFrameCaptor.capture(), - /* decodeTimeMs= */ any(Integer.class), - /* qp= */ any()); - - VideoFrame videoFrame = videoFrameCaptor.getValue(); + assertThat(fakeDecoderCallback.decodedFrames).hasSize(1); + VideoFrame videoFrame = fakeDecoderCallback.decodedFrames.get(0); assertThat(videoFrame).isNotNull(); assertThat(videoFrame.getRotatedWidth()).isEqualTo(TEST_DECODER_SETTINGS.width); assertThat(videoFrame.getRotatedHeight()).isEqualTo(TEST_DECODER_SETTINGS.height); @@ -346,7 +370,7 @@ public class AndroidVideoDecoderTest { public void testDeliversRenderedBuffers() throws InterruptedException { // Set-up. TestDecoder decoder = new TestDecoderBuilder().build(); - decoder.initDecode(TEST_DECODER_SETTINGS, mockDecoderCallback); + decoder.initDecode(TEST_DECODER_SETTINGS, fakeDecoderCallback); decoder.decode(createTestEncodedImage(), new DecodeInfo(/* isMissingFrames= */ false, /* renderTimeMs= */ 0)); fakeMediaCodecWrapper.addOutputTexture(/* presentationTimestampUs= */ 0, /* flags= */ 0); @@ -370,16 +394,13 @@ public class AndroidVideoDecoderTest { outputVideoFrame.release(); // Verify. - ArgumentCaptor videoFrameCaptor = ArgumentCaptor.forClass(VideoFrame.class); - verify(mockDecoderCallback) - .onDecodedFrame(videoFrameCaptor.capture(), - /* decodeTimeMs= */ any(Integer.class), - /* qp= */ any()); - - VideoFrame videoFrame = videoFrameCaptor.getValue(); + assertThat(fakeDecoderCallback.decodedFrames).hasSize(1); + VideoFrame videoFrame = fakeDecoderCallback.decodedFrames.get(0); assertThat(videoFrame).isNotNull(); assertThat(videoFrame.getBuffer()).isEqualTo(outputTextureBuffer); + fakeDecoderCallback.release(); + verify(releaseCallback).run(); }