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

Commit 610370e

Browse files
Revert "[camera] Add ability to concurrently record and stream video (#6290)" (#6796)
This reverts commit 374e598.
1 parent 374e598 commit 610370e

File tree

30 files changed

+76
-410
lines changed

30 files changed

+76
-410
lines changed

packages/camera/camera_android/CHANGELOG.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
## 0.10.1
2-
3-
* Implements option to also stream when recording a video.
4-
51
## 0.10.0+5
62

73
* Fixes `ArrayIndexOutOfBoundsException` when the permission request is interrupted.

packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java

Lines changed: 34 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -522,21 +522,6 @@ private void refreshPreviewCaptureSession(
522522
}
523523
}
524524

525-
private void startCapture(boolean record, boolean stream) throws CameraAccessException {
526-
List<Surface> surfaces = new ArrayList<>();
527-
Runnable successCallback = null;
528-
if (record) {
529-
surfaces.add(mediaRecorder.getSurface());
530-
successCallback = () -> mediaRecorder.start();
531-
}
532-
if (stream) {
533-
surfaces.add(imageStreamReader.getSurface());
534-
}
535-
536-
createCaptureSession(
537-
CameraDevice.TEMPLATE_RECORD, successCallback, surfaces.toArray(new Surface[0]));
538-
}
539-
540525
public void takePicture(@NonNull final Result result) {
541526
// Only take one picture at a time.
542527
if (cameraCaptureCallback.getCameraState() != CameraState.STATE_PREVIEW) {
@@ -746,17 +731,29 @@ private void unlockAutoFocus() {
746731
dartMessenger.error(flutterResult, errorCode, errorMessage, null));
747732
}
748733

749-
public void startVideoRecording(
750-
@NonNull Result result, @Nullable EventChannel imageStreamChannel) {
751-
prepareRecording(result);
752-
753-
if (imageStreamChannel != null) {
754-
setStreamHandler(imageStreamChannel);
734+
public void startVideoRecording(@NonNull Result result) {
735+
final File outputDir = applicationContext.getCacheDir();
736+
try {
737+
captureFile = File.createTempFile("REC", ".mp4", outputDir);
738+
} catch (IOException | SecurityException e) {
739+
result.error("cannotCreateFile", e.getMessage(), null);
740+
return;
755741
}
756-
742+
try {
743+
prepareMediaRecorder(captureFile.getAbsolutePath());
744+
} catch (IOException e) {
745+
recordingVideo = false;
746+
captureFile = null;
747+
result.error("videoRecordingFailed", e.getMessage(), null);
748+
return;
749+
}
750+
// Re-create autofocus feature so it's using video focus mode now.
751+
cameraFeatures.setAutoFocus(
752+
cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true));
757753
recordingVideo = true;
758754
try {
759-
startCapture(true, imageStreamChannel != null);
755+
createCaptureSession(
756+
CameraDevice.TEMPLATE_RECORD, () -> mediaRecorder.start(), mediaRecorder.getSurface());
760757
result.success(null);
761758
} catch (CameraAccessException e) {
762759
recordingVideo = false;
@@ -1076,10 +1073,21 @@ public void startPreview() throws CameraAccessException {
10761073

10771074
public void startPreviewWithImageStream(EventChannel imageStreamChannel)
10781075
throws CameraAccessException {
1079-
setStreamHandler(imageStreamChannel);
1080-
1081-
startCapture(false, true);
1076+
createCaptureSession(CameraDevice.TEMPLATE_RECORD, imageStreamReader.getSurface());
10821077
Log.i(TAG, "startPreviewWithImageStream");
1078+
1079+
imageStreamChannel.setStreamHandler(
1080+
new EventChannel.StreamHandler() {
1081+
@Override
1082+
public void onListen(Object o, EventChannel.EventSink imageStreamSink) {
1083+
setImageStreamImageAvailableListener(imageStreamSink);
1084+
}
1085+
1086+
@Override
1087+
public void onCancel(Object o) {
1088+
imageStreamReader.setOnImageAvailableListener(null, backgroundHandler);
1089+
}
1090+
});
10831091
}
10841092

10851093
/**
@@ -1109,42 +1117,6 @@ public void onError(String errorCode, String errorMessage) {
11091117
cameraCaptureCallback.setCameraState(CameraState.STATE_PREVIEW);
11101118
}
11111119

1112-
private void prepareRecording(@NonNull Result result) {
1113-
final File outputDir = applicationContext.getCacheDir();
1114-
try {
1115-
captureFile = File.createTempFile("REC", ".mp4", outputDir);
1116-
} catch (IOException | SecurityException e) {
1117-
result.error("cannotCreateFile", e.getMessage(), null);
1118-
return;
1119-
}
1120-
try {
1121-
prepareMediaRecorder(captureFile.getAbsolutePath());
1122-
} catch (IOException e) {
1123-
recordingVideo = false;
1124-
captureFile = null;
1125-
result.error("videoRecordingFailed", e.getMessage(), null);
1126-
return;
1127-
}
1128-
// Re-create autofocus feature so it's using video focus mode now.
1129-
cameraFeatures.setAutoFocus(
1130-
cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true));
1131-
}
1132-
1133-
private void setStreamHandler(EventChannel imageStreamChannel) {
1134-
imageStreamChannel.setStreamHandler(
1135-
new EventChannel.StreamHandler() {
1136-
@Override
1137-
public void onListen(Object o, EventChannel.EventSink imageStreamSink) {
1138-
setImageStreamImageAvailableListener(imageStreamSink);
1139-
}
1140-
1141-
@Override
1142-
public void onCancel(Object o) {
1143-
imageStreamReader.setOnImageAvailableListener(null, backgroundHandler);
1144-
}
1145-
});
1146-
}
1147-
11481120
private void setImageStreamImageAvailableListener(final EventChannel.EventSink imageStreamSink) {
11491121
imageStreamReader.setOnImageAvailableListener(
11501122
reader -> {

packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import io.flutter.view.TextureRegistry;
2727
import java.util.HashMap;
2828
import java.util.Map;
29-
import java.util.Objects;
3029

3130
final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
3231
private final Activity activity;
@@ -119,9 +118,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result)
119118
}
120119
case "startVideoRecording":
121120
{
122-
camera.startVideoRecording(
123-
result,
124-
Objects.equals(call.argument("enableStream"), true) ? imageStreamChannel : null);
121+
camera.startVideoRecording(result);
125122
break;
126123
}
127124
case "stopVideoRecording":

packages/camera/camera_android/example/integration_test/camera_test.dart

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -245,44 +245,4 @@ void main() {
245245
await controller.dispose();
246246
},
247247
);
248-
249-
testWidgets(
250-
'recording with image stream',
251-
(WidgetTester tester) async {
252-
final List<CameraDescription> cameras =
253-
await CameraPlatform.instance.availableCameras();
254-
if (cameras.isEmpty) {
255-
return;
256-
}
257-
258-
final CameraController controller = CameraController(
259-
cameras[0],
260-
ResolutionPreset.low,
261-
enableAudio: false,
262-
);
263-
264-
await controller.initialize();
265-
bool isDetecting = false;
266-
267-
await controller.startVideoRecording(
268-
streamCallback: (CameraImageData image) {
269-
if (isDetecting) {
270-
return;
271-
}
272-
273-
isDetecting = true;
274-
275-
expectLater(image, isNotNull).whenComplete(() => isDetecting = false);
276-
});
277-
278-
expect(controller.value.isStreamingImages, true);
279-
280-
sleep(const Duration(milliseconds: 500));
281-
282-
await controller.stopVideoRecording();
283-
await controller.dispose();
284-
285-
expect(controller.value.isStreamingImages, false);
286-
},
287-
);
288248
}

packages/camera/camera_android/example/lib/camera_controller.dart

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -306,14 +306,11 @@ class CameraController extends ValueNotifier<CameraValue> {
306306
///
307307
/// The video is returned as a [XFile] after calling [stopVideoRecording].
308308
/// Throws a [CameraException] if the capture fails.
309-
Future<void> startVideoRecording(
310-
{Function(CameraImageData image)? streamCallback}) async {
311-
await CameraPlatform.instance.startVideoCapturing(
312-
VideoCaptureOptions(_cameraId, streamCallback: streamCallback));
309+
Future<void> startVideoRecording() async {
310+
await CameraPlatform.instance.startVideoRecording(_cameraId);
313311
value = value.copyWith(
314312
isRecordingVideo: true,
315313
isRecordingPaused: false,
316-
isStreamingImages: streamCallback != null,
317314
recordingOrientation: Optional<DeviceOrientation>.of(
318315
value.lockedCaptureOrientation ?? value.deviceOrientation));
319316
}
@@ -322,15 +319,10 @@ class CameraController extends ValueNotifier<CameraValue> {
322319
///
323320
/// Throws a [CameraException] if the capture failed.
324321
Future<XFile> stopVideoRecording() async {
325-
if (value.isStreamingImages) {
326-
await stopImageStream();
327-
}
328-
329322
final XFile file =
330323
await CameraPlatform.instance.stopVideoRecording(_cameraId);
331324
value = value.copyWith(
332325
isRecordingVideo: false,
333-
isRecordingPaused: false,
334326
recordingOrientation: const Optional<DeviceOrientation>.absent(),
335327
);
336328
return file;

packages/camera/camera_android/example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ dependencies:
1414
# The example app is bundled with the plugin so we use a path dependency on
1515
# the parent directory to use the current plugin's version.
1616
path: ../
17-
camera_platform_interface: ^2.3.1
17+
camera_platform_interface: ^2.2.0
1818
flutter:
1919
sdk: flutter
2020
path_provider: ^2.0.0

packages/camera/camera_android/lib/src/android_camera.dart

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -248,25 +248,13 @@ class AndroidCamera extends CameraPlatform {
248248
@override
249249
Future<void> startVideoRecording(int cameraId,
250250
{Duration? maxVideoDuration}) async {
251-
return startVideoCapturing(
252-
VideoCaptureOptions(cameraId, maxDuration: maxVideoDuration));
253-
}
254-
255-
@override
256-
Future<void> startVideoCapturing(VideoCaptureOptions options) async {
257251
await _channel.invokeMethod<void>(
258252
'startVideoRecording',
259253
<String, dynamic>{
260-
'cameraId': options.cameraId,
261-
'maxVideoDuration': options.maxDuration?.inMilliseconds,
262-
'enableStream': options.streamCallback != null,
254+
'cameraId': cameraId,
255+
'maxVideoDuration': maxVideoDuration?.inMilliseconds,
263256
},
264257
);
265-
266-
if (options.streamCallback != null) {
267-
_installStreamController().stream.listen(options.streamCallback);
268-
_startStreamListener();
269-
}
270258
}
271259

272260
@override
@@ -302,19 +290,13 @@ class AndroidCamera extends CameraPlatform {
302290
@override
303291
Stream<CameraImageData> onStreamedFrameAvailable(int cameraId,
304292
{CameraImageStreamOptions? options}) {
305-
_installStreamController(onListen: _onFrameStreamListen);
306-
return _frameStreamController!.stream;
307-
}
308-
309-
StreamController<CameraImageData> _installStreamController(
310-
{Function()? onListen}) {
311293
_frameStreamController = StreamController<CameraImageData>(
312-
onListen: onListen ?? () {},
294+
onListen: _onFrameStreamListen,
313295
onPause: _onFrameStreamPauseResume,
314296
onResume: _onFrameStreamPauseResume,
315297
onCancel: _onFrameStreamCancel,
316298
);
317-
return _frameStreamController!;
299+
return _frameStreamController!.stream;
318300
}
319301

320302
void _onFrameStreamListen() {
@@ -323,10 +305,6 @@ class AndroidCamera extends CameraPlatform {
323305

324306
Future<void> _startPlatformStream() async {
325307
await _channel.invokeMethod<void>('startImageStream');
326-
_startStreamListener();
327-
}
328-
329-
void _startStreamListener() {
330308
const EventChannel cameraEventChannel =
331309
EventChannel('plugins.flutter.io/camera_android/imageStream');
332310
_platformImageStreamSubscription =

packages/camera/camera_android/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: camera_android
22
description: Android implementation of the camera plugin.
33
repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
5-
version: 0.10.1
5+
version: 0.10.0+5
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"
@@ -18,7 +18,7 @@ flutter:
1818
dartPluginClass: AndroidCamera
1919

2020
dependencies:
21-
camera_platform_interface: ^2.3.1
21+
camera_platform_interface: ^2.2.0
2222
flutter:
2323
sdk: flutter
2424
flutter_plugin_android_lifecycle: ^2.0.2

packages/camera/camera_android/test/android_camera_test.dart

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,6 @@ void main() {
587587
isMethodCall('startVideoRecording', arguments: <String, Object?>{
588588
'cameraId': cameraId,
589589
'maxVideoDuration': null,
590-
'enableStream': false,
591590
}),
592591
]);
593592
});
@@ -610,33 +609,7 @@ void main() {
610609
expect(channel.log, <Matcher>[
611610
isMethodCall('startVideoRecording', arguments: <String, Object?>{
612611
'cameraId': cameraId,
613-
'maxVideoDuration': 10000,
614-
'enableStream': false,
615-
}),
616-
]);
617-
});
618-
619-
test(
620-
'Should pass enableStream if callback is passed when starting recording a video',
621-
() async {
622-
// Arrange
623-
final MethodChannelMock channel = MethodChannelMock(
624-
channelName: _channelName,
625-
methods: <String, dynamic>{'startVideoRecording': null},
626-
);
627-
628-
// Act
629-
await camera.startVideoCapturing(
630-
VideoCaptureOptions(cameraId,
631-
streamCallback: (CameraImageData imageData) {}),
632-
);
633-
634-
// Assert
635-
expect(channel.log, <Matcher>[
636-
isMethodCall('startVideoRecording', arguments: <String, Object?>{
637-
'cameraId': cameraId,
638-
'maxVideoDuration': null,
639-
'enableStream': true,
612+
'maxVideoDuration': 10000
640613
}),
641614
]);
642615
});

packages/camera/camera_avfoundation/CHANGELOG.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
## 0.9.9
2-
3-
* Implements option to also stream when recording a video.
4-
51
## 0.9.8+6
62

73
* Updates code for `no_leading_underscores_for_local_identifiers` lint.

0 commit comments

Comments
 (0)