Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[camera] flip/change camera while recording (split out PR for cam_avfoundation and cam_android) #7109

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
125 commits
Select commit Hold shift + click to select a range
dcf5051
setDescription in Camera platform interface
BradenBagbyWavv Sep 21, 2022
6ebbf8f
Merge remote-tracking branch 'upstream/main' into feature/switch-camera
BradenBagbyWavv Sep 21, 2022
ffd30f0
example app setup to change description mid recording
BradenBagbyWavv Sep 21, 2022
bc9e8b9
AVFoundationCamera method call to setDescription
BradenBagbyWavv Sep 21, 2022
89accd6
FLTCam setup to setDescription
BradenBagbyWavv Sep 21, 2022
e31ba2a
captureSession split into video and audio so we will be able to switc…
BradenBagbyWavv Sep 21, 2022
ac2c249
renamed setDescription to setDescriptionWhileRecording since it can o…
BradenBagbyWavv Sep 21, 2022
1516e0d
integration tests fixed
BradenBagbyWavv Sep 21, 2022
34b9b03
set description while recording integration test
BradenBagbyWavv Sep 21, 2022
97f9733
throws error if device not recording and setDescriptionWhileRecording…
BradenBagbyWavv Sep 21, 2022
bca93e2
set description while recording test
BradenBagbyWavv Sep 21, 2022
b999be1
example project setup
BradenBagbyWavv Sep 22, 2022
568af7d
camera preview can be changed while recording
BradenBagbyWavv Sep 22, 2022
ef4f96b
camera switches and keeps surface pointed to mediarecorder
BradenBagbyWavv Sep 22, 2022
f36004d
small change to set autofocus when switching while recording
BradenBagbyWavv Sep 22, 2022
a0301c2
android video record goes through VideoRenderer to apply matrix after…
BradenBagbyWavv Sep 22, 2022
e929814
switch camera uses VideoRenderer
BradenBagbyWavv Sep 23, 2022
156f78a
dont use video renderer until user switches camera while recording
BradenBagbyWavv Sep 23, 2022
61468a9
rotate based on initial recording direction
BradenBagbyWavv Sep 23, 2022
aea9067
VideoRenderer cleanup
BradenBagbyWavv Sep 23, 2022
fdf5738
flutter results for setDescriptionWhileRecording
BradenBagbyWavv Sep 23, 2022
d9862f3
error if you setDescriptionWhileRecording while device is not recording
BradenBagbyWavv Sep 23, 2022
a20e5d3
android tests
BradenBagbyWavv Sep 23, 2022
5044d94
integration tests
BradenBagbyWavv Sep 23, 2022
667c803
method channel test
BradenBagbyWavv Sep 23, 2022
3b45ff5
main package tests
BradenBagbyWavv Sep 23, 2022
5d96ffd
setDescriptionWhileRecording called while no video was recording test
BradenBagbyWavv Sep 23, 2022
aa1d070
integration tests
BradenBagbyWavv Sep 23, 2022
858ce2e
dependency overrides
BradenBagbyWavv Sep 23, 2022
58bdcf6
update readme and version
BradenBagbyWavv Sep 23, 2022
c29ed5d
removed old TODO
BradenBagbyWavv Sep 23, 2022
156ad27
removed accidental dev team ID commit
BradenBagbyWavv Sep 26, 2022
2dbaccb
renamed local variables
BradenBagbyWavv Sep 26, 2022
c17f133
use captureSessionQueue
BradenBagbyWavv Sep 26, 2022
bfbdc48
fixed local variable name
BradenBagbyWavv Sep 26, 2022
dad170f
setupCaptureVideoOutput function
BradenBagbyWavv Sep 26, 2022
4017924
createConnectionWithInput
BradenBagbyWavv Sep 26, 2022
6d4c5a3
simplified configureConnection function to re-use code on switching c…
BradenBagbyWavv Sep 26, 2022
0ab3548
formatting
BradenBagbyWavv Sep 26, 2022
28c89f8
example project dependency overrides
BradenBagbyWavv Sep 27, 2022
9aa5289
fixed versioning
BradenBagbyWavv Sep 27, 2022
57f5f77
formatting
BradenBagbyWavv Sep 27, 2022
ccf9e63
fixed some ios native tests
BradenBagbyWavv Sep 27, 2022
9041121
fixed small bug
BradenBagbyWavv Sep 27, 2022
b03a4a5
dont emit initialized when switching camera
BradenBagbyWavv Sep 27, 2022
cfe8e20
ios formatting
BradenBagbyWavv Sep 27, 2022
7e338e4
dependency overrides for camera/example
BradenBagbyWavv Sep 27, 2022
ce6950c
android formatting
BradenBagbyWavv Sep 27, 2022
563329e
ios test formatted
BradenBagbyWavv Sep 27, 2022
9a32c1a
android tests formatted
BradenBagbyWavv Sep 27, 2022
eb47113
android format that I missed
BradenBagbyWavv Sep 27, 2022
f01f63f
other android formatting
BradenBagbyWavv Sep 27, 2022
4bdac9d
final formatting with flutter tool
BradenBagbyWavv Sep 27, 2022
68d8c8f
formatted android again
BradenBagbyWavv Sep 27, 2022
a001e02
android license in new file
BradenBagbyWavv Sep 27, 2022
322bdf5
update-excerpts ran
BradenBagbyWavv Sep 28, 2022
e62d860
Merge branch 'main' into feature/switch-camera
BradenBagby Sep 28, 2022
d9aaba0
fixed changelog
BradenBagbyWavv Sep 29, 2022
a9bb9f8
removed development team
BradenBagbyWavv Sep 29, 2022
9e40600
renames configureConnection to createConnection
BradenBagbyWavv Sep 29, 2022
4753c00
Merge branch 'main' into feature/switch-camera
BradenBagby Sep 29, 2022
5a55b7a
renames unimplemented error message
BradenBagbyWavv Oct 3, 2022
ad5d62f
renames setDescriptionWhileRecording error to match android and the o…
BradenBagbyWavv Oct 3, 2022
cb36849
fixes formatting
BradenBagbyWavv Oct 3, 2022
94c0be3
removes override dependencies from camera_web and camera_windows
BradenBagbyWavv Oct 3, 2022
f8824ed
removes camera_web override dependency in camera package
BradenBagbyWavv Oct 3, 2022
5d3bc8a
Update packages/camera/camera_android/android/src/main/java/io/flutte…
BradenBagby Oct 20, 2022
54e062d
Update packages/camera/camera_android/android/src/main/java/io/flutte…
BradenBagby Oct 21, 2022
ca2880f
Update packages/camera/camera_android/android/src/main/java/io/flutte…
BradenBagby Oct 21, 2022
f2e1569
Update packages/camera/camera_android/android/src/main/java/io/flutte…
BradenBagby Oct 21, 2022
5b7327e
Merge branch 'main' into feature/switch-camera
BradenBagby Oct 21, 2022
89b7c2f
reformats camera.java
BradenBagbyWavv Oct 21, 2022
619773d
VideoRenderer uses surface texture timestamp instead of current syste…
BradenBagbyWavv Oct 21, 2022
5e36473
formats VideoRenderer.java
BradenBagbyWavv Oct 21, 2022
973b1f8
fixes comments in VideoRenderer.java
BradenBagbyWavv Oct 21, 2022
8bd178e
Update packages/camera/camera_platform_interface/lib/src/platform_int…
BradenBagby Oct 28, 2022
08e158b
Update packages/camera/camera/lib/src/camera_controller.dart
BradenBagby Oct 28, 2022
1f2635e
renames error typo
BradenBagbyWavv Oct 31, 2022
70da5ef
frees shaders after program linking
BradenBagbyWavv Nov 1, 2022
aec423d
handles eglSwapBuffers errors
BradenBagbyWavv Nov 1, 2022
53d3e1d
extension check guards eglPresentationTimeANDROID
BradenBagbyWavv Nov 1, 2022
98969d1
cleans openGL resources
BradenBagbyWavv Nov 7, 2022
f2c4876
reverted timestamp to use uptimeMillis()
BradenBagbyWavv Nov 14, 2022
7b958ee
Merge branch 'main' into feature/switch-camera
BradenBagby Nov 22, 2022
8145162
Tests for startPreviewWithVideoRendererStream
BradenBagbyWavv Nov 28, 2022
a8e0a72
fixes exception not being caught
BradenBagbyWavv Nov 28, 2022
ea28413
tests for correct rotation to be set
BradenBagbyWavv Nov 29, 2022
a12e3f4
fixes versioning
BradenBagbyWavv Dec 4, 2022
98a493b
tests method channel setDescriptionWhileRecording
BradenBagbyWavv Dec 4, 2022
9f3fc49
adds forwarding getter on CameraController to its value's description
BradenBagbyWavv Dec 5, 2022
2c5e38f
dummy commit to fix github test's not finding commit hash
BradenBagbyWavv Dec 5, 2022
3a8fd89
adds override description for FakeController in camera tests
BradenBagbyWavv Dec 5, 2022
e52dfcc
fixes versioning for avfoundation and android
BradenBagbyWavv Dec 5, 2022
269260f
Merge branch 'main' into feature/switch-camera
BradenBagby Dec 5, 2022
e6bd484
Merge branch 'master' into feature/switch-camera
BradenBagbyWavv Dec 6, 2022
0c70970
fixes versioning
BradenBagbyWavv Dec 6, 2022
247bacb
Merge branch 'master' into feature/switch-camera
BradenBagbyWavv Dec 6, 2022
f831e4e
Merge branch 'master' into feature/switch-camera
BradenBagbyWavv Dec 9, 2022
d49dcf7
fixes pubspec versions
BradenBagbyWavv Dec 9, 2022
3d8fa3a
Merge branch 'main' into feature/switch-camera
BradenBagby Dec 16, 2022
14004fd
Merge branch 'master' into feature/switch-camera
BradenBagbyWavv Dec 22, 2022
2d154b5
Merge branch 'main' into feature/switch-camera
BradenBagby Jan 10, 2023
e95eea9
ios setDescription
BradenBagbyWavv Jan 11, 2023
e0a5fbb
setDescription
BradenBagbyWavv Jan 11, 2023
9fdba25
android setDescription
BradenBagbyWavv Jan 11, 2023
ff17835
formatting
BradenBagbyWavv Jan 11, 2023
02b847a
revert
BradenBagbyWavv Jan 11, 2023
8330cc9
nits and reverts
BradenBagbyWavv Jan 11, 2023
fbf2a23
nits
BradenBagbyWavv Jan 11, 2023
fa33e4f
fixes README
BradenBagbyWavv Jan 11, 2023
998a366
fixes other comments
BradenBagbyWavv Jan 11, 2023
1eeaacc
fixes setDescription override in camera_preview_test
BradenBagbyWavv Jan 11, 2023
a380c4d
set description test
BradenBagbyWavv Jan 12, 2023
cb72a67
Merge branch 'main' into feature/switch-camera
BradenBagby Jan 23, 2023
f6f8775
Merge branch 'master' into feature/switch-camera
BradenBagby Jan 30, 2023
2fe0024
versions
BradenBagby Jan 30, 2023
d1a2a94
removes changes on platform_interface_changes
BradenBagby Feb 6, 2023
e74c2af
points all packages to platform interface version 2.4
BradenBagby Feb 6, 2023
49e91c2
points to the new platform interface
BradenBagby Feb 6, 2023
be29466
Merge branch 'main' into feature/switch-camera
BradenBagby Feb 6, 2023
4796995
removes everything that isnt under camera_avfoundation and camera_and…
BradenBagby Feb 6, 2023
62ec3ca
removes dependency overrides in examples
BradenBagby Feb 6, 2023
14b6499
removes version change on camera
BradenBagby Feb 6, 2023
772dbd3
removes camera changes that were missed
BradenBagby Feb 6, 2023
3623e48
fixes android version
BradenBagby Feb 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/camera/camera_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.10.5

