Index: media/screen_capture/android/screen_capture_machine_android.cc |
diff --git a/media/screen_capture/android/screen_capture_machine_android.cc b/media/screen_capture/android/screen_capture_machine_android.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2044df340b4bad0dc9c3576ae300f6633ac21c29 |
--- /dev/null |
+++ b/media/screen_capture/android/screen_capture_machine_android.cc |
@@ -0,0 +1,159 @@ |
+// 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 "media/screen_capture/android/screen_capture_machine_android.h" |
+ |
+#include "base/android/jni_android.h" |
+#include "base/android/scoped_java_ref.h" |
+#include "content/browser/media/capture/video_capture_oracle.h" |
+#include "jni/ScreenCapture_jni.h" |
+#include "media/base/video_capture_types.h" |
+#include "media/base/yuv_convert.h" |
+#include "media/screen_capture/android/screen_capture_factory_android.h" |
+#include "third_party/libyuv/include/libyuv.h" |
+ |
+using base::android::AttachCurrentThread; |
+ |
+namespace media { |
+ |
+// static |
+bool ScreenCaptureMachineAndroid::RegisterScreenCaptureMachine(JNIEnv* env) { |
+ return media::RegisterNativesImpl(env); |
+} |
+ |
+ |
+ScreenCaptureMachineAndroid::ScreenCaptureMachineAndroid() {} |
+ |
+ScreenCaptureMachineAndroid::~ScreenCaptureMachineAndroid() {} |
+ |
+void ScreenCaptureMachineAndroid::OnFrameAvailable(JNIEnv* env, |
+ jobject obj, |
+ jbyteArray data, |
+ jint cropWidth, |
+ jint cropHeight, |
+ jlong timestamp) { |
+ const content::VideoCaptureOracle::Event event = |
+ content::VideoCaptureOracle::kCompositorUpdate; |
+ uint64_t absolute_micro = |
+ static_cast<int64>(timestamp / base::Time::kNanosecondsPerMicrosecond); |
+ const base::TimeTicks start_time = |
+ base::TimeTicks::FromInternalValue(absolute_micro); |
+ scoped_refptr<media::VideoFrame> frame; |
+ content::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; |
+ |
+ bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture( |
+ event, gfx::Rect(), start_time, &frame, &capture_frame_cb); |
+ |
+ if (!oracle_decision) { |
whywhat
2015/08/17 13:58:46
nit: no need for {} for a one line if statement.
|
+ return; |
+ } |
+ |
+ jbyte* buffer = env->GetByteArrayElements(data, NULL); |
+ if (!buffer) { |
+ return; |
whywhat
2015/08/17 13:58:46
ditto
|
+ } |
+ |
+ uint8* source_argb = reinterpret_cast<uint8_t*>(buffer); |
+ int source_stride = cropWidth * 4; |
+ // If needed, scale the captured frame to the required size. |
+ if (gfx::Size(cropWidth, cropHeight) != frame->visible_rect().size()) { |
+ scoped_ptr<uint8[]> scaled_frame_data; |
+ scaled_frame_data.reset(new uint8[ |
+ frame->visible_rect().width() * frame->visible_rect().height() * 4]); |
+ libyuv::ARGBScale(source_argb, |
+ source_stride, |
+ cropWidth, |
+ cropHeight, |
+ scaled_frame_data.get(), |
+ frame->visible_rect().width() * 4, |
+ frame->visible_rect().width(), |
+ frame->visible_rect().height(), |
+ libyuv::kFilterBilinear); |
+ source_argb = scaled_frame_data.get(); |
+ source_stride = frame->visible_rect().width() * 4; |
+ } |
+ |
+ // Populate the VideoFrame. |
+ DCHECK(frame->format() == media::VideoFrame::I420 || |
+ frame->format() == media::VideoFrame::YV12); |
+ |
+ media::ConvertRGB32ToYUV(source_argb, |
+ frame->visible_data(media::VideoFrame::kYPlane), |
+ frame->visible_data(media::VideoFrame::kUPlane), |
+ frame->visible_data(media::VideoFrame::kVPlane), |
+ frame->visible_rect().width(), |
+ frame->visible_rect().height(), |
+ source_stride, |
+ frame->stride(media::VideoFrame::kYPlane), |
+ frame->stride(media::VideoFrame::kUPlane)); |
+ |
+ // Deliver the populated VideoFrame. |
+ capture_frame_cb.Run(frame, start_time, true); |
+ |
+ env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); |
+} |
+ |
+void ScreenCaptureMachineAndroid::OnActivityResult(JNIEnv* env, |
+ jobject obj, |
+ jint result) { |
+ if (result == 0) { |
+ oracle_proxy_->ReportError("The user denied screen capture"); |
+ return; |
+ } |
+ |
+ media::Java_ScreenCapture_startCapture(env, obj); |
+} |
+ |
+void ScreenCaptureMachineAndroid::Start( |
+ const scoped_refptr<content::ThreadSafeCaptureOracle>& oracle_proxy, |
+ const media::VideoCaptureParams& params, |
+ const base::Callback<void(bool)> callback) { |
+ DCHECK(oracle_proxy.get()); |
+ oracle_proxy_ = oracle_proxy; |
+ |
+ j_capture_.Reset(media::ScreenCaptureFactoryAndroid |
+ ::createScreenCaptureMachineAndroid(reinterpret_cast<intptr_t>(this))); |
+ |
+ if (j_capture_.obj() == NULL) { |
+ LOG(ERROR) << "Failed to createScreenCaptureAndroid," |
+ " Maybe android version is too low"; |
+ callback.Run(false); |
+ return; |
+ } |
+ |
+ power_save_blocker_.reset( |
+ content::PowerSaveBlocker::Create( |
+ content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, |
+ content::PowerSaveBlocker::kReasonOther, |
+ "ScreenCaptureMachineAndroid is running").release()); |
+ |
+ capture_format_ = params.requested_format; |
+ // This capturer always outputs ARGB, non-interlaced. |
+ capture_format_.pixel_format = media::PIXEL_FORMAT_ARGB; |
+ |
+ CHECK(capture_format_.frame_size.GetArea() > 0); |
+ CHECK(!(capture_format_.frame_size.width() % 2)); |
+ CHECK(!(capture_format_.frame_size.height() % 2)); |
+ |
+ JNIEnv* env = AttachCurrentThread(); |
+ jboolean ret = media::Java_ScreenCapture_startPrompt(env, j_capture_.obj(), |
+ capture_format_.frame_size.width(), capture_format_.frame_size.height()); |
+ if (!ret) { |
+ callback.Run(false); |
+ return; |
+ } |
+ |
+ callback.Run(true); |
+} |
+ |
+void ScreenCaptureMachineAndroid::Stop(const base::Closure& callback) { |
+ power_save_blocker_.reset(); |
+ |
+ JNIEnv* env = AttachCurrentThread(); |
+ Java_ScreenCapture_stopCapture(env, j_capture_.obj()); |
+ |
+ callback.Run(); |
+} |
+ |
+} // namespace content |