Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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_camerax/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.7.1

* Removes outdated restrictions against concurrent camera use cases.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This is a great summary of the main change! To make the changelog even more helpful for users, consider also mentioning the fix for the video recording issue (#157181). The repository's CHANGELOG style guide also recommends linking to the fixed issues.

How about something like this?

Suggested change
* Removes outdated restrictions against concurrent camera use cases.
* Removes outdated restrictions against concurrent camera use cases (fixes flutter/flutter#150387).
* Fixes an issue where video recording could fail immediately after starting on some devices (fixes flutter/flutter#157181).
References
  1. The repository's CHANGELOG style guide recommends that if a change fixes one or more issues, they should be listed at the end of the description in parentheses. This change also includes a significant bug fix that would be valuable to mention for users. (link)


## 0.7.0+1

* Updates example to demonstrate correct exception handling for async return statements, ensuring exceptions thrown during return within try blocks are properly caught as per [dart-lang/sdk#44395](https://github.com/dart-lang/sdk/issues/44395).
Expand Down
16 changes: 0 additions & 16 deletions packages/camera/camera_android_camerax/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,6 @@ should add it to your `pubspec.yaml` as usual.

## Limitations

### Concurrent preview display, video recording, image capture, and image streaming

The CameraX plugin only supports the concurrent camera use cases supported by Camerax; see
[their documentation][6] for more information. To avoid the usage of unsupported concurrent
use cases, the plugin behaves according to the following:

* If the preview is paused (via `pausePreview`), concurrent video recording and image capture
and/or image streaming (via `startVideoCapturing(cameraId, VideoCaptureOptions(streamCallback:...))`)
is supported.
* If the preview is not paused
* **and** the camera device is at least supported hardware [`LIMITED`][8], then concurrent
image capture and video recording is supported.
* **and** the camera device is at least supported hardware [`LEVEL_3`][7], then concurrent
video recording and image streaming is supported, but concurrent video recording, image
streaming, and image capture is not supported.

### 240p resolution configuration for video recording

240p resolution configuration for video recording is unsupported by CameraX, and thus,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:video_player/video_player.dart';

// Skip due to video_player error.
// See https://github.com/flutter/flutter/issues/157181
const bool skipFor157181 = true;

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

Expand Down Expand Up @@ -162,7 +158,7 @@ void main() {
await controller.startVideoRecording();
final int recordingStart = DateTime.now().millisecondsSinceEpoch;

sleep(const Duration(seconds: 2));
await Future<void>.delayed(const Duration(seconds: 2));

final XFile file = await controller.stopVideoRecording();
final int postStopTime =
Expand All @@ -175,7 +171,7 @@ void main() {
await videoController.dispose();

expect(duration, lessThan(postStopTime));
}, skip: skipFor157181);
});

testWidgets('Pause and resume video recording', (WidgetTester tester) async {
final List<CameraDescription> cameras = await availableCameras();
Expand All @@ -198,16 +194,17 @@ void main() {

await controller.startVideoRecording();
final int recordingStart = DateTime.now().millisecondsSinceEpoch;
sleep(const Duration(milliseconds: 500));
await Future<void>.delayed(const Duration(milliseconds: 500));

for (var i = 0; i < pauseIterations; i++) {
await controller.pauseVideoRecording();
startPause = DateTime.now().millisecondsSinceEpoch;
sleep(const Duration(milliseconds: 500));
await Future<void>.delayed(const Duration(milliseconds: 500));

await controller.resumeVideoRecording();
timePaused += DateTime.now().millisecondsSinceEpoch - startPause;

sleep(const Duration(milliseconds: 500));
await Future<void>.delayed(const Duration(milliseconds: 500));
}

final XFile file = await controller.stopVideoRecording();
Expand All @@ -221,7 +218,7 @@ void main() {
await videoController.dispose();

expect(duration, lessThan(recordingTime - timePaused));
}, skip: skipFor157181);
});

testWidgets('Set description while recording captures full video', (
WidgetTester tester,
Expand All @@ -243,13 +240,15 @@ void main() {

await controller.startVideoRecording();

await Future<void>.delayed(const Duration(seconds: 1));

await controller.setDescription(cameras[1]);

await tester.pumpAndSettle(const Duration(seconds: 4));
await Future<void>.delayed(const Duration(seconds: 4));

await controller.setDescription(cameras[0]);

await tester.pumpAndSettle(const Duration(seconds: 1));
await Future<void>.delayed(const Duration(seconds: 1));

final XFile file = await controller.stopVideoRecording();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1164,47 +1164,13 @@ class AndroidCameraCameraX extends CameraPlatform {
// There is currently an active recording, so do not start a new one.
return;
}

dynamic Function(CameraImageData)? streamCallback = options.streamCallback;
if (!_previewIsPaused) {
// The plugin binds the preview use case to the camera lifecycle when
// createCamera is called, but camera use cases can become limited
// when video recording and displaying a preview concurrently. This logic
// will prioritize attempting to continue displaying the preview,
// stream images, and record video if specified and supported. Otherwise,
// the preview must be paused in order to allow those concurrently. See
// https://developer.android.com/media/camera/camerax/architecture#combine-use-cases
// for more information on supported concurrent camera use cases.
final camera2CameraInfo = Camera2CameraInfo.from(cameraInfo: cameraInfo!);
final cameraInfoSupportedHardwareLevel =
(await camera2CameraInfo.getCameraCharacteristic(
CameraCharacteristics.infoSupportedHardwareLevel,
))!
as InfoSupportedHardwareLevel;

// Handle limited level device restrictions:
final cameraSupportsConcurrentImageCapture =
cameraInfoSupportedHardwareLevel != InfoSupportedHardwareLevel.legacy;
if (!cameraSupportsConcurrentImageCapture) {
// Concurrent preview + video recording + image capture is not supported
// unless the camera device is cameraSupportsHardwareLevelLimited or
// better.
await _unbindUseCaseFromLifecycle(imageCapture!);
}

// Handle level 3 device restrictions:
final cameraSupportsHardwareLevel3 =
cameraInfoSupportedHardwareLevel == InfoSupportedHardwareLevel.level3;
if (!cameraSupportsHardwareLevel3 || streamCallback == null) {
// Concurrent preview + video recording + image streaming is not supported
// unless the camera device is cameraSupportsHardwareLevel3 or better.
streamCallback = null;
await _unbindUseCaseFromLifecycle(imageAnalysis!);
} else {
// If image streaming concurrently with video recording, image capture
// is unsupported.
await _unbindUseCaseFromLifecycle(imageCapture!);
}
final dynamic Function(CameraImageData)? streamCallback =
options.streamCallback;
if (streamCallback == null) {
// For potential performance improvements, unbind imageAnalysis if not in use.
// See https://developer.android.com/media/camera/camerax/architecture#combine-use-cases
// for details.
await _unbindUseCaseFromLifecycle(imageAnalysis!);
}

await _bindUseCaseToLifecycle(videoCapture!, options.cameraId);
Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera_android_camerax/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: camera_android_camerax
description: Android implementation of the camera plugin using the CameraX library.
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android_camerax
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
version: 0.7.0+1
version: 0.7.1

environment:
sdk: ^3.9.0
Expand Down
Loading
Loading