Make VideoFrame.Buffer implementations lock-free.
Replaces lock-based implementation with AtomicInteger. Bug: webrtc:7749 Change-Id: I226093b0af2090c080dfd4f87ed8f33a3f9efbd8 Reviewed-on: https://webrtc-review.googlesource.com/64162 Commit-Queue: Sami Kalliomäki <sakal@webrtc.org> Reviewed-by: Magnus Jedvert <magjed@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22798}
This commit is contained in:
committed by
Commit Bot
parent
11bf2fa43c
commit
61db3fd77f
@ -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",
|
||||
]
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
28
sdk/android/api/org/webrtc/RefCounted.java
Normal file
28
sdk/android/api/org/webrtc/RefCounted.java
Normal file
@ -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();
|
||||
}
|
||||
@ -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.
|
||||
*
|
||||
* <p>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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
41
sdk/android/src/java/org/webrtc/RefCountDelegate.java
Normal file
41
sdk/android/src/java/org/webrtc/RefCountDelegate.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user