video_source_handler.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "content/renderer/media/media_stream_dependency_factory.h"
11#include "content/renderer/media/media_stream_registry_interface.h"
12#include "content/renderer/render_thread_impl.h"
13#include "third_party/WebKit/public/platform/WebMediaStream.h"
14#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
15#include "third_party/libjingle/source/talk/media/base/videoframe.h"
16#include "third_party/libjingle/source/talk/media/base/videorenderer.h"
17
18using cricket::VideoFrame;
19using cricket::VideoRenderer;
20using webrtc::VideoSourceInterface;
21
22namespace content {
23
24// PpFrameReceiver implements cricket::VideoRenderer so that it can be attached
25// to native video track's video source to receive the captured frame.
26// It can be attached to a FrameReaderInterface to output the received frame.
27class PpFrameReceiver : public cricket::VideoRenderer {
28 public:
29  PpFrameReceiver() : reader_(NULL) {}
30  virtual ~PpFrameReceiver() {}
31
32  // Implements VideoRenderer.
33  virtual bool SetSize(int width, int height, int reserved) OVERRIDE {
34    return true;
35  }
36  virtual bool RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
37    base::AutoLock auto_lock(lock_);
38    if (reader_) {
39      // Make a shallow copy of the frame as the |reader_| may need to queue it.
40      // Both frames will share a single reference-counted frame buffer.
41      reader_->GotFrame(frame->Copy());
42    }
43    return true;
44  }
45
46  void SetReader(FrameReaderInterface* reader) {
47    base::AutoLock auto_lock(lock_);
48    reader_ = reader;
49  }
50
51 private:
52  FrameReaderInterface* reader_;
53  base::Lock lock_;
54
55  DISALLOW_COPY_AND_ASSIGN(PpFrameReceiver);
56};
57
58VideoSourceHandler::VideoSourceHandler(
59    MediaStreamRegistryInterface* registry)
60    : registry_(registry) {
61}
62
63VideoSourceHandler::~VideoSourceHandler() {
64  for (SourceInfoMap::iterator it = reader_to_receiver_.begin();
65       it != reader_to_receiver_.end();
66       ++it) {
67    delete it->second;
68  }
69}
70
71bool VideoSourceHandler::Open(const std::string& url,
72                              FrameReaderInterface* reader) {
73  scoped_refptr<webrtc::VideoSourceInterface> source = GetFirstVideoSource(url);
74  if (!source.get()) {
75    return false;
76  }
77  reader_to_receiver_[reader] = new SourceInfo(source, reader);
78  return true;
79}
80
81bool VideoSourceHandler::Close(FrameReaderInterface* reader) {
82  SourceInfoMap::iterator it = reader_to_receiver_.find(reader);
83  if (it == reader_to_receiver_.end()) {
84    return false;
85  }
86  delete it->second;
87  reader_to_receiver_.erase(it);
88  return true;
89}
90
91scoped_refptr<VideoSourceInterface> VideoSourceHandler::GetFirstVideoSource(
92    const std::string& url) {
93  scoped_refptr<webrtc::VideoSourceInterface> source;
94  blink::WebMediaStream stream;
95  if (registry_) {
96    stream = registry_->GetMediaStream(url);
97  } else {
98    stream =
99        blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
100  }
101  if (stream.isNull() || !stream.extraData()) {
102    LOG(ERROR) << "GetFirstVideoSource - invalid url: " << url;
103    return source;
104  }
105
106  // Get the first video track from the stream.
107  MediaStreamExtraData* extra_data =
108      static_cast<MediaStreamExtraData*>(stream.extraData());
109  if (!extra_data) {
110    LOG(ERROR) << "GetFirstVideoSource - MediaStreamExtraData is NULL.";
111    return source;
112  }
113  webrtc::MediaStreamInterface* native_stream = extra_data->stream().get();
114  if (!native_stream) {
115    LOG(ERROR) << "GetFirstVideoSource - native stream is NULL.";
116    return source;
117  }
118  webrtc::VideoTrackVector native_video_tracks =
119      native_stream->GetVideoTracks();
120  if (native_video_tracks.empty()) {
121    LOG(ERROR) << "GetFirstVideoSource - stream has no video track.";
122    return source;
123  }
124  source = native_video_tracks[0]->GetSource();
125  return source;
126}
127
128VideoRenderer* VideoSourceHandler::GetReceiver(
129    FrameReaderInterface* reader) {
130  SourceInfoMap::iterator it = reader_to_receiver_.find(reader);
131  if (it == reader_to_receiver_.end()) {
132    return NULL;
133  }
134  return it->second->receiver_.get();
135}
136
137VideoSourceHandler::SourceInfo::SourceInfo(
138    scoped_refptr<webrtc::VideoSourceInterface> source,
139    FrameReaderInterface* reader)
140    : receiver_(new PpFrameReceiver()),
141      source_(source) {
142  source_->AddSink(receiver_.get());
143  receiver_->SetReader(reader);
144}
145
146VideoSourceHandler::SourceInfo::~SourceInfo() {
147  source_->RemoveSink(receiver_.get());
148  receiver_->SetReader(NULL);
149}
150
151}  // namespace content
152
153