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