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

Unified Diff: media/base/android/java/src/org/chromium/media/ScreenCapture.java

Issue 1140113002: Implement screen capture for android (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add ScreenCaptureMachineAndroid which inherited from content::VideoCaptureMachine Created 5 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 side-by-side diff with in-line comments
Download patch
Index: media/base/android/java/src/org/chromium/media/ScreenCapture.java
diff --git a/media/base/android/java/src/org/chromium/media/ScreenCapture.java b/media/base/android/java/src/org/chromium/media/ScreenCapture.java
new file mode 100644
index 0000000000000000000000000000000000000000..8174f729c82529c1a76ff4d1d1c3b046358100ef
--- /dev/null
+++ b/media/base/android/java/src/org/chromium/media/ScreenCapture.java
@@ -0,0 +1,234 @@
+// 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.
+
+package org.chromium.media;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.Image;
+import android.media.ImageReader;
+//import android.media.projection.MediaProjection.Callback;
whywhat 2015/08/17 13:58:46 nit: Uncomment or remove?
+import android.media.projection.MediaProjection;
+import android.media.projection.MediaProjectionManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.Surface;
+
+import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This class implements Screen Capture using projection API, introduced in Android
+ * API 21 (L Release). Capture takes place in the current Looper, while pixel
+ * download takes place in another thread used by ImageReader.
+ **/
+@JNINamespace("media")
+public class ScreenCapture extends Fragment {
+
+ // Internal class implementing the ImageReader listener. Gets pinged when a
+ // new frame is been captured and downloaded to memory-backed buffers.
+ private class CrImageReaderListener implements ImageReader.OnImageAvailableListener {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Image image = null;
+ try {
+ image = reader.acquireLatestImage();
+ if (image == null) return;
+ if (image.getFormat() != PixelFormat.RGBA_8888) {
+ Log.e(TAG, "Unexpected image format: " + image.getFormat()
+ + " or #planes: " + image.getPlanes().length);
+ return;
+ }
+
+ Image.Plane[] planes = image.getPlanes();
+ ByteBuffer buffer = (ByteBuffer) planes[0].getBuffer();
+ buffer.get(mCapturedData);
+
+ nativeOnFrameAvailable(mNativeScreenCaptureMachineAndroid,
+ mCapturedData,
+ image.getCropRect().width(),
+ image.getCropRect().height(),
+ image.getTimestamp());
+
+ } catch (IllegalStateException ex) {
+ Log.e(TAG, "acquireLatestImage():" + ex);
+ return;
+ } finally {
+ if (image != null) {
whywhat 2015/08/17 13:58:46 nit: a one liner
+ image.close();
+ }
+ }
+ }
+ };
+
+ private class MediaProjectionCallback extends MediaProjection.Callback {
+ @Override
+ public void onStop() {
+ mMediaProjection = null;
+ if (mVirtualDisplay == null) {
whywhat 2015/08/17 13:58:46 nit: one liner
+ return;
+ }
+ mVirtualDisplay.release();
+ mVirtualDisplay = null;
+ }
+ }
+
+ private byte[] mCapturedData;
+ private final Context mContext;
+
+ private MediaProjection mMediaProjection;
+ private MediaProjectionManager mMediaProjectionManager;
+ private VirtualDisplay mVirtualDisplay;
+ private static final int REQUEST_MEDIA_PROJECTION = 1;
+
+ private Surface mSurface;
+ private ImageReader mImageReader = null;
+ private int mScreenDensity;
+ private int mWidth;
+ private int mHeight;
+ private int mResultCode;
+ private Intent mResultData;
+
+ // Native callback context variable.
+ private final long mNativeScreenCaptureMachineAndroid;
+
+ private static final String TAG = "ScreenCaptureMachine";
+
+ ScreenCapture(Context context, long nativeScreenCaptureMachineAndroid) {
+ mContext = context;
+ mNativeScreenCaptureMachineAndroid = nativeScreenCaptureMachineAndroid;
+ try {
+ BaseChromiumApplication ba = (BaseChromiumApplication) mContext;
+ Activity activity = ba.getActivity();
+ if (activity == null) {
+ Log.e(TAG, "activity is null");
+ return;
+ }
+
+ FragmentManager fragmentManager = activity.getFragmentManager();
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ fragmentTransaction.add(this, "screencapture");
+ fragmentTransaction.commit();
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ Display display = activity.getWindowManager().getDefaultDisplay();
+ display.getMetrics(metrics);
+ mScreenDensity = metrics.densityDpi;
+ } catch (Exception e) {
+ Log.e(TAG, "ScreenCaptureExcaption " + e);
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ Log.i(TAG, "onDetach");
+ stopCapture();
+ }
+
+ @CalledByNative
+ public boolean startPrompt(int width, int height) {
+ Log.i(TAG, "startPrompt");
+ try {
+ if (!isAdded()) {
+ Log.e(TAG, "the fragment hasn't been added to an activity");
+ return false;
+ }
+ mWidth = width;
+ mHeight = height;
+ int expectedFrameSize = mWidth * mHeight * 4;
+ mCapturedData = new byte[expectedFrameSize];
+
+ mMediaProjectionManager = (MediaProjectionManager)
+ mContext.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
+ if (mMediaProjectionManager == null) {
+ Log.e(TAG, "mMediaProjectionManager is null");
+ return false;
+ }
+
+ startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(),
+ REQUEST_MEDIA_PROJECTION);
+ } catch (Exception e) {
+ Log.e(TAG, "ScreenCaptureExcaption " + e);
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_MEDIA_PROJECTION) {
+ int result;
+ if (resultCode != Activity.RESULT_OK) {
+ result = 0;
+ } else {
+ result = 1;
+ mResultCode = resultCode;
+ mResultData = data;
+ }
+ nativeOnActivityResult(mNativeScreenCaptureMachineAndroid, result);
+ }
+ }
+
+ // start screen capture.
whywhat 2015/08/17 13:58:46 nit: follow Javadoc style for public/protected cla
+ @CalledByNative
+ public void startCapture() {
+ Log.i(TAG, "startCapture");
whywhat 2015/08/17 13:58:46 nit: s/Log.i/Log.d?
+ mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, mResultData);
+ if (mMediaProjection == null) {
+ Log.i(TAG, "mMediaProjection is null");
+ return;
+ }
+ mMediaProjection.registerCallback(new MediaProjectionCallback(), null);
+
+ final int maxImages = 2;
+ mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA_8888, maxImages);
+ mSurface = mImageReader.getSurface();
+ HandlerThread thread = new HandlerThread("Screen");
+ thread.start();
+ final Handler backgroundHandler = new Handler(thread.getLooper());
+ final CrImageReaderListener imageReaderListener = new CrImageReaderListener();
+ mImageReader.setOnImageAvailableListener(imageReaderListener,
+ backgroundHandler);
+
+ mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture",
+ mWidth, mHeight, mScreenDensity,
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
+ mSurface, null, null);
+ }
+
+ // Stops screen capture.
+ @CalledByNative
+ public void stopCapture() {
+ Log.i(TAG, "stopCapture");
whywhat 2015/08/17 13:58:46 ditto
+ if (mMediaProjection != null) {
+ mMediaProjection.stop();
whywhat 2015/08/17 13:58:46 nit: fits on one line
+ }
+ }
+
+ // Method for ScreenCapture implementations to call back native code.
+ public native void nativeOnFrameAvailable(long nativeScreenCaptureMachineAndroid,
+ byte[] data,
+ int cropWidth,
+ int cropHeight,
+ long timestamp);
+
+ // Method for ScreenCapture implementations to call back native code.
+ public native void nativeOnActivityResult(long nativeScreenCaptureMachineAndroid,
whywhat 2015/08/17 13:58:46 Do these or @CalledByNative methdos have to be pub
+ int result);
+
+}

Powered by Google App Engine
This is Rietveld 408576698