diff options
19 files changed, 569 insertions, 367 deletions
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 45dd77c..7250d83 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -690,6 +690,8 @@ 'renderer/media/video_source_handler.h', 'renderer/media/webaudio_capturer_source.cc', 'renderer/media/webaudio_capturer_source.h', + 'renderer/media/webrtc/media_stream_remote_video_source.cc', + 'renderer/media/webrtc/media_stream_remote_video_source.h', 'renderer/media/webrtc/media_stream_track_metrics.cc', 'renderer/media/webrtc/media_stream_track_metrics.h', 'renderer/media/webrtc/video_destination_handler.cc', @@ -700,8 +702,6 @@ 'renderer/media/webrtc/webrtc_local_audio_track_adapter.h', 'renderer/media/webrtc/webrtc_video_capturer_adapter.cc', 'renderer/media/webrtc/webrtc_video_capturer_adapter.h', - 'renderer/media/webrtc/webrtc_video_sink_adapter.cc', - 'renderer/media/webrtc/webrtc_video_sink_adapter.h', 'renderer/media/webrtc_audio_capturer.cc', 'renderer/media/webrtc_audio_capturer.h', 'renderer/media/webrtc_audio_device_impl.cc', diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 0d9efcc..d21aadf0 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -727,6 +727,7 @@ 'renderer/media/rtc_peer_connection_handler_unittest.cc', 'renderer/media/rtc_video_decoder_unittest.cc', 'renderer/media/video_source_handler_unittest.cc', + 'renderer/media/webrtc/media_stream_remote_video_source_unittest.cc', 'renderer/media/webrtc/media_stream_track_metrics_unittest.cc', 'renderer/media/webrtc/webrtc_local_audio_track_adapter_unittest.cc', 'renderer/media/webrtc/webrtc_video_capturer_adapter_unittest.cc', diff --git a/content/renderer/media/media_stream_center.cc b/content/renderer/media/media_stream_center.cc index 3318fbd..d7279c7 100644 --- a/content/renderer/media/media_stream_center.cc +++ b/content/renderer/media/media_stream_center.cc @@ -52,12 +52,7 @@ void CreateNativeVideoMediaStreamTrack( DCHECK_EQ(source.type(), blink::WebMediaStreamSource::TypeVideo); MediaStreamVideoSource* native_source = MediaStreamVideoSource::GetVideoSource(source); - if (!native_source) { - // TODO(perkj): Implement support for sources from - // remote MediaStreams. - NOTIMPLEMENTED(); - return; - } + DCHECK(native_source); blink::WebMediaStreamTrack writable_track(track); writable_track.setExtraData( new MediaStreamVideoTrack(native_source, source.constraints(), diff --git a/content/renderer/media/media_stream_dependency_factory.cc b/content/renderer/media/media_stream_dependency_factory.cc index fef5308..70f3d06 100644 --- a/content/renderer/media/media_stream_dependency_factory.cc +++ b/content/renderer/media/media_stream_dependency_factory.cc @@ -678,24 +678,20 @@ MediaStreamDependencyFactory::CreateAudioCapturer( GetWebRtcAudioDevice()); } -void MediaStreamDependencyFactory::AddNativeTrackToBlinkTrack( +void MediaStreamDependencyFactory::AddNativeAudioTrackToBlinkTrack( webrtc::MediaStreamTrackInterface* native_track, const blink::WebMediaStreamTrack& webkit_track, bool is_local_track) { DCHECK(!webkit_track.isNull() && !webkit_track.extraData()); + DCHECK_EQ(blink::WebMediaStreamSource::TypeAudio, + webkit_track.source().type()); blink::WebMediaStreamTrack track = webkit_track; - if (track.source().type() == blink::WebMediaStreamSource::TypeVideo) { - DVLOG(1) << "AddNativeTrackToBlinkTrack() video"; - track.setExtraData(new WebRtcMediaStreamVideoTrack( - static_cast<webrtc::VideoTrackInterface*>(native_track))); - } else { - DVLOG(1) << "AddNativeTrackToBlinkTrack() audio"; - track.setExtraData( - new MediaStreamTrack( - static_cast<webrtc::AudioTrackInterface*>(native_track), - is_local_track)); - } + DVLOG(1) << "AddNativeTrackToBlinkTrack() audio"; + track.setExtraData( + new MediaStreamTrack( + static_cast<webrtc::AudioTrackInterface*>(native_track), + is_local_track)); } bool MediaStreamDependencyFactory::OnControlMessageReceived( diff --git a/content/renderer/media/media_stream_dependency_factory.h b/content/renderer/media/media_stream_dependency_factory.h index accac97..5986abb 100644 --- a/content/renderer/media/media_stream_dependency_factory.h +++ b/content/renderer/media/media_stream_dependency_factory.h @@ -136,7 +136,7 @@ class CONTENT_EXPORT MediaStreamDependencyFactory WebRtcAudioDeviceImpl* GetWebRtcAudioDevice(); - static void AddNativeTrackToBlinkTrack( + static void AddNativeAudioTrackToBlinkTrack( webrtc::MediaStreamTrackInterface* native_track, const blink::WebMediaStreamTrack& webkit_track, bool is_local_track); diff --git a/content/renderer/media/media_stream_video_source.cc b/content/renderer/media/media_stream_video_source.cc index 6091726..51da6bb 100644 --- a/content/renderer/media/media_stream_video_source.cc +++ b/content/renderer/media/media_stream_video_source.cc @@ -308,7 +308,6 @@ MediaStreamVideoSource::MediaStreamVideoSource( : state_(NEW), factory_(factory), capture_adapter_(NULL) { - DCHECK(factory_); } MediaStreamVideoSource::~MediaStreamVideoSource() { diff --git a/content/renderer/media/media_stream_video_source.h b/content/renderer/media/media_stream_video_source.h index b080a47..af33b4e 100644 --- a/content/renderer/media/media_stream_video_source.h +++ b/content/renderer/media/media_stream_video_source.h @@ -64,7 +64,7 @@ class CONTENT_EXPORT MediaStreamVideoSource // interface of this class. // This creates a VideoSourceInterface implementation if it does not already // exist. - webrtc::VideoSourceInterface* GetAdapter(); + virtual webrtc::VideoSourceInterface* GetAdapter(); // Return true if |name| is a constraint supported by MediaStreamVideoSource. static bool IsConstraintSupported(const std::string& name); @@ -130,7 +130,7 @@ class CONTENT_EXPORT MediaStreamVideoSource STARTED, ENDED }; - State state() { return state_; } + State state() const { return state_; } private: // Creates a webrtc::VideoSourceInterface used by libjingle. diff --git a/content/renderer/media/media_stream_video_track.cc b/content/renderer/media/media_stream_video_track.cc index 3cf98cd..8d4b83d 100644 --- a/content/renderer/media/media_stream_video_track.cc +++ b/content/renderer/media/media_stream_video_track.cc @@ -5,7 +5,6 @@ #include "content/renderer/media/media_stream_video_track.h" #include "content/renderer/media/media_stream_dependency_factory.h" -#include "content/renderer/media/webrtc/webrtc_video_sink_adapter.h" namespace content { @@ -42,18 +41,12 @@ MediaStreamVideoTrack::MediaStreamVideoTrack( enabled_(enabled), source_(source), factory_(factory) { - // TODO(perkj): source can be NULL if this is actually a remote video track. - // Remove as soon as we only have one implementation of video tracks. - if (source) - source->AddTrack(this, constraints, callback); + source->AddTrack(this, constraints, callback); } MediaStreamVideoTrack::~MediaStreamVideoTrack() { DCHECK(sinks_.empty()); - // TODO(perkj): source can be NULL if this is actually a remote video track. - // Remove as soon as we only have one implementation of video tracks. - if (source_) - source_->RemoveTrack(this); + source_->RemoveTrack(this); } void MediaStreamVideoTrack::AddSink(MediaStreamVideoSink* sink) { @@ -116,43 +109,4 @@ void MediaStreamVideoTrack::OnReadyStateChanged( } } -// Wrapper which allows to use std::find_if() when adding and removing -// sinks to/from |sinks_|. -struct SinkWrapper { - explicit SinkWrapper(MediaStreamVideoSink* sink) : sink_(sink) {} - bool operator()( - const WebRtcVideoSinkAdapter* owner) { - return owner->sink() == sink_; - } - MediaStreamVideoSink* sink_; -}; - -WebRtcMediaStreamVideoTrack::WebRtcMediaStreamVideoTrack( - webrtc::VideoTrackInterface* track) - : MediaStreamVideoTrack(NULL, - blink::WebMediaConstraints(), - MediaStreamVideoSource::ConstraintsCallback(), - track->enabled(), - NULL) { - track_ = track; -} - -WebRtcMediaStreamVideoTrack::~WebRtcMediaStreamVideoTrack() { -} - -void WebRtcMediaStreamVideoTrack::AddSink(MediaStreamVideoSink* sink) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(std::find_if(sinks_.begin(), sinks_.end(), - SinkWrapper(sink)) == sinks_.end()); - sinks_.push_back(new WebRtcVideoSinkAdapter(GetVideoAdapter(), sink)); -} - -void WebRtcMediaStreamVideoTrack::RemoveSink(MediaStreamVideoSink* sink) { - DCHECK(thread_checker_.CalledOnValidThread()); - ScopedVector<WebRtcVideoSinkAdapter>::iterator it = - std::find_if(sinks_.begin(), sinks_.end(), SinkWrapper(sink)); - DCHECK(it != sinks_.end()); - sinks_.erase(it); -} - } // namespace content diff --git a/content/renderer/media/media_stream_video_track.h b/content/renderer/media/media_stream_video_track.h index 16c0a91..07307ae 100644 --- a/content/renderer/media/media_stream_video_track.h +++ b/content/renderer/media/media_stream_video_track.h @@ -22,7 +22,6 @@ class VideoTrackInterface; namespace content { class MediaStreamDependencyFactory; -class WebRtcVideoSinkAdapter; // MediaStreamVideoTrack is a video specific representation of a // blink::WebMediaStreamTrack in content. It is owned by the blink object @@ -87,26 +86,6 @@ class CONTENT_EXPORT MediaStreamVideoTrack : public MediaStreamTrack { DISALLOW_COPY_AND_ASSIGN(MediaStreamVideoTrack); }; -// WebRtcMediaStreamVideoTrack is a content representation of a video track. -// received on a PeerConnection. -// TODO(perkj): Replace WebRtcMediaStreamVideoTrack with a remote -// MediaStreamVideoSource class so that all tracks are MediaStreamVideoTracks -// and new tracks can be cloned from the original remote video track. -// crbug/334243. -class CONTENT_EXPORT WebRtcMediaStreamVideoTrack - : public MediaStreamVideoTrack { - public: - explicit WebRtcMediaStreamVideoTrack(webrtc::VideoTrackInterface* track); - virtual ~WebRtcMediaStreamVideoTrack(); - virtual void AddSink(MediaStreamVideoSink* sink) OVERRIDE; - virtual void RemoveSink(MediaStreamVideoSink* sink) OVERRIDE; - - private: - ScopedVector<WebRtcVideoSinkAdapter> sinks_; - - DISALLOW_COPY_AND_ASSIGN(WebRtcMediaStreamVideoTrack); -}; - } // namespace content #endif // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_VIDEO_TRACK_H_ diff --git a/content/renderer/media/mock_media_stream_dependency_factory.cc b/content/renderer/media/mock_media_stream_dependency_factory.cc index 1441d32..d07cb3a 100644 --- a/content/renderer/media/mock_media_stream_dependency_factory.cc +++ b/content/renderer/media/mock_media_stream_dependency_factory.cc @@ -283,60 +283,64 @@ int MockVideoSource::GetFrameNum() const { return static_cast<MockRtcVideoCapturer*>(capturer_.get())->GetFrameNum(); } -MockLocalVideoTrack::MockLocalVideoTrack(std::string id, - webrtc::VideoSourceInterface* source) +MockWebRtcVideoTrack::MockWebRtcVideoTrack( + std::string id, + webrtc::VideoSourceInterface* source) : enabled_(false), id_(id), state_(MediaStreamTrackInterface::kLive), source_(source), - observer_(NULL) { + observer_(NULL), + renderer_(NULL) { } -MockLocalVideoTrack::~MockLocalVideoTrack() {} +MockWebRtcVideoTrack::~MockWebRtcVideoTrack() {} -void MockLocalVideoTrack::AddRenderer(VideoRendererInterface* renderer) { - NOTIMPLEMENTED(); +void MockWebRtcVideoTrack::AddRenderer(VideoRendererInterface* renderer) { + DCHECK(!renderer_); + renderer_ = renderer; } -void MockLocalVideoTrack::RemoveRenderer(VideoRendererInterface* renderer) { - NOTIMPLEMENTED(); +void MockWebRtcVideoTrack::RemoveRenderer(VideoRendererInterface* renderer) { + DCHECK_EQ(renderer_, renderer); + renderer_ = NULL; } -std::string MockLocalVideoTrack::kind() const { +std::string MockWebRtcVideoTrack::kind() const { NOTIMPLEMENTED(); return std::string(); } -std::string MockLocalVideoTrack::id() const { return id_; } +std::string MockWebRtcVideoTrack::id() const { return id_; } -bool MockLocalVideoTrack::enabled() const { return enabled_; } +bool MockWebRtcVideoTrack::enabled() const { return enabled_; } -MockLocalVideoTrack::TrackState MockLocalVideoTrack::state() const { +MockWebRtcVideoTrack::TrackState MockWebRtcVideoTrack::state() const { return state_; } -bool MockLocalVideoTrack::set_enabled(bool enable) { +bool MockWebRtcVideoTrack::set_enabled(bool enable) { enabled_ = enable; return true; } -bool MockLocalVideoTrack::set_state(TrackState new_state) { +bool MockWebRtcVideoTrack::set_state(TrackState new_state) { state_ = new_state; if (observer_) observer_->OnChanged(); return true; } -void MockLocalVideoTrack::RegisterObserver(ObserverInterface* observer) { +void MockWebRtcVideoTrack::RegisterObserver(ObserverInterface* observer) { observer_ = observer; } -void MockLocalVideoTrack::UnregisterObserver(ObserverInterface* observer) { +void MockWebRtcVideoTrack::UnregisterObserver(ObserverInterface* observer) { DCHECK(observer_ == observer); observer_ = NULL; } -VideoSourceInterface* MockLocalVideoTrack::GetSource() const { +VideoSourceInterface* MockWebRtcVideoTrack::GetSource() const { return source_.get(); } @@ -480,7 +484,7 @@ MockMediaStreamDependencyFactory::CreateLocalVideoTrack( const std::string& id, webrtc::VideoSourceInterface* source) { scoped_refptr<webrtc::VideoTrackInterface> track( - new talk_base::RefCountedObject<MockLocalVideoTrack>( + new talk_base::RefCountedObject<MockWebRtcVideoTrack>( id, source)); return track; } @@ -493,7 +497,8 @@ MockMediaStreamDependencyFactory::CreateLocalVideoTrack( new talk_base::RefCountedObject<MockVideoSource>(); source->SetVideoCapturer(capturer); - return new talk_base::RefCountedObject<MockLocalVideoTrack>(id, source.get()); + return + new talk_base::RefCountedObject<MockWebRtcVideoTrack>(id, source.get()); } SessionDescriptionInterface* diff --git a/content/renderer/media/mock_media_stream_dependency_factory.h b/content/renderer/media/mock_media_stream_dependency_factory.h index 05cd5c7..a2cce87 100644 --- a/content/renderer/media/mock_media_stream_dependency_factory.h +++ b/content/renderer/media/mock_media_stream_dependency_factory.h @@ -104,9 +104,9 @@ class MockAudioSource : public webrtc::AudioSourceInterface { webrtc::MediaConstraintsInterface::Constraints mandatory_constraints_; }; -class MockLocalVideoTrack : public webrtc::VideoTrackInterface { +class MockWebRtcVideoTrack : public webrtc::VideoTrackInterface { public: - MockLocalVideoTrack(std::string id, + MockWebRtcVideoTrack(std::string id, webrtc::VideoSourceInterface* source); virtual void AddRenderer(webrtc::VideoRendererInterface* renderer) OVERRIDE; virtual void RemoveRenderer( @@ -122,7 +122,7 @@ class MockLocalVideoTrack : public webrtc::VideoTrackInterface { virtual webrtc::VideoSourceInterface* GetSource() const OVERRIDE; protected: - virtual ~MockLocalVideoTrack(); + virtual ~MockWebRtcVideoTrack(); private: bool enabled_; @@ -130,6 +130,7 @@ class MockLocalVideoTrack : public webrtc::VideoTrackInterface { TrackState state_; scoped_refptr<webrtc::VideoSourceInterface> source_; webrtc::ObserverInterface* observer_; + webrtc::VideoRendererInterface* renderer_; }; class MockMediaStream : public webrtc::MediaStreamInterface { diff --git a/content/renderer/media/remote_media_stream_impl.cc b/content/renderer/media/remote_media_stream_impl.cc index 66bdb60..1510607b 100644 --- a/content/renderer/media/remote_media_stream_impl.cc +++ b/content/renderer/media/remote_media_stream_impl.cc @@ -10,39 +10,13 @@ #include "base/strings/utf_string_conversions.h" #include "content/renderer/media/media_stream.h" #include "content/renderer/media/media_stream_dependency_factory.h" +#include "content/renderer/media/media_stream_video_track.h" +#include "content/renderer/media/webrtc/media_stream_remote_video_source.h" +#include "content/renderer/render_thread_impl.h" #include "third_party/WebKit/public/platform/WebString.h" namespace content { -// RemoteMediaStreamTrackObserver is responsible for listening on change -// notification on a remote webrtc MediaStreamTrack and notify WebKit. -class RemoteMediaStreamTrackObserver - : NON_EXPORTED_BASE(public webrtc::ObserverInterface), - NON_EXPORTED_BASE(public base::NonThreadSafe) { - public: - RemoteMediaStreamTrackObserver( - webrtc::MediaStreamTrackInterface* webrtc_track, - const blink::WebMediaStreamTrack& webkit_track); - virtual ~RemoteMediaStreamTrackObserver(); - - webrtc::MediaStreamTrackInterface* observered_track() { - return webrtc_track_.get(); - } - const blink::WebMediaStreamTrack& webkit_track() { return webkit_track_; } - - private: - // webrtc::ObserverInterface implementation. - virtual void OnChanged() OVERRIDE; - - webrtc::MediaStreamTrackInterface::TrackState state_; - scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track_; - blink::WebMediaStreamTrack webkit_track_; - - DISALLOW_COPY_AND_ASSIGN(RemoteMediaStreamTrackObserver); -}; - -} // namespace content - namespace { void InitializeWebkitTrack(webrtc::MediaStreamTrackInterface* track, @@ -53,43 +27,114 @@ void InitializeWebkitTrack(webrtc::MediaStreamTrackInterface* track, webkit_source.initialize(webkit_track_id, type, webkit_track_id); webkit_track->initialize(webkit_track_id, webkit_source); - content::MediaStreamDependencyFactory::AddNativeTrackToBlinkTrack( - track, *webkit_track, false); + + MediaStreamDependencyFactory* factory = NULL; + // RenderThreadImpl::current() may be NULL in unit tests. + RenderThreadImpl* render_thread = RenderThreadImpl::current(); + if (render_thread) + factory = render_thread->GetMediaStreamDependencyFactory(); + + if (type == blink::WebMediaStreamSource::TypeVideo) { + MediaStreamRemoteVideoSource* video_source = + new MediaStreamRemoteVideoSource( + static_cast<webrtc::VideoTrackInterface*>(track)); + webkit_source.setExtraData(video_source); + // Initial constraints must be provided to a MediaStreamVideoTrack. But + // no constraints are available initially on a remote video track. + blink::WebMediaConstraints constraints; + constraints.initialize(); + webkit_track->setExtraData( + new MediaStreamVideoTrack(video_source, constraints, + MediaStreamVideoSource::ConstraintsCallback(), + track->enabled(), factory)); + } else { + DCHECK(type == blink::WebMediaStreamSource::TypeAudio); + content::MediaStreamDependencyFactory::AddNativeAudioTrackToBlinkTrack( + track, *webkit_track, false); + } } -content::RemoteMediaStreamTrackObserver* FindTrackObserver( - webrtc::MediaStreamTrackInterface* track, - const ScopedVector<content::RemoteMediaStreamTrackObserver>& observers) { - ScopedVector<content::RemoteMediaStreamTrackObserver>::const_iterator it = +} // namespace + +// Base class used for mapping between webrtc and blink MediaStream tracks. +// An instance of a RemoteMediaStreamTrackAdapter is stored in +// RemoteMediaStreamImpl per remote audio and video track. +class RemoteMediaStreamTrackAdapter { + public: + RemoteMediaStreamTrackAdapter(webrtc::MediaStreamTrackInterface* webrtc_track, + const blink::WebMediaStreamTrack& webkit_track) + : webrtc_track_(webrtc_track), + webkit_track_(webkit_track) { + } + + virtual ~RemoteMediaStreamTrackAdapter() { + } + + webrtc::MediaStreamTrackInterface* observed_track() { + return webrtc_track_.get(); + } + + const blink::WebMediaStreamTrack& webkit_track() { return webkit_track_; } + + private: + scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track_; + blink::WebMediaStreamTrack webkit_track_; + bool sent_ended_message_; + + DISALLOW_COPY_AND_ASSIGN(RemoteMediaStreamTrackAdapter); +}; + +static content::RemoteMediaStreamTrackAdapter* FindTrackObserver( + webrtc::MediaStreamTrackInterface* track, + const ScopedVector<content::RemoteMediaStreamTrackAdapter>& observers) { + ScopedVector<content::RemoteMediaStreamTrackAdapter>::const_iterator it = observers.begin(); for (; it != observers.end(); ++it) { - if ((*it)->observered_track() == track) + if ((*it)->observed_track() == track) return *it; } return NULL; } -} // namespace anonymous +// RemoteAudioMediaStreamTrackAdapter is responsible for listening on state +// change notifications on a remote webrtc audio MediaStreamTracks and notify +// WebKit. +class RemoteAudioMediaStreamTrackAdapter + : public RemoteMediaStreamTrackAdapter, + public webrtc::ObserverInterface, + public base::NonThreadSafe { + public: + RemoteAudioMediaStreamTrackAdapter( + webrtc::MediaStreamTrackInterface* webrtc_track, + const blink::WebMediaStreamTrack& webkit_track); + virtual ~RemoteAudioMediaStreamTrackAdapter(); -namespace content { + private: + // webrtc::ObserverInterface implementation. + virtual void OnChanged() OVERRIDE; + + webrtc::MediaStreamTrackInterface::TrackState state_; + + DISALLOW_COPY_AND_ASSIGN(RemoteAudioMediaStreamTrackAdapter); +}; -RemoteMediaStreamTrackObserver::RemoteMediaStreamTrackObserver( +RemoteAudioMediaStreamTrackAdapter::RemoteAudioMediaStreamTrackAdapter( webrtc::MediaStreamTrackInterface* webrtc_track, const blink::WebMediaStreamTrack& webkit_track) - : state_(webrtc_track->state()), - webrtc_track_(webrtc_track), - webkit_track_(webkit_track) { - webrtc_track->RegisterObserver(this); + : RemoteMediaStreamTrackAdapter(webrtc_track, webkit_track), + state_(observed_track()->state()) { + observed_track()->RegisterObserver(this); } -RemoteMediaStreamTrackObserver::~RemoteMediaStreamTrackObserver() { - webrtc_track_->UnregisterObserver(this); +RemoteAudioMediaStreamTrackAdapter::~RemoteAudioMediaStreamTrackAdapter() { + observed_track()->UnregisterObserver(this); } -void RemoteMediaStreamTrackObserver::OnChanged() { +void RemoteAudioMediaStreamTrackAdapter::OnChanged() { DCHECK(CalledOnValidThread()); - webrtc::MediaStreamTrackInterface::TrackState state = webrtc_track_->state(); + webrtc::MediaStreamTrackInterface::TrackState state = + observed_track()->state(); if (state == state_) return; @@ -100,11 +145,11 @@ void RemoteMediaStreamTrackObserver::OnChanged() { // WebMediaStreamSource::ReadyState. break; case webrtc::MediaStreamTrackInterface::kLive: - webkit_track_.source().setReadyState( + webkit_track().source().setReadyState( blink::WebMediaStreamSource::ReadyStateLive); break; case webrtc::MediaStreamTrackInterface::kEnded: - webkit_track_.source().setReadyState( + webkit_track().source().setReadyState( blink::WebMediaStreamSource::ReadyStateEnded); break; default: @@ -131,8 +176,8 @@ RemoteMediaStreamImpl::RemoteMediaStreamImpl( InitializeWebkitTrack(audio_track, &webkit_audio_tracks[i], blink::WebMediaStreamSource::TypeAudio); audio_track_observers_.push_back( - new RemoteMediaStreamTrackObserver(audio_track, - webkit_audio_tracks[i])); + new RemoteAudioMediaStreamTrackAdapter(audio_track, + webkit_audio_tracks[i])); } // Initialize WebKit video tracks. @@ -146,8 +191,8 @@ RemoteMediaStreamImpl::RemoteMediaStreamImpl( InitializeWebkitTrack(video_track, &webkit_video_tracks[i], blink::WebMediaStreamSource::TypeVideo); video_track_observers_.push_back( - new RemoteMediaStreamTrackObserver(video_track, - webkit_video_tracks[i])); + new RemoteMediaStreamTrackAdapter(video_track, + webkit_video_tracks[i])); } webkit_stream_.initialize(base::UTF8ToUTF16(webrtc_stream->label()), @@ -161,10 +206,10 @@ RemoteMediaStreamImpl::~RemoteMediaStreamImpl() { void RemoteMediaStreamImpl::OnChanged() { // Find removed audio tracks. - ScopedVector<RemoteMediaStreamTrackObserver>::iterator audio_it = + ScopedVector<RemoteMediaStreamTrackAdapter>::iterator audio_it = audio_track_observers_.begin(); while (audio_it != audio_track_observers_.end()) { - std::string track_id = (*audio_it)->observered_track()->id(); + std::string track_id = (*audio_it)->observed_track()->id(); if (webrtc_stream_->FindAudioTrack(track_id) == NULL) { webkit_stream_.removeTrack((*audio_it)->webkit_track()); audio_it = audio_track_observers_.erase(audio_it); @@ -174,10 +219,10 @@ void RemoteMediaStreamImpl::OnChanged() { } // Find removed video tracks. - ScopedVector<RemoteMediaStreamTrackObserver>::iterator video_it = + ScopedVector<RemoteMediaStreamTrackAdapter>::iterator video_it = video_track_observers_.begin(); while (video_it != video_track_observers_.end()) { - std::string track_id = (*video_it)->observered_track()->id(); + std::string track_id = (*video_it)->observed_track()->id(); if (webrtc_stream_->FindVideoTrack(track_id) == NULL) { webkit_stream_.removeTrack((*video_it)->webkit_track()); video_it = video_track_observers_.erase(video_it); @@ -196,7 +241,7 @@ void RemoteMediaStreamImpl::OnChanged() { InitializeWebkitTrack(*it, &new_track, blink::WebMediaStreamSource::TypeAudio); audio_track_observers_.push_back( - new RemoteMediaStreamTrackObserver(*it, new_track)); + new RemoteAudioMediaStreamTrackAdapter(*it, new_track)); webkit_stream_.addTrack(new_track); } } @@ -211,7 +256,7 @@ void RemoteMediaStreamImpl::OnChanged() { InitializeWebkitTrack(*it, &new_track, blink::WebMediaStreamSource::TypeVideo); video_track_observers_.push_back( - new RemoteMediaStreamTrackObserver(*it, new_track)); + new RemoteMediaStreamTrackAdapter(*it, new_track)); webkit_stream_.addTrack(new_track); } } diff --git a/content/renderer/media/remote_media_stream_impl.h b/content/renderer/media/remote_media_stream_impl.h index 3263ed4..6b1554a 100644 --- a/content/renderer/media/remote_media_stream_impl.h +++ b/content/renderer/media/remote_media_stream_impl.h @@ -18,7 +18,7 @@ namespace content { -class RemoteMediaStreamTrackObserver; +class RemoteMediaStreamTrackAdapter; // RemoteMediaStreamImpl serves as a container and glue between remote webrtc // MediaStreams and WebKit MediaStreams. For each remote MediaStream received @@ -39,8 +39,8 @@ class CONTENT_EXPORT RemoteMediaStreamImpl virtual void OnChanged() OVERRIDE; scoped_refptr<webrtc::MediaStreamInterface> webrtc_stream_; - ScopedVector<RemoteMediaStreamTrackObserver> audio_track_observers_; - ScopedVector<RemoteMediaStreamTrackObserver> video_track_observers_; + ScopedVector<RemoteMediaStreamTrackAdapter> video_track_observers_; + ScopedVector<RemoteMediaStreamTrackAdapter> audio_track_observers_; blink::WebMediaStream webkit_stream_; DISALLOW_COPY_AND_ASSIGN(RemoteMediaStreamImpl); diff --git a/content/renderer/media/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/rtc_peer_connection_handler_unittest.cc index c2b21dc..17cf4e8 100644 --- a/content/renderer/media/rtc_peer_connection_handler_unittest.cc +++ b/content/renderer/media/rtc_peer_connection_handler_unittest.cc @@ -288,6 +288,7 @@ class RTCPeerConnectionHandlerTest : public ::testing::Test { return stream; } + base::MessageLoop message_loop_; scoped_ptr<MockWebRTCPeerConnectionHandlerClient> mock_client_; scoped_ptr<MockMediaStreamDependencyFactory> mock_dependency_factory_; scoped_ptr<NiceMock<MockPeerConnectionTracker> > mock_tracker_; @@ -739,17 +740,24 @@ TEST_F(RTCPeerConnectionHandlerTest, RemoveAndAddAudioTrackFromRemoteStream) { pc_handler_->OnAddStream(remote_stream.get()); const blink::WebMediaStream& webkit_stream = mock_client_->remote_stream(); - blink::WebVector<blink::WebMediaStreamTrack> audio_tracks; - webkit_stream.audioTracks(audio_tracks); - EXPECT_EQ(1u, audio_tracks.size()); + { + // Test in a small scope so that |audio_tracks| don't hold on to destroyed + // source later. + blink::WebVector<blink::WebMediaStreamTrack> audio_tracks; + webkit_stream.audioTracks(audio_tracks); + EXPECT_EQ(1u, audio_tracks.size()); + } // Remove the Webrtc audio track from the Webrtc MediaStream. scoped_refptr<webrtc::AudioTrackInterface> webrtc_track = remote_stream->GetAudioTracks()[0].get(); remote_stream->RemoveTrack(webrtc_track.get()); - blink::WebVector<blink::WebMediaStreamTrack> modified_audio_tracks1; - webkit_stream.audioTracks(modified_audio_tracks1); - EXPECT_EQ(0u, modified_audio_tracks1.size()); + + { + blink::WebVector<blink::WebMediaStreamTrack> modified_audio_tracks1; + webkit_stream.audioTracks(modified_audio_tracks1); + EXPECT_EQ(0u, modified_audio_tracks1.size()); + } // Add the WebRtc audio track again. remote_stream->AddTrack(webrtc_track.get()); @@ -769,17 +777,23 @@ TEST_F(RTCPeerConnectionHandlerTest, RemoveAndAddVideoTrackFromRemoteStream) { pc_handler_->OnAddStream(remote_stream.get()); const blink::WebMediaStream& webkit_stream = mock_client_->remote_stream(); - blink::WebVector<blink::WebMediaStreamTrack> video_tracks; - webkit_stream.videoTracks(video_tracks); - EXPECT_EQ(1u, video_tracks.size()); + { + // Test in a small scope so that |video_tracks| don't hold on to destroyed + // source later. + blink::WebVector<blink::WebMediaStreamTrack> video_tracks; + webkit_stream.videoTracks(video_tracks); + EXPECT_EQ(1u, video_tracks.size()); + } // Remove the Webrtc video track from the Webrtc MediaStream. scoped_refptr<webrtc::VideoTrackInterface> webrtc_track = remote_stream->GetVideoTracks()[0].get(); remote_stream->RemoveTrack(webrtc_track.get()); - blink::WebVector<blink::WebMediaStreamTrack> modified_video_tracks1; - webkit_stream.videoTracks(modified_video_tracks1); - EXPECT_EQ(0u, modified_video_tracks1.size()); + { + blink::WebVector<blink::WebMediaStreamTrack> modified_video_tracks1; + webkit_stream.videoTracks(modified_video_tracks1); + EXPECT_EQ(0u, modified_video_tracks1.size()); + } // Add the WebRtc video track again. remote_stream->AddTrack(webrtc_track.get()); diff --git a/content/renderer/media/webrtc/media_stream_remote_video_source.cc b/content/renderer/media/webrtc/media_stream_remote_video_source.cc new file mode 100644 index 0000000..50468af --- /dev/null +++ b/content/renderer/media/webrtc/media_stream_remote_video_source.cc @@ -0,0 +1,157 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// 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/media_stream_remote_video_source.h" + +#include "base/bind.h" +#include "base/location.h" +#include "content/renderer/media/native_handle_impl.h" +#include "media/base/video_frame.h" +#include "media/base/video_util.h" +#include "third_party/libjingle/source/talk/media/base/videoframe.h" + +namespace content { + +MediaStreamRemoteVideoSource::MediaStreamRemoteVideoSource( + webrtc::VideoTrackInterface* remote_track) + : MediaStreamVideoSource(NULL), + message_loop_proxy_(base::MessageLoopProxy::current()), + remote_track_(remote_track), + last_state_(remote_track_->state()), + first_frame_received_(false) { + remote_track_->AddRenderer(this); + remote_track_->RegisterObserver(this); +} + +MediaStreamRemoteVideoSource::~MediaStreamRemoteVideoSource() { + StopSourceImpl(); +} + +void MediaStreamRemoteVideoSource::GetCurrentSupportedFormats( + int max_requested_width, + int max_requested_height) { + DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + if (format_.IsValid()) { + media::VideoCaptureFormats formats; + formats.push_back(format_); + OnSupportedFormats(formats); + } +} + +void MediaStreamRemoteVideoSource::StartSourceImpl( + const media::VideoCaptureParams& params) { + DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + OnStartDone(true); +} + +void MediaStreamRemoteVideoSource::StopSourceImpl() { + DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + remote_track_->RemoveRenderer(this); + remote_track_->UnregisterObserver(this); +} + +webrtc::VideoSourceInterface* MediaStreamRemoteVideoSource::GetAdapter() { + DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + return remote_track_->GetSource(); +} + +void MediaStreamRemoteVideoSource::SetSize(int width, int height) { +} + +void MediaStreamRemoteVideoSource::RenderFrame( + const cricket::VideoFrame* frame) { + base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds( + frame->GetTimeStamp() / talk_base::kNumNanosecsPerMillisec); + + scoped_refptr<media::VideoFrame> video_frame; + if (frame->GetNativeHandle() != NULL) { + NativeHandleImpl* handle = + static_cast<NativeHandleImpl*>(frame->GetNativeHandle()); + video_frame = static_cast<media::VideoFrame*>(handle->GetHandle()); + video_frame->SetTimestamp(timestamp); + } else { + gfx::Size size(frame->GetWidth(), frame->GetHeight()); + video_frame = frame_pool_.CreateFrame( + media::VideoFrame::I420, size, gfx::Rect(size), size, timestamp); + + // Non-square pixels are unsupported. + DCHECK_EQ(frame->GetPixelWidth(), 1u); + DCHECK_EQ(frame->GetPixelHeight(), 1u); + + int y_rows = frame->GetHeight(); + int uv_rows = frame->GetChromaHeight(); + CopyYPlane( + frame->GetYPlane(), frame->GetYPitch(), y_rows, video_frame.get()); + CopyUPlane( + frame->GetUPlane(), frame->GetUPitch(), uv_rows, video_frame.get()); + CopyVPlane( + frame->GetVPlane(), frame->GetVPitch(), uv_rows, video_frame.get()); + } + + if (!first_frame_received_) { + first_frame_received_ = true; + media::VideoPixelFormat pixel_format = ( + video_frame->format() == media::VideoFrame::I420) ? + media::PIXEL_FORMAT_I420 : media::PIXEL_FORMAT_TEXTURE; + media::VideoCaptureFormat format( + gfx::Size(video_frame->natural_size().width(), + video_frame->natural_size().height()), + MediaStreamVideoSource::kDefaultFrameRate, + pixel_format); + message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&MediaStreamRemoteVideoSource::FrameFormatOnMainThread, + AsWeakPtr(), format)); + } + + // TODO(perkj): Consider delivering the frame on whatever thread the frame is + // delivered on once crbug/335327 is fixed. + message_loop_proxy_->PostTask( + FROM_HERE, + base::Bind(&MediaStreamRemoteVideoSource::DoRenderFrameOnMainThread, + AsWeakPtr(), video_frame)); +} + +void MediaStreamRemoteVideoSource::OnChanged() { + DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + webrtc::MediaStreamTrackInterface::TrackState state = remote_track_->state(); + if (state != last_state_) { + last_state_ = state; + switch (state) { + case webrtc::MediaStreamTrackInterface::kInitializing: + // Ignore the kInitializing state since there is no match in + // WebMediaStreamSource::ReadyState. + break; + case webrtc::MediaStreamTrackInterface::kLive: + SetReadyState(blink::WebMediaStreamSource::ReadyStateLive); + break; + case webrtc::MediaStreamTrackInterface::kEnded: + SetReadyState(blink::WebMediaStreamSource::ReadyStateEnded); + break; + default: + NOTREACHED(); + break; + } + } +} + +void MediaStreamRemoteVideoSource::FrameFormatOnMainThread( + const media::VideoCaptureFormat& format) { + DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + format_ = format; + if (state() == RETRIEVING_CAPABILITIES) { + media::VideoCaptureFormats formats; + formats.push_back(format); + OnSupportedFormats(formats); + } +} + +void MediaStreamRemoteVideoSource::DoRenderFrameOnMainThread( + scoped_refptr<media::VideoFrame> video_frame) { + DCHECK(message_loop_proxy_->BelongsToCurrentThread()); + if (state() == STARTED) + DeliverVideoFrame(video_frame); +} + +} // namespace content diff --git a/content/renderer/media/webrtc/media_stream_remote_video_source.h b/content/renderer/media/webrtc/media_stream_remote_video_source.h new file mode 100644 index 0000000..2d5be61 --- /dev/null +++ b/content/renderer/media/webrtc/media_stream_remote_video_source.h @@ -0,0 +1,74 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_MEDIA_STREAM_REMOTE_VIDEO_SOURCE_H_ +#define CONTENT_RENDERER_MEDIA_WEBRTC_MEDIA_STREAM_REMOTE_VIDEO_SOURCE_H_ + +#include "base/memory/weak_ptr.h" +#include "content/common/content_export.h" +#include "content/renderer/media/media_stream_video_source.h" +#include "media/base/video_frame_pool.h" +#include "third_party/WebKit/public/platform/WebMediaStreamSource.h" +#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h" + +namespace content { + +// MediaStreamRemoteVideoSource implements the MediaStreamVideoSource interface +// for video tracks received on a PeerConnection. The purpose of the class is +// to make sure there is no difference between a video track where the source is +// a local source and a video track where the source is a remote video track. +class CONTENT_EXPORT MediaStreamRemoteVideoSource + : public MediaStreamVideoSource, + NON_EXPORTED_BASE(public webrtc::VideoRendererInterface), + NON_EXPORTED_BASE(public webrtc::ObserverInterface), + public base::SupportsWeakPtr<MediaStreamRemoteVideoSource> { + public: + explicit MediaStreamRemoteVideoSource( + webrtc::VideoTrackInterface* remote_track); + virtual ~MediaStreamRemoteVideoSource(); + + protected: + // Implements MediaStreamVideoSource. + virtual void GetCurrentSupportedFormats( + int max_requested_width, + int max_requested_height) OVERRIDE; + + virtual void StartSourceImpl( + const media::VideoCaptureParams& params) OVERRIDE; + + virtual void StopSourceImpl() OVERRIDE; + + virtual webrtc::VideoSourceInterface* GetAdapter() OVERRIDE; + + // Implements webrtc::VideoRendererInterface used for receiving video frames + // from the PeerConnection video track. May be called on + // a different thread. + virtual void SetSize(int width, int height) OVERRIDE; + virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE; + + // webrtc::ObserverInterface implementation. + virtual void OnChanged() OVERRIDE; + + private: + void FrameFormatOnMainThread(const media::VideoCaptureFormat& format); + void DoRenderFrameOnMainThread(scoped_refptr<media::VideoFrame> video_frame); + + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; + scoped_refptr<webrtc::VideoTrackInterface> remote_track_; + webrtc::MediaStreamTrackInterface::TrackState last_state_; + + // |first_frame_received_| and |frame_pool_| are only accessed on whatever + // thread webrtc::VideoRendererInterface::RenderFrame is called on. + bool first_frame_received_; + media::VideoFramePool frame_pool_; + + // |format_| is the format currently received by this source. + media::VideoCaptureFormat format_; + + DISALLOW_COPY_AND_ASSIGN(MediaStreamRemoteVideoSource); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_WEBRTC_MEDIA_STREAM_REMOTE_VIDEO_SOURCE_H_ diff --git a/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc b/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc new file mode 100644 index 0000000..068320f --- /dev/null +++ b/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc @@ -0,0 +1,160 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/utf_string_conversions.h" +#include "content/public/renderer/media_stream_video_sink.h" +#include "content/renderer/media/media_stream_video_track.h" +#include "content/renderer/media/mock_media_stream_dependency_factory.h" +#include "content/renderer/media/webrtc/media_stream_remote_video_source.h" +#include "media/base/video_frame.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.h" + +namespace content { + +class MockVideoSink : public MediaStreamVideoSink { + public: + MockVideoSink() + : number_of_frames_(0), + state_(blink::WebMediaStreamSource::ReadyStateLive) { + } + + virtual void OnVideoFrame( + const scoped_refptr<media::VideoFrame>& frame) OVERRIDE { + ++number_of_frames_; + } + + virtual void OnReadyStateChanged( + blink::WebMediaStreamSource::ReadyState state) OVERRIDE { + state_ = state; + } + + int number_of_frames() const { return number_of_frames_; } + blink::WebMediaStreamSource::ReadyState state() const { return state_; } + + private: + int number_of_frames_; + blink::WebMediaStreamSource::ReadyState state_; +}; + +class MediaStreamRemoteVideoSourceUnderTest + : public MediaStreamRemoteVideoSource { + public: + MediaStreamRemoteVideoSourceUnderTest(webrtc::VideoTrackInterface* track) + : MediaStreamRemoteVideoSource(track) { + } + using MediaStreamRemoteVideoSource::RenderFrame; +}; + +class MediaStreamRemoteVideoSourceTest + : public ::testing::Test { + public: + MediaStreamRemoteVideoSourceTest() + : mock_factory_(new MockMediaStreamDependencyFactory()), + webrtc_video_track_( + mock_factory_->CreateLocalVideoTrack( + "test", + static_cast<cricket::VideoCapturer*>(NULL))), + remote_source_( + new MediaStreamRemoteVideoSourceUnderTest(webrtc_video_track_)), + number_of_successful_constraints_applied_(0), + number_of_failed_constraints_applied_(0) { + webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"), + blink::WebMediaStreamSource::TypeVideo, + base::UTF8ToUTF16("dummy_source_name")); + webkit_source_.setExtraData(remote_source_); + } + virtual ~MediaStreamRemoteVideoSourceTest() {} + + MediaStreamRemoteVideoSourceUnderTest* source() { + return remote_source_; + } + + MediaStreamVideoTrack* CreateTrack() { + bool enabled = true; + blink::WebMediaConstraints constraints; + constraints.initialize(); + MediaStreamDependencyFactory* factory = NULL; + return new MediaStreamVideoTrack( + source(), + constraints, + base::Bind( + &MediaStreamRemoteVideoSourceTest::OnConstraintsApplied, + base::Unretained(this)), + enabled, factory); + } + + int NumberOfSuccessConstraintsCallbacks() const { + return number_of_successful_constraints_applied_; + } + + int NumberOfFailedConstraintsCallbacks() const { + return number_of_failed_constraints_applied_; + } + + void StopWebRtcTrack() { + static_cast<MockWebRtcVideoTrack*>(webrtc_video_track_.get())->set_state( + webrtc::MediaStreamTrackInterface::kEnded); + } + + base::MessageLoop* message_loop() { return &message_loop_; } + + const blink::WebMediaStreamSource& webkit_source() const { + return webkit_source_; + } + + private: + void OnConstraintsApplied(MediaStreamSource* source, bool success) { + ASSERT_EQ(source, remote_source_); + if (success) + ++number_of_successful_constraints_applied_; + else + ++number_of_failed_constraints_applied_; + } + + base::MessageLoop message_loop_; + scoped_ptr<MockMediaStreamDependencyFactory> mock_factory_; + scoped_refptr<webrtc::VideoTrackInterface> webrtc_video_track_; + // |remote_source_| is owned by |webkit_source_|. + MediaStreamRemoteVideoSourceUnderTest* remote_source_; + blink::WebMediaStreamSource webkit_source_; + int number_of_successful_constraints_applied_; + int number_of_failed_constraints_applied_; +}; + +TEST_F(MediaStreamRemoteVideoSourceTest, StartTrack) { + scoped_ptr<MediaStreamVideoTrack> track(CreateTrack()); + EXPECT_EQ(0, NumberOfSuccessConstraintsCallbacks()); + + MockVideoSink sink; + track->AddSink(&sink); + + cricket::WebRtcVideoFrame webrtc_frame; + webrtc_frame.InitToBlack(320, 240, 1, 1, 0, 1); + source()->RenderFrame(&webrtc_frame); + message_loop()->RunUntilIdle(); + + EXPECT_EQ(1, NumberOfSuccessConstraintsCallbacks()); + EXPECT_EQ(1, sink.number_of_frames()); + track->RemoveSink(&sink); +} + +TEST_F(MediaStreamRemoteVideoSourceTest, RemoteTrackStop) { + scoped_ptr<MediaStreamVideoTrack> track(CreateTrack()); + + MockVideoSink sink; + track->AddSink(&sink); + + EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive, sink.state()); + EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive, + webkit_source().readyState()); + StopWebRtcTrack(); + EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded, + webkit_source().readyState()); + EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded, sink.state()); + + track->RemoveSink(&sink); +} + +} // namespace content diff --git a/content/renderer/media/webrtc/webrtc_video_sink_adapter.cc b/content/renderer/media/webrtc/webrtc_video_sink_adapter.cc deleted file mode 100644 index 587ecfe..0000000 --- a/content/renderer/media/webrtc/webrtc_video_sink_adapter.cc +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// 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_sink_adapter.h" - -#include "base/bind.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/message_loop/message_loop_proxy.h" -#include "content/renderer/media/native_handle_impl.h" -#include "media/base/video_frame.h" -#include "media/base/video_util.h" -#include "third_party/libjingle/source/talk/media/base/videoframe.h" -#include "third_party/WebKit/public/platform/WebMediaStreamSource.h" -#include "ui/gfx/size.h" - -using media::CopyYPlane; -using media::CopyUPlane; -using media::CopyVPlane; - -namespace content { - -WebRtcVideoSinkAdapter::WebRtcVideoSinkAdapter( - webrtc::VideoTrackInterface* video_track, - MediaStreamVideoSink* sink) - : message_loop_proxy_(base::MessageLoopProxy::current()), - sink_(sink), - video_track_(video_track), - state_(video_track->state()), - track_enabled_(video_track->enabled()) { - DCHECK(sink); - video_track_->AddRenderer(this); - video_track_->RegisterObserver(this); - DVLOG(1) << "WebRtcVideoSinkAdapter"; -} - -WebRtcVideoSinkAdapter::~WebRtcVideoSinkAdapter() { - video_track_->RemoveRenderer(this); - video_track_->UnregisterObserver(this); - DVLOG(1) << "~WebRtcVideoSinkAdapter"; -} - -void WebRtcVideoSinkAdapter::SetSize(int width, int height) { -} - -void WebRtcVideoSinkAdapter::RenderFrame(const cricket::VideoFrame* frame) { - base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds( - frame->GetTimeStamp() / talk_base::kNumNanosecsPerMillisec); - - scoped_refptr<media::VideoFrame> video_frame; - if (frame->GetNativeHandle() != NULL) { - NativeHandleImpl* handle = - static_cast<NativeHandleImpl*>(frame->GetNativeHandle()); - video_frame = static_cast<media::VideoFrame*>(handle->GetHandle()); - video_frame->SetTimestamp(timestamp); - } else { - gfx::Size size(frame->GetWidth(), frame->GetHeight()); - video_frame = media::VideoFrame::CreateFrame( - media::VideoFrame::YV12, size, gfx::Rect(size), size, timestamp); - - // Aspect ratio unsupported; DCHECK when there are non-square pixels. - DCHECK_EQ(frame->GetPixelWidth(), 1u); - DCHECK_EQ(frame->GetPixelHeight(), 1u); - - int y_rows = frame->GetHeight(); - int uv_rows = frame->GetChromaHeight(); - CopyYPlane( - frame->GetYPlane(), frame->GetYPitch(), y_rows, video_frame.get()); - CopyUPlane( - frame->GetUPlane(), frame->GetUPitch(), uv_rows, video_frame.get()); - CopyVPlane( - frame->GetVPlane(), frame->GetVPitch(), uv_rows, video_frame.get()); - } - - message_loop_proxy_->PostTask( - FROM_HERE, base::Bind(&WebRtcVideoSinkAdapter::DoRenderFrameOnMainThread, - AsWeakPtr(), video_frame)); -} - -void WebRtcVideoSinkAdapter::OnChanged() { - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); - - // TODO(perkj): OnChanged belongs to the base class of WebRtcVideoSinkAdapter - // common for both webrtc audio and video. - webrtc::MediaStreamTrackInterface::TrackState state = video_track_->state(); - if (state != state_) { - state_ = state; - switch (state) { - case webrtc::MediaStreamTrackInterface::kInitializing: - // Ignore the kInitializing state since there is no match in - // WebMediaStreamSource::ReadyState. - break; - case webrtc::MediaStreamTrackInterface::kLive: - sink_->OnReadyStateChanged(blink::WebMediaStreamSource::ReadyStateLive); - break; - case webrtc::MediaStreamTrackInterface::kEnded: - sink_->OnReadyStateChanged( - blink::WebMediaStreamSource::ReadyStateEnded); - break; - default: - NOTREACHED(); - break; - } - } - if (track_enabled_ != video_track_->enabled()) { - track_enabled_ = video_track_->enabled(); - sink_->OnEnabledChanged(track_enabled_); - } -} - -void WebRtcVideoSinkAdapter::DoRenderFrameOnMainThread( - scoped_refptr<media::VideoFrame> video_frame) { - DCHECK(message_loop_proxy_->BelongsToCurrentThread()); - sink_->OnVideoFrame(video_frame); -} - -} // namespace content diff --git a/content/renderer/media/webrtc/webrtc_video_sink_adapter.h b/content/renderer/media/webrtc/webrtc_video_sink_adapter.h deleted file mode 100644 index 2f75a95..0000000 --- a/content/renderer/media/webrtc/webrtc_video_sink_adapter.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_VIDEO_SINK_ADAPTER_H_ -#define CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_VIDEO_SINK_ADAPTER_H_ - -#include "base/memory/weak_ptr.h" -#include "content/common/content_export.h" -#include "content/public/renderer/media_stream_video_sink.h" -#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h" - -namespace base { -class MessageLoopProxy; -} - -namespace content { - -// WebRtcVideoSinkAdapter acts as the middle man between a -// webrtc:::VideoTrackInterface and a content::MediaStreamVideoSink. -// It is responsible for translating video data from a libjingle video type -// to a chrome video type. -class CONTENT_EXPORT WebRtcVideoSinkAdapter - : NON_EXPORTED_BASE(public webrtc::VideoRendererInterface), - NON_EXPORTED_BASE(public webrtc::ObserverInterface), - public base::SupportsWeakPtr<WebRtcVideoSinkAdapter> { - public: - WebRtcVideoSinkAdapter(webrtc::VideoTrackInterface* video_track, - MediaStreamVideoSink* sink); - virtual ~WebRtcVideoSinkAdapter(); - - MediaStreamVideoSink* sink() const { return sink_; } - - protected: - // webrtc::VideoRendererInterface implementation. May be called on - // a different thread. - virtual void SetSize(int width, int height) OVERRIDE; - virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE; - - // webrtc::ObserverInterface implementation. - // TODO(perkj): OnChanged should be implemented on a common base class used - // for both WebRtc Audio and Video tracks. - virtual void OnChanged() OVERRIDE; - - private: - void DoRenderFrameOnMainThread(scoped_refptr<media::VideoFrame> video_frame); - - scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; - MediaStreamVideoSink* sink_; - // The video track the renderer is connected to. - scoped_refptr<webrtc::VideoTrackInterface> video_track_; - webrtc::MediaStreamTrackInterface::TrackState state_; - bool track_enabled_; - - DISALLOW_COPY_AND_ASSIGN(WebRtcVideoSinkAdapter); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_VIDEO_SINK_ADAPTER_H_ |