Chromium Code Reviews| 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..c2e95728264655a541f099dbf1e88729c928c995 |
| --- /dev/null |
| +++ b/content/renderer/media/canvas_capture_handler.cc |
| @@ -0,0 +1,173 @@ |
| +// 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 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 { |
| + const blink::WebSize& size = canvas_handler_->GetSourceSize(); |
| + const media::VideoCaptureFormat format( |
| + gfx::Size(size.width, size.height), |
| + canvas_handler_->GetSourceFrameRate(), media::PIXEL_FORMAT_I420); |
| + media::VideoCaptureFormats formats; |
| + formats.push_back(format); |
| + callback.Run(formats); |
| + } |
| + 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_; |
| +}; |
| + |
| +class CanvasCaptureHandler::CanvasCaptureHandlerDelegate { |
| + public: |
| + explicit CanvasCaptureHandlerDelegate( |
| + media::VideoCapturerSource::VideoCaptureDeliverFrameCB new_frame_callback) |
| + : new_frame_callback_(new_frame_callback), |
| + weak_ptr_factory_(this) { |
| + thread_checker_.DetachFromThread(); |
| + } |
| + ~CanvasCaptureHandlerDelegate() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + } |
| + |
| + void SendNewFrameOnIOThread( |
| + const scoped_refptr<media::VideoFrame>& video_frame, |
| + const base::TimeTicks& current_time) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + new_frame_callback_.Run(video_frame, current_time); |
| + } |
| + |
| + base::WeakPtr<CanvasCaptureHandlerDelegate> GetWeakPtrForIOThread() { |
| + return weak_ptr_factory_.GetWeakPtr(); |
| + } |
| + |
| + private: |
| + const media::VideoCapturerSource::VideoCaptureDeliverFrameCB |
| + new_frame_callback_; |
| + base::ThreadChecker thread_checker_; |
| + base::WeakPtrFactory<CanvasCaptureHandlerDelegate> weak_ptr_factory_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(CanvasCaptureHandlerDelegate); |
| +}; |
| + |
| +CanvasCaptureHandler::CanvasCaptureHandler(const blink::WebSize& size, |
| + double frame_rate, |
| + blink::WebMediaStream* stream) |
| + : frame_rate_(frame_rate), |
| + ask_for_new_frame_(false), |
| + size_(size), |
| + io_task_runner_(content::RenderThread::Get()->GetIOMessageLoopProxy()) { |
| + scoped_ptr<media::VideoCapturerSource> video( |
| + new CanvasCaptureHandler::VideoCapturerSource(this)); |
|
perkj_chrome
2015/12/03 19:15:58
just inject the frame_rate here when you create Ca
emircan
2015/12/04 03:23:25
Done.
|
| + content::AddVideoTrackToMediaStream(video.Pass(), false, true, stream); |
| +} |
| + |
| +CanvasCaptureHandler::~CanvasCaptureHandler() { |
| + DVLOG(3) << __FUNCTION__; |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + io_task_runner_->DeleteSoon(FROM_HERE, delegate_.release()); |
| +} |
| + |
| +void CanvasCaptureHandler::sendNewFrame(const blink::WebSkImage& image) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + CreateNewFrame(image); |
| +} |
| + |
| +bool CanvasCaptureHandler::needsNewFrameCapture() const { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + 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; |
| + delegate_.reset(new CanvasCaptureHandlerDelegate(new_frame_callback)); |
| + DCHECK(delegate_); |
| + ask_for_new_frame_ = true; |
| + running_callback.Run(true); |
| +} |
| + |
| +void CanvasCaptureHandler::StopVideoCapture() { |
| + DVLOG(3) << __FUNCTION__; |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + ask_for_new_frame_ = false; |
| + io_task_runner_->DeleteSoon(FROM_HERE, delegate_.release()); |
| +} |
| + |
| +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()); |
| + |
| + io_task_runner_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&CanvasCaptureHandler::CanvasCaptureHandlerDelegate:: |
| + SendNewFrameOnIOThread, |
| + delegate_->GetWeakPtrForIOThread(), video_frame, |
| + base::TimeTicks())); |
| +} |
| + |
| +} // namespace content |