Chromium Code Reviews| Index: content/renderer/media/webrtc/webrtc_video_source.cc |
| diff --git a/content/renderer/media/webrtc/webrtc_video_source.cc b/content/renderer/media/webrtc/webrtc_video_source.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..05c03cd2b33e1b67fa5c4ac91d68abd0f4d63ada |
| --- /dev/null |
| +++ b/content/renderer/media/webrtc/webrtc_video_source.cc |
| @@ -0,0 +1,153 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
|
Jói
2014/01/09 11:18:13
2014
|
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/renderer/media/webrtc/webrtc_video_source.h" |
| + |
| +#include "content/renderer/media/media_stream_video_track.h" |
| +#include "third_party/libjingle/source/talk/app/webrtc/remotevideocapturer.h" |
| +#include "third_party/libjingle/source/talk/app/webrtc/videotrackrenderers.h" |
| +#include "third_party/libjingle/source/talk/media/base/videoframe.h" |
| + |
| +namespace { |
| + |
| +class FrameInputWrapper : public cricket::VideoRenderer { |
| + public: |
| + explicit FrameInputWrapper(cricket::VideoCapturer* capturer) |
| + : capturer_(capturer) { |
| + ASSERT(capturer_ != NULL); |
| + } |
| + |
| + virtual ~FrameInputWrapper() {} |
| + |
| + // VideoRenderer implementation. |
| + virtual bool SetSize(int width, int height, int reserved) OVERRIDE { |
| + return true; |
| + } |
| + |
| + virtual bool RenderFrame(const cricket::VideoFrame* frame) OVERRIDE { |
| + if (!capturer_->IsRunning()) { |
| + return true; |
| + } |
| + |
| + // This signal will be made on media engine render thread. The clients |
| + // of this signal should have no assumptions on what thread this signal |
| + // come from. |
| + capturer_->SignalVideoFrame(capturer_, frame); |
| + return true; |
| + } |
| + |
| + private: |
| + cricket::VideoCapturer* capturer_; |
| + int width_; |
| + int height_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FrameInputWrapper); |
| +}; |
| + |
| +} // anonymous namespace |
| + |
| +namespace content { |
| + |
| +talk_base::scoped_refptr<WebRtcVideoSource> WebRtcVideoSource::Create() { |
| + talk_base::scoped_refptr<WebRtcVideoSource> source( |
| + new talk_base::RefCountedObject<WebRtcVideoSource>()); |
| + return source; |
| +} |
| + |
| +WebRtcVideoSource::WebRtcVideoSource() |
| + : video_capturer_(new webrtc::RemoteVideoCapturer()), |
| + // TODO(ronghuawu): Rename RemoteVideoCapturer to be more general purpose. |
| + // RemoteVideoCapturer is basically a fake video capturer that wraps a |
| + // video frame provider as a cricket::VideoCapturer. |
| + frame_input_(new FrameInputWrapper(video_capturer_.get())) { |
| + video_capturer_->SignalVideoFrame.connect( |
| + this, |
| + &WebRtcVideoSource::OnVideoFrame); |
| +} |
| + |
| +WebRtcVideoSource::~WebRtcVideoSource() { |
| + // Since the signal we're connecting to is multi-threaded, |
| + // disconnect_all() will block until all calls are serviced, meaning any |
| + // outstanding calls to OnVideoFrame will be done when this is done, and no |
| + // more calls will be serviced by this. |
| + // We do this explicitly instead of just letting the has_slots<> destructor |
| + // take care of it because we need to do this *before* sinks_ is |
| + // cleared by the destructor; otherwise we could mess with it while |
| + // OnVideoFrame is running. |
| + // We *don't* take sinks_crit_ here since it could deadlock with the lock |
| + // taken by the video frame signal. |
| + disconnect_all(); |
| +} |
| + |
| +cricket::VideoCapturer* WebRtcVideoSource::GetVideoCapturer() { |
| + return video_capturer_.get(); |
| +} |
| + |
| +void WebRtcVideoSource::AddSink(cricket::VideoRenderer* output) { |
| + if (!output) { |
| + return; |
| + } |
| + |
| + talk_base::CritScope cs(&sinks_crit_); |
| + sinks_.push_back(VideoSinkInfo(output)); |
| +} |
| + |
| +void WebRtcVideoSource::RemoveSink(cricket::VideoRenderer* output) { |
| + if (!output) { |
| + return; |
| + } |
| + |
| + talk_base::CritScope cs(&sinks_crit_); |
| + for (VideoSinks::iterator iter = sinks_.begin(); |
| + iter != sinks_.end(); ++iter) { |
| + if (output == iter->sink) { |
| + sinks_.erase(iter); |
| + break; |
| + } |
| + } |
| +} |
| + |
| +const cricket::VideoOptions* WebRtcVideoSource::options() const { |
| + return &options_; |
| +} |
| + |
| +webrtc::MediaSourceInterface::SourceState WebRtcVideoSource::state() const { |
| + // TODO(ronghuawu): Implement state. |
| + return state_; |
| +} |
| + |
| +cricket::VideoRenderer* WebRtcVideoSource::FrameInput() { |
| + return frame_input_.get(); |
| +} |
| + |
| +void WebRtcVideoSource::OnVideoFrame(cricket::VideoCapturer* capturer, |
| + const cricket::VideoFrame* video_frame) { |
| + talk_base::CritScope cs(&sinks_crit_); |
| + if (sinks_.empty()) { |
| + return; |
| + } |
| + MaybeSetSize(video_frame); |
| + for (VideoSinks::iterator iter = sinks_.begin(); |
| + iter != sinks_.end(); ++iter) { |
| + cricket::VideoRenderer* sink = iter->sink; |
| + sink->RenderFrame(video_frame); |
| + } |
| +} |
| + |
| +void WebRtcVideoSource::MaybeSetSize(const cricket::VideoFrame* frame) { |
| + for (VideoSinks::iterator iter = sinks_.begin(); |
| + iter != sinks_.end(); ++iter) { |
| + const bool new_resolution = iter->width != frame->GetWidth() || |
| + iter->height != frame->GetHeight(); |
| + if (new_resolution) { |
| + if (iter->sink->SetSize(static_cast<int>(frame->GetWidth()), |
| + static_cast<int>(frame->GetHeight()), 0)) { |
| + iter->width = frame->GetWidth(); |
| + iter->height = frame->GetHeight(); |
| + } |
| + } |
| + } |
| +} |
| + |
| +} // namespace content |