Index: media/capture/content/android/java/src/org/chromium/media/ScreenCapture.java |
diff --git a/media/capture/content/android/java/src/org/chromium/media/ScreenCapture.java b/media/capture/content/android/java/src/org/chromium/media/ScreenCapture.java |
deleted file mode 100644 |
index 6ac2a76853d5609e590291b1615101dad2e1f3f5..0000000000000000000000000000000000000000 |
--- a/media/capture/content/android/java/src/org/chromium/media/ScreenCapture.java |
+++ /dev/null |
@@ -1,350 +0,0 @@ |
-// Copyright 2016 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.annotation.TargetApi; |
-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.ImageFormat; |
-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; |
-import android.media.projection.MediaProjectionManager; |
-import android.os.Build; |
-import android.os.Handler; |
-import android.os.HandlerThread; |
-import android.util.DisplayMetrics; |
-import android.view.Display; |
-import android.view.Surface; |
- |
-import org.chromium.base.ApplicationStatus; |
-import org.chromium.base.Log; |
-import org.chromium.base.annotations.CalledByNative; |
-import org.chromium.base.annotations.JNINamespace; |
- |
-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") |
-@TargetApi(Build.VERSION_CODES.LOLLIPOP) |
-public class ScreenCapture extends Fragment { |
- private static final String TAG = "ScreenCaptureMachine"; |
- |
- private static final int REQUEST_MEDIA_PROJECTION = 1; |
- |
- // Native callback context variable. |
- private final long mNativeScreenCaptureMachineAndroid; |
- private final Context mContext; |
- |
- private static enum CaptureState { ATTACHED, ALLOWED, STARTED, STOPPING, STOPPED } |
- private final Object mCaptureStateLock = new Object(); |
- private CaptureState mCaptureState = CaptureState.STOPPED; |
- |
- private MediaProjection mMediaProjection; |
- private MediaProjectionManager mMediaProjectionManager; |
- private VirtualDisplay mVirtualDisplay; |
- private Surface mSurface; |
- private ImageReader mImageReader = null; |
- private HandlerThread mThread; |
- private Handler mBackgroundHandler; |
- |
- private int mScreenDensity; |
- private int mWidth; |
- private int mHeight; |
- private int mFormat; |
- private int mResultCode; |
- private Intent mResultData; |
- |
- ScreenCapture(Context context, long nativeScreenCaptureMachineAndroid) { |
- mContext = context; |
- mNativeScreenCaptureMachineAndroid = nativeScreenCaptureMachineAndroid; |
- |
- Activity activity = ApplicationStatus.getLastTrackedFocusedActivity(); |
- if (activity == null) { |
- Log.e(TAG, "activity is null"); |
- return; |
- } |
- |
- FragmentManager fragmentManager = activity.getFragmentManager(); |
- FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); |
- fragmentTransaction.add(this, "screencapture"); |
- |
- try { |
- fragmentTransaction.commit(); |
- } catch (RuntimeException e) { |
- Log.e(TAG, "ScreenCaptureExcaption " + e); |
- } |
- |
- DisplayMetrics metrics = new DisplayMetrics(); |
- Display display = activity.getWindowManager().getDefaultDisplay(); |
- display.getMetrics(metrics); |
- mScreenDensity = metrics.densityDpi; |
- } |
- |
- // Factory method. |
- @CalledByNative |
- static ScreenCapture createScreenCaptureMachine( |
- Context context, long nativeScreenCaptureMachineAndroid) { |
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
- return new ScreenCapture(context, nativeScreenCaptureMachineAndroid); |
- } |
- return null; |
- } |
- |
- // Internal class implementing the ImageReader listener. Gets pinged when a |
- // new frame is been captured and downloaded to memory-backed buffers. |
- // TODO(braveyao): This is very similar as the one in VideoCaptureCamera2. Try to see |
- // if we can extend from it, https://crbug.com/487935. |
- private class CrImageReaderListener implements ImageReader.OnImageAvailableListener { |
- @Override |
- public void onImageAvailable(ImageReader reader) { |
- synchronized (mCaptureStateLock) { |
- if (mCaptureState != CaptureState.STARTED) { |
- Log.e(TAG, "Get captured frame in unexpected state."); |
- return; |
- } |
- } |
- |
- try (Image image = reader.acquireLatestImage()) { |
- if (image == null) return; |
- if (reader.getWidth() != image.getWidth() |
- || reader.getHeight() != image.getHeight()) { |
- Log.e(TAG, "ImageReader size (" + reader.getWidth() + "x" + reader.getHeight() |
- + ") did not match Image size (" + image.getWidth() + "x" |
- + image.getHeight() + ")"); |
- throw new IllegalStateException(); |
- } |
- |
- switch (image.getFormat()) { |
- case PixelFormat.RGBA_8888: |
- if (image.getPlanes().length != 1) { |
- Log.e(TAG, "Unexpected image planes for RGBA_8888 format: " |
- + image.getPlanes().length); |
- throw new IllegalStateException(); |
- } |
- |
- nativeOnRGBAFrameAvailable(mNativeScreenCaptureMachineAndroid, |
- image.getPlanes()[0].getBuffer(), |
- image.getPlanes()[0].getRowStride(), image.getCropRect().left, |
- image.getCropRect().top, image.getCropRect().width(), |
- image.getCropRect().height(), image.getTimestamp()); |
- break; |
- case ImageFormat.YUV_420_888: |
- if (image.getPlanes().length != 3) { |
- Log.e(TAG, "Unexpected image planes for YUV_420_888 format: " |
- + image.getPlanes().length); |
- throw new IllegalStateException(); |
- } |
- |
- // The pixel stride of Y plane is always 1. The U/V planes are guaranteed |
- // to have the same row stride and pixel stride. |
- nativeOnI420FrameAvailable(mNativeScreenCaptureMachineAndroid, |
- image.getPlanes()[0].getBuffer(), |
- image.getPlanes()[0].getRowStride(), |
- image.getPlanes()[1].getBuffer(), image.getPlanes()[2].getBuffer(), |
- image.getPlanes()[1].getRowStride(), |
- image.getPlanes()[1].getPixelStride(), image.getCropRect().left, |
- image.getCropRect().top, image.getCropRect().width(), |
- image.getCropRect().height(), image.getTimestamp()); |
- break; |
- default: |
- Log.e(TAG, "Unexpected image format: " + image.getFormat()); |
- throw new IllegalStateException(); |
- } |
- } catch (IllegalStateException ex) { |
- Log.e(TAG, "acquireLatestImage():" + ex); |
- } catch (UnsupportedOperationException ex) { |
- Log.i(TAG, "acquireLatestImage():" + ex); |
- // YUV_420_888 is the preference, but not all devices support it, |
- // fall-back to RGBA_8888 then. |
- mImageReader.close(); |
- mVirtualDisplay.release(); |
- |
- mFormat = PixelFormat.RGBA_8888; |
- createImageReaderWithFormat(mFormat); |
- createVirtualDisplay(); |
- } |
- } |
- } |
- |
- private class MediaProjectionCallback extends MediaProjection.Callback { |
- @Override |
- public void onStop() { |
- changeCaptureStateAndNotify(CaptureState.STOPPED); |
- mMediaProjection = null; |
- if (mVirtualDisplay == null) return; |
- mVirtualDisplay.release(); |
- mVirtualDisplay = null; |
- } |
- } |
- |
- @Override |
- public void onAttach(Context context) { |
- super.onAttach(context); |
- Log.d(TAG, "onAttach"); |
- changeCaptureStateAndNotify(CaptureState.ATTACHED); |
- } |
- |
- // This method was deprecated in API level 23 by onAttach(Context). |
- // TODO(braveyao): remove this method after the minSdkVersion of chrome is 23, |
- // https://crbug.com/614172. |
- @SuppressWarnings("deprecation") |
- @Override |
- public void onAttach(Activity activity) { |
- super.onAttach(activity); |
- Log.d(TAG, "onAttach"); |
- changeCaptureStateAndNotify(CaptureState.ATTACHED); |
- } |
- |
- @Override |
- public void onDetach() { |
- super.onDetach(); |
- Log.d(TAG, "onDetach"); |
- stopCapture(); |
- } |
- |
- @CalledByNative |
- public boolean startPrompt(int width, int height) { |
- Log.d(TAG, "startPrompt"); |
- synchronized (mCaptureStateLock) { |
- while (mCaptureState != CaptureState.ATTACHED) { |
- try { |
- mCaptureStateLock.wait(); |
- } catch (InterruptedException ex) { |
- Log.e(TAG, "ScreenCaptureException: " + ex); |
- } |
- } |
- } |
- |
- mWidth = width; |
- mHeight = height; |
- |
- mMediaProjectionManager = (MediaProjectionManager) mContext.getSystemService( |
- Context.MEDIA_PROJECTION_SERVICE); |
- if (mMediaProjectionManager == null) { |
- Log.e(TAG, "mMediaProjectionManager is null"); |
- return false; |
- } |
- |
- try { |
- startActivityForResult( |
- mMediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION); |
- } catch (android.content.ActivityNotFoundException e) { |
- Log.e(TAG, "ScreenCaptureException " + e); |
- return false; |
- } |
- return true; |
- } |
- |
- @Override |
- public void onActivityResult(int requestCode, int resultCode, Intent data) { |
- if (requestCode != REQUEST_MEDIA_PROJECTION) return; |
- |
- if (resultCode == Activity.RESULT_OK) { |
- mResultCode = resultCode; |
- mResultData = data; |
- changeCaptureStateAndNotify(CaptureState.ALLOWED); |
- } |
- nativeOnActivityResult( |
- mNativeScreenCaptureMachineAndroid, resultCode == Activity.RESULT_OK); |
- } |
- |
- @CalledByNative |
- public void startCapture() { |
- Log.d(TAG, "startCapture"); |
- synchronized (mCaptureStateLock) { |
- if (mCaptureState != CaptureState.ALLOWED) { |
- Log.e(TAG, "startCapture() invoked without user permission."); |
- return; |
- } |
- } |
- mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, mResultData); |
- if (mMediaProjection == null) { |
- Log.e(TAG, "mMediaProjection is null"); |
- return; |
- } |
- mMediaProjection.registerCallback(new MediaProjectionCallback(), null); |
- |
- mThread = new HandlerThread("ScreenCapture"); |
- mThread.start(); |
- mBackgroundHandler = new Handler(mThread.getLooper()); |
- |
- // On Android M and above, YUV420 is prefered. Some Android L devices will silently |
- // fail with YUV420, so keep with RGBA_8888 on L. |
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { |
- mFormat = PixelFormat.RGBA_8888; |
- } else { |
- mFormat = ImageFormat.YUV_420_888; |
- } |
- createImageReaderWithFormat(mFormat); |
- createVirtualDisplay(); |
- |
- changeCaptureStateAndNotify(CaptureState.STARTED); |
- } |
- |
- @CalledByNative |
- public void stopCapture() { |
- Log.d(TAG, "stopCapture"); |
- synchronized (mCaptureStateLock) { |
- if (mMediaProjection != null && mCaptureState == CaptureState.STARTED) { |
- mMediaProjection.stop(); |
- changeCaptureStateAndNotify(CaptureState.STOPPING); |
- } |
- |
- while (mCaptureState != CaptureState.STOPPED) { |
- try { |
- mCaptureStateLock.wait(); |
- } catch (InterruptedException ex) { |
- Log.e(TAG, "ScreenCaptureEvent: " + ex); |
- } |
- } |
- } |
- } |
- |
- private void createImageReaderWithFormat(int format) { |
- final int maxImages = 2; |
- mImageReader = ImageReader.newInstance(mWidth, mHeight, format, maxImages); |
- mSurface = mImageReader.getSurface(); |
- final CrImageReaderListener imageReaderListener = new CrImageReaderListener(); |
- mImageReader.setOnImageAvailableListener(imageReaderListener, mBackgroundHandler); |
- } |
- |
- private void createVirtualDisplay() { |
- mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture", mWidth, mHeight, |
- mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mSurface, null, |
- null); |
- } |
- |
- private void changeCaptureStateAndNotify(CaptureState state) { |
- synchronized (mCaptureStateLock) { |
- mCaptureState = state; |
- mCaptureStateLock.notifyAll(); |
- } |
- } |
- |
- // Method for ScreenCapture implementations to call back native code. |
- private native void nativeOnRGBAFrameAvailable(long nativeScreenCaptureMachineAndroid, |
- ByteBuffer buf, int left, int top, int width, int height, int rowStride, |
- long timestamp); |
- // Method for ScreenCapture implementations to call back native code. |
- private native void nativeOnI420FrameAvailable(long nativeScreenCaptureMachineAndroid, |
- ByteBuffer yBuffer, int yStride, ByteBuffer uBuffer, ByteBuffer vBuffer, |
- int uvRowStride, int uvPixelStride, int left, int top, int width, int height, |
- long timestamp); |
- // Method for ScreenCapture implementations to call back native code. |
- private native void nativeOnActivityResult( |
- long nativeScreenCaptureMachineAndroid, boolean result); |
-} |