mirror of
https://github.com/flutter/packages.git
synced 2025-06-29 22:33:11 +08:00
[camerax] Fixes relistening to onStreamedFrameAvailable
's stream behavior (#4511)
Removes incorrect assumption causing image stream to stop emitting data after subscription to stream is canceled and then the stream is listened to again. Fixes https://github.com/flutter/flutter/issues/130005.
This commit is contained in:
@ -1,3 +1,7 @@
|
||||
## 0.5.0+11
|
||||
|
||||
* Fixes issue with image data not being emitted after relistening to stream returned by `onStreamedFrameAvailable`.
|
||||
|
||||
## 0.5.0+10
|
||||
|
||||
* Implements off, auto, and always flash mode configurations for image capture.
|
||||
|
@ -605,12 +605,6 @@ class AndroidCameraCameraX extends CameraPlatform {
|
||||
/// Configures the [imageAnalysis] instance for image streaming and binds it
|
||||
/// to camera lifecycle controlled by the [processCameraProvider].
|
||||
Future<void> _configureAndBindImageAnalysisToLifecycle() async {
|
||||
if (imageAnalysis != null &&
|
||||
await processCameraProvider!.isBound(imageAnalysis!)) {
|
||||
// imageAnalysis already configured and bound to lifecycle.
|
||||
return;
|
||||
}
|
||||
|
||||
// Create Analyzer that can read image data for image streaming.
|
||||
final WeakReference<AndroidCameraCameraX> weakThis =
|
||||
WeakReference<AndroidCameraCameraX>(this);
|
||||
@ -648,9 +642,14 @@ class AndroidCameraCameraX extends CameraPlatform {
|
||||
|
||||
// TODO(camsim99): Support resolution configuration.
|
||||
// Defaults to YUV_420_888 image format.
|
||||
imageAnalysis = createImageAnalysis(null);
|
||||
imageAnalysis ??= createImageAnalysis(null);
|
||||
unawaited(imageAnalysis!.setAnalyzer(analyzer));
|
||||
|
||||
if (await processCameraProvider!.isBound(imageAnalysis!)) {
|
||||
// No need to bind imageAnalysis to lifecycle again.
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(camsim99): Reset live camera state observers here when
|
||||
// https://github.com/flutter/packages/pull/3419 lands.
|
||||
camera = await processCameraProvider!
|
||||
|
@ -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.5.0+10
|
||||
version: 0.5.0+11
|
||||
|
||||
environment:
|
||||
sdk: ">=2.19.0 <4.0.0"
|
||||
|
@ -940,7 +940,47 @@ void main() {
|
||||
});
|
||||
|
||||
test(
|
||||
'onStreamedFrameAvaiable returns stream that responds expectedly to being listened to',
|
||||
'onStreamedFrameAvailable emits CameraImageData when listened to after cancelation',
|
||||
() async {
|
||||
final FakeAndroidCameraCameraX camera =
|
||||
FakeAndroidCameraCameraX(shouldCreateDetachedObjectForTesting: true);
|
||||
final MockProcessCameraProvider mockProcessCameraProvider =
|
||||
MockProcessCameraProvider();
|
||||
final MockCamera mockCamera = MockCamera();
|
||||
const int cameraId = 22;
|
||||
|
||||
camera.processCameraProvider = mockProcessCameraProvider;
|
||||
camera.cameraSelector = MockCameraSelector();
|
||||
|
||||
when(mockProcessCameraProvider.bindToLifecycle(any, any))
|
||||
.thenAnswer((_) => Future<Camera>.value(mockCamera));
|
||||
when(mockCamera.getCameraInfo())
|
||||
.thenAnswer((_) => Future<CameraInfo>.value(MockCameraInfo()));
|
||||
|
||||
final CameraImageData mockCameraImageData = MockCameraImageData();
|
||||
final Stream<CameraImageData> imageStream =
|
||||
camera.onStreamedFrameAvailable(cameraId);
|
||||
|
||||
// Listen to image stream.
|
||||
final StreamSubscription<CameraImageData> imageStreamSubscription =
|
||||
imageStream.listen((CameraImageData data) {});
|
||||
|
||||
// Cancel subscription to image stream.
|
||||
await imageStreamSubscription.cancel();
|
||||
final Stream<CameraImageData> imageStream2 =
|
||||
camera.onStreamedFrameAvailable(cameraId);
|
||||
|
||||
// Listen to image stream again.
|
||||
final StreamQueue<CameraImageData> streamQueue =
|
||||
StreamQueue<CameraImageData>(imageStream2);
|
||||
camera.cameraImageDataStreamController!.add(mockCameraImageData);
|
||||
|
||||
expect(await streamQueue.next, equals(mockCameraImageData));
|
||||
await streamQueue.cancel();
|
||||
});
|
||||
|
||||
test(
|
||||
'onStreamedFrameAvailable returns stream that responds expectedly to being listened to',
|
||||
() async {
|
||||
final FakeAndroidCameraCameraX camera =
|
||||
FakeAndroidCameraCameraX(shouldCreateDetachedObjectForTesting: true);
|
||||
@ -963,6 +1003,8 @@ void main() {
|
||||
camera.processCameraProvider = mockProcessCameraProvider;
|
||||
camera.cameraSelector = mockCameraSelector;
|
||||
|
||||
when(mockProcessCameraProvider.isBound(camera.mockImageAnalysis))
|
||||
.thenAnswer((_) async => Future<bool>.value(false));
|
||||
when(mockProcessCameraProvider.bindToLifecycle(
|
||||
mockCameraSelector, <UseCase>[camera.mockImageAnalysis]))
|
||||
.thenAnswer((_) async => mockCamera);
|
||||
@ -989,7 +1031,9 @@ void main() {
|
||||
final Analyzer capturedAnalyzer =
|
||||
verify(camera.mockImageAnalysis.setAnalyzer(captureAny)).captured.single
|
||||
as Analyzer;
|
||||
verify(mockProcessCameraProvider.bindToLifecycle(
|
||||
await untilCalled(
|
||||
mockProcessCameraProvider.isBound(camera.mockImageAnalysis));
|
||||
await untilCalled(mockProcessCameraProvider.bindToLifecycle(
|
||||
mockCameraSelector, <UseCase>[camera.mockImageAnalysis]));
|
||||
|
||||
await capturedAnalyzer.analyze(mockImageProxy);
|
||||
@ -1011,7 +1055,7 @@ void main() {
|
||||
});
|
||||
|
||||
test(
|
||||
'onStreamedFrameAvaiable returns stream that responds expectedly to being canceled',
|
||||
'onStreamedFrameAvailable returns stream that responds expectedly to being canceled',
|
||||
() async {
|
||||
final FakeAndroidCameraCameraX camera =
|
||||
FakeAndroidCameraCameraX(shouldCreateDetachedObjectForTesting: true);
|
||||
|
Reference in New Issue
Block a user