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

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: 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/single_thread_task_runner.h" 8 #include "base/single_thread_task_runner.h"
9 #include "base/strings/utf_string_conversions.h" 9 #include "base/strings/utf_string_conversions.h"
10 #include "base/synchronization/lock.h" 10 #include "base/synchronization/lock.h"
11 #include "base/thread_task_runner_handle.h" 11 #include "base/thread_task_runner_handle.h"
12 #include "base/timer/timer.h"
12 #include "content/common/media/media_stream_options.h" 13 #include "content/common/media/media_stream_options.h"
13 #include "content/renderer/media/media_stream_constraints_util.h" 14 #include "content/renderer/media/media_stream_constraints_util.h"
14 #include "content/renderer/media/media_stream_video_track.h" 15 #include "content/renderer/media/media_stream_video_track.h"
15 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" 16 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
16 17
17 namespace content { 18 namespace content {
18 19
20 namespace {
21 // The maximum number of milliseconds that should elapse since the last video
22 // frame was received, before requesting a refresh frame.
23 const int kRefreshIntervalMilliseconds = 1000;
24 } // namespace
25
19 // Simple help class used for receiving video frames on the IO-thread from a 26 // Simple help class used for receiving video frames on the IO-thread from a
20 // MediaStreamVideoTrack and forward the frames to a WebRtcVideoCapturerAdapter 27 // MediaStreamVideoTrack and forward the frames to a WebRtcVideoCapturerAdapter
21 // on libjingle's worker thread. WebRtcVideoCapturerAdapter implements a video 28 // on libjingle's worker thread. WebRtcVideoCapturerAdapter implements a video
22 // capturer for libjingle. 29 // capturer for libjingle.
23 class MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter 30 class MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter
24 : public base::RefCountedThreadSafe<WebRtcVideoSourceAdapter> { 31 : public base::RefCountedThreadSafe<WebRtcVideoSourceAdapter> {
25 public: 32 public:
26 WebRtcVideoSourceAdapter( 33 WebRtcVideoSourceAdapter(
27 const scoped_refptr<base::SingleThreadTaskRunner>& 34 const scoped_refptr<base::SingleThreadTaskRunner>&
28 libjingle_worker_thread, 35 libjingle_worker_thread,
29 const scoped_refptr<webrtc::VideoTrackSourceInterface>& source, 36 const scoped_refptr<webrtc::VideoTrackSourceInterface>& source,
30 WebRtcVideoCapturerAdapter* capture_adapter); 37 WebRtcVideoCapturerAdapter* capture_adapter,
38 base::WeakPtr<MediaStreamVideoWebRtcSink> sink);
31 39
32 // MediaStreamVideoWebRtcSink can be destroyed on the main render thread or 40 // MediaStreamVideoWebRtcSink can be destroyed on the main render thread or
33 // libjingles worker thread since it posts video frames on that thread. But 41 // 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 42 // |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 43 // PeerConnectionFactory has been destroyed. The only way to ensure that is to
36 // make sure |video_source_| is released when MediaStreamVideoWebRtcSink() is 44 // make sure |video_source_| is released when MediaStreamVideoWebRtcSink() is
37 // destroyed. 45 // destroyed.
38 void ReleaseSourceOnMainThread(); 46 void ReleaseSourceOnMainThread();
39 47
40 void OnVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame, 48 void OnVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
41 base::TimeTicks estimated_capture_time); 49 base::TimeTicks estimated_capture_time);
42 50
43 private: 51 private:
44 void OnVideoFrameOnWorkerThread( 52 void OnVideoFrameOnWorkerThread(
45 const scoped_refptr<media::VideoFrame>& frame); 53 const scoped_refptr<media::VideoFrame>& frame);
46 friend class base::RefCountedThreadSafe<WebRtcVideoSourceAdapter>; 54 friend class base::RefCountedThreadSafe<WebRtcVideoSourceAdapter>;
47 virtual ~WebRtcVideoSourceAdapter(); 55 virtual ~WebRtcVideoSourceAdapter();
48 56
57 // Called whenever a video frame was just delivered on the IO thread. This
58 // restarts the delay period before the |refresh_timer_| will fire the next
59 // time.
60 void ResetRefreshTimerOnMainThread();
61
49 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; 62 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_;
50 63
51 // |render_thread_checker_| is bound to the main render thread. 64 // |render_thread_checker_| is bound to the main render thread.
52 base::ThreadChecker render_thread_checker_; 65 base::ThreadChecker render_thread_checker_;
53 // Used to DCHECK that frames are called on the IO-thread. 66 // Used to DCHECK that frames are called on the IO-thread.
54 base::ThreadChecker io_thread_checker_; 67 base::ThreadChecker io_thread_checker_;
55 68
56 // Used for posting frames to libjingle's worker thread. Accessed on the 69 // Used for posting frames to libjingle's worker thread. Accessed on the
57 // IO-thread. 70 // IO-thread.
58 scoped_refptr<base::SingleThreadTaskRunner> libjingle_worker_thread_; 71 scoped_refptr<base::SingleThreadTaskRunner> libjingle_worker_thread_;
59 72
60 scoped_refptr<webrtc::VideoTrackSourceInterface> video_source_; 73 scoped_refptr<webrtc::VideoTrackSourceInterface> video_source_;
61 74
62 // Used to protect |capture_adapter_|. It is taken by libjingle's worker 75 // 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 76 // thread for each video frame that is delivered but only taken on the
64 // main render thread in ReleaseSourceOnMainThread() when 77 // main render thread in ReleaseSourceOnMainThread() when
65 // the owning MediaStreamVideoWebRtcSink is being destroyed. 78 // the owning MediaStreamVideoWebRtcSink is being destroyed.
66 base::Lock capture_adapter_stop_lock_; 79 base::Lock capture_adapter_stop_lock_;
67 // |capture_adapter_| is owned by |video_source_| 80 // |capture_adapter_| is owned by |video_source_|
68 WebRtcVideoCapturerAdapter* capture_adapter_; 81 WebRtcVideoCapturerAdapter* capture_adapter_;
82
83 // Requests a refresh frame once per second. The delay on this timer is reset
84 // each time a frame is received so that it will not fire for at least an
85 // additional second. This means refresh frames will only be requested when
86 // the source has halted delivery (e.g., a screen capturer stops sending
87 // frames because the screen is not being updated).
88 //
89 // This mechanism solves a number of problems. First, it will ensure that
90 // remote clients that join a distributed session receive a first video frame
91 // in a timely manner. Second, it will allow WebRTC's internal bandwidth
92 // estimation logic to maintain a more optimal state, since sending a video
93 // frame will "prime it." Third, it allows lossy encoders to clean up
94 // artifacts in a still image. http://crbug.com/486274
95 base::RepeatingTimer refresh_timer_;
69 }; 96 };
70 97
71 MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::WebRtcVideoSourceAdapter( 98 MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::WebRtcVideoSourceAdapter(
72 const scoped_refptr<base::SingleThreadTaskRunner>& libjingle_worker_thread, 99 const scoped_refptr<base::SingleThreadTaskRunner>& libjingle_worker_thread,
73 const scoped_refptr<webrtc::VideoTrackSourceInterface>& source, 100 const scoped_refptr<webrtc::VideoTrackSourceInterface>& source,
74 WebRtcVideoCapturerAdapter* capture_adapter) 101 WebRtcVideoCapturerAdapter* capture_adapter,
102 base::WeakPtr<MediaStreamVideoWebRtcSink> sink)
75 : render_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), 103 : render_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
76 libjingle_worker_thread_(libjingle_worker_thread), 104 libjingle_worker_thread_(libjingle_worker_thread),
77 video_source_(source), 105 video_source_(source),
78 capture_adapter_(capture_adapter) { 106 capture_adapter_(capture_adapter) {
79 io_thread_checker_.DetachFromThread(); 107 io_thread_checker_.DetachFromThread();
108 refresh_timer_.Start(
109 FROM_HERE,
110 base::TimeDelta::FromMilliseconds(kRefreshIntervalMilliseconds),
111 base::Bind(&MediaStreamVideoWebRtcSink::RequestRefreshFrame, sink));
emircan 2016/04/01 00:06:47 This logic doesn't fit to the spec descriptions of
miu 2016/04/01 23:24:27 Sorry, I had not considered the other video source
80 } 112 }
81 113
82 MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: 114 MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::
83 ~WebRtcVideoSourceAdapter() { 115 ~WebRtcVideoSourceAdapter() {
84 DVLOG(3) << "~WebRtcVideoSourceAdapter()"; 116 DVLOG(3) << "~WebRtcVideoSourceAdapter()";
85 DCHECK(!capture_adapter_); 117 DCHECK(!capture_adapter_);
86 // This object can be destroyed on the main render thread or libjingles worker 118 // 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 119 // 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 120 // 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_| 121 // been destroyed. The only way to ensure that is to make sure |video_source_|
90 // is released when MediaStreamVideoWebRtcSink() is destroyed. 122 // is released when MediaStreamVideoWebRtcSink() is destroyed.
91 } 123 }
92 124
93 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: 125 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::
126 ResetRefreshTimerOnMainThread() {
127 DCHECK(render_thread_checker_.CalledOnValidThread());
128 refresh_timer_.Reset();
129 }
130
131 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::
94 ReleaseSourceOnMainThread() { 132 ReleaseSourceOnMainThread() {
95 DCHECK(render_thread_checker_.CalledOnValidThread()); 133 DCHECK(render_thread_checker_.CalledOnValidThread());
96 // Since frames are posted to the worker thread, this object might be deleted 134 // 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 135 // on that thread. However, since |video_source_| was created on the render
98 // thread, it should be released on the render thread. 136 // thread, it should be released on the render thread.
99 base::AutoLock auto_lock(capture_adapter_stop_lock_); 137 base::AutoLock auto_lock(capture_adapter_stop_lock_);
100 // |video_source| owns |capture_adapter_|. 138 // |video_source| owns |capture_adapter_|.
101 capture_adapter_ = NULL; 139 capture_adapter_ = NULL;
102 video_source_ = NULL; 140 video_source_ = NULL;
103 } 141 }
104 142
105 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::OnVideoFrameOnIO( 143 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::OnVideoFrameOnIO(
106 const scoped_refptr<media::VideoFrame>& frame, 144 const scoped_refptr<media::VideoFrame>& frame,
107 base::TimeTicks estimated_capture_time) { 145 base::TimeTicks estimated_capture_time) {
108 DCHECK(io_thread_checker_.CalledOnValidThread()); 146 DCHECK(io_thread_checker_.CalledOnValidThread());
147 render_thread_task_runner_->PostTask(
148 FROM_HERE,
149 base::Bind(&WebRtcVideoSourceAdapter::ResetRefreshTimerOnMainThread,
150 this));
109 libjingle_worker_thread_->PostTask( 151 libjingle_worker_thread_->PostTask(
110 FROM_HERE, 152 FROM_HERE,
111 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread, 153 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread,
112 this, 154 this,
113 frame)); 155 frame));
114 } 156 }
115 157
116 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: 158 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::
117 OnVideoFrameOnWorkerThread(const scoped_refptr<media::VideoFrame>& frame) { 159 OnVideoFrameOnWorkerThread(const scoped_refptr<media::VideoFrame>& frame) {
118 DCHECK(libjingle_worker_thread_->BelongsToCurrentThread()); 160 DCHECK(libjingle_worker_thread_->BelongsToCurrentThread());
119 base::AutoLock auto_lock(capture_adapter_stop_lock_); 161 base::AutoLock auto_lock(capture_adapter_stop_lock_);
120 if (capture_adapter_) 162 if (capture_adapter_)
121 capture_adapter_->OnFrameCaptured(frame); 163 capture_adapter_->OnFrameCaptured(frame);
122 } 164 }
123 165
124 MediaStreamVideoWebRtcSink::MediaStreamVideoWebRtcSink( 166 MediaStreamVideoWebRtcSink::MediaStreamVideoWebRtcSink(
125 const blink::WebMediaStreamTrack& track, 167 const blink::WebMediaStreamTrack& track,
126 PeerConnectionDependencyFactory* factory) 168 PeerConnectionDependencyFactory* factory)
127 : web_track_(track) { 169 : weak_factory_(this) {
128 const blink::WebMediaConstraints& constraints = 170 const blink::WebMediaConstraints& constraints =
129 MediaStreamVideoTrack::GetVideoTrack(track)->constraints(); 171 MediaStreamVideoTrack::GetVideoTrack(track)->constraints();
130 172
131 // Check for presence of mediaStreamSource constraint. The value is ignored. 173 // Check for presence of mediaStreamSource constraint. The value is ignored.
132 std::string value; 174 std::string value;
133 bool is_screencast = GetConstraintValueAsString( 175 bool is_screencast = GetConstraintValueAsString(
134 constraints, &blink::WebMediaTrackConstraintSet::mediaStreamSource, 176 constraints, &blink::WebMediaTrackConstraintSet::mediaStreamSource,
135 &value); 177 &value);
136 WebRtcVideoCapturerAdapter* capture_adapter = 178 WebRtcVideoCapturerAdapter* capture_adapter =
137 factory->CreateVideoCapturer(is_screencast); 179 factory->CreateVideoCapturer(is_screencast);
138 180
139 // |video_source| owns |capture_adapter| 181 // |video_source| owns |capture_adapter|
140 scoped_refptr<webrtc::VideoTrackSourceInterface> video_source( 182 scoped_refptr<webrtc::VideoTrackSourceInterface> video_source(
141 factory->CreateVideoSource(capture_adapter)); 183 factory->CreateVideoSource(capture_adapter));
142 184
143 video_track_ = factory->CreateLocalVideoTrack(web_track_.id().utf8(), 185 video_track_ = factory->CreateLocalVideoTrack(track.id().utf8(),
144 video_source.get()); 186 video_source.get());
145 187
146 video_track_->set_enabled(web_track_.isEnabled()); 188 video_track_->set_enabled(track.isEnabled());
147 189
148 source_adapter_ = new WebRtcVideoSourceAdapter( 190 source_adapter_ = new WebRtcVideoSourceAdapter(
149 factory->GetWebRtcWorkerThread(), 191 factory->GetWebRtcWorkerThread(),
150 video_source, 192 video_source,
151 capture_adapter); 193 capture_adapter,
194 weak_factory_.GetWeakPtr());
152 195
153 AddToVideoTrack( 196 MediaStreamVideoSink::ConnectToTrack(
154 this, 197 track,
155 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnIO, source_adapter_), 198 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnIO, source_adapter_));
156 web_track_);
157 199
158 DVLOG(3) << "MediaStreamVideoWebRtcSink ctor() : is_screencast " 200 DVLOG(3) << "MediaStreamVideoWebRtcSink ctor() : is_screencast "
159 << is_screencast; 201 << is_screencast;
160 } 202 }
161 203
162 MediaStreamVideoWebRtcSink::~MediaStreamVideoWebRtcSink() { 204 MediaStreamVideoWebRtcSink::~MediaStreamVideoWebRtcSink() {
163 DCHECK(thread_checker_.CalledOnValidThread()); 205 DCHECK(thread_checker_.CalledOnValidThread());
164 DVLOG(3) << "MediaStreamVideoWebRtcSink dtor()."; 206 DVLOG(3) << "MediaStreamVideoWebRtcSink dtor().";
165 RemoveFromVideoTrack(this, web_track_); 207 MediaStreamVideoSink::DisconnectFromTrack();
166 source_adapter_->ReleaseSourceOnMainThread(); 208 source_adapter_->ReleaseSourceOnMainThread();
167 } 209 }
168 210
169 void MediaStreamVideoWebRtcSink::OnEnabledChanged(bool enabled) { 211 void MediaStreamVideoWebRtcSink::OnEnabledChanged(bool enabled) {
170 DCHECK(thread_checker_.CalledOnValidThread()); 212 DCHECK(thread_checker_.CalledOnValidThread());
171 video_track_->set_enabled(enabled); 213 video_track_->set_enabled(enabled);
172 } 214 }
173 215
174 } // namespace content 216 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698