Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2162)

Unified Diff: content/renderer/media/image_capture_frame_grabber.cc

Issue 1899403002: MediaStream Image Capture (2): Platform::ImageCaptureFrameGrabber and grabFrame() (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. LayoutTests: Replace assert_array_equals with an for-each: assert_aprox_equals Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/renderer/media/image_capture_frame_grabber.cc
diff --git a/content/renderer/media/image_capture_frame_grabber.cc b/content/renderer/media/image_capture_frame_grabber.cc
new file mode 100644
index 0000000000000000000000000000000000000000..af3a5f19efe7e007484bec65f77904137b046e8d
--- /dev/null
+++ b/content/renderer/media/image_capture_frame_grabber.cc
@@ -0,0 +1,121 @@
+// Copyright 2016 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/image_capture_frame_grabber.h"
+
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_util.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/WebKit/public/platform/WebCallbacks.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/libyuv/include/libyuv.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkSurface.h"
+
+namespace content {
+
+using blink::WebImageCaptureGrabFrameCallbacks;
+
+namespace {
+
+void OnError(std::unique_ptr<WebImageCaptureGrabFrameCallbacks> callbacks) {
+ callbacks->onError();
+}
+
+// This internal method receives a |frame| and converts its pixels into a
+// SkImage via an internal SkSurface and SkPixmap. Alpha channel, if any, is
+// copied.
+void OnVideoFrame(const ImageCaptureFrameGrabber::SkImageDeliverCB& callback,
+ const scoped_refptr<media::VideoFrame>& frame,
+ base::TimeTicks /* current_time */) {
+ DCHECK(frame->format() == media::PIXEL_FORMAT_YV12 ||
+ frame->format() == media::PIXEL_FORMAT_I420 ||
+ frame->format() == media::PIXEL_FORMAT_YV12A);
+
+ const SkAlphaType alpha = media::IsOpaque(frame->format())
+ ? kOpaque_SkAlphaType
+ : kPremul_SkAlphaType;
+ const SkImageInfo info = SkImageInfo::MakeN32(
+ frame->visible_rect().width(), frame->visible_rect().height(), alpha);
+
+ sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
+ DCHECK(surface);
+
+ SkPixmap pixmap;
+ if (!skia::GetWritablePixels(surface->getCanvas(), &pixmap)) {
+ DLOG(ERROR) << "Error trying to map SkSurface's pixels";
+ callback.Run(sk_sp<SkImage>());
+ return;
+ }
+
+ libyuv::I420ToARGB(frame->visible_data(media::VideoFrame::kYPlane),
+ frame->stride(media::VideoFrame::kYPlane),
+ frame->visible_data(media::VideoFrame::kUPlane),
+ frame->stride(media::VideoFrame::kUPlane),
+ frame->visible_data(media::VideoFrame::kVPlane),
+ frame->stride(media::VideoFrame::kVPlane),
+ static_cast<uint8*>(pixmap.writable_addr()),
+ pixmap.width() * 4, pixmap.width(), pixmap.height());
+
+ if (frame->format() == media::PIXEL_FORMAT_YV12A) {
+ DCHECK(!info.isOpaque());
+ // This function copies any plane into the alpha channel of an ARGB image.
+ libyuv::ARGBCopyYToAlpha(frame->visible_data(media::VideoFrame::kAPlane),
+ frame->stride(media::VideoFrame::kAPlane),
+ static_cast<uint8*>(pixmap.writable_addr()),
+ pixmap.width() * 4, pixmap.width(),
+ pixmap.height());
+ }
+
+ callback.Run(surface->makeImageSnapshot());
+}
+
+} // anonymous namespace
+
+ImageCaptureFrameGrabber::ImageCaptureFrameGrabber() : weak_factory_(this) {}
+
+ImageCaptureFrameGrabber::~ImageCaptureFrameGrabber() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void ImageCaptureFrameGrabber::grabFrame(
+ blink::WebMediaStreamTrack* track,
+ WebImageCaptureGrabFrameCallbacks* callbacks) {
+ DVLOG(1) << __FUNCTION__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!!callbacks);
+
+ DCHECK(track && !track->isNull() && track->getExtraData());
+ DCHECK_EQ(blink::WebMediaStreamSource::TypeVideo, track->source().getType());
+
+ ScopedWebCallbacks<WebImageCaptureGrabFrameCallbacks> scoped_callbacks =
+ make_scoped_web_callbacks(callbacks, base::Bind(&OnError));
+
+ // ConnectToTrack() must happen on render's Main Thread, whereas VideoFrames
+ // are delivered on a background thread though, so we Bind the callback to our
+ // current thread.
+ MediaStreamVideoSink::ConnectToTrack(
+ *track,
+ base::Bind(&OnVideoFrame, media::BindToCurrentLoop(base::Bind(
+ &ImageCaptureFrameGrabber::OnSkImage,
+ weak_factory_.GetWeakPtr(),
+ base::Passed(&scoped_callbacks)))));
+}
+
+void ImageCaptureFrameGrabber::OnSkImage(
+ ScopedWebCallbacks<WebImageCaptureGrabFrameCallbacks> callbacks,
+ sk_sp<SkImage> image) {
+ DVLOG(1) << __FUNCTION__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ MediaStreamVideoSink::DisconnectFromTrack();
+ if (image)
+ callbacks.PassCallbacks()->onSuccess(image);
+ else
+ callbacks.PassCallbacks()->onError();
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698