Add VideoCodec::PreferDecodeLate
The purpose is so that a decoder (Android) that only have a limited number of output buffers can make sure that decoding is done just before the frame is needed.

Removed unused iSupportsRenderTiming and the settings structs since it was not used.
Added VCMReceiver::FrameForDecoding unit test for the case when PreferDecodeLate is set.

Note that this does not change the current behaviour. We actually currently always decode frames late. This cl is to make sure the behaviour is kept for Android, if the default behaviour is changed.

Review URL: https://codereview.webrtc.org/1428293003

Cr-Commit-Position: refs/heads/master@{#10974}
diff --git a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
index fa11196..fbe5b5c 100644
--- a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
+++ b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
@@ -89,6 +89,9 @@
   int32_t Release() override;
 
   int32_t Reset() override;
+
+  bool PrefersLateDecoding() const override { return true; }
+
   // rtc::MessageHandler implementation.
   void OnMessage(rtc::Message* msg) override;
 
diff --git a/webrtc/modules/video_coding/codec_database.cc b/webrtc/modules/video_coding/codec_database.cc
index be7f5ca..20a1143 100644
--- a/webrtc/modules/video_coding/codec_database.cc
+++ b/webrtc/modules/video_coding/codec_database.cc
@@ -85,12 +85,9 @@
 
 VCMExtDecoderMapItem::VCMExtDecoderMapItem(
     VideoDecoder* external_decoder_instance,
-    uint8_t payload_type,
-    bool internal_render_timing)
+    uint8_t payload_type)
     : payload_type(payload_type),
-      external_decoder_instance(external_decoder_instance),
-      internal_render_timing(internal_render_timing) {
-}
+      external_decoder_instance(external_decoder_instance) {}
 
 VCMCodecDataBase::VCMCodecDataBase(
     VideoEncoderRateObserver* encoder_rate_observer,
@@ -419,13 +416,11 @@
 
 // Add the external encoder object to the list of external decoders.
 // Won't be registered as a receive codec until RegisterReceiveCodec is called.
-void VCMCodecDataBase::RegisterExternalDecoder(
-    VideoDecoder* external_decoder,
-    uint8_t payload_type,
-    bool internal_render_timing) {
+void VCMCodecDataBase::RegisterExternalDecoder(VideoDecoder* external_decoder,
+                                               uint8_t payload_type) {
   // Check if payload value already exists, if so  - erase old and insert new.
-  VCMExtDecoderMapItem* ext_decoder = new VCMExtDecoderMapItem(
-      external_decoder, payload_type, internal_render_timing);
+  VCMExtDecoderMapItem* ext_decoder =
+      new VCMExtDecoderMapItem(external_decoder, payload_type);
   DeregisterExternalDecoder(payload_type);
   dec_external_map_[payload_type] = ext_decoder;
 }
@@ -524,12 +519,10 @@
   }
 }
 
