Move frame adaptation inside video processor.

Bug: webrtc:10530
Change-Id: Iba6a91bf3e1ec4b2821b554e9e28fd2ead662723
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/131947
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Commit-Queue: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27542}
diff --git a/sdk/android/api/org/webrtc/VideoProcessor.java b/sdk/android/api/org/webrtc/VideoProcessor.java
index 1a2aca5..3a89090 100644
--- a/sdk/android/api/org/webrtc/VideoProcessor.java
+++ b/sdk/android/api/org/webrtc/VideoProcessor.java
@@ -17,9 +17,60 @@
  * on to another object. This object is also allowed to observe capturer start/stop.
  */
 public interface VideoProcessor extends CapturerObserver {
+  public static class FrameAdaptationParameters {
+    public final int cropX;
+    public final int cropY;
+    public final int cropWidth;
+    public final int cropHeight;
+    public final int scaleWidth;
+    public final int scaleHeight;
+    public final long timestampNs;
+    public final boolean drop;
+
+    public FrameAdaptationParameters(int cropX, int cropY, int cropWidth, int cropHeight,
+        int scaleWidth, int scaleHeight, long timestampNs, boolean drop) {
+      this.cropX = cropX;
+      this.cropY = cropY;
+      this.cropWidth = cropWidth;
+      this.cropHeight = cropHeight;
+      this.scaleWidth = scaleWidth;
+      this.scaleHeight = scaleHeight;
+      this.timestampNs = timestampNs;
+      this.drop = drop;
+    }
+  }
+
+  /**
+   * This is a chance to access an unadapted frame. The default implementation applies the
+   * adaptation and forwards the frame to {@link #onFrameCaptured(VideoFrame)}.
+   */
+  default void onFrameCaptured(VideoFrame frame, FrameAdaptationParameters parameters) {
+    VideoFrame adaptedFrame = applyFrameAdaptationParameters(frame, parameters);
+    if (adaptedFrame != null) {
+      onFrameCaptured(adaptedFrame);
+      adaptedFrame.release();
+    }
+  }
+
   /**
    * Set the sink that receives the output from this processor. Null can be passed in to unregister
    * a sink. After this call returns, no frames should be delivered to an unregistered sink.
    */
   void setSink(@Nullable VideoSink sink);
+
+  /**
+   * Applies the frame adaptation parameters to a frame. Returns null if the frame is meant to be
+   * dropped. Returns a new frame. The caller is responsible for releasing the returned frame.
+   */
+  public static @Nullable VideoFrame applyFrameAdaptationParameters(
+      VideoFrame frame, FrameAdaptationParameters parameters) {
+    if (parameters.drop) {
+      return null;
+    }
+
+    final VideoFrame.Buffer adaptedBuffer =
+        frame.getBuffer().cropAndScale(parameters.cropX, parameters.cropY, parameters.cropWidth,
+            parameters.cropHeight, parameters.scaleWidth, parameters.scaleHeight);
+    return new VideoFrame(adaptedBuffer, frame.getRotation(), parameters.timestampNs);
+  }
 }
