// 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