1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/renderer/media/video_source_handler.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <string> 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/logging.h" 10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/memory/weak_ptr.h" 11c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/synchronization/lock.h" 12c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "content/public/renderer/media_stream_video_sink.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/renderer/media/media_stream.h" 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/renderer/media/media_stream_registry_interface.h" 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "media/base/bind_to_current_loop.h" 16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "media/video/capture/video_capture_types.h" 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebMediaStream.h" 18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "third_party/WebKit/public/platform/WebURL.h" 197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" 20effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "url/gurl.h" 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace content { 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// PpFrameReceiver implements MediaStreamVideoSink so that it can be attached 25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// to video track to receive the captured frame. 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// It can be attached to a FrameReaderInterface to output the received frame. 27c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochclass PpFrameReceiver : public MediaStreamVideoSink { 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PpFrameReceiver(blink::WebMediaStreamTrack track) 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : track_(track), 31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) reader_(NULL), 32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) weak_factory_(this) { 33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual ~PpFrameReceiver() {} 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void SetReader(FrameReaderInterface* reader) { 38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (reader) { 39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(!reader_); 40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MediaStreamVideoSink::AddToVideoTrack( 41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this, 42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) media::BindToCurrentLoop( 43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind( 44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &PpFrameReceiver::OnVideoFrame, 45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) weak_factory_.GetWeakPtr())), 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) track_); 47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(reader_); 49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MediaStreamVideoSink::RemoveFromVideoTrack(this, track_); 50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) weak_factory_.InvalidateWeakPtrs(); 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) reader_ = reader; 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void OnVideoFrame( 56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const scoped_refptr<media::VideoFrame>& frame, 5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const media::VideoCaptureFormat& format, 5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const base::TimeTicks& estimated_capture_time) { 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (reader_) { 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) reader_->GotFrame(frame); 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) blink::WebMediaStreamTrack track_; 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FrameReaderInterface* reader_; 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::WeakPtrFactory<PpFrameReceiver> weak_factory_; 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(PpFrameReceiver); 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)VideoSourceHandler::VideoSourceHandler( 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MediaStreamRegistryInterface* registry) 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : registry_(registry) { 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)VideoSourceHandler::~VideoSourceHandler() { 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (SourceInfoMap::iterator it = reader_to_receiver_.begin(); 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) it != reader_to_receiver_.end(); 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++it) { 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delete it->second; 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 83b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool VideoSourceHandler::Open(const std::string& url, 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FrameReaderInterface* reader) { 87c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 88c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const blink::WebMediaStreamTrack& track = GetFirstVideoTrack(url); 89c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (track.isNull()) { 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 92c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch reader_to_receiver_[reader] = new SourceInfo(track, reader); 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool VideoSourceHandler::Close(FrameReaderInterface* reader) { 97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DCHECK(thread_checker_. CalledOnValidThread()); 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SourceInfoMap::iterator it = reader_to_receiver_.find(reader); 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (it == reader_to_receiver_.end()) { 100b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 101b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delete it->second; 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) reader_to_receiver_.erase(it); 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 107c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochblink::WebMediaStreamTrack VideoSourceHandler::GetFirstVideoTrack( 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& url) { 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebMediaStream stream; 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (registry_) { 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream = registry_->GetMediaStream(url); 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) stream = 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url)); 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 116c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (stream.isNull()) { 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LOG(ERROR) << "GetFirstVideoSource - invalid url: " << url; 119c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return blink::WebMediaStreamTrack(); 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Get the first video track from the stream. 123c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch blink::WebVector<blink::WebMediaStreamTrack> video_tracks; 124c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch stream.videoTracks(video_tracks); 125c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (video_tracks.isEmpty()) { 126c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch LOG(ERROR) << "GetFirstVideoSource - non video tracks available." 127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch << " url: " << url; 128c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return blink::WebMediaStreamTrack(); 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 130c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return video_tracks[0]; 132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void VideoSourceHandler::DeliverFrameForTesting( 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FrameReaderInterface* reader, 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const scoped_refptr<media::VideoFrame>& frame) { 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SourceInfoMap::iterator it = reader_to_receiver_.find(reader); 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (it == reader_to_receiver_.end()) { 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PpFrameReceiver* receiver = it->second->receiver_.get(); 14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) receiver->OnVideoFrame(frame, media::VideoCaptureFormat(), 14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::TimeTicks()); 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VideoSourceHandler::SourceInfo::SourceInfo( 147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const blink::WebMediaStreamTrack& blink_track, 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FrameReaderInterface* reader) 149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : receiver_(new PpFrameReceiver(blink_track)) { 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) receiver_->SetReader(reader); 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VideoSourceHandler::SourceInfo::~SourceInfo() { 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) receiver_->SetReader(NULL); 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace content 158