Chromium Code Reviews| 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..5d1581e10ba901cb8e5d1b76f9fbac20de9c4bb7 |
| --- /dev/null |
| +++ b/media/base/android/java/src/org/chromium/media/ScreenCapture.java |
| @@ -0,0 +1,223 @@ |
| +// 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.graphics.Point; |
| +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.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 { |
|
mcasas
2015/05/22 02:30:59
ScreenCapture looks a lot to the naked eye like
V
|
| + |
| + // 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) { |
| + try { |
| + if (mImageReader == null) return; |
| + |
| + mImage = reader.acquireLatestImage(); |
| + if (mImage == null) return; |
| + if (mImage.getFormat() != PixelFormat.RGBA_8888) { |
| + Log.e(TAG, "Unexpected image format: " + mImage.getFormat() |
| + + " or #planes: " + mImage.getPlanes().length); |
| + return; |
| + } |
| + |
| + Image.Plane[] planes = mImage.getPlanes(); |
| + ByteBuffer buffer = (ByteBuffer) planes[0].getBuffer(); |
| + buffer.get(mCapturedData); |
| + |
| + nativeOnFrameAvailable(mNativeScreenCapturer2Android, |
| + mCapturedData, |
| + mCapturedData.length); |
| + |
| + } catch (IllegalStateException ex) { |
| + Log.e(TAG, "acquireLatestImage():" + ex); |
| + return; |
| + } finally { |
| + if (mImage != null) { |
| + mImage.close(); |
| + } |
| + } |
| + } |
| + }; |
| + |
| + 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 Image mImage = null; |
| + private ImageReader mImageReader = null; |
| + private int mScreenDensity; |
| + private int mWidth; |
| + private int mHeight; |
| + private int mResultCode; |
| + private Intent mResultData; |
| + private HandlerThread mThread = null; |
| + // Native callback context variable. |
| + private final long mNativeScreenCapturer2Android; |
| + |
| + private static final String TAG = "ScreenCaptureAndroid"; |
| + |
| + ScreenCapture(Context context, long nativeScreenCapturer2Android) { |
|
vashisthg
2015/08/11 11:35:06
Why does this fragment not have a no argument cons
|
| + mContext = context; |
| + mNativeScreenCapturer2Android = nativeScreenCapturer2Android; |
| + } |
| + |
| + @CalledByNative |
| + public boolean start(int width, int height) { |
| + Log.i(TAG, "start"); |
| + try { |
| + BaseChromiumApplication ba = (BaseChromiumApplication) mContext; |
| + Activity activity = ba.getActivity(); |
| + if (activity == null) { |
| + Log.e(TAG, "activity is null"); |
| + return false; |
| + } |
| + |
| + FragmentManager fragmentManager = activity.getFragmentManager(); |
| + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); |
| + fragmentTransaction.add(this, "screencapture"); |
| + fragmentTransaction.commit(); |
| + |
| + DisplayMetrics metrics = new DisplayMetrics(); |
| + Point size = new Point(); |
| + Display display = activity.getWindowManager().getDefaultDisplay(); |
| + display.getMetrics(metrics); |
| + display.getSize(size); |
| + mScreenDensity = metrics.densityDpi; |
| + 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 true; |
| + } |
| + |
| + 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(mNativeScreenCapturer2Android, result); |
| + } |
| + } |
| + |
| + // start screen capture. |
| + @CalledByNative |
| + public void startCapture() { |
| + Log.i(TAG, "startCapture"); |
| + mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, mResultData); |
| + if (mMediaProjection == null) { |
| + Log.i(TAG, "mMediaProjection is null"); |
| + return; |
| + } |
| + |
| + mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA_8888, 2); |
| + mSurface = mImageReader.getSurface(); |
| + mThread = new HandlerThread("ScreenPreview"); |
| + mThread.start(); |
| + final Handler backgroundHandler = new Handler(mThread.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"); |
| + if (mThread != null) { |
| + mThread.quit(); |
| + } |
| + |
| + if (mMediaProjection != null) { |
| + mMediaProjection.stop(); |
| + mMediaProjection = null; |
| + } |
| + |
| + if (mVirtualDisplay != null) { |
| + mVirtualDisplay.release(); |
| + mVirtualDisplay = null; |
| + } |
| + |
| + if (mImageReader != null) { |
| + if (mImage != null) { |
| + mImage.close(); |
| + } |
| + mImageReader.close(); |
| + mImageReader = null; |
| + } |
| + } |
| + |
| + // Method for ScreenCapture implementations to call back native code. |
| + public native void nativeOnFrameAvailable(long nativeScreenCapturer2Android, |
| + byte[] data, |
| + int length); |
| + |
| + // Method for ScreenCapture implementations to call back native code. |
| + public native void nativeOnActivityResult(long nativeScreenCapturer2Android, |
| + int result); |
| + |
| +} |