-bool VCMCodecDataBase::SupportsRenderScheduling() const {
-  const VCMExtDecoderMapItem* ext_item = FindExternalDecoderItem(
-      receive_codec_.plType);
-  if (!ext_item)
+bool VCMCodecDataBase::PrefersLateDecoding() const {
+  if (!ptr_decoder_)
     return true;
-  return ext_item->internal_render_timing;
+  return ptr_decoder_->PrefersLateDecoding();
 }
 
 bool VCMCodecDataBase::MatchesCurrentResolution(int width, int height) const {
diff --git a/webrtc/modules/video_coding/codec_database.h b/webrtc/modules/video_coding/codec_database.h
index c39474f..62ec30a 100644
--- a/webrtc/modules/video_coding/codec_database.h
+++ b/webrtc/modules/video_coding/codec_database.h
@@ -36,12 +36,10 @@
 struct VCMExtDecoderMapItem {
  public:
   VCMExtDecoderMapItem(VideoDecoder* external_decoder_instance,
-                       uint8_t payload_type,
-                       bool internal_render_timing);
+                       uint8_t payload_type);
 
   uint8_t payload_type;
   VideoDecoder* external_decoder_instance;
-  bool internal_render_timing;
 };
 
 class VCMCodecDataBase {
@@ -90,12 +88,8 @@
   bool DeregisterExternalDecoder(uint8_t payload_type);
 
   // Registers an external decoder object to the payload type |payload_type|.
-  // |internal_render_timing| is set to true if the |external_decoder| has
-  // built in rendering which is able to obey the render timestamps of the
-  // encoded frames.
   void RegisterExternalDecoder(VideoDecoder* external_decoder,
-                               uint8_t payload_type,
-                               bool internal_render_timing);
+                               uint8_t payload_type);
 
   bool DecoderRegistered() const;
 
@@ -124,10 +118,9 @@
   // deep copies returned by CreateDecoderCopy().
   void ReleaseDecoder(VCMGenericDecoder* decoder) const;
 
-  // Returns true if the currently active decoder supports render scheduling,
-  // that is, it is able to render frames according to the render timestamp of
-  // the encoded frames.
-  bool SupportsRenderScheduling() const;
+  // Returns true if the currently active decoder prefer to decode frames late.
+  // That means that frames must be decoded near the render times stamp.
+  bool PrefersLateDecoding() const;
 
   bool MatchesCurrentResolution(int width, int height) const;
 
diff --git a/webrtc/modules/video_coding/generic_decoder.cc b/webrtc/modules/video_coding/generic_decoder.cc
index 08282f9..dc78ec2 100644
--- a/webrtc/modules/video_coding/generic_decoder.cc
+++ b/webrtc/modules/video_coding/generic_decoder.cc
@@ -198,4 +198,8 @@
   return _isExternal;
 }
 
+bool VCMGenericDecoder::PrefersLateDecoding() const {
+  return _decoder->PrefersLateDecoding();
+}
+
 }  // namespace
diff --git a/webrtc/modules/video_coding/generic_decoder.h b/webrtc/modules/video_coding/generic_decoder.h
index c633519..40a9845 100644
--- a/webrtc/modules/video_coding/generic_decoder.h
+++ b/webrtc/modules/video_coding/generic_decoder.h
@@ -97,6 +97,7 @@
     int32_t RegisterDecodeCompleteCallback(VCMDecodedFrameCallback* callback);
 
     bool External() const;
+    bool PrefersLateDecoding() const;
 
 private:
     VCMDecodedFrameCallback*    _callback;
diff --git a/webrtc/modules/video_coding/include/video_coding.h b/webrtc/modules/video_coding/include/video_coding.h
index 5f5961c..880180d 100644
--- a/webrtc/modules/video_coding/include/video_coding.h
+++ b/webrtc/modules/video_coding/include/video_coding.h
@@ -333,11 +333,9 @@
     //      - externalDecoder        : The external decoder/renderer object.
     //      - payloadType            : The payload type which this decoder should be
     //                                 registered to.
-    //      - internalRenderTiming   : True if the internal renderer (if any) of the decoder
-    //                                 object can make sure to render at a given time in ms.
+    //
     virtual void RegisterExternalDecoder(VideoDecoder* externalDecoder,
-                                         uint8_t payloadType,
-                                         bool internalRenderTiming) = 0;
+                                         uint8_t payloadType) = 0;
 
     // Register a receive callback. Will be called whenever there is a new frame ready
     // for rendering.
diff --git a/webrtc/modules/video_coding/receiver.cc b/webrtc/modules/video_coding/receiver.cc
index 5314b30..fe05b86 100644
--- a/webrtc/modules/video_coding/receiver.cc
+++ b/webrtc/modules/video_coding/receiver.cc
@@ -96,7 +96,7 @@
 
 VCMEncodedFrame* VCMReceiver::FrameForDecoding(uint16_t max_wait_time_ms,
                                                int64_t& next_render_time_ms,
-                                               bool render_timing) {
+                                               bool prefer_late_decoding) {
   const int64_t start_time_ms = clock_->TimeInMilliseconds();
   uint32_t frame_timestamp = 0;
   // Exhaust wait time to get a complete frame for decoding.
@@ -140,7 +140,7 @@
     return NULL;
   }
 
