1- using System . Buffers ;
2- using System . Diagnostics ;
3- using System . Runtime . InteropServices ;
1+ using System . Diagnostics ;
42using AVFoundation ;
53using CommunityToolkit . Maui . Core . Primitives ;
64using CommunityToolkit . Maui . Extensions ;
@@ -22,19 +20,26 @@ partial class CameraManager
2220
2321 AVCaptureFlashMode flashMode ;
2422
23+ IDisposable ? orientationDidChangeObserver ;
24+ PreviewView ? previewView ;
25+ AVCaptureVideoOrientation videoOrientation ;
26+
2527 // IN the future change the return type to be an alias
2628 public UIView CreatePlatformView ( )
2729 {
2830 captureSession = new AVCaptureSession
2931 {
3032 SessionPreset = AVCaptureSession . PresetPhoto
3133 } ;
32-
33- var previewView = new PreviewView
34+
35+ previewView = new PreviewView
3436 {
3537 Session = captureSession
3638 } ;
3739
40+ orientationDidChangeObserver = UIDevice . Notifications . ObserveOrientationDidChange ( ( _ , _ ) => UpdateVideoOrientation ( ) ) ;
41+ UpdateVideoOrientation ( ) ;
42+
3843 return previewView ;
3944 }
4045
@@ -194,41 +199,51 @@ protected virtual async partial ValueTask PlatformTakePicture(CancellationToken
194199 var capturePhotoSettings = AVCapturePhotoSettings . FromFormat ( codecSettings ) ;
195200 capturePhotoSettings . FlashMode = photoOutput . SupportedFlashModes . Contains ( flashMode ) ? flashMode : photoOutput . SupportedFlashModes . First ( ) ;
196201
202+ if ( AVMediaTypes . Video . GetConstant ( ) is NSString avMediaTypeVideo )
203+ {
204+ var photoOutputConnection = photoOutput . ConnectionFromMediaType ( avMediaTypeVideo ) ;
205+ if ( photoOutputConnection is not null )
206+ {
207+ photoOutputConnection . VideoOrientation = videoOrientation ;
208+ }
209+ }
210+
197211 var wrapper = new AVCapturePhotoCaptureDelegateWrapper ( ) ;
198212
199213 photoOutput . CapturePhoto ( capturePhotoSettings , wrapper ) ;
200214
201215 var result = await wrapper . Task . WaitAsync ( token ) ;
202- var data = result . Photo . FileDataRepresentation ;
203-
204216 if ( result . Error is not null )
205217 {
206- cameraView . OnMediaCapturedFailed ( result . Error . LocalizedFailureReason ) ;
207- return ;
208- }
218+ var failureReason = result . Error . LocalizedDescription ;
219+ if ( ! string . IsNullOrEmpty ( result . Error . LocalizedFailureReason ) )
220+ {
221+ failureReason = $ "{ failureReason } - { result . Error . LocalizedFailureReason } ";
222+ }
209223
210- if ( data is null )
211- {
212- cameraView . OnMediaCapturedFailed ( "Unable to retrieve the file data representation from the captured result." ) ;
224+ cameraView . OnMediaCapturedFailed ( failureReason ) ;
213225 return ;
214226 }
215227
216- var dataBytes = ArrayPool < byte > . Shared . Rent ( ( int ) data . Length ) ;
217-
228+ Stream ? imageData ;
218229 try
219230 {
220- Marshal . Copy ( data . Bytes , dataBytes , 0 , ( int ) data . Length ) ;
221-
222- cameraView . OnMediaCaptured ( new MemoryStream ( dataBytes ) ) ;
231+ imageData = result . Photo . FileDataRepresentation ? . AsStream ( ) ;
232+ }
233+ catch ( Exception e )
234+ {
235+ // possible exception: ObjCException NSInvalidArgumentException NSAllocateMemoryPages(...) failed in AVCapturePhoto.get_FileDataRepresentation()
236+ cameraView . OnMediaCapturedFailed ( $ "Unable to retrieve the file data representation from the captured result: { e . Message } ") ;
237+ return ;
223238 }
224- catch ( Exception ex )
239+
240+ if ( imageData is null )
225241 {
226- cameraView . OnMediaCapturedFailed ( ex . Message ) ;
227- throw ;
242+ cameraView . OnMediaCapturedFailed ( "Unable to retrieve the file data representation from the captured result." ) ;
228243 }
229- finally
244+ else
230245 {
231- ArrayPool < byte > . Shared . Return ( dataBytes ) ;
246+ cameraView . OnMediaCaptured ( imageData ) ;
232247 }
233248 }
234249
@@ -243,11 +258,37 @@ protected virtual void Dispose(bool disposing)
243258 captureInput ? . Dispose ( ) ;
244259 captureInput = null ;
245260
261+ orientationDidChangeObserver ? . Dispose ( ) ;
262+ orientationDidChangeObserver = null ;
263+
246264 photoOutput ? . Dispose ( ) ;
247265 photoOutput = null ;
248266 }
249267 }
250268
269+ static AVCaptureVideoOrientation GetVideoOrientation ( )
270+ {
271+ IEnumerable < UIScene > scenes = UIApplication . SharedApplication . ConnectedScenes ;
272+ var interfaceOrientation = scenes . FirstOrDefault ( ) is UIWindowScene windowScene
273+ ? windowScene . InterfaceOrientation
274+ : UIApplication . SharedApplication . StatusBarOrientation ;
275+
276+ return interfaceOrientation switch
277+ {
278+ UIInterfaceOrientation . Portrait => AVCaptureVideoOrientation . Portrait ,
279+ UIInterfaceOrientation . PortraitUpsideDown => AVCaptureVideoOrientation . PortraitUpsideDown ,
280+ UIInterfaceOrientation . LandscapeRight => AVCaptureVideoOrientation . LandscapeRight ,
281+ UIInterfaceOrientation . LandscapeLeft => AVCaptureVideoOrientation . LandscapeLeft ,
282+ _ => AVCaptureVideoOrientation . Portrait
283+ } ;
284+ }
285+
286+ void UpdateVideoOrientation ( )
287+ {
288+ videoOrientation = GetVideoOrientation ( ) ;
289+ previewView ? . UpdatePreviewVideoOrientation ( videoOrientation ) ;
290+ }
291+
251292 sealed class AVCapturePhotoCaptureDelegateWrapper : AVCapturePhotoCaptureDelegate
252293 {
253294 readonly TaskCompletionSource < CapturePhotoResult > taskCompletionSource = new ( ) ;
@@ -299,20 +340,15 @@ public AVCaptureSession? Session
299340 public override void LayoutSubviews ( )
300341 {
301342 base . LayoutSubviews ( ) ;
343+ UpdatePreviewVideoOrientation ( GetVideoOrientation ( ) ) ;
344+ }
302345
303- if ( PreviewLayer . Connection is null )
346+ public void UpdatePreviewVideoOrientation ( AVCaptureVideoOrientation videoOrientation )
347+ {
348+ if ( PreviewLayer . Connection is not null )
304349 {
305- return ;
350+ PreviewLayer . Connection . VideoOrientation = videoOrientation ;
306351 }
307-
308- PreviewLayer . Connection . VideoOrientation = UIDevice . CurrentDevice . Orientation switch
309- {
310- UIDeviceOrientation . Portrait => AVCaptureVideoOrientation . Portrait ,
311- UIDeviceOrientation . PortraitUpsideDown => AVCaptureVideoOrientation . PortraitUpsideDown ,
312- UIDeviceOrientation . LandscapeLeft => AVCaptureVideoOrientation . LandscapeRight ,
313- UIDeviceOrientation . LandscapeRight => AVCaptureVideoOrientation . LandscapeLeft ,
314- _ => PreviewLayer . Connection . VideoOrientation
315- } ;
316352 }
317353 }
318354}
0 commit comments