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

Side by Side Diff: content/renderer/media/image_capture_frame_grabber.cc

Issue 2739253003: Image Capture: Move files out of content/renderer/media to replicate WebKit's structure (Closed)
Patch Set: DEPS Created 3 years, 9 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/media/image_capture_frame_grabber.h"
6
7 #include "cc/paint/paint_canvas.h"
8 #include "cc/paint/paint_surface.h"
9 #include "media/base/bind_to_current_loop.h"
10 #include "media/base/video_frame.h"
11 #include "media/base/video_util.h"
12 #include "skia/ext/platform_canvas.h"
13 #include "third_party/WebKit/public/platform/WebCallbacks.h"
14 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
15 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
16 #include "third_party/libyuv/include/libyuv.h"
17 #include "third_party/skia/include/core/SkImage.h"
18
19 namespace content {
20
21 using blink::WebImageCaptureGrabFrameCallbacks;
22
23 namespace {
24
25 void OnError(std::unique_ptr<WebImageCaptureGrabFrameCallbacks> callbacks) {
26 callbacks->onError();
27 }
28
29 } // anonymous namespace
30
31 // Ref-counted class to receive a single VideoFrame on IO thread, convert it and
32 // send it to |main_task_runner_|, where this class is created and destroyed.
33 class ImageCaptureFrameGrabber::SingleShotFrameHandler
34 : public base::RefCountedThreadSafe<SingleShotFrameHandler> {
35 public:
36 SingleShotFrameHandler() : first_frame_received_(false) {}
37
38 // Receives a |frame| and converts its pixels into a SkImage via an internal
39 // PaintSurface and SkPixmap. Alpha channel, if any, is copied.
40 void OnVideoFrameOnIOThread(SkImageDeliverCB callback,
41 const scoped_refptr<media::VideoFrame>& frame,
42 base::TimeTicks current_time);
43
44 private:
45 friend class base::RefCountedThreadSafe<SingleShotFrameHandler>;
46 virtual ~SingleShotFrameHandler() {}
47
48 // Flag to indicate that the first frames has been processed, and subsequent
49 // ones can be safely discarded.
50 bool first_frame_received_;
51
52 DISALLOW_COPY_AND_ASSIGN(SingleShotFrameHandler);
53 };
54
55 void ImageCaptureFrameGrabber::SingleShotFrameHandler::OnVideoFrameOnIOThread(
56 SkImageDeliverCB callback,
57 const scoped_refptr<media::VideoFrame>& frame,
58 base::TimeTicks /* current_time */) {
59 DCHECK(frame->format() == media::PIXEL_FORMAT_YV12 ||
60 frame->format() == media::PIXEL_FORMAT_I420 ||
61 frame->format() == media::PIXEL_FORMAT_YV12A);
62
63 if (first_frame_received_)
64 return;
65 first_frame_received_ = true;
66
67 const SkAlphaType alpha = media::IsOpaque(frame->format())
68 ? kOpaque_SkAlphaType
69 : kPremul_SkAlphaType;
70 const SkImageInfo info = SkImageInfo::MakeN32(
71 frame->visible_rect().width(), frame->visible_rect().height(), alpha);
72
73 sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
74 DCHECK(surface);
75
76 SkPixmap pixmap;
77 if (!skia::GetWritablePixels(surface->getCanvas(), &pixmap)) {
78 DLOG(ERROR) << "Error trying to map SkSurface's pixels";
79 callback.Run(sk_sp<SkImage>());
80 return;
81 }
82
83 const uint32 destination_pixel_format =
84 (kN32_SkColorType == kRGBA_8888_SkColorType) ? libyuv::FOURCC_ABGR
85 : libyuv::FOURCC_ARGB;
86
87 libyuv::ConvertFromI420(frame->visible_data(media::VideoFrame::kYPlane),
88 frame->stride(media::VideoFrame::kYPlane),
89 frame->visible_data(media::VideoFrame::kUPlane),
90 frame->stride(media::VideoFrame::kUPlane),
91 frame->visible_data(media::VideoFrame::kVPlane),
92 frame->stride(media::VideoFrame::kVPlane),
93 static_cast<uint8*>(pixmap.writable_addr()),
94 pixmap.width() * 4, pixmap.width(), pixmap.height(),
95 destination_pixel_format);
96
97 if (frame->format() == media::PIXEL_FORMAT_YV12A) {
98 DCHECK(!info.isOpaque());
99 // This function copies any plane into the alpha channel of an ARGB image.
100 libyuv::ARGBCopyYToAlpha(frame->visible_data(media::VideoFrame::kAPlane),
101 frame->stride(media::VideoFrame::kAPlane),
102 static_cast<uint8*>(pixmap.writable_addr()),
103 pixmap.width() * 4, pixmap.width(),
104 pixmap.height());
105 }
106
107 callback.Run(surface->makeImageSnapshot());
108 }
109
110 ImageCaptureFrameGrabber::ImageCaptureFrameGrabber()
111 : frame_grab_in_progress_(false), weak_factory_(this) {}
112
113 ImageCaptureFrameGrabber::~ImageCaptureFrameGrabber() {
114 DCHECK(thread_checker_.CalledOnValidThread());
115 }
116
117 void ImageCaptureFrameGrabber::grabFrame(
118 blink::WebMediaStreamTrack* track,
119 WebImageCaptureGrabFrameCallbacks* callbacks) {
120 DCHECK(thread_checker_.CalledOnValidThread());
121 DCHECK(!!callbacks);
122
123 DCHECK(track && !track->isNull() && track->getTrackData());
124 DCHECK_EQ(blink::WebMediaStreamSource::TypeVideo, track->source().getType());
125
126 if (frame_grab_in_progress_) {
127 // Reject grabFrame()s too close back to back.
128 callbacks->onError();
129 return;
130 }
131
132 ScopedWebCallbacks<WebImageCaptureGrabFrameCallbacks> scoped_callbacks =
133 make_scoped_web_callbacks(callbacks, base::Bind(&OnError));
134
135 // A SingleShotFrameHandler is bound and given to the Track to guarantee that
136 // only one VideoFrame is converted and delivered to OnSkImage(), otherwise
137 // SKImages might be sent to resolved |callbacks| while DisconnectFromTrack()
138 // is being processed, which might be further held up if UI is busy, see
139 // https://crbug.com/623042.
140 frame_grab_in_progress_ = true;
141 MediaStreamVideoSink::ConnectToTrack(
142 *track, base::Bind(&SingleShotFrameHandler::OnVideoFrameOnIOThread,
143 make_scoped_refptr(new SingleShotFrameHandler),
144 media::BindToCurrentLoop(
145 base::Bind(&ImageCaptureFrameGrabber::OnSkImage,
146 weak_factory_.GetWeakPtr(),
147 base::Passed(&scoped_callbacks)))),
148 false);
149 }
150
151 void ImageCaptureFrameGrabber::OnSkImage(
152 ScopedWebCallbacks<blink::WebImageCaptureGrabFrameCallbacks> callbacks,
153 sk_sp<SkImage> image) {
154 DCHECK(thread_checker_.CalledOnValidThread());
155
156 MediaStreamVideoSink::DisconnectFromTrack();
157 frame_grab_in_progress_ = false;
158 if (image)
159 callbacks.PassCallbacks()->onSuccess(image);
160 else
161 callbacks.PassCallbacks()->onError();
162 }
163
164 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698