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

Side by Side Diff: webrtc/api/android/java/src/org/webrtc/ScreenCapturerAndroid.java

Issue 2276593003: Android Screen Capturer. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Create Android screen capturer. Created 4 years, 3 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 /*
2 * Copyright 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 package org.webrtc;
12
13 import android.annotation.TargetApi;
14 import android.content.Context;
15 import android.hardware.display.DisplayManager;
16 import android.hardware.display.VirtualDisplay;
17 import android.media.projection.MediaProjection;
18 import android.util.Log;
19 import android.view.Surface;
20
21 import java.util.ArrayList;
22 import java.util.List;
23
24 /**
25 * An implementation of VideoCapturer to capture the screen content as a video s tream.
26 * Capturing is done by {@code MediaProjection} on a {@code SurfaceTexture}. We interact with this
27 * {@code SurfaceTexture} using a {@code SurfaceTextureHelper}.
28 * The {@code SurfaceTextureHelper} is created by the native code and passed to this capturer in
29 * {@code VideoCapturer.initialize()}. On receiving a new frame, this capturer p asses it
30 * as a texture to the native code via {@code CapturerObserver.onTextureFrameCap tured()}. This takes
31 * place on the HandlerThread of the given {@code SurfaceTextureHelper}. When do ne with each frame,
32 * the native code returns the buffer to the {@code SurfaceTextureHelper} to be used for new
33 * frames. At any time, at most one frame is being processed.
34 *
35 * Note that startCapture(), stopCapture(), and dispose() are called from native code.
sakal 2016/08/26 07:21:49 This is only the case using the old deprecated API
arsany 2016/08/30 00:52:15 Thanks, Sami. I wasn't aware of API deprecation, w
sakal 2016/08/30 07:30:13 The only real documentation of the API change is t
arsany 2016/08/30 20:23:17 Acknowledged.
36 * Normally, a Java application should interact with {@code }VideSource} API, wh ich indirectly calls
37 * these methods on the underlying {@code VideoCapturer}.
38 */
39 @TargetApi(21)
40 public class ScreenCapturerAndroid implements
41 VideoCapturer, SurfaceTextureHelper.OnTextureFrameAvailableListener {
42
43 private static final int DISPLAY_FLAGS = DisplayManager.VIRTUAL_DISPLAY_FLAG_P UBLIC
44 | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
45 // DPI for VirtualDisplay, does not seem to matter for us.
46 private static final int VIRTUAL_DISPLAY_DPI = 400;
47
48 private int width;
49 private int height;
50 private VirtualDisplay virtualDisplay;
51 private SurfaceTextureHelper surfaceTextureHelper;
52 private CapturerObserver capturerObserver;
53 private long numCapturedFrames = 0;
54 private MediaProjection mediaProjection;
55 private boolean isDisposed = false;
56 private boolean isCapturing = false;
57
58 /**
59 * Constructs a new Screen Capturer. To avoid distortion, make sure width and height have the
60 * same aspect ratio of the captured screen.
61 *
62 * @param mediaProjection media projection to be used to capture screen
63 * @param width output video width
64 * @param width output video height
65 **/
66 public ScreenCapturerAndroid(MediaProjection mediaProjection, int width, int h eight) {
67 this.mediaProjection = mediaProjection;
68 this.width = width;
69 this.height = height;
70 }
71
72 /**
73 * Sets the media projection used by this capturer.
74 * This method is useful when you need to pause the capture, and resume again, and make Android
75 * remove the platform cast icon while the video stream is paused (end users c an be
76 * confused/suspicious if the app notifies them that screen cast has stopped w hile Android
77 * still shows the cast icon because the app is still holding the media projec tion token).
78 *
79 * Call {@code VideoSource.stop()} before calling this method and
80 * {@code VideoSource.restart()} after that.
81 */
82 public void updateMediaProjection(MediaProjection mediaProjection) {
83 if (isCapturing) {
84 throw new RuntimeException("updateMediaProjection can be called only"
85 + " when capturer is stopped");
86 }
87 this.mediaProjection = mediaProjection;
88 }
89
90 private void checkNotDisposed() {
91 if (isDisposed) {
92 throw new RuntimeException("capturer is disposed.");
93 }
94 }
95
96 @Override
97 public synchronized void initialize(
98 final SurfaceTextureHelper surfaceTextureHelper,
99 final Context ignored_applicationContext,
100 final VideoCapturer.CapturerObserver capturerObserver) {
101 checkNotDisposed();
102
103 if (capturerObserver == null) {
104 throw new RuntimeException("capturerObserver not set.");
105 }
106 this.capturerObserver = capturerObserver;
107
108 if (surfaceTextureHelper == null) {
109 throw new RuntimeException("surfaceTextureHelper not set.");
110 }
111 this.surfaceTextureHelper = surfaceTextureHelper;
112 }
113
114 @Override
115 public synchronized List<CameraEnumerationAndroid.CaptureFormat> getSupportedF ormats() {
116 List<CameraEnumerationAndroid.CaptureFormat> supportedFormats = new ArrayLis t<>();
117 supportedFormats.add(new CameraEnumerationAndroid.CaptureFormat(
118 width, height, 1 /* minFrameRate */, 30 /* maxFrameRate */));
sakal 2016/08/26 07:21:49 Maybe minFrameRate 0? maxFrameRate 30 also seems a
arsany 2016/08/30 00:52:15 Done. Changed to 0, 60. But I am actually not cert
sakal 2016/08/30 07:30:13 I didn't really say we should change it to 60. I w
arsany 2016/08/30 20:23:17 Removed this altogether.
119 return supportedFormats;
120 }
121
122 // Initially called by native code. This can also be called from native code w hen the
sakal 2016/08/26 07:21:49 Only the case in the old deprecated API.
arsany 2016/08/30 00:52:14 Acknowledged.
arsany 2016/08/30 20:23:17 Done.
123 // enclosing VideoSource is "restarted" after being stopped.
124 @Override
125 public synchronized void startCapture(
126 final int ignored_width,
sakal 2016/08/26 07:21:49 I would prefer using these variables as the format
arsany 2016/08/30 00:52:15 Within the old API, getSupportedFormats() get call
sakal 2016/08/30 07:30:13 Hmm, I see. I would prefer you use the new API tho
magjed_webrtc 2016/08/30 10:50:54 Yes, please update to the new API in your client,
arsany 2016/08/30 20:23:17 Done.
127 final int ignored_height,
128 final int ignored_framerate) {
129 checkNotDisposed();
130 isCapturing = true;
131
132 this.surfaceTextureHelper.getSurfaceTexture().setDefaultBufferSize(width, he ight);
133 virtualDisplay = mediaProjection.createVirtualDisplay(
134 "WebRTC_ScreenCapture", width, height, VIRTUAL_DISPLAY_DPI,
135 DISPLAY_FLAGS, new Surface(surfaceTextureHelper.getSurfaceTexture()),
136 null /* callback */, null /* callback handler */);
137
138 capturerObserver.onCapturerStarted(true);
139 surfaceTextureHelper.startListening(ScreenCapturerAndroid.this);
140 }
141
142 // Called by native code to pause capturing.
sakal 2016/08/26 07:21:48 Only the case in the old deprecated API.
arsany 2016/08/30 00:52:14 Acknowledged.
arsany 2016/08/30 20:23:17 Done.
143 @Override
144 public synchronized void stopCapture() {
145 checkNotDisposed();
146 isCapturing = false;
147 ThreadUtils.invokeAtFrontUninterruptibly(surfaceTextureHelper.getHandler(), new Runnable() {
148 @Override
149 public void run() {
150 surfaceTextureHelper.stopListening();
sakal 2016/08/26 07:21:49 You should call capturerObserver.onCapturerStopped
arsany 2016/08/30 00:52:15 Done.
151 virtualDisplay.release();
152 }
153 });
154 }
155
156 // Called from native code to dispose the capturer when the enclosing VideoSou rce is disposed.
sakal 2016/08/26 07:21:48 Only the case in the old API. In the new API, app
arsany 2016/08/30 00:52:14 Acknowledged.
arsany 2016/08/30 20:23:17 Done.
157 // The native code calls stopCapture() before calling this method.
158 @Override
159 public synchronized void dispose() {
160 isDisposed = true;
161 }
162
163 @Override
164 public void onOutputFormatRequest(final int width, final int height, final int framerate) {
165 checkNotDisposed();
166 surfaceTextureHelper.getHandler().post(new Runnable() {
167 @Override
168 public void run() {
169 capturerObserver.onOutputFormatRequest(width, height, framerate);
170 }
171 });
172 }
173
174 /**
175 * Changes output video format. This method can be used to scale the output
176 * video, or to change orientation when the captured screen is rotated for exa mple.
177 *
178 * Call {@code VideoSource.stop()}
179 * before calling this method and {@code VideoSource.restart()} after that.
180 *
181 * @param width new output video width
182 * @param height new output video height
183 * @param ignored_framerate ignored
184 */
185 @Override
186 public void changeCaptureFormat(int width, int height, int ignored_framerate) {
sakal 2016/08/26 07:21:49 I think this should match the behavior of camera i
arsany 2016/08/30 00:52:15 Done. Agreed. PTAL
187 checkNotDisposed();
188 if (isCapturing) {
189 throw new RuntimeException("changeCaptureFormat can be called only" +
190 " when capturer is stopped");
191 }
192 this.width = width;
193 this.height = height;
194 }
195
196 // This is called on the internal looper thread of {@Code SurfaceTextureHelper }.
197 @Override
198 public void onTextureFrameAvailable(int oesTextureId, float[] transformMatrix, long timestampNs) {
199 numCapturedFrames++;
200 capturerObserver.onTextureFrameCaptured(width, height, oesTextureId, transfo rmMatrix,
201 0 /* rotation */, timestampNs);
202 }
203
204 @Override
205 public boolean isScreencast() {
206 return true;
207 }
208
209 public long getNumCapturedFrames() {
210 return numCapturedFrames;
211 }
212 }
213
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698