| Index: content/renderer/media/canvas_capture_handler.cc
|
| diff --git a/content/renderer/media/canvas_capture_handler.cc b/content/renderer/media/canvas_capture_handler.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..53547c43597bfc9834957ae539890968d6216582
|
| --- /dev/null
|
| +++ b/content/renderer/media/canvas_capture_handler.cc
|
| @@ -0,0 +1,169 @@
|
| +// Copyright 2015 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/canvas_capture_handler.h"
|
| +
|
| +#include "base/bind_helpers.h"
|
| +#include "content/public/renderer/media_stream_api.h"
|
| +#include "content/public/renderer/render_thread.h"
|
| +#include "content/renderer/render_thread_impl.h"
|
| +#include "third_party/libyuv/include/libyuv.h"
|
| +
|
| +namespace {
|
| +const float kDefaultFrameRate = 60.0f;
|
| +} // anonymous namespace
|
| +
|
| +namespace content {
|
| +
|
| +class CanvasCaptureHandler::VideoCapturerSource
|
| + : public media::VideoCapturerSource {
|
| + public:
|
| + explicit VideoCapturerSource(CanvasCaptureHandler* canvas_handler)
|
| + : canvas_handler_(canvas_handler) {}
|
| + protected:
|
| + void GetCurrentSupportedFormats(
|
| + int max_requested_width,
|
| + int max_requested_height,
|
| + double max_requested_frame_rate,
|
| + const VideoCaptureDeviceFormatsCB& callback) override;
|
| + void StartCapture(const media::VideoCaptureParams& params,
|
| + const VideoCaptureDeliverFrameCB& frame_callback,
|
| + const RunningCallback& running_callback) override {
|
| + canvas_handler_->StartVideoCapture(params, frame_callback,
|
| + running_callback);
|
| + }
|
| + void StopCapture() override { canvas_handler_->StopVideoCapture(); }
|
| +
|
| + private:
|
| + // CanvasCaptureHandler is owned by blink and guaranteed to be alive during
|
| + // the lifetime of this class.
|
| + CanvasCaptureHandler* canvas_handler_;
|
| +};
|
| +
|
| +void CanvasCaptureHandler::VideoCapturerSource::GetCurrentSupportedFormats(
|
| + int max_requested_width,
|
| + int max_requested_height,
|
| + double max_requested_frame_rate,
|
| + const VideoCaptureDeviceFormatsCB& callback) {
|
| + const blink::WebSize& size = canvas_handler_->GetSourceSize();
|
| + const media::VideoCaptureFormat format(gfx::Size(size.width, size.height),
|
| + kDefaultFrameRate,
|
| + media::PIXEL_FORMAT_I420);
|
| + media::VideoCaptureFormats formats;
|
| + formats.push_back(format);
|
| + callback.Run(formats);
|
| +}
|
| +
|
| +class CanvasCaptureHandler::CanvasCaptureHandlerDelegate {
|
| + public:
|
| + explicit CanvasCaptureHandlerDelegate(
|
| + media::VideoCapturerSource::VideoCaptureDeliverFrameCB new_frame_callback)
|
| + : new_frame_callback_(new_frame_callback),
|
| + io_task_runner_(content::RenderThread::Get()->GetIOMessageLoopProxy()) {
|
| + }
|
| +
|
| + void sendNewFrameOnIOThread(
|
| + const scoped_refptr<media::VideoFrame>& video_frame,
|
| + const base::TimeTicks& current_time) {
|
| + DCHECK(io_task_runner_->BelongsToCurrentThread());
|
| + new_frame_callback_.Run(video_frame, current_time);
|
| + }
|
| +
|
| + private:
|
| + const media::VideoCapturerSource::VideoCaptureDeliverFrameCB
|
| + new_frame_callback_;
|
| + const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
|
| + DISALLOW_COPY_AND_ASSIGN(CanvasCaptureHandlerDelegate);
|
| +};
|
| +
|
| +CanvasCaptureHandler::CanvasCaptureHandler(const blink::WebSize& size,
|
| + blink::WebMediaStream* stream)
|
| + : ask_for_new_frame_(false),
|
| + size_(size),
|
| + io_task_runner_(content::RenderThread::Get()->GetIOMessageLoopProxy()) {
|
| + scoped_ptr<media::VideoCapturerSource> video(
|
| + new CanvasCaptureHandler::VideoCapturerSource(this));
|
| + content::AddVideoTrackToMediaStream(video.Pass(), false, false, stream);
|
| +}
|
| +
|
| +CanvasCaptureHandler::~CanvasCaptureHandler() {
|
| + DVLOG(3) << __FUNCTION__;
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +}
|
| +
|
| +void CanvasCaptureHandler::sendNewFrame(const blink::WebSkImage& image) {
|
| + createNewFrame(image);
|
| +}
|
| +
|
| +bool CanvasCaptureHandler::needsNewFrameCapture() const {
|
| + return ask_for_new_frame_;
|
| +}
|
| +
|
| +void CanvasCaptureHandler::StartVideoCapture(
|
| + const media::VideoCaptureParams& params,
|
| + const media::VideoCapturerSource::VideoCaptureDeliverFrameCB&
|
| + new_frame_callback,
|
| + const media::VideoCapturerSource::RunningCallback& running_callback) {
|
| + DVLOG(3) << __FUNCTION__ << " requested "
|
| + << media::VideoCaptureFormat::ToString(params.requested_format);
|
| + DCHECK(params.requested_format.IsValid());
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + // TODO(emircan): Accomodate to the given frame rate constraints here.
|
| + capture_format_ = params.requested_format;
|
| + ask_for_new_frame_ = true;
|
| +
|
| + delegate_ =
|
| + make_scoped_ptr(new CanvasCaptureHandlerDelegate(new_frame_callback));
|
| + DCHECK(delegate_);
|
| + running_callback.Run(true);
|
| +}
|
| +
|
| +void CanvasCaptureHandler::StopVideoCapture() {
|
| + DVLOG(3) << __FUNCTION__;
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + ask_for_new_frame_ = false;
|
| + delegate_.reset();
|
| +}
|
| +
|
| +void CanvasCaptureHandler::createNewFrame(const blink::WebSkImage& image) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + DCHECK(!image.isNull());
|
| + const gfx::Size size(image.width(), image.height());
|
| + if (size != last_size) {
|
| + temp_data_.resize(
|
| + media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_ARGB, size));
|
| + row_bytes_ = media::VideoFrame::RowBytes(
|
| + 0, media::PIXEL_FORMAT_ARGB, capture_format_.frame_size.width());
|
| + image_info_ =
|
| + SkImageInfo::Make(size.width(), size.height(),
|
| + kBGRA_8888_SkColorType, kPremul_SkAlphaType);
|
| + last_size = size;
|
| + }
|
| +
|
| + image.readPixels(image_info_, &temp_data_[0], row_bytes_, 0, 0);
|
| + scoped_refptr<media::VideoFrame> video_frame =
|
| + frame_pool_.CreateFrame(media::PIXEL_FORMAT_I420, size, gfx::Rect(size),
|
| + size, base::TimeTicks::Now() - base::TimeTicks());
|
| + libyuv::ARGBToI420(temp_data_.data(), row_bytes_,
|
| + video_frame->data(media::VideoFrame::kYPlane),
|
| + video_frame->stride(media::VideoFrame::kYPlane),
|
| + video_frame->data(media::VideoFrame::kUPlane),
|
| + video_frame->stride(media::VideoFrame::kUPlane),
|
| + video_frame->data(media::VideoFrame::kVPlane),
|
| + video_frame->stride(media::VideoFrame::kVPlane),
|
| + size.width(), size.height());
|
| +
|
| + if (!delegate_)
|
| + return;
|
| + io_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&CanvasCaptureHandler::CanvasCaptureHandlerDelegate::
|
| + sendNewFrameOnIOThread,
|
| + base::Unretained(delegate_.get()), video_frame,
|
| + base::TimeTicks()));
|
| +}
|
| +
|
| +} // namespace content
|
|
|