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