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

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

Powered by Google App Engine
This is Rietveld 408576698