Skip to content

Commit

Permalink
Merge branch 'main' into android-examples-kotlin-1-9
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartmorgan committed Nov 4, 2024
2 parents aa1decc + da4c3ee commit 16ea5d9
Show file tree
Hide file tree
Showing 61 changed files with 959 additions and 1,353 deletions.
2 changes: 1 addition & 1 deletion .ci/flutter_master.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0fe615343bd9e9b6ef00eecaa906fe10f4a39040
8591d0c16a6c7edfbea3b5b1bf08ae09db117b71
8 changes: 7 additions & 1 deletion packages/camera/camera_windows/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## NEXT
## 0.2.6

* Reverts streaming frame support, as the implementation was incorrect and never
exposed.

## 0.2.5+1

* Updates C++ to Dart communication to use Pigeon.
* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.

## 0.2.5
Expand Down
141 changes: 40 additions & 101 deletions packages/camera/camera_windows/lib/camera_windows.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import 'package:flutter/widgets.dart';
import 'package:stream_transform/stream_transform.dart';

import 'src/messages.g.dart';
import 'type_conversion.dart';

/// An implementation of [CameraPlatform] for Windows.
class CameraWindows extends CameraPlatform {
Expand All @@ -27,14 +26,11 @@ class CameraWindows extends CameraPlatform {
/// Interface for calling host-side code.
final CameraApi _hostApi;

/// Camera specific method channels to allow communicating with specific cameras.
final Map<int, MethodChannel> _cameraChannels = <int, MethodChannel>{};

// The stream to receive frames from the native code.
StreamSubscription<dynamic>? _platformImageStreamSubscription;

// The stream for vending frames to platform interface clients.
StreamController<CameraImageData>? _frameStreamController;
/// The per-camera handlers for messages that should be rebroadcast to
/// clients as [CameraEvent]s.
@visibleForTesting
final Map<int, HostCameraMessageHandler> hostCameraHandlers =
<int, HostCameraMessageHandler>{};

/// The controller that broadcasts events coming from handleCameraMethodCall
///
Expand Down Expand Up @@ -105,15 +101,8 @@ class CameraWindows extends CameraPlatform {
int cameraId, {
ImageFormatGroup imageFormatGroup = ImageFormatGroup.unknown,
}) async {
/// Creates channel for camera events.
_cameraChannels.putIfAbsent(cameraId, () {
final MethodChannel channel =
MethodChannel('plugins.flutter.io/camera_windows/camera$cameraId');
channel.setMethodCallHandler(
(MethodCall call) => handleCameraMethodCall(call, cameraId),
);
return channel;
});
hostCameraHandlers.putIfAbsent(cameraId,
() => HostCameraMessageHandler(cameraId, cameraEventStreamController));

final PlatformSize reply;
try {
Expand All @@ -140,11 +129,7 @@ class CameraWindows extends CameraPlatform {
await _hostApi.dispose(cameraId);

// Destroy method channel after camera is disposed to be able to handle last messages.
if (_cameraChannels.containsKey(cameraId)) {
final MethodChannel? cameraChannel = _cameraChannels[cameraId];
cameraChannel?.setMethodCallHandler(null);
_cameraChannels.remove(cameraId);
}
hostCameraHandlers.remove(cameraId)?.dispose();
}

@override
Expand Down Expand Up @@ -249,57 +234,6 @@ class CameraWindows extends CameraPlatform {
'resumeVideoRecording() is not supported due to Win32 API limitations.');
}

@override
Stream<CameraImageData> onStreamedFrameAvailable(int cameraId,
{CameraImageStreamOptions? options}) {
_installStreamController(
onListen: () => _onFrameStreamListen(cameraId),
onCancel: () => _onFrameStreamCancel(cameraId));
return _frameStreamController!.stream;
}

StreamController<CameraImageData> _installStreamController(
{void Function()? onListen, void Function()? onCancel}) {
_frameStreamController = StreamController<CameraImageData>(
onListen: onListen ?? () {},
onPause: _onFrameStreamPauseResume,
onResume: _onFrameStreamPauseResume,
onCancel: onCancel ?? () {},
);
return _frameStreamController!;
}

void _onFrameStreamListen(int cameraId) {
_startPlatformStream(cameraId);
}

Future<void> _startPlatformStream(int cameraId) async {
_startStreamListener();
await _hostApi.startImageStream(cameraId);
}

void _startStreamListener() {
const EventChannel cameraEventChannel =
EventChannel('plugins.flutter.io/camera_android/imageStream');
_platformImageStreamSubscription =
cameraEventChannel.receiveBroadcastStream().listen((dynamic imageData) {
_frameStreamController!
.add(cameraImageFromPlatformData(imageData as Map<dynamic, dynamic>));
});
}

FutureOr<void> _onFrameStreamCancel(int cameraId) async {
await _hostApi.stopImageStream(cameraId);
await _platformImageStreamSubscription?.cancel();
_platformImageStreamSubscription = null;
_frameStreamController = null;
}

void _onFrameStreamPauseResume() {
throw CameraException('InvalidCall',
'Pause and resume are not supported for onStreamedFrameAvailable');
}

@override
Future<void> setFlashMode(int cameraId, FlashMode mode) async {
// TODO(jokerttu): Implement flash mode support, https://github.com/flutter/flutter/issues/97537.
Expand Down Expand Up @@ -398,33 +332,6 @@ class CameraWindows extends CameraPlatform {
return Texture(textureId: cameraId);
}

/// Converts messages received from the native platform into camera events.
///
/// This is only exposed for test purposes. It shouldn't be used by clients
/// of the plugin as it may break or change at any time.
@visibleForTesting
Future<dynamic> handleCameraMethodCall(MethodCall call, int cameraId) async {
switch (call.method) {
case 'camera_closing':
cameraEventStreamController.add(
CameraClosingEvent(
cameraId,
),
);
case 'error':
final Map<String, Object?> arguments =
(call.arguments as Map<Object?, Object?>).cast<String, Object?>();
cameraEventStreamController.add(
CameraErrorEvent(
cameraId,
arguments['description']! as String,
),
);
default:
throw UnimplementedError();
}
}

/// Returns a [MediaSettings]'s Pigeon representation.
PlatformMediaSettings _pigeonMediaSettings(MediaSettings? settings) {
return PlatformMediaSettings(
Expand Down Expand Up @@ -467,3 +374,35 @@ class CameraWindows extends CameraPlatform {
return PlatformResolutionPreset.max;
}
}

/// Callback handler for camera-level events from the platform host.
@visibleForTesting
class HostCameraMessageHandler implements CameraEventApi {
/// Creates a new handler that listens for events from camera [cameraId], and
/// broadcasts them to [streamController].
HostCameraMessageHandler(this.cameraId, this.streamController) {
CameraEventApi.setUp(this, messageChannelSuffix: cameraId.toString());
}

/// Removes the handler for native messages.
void dispose() {
CameraEventApi.setUp(null, messageChannelSuffix: cameraId.toString());
}

/// The camera ID this handler listens for events from.
final int cameraId;

/// The controller used to broadcast camera events coming from the
/// host platform.
final StreamController<CameraEvent> streamController;

@override
void error(String message) {
streamController.add(CameraErrorEvent(cameraId, message));
}

@override
void cameraClosing() {
streamController.add(CameraClosingEvent(cameraId));
}
}
Loading

0 comments on commit 16ea5d9

Please sign in to comment.