Add checks that we don't redraw the previous frame.

Bug: webrtc:9149
Change-Id: Ia1f61fd43ea9be6c341a111595e8a290a809c72f
Reviewed-on: https://webrtc-review.googlesource.com/69810
Reviewed-by: Peter Hanspers <peterhanspers@webrtc.org>
Commit-Queue: Kári Helgason <kthelgason@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22937}
diff --git a/sdk/objc/Framework/Classes/Metal/RTCMTLVideoView.m b/sdk/objc/Framework/Classes/Metal/RTCMTLVideoView.m
index 0fd8a1a..24dc29f 100644
--- a/sdk/objc/Framework/Classes/Metal/RTCMTLVideoView.m
+++ b/sdk/objc/Framework/Classes/Metal/RTCMTLVideoView.m
@@ -33,7 +33,9 @@
 @property(atomic, strong) RTCVideoFrame *videoFrame;
 @end
 
-@implementation RTCMTLVideoView
+@implementation RTCMTLVideoView {
+  int64_t _lastFrameTimeNs;
+}
 
 @synthesize rendererI420 = _rendererI420;
 @synthesize rendererNV12 = _rendererNV12;
@@ -106,7 +108,8 @@
 - (void)drawInMTKView:(nonnull MTKView *)view {
   NSAssert(view == self.metalView, @"Receiving draw callbacks from foreign instance.");
   RTCVideoFrame *videoFrame = self.videoFrame;
-  if (!videoFrame) {
+  // Skip rendering if we've already rendered this frame.
+  if (!videoFrame || videoFrame.timeStampNs == _lastFrameTimeNs) {
     return;
   }
 
@@ -116,6 +119,7 @@
       if (![self.rendererNV12 addRenderingDestination:self.metalView]) {
         self.rendererNV12 = nil;
         RTCLogError(@"Failed to create NV12 renderer");
+        return;
       }
     }
     [self.rendererNV12 drawFrame:videoFrame];
@@ -125,10 +129,12 @@
       if (![self.rendererI420 addRenderingDestination:self.metalView]) {
         self.rendererI420 = nil;
         RTCLogError(@"Failed to create I420 renderer");
+        return;
       }
     }
     [self.rendererI420 drawFrame:videoFrame];
   }
+  _lastFrameTimeNs = videoFrame.timeStampNs;
 }
 
 - (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size {
diff --git a/sdk/objc/Framework/UnitTests/RTCMTLVideoView_xctest.mm b/sdk/objc/Framework/UnitTests/RTCMTLVideoView_xctest.mm
index 782bc64..8533a31 100644
--- a/sdk/objc/Framework/UnitTests/RTCMTLVideoView_xctest.mm
+++ b/sdk/objc/Framework/UnitTests/RTCMTLVideoView_xctest.mm
@@ -73,6 +73,7 @@
   } else {
     OCMStub([frameMock buffer]).andReturn([[RTCI420Buffer alloc] initWithWidth:200 height:200]);
   }
+  OCMStub([frameMock timeStampNs]).andReturn(arc4random_uniform(INT_MAX));
   return frameMock;
 }
 
@@ -196,4 +197,54 @@
   [self.classMock verify];
 }
 
+- (void)testDontRedrawOldFrame {
+  OCMStub([self.classMock isMetalAvailable]).andReturn(YES);
+  self.rendererNV12Mock = [self rendererMockWithSuccessfulSetup:YES];
+  self.frameMock = [self frameMockWithCVPixelBuffer:YES];
+
+  OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]);
+  OCMExpect([self.classMock createNV12Renderer]).andReturn(self.rendererNV12Mock);
+  [[self.classMock reject] createI420Renderer];
+
+  RTCMTLVideoView *realView = [[RTCMTLVideoView alloc] init];
+  [realView renderFrame:self.frameMock];
+  [realView drawInMTKView:nil];
+
+  [self.rendererNV12Mock verify];
+  [self.classMock verify];
+
+  [[self.rendererNV12Mock reject] drawFrame:[OCMArg any]];
+
+  [realView renderFrame:self.frameMock];
+  [realView drawInMTKView:nil];
+
+  [self.rendererNV12Mock verify];
+}
+
+- (void)testDoDrawNewFrame {
+  OCMStub([self.classMock isMetalAvailable]).andReturn(YES);
+  self.rendererNV12Mock = [self rendererMockWithSuccessfulSetup:YES];
+  self.frameMock = [self frameMockWithCVPixelBuffer:YES];
+
+  OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]);
+  OCMExpect([self.classMock createNV12Renderer]).andReturn(self.rendererNV12Mock);
+  [[self.classMock reject] createI420Renderer];
+
+  RTCMTLVideoView *realView = [[RTCMTLVideoView alloc] init];
+  [realView renderFrame:self.frameMock];
+  [realView drawInMTKView:nil];
+
+  [self.rendererNV12Mock verify];
+  [self.classMock verify];
+
+  // Get new frame.
+  self.frameMock = [self frameMockWithCVPixelBuffer:YES];
+  OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]);
+
+  [realView renderFrame:self.frameMock];
+  [realView drawInMTKView:nil];
+
+  [self.rendererNV12Mock verify];
+}
+
 @end