Index: media/screen_capture/android/screen_capturer2_android.cc |
diff --git a/media/screen_capture/android/screen_capturer2_android.cc b/media/screen_capture/android/screen_capturer2_android.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ca4c381be68d1db7928ac05ed0cc74c7a8c177b1 |
--- /dev/null |
+++ b/media/screen_capture/android/screen_capturer2_android.cc |
@@ -0,0 +1,162 @@ |
+// Copyright (c) 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_capturer2_android.h" |
+ |
+#include "base/android/jni_android.h" |
+#include "base/android/scoped_java_ref.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "jni/ScreenCapture_jni.h" |
+#include "media/base/video_capture_types.h" |
+#include "media/screen_capture/android/screen_capture_factory_android.h" |
+ |
+using base::android::AttachCurrentThread; |
+ |
+namespace media { |
+ |
+// static |
+bool ScreenCapturer2Android::RegisterScreenCapturer2(JNIEnv* env) { |
+ return media::RegisterNativesImpl(env); |
+} |
+ |
+ScreenCapturer2Android::ScreenCapturer2Android() |
+ : state_(kIdle), got_first_frame_(false) {} |
+ |
+ScreenCapturer2Android::~ScreenCapturer2Android() { |
+ StopAndDeAllocate(); |
+} |
+ |
+void ScreenCapturer2Android::OnFrameAvailable(JNIEnv* env, |
+ jobject obj, |
+ jbyteArray data, |
+ jint length) { |
+ base::AutoLock lock(lock_); |
+ if (state_ != kCapturing || !client_.get()) |
+ return; |
+ |
+ jbyte* buffer = env->GetByteArrayElements(data, NULL); |
+ if (!buffer) { |
+ LOG(ERROR) << "ScreenCapturer2Android::OnFrameAvailable: " |
+ "failed to GetByteArrayElements"; |
+ return; |
+ } |
+ |
+ base::TimeTicks current_time = base::TimeTicks::Now(); |
+ if (!got_first_frame_) { |
+ // Set aside one frame allowance for fluctuation. |
+ expected_next_frame_time_ = current_time - frame_interval_; |
+ got_first_frame_ = true; |
+ } |
+ |
+ // Deliver the frame when it doesn't arrive too early. |
+ if (expected_next_frame_time_ <= current_time) { |
+ expected_next_frame_time_ += frame_interval_; |
+ |
+ client_->OnIncomingCapturedData(reinterpret_cast<uint8*>(buffer), |
+ length, |
+ capture_format_, |
+ 0, |
+ base::TimeTicks::Now()); |
+ } |
+ |
+ env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); |
+} |
+ |
+void ScreenCapturer2Android::OnActivityResult(JNIEnv* env, |
+ jobject obj, |
+ jint result) { |
+ if (result == 0) { |
+ state_ = kIdle; |
+ return; |
+ } |
+ |
+ media::Java_ScreenCapture_startCapture(env, obj); |
+ |
+ { |
+ base::AutoLock lock(lock_); |
+ state_ = kCapturing; |
+ } |
+} |
+ |
+bool ScreenCapturer2Android::Init() { |
+ j_capture_.Reset(media::ScreenCaptureFactoryAndroid |
+ ::createScreenCapture2Android(reinterpret_cast<intptr_t>(this))); |
+ |
+ if (j_capture_.obj() == NULL) { |
+ LOG(ERROR) << "ScreenCapturer2Android::Init" |
+ " failed to createScreenCaptureAndroid," |
+ " Maybe android version is too low"; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+void ScreenCapturer2Android::AllocateAndStart( |
+ const VideoCaptureParams& params, |
+ scoped_ptr<Client> client) { |
+ DVLOG(1) << "ScreenCapturer2Android::AllocateAndStart"; |
+ { |
+ base::AutoLock lock(lock_); |
+ if (state_ != kIdle) |
+ return; |
+ client_ = client.Pass(); |
+ got_first_frame_ = false; |
+ } |
+/* |
+ // Store current width and height. |
+ capture_format_.frame_size.SetSize( |
+ params.requested_format.frame_size.width(), |
+ params.requested_format.frame_size.height()); |
+ capture_format_.frame_rate = params.requested_format.frame_rate; |
+*/ |
+ 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)); |
+ |
+ if (capture_format_.frame_rate > 0) { |
+ frame_interval_ = base::TimeDelta::FromMicroseconds( |
+ (base::Time::kMicrosecondsPerSecond + capture_format_.frame_rate - 1) / |
+ capture_format_.frame_rate); |
+ } |
+ |
+ DVLOG(1) << "ScreenCapturer2Android::AllocateAndStart: queried frame_size=" |
+ << capture_format_.frame_size.ToString() |
+ << ", frame_rate=" << capture_format_.frame_rate; |
+ |
+ JNIEnv* env = AttachCurrentThread(); |
+ jboolean ret = media::Java_ScreenCapture_start(env, j_capture_.obj(), |
+ capture_format_.frame_size.width(), capture_format_.frame_size.height()); |
+ if (!ret) { |
+ { |
+ base::AutoLock lock(lock_); |
+ state_ = kError; |
+ } |
+ client_->OnError("Failed to start"); |
+ return; |
+ } |
+} |
+ |
+void ScreenCapturer2Android::StopAndDeAllocate() { |
+ DVLOG(1) << "ScreenCapturer2Android::StopAndDeAllocate"; |
+ { |
+ base::AutoLock lock(lock_); |
+ if (state_ != kCapturing && state_ != kError) |
+ return; |
+ } |
+ |
+ JNIEnv* env = AttachCurrentThread(); |
+ Java_ScreenCapture_stopCapture(env, j_capture_.obj()); |
+ |
+ { |
+ base::AutoLock lock(lock_); |
+ state_ = kIdle; |
+ client_.reset(); |
+ } |
+} |
+ |
+} // namespace media |