-  if (!render_timing) {
+  if (prefer_late_decoding) {
     // Decode frame as close as possible to the render timestamp.
     const int32_t available_wait_time = max_wait_time_ms -
         static_cast<int32_t>(clock_->TimeInMilliseconds() - start_time_ms);
diff --git a/webrtc/modules/video_coding/receiver.h b/webrtc/modules/video_coding/receiver.h
index bc2e026..a30d16c 100644
--- a/webrtc/modules/video_coding/receiver.h
+++ b/webrtc/modules/video_coding/receiver.h
@@ -47,7 +47,7 @@
                        uint16_t frame_height);
   VCMEncodedFrame* FrameForDecoding(uint16_t max_wait_time_ms,
                                     int64_t& next_render_time_ms,
-                                    bool render_timing = true);
+                                    bool prefer_late_decoding);
   void ReleaseFrame(VCMEncodedFrame* frame);
   void ReceiveStatistics(uint32_t* bitrate, uint32_t* framerate);
   uint32_t DiscardedPackets() const;
diff --git a/webrtc/modules/video_coding/receiver_unittest.cc b/webrtc/modules/video_coding/receiver_unittest.cc
index 82345c8..d51b004 100644
--- a/webrtc/modules/video_coding/receiver_unittest.cc
+++ b/webrtc/modules/video_coding/receiver_unittest.cc
@@ -14,6 +14,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webrtc/base/checks.h"
+#include "webrtc/modules/video_coding/encoded_frame.h"
 #include "webrtc/modules/video_coding/packet.h"
 #include "webrtc/modules/video_coding/receiver.h"
 #include "webrtc/modules/video_coding/test/stream_generator.h"
@@ -141,7 +142,8 @@
     EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
   }
   int64_t next_render_time_ms = 0;
-  VCMEncodedFrame* frame = receiver_.FrameForDecoding(10, next_render_time_ms);
+  VCMEncodedFrame* frame =
+      receiver_.FrameForDecoding(10, next_render_time_ms, false);
   EXPECT_TRUE(frame == NULL);
   receiver_.ReleaseFrame(frame);
   EXPECT_GE(InsertFrame(kVideoFrameDelta, false), kNoError);
@@ -523,4 +525,60 @@
   }
 }
 
