OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2016 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 package org.webrtc; | 11 package org.webrtc; |
12 | 12 |
13 import android.content.Context; | 13 import android.content.Context; |
14 import android.media.MediaRecorder; | |
14 import android.os.Handler; | 15 import android.os.Handler; |
15 import android.os.Looper; | 16 import android.os.Looper; |
16 import java.util.Arrays; | 17 import java.util.Arrays; |
17 | 18 |
18 @SuppressWarnings("deprecation") | 19 @SuppressWarnings("deprecation") |
19 abstract class CameraCapturer implements CameraVideoCapturer { | 20 abstract class CameraCapturer implements CameraVideoCapturer { |
20 enum SwitchState { | 21 enum SwitchState { |
21 IDLE, // No switch requested. | 22 IDLE, // No switch requested. |
22 PENDING, // Waiting for previous capture session to open. | 23 PENDING, // Waiting for previous capture session to open. |
23 IN_PROGRESS, // Waiting for new switched capture session to start. | 24 IN_PROGRESS, // Waiting for new switched capture session to start. |
24 } | 25 } |
25 | 26 |
27 enum MediaRecorderState { | |
28 IDLE, // No media recording update (add or remove) requested. | |
29 IDLE_TO_ACTIVE, // Waiting for new capture session with added MediaRecorder surface to start. | |
30 ACTIVE_TO_IDLE, // Waiting for new capture session with removed MediaRecorde r surface to start. | |
31 ACTIVE, // MediaRecorder was successfully added to camera pipeline. | |
32 } | |
33 | |
26 private static final String TAG = "CameraCapturer"; | 34 private static final String TAG = "CameraCapturer"; |
27 private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3; | 35 private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3; |
28 private final static int OPEN_CAMERA_DELAY_MS = 500; | 36 private final static int OPEN_CAMERA_DELAY_MS = 500; |
29 private final static int OPEN_CAMERA_TIMEOUT = 10000; | 37 private final static int OPEN_CAMERA_TIMEOUT = 10000; |
30 | 38 |
31 private final CameraEnumerator cameraEnumerator; | 39 private final CameraEnumerator cameraEnumerator; |
32 private final CameraEventsHandler eventsHandler; | 40 private final CameraEventsHandler eventsHandler; |
33 private final Handler uiThreadHandler; | 41 private final Handler uiThreadHandler; |
34 | 42 |
35 private final CameraSession.CreateSessionCallback createSessionCallback = | 43 private final CameraSession.CreateSessionCallback createSessionCallback = |
36 new CameraSession.CreateSessionCallback() { | 44 new CameraSession.CreateSessionCallback() { |
37 @Override | 45 @Override |
38 public void onDone(CameraSession session) { | 46 public void onDone(CameraSession session) { |
39 checkIsOnCameraThread(); | 47 checkIsOnCameraThread(); |
40 Logging.d(TAG, "Create session done"); | 48 Logging.d(TAG, |
49 "Create session done. Switch state: " + switchState | |
50 + ". MediaRecorder state: " + mediaRecorderState); | |
41 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); | 51 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); |
42 synchronized (stateLock) { | 52 synchronized (stateLock) { |
43 capturerObserver.onCapturerStarted(true /* success */); | 53 capturerObserver.onCapturerStarted(true /* success */); |
44 sessionOpening = false; | 54 sessionOpening = false; |
45 currentSession = session; | 55 currentSession = session; |
46 cameraStatistics = new CameraStatistics(surfaceHelper, eventsHandler ); | 56 cameraStatistics = new CameraStatistics(surfaceHelper, eventsHandler ); |
47 firstFrameObserved = false; | 57 firstFrameObserved = false; |
48 stateLock.notifyAll(); | 58 stateLock.notifyAll(); |
49 | 59 |
50 if (switchState == SwitchState.IN_PROGRESS) { | 60 if (switchState == SwitchState.IN_PROGRESS) { |
51 if (switchEventsHandler != null) { | 61 if (switchEventsHandler != null) { |
52 switchEventsHandler.onCameraSwitchDone(cameraEnumerator.isFrontF acing(cameraName)); | 62 switchEventsHandler.onCameraSwitchDone(cameraEnumerator.isFrontF acing(cameraName)); |
53 switchEventsHandler = null; | 63 switchEventsHandler = null; |
54 } | 64 } |
55 switchState = SwitchState.IDLE; | 65 switchState = SwitchState.IDLE; |
56 } else if (switchState == SwitchState.PENDING) { | 66 } else if (switchState == SwitchState.PENDING) { |
57 switchState = SwitchState.IDLE; | 67 switchState = SwitchState.IDLE; |
58 switchCameraInternal(switchEventsHandler); | 68 switchCameraInternal(switchEventsHandler); |
59 } | 69 } |
70 | |
71 if (mediaRecorderState == MediaRecorderState.IDLE_TO_ACTIVE | |
72 || mediaRecorderState == MediaRecorderState.ACTIVE_TO_IDLE) { | |
73 if (mediaRecorderEventsHandler != null) { | |
74 mediaRecorderEventsHandler.onMediaRecorderSuccess(); | |
75 mediaRecorderEventsHandler = null; | |
76 } | |
77 if (mediaRecorderState == MediaRecorderState.IDLE_TO_ACTIVE) { | |
78 mediaRecorderState = MediaRecorderState.ACTIVE; | |
79 } else { | |
80 mediaRecorderState = MediaRecorderState.IDLE; | |
81 } | |
82 mediaRecorder = null; | |
83 } | |
60 } | 84 } |
61 } | 85 } |
62 | 86 |
63 @Override | 87 @Override |
64 public void onFailure(CameraSession.FailureType failureType, String erro r) { | 88 public void onFailure(CameraSession.FailureType failureType, String erro r) { |
65 checkIsOnCameraThread(); | 89 checkIsOnCameraThread(); |
66 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); | 90 uiThreadHandler.removeCallbacks(openCameraTimeoutRunnable); |
67 synchronized (stateLock) { | 91 synchronized (stateLock) { |
68 capturerObserver.onCapturerStarted(false /* success */); | 92 capturerObserver.onCapturerStarted(false /* success */); |
69 openAttemptsRemaining--; | 93 openAttemptsRemaining--; |
70 | 94 |
71 if (openAttemptsRemaining <= 0) { | 95 if (openAttemptsRemaining <= 0) { |
72 Logging.w(TAG, "Opening camera failed, passing: " + error); | 96 Logging.w(TAG, "Opening camera failed, passing: " + error); |
73 sessionOpening = false; | 97 sessionOpening = false; |
74 stateLock.notifyAll(); | 98 stateLock.notifyAll(); |
75 | 99 |
76 if (switchState != SwitchState.IDLE) { | 100 if (switchState != SwitchState.IDLE) { |
77 if (switchEventsHandler != null) { | 101 if (switchEventsHandler != null) { |
78 switchEventsHandler.onCameraSwitchError(error); | 102 switchEventsHandler.onCameraSwitchError(error); |
79 switchEventsHandler = null; | 103 switchEventsHandler = null; |
80 } | 104 } |
81 switchState = SwitchState.IDLE; | 105 switchState = SwitchState.IDLE; |
82 } | 106 } |
83 | 107 |
108 if (mediaRecorderState != MediaRecorderState.IDLE) { | |
109 if (mediaRecorderEventsHandler != null) { | |
110 mediaRecorderEventsHandler.onMediaRecorderError(error); | |
111 mediaRecorderEventsHandler = null; | |
112 } | |
113 mediaRecorderState = MediaRecorderState.IDLE; | |
114 mediaRecorder = null; | |
115 } | |
116 | |
84 if (failureType == CameraSession.FailureType.DISCONNECTED) { | 117 if (failureType == CameraSession.FailureType.DISCONNECTED) { |
85 eventsHandler.onCameraDisconnected(); | 118 eventsHandler.onCameraDisconnected(); |
86 } else { | 119 } else { |
87 eventsHandler.onCameraError(error); | 120 eventsHandler.onCameraError(error); |
88 } | 121 } |
89 } else { | 122 } else { |
90 Logging.w(TAG, "Opening camera failed, retry: " + error); | 123 Logging.w(TAG, "Opening camera failed, retry: " + error); |
91 | 124 |
92 createSessionInternal(OPEN_CAMERA_DELAY_MS); | 125 createSessionInternal(OPEN_CAMERA_DELAY_MS); |
93 } | 126 } |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
206 private int width; /* guarded by stateLock */ | 239 private int width; /* guarded by stateLock */ |
207 private int height; /* guarded by stateLock */ | 240 private int height; /* guarded by stateLock */ |
208 private int framerate; /* guarded by stateLock */ | 241 private int framerate; /* guarded by stateLock */ |
209 private int openAttemptsRemaining; /* guarded by stateLock */ | 242 private int openAttemptsRemaining; /* guarded by stateLock */ |
210 private SwitchState switchState = SwitchState.IDLE; /* guarded by stateLock */ | 243 private SwitchState switchState = SwitchState.IDLE; /* guarded by stateLock */ |
211 private CameraSwitchHandler switchEventsHandler; /* guarded by stateLock */ | 244 private CameraSwitchHandler switchEventsHandler; /* guarded by stateLock */ |
212 // Valid from onDone call until stopCapture, otherwise null. | 245 // Valid from onDone call until stopCapture, otherwise null. |
213 private CameraStatistics cameraStatistics; /* guarded by stateLock */ | 246 private CameraStatistics cameraStatistics; /* guarded by stateLock */ |
214 private boolean firstFrameObserved; /* guarded by stateLock */ | 247 private boolean firstFrameObserved; /* guarded by stateLock */ |
215 | 248 |
249 // Variables used on camera thread - do not require stateLock synchronization. | |
250 private MediaRecorderState mediaRecorderState = MediaRecorderState.IDLE; | |
251 private MediaRecorderHandler mediaRecorderEventsHandler; | |
252 private MediaRecorder mediaRecorder; | |
253 | |
216 public CameraCapturer( | 254 public CameraCapturer( |
217 String cameraName, CameraEventsHandler eventsHandler, CameraEnumerator cam eraEnumerator) { | 255 String cameraName, CameraEventsHandler eventsHandler, CameraEnumerator cam eraEnumerator) { |
218 if (eventsHandler == null) { | 256 if (eventsHandler == null) { |
219 eventsHandler = new CameraEventsHandler() { | 257 eventsHandler = new CameraEventsHandler() { |
220 @Override | 258 @Override |
221 public void onCameraError(String errorDescription) {} | 259 public void onCameraError(String errorDescription) {} |
222 @Override | 260 @Override |
223 public void onCameraDisconnected() {} | 261 public void onCameraDisconnected() {} |
224 @Override | 262 @Override |
225 public void onCameraFreezed(String errorDescription) {} | 263 public void onCameraFreezed(String errorDescription) {} |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
280 createSessionInternal(0); | 318 createSessionInternal(0); |
281 } | 319 } |
282 } | 320 } |
283 | 321 |
284 private void createSessionInternal(int delayMs) { | 322 private void createSessionInternal(int delayMs) { |
285 uiThreadHandler.postDelayed(openCameraTimeoutRunnable, delayMs + OPEN_CAMERA _TIMEOUT); | 323 uiThreadHandler.postDelayed(openCameraTimeoutRunnable, delayMs + OPEN_CAMERA _TIMEOUT); |
286 cameraThreadHandler.postDelayed(new Runnable() { | 324 cameraThreadHandler.postDelayed(new Runnable() { |
287 @Override | 325 @Override |
288 public void run() { | 326 public void run() { |
289 createCameraSession(createSessionCallback, cameraSessionEventsHandler, a pplicationContext, | 327 createCameraSession(createSessionCallback, cameraSessionEventsHandler, a pplicationContext, |
290 surfaceHelper, cameraName, width, height, framerate); | 328 surfaceHelper, mediaRecorder, cameraName, width, height, framerate); |
291 } | 329 } |
292 }, delayMs); | 330 }, delayMs); |
293 } | 331 } |
294 | 332 |
295 @Override | 333 @Override |
296 public void stopCapture() { | 334 public void stopCapture() { |
297 Logging.d(TAG, "Stop capture"); | 335 Logging.d(TAG, "Stop capture"); |
298 | 336 |
299 synchronized (stateLock) { | 337 synchronized (stateLock) { |
300 while (sessionOpening) { | 338 while (sessionOpening) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
343 Logging.d(TAG, "switchCamera"); | 381 Logging.d(TAG, "switchCamera"); |
344 cameraThreadHandler.post(new Runnable() { | 382 cameraThreadHandler.post(new Runnable() { |
345 @Override | 383 @Override |
346 public void run() { | 384 public void run() { |
347 switchCameraInternal(switchEventsHandler); | 385 switchCameraInternal(switchEventsHandler); |
348 } | 386 } |
349 }); | 387 }); |
350 } | 388 } |
351 | 389 |
352 @Override | 390 @Override |
391 public void addMediaRecorderToCamera( | |
392 final MediaRecorder mediaRecorder, final MediaRecorderHandler mediaRecoder EventsHandler) { | |
393 Logging.d(TAG, "addMediaRecorderToCamera"); | |
394 cameraThreadHandler.post(new Runnable() { | |
395 @Override | |
396 public void run() { | |
397 updateMediaRecorderInternal(mediaRecorder, mediaRecoderEventsHandler); | |
398 } | |
399 }); | |
400 } | |
401 | |
402 @Override | |
403 public void removeMediaRecorderFromCamera(final MediaRecorderHandler mediaReco derEventsHandler) { | |
404 Logging.d(TAG, "removeMediaRecorderFromCamera"); | |
405 cameraThreadHandler.post(new Runnable() { | |
406 @Override | |
407 public void run() { | |
408 updateMediaRecorderInternal(null /* mediaRecorder */, mediaRecoderEvents Handler); | |
409 } | |
410 }); | |
411 } | |
412 | |
413 @Override | |
353 public boolean isScreencast() { | 414 public boolean isScreencast() { |
354 return false; | 415 return false; |
355 } | 416 } |
356 | 417 |
357 public void printStackTrace() { | 418 public void printStackTrace() { |
358 Thread cameraThread = null; | 419 Thread cameraThread = null; |
359 if (cameraThreadHandler != null) { | 420 if (cameraThreadHandler != null) { |
360 cameraThread = cameraThreadHandler.getLooper().getThread(); | 421 cameraThread = cameraThreadHandler.getLooper().getThread(); |
361 } | 422 } |
362 if (cameraThread != null) { | 423 if (cameraThread != null) { |
363 StackTraceElement[] cameraStackTrace = cameraThread.getStackTrace(); | 424 StackTraceElement[] cameraStackTrace = cameraThread.getStackTrace(); |
364 if (cameraStackTrace.length > 0) { | 425 if (cameraStackTrace.length > 0) { |
365 Logging.d(TAG, "CameraCapturer stack trace:"); | 426 Logging.d(TAG, "CameraCapturer stack trace:"); |
366 for (StackTraceElement traceElem : cameraStackTrace) { | 427 for (StackTraceElement traceElem : cameraStackTrace) { |
367 Logging.d(TAG, traceElem.toString()); | 428 Logging.d(TAG, traceElem.toString()); |
368 } | 429 } |
369 } | 430 } |
370 } | 431 } |
371 } | 432 } |
372 | 433 |
434 private void reportCameraSwitchError(String error, CameraSwitchHandler switchE ventsHandler) { | |
435 Logging.e(TAG, error); | |
436 if (switchEventsHandler != null) { | |
437 switchEventsHandler.onCameraSwitchError(error); | |
438 } | |
439 } | |
440 | |
373 private void switchCameraInternal(final CameraSwitchHandler switchEventsHandle r) { | 441 private void switchCameraInternal(final CameraSwitchHandler switchEventsHandle r) { |
374 Logging.d(TAG, "switchCamera internal"); | 442 Logging.d(TAG, "switchCamera internal"); |
375 | 443 |
376 final String[] deviceNames = cameraEnumerator.getDeviceNames(); | 444 final String[] deviceNames = cameraEnumerator.getDeviceNames(); |
377 | 445 |
378 if (deviceNames.length < 2) { | 446 if (deviceNames.length < 2) { |
379 if (switchEventsHandler != null) { | 447 if (switchEventsHandler != null) { |
380 switchEventsHandler.onCameraSwitchError("No camera to switch to."); | 448 switchEventsHandler.onCameraSwitchError("No camera to switch to."); |
381 } | 449 } |
382 return; | 450 return; |
383 } | 451 } |
384 | 452 |
385 synchronized (stateLock) { | 453 synchronized (stateLock) { |
386 if (switchState != SwitchState.IDLE) { | 454 if (switchState != SwitchState.IDLE) { |
387 Logging.d(TAG, "switchCamera switchInProgress"); | 455 reportCameraSwitchError("Camera switch already in progress.", switchEven tsHandler); |
388 if (switchEventsHandler != null) { | 456 return; |
389 switchEventsHandler.onCameraSwitchError("Camera switch already in prog ress."); | 457 } |
390 } | 458 if (mediaRecorderState != MediaRecorderState.IDLE) { |
459 reportCameraSwitchError("switchCamera: media recording is active", switc hEventsHandler); | |
460 return; | |
461 } | |
462 if (!sessionOpening && currentSession == null) { | |
463 reportCameraSwitchError("switchCamera: camera is not running.", switchEv entsHandler); | |
391 return; | 464 return; |
392 } | 465 } |
393 | 466 |
394 if (!sessionOpening && currentSession == null) { | |
395 Logging.d(TAG, "switchCamera: No session open"); | |
396 if (switchEventsHandler != null) { | |
397 switchEventsHandler.onCameraSwitchError("Camera is not running."); | |
398 } | |
399 return; | |
400 } | |
401 | |
402 this.switchEventsHandler = switchEventsHandler; | 467 this.switchEventsHandler = switchEventsHandler; |
403 if (sessionOpening) { | 468 if (sessionOpening) { |
404 switchState = SwitchState.PENDING; | 469 switchState = SwitchState.PENDING; |
405 return; | 470 return; |
406 } else { | 471 } else { |
407 switchState = SwitchState.IN_PROGRESS; | 472 switchState = SwitchState.IN_PROGRESS; |
408 } | 473 } |
409 | 474 |
410 Logging.d(TAG, "switchCamera: Stopping session"); | 475 Logging.d(TAG, "switchCamera: Stopping session"); |
411 cameraStatistics.release(); | 476 cameraStatistics.release(); |
(...skipping 10 matching lines...) Expand all Loading... | |
422 int cameraNameIndex = Arrays.asList(deviceNames).indexOf(cameraName); | 487 int cameraNameIndex = Arrays.asList(deviceNames).indexOf(cameraName); |
423 cameraName = deviceNames[(cameraNameIndex + 1) % deviceNames.length]; | 488 cameraName = deviceNames[(cameraNameIndex + 1) % deviceNames.length]; |
424 | 489 |
425 sessionOpening = true; | 490 sessionOpening = true; |
426 openAttemptsRemaining = 1; | 491 openAttemptsRemaining = 1; |
427 createSessionInternal(0); | 492 createSessionInternal(0); |
428 } | 493 } |
429 Logging.d(TAG, "switchCamera done"); | 494 Logging.d(TAG, "switchCamera done"); |
430 } | 495 } |
431 | 496 |
497 private void reportUpdateMediaRecorderError( | |
498 String error, MediaRecorderHandler mediaRecoderEventsHandler) { | |
499 checkIsOnCameraThread(); | |
500 Logging.e(TAG, error); | |
501 if (mediaRecoderEventsHandler != null) { | |
502 mediaRecoderEventsHandler.onMediaRecorderError(error); | |
503 } | |
504 } | |
505 | |
506 private void updateMediaRecorderInternal( | |
507 MediaRecorder mediaRecorder, MediaRecorderHandler mediaRecoderEventsHandle r) { | |
508 checkIsOnCameraThread(); | |
509 boolean addMediaRecorder = (mediaRecorder != null); | |
510 Logging.d(TAG, | |
511 "updateMediaRecoderInternal internal. State: " + mediaRecorderState | |
512 + ". Switch state: " + switchState + ". Add MediaRecorder: " + addMe diaRecorder); | |
513 | |
514 synchronized (stateLock) { | |
515 if ((addMediaRecorder && mediaRecorderState != MediaRecorderState.IDLE) | |
516 || (!addMediaRecorder && mediaRecorderState != MediaRecorderState.ACTI VE)) { | |
517 reportUpdateMediaRecorderError( | |
518 "Incorrect state for MediaRecorder update.", mediaRecoderEventsHandl er); | |
519 return; | |
520 } | |
521 if (switchState != SwitchState.IDLE) { | |
522 reportUpdateMediaRecorderError( | |
523 "MediaRecorder update while camera is switching.", mediaRecoderEvent sHandler); | |
524 return; | |
525 } | |
526 if (currentSession == null) { | |
527 reportUpdateMediaRecorderError( | |
528 "MediaRecorder update while camera is closed.", mediaRecoderEventsHa ndler); | |
529 return; | |
530 } | |
531 if (sessionOpening) { | |
532 reportUpdateMediaRecorderError( | |
533 "MediaRecorder update while camera is still opening.", mediaRecoderE ventsHandler); | |
534 return; | |
535 } | |
536 | |
537 this.mediaRecorderEventsHandler = mediaRecoderEventsHandler; | |
538 if (addMediaRecorder) { | |
sakal
2017/04/26 07:34:12
nit: can be replaced with a ternary operator
AlexG
2017/04/26 21:04:10
Done.
| |
539 mediaRecorderState = MediaRecorderState.IDLE_TO_ACTIVE; | |
540 } else { | |
541 mediaRecorderState = MediaRecorderState.ACTIVE_TO_IDLE; | |
542 } | |
543 this.mediaRecorder = mediaRecorder; | |
544 | |
545 Logging.d(TAG, "updateMediaRecoder: Stopping session"); | |
546 cameraStatistics.release(); | |
547 cameraStatistics = null; | |
548 final CameraSession oldSession = currentSession; | |
549 cameraThreadHandler.post(new Runnable() { | |
550 @Override | |
551 public void run() { | |
552 oldSession.stop(); | |
553 } | |
554 }); | |
555 currentSession = null; | |
556 | |
557 sessionOpening = true; | |
558 openAttemptsRemaining = 1; | |
559 createSessionInternal(0); | |
560 } | |
561 Logging.d(TAG, "updateMediaRecoderInternal done"); | |
562 } | |
563 | |
432 private void checkIsOnCameraThread() { | 564 private void checkIsOnCameraThread() { |
433 if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) { | 565 if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) { |
434 Logging.e(TAG, "Check is on camera thread failed."); | 566 Logging.e(TAG, "Check is on camera thread failed."); |
435 throw new RuntimeException("Not on camera thread."); | 567 throw new RuntimeException("Not on camera thread."); |
436 } | 568 } |
437 } | 569 } |
438 | 570 |
439 protected String getCameraName() { | 571 protected String getCameraName() { |
440 synchronized (stateLock) { | 572 synchronized (stateLock) { |
441 return cameraName; | 573 return cameraName; |
442 } | 574 } |
443 } | 575 } |
444 | 576 |
445 abstract protected void createCameraSession( | 577 abstract protected void createCameraSession( |
446 CameraSession.CreateSessionCallback createSessionCallback, CameraSession.E vents events, | 578 CameraSession.CreateSessionCallback createSessionCallback, CameraSession.E vents events, |
447 Context applicationContext, SurfaceTextureHelper surfaceTextureHelper, Str ing cameraName, | 579 Context applicationContext, SurfaceTextureHelper surfaceTextureHelper, |
448 int width, int height, int framerate); | 580 MediaRecorder mediaRecoder, String cameraName, int width, int height, int framerate); |
449 } | 581 } |
OLD | NEW |