     
     override open func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
-        // Start the session when view will appear if necessary.
-        if !_session.isRunning {
-            _session.startRunning()
+        
+        // Start the session immediately if the starting mode is `.at(.willAppear)`.
+        switch _startingOfSession {
+        case .at(.willAppear):
+            if !_session.isRunning {
+                _session.startRunning()
+            }
+        default: break
+        }
+    }
+    
+    open override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        
+        // Start the session immediately if the starting mode is `.at(.didAppear)`.
+        switch _startingOfSession {
+        case .at(.didAppear):
+            if !_session.isRunning {
+                _session.startRunning()
+            }
+        default: break
         }
     }
     
     override open func viewDidDisappear(_ animated: Bool) {
         super.viewDidDisappear(animated)
         // Stop the session when view did disappear.
-        if stopSessionWhenDisposed {
+        /* if stopSessionWhenDisposed {
             _session.stopRunning()
-        }
+        } */
     }
     
     // MARK: Private.
     
+    /// Create session and device input if session is nil and device inputs of session is empty.
     private func _initSession() throws {
-        // Initialize the device input for the session.
-        var adevice: AVCaptureDevice!
-        if #available(iOS 10.0, *) {
-            adevice = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .back)
-        } else {
-            adevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
-        }
-        guard let device = adevice else { throw CameraError.initializing(.noneOfCaptureDevice) }
-        
-        _input = try AVCaptureDeviceInput(device: device)
+        func create_add_input() throws {
+            var adevice:  AVCaptureDevice!
+            if #available(iOS 10.0, *) {
+                adevice = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .back)
+            } else {
+                adevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
+            }
+            guard let device = adevice else { throw CameraError.initializing(.noneOfCaptureDevice) }
+            
+            _input = try AVCaptureDeviceInput(device: device)
+            _session =  AVCaptureSession()
+            if  _session.canAddInput (_input) {
+                _session.addInput    (_input)
+            } else { throw CameraError.initializing(.sessionCannotAddInput) }
+        }
         // Configure the display out put.
         _displayOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as AnyHashable: kCVPixelFormatType_32BGRA]
         _displayOutput.setSampleBufferDelegate(self, queue: _displayQueue)
         _displayOutput.alwaysDiscardsLateVideoFrames = true
         // Initialize and configure the session of the capture.
-        _session = AVCaptureSession()
-        if _session.canSetSessionPreset(AVCaptureSessionPresetPhoto) {
-            _session.sessionPreset = AVCaptureSessionPresetPhoto
-        }
-        
-    }
-    
-    private func _configureSession() {
-        _sessionQueue.async { [weak self] in autoreleasepool{
-            guard let wself = self else { return }
-            if wself._session.canAddInput(wself._input) {
-                wself._session.addInput(wself._input)
-            }
-            if wself._session.canAddOutput(wself._output) {
-                wself._session.addOutput(wself._output)
-            }
-            if wself._session.canAddOutput(wself._displayOutput) {
-                wself._session.addOutput(wself._displayOutput)
-            }
-        } }
+        if  _session == nil {
+            // Initialize the device input for the session.
+            try create_add_input()
+        } else {
+            // Find the available device inputs.
+            let deviceInputs = _session.inputs.flatMap({ ($0 is AVCaptureDeviceInput && ($0 as! AVCaptureDeviceInput).device.hasMediaType(AVMediaTypeVideo)) ? $0 : nil }) as! [AVCaptureDeviceInput]
+            if  deviceInputs.isEmpty {
+                try create_add_input()
+            } else if deviceInputs.startIndex == deviceInputs.index(before: deviceInputs.endIndex) {
+                // Has only one video device inputs.
+                _input = deviceInputs.first
+            }
+        }
+        _initPreviewView() // Call the initialzer of preview view obviously.
+        // Configure session.
+        if #available(iOS 10.0, *) {
+            if  _session.canAddOutput(capturePhotoOutput) {
+                _session.addOutput   (capturePhotoOutput)
+            } else { throw CameraError.initializing(.sessionCannotAddOutput) }
+        }
+        if  _session.canAddOutput(_displayOutput) {
+            _session.addOutput   (_displayOutput)
+        } else { throw CameraError.initializing(.sessionCannotAddOutput) }
+    }
+    /// Initialize the preview view if the session is not nil and inputs of the session is not empty.
+    private func _initPreviewView() {
+        guard _previewView?.previewLayer.session !== _session && _session != nil && !_session.inputs.filter({ ($0 is AVCaptureDeviceInput && ($0 as! AVCaptureDeviceInput).device.hasMediaType(AVMediaTypeVideo)) }).isEmpty else { return }
+        
+        _previewView = PreviewView(session: _session)
     }
     
     private func _setupTopBar() {

@objc public protocol CameraViewControllerDelegate {
    @objc optional func cameraViewControllerDidCancel(_ cameraViewController: CameraViewController)
}

@available(iOS 9.0, *)
open class CameraViewController: UIViewController {
    open weak var delegate: CameraViewControllerDelegate?
    open   var stopSessionWhenDisposed: Bool = false
    public var configurationQueue: DispatchQueue { return _sessionQueue }
    /// Sample buffer delegates queue.
    fileprivate
    var _sampleBufferDelegates: NSHashTable<AVCaptureVideoDataOutputSampleBufferDelegate> = NSHashTable.weakObjects()
    
    private var _session: AVCaptureSession!
    private var _input  : AVCaptureDeviceInput!
    private var _output : AVCapturePhotoOutput!
    
    public var previewView: CaptureVideoPreviewView! { return _previewView }
    fileprivate var _previewView: CaptureVideoPreviewView!
    
    // MARK: Tool Views.
    
    private let _flashConfigs: [(title: String, image: UIImage)] = [("自动", #imageLiteral(resourceName: "flash_auto")), ("打开", #imageLiteral(resourceName: "flash_on")), ("关闭", #imageLiteral(resourceName: "flash_off"))]
    private let _hdrConfigs: [(title: String, image: UIImage)] = [("自动", UIImage(named: _Resource.bundle+"HDR_auto")!), ("打开", UIImage(named: _Resource.bundle+"HDR_on")!), ("关闭", UIImage(named: _Resource.bundle+"HDR_off")!)]
    public var topBar: TopBar { return _topBar }
    fileprivate lazy var _topBar: TopBar = { () -> TopBar in
        let topBar = TopBar()
        topBar.tintColor = .white

        
    }
    
    @objc fileprivate func _handleToggleFace(_ sender: UIButton) {
        _sessionQueue.async { [unowned self] in
            let _ = try? self._previewView.toggle()
        }
        // Add transition animation.
        let transition = CATransition()
        // cube, suckEffect, oglFlip, rippleEffect, pageCurl, pageUnCurl, cameraIrisHollowOpen, cameraIrisHollowClose
        transition.type = "oglFlip"
        transition.subtype = kCATransitionFromLeft
        transition.duration = 0.25 * 2.0
        self.previewView.layer.add(transition, forKey: "transition")
    }
    
    @objc
    fileprivate func _handleCancel(_ sender: UIButton) {