+// Test whether VCMReceiver::FrameForDecoding handles parameter
+// |prefer_late_decoding| and |max_wait_time_ms| correctly:
+// 1. The function execution should never take more than |max_wait_time_ms|.
+// 2. If the function exit before now + |max_wait_time_ms|, a frame must be
+//    returned and the end time must be equal to the render timestamp - delay
+//    for decoding and rendering.
+TEST_F(VCMReceiverTimingTest, FrameForDecodingPreferLateDecoding) {
+  const size_t kNumFrames = 100;
+  const int kFramePeriod = 40;
+
+  int64_t arrive_timestamps[kNumFrames];
+  int64_t render_timestamps[kNumFrames];
+  int64_t next_render_time;
+
+  int render_delay_ms;
+  int max_decode_ms;
+  int dummy;
+  timing_.GetTimings(&dummy, &max_decode_ms, &dummy, &dummy, &dummy, &dummy,
+                     &render_delay_ms);
+
+  // Construct test samples.
+  // render_timestamps are the timestamps stored in the Frame;
+  // arrive_timestamps controls when the Frame packet got received.
+  for (size_t i = 0; i < kNumFrames; i++) {
+    // Preset frame rate to 25Hz.
+    // But we add a reasonable deviation to arrive_timestamps to mimic Internet
+    // fluctuation.
+    arrive_timestamps[i] =
+        (i + 1) * kFramePeriod + (i % 10) * ((i % 2) ? 1 : -1);
+    render_timestamps[i] = (i + 1) * kFramePeriod;
+  }
+
+  clock_.SetFrames(arrive_timestamps, render_timestamps, kNumFrames);
+
+  // Record how many frames we finally get out of the receiver.
+  size_t num_frames_return = 0;
+  const int64_t kMaxWaitTime = 30;
+  bool prefer_late_decoding = true;
+  while (num_frames_return < kNumFrames) {
+    int64_t start_time = clock_.TimeInMilliseconds();
+
+    VCMEncodedFrame* frame =
+        receiver_.FrameForDecoding(kMaxWaitTime, next_render_time,
+                                   prefer_late_decoding);
+    int64_t end_time = clock_.TimeInMilliseconds();
+    if (frame) {
+      EXPECT_EQ(frame->RenderTimeMs() - max_decode_ms - render_delay_ms,
+                end_time);
+      receiver_.ReleaseFrame(frame);
+      ++num_frames_return;
+    } else {
+      EXPECT_EQ(kMaxWaitTime, end_time - start_time);
+    }
+  }
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/video_coding/video_coding_impl.cc b/webrtc/modules/video_coding/video_coding_impl.cc
index c9ed6f4..64cc090 100644
--- a/webrtc/modules/video_coding/video_coding_impl.cc
+++ b/webrtc/modules/video_coding/video_coding_impl.cc
@@ -197,10 +197,8 @@
   }
 
   void RegisterExternalDecoder(VideoDecoder* externalDecoder,
-                               uint8_t payloadType,
-                               bool internalRenderTiming) override {
-    receiver_.RegisterExternalDecoder(externalDecoder, payloadType,
-                                      internalRenderTiming);
+                               uint8_t payloadType) override {
+    receiver_.RegisterExternalDecoder(externalDecoder, payloadType);
   }
 
   int32_t RegisterReceiveCallback(
diff --git a/webrtc/modules/video_coding/video_coding_impl.h b/webrtc/modules/video_coding/video_coding_impl.h
index cfa0f92..2134e4d 100644
--- a/webrtc/modules/video_coding/video_coding_impl.h
+++ b/webrtc/modules/video_coding/video_coding_impl.h
@@ -151,8 +151,7 @@
                                bool requireKeyFrame);
 
   void RegisterExternalDecoder(VideoDecoder* externalDecoder,
-                               uint8_t payloadType,
-                               bool internalRenderTiming);
+                               uint8_t payloadType);
   int32_t RegisterReceiveCallback(VCMReceiveCallback* receiveCallback);
   int32_t RegisterReceiveStatisticsCallback(
       VCMReceiveStatisticsCallback* receiveStats);
diff --git a/webrtc/modules/video_coding/video_coding_robustness_unittest.cc b/webrtc/modules/video_coding/video_coding_robustness_unittest.cc
index d5a179d..4111109 100644
--- a/webrtc/modules/video_coding/video_coding_robustness_unittest.cc
+++ b/webrtc/modules/video_coding/video_coding_robustness_unittest.cc
@@ -44,7 +44,7 @@
     ASSERT_EQ(0, vcm_->RegisterPacketRequestCallback(&request_callback_));
     ASSERT_EQ(VCM_OK, vcm_->Codec(kVideoCodecVP8, &video_codec_));
     ASSERT_EQ(VCM_OK, vcm_->RegisterReceiveCodec(&video_codec_, 1));
-    vcm_->RegisterExternalDecoder(&decoder_, video_codec_.plType, true);
+    vcm_->RegisterExternalDecoder(&decoder_, video_codec_.plType);
   }
 
   virtual void TearDown() {
@@ -204,7 +204,7 @@
   InsertPacket(0, 0, true, false, kVideoFrameKey);
   InsertPacket(0, 1, false, false, kVideoFrameKey);
   InsertPacket(0, 2, false, true, kVideoFrameKey);
-  EXPECT_EQ(VCM_OK, vcm_->Decode(0));  // Decode timestamp 0.
+  EXPECT_EQ(VCM_OK, vcm_->Decode(33));  // Decode timestamp 0.
   EXPECT_EQ(VCM_OK, vcm_->Process());  // Expect no NACK list.
 
   clock_->AdvanceTimeMilliseconds(33);
@@ -222,7 +222,7 @@
   EXPECT_EQ(VCM_OK, vcm_->Process());  // Expect no NACK list.
 
   clock_->AdvanceTimeMilliseconds(10);
-  EXPECT_EQ(VCM_OK, vcm_->Decode(0));  // Decode timestamp 6000 complete.
+  EXPECT_EQ(VCM_OK, vcm_->Decode(23));  // Decode timestamp 6000 complete.
   EXPECT_EQ(VCM_OK, vcm_->Process());  // Expect no NACK list.
 
   clock_->AdvanceTimeMilliseconds(23);
@@ -231,6 +231,6 @@
   InsertPacket(9000, 9, true, false, kVideoFrameDelta);
   InsertPacket(9000, 10, false, false, kVideoFrameDelta);
   InsertPacket(9000, 11, false, true, kVideoFrameDelta);
-  EXPECT_EQ(VCM_OK, vcm_->Decode(0));  // Decode timestamp 9000 complete.
+  EXPECT_EQ(VCM_OK, vcm_->Decode(33));  // Decode timestamp 9000 complete.
 }
 }  // namespace webrtc
