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

Side by Side 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: make ScreenCapturerAndroid inherit VideoCaptureDevice 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.media;
6
7 import android.app.Activity;
8 import android.app.Fragment;
9 import android.app.FragmentManager;
10 import android.app.FragmentTransaction;
11 import android.content.Context;
12 import android.content.Intent;
13 import android.graphics.PixelFormat;
14 import android.graphics.Point;
15 import android.hardware.display.DisplayManager;
16 import android.hardware.display.VirtualDisplay;
17 import android.media.Image;
18 import android.media.ImageReader;
19 import android.media.projection.MediaProjection;
20 import android.media.projection.MediaProjectionManager;
21 import android.os.Handler;
22 import android.os.HandlerThread;
23 import android.util.DisplayMetrics;
24 import android.view.Display;
25 import android.view.Surface;
26
27 import org.chromium.base.BaseChromiumApplication;
28 import org.chromium.base.CalledByNative;
29 import org.chromium.base.JNINamespace;
30 import org.chromium.base.Log;
31
32 import java.nio.ByteBuffer;
33
34 /**
35 * This class implements Screen Capture using projection API, introduced in Andr oid
36 * API 21 (L Release). Capture takes place in the current Looper, while pixel
37 * download takes place in another thread used by ImageReader.
38 **/
39 @JNINamespace("media")
40 public class ScreenCapture extends Fragment {
mcasas 2015/05/22 02:30:59 ScreenCapture looks a lot to the naked eye like V
41
42 // Internal class implementing the ImageReader listener. Gets pinged when a
43 // new frame is been captured and downloaded to memory-backed buffers.
44 private class CrImageReaderListener implements ImageReader.OnImageAvailableL istener {
45 @Override
46 public void onImageAvailable(ImageReader reader) {
47 try {
48 if (mImageReader == null) return;
49
50 mImage = reader.acquireLatestImage();
51 if (mImage == null) return;
52 if (mImage.getFormat() != PixelFormat.RGBA_8888) {
53 Log.e(TAG, "Unexpected image format: " + mImage.getFormat()
54 + " or #planes: " + mImage.getPlanes().length);
55 return;
56 }
57
58 Image.Plane[] planes = mImage.getPlanes();
59 ByteBuffer buffer = (ByteBuffer) planes[0].getBuffer();
60 buffer.get(mCapturedData);
61
62 nativeOnFrameAvailable(mNativeScreenCapturer2Android,
63 mCapturedData,
64 mCapturedData.length);
65
66 } catch (IllegalStateException ex) {
67 Log.e(TAG, "acquireLatestImage():" + ex);
68 return;
69 } finally {
70 if (mImage != null) {
71 mImage.close();
72 }
73 }
74 }
75 };
76
77 private byte[] mCapturedData;
78 private final Context mContext;
79
80 private MediaProjection mMediaProjection;
81 private MediaProjectionManager mMediaProjectionManager;
82 private VirtualDisplay mVirtualDisplay;
83 private static final int REQUEST_MEDIA_PROJECTION = 1;
84
85 private Surface mSurface;
86 private Image mImage = null;
87 private ImageReader mImageReader = null;
88 private int mScreenDensity;
89 private int mWidth;
90 private int mHeight;
91 private int mResultCode;
92 private Intent mResultData;
93 private HandlerThread mThread = null;
94 // Native callback context variable.
95 private final long mNativeScreenCapturer2Android;
96
97 private static final String TAG = "ScreenCaptureAndroid";
98
99 ScreenCapture(Context context, long nativeScreenCapturer2Android) {
vashisthg 2015/08/11 11:35:06 Why does this fragment not have a no argument cons
100 mContext = context;
101 mNativeScreenCapturer2Android = nativeScreenCapturer2Android;
102 }
103
104 @CalledByNative
105 public boolean start(int width, int height) {
106 Log.i(TAG, "start");
107 try {
108 BaseChromiumApplication ba = (BaseChromiumApplication) mContext;
109 Activity activity = ba.getActivity();
110 if (activity == null) {
111 Log.e(TAG, "activity is null");
112 return false;
113 }
114
115 FragmentManager fragmentManager = activity.getFragmentManager();
116 FragmentTransaction fragmentTransaction = fragmentManager.beginTrans action();
117 fragmentTransaction.add(this, "screencapture");
118 fragmentTransaction.commit();
119
120 DisplayMetrics metrics = new DisplayMetrics();
121 Point size = new Point();
122 Display display = activity.getWindowManager().getDefaultDisplay();
123 display.getMetrics(metrics);
124 display.getSize(size);
125 mScreenDensity = metrics.densityDpi;
126 mWidth = width;
127 mHeight = height;
128 int expectedFrameSize = mWidth * mHeight * 4;
129 mCapturedData = new byte[expectedFrameSize];
130
131 mMediaProjectionManager = (MediaProjectionManager)
132 mContext.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
133 if (mMediaProjectionManager == null) {
134 Log.e(TAG, "mMediaProjectionManager is null");
135 return true;
136 }
137
138 startActivityForResult(mMediaProjectionManager.createScreenCaptureIn tent(),
139 REQUEST_MEDIA_PROJECTION);
140 } catch (Exception e) {
141 Log.e(TAG, "ScreenCaptureExcaption " + e);
142 return false;
143 }
144 return true;
145 }
146
147 @Override
148 public void onActivityResult(int requestCode, int resultCode, Intent data) {
149 if (requestCode == REQUEST_MEDIA_PROJECTION) {
150 int result;
151 if (resultCode != Activity.RESULT_OK) {
152 result = 0;
153 } else {
154 result = 1;
155 mResultCode = resultCode;
156 mResultData = data;
157 }
158 nativeOnActivityResult(mNativeScreenCapturer2Android, result);
159 }
160 }
161
162 // start screen capture.
163 @CalledByNative
164 public void startCapture() {
165 Log.i(TAG, "startCapture");
166 mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCod e, mResultData);
167 if (mMediaProjection == null) {
168 Log.i(TAG, "mMediaProjection is null");
169 return;
170 }
171
172 mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA _8888, 2);
173 mSurface = mImageReader.getSurface();
174 mThread = new HandlerThread("ScreenPreview");
175 mThread.start();
176 final Handler backgroundHandler = new Handler(mThread.getLooper());
177 final CrImageReaderListener imageReaderListener = new CrImageReaderListe ner();
178 mImageReader.setOnImageAvailableListener(imageReaderListener,
179 backgroundHandler);
180
181 mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture",
182 mWidth, mHeight, mScreenDensity,
183 DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
184 mSurface, null, null);
185 }
186
187 // Stops screen capture.
188 @CalledByNative
189 public void stopCapture() {
190 Log.i(TAG, "stopCapture");
191 if (mThread != null) {
192 mThread.quit();
193 }
194
195 if (mMediaProjection != null) {
196 mMediaProjection.stop();
197 mMediaProjection = null;
198 }
199
200 if (mVirtualDisplay != null) {
201 mVirtualDisplay.release();
202 mVirtualDisplay = null;
203 }
204
205 if (mImageReader != null) {
206 if (mImage != null) {
207 mImage.close();
208 }
209 mImageReader.close();
210 mImageReader = null;
211 }
212 }
213
214 // Method for ScreenCapture implementations to call back native code.
215 public native void nativeOnFrameAvailable(long nativeScreenCapturer2Android,
216 byte[] data,
217 int length);
218
219 // Method for ScreenCapture implementations to call back native code.
220 public native void nativeOnActivityResult(long nativeScreenCapturer2Android,
221 int result);
222
223 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698