summaryrefslogtreecommitdiff
path: root/chromium/content/renderer/media/video_destination_handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/renderer/media/video_destination_handler.cc')
-rw-r--r--chromium/content/renderer/media/video_destination_handler.cc210
1 files changed, 210 insertions, 0 deletions
diff --git a/chromium/content/renderer/media/video_destination_handler.cc b/chromium/content/renderer/media/video_destination_handler.cc
new file mode 100644
index 00000000000..7438c495f3a
--- /dev/null
+++ b/chromium/content/renderer/media/video_destination_handler.cc
@@ -0,0 +1,210 @@
+// 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_destination_handler.h"
+
+#include <string>
+
+#include "base/base64.h"
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "content/renderer/media/media_stream_dependency_factory.h"
+#include "content/renderer/media/media_stream_registry_interface.h"
+#include "content/renderer/pepper/ppb_image_data_impl.h"
+#include "content/renderer/render_thread_impl.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
+
+using cricket::CaptureState;
+using cricket::VideoFormat;
+using webrtc::VideoTrackInterface;
+using webrtc::VideoTrackVector;
+
+static const cricket::FourCC kEffectColorFormat = cricket::FOURCC_BGRA;
+
+namespace content {
+
+PpFrameWriter::PpFrameWriter()
+ : started_(false) {}
+
+PpFrameWriter::~PpFrameWriter() {}
+
+CaptureState PpFrameWriter::Start(const VideoFormat& capture_format) {
+ base::AutoLock auto_lock(lock_);
+ if (started_) {
+ LOG(ERROR) << "PpFrameWriter::Start - "
+ << "Got a StartCapture when already started!";
+ return cricket::CS_FAILED;
+ }
+ started_ = true;
+ return cricket::CS_STARTING;
+}
+
+void PpFrameWriter::Stop() {
+ base::AutoLock auto_lock(lock_);
+ started_ = false;
+ SignalStateChange(this, cricket::CS_STOPPED);
+}
+
+bool PpFrameWriter::IsRunning() {
+ return started_;
+}
+
+bool PpFrameWriter::GetPreferredFourccs(std::vector<uint32>* fourccs) {
+ if (!fourccs) {
+ LOG(ERROR) << "PpFrameWriter::GetPreferredFourccs - "
+ << "fourccs is NULL.";
+ return false;
+ }
+ // The effects plugin output BGRA.
+ fourccs->push_back(kEffectColorFormat);
+ return true;
+}
+
+bool PpFrameWriter::GetBestCaptureFormat(const VideoFormat& desired,
+ VideoFormat* best_format) {
+ if (!best_format) {
+ LOG(ERROR) << "PpFrameWriter::GetBestCaptureFormat - "
+ << "best_format is NULL.";
+ return false;
+ }
+
+ // Use the desired format as the best format.
+ best_format->width = desired.width;
+ best_format->height = desired.height;
+ best_format->fourcc = kEffectColorFormat;
+ best_format->interval = desired.interval;
+ return true;
+}
+
+bool PpFrameWriter::IsScreencast() const {
+ return false;
+}
+
+void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
+ int64 time_stamp_ns) {
+ base::AutoLock auto_lock(lock_);
+ // This assumes the handler of the SignalFrameCaptured won't call Start/Stop.
+ // TODO(ronghuawu): Avoid the using of lock. One way is to post this call to
+ // libjingle worker thread, which will require an extra copy of |image_data|.
+ // However if pepper host can hand over the ownership of |image_data|
+ // then we can avoid this extra copy.
+ if (!started_) {
+ LOG(ERROR) << "PpFrameWriter::PutFrame - "
+ << "Called when capturer is not started.";
+ return;
+ }
+ if (!image_data) {
+ LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data.";
+ return;
+ }
+ ImageDataAutoMapper mapper(image_data);
+ if (!mapper.is_valid()) {
+ LOG(ERROR) << "PpFrameWriter::PutFrame - "
+ << "The image could not be mapped and is unusable.";
+ return;
+ }
+ const SkBitmap* bitmap = image_data->GetMappedBitmap();
+ if (!bitmap) {
+ LOG(ERROR) << "PpFrameWriter::PutFrame - "
+ << "The image_data's mapped bitmap is NULL.";
+ return;
+ }
+
+ cricket::CapturedFrame frame;
+ frame.elapsed_time = 0;
+ frame.time_stamp = time_stamp_ns;
+ frame.pixel_height = 1;
+ frame.pixel_width = 1;
+ frame.width = bitmap->width();
+ frame.height = bitmap->height();
+ if (image_data->format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL) {
+ frame.fourcc = cricket::FOURCC_BGRA;
+ } else {
+ LOG(ERROR) << "PpFrameWriter::PutFrame - Got RGBA which is not supported.";
+ return;
+ }
+ frame.data_size = bitmap->getSize();
+ frame.data = bitmap->getPixels();
+
+ // This signals to libJingle that a new VideoFrame is available.
+ // libJingle have no assumptions on what thread this signal come from.
+ SignalFrameCaptured(this, &frame);
+}
+
+// PpFrameWriterProxy is a helper class to make sure the user won't use
+// PpFrameWriter after it is released (IOW its owner - WebMediaStreamTrack -
+// is released).
+class PpFrameWriterProxy : public FrameWriterInterface {
+ public:
+ PpFrameWriterProxy(VideoTrackInterface* track,
+ PpFrameWriter* writer)
+ : track_(track),
+ writer_(writer) {
+ DCHECK(writer_ != NULL);
+ }
+
+ virtual ~PpFrameWriterProxy() {}
+
+ virtual void PutFrame(PPB_ImageData_Impl* image_data,
+ int64 time_stamp_ns) OVERRIDE {
+ writer_->PutFrame(image_data, time_stamp_ns);
+ }
+
+ private:
+ scoped_refptr<VideoTrackInterface> track_;
+ PpFrameWriter* writer_;
+
+ DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy);
+};
+
+bool VideoDestinationHandler::Open(
+ MediaStreamDependencyFactory* factory,
+ MediaStreamRegistryInterface* registry,
+ const std::string& url,
+ FrameWriterInterface** frame_writer) {
+ if (!factory) {
+ factory = RenderThreadImpl::current()->GetMediaStreamDependencyFactory();
+ DCHECK(factory != NULL);
+ }
+ WebKit::WebMediaStream stream;
+ if (registry) {
+ stream = registry->GetMediaStream(url);
+ } else {
+ stream =
+ WebKit::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
+ }
+ if (stream.isNull() || !stream.extraData()) {
+ LOG(ERROR) << "VideoDestinationHandler::Open - invalid url: " << url;
+ return false;
+ }
+
+ // Create a new native video track and add it to |stream|.
+ std::string track_id;
+ // According to spec, a media stream track's id should be globally unique.
+ // There's no easy way to strictly achieve that. The id generated with this
+ // method should be unique for most of the cases but theoretically it's
+ // possible we can get an id that's duplicated with the existing tracks.
+ base::Base64Encode(base::RandBytesAsString(64), &track_id);
+ PpFrameWriter* writer = new PpFrameWriter();
+ if (!factory->AddNativeVideoMediaTrack(track_id, &stream, writer)) {
+ delete writer;
+ return false;
+ }
+
+ // Gets a handler to the native video track, which owns the |writer|.
+ MediaStreamExtraData* extra_data =
+ static_cast<MediaStreamExtraData*>(stream.extraData());
+ webrtc::MediaStreamInterface* native_stream = extra_data->stream().get();
+ DCHECK(native_stream);
+ VideoTrackVector video_tracks = native_stream->GetVideoTracks();
+ // Currently one supports one video track per media stream.
+ DCHECK(video_tracks.size() == 1);
+
+ *frame_writer = new PpFrameWriterProxy(video_tracks[0].get(), writer);
+ return true;
+}
+
+} // namespace content
+