* Allows camera to be switched while video recording.

## 0.10.4

* Temporarily fixes issue with requested video profiles being null by falling back to deprecated behavior in that case.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,28 @@ class Camera
* Holds all of the camera features/settings and will be used to update the request builder when
* one changes.
*/
private final CameraFeatures cameraFeatures;
private CameraFeatures cameraFeatures;

private String imageFormatGroup;

/**
* Takes an input/output surface and orients the recording correctly. This is needed because
* switching cameras while recording causes the wrong orientation.
*/
private VideoRenderer videoRenderer;

/**
* Whether or not the camera aligns with the initial way the camera was facing if the camera was
* flipped.
*/
private int initialCameraFacing;

private final SurfaceTextureEntry flutterTexture;
private final ResolutionPreset resolutionPreset;
private final boolean enableAudio;
private final Context applicationContext;
private final DartMessenger dartMessenger;
private final CameraProperties cameraProperties;
private CameraProperties cameraProperties;
private final CameraFeatureFactory cameraFeatureFactory;
private final Activity activity;
/** A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture. */
Expand Down Expand Up @@ -211,6 +226,7 @@ public Camera(
this.applicationContext = activity.getApplicationContext();
this.cameraProperties = cameraProperties;
this.cameraFeatureFactory = cameraFeatureFactory;
this.resolutionPreset = resolutionPreset;
this.cameraFeatures =
CameraFeatures.init(
cameraFeatureFactory, cameraProperties, activity, dartMessenger, resolutionPreset);
Expand Down Expand Up @@ -251,6 +267,7 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException {
if (mediaRecorder != null) {
mediaRecorder.release();
}
closeRenderer();

final PlatformChannel.DeviceOrientation lockedOrientation =
((SensorOrientationFeature) cameraFeatures.getSensorOrientation())
Expand Down Expand Up @@ -279,6 +296,7 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException {

@SuppressLint("MissingPermission")
public void open(String imageFormatGroup) throws CameraAccessException {
this.imageFormatGroup = imageFormatGroup;
final ResolutionFeature resolutionFeature = cameraFeatures.getResolution();

if (!resolutionFeature.checkIsSupported()) {
Expand Down Expand Up @@ -323,14 +341,16 @@ public void onOpened(@NonNull CameraDevice device) {
cameraDevice = new DefaultCameraDeviceWrapper(device);
try {
startPreview();
if (!recordingVideo) // only send initialization if we werent already recording and switching cameras
dartMessenger.sendCameraInitializedEvent(
resolutionFeature.getPreviewSize().getWidth(),
resolutionFeature.getPreviewSize().getHeight(),
cameraFeatures.getExposureLock().getValue(),
cameraFeatures.getAutoFocus().getValue(),
cameraFeatures.getExposurePoint().checkIsSupported(),
cameraFeatures.getFocusPoint().checkIsSupported());
} catch (CameraAccessException e) {
resolutionFeature.getPreviewSize().getWidth(),
resolutionFeature.getPreviewSize().getHeight(),
cameraFeatures.getExposureLock().getValue(),
cameraFeatures.getAutoFocus().getValue(),
cameraFeatures.getExposurePoint().checkIsSupported(),
cameraFeatures.getFocusPoint().checkIsSupported());

} catch (CameraAccessException | InterruptedException e) {
dartMessenger.sendCameraErrorEvent(e.getMessage());
close();
}
Expand All @@ -340,7 +360,8 @@ public void onOpened(@NonNull CameraDevice device) {
public void onClosed(@NonNull CameraDevice camera) {
Log.i(TAG, "open | onClosed");

// Prevents calls to methods that would otherwise result in IllegalStateException exceptions.
// Prevents calls to methods that would otherwise result in IllegalStateException
// exceptions.
cameraDevice = null;
closeCaptureSession();
dartMessenger.sendCameraClosingEvent();
Expand Down Expand Up @@ -756,7 +777,7 @@ public void startVideoRecording(
if (imageStreamChannel != null) {
setStreamHandler(imageStreamChannel);
}

initialCameraFacing = cameraProperties.getLensFacing();
recordingVideo = true;
try {
startCapture(true, imageStreamChannel != null);
Expand All @@ -768,6 +789,13 @@ public void startVideoRecording(
}
}

private void closeRenderer() {
if (videoRenderer != null) {
videoRenderer.close();
videoRenderer = null;
}
}

public void stopVideoRecording(@NonNull final Result result) {
if (!recordingVideo) {
result.success(null);
Expand All @@ -778,6 +806,7 @@ public void stopVideoRecording(@NonNull final Result result) {
cameraFeatureFactory.createAutoFocusFeature(cameraProperties, false));
recordingVideo = false;
try {
closeRenderer();
captureSession.abortCaptures();
mediaRecorder.stop();
} catch (CameraAccessException | IllegalStateException e) {
Expand All @@ -786,7 +815,7 @@ public void stopVideoRecording(@NonNull final Result result) {
mediaRecorder.reset();
try {
startPreview();
} catch (CameraAccessException | IllegalStateException e) {
} catch (CameraAccessException | IllegalStateException | InterruptedException e) {
result.error("videoRecordingFailed", e.getMessage(), null);
return;
}
Expand Down Expand Up @@ -1070,13 +1099,51 @@ public void resumePreview() {
null, (code, message) -> dartMessenger.sendCameraErrorEvent(message));
}

public void startPreview() throws CameraAccessException {
public void startPreview() throws CameraAccessException, InterruptedException {
// If recording is already in progress, the camera is being flipped, so send it through the VideoRenderer to keep the correct orientation.
if (recordingVideo) {
startPreviewWithVideoRendererStream();
} else {
startRegularPreview();
}
}

private void startRegularPreview() throws CameraAccessException {
if (pictureImageReader == null || pictureImageReader.getSurface() == null) return;
Log.i(TAG, "startPreview");

createCaptureSession(CameraDevice.TEMPLATE_PREVIEW, pictureImageReader.getSurface());
}

private void startPreviewWithVideoRendererStream()
throws CameraAccessException, InterruptedException {
if (videoRenderer == null) return;

// get rotation for rendered video
final PlatformChannel.DeviceOrientation lockedOrientation =
((SensorOrientationFeature) cameraFeatures.getSensorOrientation())
.getLockedCaptureOrientation();
DeviceOrientationManager orientationManager =
cameraFeatures.getSensorOrientation().getDeviceOrientationManager();

int rotation = 0;
if (orientationManager != null) {
rotation =
lockedOrientation == null
? orientationManager.getVideoOrientation()
: orientationManager.getVideoOrientation(lockedOrientation);
}

if (cameraProperties.getLensFacing() != initialCameraFacing) {

// If the new camera is facing the opposite way than the initial recording,
// the rotation should be flipped 180 degrees.
rotation = (rotation + 180) % 360;
}
videoRenderer.setRotation(rotation);

createCaptureSession(CameraDevice.TEMPLATE_RECORD, videoRenderer.getInputSurface());
}

public void startPreviewWithImageStream(EventChannel imageStreamChannel)
throws CameraAccessException {
setStreamHandler(imageStreamChannel);
Expand Down Expand Up @@ -1200,17 +1267,7 @@ private void closeCaptureSession() {
public void close() {
Log.i(TAG, "close");

if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;

// Closing the CameraDevice without closing the CameraCaptureSession is recommended
// for quickly closing the camera:
// https://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession#close()
captureSession = null;
} else {
closeCaptureSession();
}
stopAndReleaseCamera();

if (pictureImageReader != null) {
pictureImageReader.close();
Expand All @@ -1229,6 +1286,66 @@ public void close() {
stopBackgroundThread();
}

private void stopAndReleaseCamera() {
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;

// Closing the CameraDevice without closing the CameraCaptureSession is recommended
// for quickly closing the camera:
// https://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession#close()
captureSession = null;
} else {
closeCaptureSession();
}
}

private void prepareVideoRenderer() {
if (videoRenderer != null) return;
final ResolutionFeature resolutionFeature = cameraFeatures.getResolution();

// handle videoRenderer errors
Thread.UncaughtExceptionHandler videoRendererUncaughtExceptionHandler =
new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
dartMessenger.sendCameraErrorEvent(
"Failed to process frames after camera was flipped.");
}
};

videoRenderer =
new VideoRenderer(
mediaRecorder.getSurface(),
resolutionFeature.getCaptureSize().getWidth(),
resolutionFeature.getCaptureSize().getHeight(),
videoRendererUncaughtExceptionHandler);
}

public void setDescriptionWhileRecording(
@NonNull final Result result, CameraProperties properties) {

if (!recordingVideo) {
result.error("setDescriptionWhileRecordingFailed", "Device was not recording", null);
return;
}

stopAndReleaseCamera();
prepareVideoRenderer();
cameraProperties = properties;
cameraFeatures =
CameraFeatures.init(
cameraFeatureFactory, cameraProperties, activity, dartMessenger, resolutionPreset);
cameraFeatures.setAutoFocus(
cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true));
try {
open(imageFormatGroup);
} catch (CameraAccessException e) {
result.error("setDescriptionWhileRecordingFailed", e.getMessage(), null);
}
result.success(null);
}

public void dispose() {
Log.i(TAG, "dispose");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,18 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result)
result.success(null);
break;
}
case "setDescriptionWhileRecording":
{
try {
String cameraName = call.argument("cameraName");
CameraProperties cameraProperties =
new CameraPropertiesImpl(cameraName, CameraUtils.getCameraManager(activity));
camera.setDescriptionWhileRecording(result, cameraProperties);
} catch (Exception e) {
handleException(e, result);
}
break;
}
case "dispose":
{
if (camera != null) {
Expand Down
Loading