diff options
Diffstat (limited to 'chromium/content/renderer/media/video_destination_handler.cc')
-rw-r--r-- | chromium/content/renderer/media/video_destination_handler.cc | 210 |
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 + |