diff --git a/sdk/android/api/org/webrtc/VideoSource.java b/sdk/android/api/org/webrtc/VideoSource.java
index 847a7bd..1b40231 100644
--- a/sdk/android/api/org/webrtc/VideoSource.java
+++ b/sdk/android/api/org/webrtc/VideoSource.java
@@ -59,28 +59,20 @@
 
     @Override
     public void onFrameCaptured(VideoFrame frame) {
-      final NativeAndroidVideoTrackSource.FrameAdaptationParameters parameters =
+      final VideoProcessor.FrameAdaptationParameters parameters =
           nativeAndroidVideoTrackSource.adaptFrame(frame);
-      if (parameters == null) {
-        // Drop frame.
-        return;
-      }
-
-      final VideoFrame.Buffer adaptedBuffer =
-          frame.getBuffer().cropAndScale(parameters.cropX, parameters.cropY, parameters.cropWidth,
-              parameters.cropHeight, parameters.scaleWidth, parameters.scaleHeight);
-      final VideoFrame adaptedFrame =
-          new VideoFrame(adaptedBuffer, frame.getRotation(), parameters.timestampNs);
-
       synchronized (videoProcessorLock) {
         if (videoProcessor != null) {
-          videoProcessor.onFrameCaptured(adaptedFrame);
-          adaptedBuffer.release();
+          videoProcessor.onFrameCaptured(frame, parameters);
           return;
         }
       }
-      nativeAndroidVideoTrackSource.onFrameCaptured(adaptedFrame);
-      adaptedBuffer.release();
+
+      VideoFrame adaptedFrame = VideoProcessor.applyFrameAdaptationParameters(frame, parameters);
+      if (adaptedFrame != null) {
+        nativeAndroidVideoTrackSource.onFrameCaptured(adaptedFrame);
+        adaptedFrame.release();
+      }
     }
   };
 
diff --git a/sdk/android/src/java/org/webrtc/NativeAndroidVideoTrackSource.java b/sdk/android/src/java/org/webrtc/NativeAndroidVideoTrackSource.java
index d19f6f0..48690fb 100644
--- a/sdk/android/src/java/org/webrtc/NativeAndroidVideoTrackSource.java
+++ b/sdk/android/src/java/org/webrtc/NativeAndroidVideoTrackSource.java
@@ -12,6 +12,7 @@
 
 import android.support.annotation.Nullable;
 import org.webrtc.VideoFrame;
+import org.webrtc.VideoProcessor;
 
 /**
  * This class is meant to be a simple layer that only handles the JNI wrapping of a C++
@@ -25,28 +26,6 @@
   // Pointer to webrtc::jni::AndroidVideoTrackSource.
   private final long nativeAndroidVideoTrackSource;
 
-  public static class FrameAdaptationParameters {
-    public final int cropX;
-    public final int cropY;
-    public final int cropWidth;
-    public final int cropHeight;
-    public final int scaleWidth;
-    public final int scaleHeight;
-    public final long timestampNs;
-
-    @CalledByNative("FrameAdaptationParameters")
-    FrameAdaptationParameters(int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth,
-        int scaleHeight, long timestampNs) {
-      this.cropX = cropX;
-      this.cropY = cropY;
-      this.cropWidth = cropWidth;
-      this.cropHeight = cropHeight;
-      this.scaleWidth = scaleWidth;
-      this.scaleHeight = scaleHeight;
-      this.timestampNs = timestampNs;
-    }
-  }
-
   public NativeAndroidVideoTrackSource(long nativeAndroidVideoTrackSource) {
     this.nativeAndroidVideoTrackSource = nativeAndroidVideoTrackSource;
   }
@@ -66,7 +45,7 @@
    * adaptation parameters before calling onFrameCaptured().
    */
   @Nullable
-  public FrameAdaptationParameters adaptFrame(VideoFrame frame) {
+  public VideoProcessor.FrameAdaptationParameters adaptFrame(VideoFrame frame) {
     return nativeAdaptFrame(nativeAndroidVideoTrackSource, frame.getBuffer().getWidth(),
         frame.getBuffer().getHeight(), frame.getRotation(), frame.getTimestampNs());
   }
@@ -93,13 +72,21 @@
         targetPortraitAspectRatio.height, maxPortraitPixelCount, maxFps);
   }
 
+  @CalledByNative
+  static VideoProcessor.FrameAdaptationParameters createFrameAdaptationParameters(int cropX,
+      int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight, long timestampNs,
+      boolean drop) {
+    return new VideoProcessor.FrameAdaptationParameters(
+        cropX, cropY, cropWidth, cropHeight, scaleWidth, scaleHeight, timestampNs, drop);
+  }
+
   private static native void nativeSetState(long nativeAndroidVideoTrackSource, boolean isLive);
   private static native void nativeAdaptOutputFormat(long nativeAndroidVideoTrackSource,
       int landscapeWidth, int landscapeHeight, @Nullable Integer maxLandscapePixelCount,
       int portraitWidth, int portraitHeight, @Nullable Integer maxPortraitPixelCount,
       @Nullable Integer maxFps);
   @Nullable