diff --git a/webrtc/modules/video_coding/video_receiver.cc b/webrtc/modules/video_coding/video_receiver.cc
index c347baa..f7ac4bc 100644
--- a/webrtc/modules/video_coding/video_receiver.cc
+++ b/webrtc/modules/video_coding/video_receiver.cc
@@ -235,11 +235,9 @@
   return VCM_OK;
 }
 
-// Register an externally defined decoder/render object.
-// Can be a decoder only or a decoder coupled with a renderer.
+// Register an externally defined decoder object.
 void VideoReceiver::RegisterExternalDecoder(VideoDecoder* externalDecoder,
-                                               uint8_t payloadType,
-                                               bool internalRenderTiming) {
+                                            uint8_t payloadType) {
   CriticalSectionScoped cs(_receiveCritSect);
   if (externalDecoder == NULL) {
     // Make sure the VCM updates the decoder next time it decodes.
@@ -247,8 +245,7 @@
     RTC_CHECK(_codecDataBase.DeregisterExternalDecoder(payloadType));
     return;
   }
-  _codecDataBase.RegisterExternalDecoder(externalDecoder, payloadType,
-                                         internalRenderTiming);
+  _codecDataBase.RegisterExternalDecoder(externalDecoder, payloadType);
 }
 
 // Register a frame type request callback.
@@ -281,14 +278,14 @@
 // Should be called as often as possible to get the most out of the decoder.
 int32_t VideoReceiver::Decode(uint16_t maxWaitTimeMs) {
   int64_t nextRenderTimeMs;
-  bool supports_render_scheduling;
+  bool prefer_late_decoding = false;
   {
     CriticalSectionScoped cs(_receiveCritSect);
-    supports_render_scheduling = _codecDataBase.SupportsRenderScheduling();
+    prefer_late_decoding = _codecDataBase.PrefersLateDecoding();
   }
 
   VCMEncodedFrame* frame = _receiver.FrameForDecoding(
-      maxWaitTimeMs, nextRenderTimeMs, supports_render_scheduling);
+      maxWaitTimeMs, nextRenderTimeMs, prefer_late_decoding);
 
   if (frame == NULL) {
     return VCM_FRAME_NOT_READY;
@@ -369,13 +366,7 @@
                           "type",
                           frame.FrameType());
   // Change decoder if payload type has changed
-  const bool renderTimingBefore = _codecDataBase.SupportsRenderScheduling();
   _decoder = _codecDataBase.GetDecoder(frame, &_decodedFrameCallback);
-  if (renderTimingBefore != _codecDataBase.SupportsRenderScheduling()) {
-    // Make sure we reset the decode time estimate since it will
-    // be zero for codecs without render timing.
-    _timing.ResetDecodeTime();
-  }
   if (_decoder == NULL) {
     return VCM_NO_CODEC_REGISTERED;
   }
diff --git a/webrtc/modules/video_coding/video_receiver_unittest.cc b/webrtc/modules/video_coding/video_receiver_unittest.cc
index 049f600..8fd46ec 100644
--- a/webrtc/modules/video_coding/video_receiver_unittest.cc
+++ b/webrtc/modules/video_coding/video_receiver_unittest.cc
@@ -34,7 +34,7 @@
 
   virtual void SetUp() {
     receiver_.reset(new VideoReceiver(&clock_, &event_factory_));
-    receiver_->RegisterExternalDecoder(&decoder_, kUnusedPayloadType, true);
+    receiver_->RegisterExternalDecoder(&decoder_, kUnusedPayloadType);
     const size_t kMaxNackListSize = 250;
     const int kMaxPacketAgeToNack = 450;
     receiver_->SetNackSettings(kMaxNackListSize, kMaxPacketAgeToNack, 0);
@@ -55,7 +55,7 @@
     }
     EXPECT_EQ(0, receiver_->Process());
     EXPECT_CALL(decoder_, Decode(_, _, _, _, _)).Times(0);
