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