This repository has been archived by the owner on Feb 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[camera] Fix iOS rotation issue (#3591)
* Fix iOS rotation issue * Fix orientation issues on iOS * Merged with master and added test * Test RotationBox turns according to device orientation * Fix formatting * Removed merge conflict tags from CHANGELOG * Fix license header in test
- Loading branch information
1 parent
9548bc2
commit 9cd84bd
Showing
5 changed files
with
324 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -345,6 +345,7 @@ @interface FLTCam : NSObject <FlutterTexture, | |
|
||
@implementation FLTCam { | ||
dispatch_queue_t _dispatchQueue; | ||
UIDeviceOrientation _deviceOrientation; | ||
} | ||
// Format used for video and image streaming. | ||
FourCharCode videoFormat = kCVPixelFormatType_32BGRA; | ||
|
@@ -353,6 +354,7 @@ @implementation FLTCam { | |
- (instancetype)initWithCameraName:(NSString *)cameraName | ||
resolutionPreset:(NSString *)resolutionPreset | ||
enableAudio:(BOOL)enableAudio | ||
orientation:(UIDeviceOrientation)orientation | ||
dispatchQueue:(dispatch_queue_t)dispatchQueue | ||
error:(NSError **)error { | ||
self = [super init]; | ||
|
@@ -370,6 +372,7 @@ - (instancetype)initWithCameraName:(NSString *)cameraName | |
_exposureMode = ExposureModeAuto; | ||
_focusMode = FocusModeAuto; | ||
_lockedCaptureOrientation = UIDeviceOrientationUnknown; | ||
_deviceOrientation = orientation; | ||
|
||
NSError *localError = nil; | ||
_captureVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:_captureDevice | ||
|
@@ -389,10 +392,11 @@ - (instancetype)initWithCameraName:(NSString *)cameraName | |
AVCaptureConnection *connection = | ||
[AVCaptureConnection connectionWithInputPorts:_captureVideoInput.ports | ||
output:_captureVideoOutput]; | ||
|
||
if ([_captureDevice position] == AVCaptureDevicePositionFront) { | ||
connection.videoMirrored = YES; | ||
} | ||
connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight; | ||
|
||
[_captureSession addInputWithNoConnections:_captureVideoInput]; | ||
[_captureSession addOutputWithNoConnections:_captureVideoOutput]; | ||
[_captureSession addConnection:connection]; | ||
|
@@ -406,6 +410,8 @@ - (instancetype)initWithCameraName:(NSString *)cameraName | |
[_motionManager startAccelerometerUpdates]; | ||
|
||
[self setCaptureSessionPreset:_resolutionPreset]; | ||
[self updateOrientation]; | ||
|
||
return self; | ||
} | ||
|
||
|
@@ -417,6 +423,40 @@ - (void)stop { | |
[_captureSession stopRunning]; | ||
} | ||
|
||
- (void)setDeviceOrientation:(UIDeviceOrientation)orientation { | ||
if (_deviceOrientation == orientation) { | ||
return; | ||
} | ||
|
||
_deviceOrientation = orientation; | ||
[self updateOrientation]; | ||
} | ||
|
||
- (void)updateOrientation { | ||
if (_isRecording) { | ||
return; | ||
} | ||
|
||
UIDeviceOrientation orientation = (_lockedCaptureOrientation != UIDeviceOrientationUnknown) | ||
? _lockedCaptureOrientation | ||
: _deviceOrientation; | ||
|
||
[self updateOrientation:orientation forCaptureOutput:_capturePhotoOutput]; | ||
[self updateOrientation:orientation forCaptureOutput:_captureVideoOutput]; | ||
} | ||
|
||
- (void)updateOrientation:(UIDeviceOrientation)orientation | ||
forCaptureOutput:(AVCaptureOutput *)captureOutput { | ||
if (!captureOutput) { | ||
return; | ||
} | ||
|
||
AVCaptureConnection *connection = [captureOutput connectionWithMediaType:AVMediaTypeVideo]; | ||
if (connection && connection.isVideoOrientationSupported) { | ||
connection.videoOrientation = [self getVideoOrientationForDeviceOrientation:orientation]; | ||
} | ||
} | ||
|
||
- (void)captureToFile:(FlutterResult)result API_AVAILABLE(ios(10)) { | ||
AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; | ||
if (_resolutionPreset == max) { | ||
|
@@ -437,18 +477,6 @@ - (void)captureToFile:(FlutterResult)result API_AVAILABLE(ios(10)) { | |
return; | ||
} | ||
|
||
AVCaptureConnection *connection = [_capturePhotoOutput connectionWithMediaType:AVMediaTypeVideo]; | ||
|
||
if (connection) { | ||
if (_lockedCaptureOrientation != UIDeviceOrientationUnknown) { | ||
connection.videoOrientation = | ||
[self getVideoOrientationForDeviceOrientation:_lockedCaptureOrientation]; | ||
} else { | ||
connection.videoOrientation = | ||
[self getVideoOrientationForDeviceOrientation:[[UIDevice currentDevice] orientation]]; | ||
} | ||
} | ||
|
||
[_capturePhotoOutput capturePhotoWithSettings:settings | ||
delegate:[[FLTSavePhotoDelegate alloc] initWithPath:path | ||
result:result]]; | ||
|
@@ -812,9 +840,11 @@ - (void)startVideoRecordingWithResult:(FlutterResult)result { | |
- (void)stopVideoRecordingWithResult:(FlutterResult)result { | ||
if (_isRecording) { | ||
_isRecording = NO; | ||
|
||
if (_videoWriter.status != AVAssetWriterStatusUnknown) { | ||
[_videoWriter finishWritingWithCompletionHandler:^{ | ||
if (self->_videoWriter.status == AVAssetWriterStatusCompleted) { | ||
[self updateOrientation]; | ||
result(self->_videoRecordingPath); | ||
self->_videoRecordingPath = nil; | ||
} else { | ||
|
@@ -854,12 +884,18 @@ - (void)lockCaptureOrientationWithResult:(FlutterResult)result | |
result(getFlutterError(e)); | ||
return; | ||
} | ||
_lockedCaptureOrientation = orientation; | ||
|
||
if (_lockedCaptureOrientation != orientation) { | ||
_lockedCaptureOrientation = orientation; | ||
[self updateOrientation]; | ||
} | ||
|
||
result(nil); | ||
} | ||
|
||
- (void)unlockCaptureOrientationWithResult:(FlutterResult)result { | ||
_lockedCaptureOrientation = UIDeviceOrientationUnknown; | ||
[self updateOrientation]; | ||
result(nil); | ||
} | ||
|
||
|
@@ -1101,6 +1137,7 @@ - (BOOL)setupWriterForPath:(NSString *)path { | |
if (_enableAudio && !_isAudioSetup) { | ||
[self setUpCaptureSessionForAudio]; | ||
} | ||
|
||
_videoWriter = [[AVAssetWriter alloc] initWithURL:outputURL | ||
fileType:AVFileTypeMPEG4 | ||
error:&error]; | ||
|
@@ -1109,11 +1146,9 @@ - (BOOL)setupWriterForPath:(NSString *)path { | |
[_methodChannel invokeMethod:errorMethod arguments:error.description]; | ||
return NO; | ||
} | ||
NSDictionary *videoSettings = [NSDictionary | ||
dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey, | ||
[NSNumber numberWithInt:_previewSize.width], AVVideoWidthKey, | ||
[NSNumber numberWithInt:_previewSize.height], AVVideoHeightKey, | ||
nil]; | ||
|
||
NSDictionary *videoSettings = [_captureVideoOutput | ||
recommendedVideoSettingsForAssetWriterWithOutputFileType:AVFileTypeMPEG4]; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
cfchris
|
||
_videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo | ||
outputSettings:videoSettings]; | ||
|
||
|
@@ -1124,14 +1159,7 @@ - (BOOL)setupWriterForPath:(NSString *)path { | |
}]; | ||
|
||
NSParameterAssert(_videoWriterInput); | ||
CGFloat rotationDegrees; | ||
if (_lockedCaptureOrientation != UIDeviceOrientationUnknown) { | ||
rotationDegrees = [self getRotationFromDeviceOrientation:_lockedCaptureOrientation]; | ||
} else { | ||
rotationDegrees = [self getRotationFromDeviceOrientation:[UIDevice currentDevice].orientation]; | ||
} | ||
|
||
_videoWriterInput.transform = CGAffineTransformMakeRotation(rotationDegrees * M_PI / 180); | ||
_videoWriterInput.expectsMediaDataInRealTime = YES; | ||
|
||
// Add the audio input | ||
|
@@ -1194,21 +1222,6 @@ - (void)setUpCaptureSessionForAudio { | |
} | ||
} | ||
} | ||
|
||
- (int)getRotationFromDeviceOrientation:(UIDeviceOrientation)orientation { | ||
switch (orientation) { | ||
case UIDeviceOrientationPortraitUpsideDown: | ||
return 270; | ||
case UIDeviceOrientationLandscapeRight: | ||
return 180; | ||
case UIDeviceOrientationLandscapeLeft: | ||
return 0; | ||
case UIDeviceOrientationPortrait: | ||
default: | ||
return 90; | ||
}; | ||
} | ||
|
||
@end | ||
|
||
@interface CameraPlugin () | ||
|
@@ -1257,7 +1270,13 @@ - (void)startOrientationListener { | |
|
||
- (void)orientationChanged:(NSNotification *)note { | ||
UIDevice *device = note.object; | ||
[self sendDeviceOrientation:device.orientation]; | ||
UIDeviceOrientation orientation = device.orientation; | ||
|
||
if (_camera) { | ||
[_camera setDeviceOrientation:orientation]; | ||
} | ||
|
||
[self sendDeviceOrientation:orientation]; | ||
} | ||
|
||
- (void)sendDeviceOrientation:(UIDeviceOrientation)orientation { | ||
|
@@ -1318,6 +1337,7 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re | |
FLTCam *cam = [[FLTCam alloc] initWithCameraName:cameraName | ||
resolutionPreset:resolutionPreset | ||
enableAudio:[enableAudio boolValue] | ||
orientation:[[UIDevice currentDevice] orientation] | ||
dispatchQueue:_dispatchQueue | ||
error:&error]; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
This change has spawned at least 5 issues because video encoding went from always being MPEG-4/H264 to sometimes on iOS being MPEG-H/HEVC/H265 (which is far less compatible). See flutter/flutter#83074
We updated Flutter, and several plugins, and fixed some bugs, that made it through PR and TestFlight. And about a month later, our customers started telling us some of their customers are getting "black" videos with only audio. It is because those customers are getting HEVC encoded videos.
I cannot use the old version of the plugin because of version and compatibility issues. So, I must move forward.
I'm hopeful this will eventually either be reverted or made a configuration setting so I can opt back in.
In the meantime, I have started a fork to revert this one change. But, I'm not an iOS developer, and when I try to start recording video in the example app, it immediately crashes and logs errors.
Here is the link to my fork. https://github.com/DealerPeak/plugins/tree/revert-to-h264-v2
I would appreciate any help getting this working again.