// 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_track_to_pepper_adapter.h" #include #include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/synchronization/lock.h" #include "base/trace_event/trace_event.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/base/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 captured frames. // 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) { } ~PpFrameReceiver() override {} void SetReader(FrameReaderInterface* reader) { DCHECK((reader_ && !reader) || (!reader_ && reader)) << " |reader| = " << reader << ", |reader_| = " << reader_; if (reader) { AddToVideoTrack(this, media::BindToCurrentLoop( base::Bind(&PpFrameReceiver::OnVideoFrame, weak_factory_.GetWeakPtr())), track_); } else { RemoveFromVideoTrack(this, track_); weak_factory_.InvalidateWeakPtrs(); } reader_ = reader; } void OnVideoFrame(const scoped_refptr& frame, base::TimeTicks estimated_capture_time) { TRACE_EVENT0("video", "PpFrameReceiver::OnVideoFrame"); if (reader_) reader_->GotFrame(frame); } private: const blink::WebMediaStreamTrack track_; FrameReaderInterface* reader_; base::WeakPtrFactory weak_factory_; DISALLOW_COPY_AND_ASSIGN(PpFrameReceiver); }; VideoTrackToPepperAdapter::VideoTrackToPepperAdapter( MediaStreamRegistryInterface* registry) : registry_(registry) {} VideoTrackToPepperAdapter::~VideoTrackToPepperAdapter() { for (const auto& reader_and_receiver : reader_to_receiver_) delete reader_and_receiver.second; } bool VideoTrackToPepperAdapter::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 VideoTrackToPepperAdapter::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 VideoTrackToPepperAdapter::GetFirstVideoTrack( const std::string& url) { DCHECK(thread_checker_.CalledOnValidThread()); const blink::WebMediaStream stream = registry_ ? registry_->GetMediaStream(url) : 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 - no video tracks. url: " << url; return blink::WebMediaStreamTrack(); } return video_tracks[0]; } void VideoTrackToPepperAdapter::DeliverFrameForTesting( FrameReaderInterface* reader, const scoped_refptr& frame) { SourceInfoMap::const_iterator it = reader_to_receiver_.find(reader); if (it == reader_to_receiver_.end()) return; PpFrameReceiver* receiver = it->second->receiver_.get(); receiver->OnVideoFrame(frame, base::TimeTicks()); } VideoTrackToPepperAdapter::SourceInfo::SourceInfo( const blink::WebMediaStreamTrack& blink_track, FrameReaderInterface* reader) : receiver_(new PpFrameReceiver(blink_track)) { receiver_->SetReader(reader); } VideoTrackToPepperAdapter::SourceInfo::~SourceInfo() { receiver_->SetReader(NULL); } } // namespace content