From d08c2d4f4969c32151e88acac874ae1d72859ba9 Mon Sep 17 00:00:00 2001 From: Huan Lin Date: Thu, 18 Jan 2024 10:20:12 -0800 Subject: [PATCH 1/2] [camera]fix a sample buffer memory leak on pause resume recording remove annotation run format --- .../camera/camera_avfoundation/CHANGELOG.md | 5 +-- .../ios/RunnerTests/FLTCamSampleBufferTests.m | 35 +++++++++++++++++++ .../camera_avfoundation/ios/Classes/FLTCam.m | 15 ++++---- .../ios/Classes/QueueUtils.h | 2 +- .../camera/camera_avfoundation/pubspec.yaml | 2 +- 5 files changed, 47 insertions(+), 12 deletions(-) diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index b8d61cb0b330..dae480a6b169 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,6 +1,7 @@ -## NEXT +## 0.9.13+11 -* Remove development team from example app. +* Fixes a memory leak of sample buffer when pause and resume the video recording. +* Removes development team from example app. * Updates minimum iOS version to 12.0 and minimum Flutter version to 3.16.6. ## 0.9.13+10 diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSampleBufferTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSampleBufferTests.m index 6f0a4edab080..24e354491143 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSampleBufferTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSampleBufferTests.m @@ -38,6 +38,41 @@ - (void)testCopyPixelBuffer { CFRelease(deliveriedPixelBuffer); } +- (void)testDidOutputSampleBuffer_mustNotChangeSampleBufferRetainCountAfterPauseResumeRecording { + FLTCam *cam = FLTCreateCamWithCaptureSessionQueue(dispatch_queue_create("test", NULL)); + CMSampleBufferRef sampleBuffer = FLTCreateTestSampleBuffer(); + + id writerMock = OCMClassMock([AVAssetWriter class]); + OCMStub([writerMock alloc]).andReturn(writerMock); + OCMStub([writerMock initWithURL:OCMOCK_ANY fileType:OCMOCK_ANY error:[OCMArg setTo:nil]]) + .andReturn(writerMock); + __block AVAssetWriterStatus status = AVAssetWriterStatusUnknown; + OCMStub([writerMock startWriting]).andDo(^(NSInvocation *invocation) { + status = AVAssetWriterStatusWriting; + }); + OCMStub([writerMock status]).andDo(^(NSInvocation *invocation) { + [invocation setReturnValue:&status]; + }); + + FLTThreadSafeFlutterResult *result = + [[FLTThreadSafeFlutterResult alloc] initWithResult:^(id result){ + // no-op + }]; + + // Pause then resume the recording. + [cam startVideoRecordingWithResult:result]; + [cam pauseVideoRecordingWithResult:result]; + [cam resumeVideoRecordingWithResult:result]; + + [cam captureOutput:cam.captureVideoOutput + didOutputSampleBuffer:sampleBuffer + fromConnection:OCMClassMock([AVCaptureConnection class])]; + XCTAssertEqual(CFGetRetainCount(sampleBuffer), 1, + @"didOutputSampleBuffer must not change the sample buffer retain count after " + @"pause resume recording."); + CFRelease(sampleBuffer); +} + - (void)testDidOutputSampleBufferIgnoreAudioSamplesBeforeVideoSamples { FLTCam *cam = FLTCreateCamWithCaptureSessionQueue(dispatch_queue_create("testing", NULL)); CMSampleBufferRef videoSample = FLTCreateTestSampleBuffer(); diff --git a/packages/camera/camera_avfoundation/ios/Classes/FLTCam.m b/packages/camera/camera_avfoundation/ios/Classes/FLTCam.m index 1f9404033204..b3dd9c53e2b9 100644 --- a/packages/camera/camera_avfoundation/ios/Classes/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/Classes/FLTCam.m @@ -514,7 +514,6 @@ - (void)captureOutput:(AVCaptureOutput *)output return; } - CFRetain(sampleBuffer); CMTime currentSampleTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer); if (_videoWriter.status != AVAssetWriterStatusWriting) { @@ -564,18 +563,18 @@ - (void)captureOutput:(AVCaptureOutput *)output _lastAudioSampleTime = currentSampleTime; if (_audioTimeOffset.value != 0) { - CFRelease(sampleBuffer); - sampleBuffer = [self adjustTime:sampleBuffer by:_audioTimeOffset]; + CMSampleBufferRef adjustedSampleBuffer = + [self copySampleBufferWithAdjustedTime:sampleBuffer by:_audioTimeOffset]; + [self newAudioSample:adjustedSampleBuffer]; + CFRelease(adjustedSampleBuffer); + } else { + [self newAudioSample:sampleBuffer]; } - - [self newAudioSample:sampleBuffer]; } - - CFRelease(sampleBuffer); } } -- (CMSampleBufferRef)adjustTime:(CMSampleBufferRef)sample by:(CMTime)offset CF_RETURNS_RETAINED { +- (CMSampleBufferRef)copySampleBufferWithAdjustedTime:(CMSampleBufferRef)sample by:(CMTime)offset { CMItemCount count; CMSampleBufferGetSampleTimingInfoArray(sample, 0, nil, &count); CMSampleTimingInfo *pInfo = malloc(sizeof(CMSampleTimingInfo) * count); diff --git a/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h b/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h index a7e22da716d0..e230a53508fa 100644 --- a/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h +++ b/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN /// Queue-specific context data to be associated with the capture session queue. -extern const char* FLTCaptureSessionQueueSpecific; +extern const char *FLTCaptureSessionQueueSpecific; /// Ensures the given block to be run on the main queue. /// If caller site is already on the main queue, the block will be run diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 175213883b14..e3845c4f5ea2 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.13+10 +version: 0.9.13+11 environment: sdk: ^3.2.3 From 4eccc834d071b49c72bf4b77d6fbd4e43755bec1 Mon Sep 17 00:00:00 2001 From: hellohuanlin <41930132+hellohuanlin@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:06:06 -0800 Subject: [PATCH 2/2] Revert format --- packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h b/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h index e230a53508fa..a7e22da716d0 100644 --- a/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h +++ b/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN /// Queue-specific context data to be associated with the capture session queue. -extern const char *FLTCaptureSessionQueueSpecific; +extern const char* FLTCaptureSessionQueueSpecific; /// Ensures the given block to be run on the main queue. /// If caller site is already on the main queue, the block will be run