4

How to Fix capturing images with front facing camera mirrors image? SnapChat seems to fix it as well as WhatsApp and Instagram , how can i? i would really love to find a solution for this... its quite of annoying...Thanks ahead

I have seen Always seeing Mirror image while capturing from Front Camera iOS 5.0 but it flip the images both for rear camera and frontal which doesnt solve the problem for anyone really . if anyone can help me figure out how to only flip the front camera images or any other solution that will be great !

import UIKit
import AVFoundation

@available(iOS 10.0, *)
class CameraViewController: UIViewController,AVCaptureVideoDataOutputSampleBufferDelegate {

let photoSettings = AVCapturePhotoSettings()
    var audioPlayer = AVAudioPlayer()
    var captureSession = AVCaptureSession()
    var videoDeviceInput: AVCaptureDeviceInput!
    var previewLayer = AVCaptureVideoPreviewLayer()
    var frontCamera: Bool = false
    var captureDevice:AVCaptureDevice!
    var takePhoto = false

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        prepareCamera()
    }

    func prepareCamera() {
        captureSession.sessionPreset = AVCaptureSessionPresetPhoto

        if let availableDevices = AVCaptureDeviceDiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaTypeVideo, position: .back).devices {
            captureDevice = availableDevices.first
            beginSession()
        } 
    }

    func frontCamera(_ front: Bool){
        let devices = AVCaptureDevice.devices()

        do{
            try captureSession.removeInput(AVCaptureDeviceInput(device:captureDevice!)) 
        }catch{
            print("Error")
        }

        for device in devices!{
            if((device as AnyObject).hasMediaType(AVMediaTypeVideo)){
                if front{
                    if (device as AnyObject).position == AVCaptureDevicePosition.front {
                        captureDevice = device as? AVCaptureDevice

                        do{
                            try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice!))
                        }catch{}
                        break
                    }
                }else{
                    if (device as AnyObject).position == AVCaptureDevicePosition.back {
                        captureDevice = device as? AVCaptureDevice

                        do{
                            try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice!))
                        }catch{}
                        break
                    }
                }
            }
        }
    }

    func beginSession () {
        do {
            let captureDeviceInput = try AVCaptureDeviceInput(device: captureDevice)
            if let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) {
            self.previewLayer = previewLayer
            containerView.layer.addSublayer(previewLayer as? CALayer ?? CALayer())
            self.previewLayer.frame = self.view.layer.frame
            self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
            previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait
            captureSession.startRunning()

            let dataOutput = AVCaptureVideoDataOutput()
            dataOutput.videoSettings = [(kCVPixelBufferPixelFormatTypeKey as NSString):NSNumber(value:kCVPixelFormatType_32BGRA)]

            dataOutput.alwaysDiscardsLateVideoFrames = true

            if captureSession.canAddOutput(dataOutput) {
                captureSession.addOutput(dataOutput)

                photoSettings.isHighResolutionPhotoEnabled = true
                photoSettings.isAutoStillImageStabilizationEnabled = true
            }

            captureSession.commitConfiguration()

            let queue = DispatchQueue(label: "com.NightOut.captureQueue")
            dataOutput.setSampleBufferDelegate(self, queue: queue) 
        }
    }
        @IBAction func takePhoto(_ sender: Any) {
            takePhoto = true

            photoSettings.isHighResolutionPhotoEnabled = true
            photoSettings.isAutoStillImageStabilizationEnabled = true
    }

    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
        if takePhoto {
            takePhoto = false
            if let image = self.getImageFromSampleBuffer(buffer: sampleBuffer) {
                let photoVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PhotoVC") as! PhotoPreviewViewController

                photoVC.takenPhoto = image

                DispatchQueue.main.async {
                    self.present(photoVC, animated: true, completion: {
                        self.stopCaptureSession()
                    })
                }
            }  
        }
    }

    func getImageFromSampleBuffer (buffer:CMSampleBuffer) -> UIImage? {
        if let pixelBuffer = CMSampleBufferGetImageBuffer(buffer) {
            let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
            let context = CIContext()

            let imageRect = CGRect(x: 0, y: 0, width: CVPixelBufferGetWidth(pixelBuffer), height: CVPixelBufferGetHeight(pixelBuffer))

            if let image = context.createCGImage(ciImage, from: imageRect) {
                return UIImage(cgImage: image, scale: UIScreen.main.scale, orientation: .leftMirrored)
            }
    }
        return nil
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        self.captureSession.stopRunning()
    }

    func stopCaptureSession () {
        self.captureSession.stopRunning()

        if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
            for input in inputs {
                self.captureSession.removeInput(input)
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func DismissButtonAction(_ sender: UIButton) {

        UIView.animate(withDuration: 0.1, animations: {
            self.DismissButton.transform = CGAffineTransform.identity.scaledBy(x: 0.8, y: 0.8)
        }, completion: { (finish) in
            UIView.animate(withDuration: 0.1, animations: {
                self.DismissButton.transform = CGAffineTransform.identity
            })
        })
        performSegue(withIdentifier: "Segue", sender: nil)
    }
}
RandomGeek
  • 303
  • 5
  • 20
  • Possible duplicate of [Always seeing Mirror image while capturing from Front Camera iOS 5.0](https://stackoverflow.com/questions/9227450/always-seeing-mirror-image-while-capturing-from-front-camera-ios-5-0) – Craig Siemens Jul 20 '17 at 21:31
  • I saw that..`LeftMirrored` does the trick for the front camera but makes the rear camera flip the image the way u dont want... @CleverError – RandomGeek Jul 20 '17 at 22:19

4 Answers4

5

i figured this out myself, Here is the solution:

if captureDevice.position == AVCaptureDevicePosition.back {
    if let image = context.createCGImage(ciImage, from: imageRect) {
        return UIImage(cgImage: image, scale: UIScreen.main.scale, orientation: .right)
    }
}
                
if captureDevice.position == AVCaptureDevicePosition.front {
    if let image = context.createCGImage(ciImage, from: imageRect) {
        return UIImage(cgImage: image, scale: UIScreen.main.scale, orientation: .leftMirrored)
    }
}
grebulon
  • 7,697
  • 5
  • 42
  • 66
RandomGeek
  • 303
  • 5
  • 20
  • 8
    The correct solution to this is to set the AVCaptureConnection object's isVideoMirrored property to true when it's the front camera within the captureOutput callback, before CMSampleBufferGetImageBuffer is called. – Boon Oct 30 '17 at 07:28
  • @Boon can you write this as solution as I can get a better understanding? – Moondra Aug 07 '18 at 06:15
  • @RandomGeek is image the UIImageView when the captured image is temporarily stored? – Moondra Aug 07 '18 at 06:17
4

I'd recommend using native isVideoMirrored property of AVCaptureConnection without transforms.

Here are the example steps:

  1. Save the current camera position in your custom camera class:

private var currentCameraPosition: AVCaptureDevice.Position = .back

  1. Each time user rotates the camera, update currentCameraPosition

  2. And finally in your capturePhoto() method set isVideoMirrored accordingly:

     guard let connection = stillImageOutput.connection(with: .video) else { return }
     connection.isVideoMirrored = currentCameraPosition == .front
    

This will mirror the photo when the front camera is in use.

Use the same approach to mirror the front camera video:

    guard let connection = videoCaptureOutput.connection(with: .video) else { return }
    connection.isVideoMirrored = currentCameraPosition == .front
   

That's it!

Stacy Smith
  • 490
  • 5
  • 11
0

I did that a long ago. I don't have my system with me but i can say that transform your preview layer horizontally and it will show exact result as you want. For saving and exporting you will find lot of examples out here.

Amrit Trivedi
  • 1,240
  • 1
  • 9
  • 24
0
@IBAction func takePhotoClicked(_ sender: Any) {
    let settings = AVCapturePhotoSettings()
    //configure settings if needed.
    
    //Need to correct image orientation before moving further
    if let photoOutputConnection = photoOutput?.connection(with: .video) {
        photoOutputConnection.videoOrientation = orientationHandler.currentInterfaceOrientation()
        
        //For frontCamera settings to capture mirror image
        if currentCamera == frontCamera {
            photoOutputConnection.automaticallyAdjustsVideoMirroring = false
            photoOutputConnection.isVideoMirrored = true
        } else {
            photoOutputConnection.automaticallyAdjustsVideoMirroring = true
        }
        
    }
    photoOutput?.capturePhoto(with: settings, delegate: self)
}