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..769dad1df3da661ae55831e998fd7537360d702a |
| --- /dev/null |
| +++ b/content/renderer/media/canvas_capture_handler.cc |
| @@ -0,0 +1,174 @@ |
| +// 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(const scoped_refptr<CanvasCaptureHandler> |
| + canvas_handler) |
|
perkj_chrome
2015/11/26 18:52:14
Have you tried git cl format?
emircan
2015/12/01 00:25:44
Fixed it. I am using clang-format:Chromium on Ecli
|
| + : 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. |
| + scoped_refptr<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( |
| + scoped_refptr<CanvasCaptureHandler>(this))); |
| + content::AddVideoTrackToMediaStream(video.Pass(), false, false, stream); |
|
perkj_chrome
2015/11/26 18:52:14
I think you should mark this as read_only. Ie - yo
emircan
2015/12/01 00:25:44
Done.
|
| +} |
| + |
| +CanvasCaptureHandler::~CanvasCaptureHandler() { |
| + DVLOG(3) << __FUNCTION__; |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| +} |
| + |
| +void CanvasCaptureHandler::sendNewFrame(const blink::WebSkImage& image) { |
| + createNewFrame(image); |
|
perkj_chrome
2015/11/26 18:52:14
add thread checker
emircan
2015/12/01 00:25:45
Done.
|
| +} |
| + |
| +bool CanvasCaptureHandler::needsNewFrameCapture() const { |
| + return ask_for_new_frame_; |
|
perkj_chrome
2015/11/26 18:52:14
add thread checker
perkj_chrome
2015/11/26 18:52:14
ask_for_new_frame_ this seems to be unnessecary?
emircan
2015/12/01 00:25:44
When CanvasCaptureHandler::VideoCapturerSource::St
emircan
2015/12/01 00:25:44
Done.
|
| +} |
| + |
| +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_ = |
| + make_scoped_ptr(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; |
| + 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, |
|
perkj_chrome
2015/11/26 18:52:14
This does not seem to be safe. You post to the io
emircan
2015/12/01 00:25:45
Thanks for pointing out. Added a weak_ptr for the
|
| + base::TimeTicks())); |
| +} |
| + |
| +} // namespace content |