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

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

Issue 1917023003: ScreenCapture for Android phase1, part I (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: relocate java files, support YUV format and improve JNI operation Created 4 years, 7 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 "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 width,
42 jint height,
43 jint rowStride,
44 jlong timestamp) {
45 const VideoCaptureOracle::Event event = VideoCaptureOracle::kCompositorUpdate;
46 uint64_t absolute_micro =
47 static_cast<int64>(timestamp / base::Time::kNanosecondsPerMicrosecond);
48 const base::TimeTicks start_time =
49 base::TimeTicks::FromInternalValue(absolute_micro);
50 scoped_refptr<VideoFrame> frame;
51 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
52
53 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture(
54 event, gfx::Rect(), start_time, &frame, &capture_frame_cb);
55
56 if (!oracle_decision)
57 return;
58
59 uint8* source_data =
60 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buf));
61 int source_stride = rowStride;
mcasas 2016/05/19 19:11:41 Why not use |rowStride| directly? Consider renamin
braveyao 2016/05/20 22:27:25 Because the stride might be changed below at l.73.
62
63 // If needed, scale the captured frame to the required size.
64 if (gfx::Size(width, height) != frame->visible_rect().size()) {
65 std::unique_ptr<uint8[]> scaled_frame_data;
66 scaled_frame_data.reset(new uint8[frame->visible_rect().width() *
67 frame->visible_rect().height() * 4]);
68 libyuv::ARGBScale(
69 source_data, source_stride, width, height, scaled_frame_data.get(),
70 frame->visible_rect().width() * 4, frame->visible_rect().width(),
71 frame->visible_rect().height(), libyuv::kFilterBilinear);
72 source_data = scaled_frame_data.get();
73 source_stride = frame->visible_rect().width() * 4;
74 }
75
76 DCHECK(frame->format() == PIXEL_FORMAT_I420 ||
77 frame->format() == PIXEL_FORMAT_YV12);
78
79 ConvertRGB32ToYUV(
mcasas 2016/05/19 19:11:41 Why not use libyuv here as well [1] ? [1] https:/
braveyao 2016/05/20 22:27:25 Done.
80 source_data, frame->visible_data(VideoFrame::kYPlane),
81 frame->visible_data(VideoFrame::kUPlane),
82 frame->visible_data(VideoFrame::kVPlane), frame->visible_rect().width(),
83 frame->visible_rect().height(), source_stride,
84 frame->stride(VideoFrame::kYPlane), frame->stride(VideoFrame::kUPlane));
mcasas 2016/05/19 19:11:41 It'd be possible that the if{} in l.64-74 would be
braveyao 2016/05/20 22:27:25 Refactored the processing here. The previous l.64-
85
86 // Deliver the populated VideoFrame.
87 capture_frame_cb.Run(frame, start_time, true);
88
89 lastFrame_ = frame;
90 }
91
92 void ScreenCaptureMachineAndroid::OnI420FrameAvailable(JNIEnv* env,
93 jobject obj,
94 jobject y_buffer,
95 jint y_stride,
96 jobject u_buffer,
97 jint u_stride,
98 jobject v_buffer,
99 jint v_stride,
100 jint width,
101 jint height,
102 jlong timestamp) {
103 const VideoCaptureOracle::Event event = VideoCaptureOracle::kCompositorUpdate;
104 uint64_t absolute_micro =
mcasas 2016/05/19 19:11:41 const
braveyao 2016/05/20 22:27:25 Done.
105 static_cast<int64>(timestamp / base::Time::kNanosecondsPerMicrosecond);
106 const base::TimeTicks start_time =
107 base::TimeTicks::FromInternalValue(absolute_micro);
108 scoped_refptr<VideoFrame> frame;
109 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
110
111 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture(
mcasas 2016/05/19 19:11:41 const? Or fold it into l.114.
braveyao 2016/05/20 22:27:26 Done.
112 event, gfx::Rect(), start_time, &frame, &capture_frame_cb);
113
114 if (!oracle_decision)
115 return;
116
117 uint8 *y_src, *u_src, *v_src;
118 y_src = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(y_buffer));
119 CHECK(y_src);
120 u_src = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(u_buffer));
121 CHECK(u_src);
122 v_src = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(v_buffer));
123 CHECK(v_src);
124
125 // U and V planes have |pixelStride| = 2, unpack them here.
126 int uv_plane_len = (int)env->GetDirectBufferCapacity(u_buffer);
127 for (int index = 0; index * 2 <= uv_plane_len; index++) {
128 u_src[index] = u_src[index * 2];
129 v_src[index] = v_src[index * 2];
130 }
131
132 libyuv::I420Scale(y_src, y_stride, u_src, u_stride, v_src, v_stride, width,
133 height, frame->visible_data(VideoFrame::kYPlane),
134 frame->stride(VideoFrame::kYPlane),
135 frame->visible_data(VideoFrame::kUPlane),
136 frame->stride(VideoFrame::kUPlane),
137 frame->visible_data(VideoFrame::kVPlane),
138 frame->stride(VideoFrame::kVPlane),
139 frame->visible_rect().width(),
140 frame->visible_rect().height(), libyuv::kFilterBilinear);
141
142 // Deliver the populated VideoFrame.
143 capture_frame_cb.Run(frame, start_time, true);
144
145 lastFrame_ = frame;
146 }
147
148 void ScreenCaptureMachineAndroid::OnActivityResult(JNIEnv* env,
149 jobject obj,
150 jboolean result) {
151 if (!result) {
152 oracle_proxy_->ReportError(FROM_HERE, "The user denied screen capture");
153 return;
154 }
155
156 Java_ScreenCapture_startCapture(env, obj);
157 }
158
159 void ScreenCaptureMachineAndroid::Start(
160 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
161 const VideoCaptureParams& params,
162 const base::Callback<void(bool)> callback) {
163 DCHECK(oracle_proxy.get());
164 oracle_proxy_ = oracle_proxy;
165
166 j_capture_.Reset(
167 createScreenCaptureMachineAndroid(reinterpret_cast<intptr_t>(this)));
168
169 if (j_capture_.obj() == NULL) {
mcasas 2016/05/19 19:11:41 s/NULL/nullptr/
braveyao 2016/05/20 22:27:26 Done.
170 LOG(ERROR) << "Failed to createScreenCaptureAndroid,"
171 " Maybe android version is too low";
172 callback.Run(false);
173 return;
174 }
175
176 DCHECK(params.requested_format.frame_size.GetArea() > 0);
mcasas 2016/05/19 19:11:41 No need for |> 0|.
braveyao 2016/05/20 22:27:25 Done.
177 DCHECK(!(params.requested_format.frame_size.width() % 2));
178 DCHECK(!(params.requested_format.frame_size.height() % 2));
179
180 jboolean ret = Java_ScreenCapture_startPrompt(
mcasas 2016/05/19 19:11:41 const
braveyao 2016/05/20 22:27:26 Done.
181 AttachCurrentThread(), j_capture_.obj(),
182 params.requested_format.frame_size.width(),
183 params.requested_format.frame_size.height());
184 if (!ret) {
mcasas 2016/05/19 19:11:41 Substitute l.184-189 with callback.Run(ret);
braveyao 2016/05/20 22:27:26 Done.
185 callback.Run(false);
186 return;
187 }
188
189 callback.Run(true);
190 }
191
192 void ScreenCaptureMachineAndroid::Stop(const base::Closure& callback) {
193 Java_ScreenCapture_stopCapture(AttachCurrentThread(), j_capture_.obj());
194
195 callback.Run();
196 }
197
198 // ScreenCapture on Android works in passive way and there will be no captured
199 // frame when there is no update to the screen. When oracle asks capturing for
200 // refresh, the cached last frame will be delivered.
201 void ScreenCaptureMachineAndroid::MaybeCaptureForRefresh() {
202 if (lastFrame_.get() == NULL)
mcasas 2016/05/19 19:11:41 s/NULL/nullptr/ I think you can also say if(!last
braveyao 2016/05/20 22:27:26 Done.
203 return;
204
205 const VideoCaptureOracle::Event event = VideoCaptureOracle::kCompositorUpdate;
206 const base::TimeTicks start_time = base::TimeTicks::Now();
207 scoped_refptr<VideoFrame> frame;
208 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
209
210 if (oracle_proxy_->ObserveEventAndDecideCapture(
211 event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) {
212 // Deliver the last VideoFrame.
mcasas 2016/05/19 19:11:41 nit: Suggest something like: // Deliver again the
braveyao 2016/05/20 22:27:25 Done.
213 frame = lastFrame_;
214 capture_frame_cb.Run(frame, start_time, true);
215 }
216 }
217
218 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698