| Index: webrtc/video/video_receive_stream.cc
 | 
| diff --git a/webrtc/video/video_receive_stream.cc b/webrtc/video/video_receive_stream.cc
 | 
| index 9909e29c433b394da8ed2b9ca18b51442e4ddb5e..92f84a0cb8e0d82eede9df651d927a383ccc0a70 100644
 | 
| --- a/webrtc/video/video_receive_stream.cc
 | 
| +++ b/webrtc/video/video_receive_stream.cc
 | 
| @@ -144,6 +144,32 @@ VideoCodec CreateDecoderVideoCodec(const VideoReceiveStream::Decoder& decoder) {
 | 
|  }  // namespace
 | 
|  
 | 
|  namespace internal {
 | 
| +
 | 
| +// Since an IncomingVideoStream instance will create a thread/queue, we don't
 | 
| +// instantiate one unless we know we're going to be delivering the frames
 | 
| +// to a renderer.
 | 
| +//
 | 
| +// TODO(tommi): Consider making the functionality provided by the
 | 
| +// IncomingVideoStream classes, tied to the Config class instead or even higher
 | 
| +// level.  That will make it an optional feature that will be up to the
 | 
| +// application to use or not use.  Right now, we have two classes available,
 | 
| +// they both have threads involved which uses WebRTC's threading classes and
 | 
| +// that might not suit what the application wants to do.  If one of them or
 | 
| +// neither, suits, the app can get some code size back as well as more control.
 | 
| +std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>
 | 
| +MaybeCreateIncomingVideoStream(const VideoReceiveStream::Config& config,
 | 
| +                               rtc::VideoSinkInterface<VideoFrame>* callback) {
 | 
| +  std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> ret;
 | 
| +  if (config.renderer) {
 | 
| +    if (config.disable_prerenderer_smoothing) {
 | 
| +      ret.reset(new IncomingVideoStreamNoSmoothing(callback));
 | 
| +    } else {
 | 
| +      ret.reset(new IncomingVideoStream(config.render_delay_ms, callback));
 | 
| +    }
 | 
| +  }
 | 
| +  return ret;
 | 
| +}
 | 
| +
 | 
|  VideoReceiveStream::VideoReceiveStream(
 | 
|      int num_cpu_cores,
 | 
|      CongestionController* congestion_controller,
 | 
| @@ -160,7 +186,6 @@ VideoReceiveStream::VideoReceiveStream(
 | 
|        congestion_controller_(congestion_controller),
 | 
|        call_stats_(call_stats),
 | 
|        video_receiver_(clock_, nullptr, this, this, this),
 | 
| -      incoming_video_stream_(config_.disable_prerenderer_smoothing),
 | 
|        stats_proxy_(&config_, clock_),
 | 
|        rtp_stream_receiver_(&video_receiver_,
 | 
|                             congestion_controller_->GetRemoteBitrateEstimator(
 | 
| @@ -173,14 +198,6 @@ VideoReceiveStream::VideoReceiveStream(
 | 
|                             &config_,
 | 
|                             &stats_proxy_,
 | 
|                             process_thread_),
 | 
| -      video_stream_decoder_(&video_receiver_,
 | 
| -                            &rtp_stream_receiver_,
 | 
| -                            &rtp_stream_receiver_,
 | 
| -                            rtp_stream_receiver_.IsRetransmissionsEnabled(),
 | 
| -                            rtp_stream_receiver_.IsFecEnabled(),
 | 
| -                            &stats_proxy_,
 | 
| -                            &incoming_video_stream_,
 | 
| -                            config.pre_render_callback),
 | 
|        vie_sync_(&video_receiver_) {
 | 
|    LOG(LS_INFO) << "VideoReceiveStream: " << config_.ToString();
 | 
|  
 | 
| @@ -188,9 +205,6 @@ VideoReceiveStream::VideoReceiveStream(
 | 
|    RTC_DCHECK(congestion_controller_);
 | 
|    RTC_DCHECK(call_stats_);
 | 
|  
 | 
| -  // Register the channel to receive stats updates.
 | 
| -  call_stats_->RegisterStatsObserver(&video_stream_decoder_);
 | 
| -
 | 
|    RTC_DCHECK(!config_.decoders.empty());
 | 
|    std::set<int> decoder_payload_types;
 | 
|    for (const Decoder& decoder : config_.decoders) {
 | 
| @@ -210,8 +224,6 @@ VideoReceiveStream::VideoReceiveStream(
 | 
|    }
 | 
|  
 | 
|    video_receiver_.SetRenderDelay(config.render_delay_ms);
 | 
| -  incoming_video_stream_.SetExpectedRenderDelay(config.render_delay_ms);
 | 
| -  incoming_video_stream_.SetExternalCallback(this);
 | 
|  
 | 
|    process_thread_->RegisterModule(&video_receiver_);
 | 
|    process_thread_->RegisterModule(&vie_sync_);
 | 
| @@ -231,8 +243,6 @@ VideoReceiveStream::~VideoReceiveStream() {
 | 
|    for (const Decoder& decoder : config_.decoders)
 | 
|      video_receiver_.RegisterExternalDecoder(nullptr, decoder.payload_type);
 | 
|  
 | 
| -  call_stats_->DeregisterStatsObserver(&video_stream_decoder_);
 | 
| -
 | 
|    congestion_controller_->GetRemoteBitrateEstimator(UseSendSideBwe(config_))
 | 
|        ->RemoveStream(rtp_stream_receiver_.GetRemoteSsrc());
 | 
|  }
 | 
| @@ -256,7 +266,14 @@ void VideoReceiveStream::Start() {
 | 
|    if (decode_thread_.IsRunning())
 | 
|      return;
 | 
|    transport_adapter_.Enable();
 | 
| -  incoming_video_stream_.Start();
 | 
| +  incoming_video_stream_ = MaybeCreateIncomingVideoStream(config_, this);
 | 
| +  video_stream_decoder_.reset(new VideoStreamDecoder(
 | 
| +      &video_receiver_, &rtp_stream_receiver_, &rtp_stream_receiver_,
 | 
| +      rtp_stream_receiver_.IsRetransmissionsEnabled(),
 | 
| +      rtp_stream_receiver_.IsFecEnabled(), &stats_proxy_,
 | 
| +      incoming_video_stream_.get(), config_.pre_render_callback));
 | 
| +  // Register the channel to receive stats updates.
 | 
| +  call_stats_->RegisterStatsObserver(video_stream_decoder_.get());
 | 
|    // Start the decode thread
 | 
|    decode_thread_.Start();
 | 
|    decode_thread_.SetPriority(rtc::kHighestPriority);
 | 
| @@ -264,10 +281,12 @@ void VideoReceiveStream::Start() {
 | 
|  }
 | 
|  
 | 
|  void VideoReceiveStream::Stop() {
 | 
| -  incoming_video_stream_.Stop();
 | 
|    rtp_stream_receiver_.StopReceive();
 | 
|    video_receiver_.TriggerDecoderShutdown();
 | 
|    decode_thread_.Stop();
 | 
| +  call_stats_->DeregisterStatsObserver(video_stream_decoder_.get());
 | 
| +  video_stream_decoder_.reset();
 | 
| +  incoming_video_stream_.reset();
 | 
|    transport_adapter_.Disable();
 | 
|  }
 | 
|  
 | 
| @@ -289,16 +308,26 @@ VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
 | 
|    return stats_proxy_.GetStats();
 | 
|  }
 | 
|  
 | 
| +// TODO(tommi): This method grabs a lock 6 times.
 | 
|  void VideoReceiveStream::OnFrame(const VideoFrame& video_frame) {
 | 
| +  // TODO(tommi): OnDecodedFrame grabs a lock, incidentally the same lock
 | 
| +  // that OnSyncOffsetUpdated() and OnRenderedFrame() below grab.
 | 
|    stats_proxy_.OnDecodedFrame();
 | 
|  
 | 
|    int64_t sync_offset_ms;
 | 
| -  if (vie_sync_.GetStreamSyncOffsetInMs(video_frame, &sync_offset_ms))
 | 
| +  // TODO(tommi): GetStreamSyncOffsetInMs grabs three locks.  One inside the
 | 
| +  // function itself, another in GetChannel() and a third in
 | 
| +  // GetPlayoutTimestamp.  Seems excessive.  Anyhow, I'm assuming the function
 | 
| +  // succeeds most of the time, which leads to grabbing a fourth lock.
 | 
| +  if (vie_sync_.GetStreamSyncOffsetInMs(video_frame, &sync_offset_ms)) {
 | 
| +    // TODO(tommi): OnSyncOffsetUpdated grabs a lock.
 | 
|      stats_proxy_.OnSyncOffsetUpdated(sync_offset_ms);
 | 
| +  }
 | 
|  
 | 
| -  if (config_.renderer)
 | 
| -    config_.renderer->OnFrame(video_frame);
 | 
| +  // config_.renderer must never be null if we're getting this callback.
 | 
| +  config_.renderer->OnFrame(video_frame);
 | 
|  
 | 
| +  // TODO(tommi): OnRenderFrame grabs a lock too.
 | 
|    stats_proxy_.OnRenderedFrame(video_frame.width(), video_frame.height());
 | 
|  }
 | 
|  
 | 
| 
 |