-    EXPECT_EQ(VCM_FRAME_NOT_READY, receiver_->Decode(0));
+    EXPECT_EQ(VCM_FRAME_NOT_READY, receiver_->Decode(100));
   }
 
   void InsertAndVerifyDecodableFrame(const uint8_t* payload,
@@ -67,7 +67,7 @@
     EXPECT_CALL(packet_request_callback_, ResendPackets(_, _)).Times(0);
     EXPECT_EQ(0, receiver_->Process());
     EXPECT_CALL(decoder_, Decode(_, _, _, _, _)).Times(1);
-    EXPECT_EQ(0, receiver_->Decode(0));
+    EXPECT_EQ(0, receiver_->Decode(100));
   }
 
   SimulatedClock clock_;
diff --git a/webrtc/video/video_decoder.cc b/webrtc/video/video_decoder.cc
index fa1f2ee..2a0151d 100644
--- a/webrtc/video/video_decoder.cc
+++ b/webrtc/video/video_decoder.cc
@@ -131,4 +131,10 @@
   return decoder_->Reset();
 }
 
+bool VideoDecoderSoftwareFallbackWrapper::PrefersLateDecoding() const {
+  if (fallback_decoder_)
+    return fallback_decoder_->PrefersLateDecoding();
+  return decoder_->PrefersLateDecoding();
+}
+
 }  // namespace webrtc
diff --git a/webrtc/video/video_receive_stream.cc b/webrtc/video/video_receive_stream.cc
index 9d1664e..7779fdd 100644
--- a/webrtc/video/video_receive_stream.cc
+++ b/webrtc/video/video_receive_stream.cc
@@ -39,8 +39,6 @@
   ss << "{decoder: " << (decoder != nullptr ? "(VideoDecoder)" : "nullptr");
   ss << ", payload_type: " << payload_type;
   ss << ", payload_name: " << payload_name;
-  ss << ", is_renderer: " << (is_renderer ? "yes" : "no");
-  ss << ", expected_delay_ms: " << expected_delay_ms;
   ss << '}';
 
   return ss.str();
@@ -269,11 +267,8 @@
         << "Duplicate payload type (" << decoder.payload_type
         << ") for different decoders.";
     decoder_payload_types.insert(decoder.payload_type);
-    RTC_CHECK_EQ(0,
-                 vie_channel_->RegisterExternalDecoder(
-                     decoder.payload_type, decoder.decoder, decoder.is_renderer,
-                     decoder.is_renderer ? decoder.expected_delay_ms
-                                         : config.render_delay_ms));
+    vie_channel_->RegisterExternalDecoder(decoder.payload_type,
+                                          decoder.decoder);
 
     VideoCodec codec = CreateDecoderVideoCodec(decoder);
 
@@ -283,6 +278,7 @@
   incoming_video_stream_.reset(new IncomingVideoStream(
       0, config.renderer ? config.renderer->SmoothsRenderedFrames() : false));
   incoming_video_stream_->SetExpectedRenderDelay(config.render_delay_ms);
+  vie_channel_->SetExpectedRenderDelay(config.render_delay_ms);
   incoming_video_stream_->SetExternalCallback(this);
   vie_channel_->SetIncomingVideoStream(incoming_video_stream_.get());
 
diff --git a/webrtc/video/vie_channel.cc b/webrtc/video/vie_channel.cc
index 4097a8b..54bc72b 100644
--- a/webrtc/video/vie_channel.cc
+++ b/webrtc/video/vie_channel.cc
@@ -430,14 +430,10 @@
   return 0;
 }
 
