diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 86c650230f..bb43434cca 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -271,7 +271,6 @@ generate_jni("generated_video_jni") { "api/org/webrtc/VideoEncoderFactory.java", "api/org/webrtc/VideoEncoderFallback.java", "api/org/webrtc/VideoFrame.java", - "api/org/webrtc/VideoRenderer.java", "api/org/webrtc/VideoSink.java", "api/org/webrtc/VideoSource.java", "api/org/webrtc/VideoTrack.java", @@ -306,7 +305,6 @@ rtc_static_library("video_jni") { "src/jni/nv12buffer.cc", "src/jni/nv21buffer.cc", "src/jni/pc/video.cc", - "src/jni/video_renderer.cc", "src/jni/videocodecinfo.cc", "src/jni/videocodecinfo.h", "src/jni/videocodecstatus.cc", @@ -753,7 +751,6 @@ rtc_android_library("video_api_java") { "api/org/webrtc/VideoEncoder.java", "api/org/webrtc/VideoEncoderFactory.java", "api/org/webrtc/VideoFrame.java", - "api/org/webrtc/VideoRenderer.java", # TODO(sakal): Remove "api/org/webrtc/VideoSink.java", ] diff --git a/sdk/android/api/org/webrtc/EglRenderer.java b/sdk/android/api/org/webrtc/EglRenderer.java index fc29aa1a41..d0a1d98b2b 100644 --- a/sdk/android/api/org/webrtc/EglRenderer.java +++ b/sdk/android/api/org/webrtc/EglRenderer.java @@ -27,11 +27,10 @@ import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; /** - * Implements org.webrtc.VideoRenderer.Callbacks by displaying the video stream on an EGL Surface. - * This class is intended to be used as a helper class for rendering on SurfaceViews and - * TextureViews. + * Implements VideoSink by displaying the video stream on an EGL Surface. This class is intended to + * be used as a helper class for rendering on SurfaceViews and TextureViews. */ -public class EglRenderer implements VideoRenderer.Callbacks, VideoSink { +public class EglRenderer implements VideoSink { private static final String TAG = "EglRenderer"; private static final long LOG_INTERVAL_SEC = 4; @@ -421,14 +420,6 @@ public class EglRenderer implements VideoRenderer.Callbacks, VideoSink { ThreadUtils.awaitUninterruptibly(latch); } - // VideoRenderer.Callbacks interface. - @Override - public void renderFrame(VideoRenderer.I420Frame frame) { - VideoFrame videoFrame = frame.toVideoFrame(); - onFrame(videoFrame); - videoFrame.release(); - } - // VideoSink interface. @Override public void onFrame(VideoFrame frame) { diff --git a/sdk/android/api/org/webrtc/VideoRenderer.java b/sdk/android/api/org/webrtc/VideoRenderer.java deleted file mode 100644 index 696683c463..0000000000 --- a/sdk/android/api/org/webrtc/VideoRenderer.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright 2013 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 javax.annotation.Nullable; -import java.nio.ByteBuffer; -import org.webrtc.VideoFrame; - -/** - * Java version of VideoSinkInterface. In addition to allowing clients to - * define their own rendering behavior (by passing in a Callbacks object), this - * class also provides a createGui() method for creating a GUI-rendering window - * on various platforms. - */ -// Use VideoSink instead. -@Deprecated -public class VideoRenderer { - /** - * Java version of webrtc::VideoFrame. Frames are only constructed from native code and test - * code. - */ - // Use VideoFrame instead. - @Deprecated - public static class I420Frame { - public final int width; - public final int height; - @Nullable public final int[] yuvStrides; - @Nullable public ByteBuffer[] yuvPlanes; - public final boolean yuvFrame; - // Matrix that transforms standard coordinates to their proper sampling locations in - // the texture. This transform compensates for any properties of the video source that - // cause it to appear different from a normalized texture. This matrix does not take - // |rotationDegree| into account. - @Nullable public final float[] samplingMatrix; - public int textureId; - // Frame pointer in C++. - private long nativeFramePointer; - - // rotationDegree is the degree that the frame must be rotated clockwisely - // to be rendered correctly. - public int rotationDegree; - - // If this I420Frame was constructed from VideoFrame.Buffer, this points to - // the backing buffer. - @Nullable private final VideoFrame.Buffer backingBuffer; - - /** - * Construct a frame of the given dimensions with the specified planar data. - */ - public I420Frame(int width, int height, int rotationDegree, int[] yuvStrides, - ByteBuffer[] yuvPlanes, long nativeFramePointer) { - this.width = width; - this.height = height; - this.yuvStrides = yuvStrides; - this.yuvPlanes = yuvPlanes; - this.yuvFrame = true; - this.rotationDegree = rotationDegree; - this.nativeFramePointer = nativeFramePointer; - backingBuffer = null; - if (rotationDegree % 90 != 0) { - throw new IllegalArgumentException("Rotation degree not multiple of 90: " + rotationDegree); - } - // The convention in WebRTC is that the first element in a ByteBuffer corresponds to the - // top-left corner of the image, but in glTexImage2D() the first element corresponds to the - // bottom-left corner. This discrepancy is corrected by setting a vertical flip as sampling - // matrix. - samplingMatrix = RendererCommon.verticalFlipMatrix(); - } - - /** - * Construct a texture frame of the given dimensions with data in SurfaceTexture - */ - public I420Frame(int width, int height, int rotationDegree, int textureId, - float[] samplingMatrix, long nativeFramePointer) { - this.width = width; - this.height = height; - this.yuvStrides = null; - this.yuvPlanes = null; - this.samplingMatrix = samplingMatrix; - this.textureId = textureId; - this.yuvFrame = false; - this.rotationDegree = rotationDegree; - this.nativeFramePointer = nativeFramePointer; - backingBuffer = null; - if (rotationDegree % 90 != 0) { - throw new IllegalArgumentException("Rotation degree not multiple of 90: " + rotationDegree); - } - } - - /** - * Construct a frame from VideoFrame.Buffer. - */ - @CalledByNative("I420Frame") - public I420Frame(int rotationDegree, VideoFrame.Buffer buffer, long nativeFramePointer) { - this.width = buffer.getWidth(); - this.height = buffer.getHeight(); - this.rotationDegree = rotationDegree; - if (rotationDegree % 90 != 0) { - throw new IllegalArgumentException("Rotation degree not multiple of 90: " + rotationDegree); - } - if (buffer instanceof VideoFrame.TextureBuffer - && ((VideoFrame.TextureBuffer) buffer).getType() == VideoFrame.TextureBuffer.Type.OES) { - VideoFrame.TextureBuffer textureBuffer = (VideoFrame.TextureBuffer) buffer; - this.yuvFrame = false; - this.textureId = textureBuffer.getTextureId(); - this.samplingMatrix = RendererCommon.convertMatrixFromAndroidGraphicsMatrix( - textureBuffer.getTransformMatrix()); - - this.yuvStrides = null; - this.yuvPlanes = null; - } else if (buffer instanceof VideoFrame.I420Buffer) { - VideoFrame.I420Buffer i420Buffer = (VideoFrame.I420Buffer) buffer; - this.yuvFrame = true; - this.yuvStrides = - new int[] {i420Buffer.getStrideY(), i420Buffer.getStrideU(), i420Buffer.getStrideV()}; - this.yuvPlanes = - new ByteBuffer[] {i420Buffer.getDataY(), i420Buffer.getDataU(), i420Buffer.getDataV()}; - // The convention in WebRTC is that the first element in a ByteBuffer corresponds to the - // top-left corner of the image, but in glTexImage2D() the first element corresponds to the - // bottom-left corner. This discrepancy is corrected by multiplying the sampling matrix with - // a vertical flip matrix. - this.samplingMatrix = RendererCommon.verticalFlipMatrix(); - - this.textureId = 0; - } else { - this.yuvFrame = false; - this.textureId = 0; - this.samplingMatrix = null; - this.yuvStrides = null; - this.yuvPlanes = null; - } - this.nativeFramePointer = nativeFramePointer; - backingBuffer = buffer; - } - - public int rotatedWidth() { - return (rotationDegree % 180 == 0) ? width : height; - } - - public int rotatedHeight() { - return (rotationDegree % 180 == 0) ? height : width; - } - - @Override - public String toString() { - final String type = yuvFrame - ? "Y: " + yuvStrides[0] + ", U: " + yuvStrides[1] + ", V: " + yuvStrides[2] - : "Texture: " + textureId; - return width + "x" + height + ", " + type; - } - - /** - * Convert the frame to VideoFrame. It is no longer safe to use the I420Frame after calling - * this. - */ - VideoFrame toVideoFrame() { - final VideoFrame.Buffer buffer; - if (backingBuffer != null) { - // We were construted from a VideoFrame.Buffer, just return it. - // Make sure webrtc::VideoFrame object is released. - backingBuffer.retain(); - VideoRenderer.renderFrameDone(this); - buffer = backingBuffer; - } else if (yuvFrame) { - buffer = JavaI420Buffer.wrap(width, height, yuvPlanes[0], yuvStrides[0], yuvPlanes[1], - yuvStrides[1], yuvPlanes[2], yuvStrides[2], - () -> { VideoRenderer.renderFrameDone(this); }); - } else { - // Note: No Handler or YuvConverter means calling toI420 will crash. - buffer = new TextureBufferImpl(width, height, VideoFrame.TextureBuffer.Type.OES, textureId, - RendererCommon.convertMatrixToAndroidGraphicsMatrix(samplingMatrix), null /* handler */, - null /* yuvConverter */, () -> VideoRenderer.renderFrameDone(this)); - } - return new VideoFrame(buffer, rotationDegree, 0 /* timestampNs */); - } - - @CalledByNative("I420Frame") - static I420Frame createI420Frame(int width, int height, int rotationDegree, int y_stride, - ByteBuffer y_buffer, int u_stride, ByteBuffer u_buffer, int v_stride, ByteBuffer v_buffer, - long nativeFramePointer) { - return new I420Frame(width, height, rotationDegree, new int[] {y_stride, u_stride, v_stride}, - new ByteBuffer[] {y_buffer, u_buffer, v_buffer}, nativeFramePointer); - } - } - - /** The real meat of VideoSinkInterface. */ - public static interface Callbacks { - // |frame| might have pending rotation and implementation of Callbacks - // should handle that by applying rotation during rendering. The callee - // is responsible for signaling when it is done with |frame| by calling - // renderFrameDone(frame). - @CalledByNative("Callbacks") void renderFrame(I420Frame frame); - } - - /** - * This must be called after every renderFrame() to release the frame. - */ - public static void renderFrameDone(I420Frame frame) { - frame.yuvPlanes = null; - frame.textureId = 0; - if (frame.nativeFramePointer != 0) { - nativeReleaseFrame(frame.nativeFramePointer); - frame.nativeFramePointer = 0; - } - } - - long nativeVideoRenderer; - - public VideoRenderer(Callbacks callbacks) { - nativeVideoRenderer = nativeCreateVideoRenderer(callbacks); - } - - public void dispose() { - if (nativeVideoRenderer == 0) { - // Already disposed. - return; - } - - nativeFreeWrappedVideoRenderer(nativeVideoRenderer); - nativeVideoRenderer = 0; - } - - private static native long nativeCreateVideoRenderer(Callbacks callbacks); - private static native void nativeFreeWrappedVideoRenderer(long videoRenderer); - private static native void nativeReleaseFrame(long framePointer); -} diff --git a/sdk/android/api/org/webrtc/VideoTrack.java b/sdk/android/api/org/webrtc/VideoTrack.java index a5a6eb0a43..5495ee82b1 100644 --- a/sdk/android/api/org/webrtc/VideoTrack.java +++ b/sdk/android/api/org/webrtc/VideoTrack.java @@ -16,7 +16,6 @@ import java.util.List; /** Java version of VideoTrackInterface. */ public class VideoTrack extends MediaStreamTrack { - private final List renderers = new ArrayList<>(); private final IdentityHashMap sinks = new IdentityHashMap(); public VideoTrack(long nativeTrack) { @@ -57,26 +56,8 @@ public class VideoTrack extends MediaStreamTrack { } } - public void addRenderer(VideoRenderer renderer) { - renderers.add(renderer); - nativeAddSink(nativeTrack, renderer.nativeVideoRenderer); - } - - public void removeRenderer(VideoRenderer renderer) { - if (!renderers.remove(renderer)) { - return; - } - nativeRemoveSink(nativeTrack, renderer.nativeVideoRenderer); - renderer.dispose(); - } - @Override public void dispose() { - for (VideoRenderer renderer : renderers) { - nativeRemoveSink(nativeTrack, renderer.nativeVideoRenderer); - renderer.dispose(); - } - renderers.clear(); for (long nativeSink : sinks.values()) { nativeRemoveSink(nativeTrack, nativeSink); nativeFreeSink(nativeSink); diff --git a/sdk/android/src/jni/video_renderer.cc b/sdk/android/src/jni/video_renderer.cc deleted file mode 100644 index 889012a9cb..0000000000 --- a/sdk/android/src/jni/video_renderer.cc +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2017 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. - */ - -#include - -#include "api/video/video_frame.h" -#include "api/video/video_sink_interface.h" -#include "sdk/android/generated_video_jni/jni/VideoRenderer_jni.h" -#include "sdk/android/src/jni/jni_helpers.h" -#include "sdk/android/src/jni/videoframe.h" - -namespace webrtc { -namespace jni { - -// Wrapper dispatching rtc::VideoSinkInterface to a Java VideoRenderer -// instance. -class JavaVideoRendererWrapper : public rtc::VideoSinkInterface { - public: - JavaVideoRendererWrapper(JNIEnv* jni, const JavaRef& j_callbacks) - : j_callbacks_(jni, j_callbacks) {} - - ~JavaVideoRendererWrapper() override {} - - void OnFrame(const VideoFrame& video_frame) override { - JNIEnv* env = AttachCurrentThreadIfNeeded(); - - ScopedJavaLocalRef j_frame; - if (video_frame.video_frame_buffer()->type() == - VideoFrameBuffer::Type::kNative) { - j_frame = FromWrappedJavaBuffer(env, video_frame); - } else { - j_frame = ToJavaI420Frame(env, video_frame); - } - // |j_callbacks_| is responsible for releasing |j_frame| with - // VideoRenderer.renderFrameDone(). - Java_Callbacks_renderFrame(env, j_callbacks_, j_frame); - } - - private: - // Make a shallow copy of |frame| to be used with Java. The callee has - // ownership of the frame, and the frame should be released with - // VideoRenderer.releaseNativeFrame(). - static jlong javaShallowCopy(const VideoFrame& frame) { - return jlongFromPointer(new VideoFrame(frame)); - } - - // Return a VideoRenderer.I420Frame referring to the data in |frame|. - ScopedJavaLocalRef FromWrappedJavaBuffer(JNIEnv* env, - const VideoFrame& frame) { - return Java_I420Frame_Constructor( - env, frame.rotation(), - static_cast(frame.video_frame_buffer().get()) - ->video_frame_buffer(), - javaShallowCopy(frame)); - } - - // Return a VideoRenderer.I420Frame referring to the data in |frame|. - ScopedJavaLocalRef ToJavaI420Frame(JNIEnv* env, - const VideoFrame& frame) { - rtc::scoped_refptr i420_buffer = - frame.video_frame_buffer()->ToI420(); - ScopedJavaLocalRef y_buffer = - NewDirectByteBuffer(env, const_cast(i420_buffer->DataY()), - i420_buffer->StrideY() * i420_buffer->height()); - size_t chroma_height = i420_buffer->ChromaHeight(); - ScopedJavaLocalRef u_buffer = - NewDirectByteBuffer(env, const_cast(i420_buffer->DataU()), - i420_buffer->StrideU() * chroma_height); - ScopedJavaLocalRef v_buffer = - NewDirectByteBuffer(env, const_cast(i420_buffer->DataV()), - i420_buffer->StrideV() * chroma_height); - return Java_I420Frame_createI420Frame( - env, frame.width(), frame.height(), static_cast(frame.rotation()), - i420_buffer->StrideY(), y_buffer, i420_buffer->StrideU(), u_buffer, - i420_buffer->StrideV(), v_buffer, javaShallowCopy(frame)); - } - - ScopedJavaGlobalRef j_callbacks_; -}; - -static void JNI_VideoRenderer_FreeWrappedVideoRenderer( - JNIEnv*, - const JavaParamRef&, - jlong j_p) { - delete reinterpret_cast(j_p); -} - -static void JNI_VideoRenderer_ReleaseFrame(JNIEnv* jni, - const JavaParamRef&, - jlong j_frame_ptr) { - delete reinterpret_cast(j_frame_ptr); -} - -static jlong JNI_VideoRenderer_CreateVideoRenderer( - JNIEnv* jni, - const JavaParamRef&, - const JavaParamRef& j_callbacks) { - std::unique_ptr renderer( - new JavaVideoRendererWrapper(jni, j_callbacks)); - return jlongFromPointer(renderer.release()); -} - -} // namespace jni -} // namespace webrtc