1010@import CoreMotion;
1111#import < libkern/OSAtomic.h>
1212
13- @interface FLTImageStreamHandler : NSObject <FlutterStreamHandler>
14- // The queue on which `eventSink` property should be accessed
15- @property (nonatomic , strong ) dispatch_queue_t captureSessionQueue;
16- // `eventSink` property should be accessed on `captureSessionQueue`.
17- // The block itself should be invoked on the main queue.
18- @property FlutterEventSink eventSink;
19- @end
20-
2113@implementation FLTImageStreamHandler
2214
2315- (instancetype )initWithCaptureSessionQueue : (dispatch_queue_t )captureSessionQueue {
@@ -68,7 +60,13 @@ @interface FLTCam () <AVCaptureVideoDataOutputSampleBufferDelegate,
6860@property (assign , nonatomic ) BOOL videoIsDisconnected;
6961@property (assign , nonatomic ) BOOL audioIsDisconnected;
7062@property (assign , nonatomic ) BOOL isAudioSetup;
71- @property (assign , nonatomic ) BOOL isStreamingImages;
63+
64+ // / Number of frames currently pending processing.
65+ @property (assign , nonatomic ) int streamingPendingFramesCount;
66+
67+ // / Maximum number of frames pending processing.
68+ @property (assign , nonatomic ) int maxStreamingPendingFramesCount;
69+
7270@property (assign , nonatomic ) UIDeviceOrientation lockedCaptureOrientation;
7371@property (assign , nonatomic ) CMTime lastVideoSampleTime;
7472@property (assign , nonatomic ) CMTime lastAudioSampleTime;
@@ -135,6 +133,11 @@ - (instancetype)initWithCameraName:(NSString *)cameraName
135133 _videoFormat = kCVPixelFormatType_32BGRA ;
136134 _inProgressSavePhotoDelegates = [NSMutableDictionary dictionary ];
137135
136+ // To limit memory consumption, limit the number of frames pending processing.
137+ // After some testing, 4 was determined to be the best maximum value.
138+ // https://github.com/flutter/plugins/pull/4520#discussion_r766335637
139+ _maxStreamingPendingFramesCount = 4 ;
140+
138141 NSError *localError = nil ;
139142 _captureVideoInput = [AVCaptureDeviceInput deviceInputWithDevice: _captureDevice
140143 error: &localError];
@@ -401,7 +404,8 @@ - (void)captureOutput:(AVCaptureOutput *)output
401404 }
402405 if (_isStreamingImages) {
403406 FlutterEventSink eventSink = _imageStreamHandler.eventSink ;
404- if (eventSink) {
407+ if (eventSink && (self.streamingPendingFramesCount < self.maxStreamingPendingFramesCount )) {
408+ self.streamingPendingFramesCount ++;
405409 CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer (sampleBuffer);
406410 // Must lock base address before accessing the pixel data
407411 CVPixelBufferLockBaseAddress (pixelBuffer, kCVPixelBufferLock_ReadOnly );
@@ -898,19 +902,26 @@ - (void)setExposureOffsetWithResult:(FLTThreadSafeFlutterResult *)result offset:
898902}
899903
900904- (void )startImageStreamWithMessenger : (NSObject <FlutterBinaryMessenger> *)messenger {
905+ [self startImageStreamWithMessenger: messenger
906+ imageStreamHandler: [[FLTImageStreamHandler alloc ]
907+ initWithCaptureSessionQueue: _captureSessionQueue]];
908+ }
909+
910+ - (void )startImageStreamWithMessenger : (NSObject <FlutterBinaryMessenger> *)messenger
911+ imageStreamHandler : (FLTImageStreamHandler *)imageStreamHandler {
901912 if (!_isStreamingImages) {
902913 FlutterEventChannel *eventChannel =
903914 [FlutterEventChannel eventChannelWithName: @" plugins.flutter.io/camera/imageStream"
904915 binaryMessenger: messenger];
905916 FLTThreadSafeEventChannel *threadSafeEventChannel =
906917 [[FLTThreadSafeEventChannel alloc ] initWithEventChannel: eventChannel];
907918
908- _imageStreamHandler =
909- [[FLTImageStreamHandler alloc ] initWithCaptureSessionQueue: _captureSessionQueue];
919+ _imageStreamHandler = imageStreamHandler;
910920 [threadSafeEventChannel setStreamHandler: _imageStreamHandler
911921 completion: ^{
912922 dispatch_async (self->_captureSessionQueue , ^{
913923 self.isStreamingImages = YES ;
924+ self.streamingPendingFramesCount = 0 ;
914925 });
915926 }];
916927 } else {
@@ -928,6 +939,10 @@ - (void)stopImageStream {
928939 }
929940}
930941
942+ - (void )receivedImageStreamData {
943+ self.streamingPendingFramesCount --;
944+ }
945+
931946- (void )getMaxZoomLevelWithResult : (FLTThreadSafeFlutterResult *)result {
932947 CGFloat maxZoomFactor = [self getMaxAvailableZoomFactor ];
933948
0 commit comments