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

Side by Side Diff: media/capture/content/android/screen_capture_machine_android.cc

Issue 2125973002: Reland: ScreenCapture for Android phase1, part I (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add dependency to mojo/interfaces:image_capture Created 4 years, 5 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
« no previous file with comments | « media/capture/content/android/screen_capture_machine_android.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "media/capture/content/android/screen_capture_machine_android.h"
6
7 #include "base/android/context_utils.h"
8 #include "base/android/jni_android.h"
9 #include "base/android/scoped_java_ref.h"
10 #include "jni/ScreenCapture_jni.h"
11 #include "media/base/video_capture_types.h"
12 #include "media/base/yuv_convert.h"
13 #include "media/capture/content/video_capture_oracle.h"
14 #include "third_party/libyuv/include/libyuv.h"
15
16 using base::android::AttachCurrentThread;
17
18 namespace media {
19
20 // static
21 bool ScreenCaptureMachineAndroid::RegisterScreenCaptureMachine(JNIEnv* env) {
22 return RegisterNativesImpl(env);
23 }
24
25 ScreenCaptureMachineAndroid::ScreenCaptureMachineAndroid() {}
26
27 ScreenCaptureMachineAndroid::~ScreenCaptureMachineAndroid() {}
28
29 // static
30 ScopedJavaLocalRef<jobject>
31 ScreenCaptureMachineAndroid::createScreenCaptureMachineAndroid(
32 jlong nativeScreenCaptureMachineAndroid) {
33 return (Java_ScreenCapture_createScreenCaptureMachine(
34 AttachCurrentThread(), base::android::GetApplicationContext(),
35 nativeScreenCaptureMachineAndroid));
36 }
37
38 void ScreenCaptureMachineAndroid::OnRGBAFrameAvailable(JNIEnv* env,
39 jobject obj,
40 jobject buf,
41 jint row_stride,
42 jint left,
43 jint top,
44 jint width,
45 jint height,
46 jlong timestamp) {
47 const VideoCaptureOracle::Event event = VideoCaptureOracle::kCompositorUpdate;
48 const uint64_t absolute_micro =
49 timestamp / base::Time::kNanosecondsPerMicrosecond;
50 const base::TimeTicks start_time =
51 base::TimeTicks() + base::TimeDelta::FromMicroseconds(absolute_micro);
52 scoped_refptr<VideoFrame> frame;
53 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
54
55 if (!oracle_proxy_->ObserveEventAndDecideCapture(
56 event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) {
57 return;
58 }
59
60 DCHECK(frame->format() == PIXEL_FORMAT_I420 ||
61 frame->format() == PIXEL_FORMAT_YV12);
62
63 scoped_refptr<VideoFrame> unscaled_frame = frame;
64 if (frame->visible_rect().width() != width ||
65 frame->visible_rect().height() != height) {
66 unscaled_frame = VideoFrame::CreateFrame(
67 PIXEL_FORMAT_I420, gfx::Size(width, height), gfx::Rect(width, height),
68 gfx::Size(width, height), base::TimeDelta());
69 }
70
71 uint8_t* const src =
72 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buf));
73 CHECK(src);
74
75 const int offset = top * row_stride + left * 4;
76 // ABGR little endian (rgba in memory) to I420.
77 libyuv::ABGRToI420(src + offset, row_stride,
78 unscaled_frame->visible_data(VideoFrame::kYPlane),
79 unscaled_frame->stride(VideoFrame::kYPlane),
80 unscaled_frame->visible_data(VideoFrame::kUPlane),
81 unscaled_frame->stride(VideoFrame::kUPlane),
82 unscaled_frame->visible_data(VideoFrame::kVPlane),
83 unscaled_frame->stride(VideoFrame::kVPlane),
84 unscaled_frame->visible_rect().width(),
85 unscaled_frame->visible_rect().height());
86
87 if (unscaled_frame != frame) {
88 libyuv::I420Scale(unscaled_frame->visible_data(VideoFrame::kYPlane),
89 unscaled_frame->stride(VideoFrame::kYPlane),
90 unscaled_frame->visible_data(VideoFrame::kUPlane),
91 unscaled_frame->stride(VideoFrame::kUPlane),
92 unscaled_frame->visible_data(VideoFrame::kVPlane),
93 unscaled_frame->stride(VideoFrame::kVPlane),
94 unscaled_frame->visible_rect().width(),
95 unscaled_frame->visible_rect().height(),
96 frame->visible_data(VideoFrame::kYPlane),
97 frame->stride(VideoFrame::kYPlane),
98 frame->visible_data(VideoFrame::kUPlane),
99 frame->stride(VideoFrame::kUPlane),
100 frame->visible_data(VideoFrame::kVPlane),
101 frame->stride(VideoFrame::kVPlane),
102 frame->visible_rect().width(),
103 frame->visible_rect().height(), libyuv::kFilterBilinear);
104 }
105
106 capture_frame_cb.Run(frame, start_time, true);
107
108 lastFrame_ = frame;
109 }
110
111 void ScreenCaptureMachineAndroid::OnI420FrameAvailable(JNIEnv* env,
112 jobject obj,
113 jobject y_buffer,
114 jint y_stride,
115 jobject u_buffer,
116 jobject v_buffer,
117 jint uv_row_stride,
118 jint uv_pixel_stride,
119 jint left,
120 jint top,
121 jint width,
122 jint height,
123 jlong timestamp) {
124 const VideoCaptureOracle::Event event = VideoCaptureOracle::kCompositorUpdate;
125 const uint64_t absolute_micro =
126 timestamp / base::Time::kNanosecondsPerMicrosecond;
127 const base::TimeTicks start_time =
128 base::TimeTicks() + base::TimeDelta::FromMicroseconds(absolute_micro);
129 scoped_refptr<VideoFrame> frame;
130 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
131
132 if (!oracle_proxy_->ObserveEventAndDecideCapture(
133 event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) {
134 return;
135 }
136
137 DCHECK(frame->format() == PIXEL_FORMAT_I420 ||
138 frame->format() == PIXEL_FORMAT_YV12);
139
140 uint8_t* const y_src =
141 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(y_buffer));
142 CHECK(y_src);
143 uint8_t* u_src =
144 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(u_buffer));
145 CHECK(u_src);
146 uint8_t* v_src =
147 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(v_buffer));
148 CHECK(v_src);
149
150 // De-interleave the U and V planes into temporary buffers, if needed.
151 int uv_stride = uv_row_stride;
152 std::unique_ptr<uint8_t[]> u_tmp, v_tmp;
153 if (uv_pixel_stride != 1) {
154 // U and V planes are actually interleaved, unpack them here.
155 // TODO(braveyao): According to
156 // https://developer.android.com/reference/android/graphics/ImageFormat.html #YUV_420_888,
157 // how U and V planes are interlaced is not guaranteed, so there is no an
158 // existing libyuv function suitable for such a job. Filed a request at
159 // https://bugs.chromium.org/p/libyuv/issues/detail?id=604. Switch to new
160 // function when it's available.
161 const int uv_plane_len = (int)env->GetDirectBufferCapacity(u_buffer);
162 u_tmp.reset(new uint8_t[(uv_plane_len + 1) / uv_pixel_stride]);
163 v_tmp.reset(new uint8_t[(uv_plane_len + 1) / uv_pixel_stride]);
164 for (int index = 0; index * uv_pixel_stride <= uv_plane_len; index++) {
165 u_tmp[index] = u_src[index * uv_pixel_stride];
166 v_tmp[index] = v_src[index * uv_pixel_stride];
167 }
168 u_src = u_tmp.get();
169 v_src = v_tmp.get();
170 uv_stride /= uv_pixel_stride;
171 }
172
173 const int y_offset = top * y_stride + left;
174 const int uv_offset = (top / 2) * uv_stride + left / 2;
175 // Note: If source width/height are same as the frame's width/height, the
176 // following will, internally, just perform a copy without scaling.
177 libyuv::I420Scale(y_src + y_offset, y_stride, u_src + uv_offset, uv_stride,
178 v_src + uv_offset, uv_stride, width, height,
179 frame->visible_data(VideoFrame::kYPlane),
180 frame->stride(VideoFrame::kYPlane),
181 frame->visible_data(VideoFrame::kUPlane),
182 frame->stride(VideoFrame::kUPlane),
183 frame->visible_data(VideoFrame::kVPlane),
184 frame->stride(VideoFrame::kVPlane),
185 frame->visible_rect().width(),
186 frame->visible_rect().height(), libyuv::kFilterBilinear);
187
188 capture_frame_cb.Run(frame, start_time, true);
189
190 lastFrame_ = frame;
191 }
192
193 void ScreenCaptureMachineAndroid::OnActivityResult(JNIEnv* env,
194 jobject obj,
195 jboolean result) {
196 if (!result) {
197 oracle_proxy_->ReportError(FROM_HERE, "The user denied screen capture");
198 return;
199 }
200
201 Java_ScreenCapture_startCapture(env, obj);
202 }
203
204 void ScreenCaptureMachineAndroid::Start(
205 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
206 const VideoCaptureParams& params,
207 const base::Callback<void(bool)> callback) {
208 DCHECK(oracle_proxy.get());
209 oracle_proxy_ = oracle_proxy;
210
211 j_capture_.Reset(
212 createScreenCaptureMachineAndroid(reinterpret_cast<intptr_t>(this)));
213
214 if (j_capture_.obj() == nullptr) {
215 DLOG(ERROR) << "Failed to createScreenCaptureAndroid";
216 callback.Run(false);
217 return;
218 }
219
220 DCHECK(params.requested_format.frame_size.GetArea());
221 DCHECK(!(params.requested_format.frame_size.width() % 2));
222 DCHECK(!(params.requested_format.frame_size.height() % 2));
223
224 const jboolean ret = Java_ScreenCapture_startPrompt(
225 AttachCurrentThread(), j_capture_.obj(),
226 params.requested_format.frame_size.width(),
227 params.requested_format.frame_size.height());
228
229 callback.Run(ret);
230 }
231
232 void ScreenCaptureMachineAndroid::Stop(const base::Closure& callback) {
233 Java_ScreenCapture_stopCapture(AttachCurrentThread(), j_capture_.obj());
234
235 callback.Run();
236 }
237
238 // ScreenCapture on Android works in a passive way and there are no captured
239 // frames when there is no update to the screen. When the oracle asks for a
240 // capture refresh, the cached captured frame is redelivered.
241 void ScreenCaptureMachineAndroid::MaybeCaptureForRefresh() {
242 if (lastFrame_.get() == nullptr)
243 return;
244
245 const VideoCaptureOracle::Event event =
246 VideoCaptureOracle::kActiveRefreshRequest;
247 const base::TimeTicks start_time = base::TimeTicks::Now();
248 scoped_refptr<VideoFrame> frame;
249 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
250
251 if (!oracle_proxy_->ObserveEventAndDecideCapture(
252 event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) {
253 return;
254 }
255
256 DCHECK(frame->format() == PIXEL_FORMAT_I420 ||
257 frame->format() == PIXEL_FORMAT_YV12);
258
259 libyuv::I420Scale(
260 lastFrame_->visible_data(VideoFrame::kYPlane),
261 lastFrame_->stride(VideoFrame::kYPlane),
262 lastFrame_->visible_data(VideoFrame::kUPlane),
263 lastFrame_->stride(VideoFrame::kUPlane),
264 lastFrame_->visible_data(VideoFrame::kVPlane),
265 lastFrame_->stride(VideoFrame::kVPlane),
266 lastFrame_->visible_rect().width(), lastFrame_->visible_rect().height(),
267 frame->visible_data(VideoFrame::kYPlane),
268 frame->stride(VideoFrame::kYPlane),
269 frame->visible_data(VideoFrame::kUPlane),
270 frame->stride(VideoFrame::kUPlane),
271 frame->visible_data(VideoFrame::kVPlane),
272 frame->stride(VideoFrame::kVPlane), frame->visible_rect().width(),
273 frame->visible_rect().height(), libyuv::kFilterBilinear);
274
275 capture_frame_cb.Run(frame, start_time, true);
276 }
277
278 } // namespace media
OLDNEW
« no previous file with comments | « media/capture/content/android/screen_capture_machine_android.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698