video_source_handler.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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  // All the opened readers should have been closed by now.
65  DCHECK(reader_to_receiver_.empty());
66}
67
68bool VideoSourceHandler::Open(const std::string& url,
69                              FrameReaderInterface* reader) {
70  scoped_refptr<webrtc::VideoSourceInterface> source = GetFirstVideoSource(url);
71  if (!source.get()) {
72    return false;
73  }
74  PpFrameReceiver* receiver = new PpFrameReceiver();
75  receiver->SetReader(reader);
76  source->AddSink(receiver);
77  reader_to_receiver_[reader] = receiver;
78  return true;
79}
80
81bool VideoSourceHandler::Close(const std::string& url,
82                               FrameReaderInterface* reader) {
83  scoped_refptr<webrtc::VideoSourceInterface> source = GetFirstVideoSource(url);
84  if (!source.get()) {
85    LOG(ERROR) << "VideoSourceHandler::Close - Failed to get the video source "
86               << "from MediaStream with url: " << url;
87    return false;
88  }
89  PpFrameReceiver* receiver =
90      static_cast<PpFrameReceiver*>(GetReceiver(reader));
91  if (!receiver) {
92    LOG(ERROR) << "VideoSourceHandler::Close - Failed to find receiver that "
93               << "is associated with the given reader.";
94    return false;
95  }
96  receiver->SetReader(NULL);
97  source->RemoveSink(receiver);
98  reader_to_receiver_.erase(reader);
99  delete receiver;
100  return true;
101}
102
103scoped_refptr<VideoSourceInterface> VideoSourceHandler::GetFirstVideoSource(
104    const std::string& url) {
105  scoped_refptr<webrtc::VideoSourceInterface> source;
106  WebKit::WebMediaStream stream;
107  if (registry_) {
108    stream = registry_->GetMediaStream(url);
109  } else {
110    stream =
111        WebKit::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
112  }
113  if (stream.isNull() || !stream.extraData()) {
114    LOG(ERROR) << "GetFirstVideoSource - invalid url: " << url;
115    return source;
116  }
117
118  // Get the first video track from the stream.
119  MediaStreamExtraData* extra_data =
120      static_cast<MediaStreamExtraData*>(stream.extraData());
121  if (!extra_data) {
122    LOG(ERROR) << "GetFirstVideoSource - MediaStreamExtraData is NULL.";
123    return source;
124  }
125  webrtc::MediaStreamInterface* native_stream = extra_data->stream().get();
126  if (!native_stream) {
127    LOG(ERROR) << "GetFirstVideoSource - native stream is NULL.";
128    return source;
129  }
130  webrtc::VideoTrackVector native_video_tracks =
131      native_stream->GetVideoTracks();
132  if (native_video_tracks.empty()) {
133    LOG(ERROR) << "GetFirstVideoSource - stream has no video track.";
134    return source;
135  }
136  source = native_video_tracks[0]->GetSource();
137  return source;
138}
139
140VideoRenderer* VideoSourceHandler::GetReceiver(
141    FrameReaderInterface* reader) {
142  std::map<FrameReaderInterface*, VideoRenderer*>::iterator it;
143  it = reader_to_receiver_.find(reader);
144  if (it == reader_to_receiver_.end()) {
145    return NULL;
146  }
147  return it->second;
148}
149
150}  // namespace content
151
152