| OLD | NEW |
| 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/numerics/safe_conversions.h" |
| 9 #include "base/single_thread_task_runner.h" | 9 #include "base/single_thread_task_runner.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 | 52 |
| 53 // The default number of microseconds that should elapse since the last video | 53 // The default number of microseconds that should elapse since the last video |
| 54 // frame was received, before requesting a refresh frame. | 54 // frame was received, before requesting a refresh frame. |
| 55 const int64_t kDefaultRefreshIntervalMicros = | 55 const int64_t kDefaultRefreshIntervalMicros = |
| 56 base::Time::kMicrosecondsPerSecond; | 56 base::Time::kMicrosecondsPerSecond; |
| 57 | 57 |
| 58 // A lower-bound for the refresh interval. | 58 // A lower-bound for the refresh interval. |
| 59 const int64_t kLowerBoundRefreshIntervalMicros = | 59 const int64_t kLowerBoundRefreshIntervalMicros = |
| 60 base::Time::kMicrosecondsPerSecond / media::limits::kMaxFramesPerSecond; | 60 base::Time::kMicrosecondsPerSecond / media::limits::kMaxFramesPerSecond; |
| 61 | 61 |
| 62 webrtc::VideoTrackInterface::ContentHint ContentHintTypeToWebRtcContentHint( |
| 63 blink::WebMediaStreamTrack::ContentHintType content_hint) { |
| 64 switch (content_hint) { |
| 65 case blink::WebMediaStreamTrack::ContentHintType::None: |
| 66 return webrtc::VideoTrackInterface::ContentHint::kNone; |
| 67 case blink::WebMediaStreamTrack::ContentHintType::AudioSpeech: |
| 68 case blink::WebMediaStreamTrack::ContentHintType::AudioMusic: |
| 69 NOTREACHED(); |
| 70 break; |
| 71 case blink::WebMediaStreamTrack::ContentHintType::VideoFluid: |
| 72 return webrtc::VideoTrackInterface::ContentHint::kFluid; |
| 73 case blink::WebMediaStreamTrack::ContentHintType::VideoDetailed: |
| 74 return webrtc::VideoTrackInterface::ContentHint::kDetailed; |
| 75 } |
| 76 NOTREACHED(); |
| 77 return webrtc::VideoTrackInterface::ContentHint::kNone; |
| 78 } |
| 79 |
| 62 } // namespace | 80 } // namespace |
| 63 | 81 |
| 64 // Simple help class used for receiving video frames on the IO-thread from a | 82 // Simple help class used for receiving video frames on the IO-thread from a |
| 65 // MediaStreamVideoTrack and forward the frames to a WebRtcVideoCapturerAdapter | 83 // MediaStreamVideoTrack and forward the frames to a WebRtcVideoCapturerAdapter |
| 66 // on libjingle's worker thread. WebRtcVideoCapturerAdapter implements a video | 84 // on libjingle's worker thread. WebRtcVideoCapturerAdapter implements a video |
| 67 // capturer for libjingle. | 85 // capturer for libjingle. |
| 68 class MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter | 86 class MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter |
| 69 : public base::RefCountedThreadSafe<WebRtcVideoSourceAdapter> { | 87 : public base::RefCountedThreadSafe<WebRtcVideoSourceAdapter> { |
| 70 public: | 88 public: |
| 71 WebRtcVideoSourceAdapter(const scoped_refptr<base::SingleThreadTaskRunner>& | 89 WebRtcVideoSourceAdapter(const scoped_refptr<base::SingleThreadTaskRunner>& |
| 72 libjingle_worker_thread, | 90 libjingle_worker_thread, |
| 73 const scoped_refptr<WebRtcVideoSource>& source, | 91 const scoped_refptr<WebRtcVideoSource>& source, |
| 74 base::TimeDelta refresh_interval, | 92 base::TimeDelta refresh_interval, |
| 75 const base::Closure& refresh_callback); | 93 const base::Closure& refresh_callback); |
| 76 | 94 |
| 77 // MediaStreamVideoWebRtcSink can be destroyed on the main render thread or | 95 // MediaStreamVideoWebRtcSink can be destroyed on the main render thread or |
| 78 // libjingles worker thread since it posts video frames on that thread. But | 96 // libjingles worker thread since it posts video frames on that thread. But |
| 79 // |video_source_| must be released on the main render thread before the | 97 // |video_source_| must be released on the main render thread before the |
| 80 // PeerConnectionFactory has been destroyed. The only way to ensure that is to | 98 // PeerConnectionFactory has been destroyed. The only way to ensure that is to |
| 81 // make sure |video_source_| is released when MediaStreamVideoWebRtcSink() is | 99 // make sure |video_source_| is released when MediaStreamVideoWebRtcSink() is |
| 82 // destroyed. | 100 // destroyed. |
| 83 void ReleaseSourceOnMainThread(); | 101 void ReleaseSourceOnMainThread(); |
| 84 | 102 |
| 103 void SetContentHint(blink::WebMediaStreamTrack::ContentHintType content_hint); |
| 104 |
| 85 void OnVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame, | 105 void OnVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame, |
| 86 base::TimeTicks estimated_capture_time); | 106 base::TimeTicks estimated_capture_time); |
| 87 | 107 |
| 88 private: | 108 private: |
| 109 friend class base::RefCountedThreadSafe<WebRtcVideoSourceAdapter>; |
| 110 |
| 89 void OnVideoFrameOnWorkerThread( | 111 void OnVideoFrameOnWorkerThread( |
| 90 const scoped_refptr<media::VideoFrame>& frame); | 112 const scoped_refptr<media::VideoFrame>& frame); |
| 91 friend class base::RefCountedThreadSafe<WebRtcVideoSourceAdapter>; | 113 |
| 114 void SetContentHintOnWorkerThread( |
| 115 blink::WebMediaStreamTrack::ContentHintType content_hint); |
| 116 |
| 92 virtual ~WebRtcVideoSourceAdapter(); | 117 virtual ~WebRtcVideoSourceAdapter(); |
| 93 | 118 |
| 94 // Called whenever a video frame was just delivered on the IO thread. This | 119 // Called whenever a video frame was just delivered on the IO thread. This |
| 95 // restarts the delay period before the |refresh_timer_| will fire the next | 120 // restarts the delay period before the |refresh_timer_| will fire the next |
| 96 // time. | 121 // time. |
| 97 void ResetRefreshTimerOnMainThread(); | 122 void ResetRefreshTimerOnMainThread(); |
| 98 | 123 |
| 99 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; | 124 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; |
| 100 | 125 |
| 101 // |render_thread_checker_| is bound to the main render thread. | 126 // |render_thread_checker_| is bound to the main render thread. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 DVLOG(3) << "~WebRtcVideoSourceAdapter()"; | 179 DVLOG(3) << "~WebRtcVideoSourceAdapter()"; |
| 155 DCHECK(!capture_adapter_); | 180 DCHECK(!capture_adapter_); |
| 156 // This object can be destroyed on the main render thread or libjingles worker | 181 // This object can be destroyed on the main render thread or libjingles worker |
| 157 // thread since it posts video frames on that thread. But |video_source_| must | 182 // thread since it posts video frames on that thread. But |video_source_| must |
| 158 // be released on the main render thread before the PeerConnectionFactory has | 183 // be released on the main render thread before the PeerConnectionFactory has |
| 159 // been destroyed. The only way to ensure that is to make sure |video_source_| | 184 // been destroyed. The only way to ensure that is to make sure |video_source_| |
| 160 // is released when MediaStreamVideoWebRtcSink() is destroyed. | 185 // is released when MediaStreamVideoWebRtcSink() is destroyed. |
| 161 } | 186 } |
| 162 | 187 |
| 163 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: | 188 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: |
| 164 ResetRefreshTimerOnMainThread() { | 189 ResetRefreshTimerOnMainThread() { |
| 165 DCHECK(render_thread_checker_.CalledOnValidThread()); | 190 DCHECK(render_thread_checker_.CalledOnValidThread()); |
| 166 if (refresh_timer_.IsRunning()) | 191 if (refresh_timer_.IsRunning()) |
| 167 refresh_timer_.Reset(); | 192 refresh_timer_.Reset(); |
| 168 } | 193 } |
| 169 | 194 |
| 170 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: | 195 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: |
| 171 ReleaseSourceOnMainThread() { | 196 ReleaseSourceOnMainThread() { |
| 172 DCHECK(render_thread_checker_.CalledOnValidThread()); | 197 DCHECK(render_thread_checker_.CalledOnValidThread()); |
| 173 // Since frames are posted to the worker thread, this object might be deleted | 198 // Since frames are posted to the worker thread, this object might be deleted |
| 174 // on that thread. However, since |video_source_| was created on the render | 199 // on that thread. However, since |video_source_| was created on the render |
| 175 // thread, it should be released on the render thread. | 200 // thread, it should be released on the render thread. |
| 176 base::AutoLock auto_lock(capture_adapter_stop_lock_); | 201 base::AutoLock auto_lock(capture_adapter_stop_lock_); |
| 177 // |video_source| owns |capture_adapter_|. | 202 // |video_source| owns |capture_adapter_|. |
| 178 capture_adapter_ = NULL; | 203 capture_adapter_ = NULL; |
| 179 video_source_ = NULL; | 204 video_source_ = NULL; |
| 180 } | 205 } |
| 181 | 206 |
| 207 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::SetContentHint( |
| 208 blink::WebMediaStreamTrack::ContentHintType content_hint) { |
| 209 DCHECK(render_thread_checker_.CalledOnValidThread()); |
| 210 libjingle_worker_thread_->PostTask( |
| 211 FROM_HERE, |
| 212 base::Bind(&WebRtcVideoSourceAdapter::SetContentHintOnWorkerThread, this, |
| 213 content_hint)); |
| 214 } |
| 215 |
| 216 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter:: |
| 217 SetContentHintOnWorkerThread( |
| 218 blink::WebMediaStreamTrack::ContentHintType content_hint) { |
| 219 DCHECK(libjingle_worker_thread_->BelongsToCurrentThread()); |
| 220 base::AutoLock auto_lock(capture_adapter_stop_lock_); |
| 221 if (capture_adapter_) |
| 222 capture_adapter_->SetContentHint(content_hint); |
| 223 } |
| 224 |
| 182 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::OnVideoFrameOnIO( | 225 void MediaStreamVideoWebRtcSink::WebRtcVideoSourceAdapter::OnVideoFrameOnIO( |
| 183 const scoped_refptr<media::VideoFrame>& frame, | 226 const scoped_refptr<media::VideoFrame>& frame, |
| 184 base::TimeTicks estimated_capture_time) { | 227 base::TimeTicks estimated_capture_time) { |
| 185 DCHECK(io_thread_checker_.CalledOnValidThread()); | 228 DCHECK(io_thread_checker_.CalledOnValidThread()); |
| 186 render_thread_task_runner_->PostTask( | 229 render_thread_task_runner_->PostTask( |
| 187 FROM_HERE, | 230 FROM_HERE, |
| 188 base::Bind(&WebRtcVideoSourceAdapter::ResetRefreshTimerOnMainThread, | 231 base::Bind(&WebRtcVideoSourceAdapter::ResetRefreshTimerOnMainThread, |
| 189 this)); | 232 this)); |
| 190 libjingle_worker_thread_->PostTask( | 233 libjingle_worker_thread_->PostTask( |
| 191 FROM_HERE, | 234 FROM_HERE, |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 if (refresh_interval.InMicroseconds() < kLowerBoundRefreshIntervalMicros) { | 303 if (refresh_interval.InMicroseconds() < kLowerBoundRefreshIntervalMicros) { |
| 261 refresh_interval = | 304 refresh_interval = |
| 262 base::TimeDelta::FromMicroseconds(kLowerBoundRefreshIntervalMicros); | 305 base::TimeDelta::FromMicroseconds(kLowerBoundRefreshIntervalMicros); |
| 263 } | 306 } |
| 264 } | 307 } |
| 265 | 308 |
| 266 // TODO(pbos): Consolidate WebRtcVideoCapturerAdapter into WebRtcVideoSource | 309 // TODO(pbos): Consolidate WebRtcVideoCapturerAdapter into WebRtcVideoSource |
| 267 // by removing the need for and dependency on a cricket::VideoCapturer. | 310 // by removing the need for and dependency on a cricket::VideoCapturer. |
| 268 video_source_ = scoped_refptr<WebRtcVideoSource>( | 311 video_source_ = scoped_refptr<WebRtcVideoSource>( |
| 269 new rtc::RefCountedObject<WebRtcVideoSource>( | 312 new rtc::RefCountedObject<WebRtcVideoSource>( |
| 270 new WebRtcVideoCapturerAdapter(is_screencast), is_screencast, | 313 new WebRtcVideoCapturerAdapter(is_screencast, track.contentHint()), |
| 271 needs_denoising)); | 314 is_screencast, needs_denoising)); |
| 272 | 315 |
| 273 // TODO(pbos): Consolidate the local video track with the source proxy and | 316 // TODO(pbos): Consolidate the local video track with the source proxy and |
| 274 // move into PeerConnectionDependencyFactory. This now separately holds on a | 317 // move into PeerConnectionDependencyFactory. This now separately holds on a |
| 275 // reference to the proxy object because | 318 // reference to the proxy object because |
| 276 // PeerConnectionFactory::CreateVideoTrack doesn't do reference counting. | 319 // PeerConnectionFactory::CreateVideoTrack doesn't do reference counting. |
| 277 video_source_proxy_ = | 320 video_source_proxy_ = |
| 278 factory->CreateVideoTrackSourceProxy(video_source_.get()); | 321 factory->CreateVideoTrackSourceProxy(video_source_.get()); |
| 279 video_track_ = factory->CreateLocalVideoTrack(track.id().utf8(), | 322 video_track_ = factory->CreateLocalVideoTrack(track.id().utf8(), |
| 280 video_source_proxy_.get()); | 323 video_source_proxy_.get()); |
| 281 | 324 |
| 325 video_track_->set_content_hint( |
| 326 ContentHintTypeToWebRtcContentHint(track.contentHint())); |
| 282 video_track_->set_enabled(track.isEnabled()); | 327 video_track_->set_enabled(track.isEnabled()); |
| 283 | 328 |
| 284 source_adapter_ = new WebRtcVideoSourceAdapter( | 329 source_adapter_ = new WebRtcVideoSourceAdapter( |
| 285 factory->GetWebRtcWorkerThread(), video_source_.get(), refresh_interval, | 330 factory->GetWebRtcWorkerThread(), video_source_.get(), refresh_interval, |
| 286 base::Bind(&MediaStreamVideoWebRtcSink::RequestRefreshFrame, | 331 base::Bind(&MediaStreamVideoWebRtcSink::RequestRefreshFrame, |
| 287 weak_factory_.GetWeakPtr())); | 332 weak_factory_.GetWeakPtr())); |
| 288 | 333 |
| 289 MediaStreamVideoSink::ConnectToTrack( | 334 MediaStreamVideoSink::ConnectToTrack( |
| 290 track, | 335 track, |
| 291 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnIO, source_adapter_), | 336 base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnIO, source_adapter_), |
| 292 false); | 337 false); |
| 293 | 338 |
| 294 DVLOG(3) << "MediaStreamVideoWebRtcSink ctor() : is_screencast " | 339 DVLOG(3) << "MediaStreamVideoWebRtcSink ctor() : is_screencast " |
| 295 << is_screencast; | 340 << is_screencast; |
| 296 } | 341 } |
| 297 | 342 |
| 298 MediaStreamVideoWebRtcSink::~MediaStreamVideoWebRtcSink() { | 343 MediaStreamVideoWebRtcSink::~MediaStreamVideoWebRtcSink() { |
| 299 DCHECK(thread_checker_.CalledOnValidThread()); | 344 DCHECK(thread_checker_.CalledOnValidThread()); |
| 300 DVLOG(3) << "MediaStreamVideoWebRtcSink dtor()."; | 345 DVLOG(3) << "MediaStreamVideoWebRtcSink dtor()."; |
| 301 weak_factory_.InvalidateWeakPtrs(); | 346 weak_factory_.InvalidateWeakPtrs(); |
| 302 MediaStreamVideoSink::DisconnectFromTrack(); | 347 MediaStreamVideoSink::DisconnectFromTrack(); |
| 303 source_adapter_->ReleaseSourceOnMainThread(); | 348 source_adapter_->ReleaseSourceOnMainThread(); |
| 304 } | 349 } |
| 305 | 350 |
| 306 void MediaStreamVideoWebRtcSink::OnEnabledChanged(bool enabled) { | 351 void MediaStreamVideoWebRtcSink::OnEnabledChanged(bool enabled) { |
| 307 DCHECK(thread_checker_.CalledOnValidThread()); | 352 DCHECK(thread_checker_.CalledOnValidThread()); |
| 308 video_track_->set_enabled(enabled); | 353 video_track_->set_enabled(enabled); |
| 309 } | 354 } |
| 310 | 355 |
| 356 void MediaStreamVideoWebRtcSink::OnContentHintChanged( |
| 357 blink::WebMediaStreamTrack::ContentHintType content_hint) { |
| 358 DCHECK(thread_checker_.CalledOnValidThread()); |
| 359 source_adapter_->SetContentHint(content_hint); |
| 360 video_track_->set_content_hint( |
| 361 ContentHintTypeToWebRtcContentHint(content_hint)); |
| 362 } |
| 363 |
| 311 void MediaStreamVideoWebRtcSink::RequestRefreshFrame() { | 364 void MediaStreamVideoWebRtcSink::RequestRefreshFrame() { |
| 312 DCHECK(thread_checker_.CalledOnValidThread()); | 365 DCHECK(thread_checker_.CalledOnValidThread()); |
| 313 content::RequestRefreshFrameFromVideoTrack(connected_track()); | 366 content::RequestRefreshFrameFromVideoTrack(connected_track()); |
| 314 } | 367 } |
| 315 | 368 |
| 316 rtc::Optional<bool> MediaStreamVideoWebRtcSink::SourceNeedsDenoisingForTesting() | 369 rtc::Optional<bool> MediaStreamVideoWebRtcSink::SourceNeedsDenoisingForTesting() |
| 317 const { | 370 const { |
| 318 return video_source_->needs_denoising(); | 371 return video_source_->needs_denoising(); |
| 319 } | 372 } |
| 320 | 373 |
| 321 } // namespace content | 374 } // namespace content |
| OLD | NEW |