普通文本  |  152行  |  4.79 KB

// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/media/video_source_handler.h"

#include <string>

#include "base/logging.h"
#include "content/renderer/media/media_stream_dependency_factory.h"
#include "content/renderer/media/media_stream_registry_interface.h"
#include "content/renderer/render_thread_impl.h"
#include "third_party/WebKit/public/platform/WebMediaStream.h"
#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
#include "third_party/libjingle/source/talk/media/base/videoframe.h"
#include "third_party/libjingle/source/talk/media/base/videorenderer.h"

using cricket::VideoFrame;
using cricket::VideoRenderer;
using webrtc::VideoSourceInterface;

namespace content {

// PpFrameReceiver implements cricket::VideoRenderer so that it can be attached
// to native video track's video source to receive the captured frame.
// It can be attached to a FrameReaderInterface to output the received frame.
class PpFrameReceiver : public cricket::VideoRenderer {
 public:
  PpFrameReceiver() : reader_(NULL) {}
  virtual ~PpFrameReceiver() {}

  // Implements VideoRenderer.
  virtual bool SetSize(int width, int height, int reserved) OVERRIDE {
    return true;
  }
  virtual bool RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
    base::AutoLock auto_lock(lock_);
    if (reader_) {
      // Make a shallow copy of the frame as the |reader_| may need to queue it.
      // Both frames will share a single reference-counted frame buffer.
      reader_->GotFrame(frame->Copy());
    }
    return true;
  }

  void SetReader(FrameReaderInterface* reader) {
    base::AutoLock auto_lock(lock_);
    reader_ = reader;
  }

 private:
  FrameReaderInterface* reader_;
  base::Lock lock_;

  DISALLOW_COPY_AND_ASSIGN(PpFrameReceiver);
};

VideoSourceHandler::VideoSourceHandler(
    MediaStreamRegistryInterface* registry)
    : registry_(registry) {
}

VideoSourceHandler::~VideoSourceHandler() {
  // All the opened readers should have been closed by now.
  DCHECK(reader_to_receiver_.empty());
}

bool VideoSourceHandler::Open(const std::string& url,
                              FrameReaderInterface* reader) {
  scoped_refptr<webrtc::VideoSourceInterface> source = GetFirstVideoSource(url);
  if (!source.get()) {
    return false;
  }
  PpFrameReceiver* receiver = new PpFrameReceiver();
  receiver->SetReader(reader);
  source->AddSink(receiver);
  reader_to_receiver_[reader] = receiver;
  return true;
}

bool VideoSourceHandler::Close(const std::string& url,
                               FrameReaderInterface* reader) {
  scoped_refptr<webrtc::VideoSourceInterface> source = GetFirstVideoSource(url);
  if (!source.get()) {
    LOG(ERROR) << "VideoSourceHandler::Close - Failed to get the video source "
               << "from MediaStream with url: " << url;
    return false;
  }
  PpFrameReceiver* receiver =
      static_cast<PpFrameReceiver*>(GetReceiver(reader));
  if (!receiver) {
    LOG(ERROR) << "VideoSourceHandler::Close - Failed to find receiver that "
               << "is associated with the given reader.";
    return false;
  }
  receiver->SetReader(NULL);
  source->RemoveSink(receiver);
  reader_to_receiver_.erase(reader);
  delete receiver;
  return true;
}

scoped_refptr<VideoSourceInterface> VideoSourceHandler::GetFirstVideoSource(
    const std::string& url) {
  scoped_refptr<webrtc::VideoSourceInterface> source;
  blink::WebMediaStream stream;
  if (registry_) {
    stream = registry_->GetMediaStream(url);
  } else {
    stream =
        blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
  }
  if (stream.isNull() || !stream.extraData()) {
    LOG(ERROR) << "GetFirstVideoSource - invalid url: " << url;
    return source;
  }

  // Get the first video track from the stream.
  MediaStreamExtraData* extra_data =
      static_cast<MediaStreamExtraData*>(stream.extraData());
  if (!extra_data) {
    LOG(ERROR) << "GetFirstVideoSource - MediaStreamExtraData is NULL.";
    return source;
  }
  webrtc::MediaStreamInterface* native_stream = extra_data->stream().get();
  if (!native_stream) {
    LOG(ERROR) << "GetFirstVideoSource - native stream is NULL.";
    return source;
  }
  webrtc::VideoTrackVector native_video_tracks =
      native_stream->GetVideoTracks();
  if (native_video_tracks.empty()) {
    LOG(ERROR) << "GetFirstVideoSource - stream has no video track.";
    return source;
  }
  source = native_video_tracks[0]->GetSource();
  return source;
}

VideoRenderer* VideoSourceHandler::GetReceiver(
    FrameReaderInterface* reader) {
  std::map<FrameReaderInterface*, VideoRenderer*>::iterator it;
  it = reader_to_receiver_.find(reader);
  if (it == reader_to_receiver_.end()) {
    return NULL;
  }
  return it->second;
}

}  // namespace content