OLD | NEW |
---|---|
(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 } | |
OLD | NEW |