Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 5 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
4 changes: 2 additions & 2 deletions packages/camera/camera/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## NEXT
## 0.9.4+2

* Updated package description.
* Update front camera mirroring on iOS.

## 0.9.4+1

Expand Down
166 changes: 165 additions & 1 deletion packages/camera/camera/ios/Classes/CameraPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,171 @@ - (void)captureOutput:(AVCaptureOutput *)output

CVPixelBufferRef nextBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CMTime nextSampleTime = CMTimeSubtract(_lastVideoSampleTime, _videoTimeOffset);
[_videoAdaptor appendPixelBuffer:nextBuffer withPresentationTime:nextSampleTime];

if ([_captureDevice position] == AVCaptureDevicePositionFront) {
CVPixelBufferLockBaseAddress(nextBuffer, kCVPixelBufferLock_ReadOnly);

const Boolean isPlanar = CVPixelBufferIsPlanar(nextBuffer);
size_t planeCount;
if (isPlanar) {
planeCount = CVPixelBufferGetPlaneCount(nextBuffer);
} else {
planeCount = 1;
}

OSType formatType = CVPixelBufferGetPixelFormatType(nextBuffer);

if (!isPlanar) {
void *planeAddress = CVPixelBufferGetBaseAddress(nextBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(nextBuffer);
size_t height = CVPixelBufferGetHeight(nextBuffer);
size_t width = CVPixelBufferGetWidth(nextBuffer);

void *targetBytes = malloc(height * bytesPerRow);
size_t targetBytesPerRow = bytesPerRow;

vImage_Buffer inBuffer;
inBuffer.data = planeAddress;
inBuffer.rowBytes = bytesPerRow;
inBuffer.width = width;
inBuffer.height = height;

vImage_Buffer outBuffer;
outBuffer.data = targetBytes;
outBuffer.rowBytes = targetBytesPerRow;
outBuffer.width = width;
outBuffer.height = height;

vImage_Error err;

err = vImageHorizontalReflect_ARGB8888(&inBuffer, &outBuffer, kvImageNoFlags);

if (err != kvImageNoError) {
NSLog(@"vImageHorizontalReflect_ARGB8888 returned %ld", err);

free(targetBytes);
targetBytes = NULL;

return;
}

CVReturn status;
CVPixelBufferRef nnb = NULL;

status = CVPixelBufferCreateWithBytes(kCFAllocatorDefault, width, height, formatType,
outBuffer.data, outBuffer.rowBytes, NULL, NULL,
NULL, &nnb);

if (status != kCVReturnSuccess) {
NSLog(@"CVPixelBufferCreateWithBytes returned %d", status);

free(targetBytes);
targetBytes = NULL;

return;
}

[_videoAdaptor appendPixelBuffer:nnb withPresentationTime:nextSampleTime];

free(targetBytes);
targetBytes = NULL;

CVBufferRelease(nnb);
} else {
uint8_t *planeAddress[planeCount];
size_t bytesPerRow[planeCount];
size_t height[planeCount];
size_t width[planeCount];

uint8_t *targetAddress[planeCount];

for (int i = 0; i < planeCount; i++) {
planeAddress[i] = CVPixelBufferGetBaseAddressOfPlane(nextBuffer, i);
bytesPerRow[i] = CVPixelBufferGetBytesPerRowOfPlane(nextBuffer, i);
height[i] = CVPixelBufferGetHeightOfPlane(nextBuffer, i);
width[i] = CVPixelBufferGetWidthOfPlane(nextBuffer, i);

targetAddress[i] = malloc(height[i] * bytesPerRow[i]);
}

size_t wp;
size_t hp;

uint8_t x = bytesPerRow[1] - (width[1] * 2) - 1;

for (size_t i = 0; i < height[1]; i++) {
for (size_t j = 0; j < bytesPerRow[1]; j++) {
if (j >= bytesPerRow[1] / 2) {
continue;
}

wp = j + (i * bytesPerRow[1]);
hp = (bytesPerRow[1] - j - 1) + (bytesPerRow[1] * i);

targetAddress[1][hp] = planeAddress[1][wp - x];
targetAddress[1][wp] = planeAddress[1][hp - x];
}
}

vImage_Buffer inBuffer;
inBuffer.data = planeAddress[0];
inBuffer.rowBytes = bytesPerRow[0];
inBuffer.width = width[0];
inBuffer.height = height[0];

vImage_Buffer outBuffer;
outBuffer.data = targetAddress[0];
outBuffer.rowBytes = bytesPerRow[0];
outBuffer.width = width[0];
outBuffer.height = height[0];

vImage_Error err;

err = vImageHorizontalReflect_Planar8(&inBuffer, &outBuffer, kvImageNoFlags);

if (err != kvImageNoError) {
NSLog(@"vImageHorizontalReflect_Planar8 returned %ld", err);

for (int i = 0; i < planeCount; i++) {
free(targetAddress[i]);
}

return;
}

CVReturn status;
CVPixelBufferRef nnb = NULL;

status =
CVPixelBufferCreate(kCFAllocatorDefault, width[0], height[0], formatType, NULL, &nnb);

if (status != kCVReturnSuccess) {
NSLog(@"CVPixelBufferCreate returned %d", status);

return;
}

CVPixelBufferLockBaseAddress(nnb, kCVPixelBufferLock_ReadOnly);
uint8_t *y = CVPixelBufferGetBaseAddressOfPlane(nnb, 0);
memcpy(y, targetAddress[0], height[0] * bytesPerRow[0]);

uint8_t *uv = CVPixelBufferGetBaseAddressOfPlane(nnb, 1);
memcpy(uv, targetAddress[1], height[1] * bytesPerRow[1]);
CVPixelBufferUnlockBaseAddress(nnb, kCVPixelBufferLock_ReadOnly);

[_videoAdaptor appendPixelBuffer:nnb withPresentationTime:nextSampleTime];

for (int i = 0; i < planeCount; i++) {
free(targetAddress[i]);
}

CVBufferRelease(nnb);
}

CVPixelBufferUnlockBaseAddress(nextBuffer, kCVPixelBufferLock_ReadOnly);
} else {
[_videoAdaptor appendPixelBuffer:nextBuffer withPresentationTime:nextSampleTime];
}
} else {
CMTime dur = CMSampleBufferGetDuration(sampleBuffer);

Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing
Dart.
repository: https://github.com/flutter/plugins/tree/master/packages/camera/camera
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
version: 0.9.4+1
version: 0.9.4+2

environment:
sdk: ">=2.14.0 <3.0.0"
Expand Down