xamarin Camera2Forms switch camera

hossein tavakoli 471 Reputation points
2021-05-22T20:19:46.777+00:00

I use Camera2Forms.
when I want to switch camera Front/Rear it doesn't work.

I tried this code :

            if (CameraPreview.Camera == CameraOptions.Front)
                CameraPreview.Camera = CameraOptions.Rear;
            else
                CameraPreview.Camera = CameraOptions.Front;

and this code :

          <cameraView:CameraPreview  
                    x:Name="CameraPreview"           
                    BackgroundColor="Black"
                    HorizontalOptions="FillAndExpand"
                    Camera="Front"                                         
                    Margin="0,0,0,0"
                    VerticalOptions="FillAndExpand">
            </cameraView:CameraPreview>
Developer technologies .NET Xamarin
{count} votes

2 answers

Sort by: Most helpful
  1. Anonymous
    2021-05-25T08:15:57.99+00:00

    Hello,​

    Welcome to our Microsoft Q&A platform!

    how can I do it from UI, for android or IOS

    First of all, Camera2 API just could be used in android, it does not work in iOS.

    So, we can change the code in the custom renderer CameraViewServiceRenderer.cs.

       [assembly: ExportRenderer(typeof(CameraPreview), typeof(CameraViewServiceRenderer))]  
       namespace Camera2Forms.Camera2  
       {  
           public class CameraViewServiceRenderer : ViewRenderer<CameraPreview, CameraDroid>  
       	{  
       		private CameraDroid _camera;  
               private CameraPreview _currentElement;  
               private readonly Context _context;  
         
       		public CameraViewServiceRenderer(Context context) : base(context)  
       		{  
       			_context = context;  
       		}  
         
       		protected override void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)  
       		{  
       			base.OnElementChanged(e);  
                   _currentElement = e.NewElement;  
         
                   _camera = new CameraDroid(Context,"0");  
         
                   SetNativeControl(_camera);  
         
                   if (e.NewElement != null && _camera != null)  
                   {  
                       e.NewElement.CameraClick = new Command(() => TakePicture());  
                       _currentElement = e.NewElement;  
                       _camera.SetCameraOption(_currentElement.Camera);  
                       _camera.Photo += OnPhoto;  
                   }  
         
               }  
         
               protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)  
               {  
                   base.OnElementPropertyChanged(sender, e);  
         
                   if (e.PropertyName == CameraPreview.CameraProperty.PropertyName)  
                   {  
                       //Set text block properties  
         
                       if (_currentElement.Camera == CustomViews.CameraOptions.Front)  
                       {  
                           //_camera = new CameraDroid(Context, "0");  
                           _camera._cameraId = "1";  
                           _camera.closeCamera();  
                           _camera.reopenCamera();  
                             
                       }  
                       else  
                       {  
                           _camera = new CameraDroid(Context, "1");  
                       }  
                       _camera.SetCameraOption(CustomViews.CameraOptions.Front);  
                       _camera.Photo += OnPhoto;  
                   }  
               }  
         
               public void TakePicture()  
               {  
                   _camera.LockFocus();  
               }  
         
               private void OnPhoto(object sender, byte[] imgSource)  
       		{  
                  //Here you have the image byte data to do whatever you want   
         
         
                   Device.BeginInvokeOnMainThread(() =>  
                   {  
                       _currentElement?.PictureTaken();  
                   });     
               }  
         
               protected override void Dispose(bool disposing)  
       		{  
       			_camera.Photo -= OnPhoto;  
         
       			base.Dispose(disposing);  
       		}  
       	}  
       }  
    

    Here is my code about the CameraDroid.cs, Due to the code in SetUpCameraOutputs method, it set the camera by LensFacing, so whatever we change for _cameraId, it not work.

       using Android.Content;  
       using Android.Graphics;  
       using Android.Hardware.Camera2;  
       using Android.Hardware.Camera2.Params;  
       using Android.Media;  
       using Android.OS;  
       using Android.Runtime;  
       using Android.Util;  
       using Android.Views;  
       using Android.Widget;  
       using Camera2Forms.CustomViews;  
       using Camera2Forms.Droid;  
       using Java.Lang;  
       using Java.Util.Concurrent;  
       using System;  
       using System.Collections.Generic;  
       using System.Diagnostics;  
       using Size = Android.Util.Size;  
         
       namespace Camera2Forms.Camera2  
       {  
           public class CameraDroid : FrameLayout, TextureView.ISurfaceTextureListener  
           {  
               #region Camera States  
         
               // Camera state: Showing camera preview.  
               public const int STATE_PREVIEW = 0;  
         
               // Camera state: Waiting for the focus to be locked.  
               public const int STATE_WAITING_LOCK = 1;  
         
               // Camera state: Waiting for the exposure to be precapture state.  
               public const int STATE_WAITING_PRECAPTURE = 2;  
         
               //Camera state: Waiting for the exposure state to be something other than precapture.  
               public const int STATE_WAITING_NON_PRECAPTURE = 3;  
         
               // Camera state: Picture was taken.  
               public const int STATE_PICTURE_TAKEN = 4;  
         
               #endregion  
         
               // The current state of camera state for taking pictures.  
               public int mState = STATE_PREVIEW;  
         
               private static readonly SparseIntArray Orientations = new SparseIntArray();  
         
               public event EventHandler<byte[]> Photo;  
         
               public bool OpeningCamera { private get; set; }  
         
               public CameraDevice CameraDevice;  
         
               private readonly CameraStateListener _cameraStateListener;  
               private readonly CameraCaptureListener _cameraCaptureListener;  
         
               private CaptureRequest.Builder _previewBuilder;  
               private CaptureRequest.Builder _captureBuilder;  
               private CaptureRequest _previewRequest;  
               private CameraCaptureSession _previewSession;  
               private SurfaceTexture _viewSurface;  
               private readonly TextureView _cameraTexture;  
               private Size _previewSize;  
               private readonly Context _context;  
               private CameraManager _manager;  
         
               private bool _flashSupported;  
               private Size[] _supportedJpegSizes;  
               private Size _idealPhotoSize = new Size(480, 640);  
         
               private HandlerThread _backgroundThread;  
               private Handler _backgroundHandler;  
         
               private ImageReader _imageReader;  
               public string _cameraId;  
         
               private LensFacing lensFacing;  
               private Semaphore mCameraOpenCloseLock = new Semaphore(1);  
         
               public void SetCameraOption(CameraOptions cameraOptions)  
               {  
                  this.lensFacing = (cameraOptions == CameraOptions.Front) ? LensFacing.Front : LensFacing.Back;  
                 //  this.lensFacing = LensFacing.Back;  
               }  
         
               public CameraDroid(Context context, string _cameraId) : base(context)  
               {  
                   _context = context;  
         
                   var inflater = LayoutInflater.FromContext(context);  
         
                   if (inflater == null) return;  
                   var view = inflater.Inflate(Resource.Layout.CameraLayout, this);  
                   this._cameraId = _cameraId;  
                   _cameraTexture = view.FindViewById<TextureView>(Resource.Id.cameraTexture);  
         
                   _cameraTexture.SurfaceTextureListener = this;  
         
                   _cameraStateListener = new CameraStateListener { Camera = this };  
         
                   _cameraCaptureListener = new CameraCaptureListener(this);  
         
                     
               }  
         
               public void OnSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)  
               {  
                   _viewSurface = surface;  
         
                   StartBackgroundThread();  
         
                   OpenCamera(width, height);  
               }  
         
               public bool OnSurfaceTextureDestroyed(SurfaceTexture surface)  
               {  
                   StopBackgroundThread();  
         
                   return true;  
               }  
         
               public void OnSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)  
               {  
         
               }  
         
               public void OnSurfaceTextureUpdated(SurfaceTexture surface)  
               {  
         
               }  
         
               private void SetUpCameraOutputs(int width, int height)  
               {  
                   _manager = (CameraManager)_context.GetSystemService(Context.CameraService);  
         
                   string[] cameraIds = _manager.GetCameraIdList();  
         
                   ///ffff  
                   //_cameraId = cameraIds[0];  
         
                   //for (int i = 0; i < cameraIds.Length; i++)  
                   //{  
                   //    CameraCharacteristics chararc = _manager.GetCameraCharacteristics(cameraIds[i]);  
         
                   //    var facing = (Integer)chararc.Get(CameraCharacteristics.LensFacing);  
                   //    if (facing != null && facing == (Integer.ValueOf((int)LensFacing.Back)))  
                   //    {  
                   //        _cameraId = cameraIds[i];  
         
                   //        //Phones like Galaxy S10 have 2 or 3 frontal cameras usually the one with flash is the one  
                   //        //that should be chosen, if not It will select the first one and that can be the fish  
                   //        //eye camera  
                   //        if (HasFLash(chararc))  
                   //            break;  
                   //    }  
                   //}  
         
                   var characteristics = _manager.GetCameraCharacteristics(_cameraId);  
                   var map = (StreamConfigurationMap)characteristics.Get(CameraCharacteristics.ScalerStreamConfigurationMap);  
         
                   if (_supportedJpegSizes == null && characteristics != null)  
                   {  
                       _supportedJpegSizes = ((StreamConfigurationMap)characteristics.Get(CameraCharacteristics.ScalerStreamConfigurationMap)).GetOutputSizes((int)ImageFormatType.Jpeg);  
                   }  
         
                   if (_supportedJpegSizes != null && _supportedJpegSizes.Length > 0)  
                   {  
                       _idealPhotoSize = GetOptimalSize(_supportedJpegSizes, 1050, 1400); //MAGIC NUMBER WHICH HAS PROVEN TO BE THE BEST  
                   }  
         
                   _imageReader = ImageReader.NewInstance(_idealPhotoSize.Width, _idealPhotoSize.Height, ImageFormatType.Jpeg, 1);  
         
                   var readerListener = new ImageAvailableListener();  
         
                   readerListener.Photo += (sender, buffer) =>  
                   {  
                       Photo?.Invoke(this, buffer);  
                   };  
         
                   _flashSupported = HasFLash(characteristics);  
         
                   _imageReader.SetOnImageAvailableListener(readerListener, _backgroundHandler);  
         
                   _previewSize = GetOptimalSize(map.GetOutputSizes(Class.FromType(typeof(SurfaceTexture))), width, height);  
               }  
         
               private bool HasFLash(CameraCharacteristics characteristics)  
               {  
                   var available = (Java.Lang.Boolean)characteristics.Get(CameraCharacteristics.FlashInfoAvailable);  
                   if (available == null)  
                   {  
                       return false;  
                   }  
                   else  
                   {  
                       return (bool)available;  
                   }  
               }  
         
               public void closeCamera()  
               {  
                   try  
                   {  
                       mCameraOpenCloseLock.Acquire();  
                       closePreviewSession();  
                       if (null != CameraDevice)  
                       {  
                           CameraDevice.Close();  
                           CameraDevice = null;  
                       }  
                       //if (null != mMediaRecorder)  
                       //{  
                       //    mMediaRecorder.release();  
                       //    mMediaRecorder = null;  
                       //}  
                   }  
                   catch (InterruptedException e)  
                   {  
                       throw new RuntimeException("Interrupted while trying to lock camera closing.");  
                   }  
                   finally  
                   {  
                       mCameraOpenCloseLock.Release();  
                   }  
               }  
         
               private void closePreviewSession()  
               {  
                   if (_previewSession != null)  
                   {  
                       _previewSession.Close();  
                       _previewSession = null;  
                   }  
               }  
         
               public void OpenCamera(int width, int height)  
               {  
                   if (_context == null || OpeningCamera)  
                   {  
                       return;  
                   }  
         
                   OpeningCamera = true;  
         
                   SetUpCameraOutputs(width, height);  
          
                   _manager.OpenCamera(_cameraId, _cameraStateListener, null);  
         
               }  
               public void reopenCamera()  
               {  
                   if (_cameraTexture.IsAvailable)  
                   {  
                       OpenCamera(_cameraTexture.Width, _cameraTexture.Height);  
                   }  
                   else  
                   {  
                       //_cameraTexture.setSurfaceTextureListener(mSurfaceTextureListener);  
                   }  
               }  
                   public void TakePhoto()  
               {  
                   if (_context == null || CameraDevice == null) return;  
         
                   if (_captureBuilder == null)  
                       _captureBuilder = CameraDevice.CreateCaptureRequest(CameraTemplate.StillCapture);  
         
                   _captureBuilder.AddTarget(_imageReader.Surface);  
         
                   _captureBuilder.Set(CaptureRequest.ControlAfMode, (int)ControlAFMode.ContinuousPicture);  
                   SetAutoFlash(_captureBuilder);  
         
                   _previewSession.StopRepeating();  
                   _previewSession.Capture(_captureBuilder.Build(),  
                       new CameraCaptureStillPictureSessionCallback  
                   {  
                       OnCaptureCompletedAction = session =>  
                       {  
                           UnlockFocus();  
                       }  
                   }, null);  
               }  
         
               public void StartPreview()  
               {  
                   if (CameraDevice == null || !_cameraTexture.IsAvailable || _previewSize == null) return;  
         
                   var texture = _cameraTexture.SurfaceTexture;  
         
                   texture.SetDefaultBufferSize(_previewSize.Width, _previewSize.Height);  
         
                   var surface = new Surface(texture);  
         
                   _previewBuilder = CameraDevice.CreateCaptureRequest(CameraTemplate.Preview);  
                   _previewBuilder.AddTarget(surface);  
         
                   List<Surface> surfaces = new List<Surface>();  
                   surfaces.Add(surface);  
                   surfaces.Add(_imageReader.Surface);  
         
                   CameraDevice.CreateCaptureSession(surfaces,  
                       new CameraCaptureStateListener  
                       {  
                           OnConfigureFailedAction = session =>  
                           {  
                           },  
                           OnConfiguredAction = session =>  
                           {  
                               _previewSession = session;  
                               UpdatePreview();  
                           }  
                       },  
                       _backgroundHandler);  
               }  
         
               private void UpdatePreview()  
               {  
                   if (CameraDevice == null || _previewSession == null) return;  
         
                   // Reset the auto-focus trigger  
                   _previewBuilder.Set(CaptureRequest.ControlAfMode, (int)ControlAFMode.ContinuousPicture);  
                   SetAutoFlash(_previewBuilder);  
         
                   _previewRequest = _previewBuilder.Build();  
                   _previewSession.SetRepeatingRequest(_previewRequest, _cameraCaptureListener, _backgroundHandler);  
         
                     
               }  
         
               Size GetOptimalSize(IList<Size> sizes, int h, int w)  
               {  
                   double AspectTolerance = 0.1;  
                   double targetRatio = (double)w / h;  
         
                   if (sizes == null)  
                   {  
                       return null;  
                   }  
         
                   Size optimalSize = null;  
                   double minDiff = double.MaxValue;  
                   int targetHeight = h;  
         
                   while (optimalSize == null)  
                   {  
                       foreach (Size size in sizes)  
                       {  
                           double ratio = (double)size.Width / size.Height;  
         
                           if (System.Math.Abs(ratio - targetRatio) > AspectTolerance)  
                               continue;  
                           if (System.Math.Abs(size.Height - targetHeight) < minDiff)  
                           {  
                               optimalSize = size;  
                               minDiff = System.Math.Abs(size.Height - targetHeight);  
                           }  
                       }  
         
                       if (optimalSize == null)  
                           AspectTolerance += 0.1f;  
                   }  
         
                   return optimalSize;  
               }  
         
               public void SetAutoFlash(CaptureRequest.Builder requestBuilder)  
               {  
                   if (_flashSupported)  
                   {  
                       requestBuilder.Set(CaptureRequest.ControlAeMode, (int)ControlAEMode.OnAutoFlash);  
                   }  
               }  
         
               private void StartBackgroundThread()  
               {  
                   _backgroundThread = new HandlerThread("CameraBackground");  
                   _backgroundThread.Start();  
                   _backgroundHandler = new Handler(_backgroundThread.Looper);  
               }  
         
               private void StopBackgroundThread()  
               {  
                   _backgroundThread.QuitSafely();  
                   try  
                   {  
                       _backgroundThread.Join();  
                       _backgroundThread = null;  
                       _backgroundHandler = null;  
                   }  
                   catch (InterruptedException e)  
                   {  
                       e.PrintStackTrace();  
                   }  
               }  
         
               public void LockFocus()  
               {  
                   try  
                   {  
                       // This is how to tell the camera to lock focus.  
                       _previewBuilder.Set(CaptureRequest.ControlAfTrigger, (int)ControlAFTrigger.Start);  
                       // Tell #mCaptureCallback to wait for the lock.  
                       mState = STATE_WAITING_LOCK;  
                       _previewSession.Capture(_previewBuilder.Build(), _cameraCaptureListener, _backgroundHandler);  
                   }  
                   catch (CameraAccessException e)  
                   {  
                       e.PrintStackTrace();  
                   }  
               }  
         
               public void UnlockFocus()  
               {  
                   try  
                   {  
                       // Reset the auto-focus trigger  
                       _previewBuilder.Set(CaptureRequest.ControlAfTrigger, (int)ControlAFTrigger.Cancel);  
                       SetAutoFlash(_previewBuilder);  
         
                       _previewSession.Capture(_previewBuilder.Build(), _cameraCaptureListener, _backgroundHandler);  
                       // After this, the camera will go back to the normal state of preview.  
                       mState = STATE_PREVIEW;  
                       _previewSession.SetRepeatingRequest(_previewRequest, _cameraCaptureListener, _backgroundHandler);  
                   }  
                   catch (CameraAccessException e)  
                   {  
                       e.PrintStackTrace();  
                   }  
               }  
         
               public void RunPrecaptureSequence()  
               {  
                   try  
                   {  
                       _previewBuilder.Set(CaptureRequest.ControlAePrecaptureTrigger, (int)ControlAEPrecaptureTrigger.Start);  
                       mState = STATE_WAITING_PRECAPTURE;  
                       _previewSession.Capture(_previewBuilder.Build(), _cameraCaptureListener, _backgroundHandler);  
                   }  
                   catch (CameraAccessException e)  
                   {  
                       e.PrintStackTrace();  
                   }  
               }  
           }  
       }  
    

    In the xamarinforms, we can add button to switch camera.

       <cameraView:CameraPreview    
                           x:Name="CameraPreview"             
                           BackgroundColor="Black"  
                           HorizontalOptions="FillAndExpand"  
                           Camera="Rear"                                           
                           Margin="0,0,0,0"  
                           VerticalOptions="FillAndExpand"  
                           Grid.Column="0" Grid.Row="0">  
                   </cameraView:CameraPreview>  
                   <Button   
                                   Text="Take Picture"  
                                   x:Name="CameraButton"  
                                   Clicked="OnCameraClicked"   
                                   FontSize="Medium"  
                                   />  
         
                   <Button Text="ChangeCamera" Clicked="Button_Clicked"></Button>  
         
         
         private void Button_Clicked(object sender, EventArgs e)  
               {  
                   CameraPreview.Camera = CameraOptions.Front;  
               }  
    

    Best Regards,

    Leon Lu


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Anonymous
    2021-05-26T09:42:16.3+00:00

    First, download this demo that you provide in question from this url.

    https://github.com/vtserej/Camera2Forms

    Then Add a button in CameraPage.xaml. In the Button_Clicked, change the camera from back to front.

    <ContentPage.Content>
            <StackLayout>
                <cameraView:CameraPreview  
                        x:Name="CameraPreview"           
                        BackgroundColor="Black"
                        HorizontalOptions="FillAndExpand"
                        Camera="Rear"                                         
                        Margin="0,0,0,0"
                        VerticalOptions="FillAndExpand"
                        Grid.Column="0" Grid.Row="0">
                </cameraView:CameraPreview>
                <Button 
                                Text="Take Picture"
                                x:Name="CameraButton"
                                Clicked="OnCameraClicked" 
                                FontSize="Medium"
                                />
    
                <Button Text="ChangeCamera" Clicked="Button_Clicked"></Button>
            </StackLayout>
        </ContentPage.Content>
    
    
    public partial class CameraPage : ContentPage
        {
            public CameraPage ()
            {
                InitializeComponent();
                CameraPreview.PictureFinished += OnPictureFinished;
            }
    
            void OnCameraClicked(object sender, EventArgs e)
            {
                CameraPreview.CameraClick.Execute(null);
            }
    
            private void OnPictureFinished()
            {
                DisplayAlert("Confirm", "Picture Taken","","Ok");
            }
    
            private void Button_Clicked(object sender, EventArgs e)
            {
                CameraPreview.Camera = CameraOptions.Front;
            }
        }
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.