// Copyright (c) 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/video_source_handler.h" #include #include "base/logging.h" #include "base/memory/weak_ptr.h" #include "base/synchronization/lock.h" #include "content/public/renderer/media_stream_video_sink.h" #include "content/renderer/media/media_stream.h" #include "content/renderer/media/media_stream_registry_interface.h" #include "media/base/bind_to_current_loop.h" #include "media/video/capture/video_capture_types.h" #include "third_party/WebKit/public/platform/WebMediaStream.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" #include "url/gurl.h" namespace content { // PpFrameReceiver implements MediaStreamVideoSink so that it can be attached // to video track to receive the captured frame. // It can be attached to a FrameReaderInterface to output the received frame. class PpFrameReceiver : public MediaStreamVideoSink { public: PpFrameReceiver(blink::WebMediaStreamTrack track) : track_(track), reader_(NULL), weak_factory_(this) { } virtual ~PpFrameReceiver() {} void SetReader(FrameReaderInterface* reader) { if (reader) { DCHECK(!reader_); MediaStreamVideoSink::AddToVideoTrack( this, media::BindToCurrentLoop( base::Bind( &PpFrameReceiver::OnVideoFrame, weak_factory_.GetWeakPtr())), track_); } else { DCHECK(reader_); MediaStreamVideoSink::RemoveFromVideoTrack(this, track_); weak_factory_.InvalidateWeakPtrs(); } reader_ = reader; } void OnVideoFrame( const scoped_refptr& frame, const media::VideoCaptureFormat& format) { if (reader_) { reader_->GotFrame(frame); } } private: blink::WebMediaStreamTrack track_; FrameReaderInterface* reader_; base::WeakPtrFactory weak_factory_; DISALLOW_COPY_AND_ASSIGN(PpFrameReceiver); }; VideoSourceHandler::VideoSourceHandler( MediaStreamRegistryInterface* registry) : registry_(registry) { } VideoSourceHandler::~VideoSourceHandler() { for (SourceInfoMap::iterator it = reader_to_receiver_.begin(); it != reader_to_receiver_.end(); ++it) { delete it->second; } } bool VideoSourceHandler::Open(const std::string& url, FrameReaderInterface* reader) { DCHECK(thread_checker_.CalledOnValidThread()); const blink::WebMediaStreamTrack& track = GetFirstVideoTrack(url); if (track.isNull()) { return false; } reader_to_receiver_[reader] = new SourceInfo(track, reader); return true; } bool VideoSourceHandler::Close(FrameReaderInterface* reader) { DCHECK(thread_checker_. CalledOnValidThread()); SourceInfoMap::iterator it = reader_to_receiver_.find(reader); if (it == reader_to_receiver_.end()) { return false; } delete it->second; reader_to_receiver_.erase(it); return true; } blink::WebMediaStreamTrack VideoSourceHandler::GetFirstVideoTrack( const std::string& url) { blink::WebMediaStream stream; if (registry_) { stream = registry_->GetMediaStream(url); } else { stream = blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url)); } if (stream.isNull()) { LOG(ERROR) << "GetFirstVideoSource - invalid url: " << url; return blink::WebMediaStreamTrack(); } // Get the first video track from the stream. blink::WebVector video_tracks; stream.videoTracks(video_tracks); if (video_tracks.isEmpty()) { LOG(ERROR) << "GetFirstVideoSource - non video tracks available." << " url: " << url; return blink::WebMediaStreamTrack(); } return video_tracks[0]; } void VideoSourceHandler::DeliverFrameForTesting( FrameReaderInterface* reader, const scoped_refptr& frame) { SourceInfoMap::iterator it = reader_to_receiver_.find(reader); if (it == reader_to_receiver_.end()) { return; } PpFrameReceiver* receiver = it->second->receiver_.get(); receiver->OnVideoFrame(frame, media::VideoCaptureFormat()); } VideoSourceHandler::SourceInfo::SourceInfo( const blink::WebMediaStreamTrack& blink_track, FrameReaderInterface* reader) : receiver_(new PpFrameReceiver(blink_track)) { receiver_->SetReader(reader); } VideoSourceHandler::SourceInfo::~SourceInfo() { receiver_->SetReader(NULL); } } // namespace content