Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(657)

Side by Side Diff: content/renderer/media/webrtc/media_stream_video_webrtc_sink.cc

Issue 1849003002: Add video frame refresh to MediaStream and VideoCapture stacks. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed last round of comments from xjz and emircan. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/webrtc/media_stream_video_webrtc_sink.h" 5 #include "content/renderer/media/webrtc/media_stream_video_webrtc_sink.h"
6 6
7 #include "base/location.h" 7 #include "base/location.h"
8 #include "base/numerics/safe_conversions.h"
8 #include "base/single_thread_task_runner.h" 9 #include "base/single_thread_task_runner.h"
9 #include "base/strings/utf_string_conversions.h" 10 #include "base/strings/utf_string_conversions.h"
10 #include "base/synchronization/lock.h" 11 #include "base/synchronization/lock.h"
11 #include "base/thread_task_runner_handle.h" 12 #include "base/thread_task_runner_handle.h"
13 #include "base/timer/timer.h"
12 #include "content/common/media/media_stream_options.h" 14 #include "content/common/media/media_stream_options.h"
13 #include "content/renderer/media/media_stream_constraints_util.h" 15 #include "content/renderer/media/media_stream_constraints_util.h"
14 #include "content/renderer/media/media_stream_video_track.h" 16 #include "content/renderer/media/media_stream_video_track.h"
15 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" 17 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
18 #include "media/base/limits.h"
16 19
17 namespace content { 20 namespace content {
18 21
22 namespace {
23
24 // The default number of microseconds that should elapse since the last video
25 // frame was received, before requesting a refresh frame.
26 const int64_t kDefaultRefreshIntervalMicros =
27 base::Time::kMicrosecondsPerSecond;
28
29 // A lower-bound for the refresh interval.
30 const int64_t kLowerBoundRefreshIntervalMicros =
31 base::Time::kMicrosecondsPerSecond / media::limits::kMaxFramesPerSecond;
32
33 } // namespace
34
19 // Simple help class used for receiving video frames on the IO-thread from a 35 // Simple help class used for receiving video frames on the IO-thread from a
20 // MediaStreamVideoTrack and forward the frames to a WebRtcVideoCapturerAdapter 36 // MediaStreamVideoTrack and forward the frames to a WebRtcVideoCapturerAdapter
21 // on libjingle's worker thread. WebRtcVideoCapturerAdapter implements a video 37 // on libjingle's worker thread. WebRtcVideoCapturerAdapter implements a video
22 // capturer for libjingle. 38 // capturer for libjingle.
23 class MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter 39 class MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter
24 : public base::RefCountedThreadSafe<WebRtcVideoSourceAdapter> { 40 : public base::RefCountedThreadSafe<WebRtcVideoSourceAdapter> {
25 public: 41 public:
26 WebRtcVideoSourceAdapter( 42 WebRtcVideoSourceAdapter(
27 const scoped_refptr<base::SingleThreadTaskRunner>& 43 const scoped_refptr<base::SingleThreadTaskRunner>&
28 libjingle_worker_thread, 44 libjingle_worker_thread,
29 const scoped_refptr<webrtc::VideoTrackSourceInterface>& source, 45 const scoped_refptr<webrtc::VideoTrackSourceInterface>& source,
30 WebRtcVideoCapturerAdapter* capture_adapter); 46 WebRtcVideoCapturerAdapter* capture_adapter,
47 base::TimeDelta refresh_interval,
48 base::WeakPtr<MediaStreamVideoWebRtcSink> sink);
31 49
32 // MediaStreamVideoWebRtcSink can be destroyed on the main render thread or 50 // MediaStreamVideoWebRtcSink can be destroyed on the main render thread or
33 // libjingles worker thread since it posts video frames on that thread. But 51 // libjingles worker thread since it posts video frames on that thread. But
34 // |video_source_| must be released on the main render thread before the 52 // |video_source_| must be released on the main render thread before the
35 // PeerConnectionFactory has been destroyed. The only way to ensure that is to 53 // PeerConnectionFactory has been destroyed. The only way to ensure that is to
36 // make sure |video_source_| is released when MediaStreamVideoWebRtcSink() is 54 // make sure |video_source_| is released when MediaStreamVideoWebRtcSink() is
37 // destroyed. 55 // destroyed.
38 void ReleaseSourceOnMainThread(); 56 void ReleaseSourceOnMainThread();
39 57
40 void OnVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame, 58 void OnVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
41 base::TimeTicks estimated_capture_time); 59 base::TimeTicks estimated_capture_time);
42 60
43 private: 61 private:
44 void OnVideoFrameOnWorkerThread( 62 void OnVideoFrameOnWorkerThread(
45 const scoped_refptr<media::VideoFrame>& frame); 63 const scoped_refptr<media::VideoFrame>& frame);
46 friend class base::RefCountedThreadSafe<WebRtcVideoSourceAdapter>; 64 friend class base::RefCountedThreadSafe<WebRtcVideoSourceAdapter>;
47 virtual ~WebRtcVideoSourceAdapter(); 65 virtual ~WebRtcVideoSourceAdapter();
48 66
67 // Called whenever a video frame was just delivered on the IO thread. This
68 // restarts the delay period before the |refresh_timer_| will fire the next
69 // time.
70 void ResetRefreshTimerOnMainThread();
71
49 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; 72 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_;
50 73
51 // |render_thread_checker_| is bound to the main render thread. 74 // |render_thread_checker_| is bound to the main render thread.
52 base::ThreadChecker render_thread_checker_; 75 base::ThreadChecker render_thread_checker_;
53 // Used to DCHECK that frames are called on the IO-thread. 76 // Used to DCHECK that frames are called on the IO-thread.
54 base::ThreadChecker io_thread_checker_; 77 base::ThreadChecker io_thread_checker_;
55 78
56 // Used for posting frames to libjingle's worker thread. Accessed on the 79 // Used for posting frames to libjingle's worker thread. Accessed on the
57 // IO-thread. 80 // IO-thread.
58 scoped_refptr<base::SingleThreadTaskRunner> libjingle_worker_thread_; 81 scoped_refptr<base::SingleThreadTaskRunner> libjingle_worker_thread_;
59 82
60 scoped_refptr<webrtc::VideoTrackSourceInterface> video_source_; 83 scoped_refptr<webrtc::VideoTrackSourceInterface> video_source_;
61 84
62 // Used to protect |capture_adapter_|. It is taken by libjingle's worker 85 // Used to protect |capture_adapter_|. It is taken by libjingle's worker
63 // thread for each video frame that is delivered but only taken on the 86 // thread for each video frame that is delivered but only taken on the
64 // main render thread in ReleaseSourceOnMainThread() when 87 // main render thread in ReleaseSourceOnMainThread() when
65 // the owning MediaStreamVideoWebRtcSink is being destroyed. 88 // the owning MediaStreamVideoWebRtcSink is being destroyed.
66 base::Lock capture_adapter_stop_lock_; 89 base::Lock capture_adapter_stop_lock_;
67 // |capture_adapter_| is owned by |video_source_| 90 // |capture_adapter_| is owned by |video_source_|
68 WebRtcVideoCapturerAdapter* capture_adapter_; 91 WebRtcVideoCapturerAdapter* capture_adapter_;
92
93 // Requests a refresh frame at regular intervals. The delay on this timer is
94 // reset each time a frame is received so that it will not fire for at least
95 // an additional period. This means refresh frames will only be requested when
96 // the source has halted delivery (e.g., a screen capturer stops sending
97 // frames because the screen is not being updated).
98 //
99 // This mechanism solves a number of problems. First, it will ensure that
100 // remote clients that join a distributed session receive a first video frame
101 // in a timely manner. Second, it will allow WebRTC's internal bandwidth
102 // estimation logic to maintain a more optimal state, since sending a video
103 // frame will "prime it." Third, it allows lossy encoders to clean up
104 // artifacts in a still image. http://crbug.com/486274
105 base::RepeatingTimer refresh_timer_;
69 }; 106 };
70 107
71 MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::WebRtcVideoSourceAdapter( 108 MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::WebRtcVideoSourceAdapter(
72 const scoped_refptr<base::SingleThreadTaskRunner>& libjingle_worker_thread, 109 const scoped_refptr<base::SingleThreadTaskRunner>& libjingle_worker_thread,
73 const scoped_refptr<webrtc::VideoTrackSourceInterface>& source, 110 const scoped_refptr<webrtc::VideoTrackSourceInterface>& source,
74 WebRtcVideoCapturerAdapter* capture_adapter) 111 WebRtcVideoCapturerAdapter* capture_adapter,
112 base::TimeDelta refresh_interval,
113 base::WeakPtr<MediaStreamVideoWebRtcSink> sink)
75 : render_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), 114 : render_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
76 libjingle_worker_thread_(libjingle_worker_thread), 115 libjingle_worker_thread_(libjingle_worker_thread),
77 video_source_(source), 116 video_source_(source),
78 capture_adapter_(capture_adapter) { 117 capture_adapter_(capture_adapter) {
79 io_thread_checker_.DetachFromThread(); 118 io_thread_checker_.DetachFromThread();
119 if (!refresh_interval.is_zero()) {
120 VLOG(1) << "Starting frame refresh timer with interval "
mcasas 2016/04/05 23:12:52 s/VLOG/DVLOG/, right?
miu 2016/04/06 00:03:18 For the time being, I wanted to leave it as a VLOG
121 << refresh_interval.InMillisecondsF() << " ms.";
122 refresh_timer_.Start(
123 FROM_HERE, refresh_interval,
124 base::Bind(&MediaStreamVideoWebRtcSink::RequestRefreshFrame, sink));
125 }
80 } 126 }
81 127
82 MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: 128 MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::
83 ~WebRtcVideoSourceAdapter() { 129 ~WebRtcVideoSourceAdapter() {
84 DVLOG(3) << "~WebRtcVideoSourceAdapter()"; 130 DVLOG(3) << "~WebRtcVideoSourceAdapter()";
85 DCHECK(!capture_adapter_); 131 DCHECK(!capture_adapter_);
86 // This object can be destroyed on the main render thread or libjingles worker 132 // This object can be destroyed on the main render thread or libjingles worker
87 // thread since it posts video frames on that thread. But |video_source_| must 133 // thread since it posts video frames on that thread. But |video_source_| must
88 // be released on the main render thread before the PeerConnectionFactory has 134 // be released on the main render thread before the PeerConnectionFactory has
89 // been destroyed. The only way to ensure that is to make sure |video_source_| 135 // been destroyed. The only way to ensure that is to make sure |video_source_|
90 // is released when MediaStreamVideoWebRtcSink() is destroyed. 136 // is released when MediaStreamVideoWebRtcSink() is destroyed.
91 } 137 }
92 138
93 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: 139 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::
140 ResetRefreshTimerOnMainThread() {
141 DCHECK(render_thread_checker_.CalledOnValidThread());
142 if (refresh_timer_.IsRunning())
143 refresh_timer_.Reset();
144 }
145
146 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::
94 ReleaseSourceOnMainThread() { 147 ReleaseSourceOnMainThread() {
95 DCHECK(render_thread_checker_.CalledOnValidThread()); 148 DCHECK(render_thread_checker_.CalledOnValidThread());
96 // Since frames are posted to the worker thread, this object might be deleted 149 // Since frames are posted to the worker thread, this object might be deleted
97 // on that thread. However, since |video_source_| was created on the render 150 // on that thread. However, since |video_source_| was created on the render
98 // thread, it should be released on the render thread. 151 // thread, it should be released on the render thread.
99 base::AutoLock auto_lock(capture_adapter_stop_lock_); 152 base::AutoLock auto_lock(capture_adapter_stop_lock_);
100 // |video_source| owns |capture_adapter_|. 153 // |video_source| owns |capture_adapter_|.
101 capture_adapter_ = NULL; 154 capture_adapter_ = NULL;
102 video_source_ = NULL; 155 video_source_ = NULL;
103 } 156 }
104 157
105 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::OnVideoFrameOnIO( 158 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::OnVideoFrameOnIO(
106 const scoped_refptr<media::VideoFrame>& frame, 159 const scoped_refptr<media::VideoFrame>& frame,
107 base::TimeTicks estimated_capture_time) { 160 base::TimeTicks estimated_capture_time) {
108 DCHECK(io_thread_checker_.CalledOnValidThread()); 161 DCHECK(io_thread_checker_.CalledOnValidThread());
162 render_thread_task_runner_->PostTask(
163 FROM_HERE,
164 base::Bind(&WebRtcVideoSourceAdapter::ResetRefreshTimerOnMainThread,
165 this));
109 libjingle_worker_thread_->PostTask( 166 libjingle_worker_thread_->PostTask(
110 FROM_HERE, 167 FROM_HERE,
111 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread, 168 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread,
112 this, 169 this,
113 frame)); 170 frame));
114 } 171 }
115 172
116 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: 173 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::
117 OnVideoFrameOnWorkerThread(const scoped_refptr<media::VideoFrame>& frame) { 174 OnVideoFrameOnWorkerThread(const scoped_refptr<media::VideoFrame>& frame) {
118 DCHECK(libjingle_worker_thread_->BelongsToCurrentThread()); 175 DCHECK(libjingle_worker_thread_->BelongsToCurrentThread());
119 base::AutoLock auto_lock(capture_adapter_stop_lock_); 176 base::AutoLock auto_lock(capture_adapter_stop_lock_);
120 if (capture_adapter_) 177 if (capture_adapter_)
121 capture_adapter_->OnFrameCaptured(frame); 178 capture_adapter_->OnFrameCaptured(frame);
122 } 179 }
123 180
124 MediaStreamVideoWebRtcSink::MediaStreamVideoWebRtcSink( 181 MediaStreamVideoWebRtcSink::MediaStreamVideoWebRtcSink(
125 const blink::WebMediaStreamTrack& track, 182 const blink::WebMediaStreamTrack& track,
126 PeerConnectionDependencyFactory* factory) 183 PeerConnectionDependencyFactory* factory)
127 : web_track_(track) { 184 : weak_factory_(this) {
128 const blink::WebMediaConstraints& constraints = 185 const blink::WebMediaConstraints& constraints =
129 MediaStreamVideoTrack::GetVideoTrack(track)->constraints(); 186 MediaStreamVideoTrack::GetVideoTrack(track)->constraints();
130 187
131 // Check for presence of mediaStreamSource constraint. The value is ignored. 188 // Check for presence of mediaStreamSource constraint. The value is ignored.
132 std::string value; 189 std::string value;
133 bool is_screencast = GetConstraintValueAsString( 190 bool is_screencast = GetConstraintValueAsString(
134 constraints, &blink::WebMediaTrackConstraintSet::mediaStreamSource, 191 constraints, &blink::WebMediaTrackConstraintSet::mediaStreamSource,
135 &value); 192 &value);
193
194 // Enable automatic frame refreshes for the screen capture sources, which will
195 // stop producing frames whenever screen content is not changing. Check the
196 // frameRate constraint to determine the rate of refreshes. If a minimum
197 // frameRate is provided, use that. Otherwise, use the maximum frameRate if it
198 // happens to be less than the default.
199 base::TimeDelta refresh_interval = base::TimeDelta::FromMicroseconds(0);
200 if (is_screencast) {
mcasas 2016/04/05 23:12:52 if (!is_screencast) return; // ...
miu 2016/04/06 00:03:18 I can't return early here. All the code after L22
201 // Start with the default refresh interval, and refine based on constraints.
202 refresh_interval =
203 base::TimeDelta::FromMicroseconds(kDefaultRefreshIntervalMicros);
204 double value = 0.0;
205 if (GetConstraintMinAsDouble(
206 constraints, &blink::WebMediaTrackConstraintSet::frameRate,
207 &value) &&
208 value > 0.0) {
209 refresh_interval =
210 base::TimeDelta::FromMicroseconds(base::saturated_cast<int64_t>(
211 base::Time::kMicrosecondsPerSecond / value));
212 }
213 if (GetConstraintMaxAsDouble(
214 constraints, &blink::WebMediaTrackConstraintSet::frameRate,
215 &value) &&
216 value > 0.0) {
217 const base::TimeDelta alternate_refresh_interval =
218 base::TimeDelta::FromMicroseconds(base::saturated_cast<int64_t>(
219 base::Time::kMicrosecondsPerSecond / value));
220 refresh_interval = std::max(refresh_interval, alternate_refresh_interval);
221 }
222 if (refresh_interval.InMicroseconds() < kLowerBoundRefreshIntervalMicros) {
223 refresh_interval =
224 base::TimeDelta::FromMicroseconds(kLowerBoundRefreshIntervalMicros);
225 }
226 }
227
136 WebRtcVideoCapturerAdapter* capture_adapter = 228 WebRtcVideoCapturerAdapter* capture_adapter =
137 factory->CreateVideoCapturer(is_screencast); 229 factory->CreateVideoCapturer(is_screencast);
138 230
139 // |video_source| owns |capture_adapter| 231 // |video_source| owns |capture_adapter|
140 scoped_refptr<webrtc::VideoTrackSourceInterface> video_source( 232 scoped_refptr<webrtc::VideoTrackSourceInterface> video_source(
141 factory->CreateVideoSource(capture_adapter)); 233 factory->CreateVideoSource(capture_adapter));
142 234
143 video_track_ = factory->CreateLocalVideoTrack(web_track_.id().utf8(), 235 video_track_ = factory->CreateLocalVideoTrack(track.id().utf8(),
144 video_source.get()); 236 video_source.get());
145 237
146 video_track_->set_enabled(web_track_.isEnabled()); 238 video_track_->set_enabled(track.isEnabled());
147 239
148 source_adapter_ = new WebRtcVideoSourceAdapter( 240 source_adapter_ = new WebRtcVideoSourceAdapter(
149 factory->GetWebRtcWorkerThread(), 241 factory->GetWebRtcWorkerThread(),
150 video_source, 242 video_source,
151 capture_adapter); 243 capture_adapter,
244 refresh_interval,
245 weak_factory_.GetWeakPtr());
152 246
153 AddToVideoTrack( 247 MediaStreamVideoSink::ConnectToTrack(
154 this, 248 track,
155 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnIO, source_adapter_), 249 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnIO, source_adapter_));
156 web_track_);
157 250
158 DVLOG(3) << "MediaStreamVideoWebRtcSink ctor() : is_screencast " 251 DVLOG(3) << "MediaStreamVideoWebRtcSink ctor() : is_screencast "
159 << is_screencast; 252 << is_screencast;
160 } 253 }
161 254
162 MediaStreamVideoWebRtcSink::~MediaStreamVideoWebRtcSink() { 255 MediaStreamVideoWebRtcSink::~MediaStreamVideoWebRtcSink() {
163 DCHECK(thread_checker_.CalledOnValidThread()); 256 DCHECK(thread_checker_.CalledOnValidThread());
164 DVLOG(3) << "MediaStreamVideoWebRtcSink dtor()."; 257 DVLOG(3) << "MediaStreamVideoWebRtcSink dtor().";
165 RemoveFromVideoTrack(this, web_track_); 258 MediaStreamVideoSink::DisconnectFromTrack();
166 source_adapter_->ReleaseSourceOnMainThread(); 259 source_adapter_->ReleaseSourceOnMainThread();
167 } 260 }
168 261
169 void MediaStreamVideoWebRtcSink::OnEnabledChanged(bool enabled) { 262 void MediaStreamVideoWebRtcSink::OnEnabledChanged(bool enabled) {
170 DCHECK(thread_checker_.CalledOnValidThread()); 263 DCHECK(thread_checker_.CalledOnValidThread());
171 video_track_->set_enabled(enabled); 264 video_track_->set_enabled(enabled);
172 } 265 }
173 266
174 } // namespace content 267 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698