-  private static native FrameAdaptationParameters nativeAdaptFrame(
+  private static native VideoProcessor.FrameAdaptationParameters nativeAdaptFrame(
       long nativeAndroidVideoTrackSource, int width, int height, int rotation, long timestampNs);
   private static native void nativeOnFrameCaptured(
       long nativeAndroidVideoTrackSource, int rotation, long timestampNs, VideoFrame.Buffer buffer);
diff --git a/sdk/android/src/java/org/webrtc/NativeCapturerObserver.java b/sdk/android/src/java/org/webrtc/NativeCapturerObserver.java
index f0c27c5..c195fb3 100644
--- a/sdk/android/src/java/org/webrtc/NativeCapturerObserver.java
+++ b/sdk/android/src/java/org/webrtc/NativeCapturerObserver.java
@@ -36,7 +36,7 @@
 
   @Override
   public void onFrameCaptured(VideoFrame frame) {
-    final NativeAndroidVideoTrackSource.FrameAdaptationParameters parameters =
+    final VideoProcessor.FrameAdaptationParameters parameters =
         nativeAndroidVideoTrackSource.adaptFrame(frame);
     if (parameters == null) {
       // Drop frame.
diff --git a/sdk/android/src/jni/android_video_track_source.cc b/sdk/android/src/jni/android_video_track_source.cc
index dbcbd6a..973167a 100644
--- a/sdk/android/src/jni/android_video_track_source.cc
+++ b/sdk/android/src/jni/android_video_track_source.cc
@@ -102,33 +102,30 @@
                                   camera_time_us, rtc::TimeMicros())
                         : j_timestamp_ns;
 
-  int adapted_width;
-  int adapted_height;
-  int crop_width;
-  int crop_height;
-  int crop_x;
-  int crop_y;
+  int adapted_width = 0;
+  int adapted_height = 0;
+  int crop_width = 0;
+  int crop_height = 0;
+  int crop_x = 0;
+  int crop_y = 0;
+  bool drop;
 
   // TODO(magjed): Move this logic to users of NativeAndroidVideoTrackSource
   // instead, in order to keep this native wrapping layer as thin as possible.
   if (rotation % 180 == 0) {
-    if (!rtc::AdaptedVideoTrackSource::AdaptFrame(
-            j_width, j_height, camera_time_us, &adapted_width, &adapted_height,
-            &crop_width, &crop_height, &crop_x, &crop_y)) {
-      return nullptr;
-    }
+    drop = !rtc::AdaptedVideoTrackSource::AdaptFrame(
+        j_width, j_height, camera_time_us, &adapted_width, &adapted_height,
+        &crop_width, &crop_height, &crop_x, &crop_y);
   } else {
     // Swap all width/height and x/y.
-    if (!rtc::AdaptedVideoTrackSource::AdaptFrame(
-            j_height, j_width, camera_time_us, &adapted_height, &adapted_width,
-            &crop_height, &crop_width, &crop_y, &crop_x)) {
-      return nullptr;
-    }
+    drop = !rtc::AdaptedVideoTrackSource::AdaptFrame(
+        j_height, j_width, camera_time_us, &adapted_height, &adapted_width,
+        &crop_height, &crop_width, &crop_y, &crop_x);
   }
 
-  return Java_FrameAdaptationParameters_Constructor(
+  return Java_NativeAndroidVideoTrackSource_createFrameAdaptationParameters(
       env, crop_x, crop_y, crop_width, crop_height, adapted_width,
-      adapted_height, aligned_timestamp_ns);
+      adapted_height, aligned_timestamp_ns, drop);
 }
 
 void AndroidVideoTrackSource::OnFrameCaptured(