普通文本  |  158行  |  4.62 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 "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "content/public/renderer/media_stream_video_sink.h"
#include "content/renderer/media/media_stream.h"
#include "content/renderer/media/media_stream_registry_interface.h"
#include "media/base/bind_to_current_loop.h"
#include "media/video/capture/video_capture_types.h"
#include "third_party/WebKit/public/platform/WebMediaStream.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
#include "url/gurl.h"

namespace content {

// PpFrameReceiver implements MediaStreamVideoSink so that it can be attached
// to video track to receive the captured frame.
// It can be attached to a FrameReaderInterface to output the received frame.
class PpFrameReceiver : public MediaStreamVideoSink {
 public:
  PpFrameReceiver(blink::WebMediaStreamTrack track)
    : track_(track),
      reader_(NULL),
      weak_factory_(this) {
  }

  virtual ~PpFrameReceiver() {}

  void SetReader(FrameReaderInterface* reader) {
    if (reader) {
      DCHECK(!reader_);
      MediaStreamVideoSink::AddToVideoTrack(
          this,
          media::BindToCurrentLoop(
              base::Bind(
                  &PpFrameReceiver::OnVideoFrame,
                  weak_factory_.GetWeakPtr())),
          track_);
    } else {
      DCHECK(reader_);
      MediaStreamVideoSink::RemoveFromVideoTrack(this, track_);
      weak_factory_.InvalidateWeakPtrs();
    }
    reader_ = reader;
  }

  void OnVideoFrame(
      const scoped_refptr<media::VideoFrame>& frame,
      const media::VideoCaptureFormat& format,
      const base::TimeTicks& estimated_capture_time) {
    if (reader_) {
      reader_->GotFrame(frame);
    }
  }

 private:
  blink::WebMediaStreamTrack track_;
  FrameReaderInterface* reader_;
  base::WeakPtrFactory<PpFrameReceiver> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(PpFrameReceiver);
};

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

VideoSourceHandler::~VideoSourceHandler() {
  for (SourceInfoMap::iterator it = reader_to_receiver_.begin();
       it != reader_to_receiver_.end();
       ++it) {
    delete it->second;
  }
}

bool VideoSourceHandler::Open(const std::string& url,
                              FrameReaderInterface* reader) {
  DCHECK(thread_checker_.CalledOnValidThread());
  const blink::WebMediaStreamTrack& track = GetFirstVideoTrack(url);
  if (track.isNull()) {
    return false;
  }
  reader_to_receiver_[reader] = new SourceInfo(track, reader);
  return true;
}

bool VideoSourceHandler::Close(FrameReaderInterface* reader) {
  DCHECK(thread_checker_. CalledOnValidThread());
  SourceInfoMap::iterator it = reader_to_receiver_.find(reader);
  if (it == reader_to_receiver_.end()) {
    return false;
  }
  delete it->second;
  reader_to_receiver_.erase(it);
  return true;
}

blink::WebMediaStreamTrack VideoSourceHandler::GetFirstVideoTrack(
    const std::string& url) {
  blink::WebMediaStream stream;
  if (registry_) {
    stream = registry_->GetMediaStream(url);
  } else {
    stream =
        blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
  }

  if (stream.isNull()) {
    LOG(ERROR) << "GetFirstVideoSource - invalid url: " << url;
    return blink::WebMediaStreamTrack();
  }

  // Get the first video track from the stream.
  blink::WebVector<blink::WebMediaStreamTrack> video_tracks;
  stream.videoTracks(video_tracks);
  if (video_tracks.isEmpty()) {
    LOG(ERROR) << "GetFirstVideoSource - non video tracks available."
               << " url: " << url;
    return blink::WebMediaStreamTrack();
  }

  return video_tracks[0];
}

void VideoSourceHandler::DeliverFrameForTesting(
    FrameReaderInterface* reader,
    const scoped_refptr<media::VideoFrame>& frame) {
  SourceInfoMap::iterator it = reader_to_receiver_.find(reader);
  if (it == reader_to_receiver_.end()) {
    return;
  }
  PpFrameReceiver* receiver = it->second->receiver_.get();
  receiver->OnVideoFrame(frame, media::VideoCaptureFormat(),
                         base::TimeTicks());
}

VideoSourceHandler::SourceInfo::SourceInfo(
    const blink::WebMediaStreamTrack& blink_track,
    FrameReaderInterface* reader)
    : receiver_(new PpFrameReceiver(blink_track)) {
  receiver_->SetReader(reader);
}

VideoSourceHandler::SourceInfo::~SourceInfo() {
  receiver_->SetReader(NULL);
}

}  // namespace content