diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index a08cae7225..303554eb61 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -725,6 +725,7 @@ dist_jar("libwebrtc") { # TODO(sakal): Extract files from this target to releveant subtargets, video, audio etc. rtc_android_library("base_java") { java_files = [ + "api/org/webrtc/RefCounted.java", "src/java/org/webrtc/CalledByNative.java", "src/java/org/webrtc/CalledByNativeUnchecked.java", "src/java/org/webrtc/Histogram.java", @@ -732,6 +733,7 @@ rtc_android_library("base_java") { "src/java/org/webrtc/JniHelper.java", "src/java/org/webrtc/JNINamespace.java", "src/java/org/webrtc/NativeClassQualifiedName.java", + "src/java/org/webrtc/RefCountDelegate.java", "src/java/org/webrtc/WebRtcClassLoader.java", ] diff --git a/sdk/android/api/org/webrtc/JavaI420Buffer.java b/sdk/android/api/org/webrtc/JavaI420Buffer.java index 3498faf50e..19dd3e91e2 100644 --- a/sdk/android/api/org/webrtc/JavaI420Buffer.java +++ b/sdk/android/api/org/webrtc/JavaI420Buffer.java @@ -11,6 +11,7 @@ package org.webrtc; import java.nio.ByteBuffer; +import javax.annotation.Nullable; import org.webrtc.VideoFrame.I420Buffer; /** Implementation of VideoFrame.I420Buffer backed by Java direct byte buffers. */ @@ -23,13 +24,10 @@ public class JavaI420Buffer implements VideoFrame.I420Buffer { private final int strideY; private final int strideU; private final int strideV; - private final Runnable releaseCallback; - private final Object refCountLock = new Object(); - - private int refCount; + private final RefCountDelegate refCountDelegate; private JavaI420Buffer(int width, int height, ByteBuffer dataY, int strideY, ByteBuffer dataU, - int strideU, ByteBuffer dataV, int strideV, Runnable releaseCallback) { + int strideU, ByteBuffer dataV, int strideV, @Nullable Runnable releaseCallback) { this.width = width; this.height = height; this.dataY = dataY; @@ -38,9 +36,7 @@ public class JavaI420Buffer implements VideoFrame.I420Buffer { this.strideY = strideY; this.strideU = strideU; this.strideV = strideV; - this.releaseCallback = releaseCallback; - - this.refCount = 1; + this.refCountDelegate = new RefCountDelegate(releaseCallback); } /** Wraps existing ByteBuffers into JavaI420Buffer object without copying the contents. */ @@ -155,18 +151,12 @@ public class JavaI420Buffer implements VideoFrame.I420Buffer { @Override public void retain() { - synchronized (refCountLock) { - ++refCount; - } + refCountDelegate.retain(); } @Override public void release() { - synchronized (refCountLock) { - if (--refCount == 0 && releaseCallback != null) { - releaseCallback.run(); - } - } + refCountDelegate.release(); } @Override diff --git a/sdk/android/api/org/webrtc/RefCounted.java b/sdk/android/api/org/webrtc/RefCounted.java new file mode 100644 index 0000000000..7741a445d9 --- /dev/null +++ b/sdk/android/api/org/webrtc/RefCounted.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +/** + * Interface for ref counted objects in WebRTC. These objects have significant resources that need + * to be freed when they are no longer in use. Each objects starts with ref count of one when + * created. If a reference is passed as a parameter to a method, the caller has ownesrship of the + * object by default - calling release is not necessary unless retain is called. + */ +public interface RefCounted { + /** Increases ref count by one. */ + void retain(); + + /** + * Decreases ref count by one. When the ref count reaches zero, resources related to the object + * will be freed. + */ + void release(); +} diff --git a/sdk/android/api/org/webrtc/VideoFrame.java b/sdk/android/api/org/webrtc/VideoFrame.java index 2c21b6e271..91c596c01c 100644 --- a/sdk/android/api/org/webrtc/VideoFrame.java +++ b/sdk/android/api/org/webrtc/VideoFrame.java @@ -27,8 +27,15 @@ import javax.annotation.Nullable; * WebRTC software encoders. */ @JNINamespace("webrtc::jni") -public class VideoFrame { - public interface Buffer { +public class VideoFrame implements RefCounted { + /** + * Implements image storage medium. Might be for example an OpenGL texture or a memory region + * containing I420-data. + * + *
Reference counting is needed since a video buffer can be shared between multiple VideoSinks, + * and the buffer needs to be returned to the VideoSource as soon as all references are gone. + */ + public interface Buffer extends RefCounted { /** * Resolution of the buffer in pixels. */ @@ -42,12 +49,8 @@ public class VideoFrame { */ @CalledByNative("Buffer") I420Buffer toI420(); - /** - * Reference counting is needed since a video buffer can be shared between multiple VideoSinks, - * and the buffer needs to be returned to the VideoSource as soon as all references are gone. - */ - @CalledByNative("Buffer") void retain(); - @CalledByNative("Buffer") void release(); + @Override @CalledByNative("Buffer") void retain(); + @Override @CalledByNative("Buffer") void release(); /** * Crops a region defined by |cropx|, |cropY|, |cropWidth| and |cropHeight|. Scales it to size @@ -123,6 +126,11 @@ public class VideoFrame { private final int rotation; private final long timestampNs; + /** + * Constructs a new VideoFrame backed by the given {@code buffer}. + * + * @note Ownership of the buffer object is tranferred to the new VideoFrame. + */ @CalledByNative public VideoFrame(Buffer buffer, int rotation, long timestampNs) { if (buffer == null) { @@ -171,13 +179,12 @@ public class VideoFrame { return buffer.getWidth(); } - /** - * Reference counting of the underlying buffer. - */ + @Override public void retain() { buffer.retain(); } + @Override @CalledByNative public void release() { buffer.release(); diff --git a/sdk/android/src/java/org/webrtc/NV12Buffer.java b/sdk/android/src/java/org/webrtc/NV12Buffer.java index cdef36b0a8..0a85d7f51c 100644 --- a/sdk/android/src/java/org/webrtc/NV12Buffer.java +++ b/sdk/android/src/java/org/webrtc/NV12Buffer.java @@ -11,6 +11,7 @@ package org.webrtc; import java.nio.ByteBuffer; +import javax.annotation.Nullable; @JNINamespace("webrtc::jni") public class NV12Buffer implements VideoFrame.Buffer { @@ -19,21 +20,16 @@ public class NV12Buffer implements VideoFrame.Buffer { private final int stride; private final int sliceHeight; private final ByteBuffer buffer; - private final Runnable releaseCallback; - private final Object refCountLock = new Object(); - - private int refCount; + private final RefCountDelegate refCountDelegate; public NV12Buffer(int width, int height, int stride, int sliceHeight, ByteBuffer buffer, - Runnable releaseCallback) { + @Nullable Runnable releaseCallback) { this.width = width; this.height = height; this.stride = stride; this.sliceHeight = sliceHeight; this.buffer = buffer; - this.releaseCallback = releaseCallback; - - refCount = 1; + this.refCountDelegate = new RefCountDelegate(releaseCallback); } @Override @@ -53,18 +49,12 @@ public class NV12Buffer implements VideoFrame.Buffer { @Override public void retain() { - synchronized (refCountLock) { - ++refCount; - } + refCountDelegate.retain(); } @Override public void release() { - synchronized (refCountLock) { - if (--refCount == 0 && releaseCallback != null) { - releaseCallback.run(); - } - } + refCountDelegate.release(); } @Override diff --git a/sdk/android/src/java/org/webrtc/NV21Buffer.java b/sdk/android/src/java/org/webrtc/NV21Buffer.java index b3ce41a337..a2c47b93e4 100644 --- a/sdk/android/src/java/org/webrtc/NV21Buffer.java +++ b/sdk/android/src/java/org/webrtc/NV21Buffer.java @@ -11,22 +11,21 @@ package org.webrtc; import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicInteger; +import javax.annotation.Nullable; @JNINamespace("webrtc::jni") public class NV21Buffer implements VideoFrame.Buffer { private final byte[] data; private final int width; private final int height; - private final Runnable releaseCallback; - private final Object refCountLock = new Object(); + private final RefCountDelegate refCountDelegate; - private int refCount = 1; - - public NV21Buffer(byte[] data, int width, int height, Runnable releaseCallback) { + public NV21Buffer(byte[] data, int width, int height, @Nullable Runnable releaseCallback) { this.data = data; this.width = width; this.height = height; - this.releaseCallback = releaseCallback; + this.refCountDelegate = new RefCountDelegate(releaseCallback); } @Override @@ -48,18 +47,12 @@ public class NV21Buffer implements VideoFrame.Buffer { @Override public void retain() { - synchronized (refCountLock) { - ++refCount; - } + refCountDelegate.retain(); } @Override public void release() { - synchronized (refCountLock) { - if (--refCount == 0 && releaseCallback != null) { - releaseCallback.run(); - } - } + refCountDelegate.release(); } @Override diff --git a/sdk/android/src/java/org/webrtc/RefCountDelegate.java b/sdk/android/src/java/org/webrtc/RefCountDelegate.java new file mode 100644 index 0000000000..6ea8824312 --- /dev/null +++ b/sdk/android/src/java/org/webrtc/RefCountDelegate.java @@ -0,0 +1,41 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +import java.util.concurrent.atomic.AtomicInteger; +import javax.annotation.Nullable; + +/** + * Implementation of RefCounted that executes a Runnable once the ref count reaches zero. + */ +class RefCountDelegate implements RefCounted { + private final AtomicInteger refCount = new AtomicInteger(1); + private final @Nullable Runnable releaseCallback; + + /** + * @param releaseCallback Callback that will be executed once the ref count reaches zero. + */ + public RefCountDelegate(@Nullable Runnable releaseCallback) { + this.releaseCallback = releaseCallback; + } + + @Override + public void retain() { + refCount.incrementAndGet(); + } + + @Override + public void release() { + if (refCount.decrementAndGet() == 0 && releaseCallback != null) { + releaseCallback.run(); + } + } +} diff --git a/sdk/android/src/java/org/webrtc/TextureBufferImpl.java b/sdk/android/src/java/org/webrtc/TextureBufferImpl.java index b862f1dd72..9ad2ae2d14 100644 --- a/sdk/android/src/java/org/webrtc/TextureBufferImpl.java +++ b/sdk/android/src/java/org/webrtc/TextureBufferImpl.java @@ -12,6 +12,8 @@ package org.webrtc; import android.graphics.Matrix; import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicInteger; +import javax.annotation.Nullable; /** * Android texture buffer backed by a SurfaceTextureHelper's texture. The buffer calls @@ -24,20 +26,17 @@ class TextureBufferImpl implements VideoFrame.TextureBuffer { private final int id; private final Matrix transformMatrix; private final SurfaceTextureHelper surfaceTextureHelper; - private final Runnable releaseCallback; - private final Object refCountLock = new Object(); - private int refCount; + private final RefCountDelegate refCountDelegate; public TextureBufferImpl(int width, int height, Type type, int id, Matrix transformMatrix, - SurfaceTextureHelper surfaceTextureHelper, Runnable releaseCallback) { + SurfaceTextureHelper surfaceTextureHelper, @Nullable Runnable releaseCallback) { this.width = width; this.height = height; this.type = type; this.id = id; this.transformMatrix = transformMatrix; this.surfaceTextureHelper = surfaceTextureHelper; - this.releaseCallback = releaseCallback; - this.refCount = 1; // Creator implicitly holds a reference. + this.refCountDelegate = new RefCountDelegate(releaseCallback); } @Override @@ -72,18 +71,12 @@ class TextureBufferImpl implements VideoFrame.TextureBuffer { @Override public void retain() { - synchronized (refCountLock) { - ++refCount; - } + refCountDelegate.retain(); } @Override public void release() { - synchronized (refCountLock) { - if (--refCount == 0 && releaseCallback != null) { - releaseCallback.run(); - } - } + refCountDelegate.release(); } @Override