-
-int32_t ViEChannel::RegisterExternalDecoder(const uint8_t pl_type,
-                                            VideoDecoder* decoder,
-                                            bool buffered_rendering,
-                                            int32_t render_delay) {
+void ViEChannel::RegisterExternalDecoder(const uint8_t pl_type,
+                                         VideoDecoder* decoder) {
   RTC_DCHECK(!sender_);
-  vcm_->RegisterExternalDecoder(decoder, pl_type, buffered_rendering);
-  return vcm_->SetRenderDelay(render_delay);
+  vcm_->RegisterExternalDecoder(decoder, pl_type);
 }
 
 int32_t ViEChannel::ReceiveCodecStatistics(uint32_t* num_key_frames,
@@ -456,6 +452,10 @@
   return vcm_->Delay();
 }
 
+void ViEChannel::SetExpectedRenderDelay(int delay_ms) {
+  vcm_->SetRenderDelay(delay_ms);
+}
+
 void ViEChannel::SetRTCPMode(const RtcpMode rtcp_mode) {
   for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_)
     rtp_rtcp->SetRTCPStatus(rtcp_mode);
diff --git a/webrtc/video/vie_channel.h b/webrtc/video/vie_channel.h
index ed0712b..8f99260 100644
--- a/webrtc/video/vie_channel.h
+++ b/webrtc/video/vie_channel.h
@@ -86,14 +86,8 @@
   // type has changed and we should start a new RTP stream.
   int32_t SetSendCodec(const VideoCodec& video_codec, bool new_stream = true);
   int32_t SetReceiveCodec(const VideoCodec& video_codec);
-  // Registers an external decoder. |buffered_rendering| means that the decoder
-  // will render frames after decoding according to the render timestamp
-  // provided by the video coding module. |render_delay| indicates the time
-  // needed to decode and render a frame.
-  int32_t RegisterExternalDecoder(const uint8_t pl_type,
-                                  VideoDecoder* decoder,
-                                  bool buffered_rendering,
-                                  int32_t render_delay);
+  // Registers an external decoder.
+  void RegisterExternalDecoder(const uint8_t pl_type, VideoDecoder* decoder);
   int32_t ReceiveCodecStatistics(uint32_t* num_key_frames,
                                  uint32_t* num_delta_frames);
   uint32_t DiscardedPackets() const;
@@ -101,6 +95,8 @@
   // Returns the estimated delay in milliseconds.
   int ReceiveDelay() const;
 
+  void SetExpectedRenderDelay(int delay_ms);
+
   void SetRTCPMode(const RtcpMode rtcp_mode);
   void SetProtectionMode(bool enable_nack,
                          bool enable_fec,
diff --git a/webrtc/video_decoder.h b/webrtc/video_decoder.h
index 3d04104..30e2779 100644
--- a/webrtc/video_decoder.h
+++ b/webrtc/video_decoder.h
@@ -73,6 +73,11 @@
 
   virtual int32_t Release() = 0;
   virtual int32_t Reset() = 0;
+
+  // Returns true if the decoder prefer to decode frames late.
+  // That is, it can not decode infinite number of frames before the decoded
+  // frame is consumed.
+  virtual bool PrefersLateDecoding() const { return true; }
 };
 
 // Class used to wrap external VideoDecoders to provide a fallback option on
@@ -97,6 +102,7 @@
 
   int32_t Release() override;
   int32_t Reset() override;
+  bool PrefersLateDecoding() const override;
 
  private:
   bool InitFallbackDecoder();
diff --git a/webrtc/video_receive_stream.h b/webrtc/video_receive_stream.h
index 6be2c5a..cd1434c 100644
--- a/webrtc/video_receive_stream.h
+++ b/webrtc/video_receive_stream.h
@@ -43,15 +43,6 @@
     // Name of the decoded payload (such as VP8). Maps back to the depacketizer
     // used to unpack incoming packets.
     std::string payload_name;
-
-    // 'true' if the decoder handles rendering as well.
-    bool is_renderer = false;
-
-    // The expected delay for decoding and rendering, i.e. the frame will be
-    // delivered this many milliseconds, if possible, earlier than the ideal
-    // render time.
-    // Note: Ignored if 'renderer' is false.
-    int expected_delay_ms = 0;
   };
 
   struct Stats {