Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/camera/camera_avfoundation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
15 changes: 7 additions & 8 deletions packages/camera/camera_avfoundation/ios/Classes/FLTCam.m
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,6 @@ - (void)captureOutput:(AVCaptureOutput *)output
return;
}

CFRetain(sampleBuffer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the bug that this is retained but not released before the if(_audioIsDisconnected) early returns?

Copy link
Member

@jmagman jmagman Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I think you're right it doesn't need to be retained at all since sampleBuffer isn't used outside the scope of this method)

Clients that need to reference the CMSampleBuffer object outside of the scope of this method must CFRetain it and then CFRelease it when they are finished with it.

CMTime currentSampleTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);

if (_videoWriter.status != AVAssetWriterStatusWriting) {
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera_avfoundation/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down