From 5ebd4668690c9e51ae80342d5e43bccac2339c1d Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Sun, 20 May 2018 09:07:37 +0800
Subject: [PATCH 1/7] camera: Add camera flip config

---
 src/citra/config.cpp                          |   6 +
 src/citra/default_ini.h                       |   6 +
 src/citra_qt/camera/qt_camera_factory.cpp     |   6 +-
 src/citra_qt/camera/qt_camera_factory.h       |   4 +-
 src/citra_qt/camera/qt_multimedia_camera.cpp  |  14 +-
 src/citra_qt/camera/qt_multimedia_camera.h    |   6 +-
 src/citra_qt/camera/still_image_camera.cpp    |  16 +-
 src/citra_qt/camera/still_image_camera.h      |   6 +-
 src/citra_qt/configuration/config.cpp         |   8 +
 .../configuration/configure_camera.cpp        |  23 +-
 src/citra_qt/configuration/configure_camera.h |   1 +
 .../configuration/configure_camera.ui         | 572 ++++++++++--------
 src/core/frontend/camera/factory.cpp          |   9 +-
 src/core/frontend/camera/factory.h            |  15 +-
 src/core/hle/service/cam/cam.cpp              |   5 +-
 src/core/settings.h                           |   1 +
 16 files changed, 416 insertions(+), 282 deletions(-)

diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index b4e3a2ce9..ce51b687b 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -155,14 +155,20 @@ void Config::ReadValues() {
         sdl2_config->Get("Camera", "camera_outer_right_name", "blank");
     Settings::values.camera_config[OuterRightCamera] =
         sdl2_config->Get("Camera", "camera_outer_right_config", "");
+    Settings::values.camera_flip[OuterRightCamera] =
+        sdl2_config->GetInteger("Camera", "camera_outer_right_flip", 0);
     Settings::values.camera_name[InnerCamera] =
         sdl2_config->Get("Camera", "camera_inner_name", "blank");
     Settings::values.camera_config[InnerCamera] =
         sdl2_config->Get("Camera", "camera_inner_config", "");
+    Settings::values.camera_flip[InnerCamera] =
+        sdl2_config->GetInteger("Camera", "camera_inner_flip", 0);
     Settings::values.camera_name[OuterLeftCamera] =
         sdl2_config->Get("Camera", "camera_outer_left_name", "blank");
     Settings::values.camera_config[OuterLeftCamera] =
         sdl2_config->Get("Camera", "camera_outer_left_config", "");
+    Settings::values.camera_flip[OuterLeftCamera] =
+        sdl2_config->GetInteger("Camera", "camera_outer_left_flip", 0);
 
     // Miscellaneous
     Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Info");
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 7179d6f94..4a17eb6ca 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -178,13 +178,19 @@ camera_outer_right_name =
 # A config string for the right outer camera. Its meaning is defined by the camera engine
 camera_outer_right_config =
 
+# The image flip to apply
+# 0: None (default), 1: Horizontal, 2: Vertical, 3: Reverse
+camera_outer_right_flip =
+
 # ... for the left outer camera
 camera_outer_left_name =
 camera_outer_left_config =
+camera_outer_left_flip =
 
 # ... for the inner camera
 camera_inner_name =
 camera_inner_config =
+camera_inner_flip =
 
 [Miscellaneous]
 # A filter which removes logs below a certain logging level.
diff --git a/src/citra_qt/camera/qt_camera_factory.cpp b/src/citra_qt/camera/qt_camera_factory.cpp
index fa78591ba..063a600df 100644
--- a/src/citra_qt/camera/qt_camera_factory.cpp
+++ b/src/citra_qt/camera/qt_camera_factory.cpp
@@ -7,9 +7,9 @@
 
 namespace Camera {
 
-std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(const std::string& config,
-                                                                int width, int height) const {
-    std::unique_ptr<CameraInterface> camera = Create(config);
+std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(
+    const std::string& config, int width, int height, const Service::CAM::Flip& flip) const {
+    std::unique_ptr<CameraInterface> camera = Create(config, flip);
 
     if (camera->IsPreviewAvailable()) {
         return camera;
diff --git a/src/citra_qt/camera/qt_camera_factory.h b/src/citra_qt/camera/qt_camera_factory.h
index 7efc21b58..9e590ca66 100644
--- a/src/citra_qt/camera/qt_camera_factory.h
+++ b/src/citra_qt/camera/qt_camera_factory.h
@@ -11,8 +11,8 @@ namespace Camera {
 
 // Base class for camera factories of citra_qt
 class QtCameraFactory : public CameraFactory {
-    std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,
-                                                   int height) const override;
+    std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width, int height,
+                                                   const Service::CAM::Flip& flip) const override;
 };
 
 } // namespace Camera
diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp
index 6c2668df6..5f2137835 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.cpp
+++ b/src/citra_qt/camera/qt_multimedia_camera.cpp
@@ -46,7 +46,8 @@ bool QtCameraSurface::present(const QVideoFrame& frame) {
     return true;
 }
 
-QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name)
+QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name,
+                                       const Service::CAM::Flip& flip)
     : handler(QtMultimediaCameraHandler::GetHandler()) {
     if (handler->thread() == QThread::currentThread()) {
         handler->CreateCamera(camera_name);
@@ -54,6 +55,9 @@ QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name)
         QMetaObject::invokeMethod(handler.get(), "CreateCamera", Qt::BlockingQueuedConnection,
                                   Q_ARG(const std::string&, camera_name));
     }
+    using namespace Service::CAM;
+    flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
 }
 
 QtMultimediaCamera::~QtMultimediaCamera() {
@@ -107,8 +111,8 @@ void QtMultimediaCamera::SetResolution(const Service::CAM::Resolution& resolutio
 
 void QtMultimediaCamera::SetFlip(Service::CAM::Flip flip) {
     using namespace Service::CAM;
-    flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
-    flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
+    flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
 }
 
 void QtMultimediaCamera::SetEffect(Service::CAM::Effect effect) {
@@ -128,8 +132,8 @@ bool QtMultimediaCamera::IsPreviewAvailable() {
 }
 
 std::unique_ptr<CameraInterface> QtMultimediaCameraFactory::Create(
-    const std::string& config) const {
-    return std::make_unique<QtMultimediaCamera>(config);
+    const std::string& config, const Service::CAM::Flip& flip) const {
+    return std::make_unique<QtMultimediaCamera>(config, flip);
 }
 
 std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> QtMultimediaCameraHandler::handlers;
diff --git a/src/citra_qt/camera/qt_multimedia_camera.h b/src/citra_qt/camera/qt_multimedia_camera.h
index 103aff8a0..580834275 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.h
+++ b/src/citra_qt/camera/qt_multimedia_camera.h
@@ -38,7 +38,7 @@ class QtMultimediaCameraHandler;
 /// This class is only an interface. It just calls QtMultimediaCameraHandler.
 class QtMultimediaCamera final : public CameraInterface {
 public:
-    QtMultimediaCamera(const std::string& camera_name);
+    QtMultimediaCamera(const std::string& camera_name, const Service::CAM::Flip& flip);
     ~QtMultimediaCamera();
     void StartCapture() override;
     void StopCapture() override;
@@ -55,11 +55,13 @@ private:
     int width, height;
     bool output_rgb;
     bool flip_horizontal, flip_vertical;
+    bool basic_flip_horizontal, basic_flip_vertical;
 };
 
 class QtMultimediaCameraFactory final : public QtCameraFactory {
 public:
-    std::unique_ptr<CameraInterface> Create(const std::string& config) const override;
+    std::unique_ptr<CameraInterface> Create(const std::string& config,
+                                            const Service::CAM::Flip& flip) const override;
 };
 
 class QtMultimediaCameraHandler final : public QObject {
diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp
index ab0d18308..7e54fad3e 100644
--- a/src/citra_qt/camera/still_image_camera.cpp
+++ b/src/citra_qt/camera/still_image_camera.cpp
@@ -9,7 +9,12 @@
 
 namespace Camera {
 
-StillImageCamera::StillImageCamera(QImage image_) : image(std::move(image_)) {}
+StillImageCamera::StillImageCamera(QImage image_, const Service::CAM::Flip& flip)
+    : image(std::move(image_)) {
+    using namespace Service::CAM;
+    flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
+}
 
 void StillImageCamera::StartCapture() {}
 
@@ -26,8 +31,8 @@ void StillImageCamera::SetResolution(const Service::CAM::Resolution& resolution)
 
 void StillImageCamera::SetFlip(Service::CAM::Flip flip) {
     using namespace Service::CAM;
-    flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
-    flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
+    flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
 }
 
 void StillImageCamera::SetEffect(Service::CAM::Effect effect) {
@@ -58,7 +63,8 @@ const std::string StillImageCameraFactory::getFilePath() {
         .toStdString();
 }
 
-std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::string& config) const {
+std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(
+    const std::string& config, const Service::CAM::Flip& flip) const {
     std::string real_config = config;
     if (config.empty()) {
         real_config = getFilePath();
@@ -67,7 +73,7 @@ std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::stri
     if (image.isNull()) {
         NGLOG_ERROR(Service_CAM, "Couldn't load image \"{}\"", real_config.c_str());
     }
-    return std::make_unique<StillImageCamera>(image);
+    return std::make_unique<StillImageCamera>(image, flip);
 }
 
 } // namespace Camera
diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h
index c54d367e8..e9016981b 100644
--- a/src/citra_qt/camera/still_image_camera.h
+++ b/src/citra_qt/camera/still_image_camera.h
@@ -14,7 +14,7 @@ namespace Camera {
 
 class StillImageCamera final : public CameraInterface {
 public:
-    StillImageCamera(QImage image);
+    StillImageCamera(QImage image, const Service::CAM::Flip& flip);
     void StartCapture() override;
     void StopCapture() override;
     void SetResolution(const Service::CAM::Resolution&) override;
@@ -30,11 +30,13 @@ private:
     int width, height;
     bool output_rgb;
     bool flip_horizontal, flip_vertical;
+    bool basic_flip_horizontal, basic_flip_vertical;
 };
 
 class StillImageCameraFactory final : public QtCameraFactory {
 public:
-    std::unique_ptr<CameraInterface> Create(const std::string& config) const override;
+    std::unique_ptr<CameraInterface> Create(const std::string& config,
+                                            const Service::CAM::Flip& flip) const override;
 
 private:
     static const std::string getFilePath();
diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp
index bdb296659..e5d252c81 100644
--- a/src/citra_qt/configuration/config.cpp
+++ b/src/citra_qt/configuration/config.cpp
@@ -128,14 +128,19 @@ void Config::ReadValues() {
         qt_config->value("camera_outer_right_name", "blank").toString().toStdString();
     Settings::values.camera_config[OuterRightCamera] =
         qt_config->value("camera_outer_right_config", "").toString().toStdString();
+    Settings::values.camera_flip[OuterRightCamera] =
+        qt_config->value("camera_outer_right_flip", "0").toInt();
     Settings::values.camera_name[InnerCamera] =
         qt_config->value("camera_inner_name", "blank").toString().toStdString();
     Settings::values.camera_config[InnerCamera] =
         qt_config->value("camera_inner_config", "").toString().toStdString();
+    Settings::values.camera_flip[InnerCamera] = qt_config->value("camera_inner_flip", "").toInt();
     Settings::values.camera_name[OuterLeftCamera] =
         qt_config->value("camera_outer_left_name", "blank").toString().toStdString();
     Settings::values.camera_config[OuterLeftCamera] =
         qt_config->value("camera_outer_left_config", "").toString().toStdString();
+    Settings::values.camera_flip[OuterLeftCamera] =
+        qt_config->value("camera_outer_left_flip", "").toInt();
     qt_config->endGroup();
 
     qt_config->beginGroup("Data Storage");
@@ -317,14 +322,17 @@ void Config::SaveValues() {
                         QString::fromStdString(Settings::values.camera_name[OuterRightCamera]));
     qt_config->setValue("camera_outer_right_config",
                         QString::fromStdString(Settings::values.camera_config[OuterRightCamera]));
+    qt_config->setValue("camera_outer_right_flip", Settings::values.camera_flip[OuterRightCamera]);
     qt_config->setValue("camera_inner_name",
                         QString::fromStdString(Settings::values.camera_name[InnerCamera]));
     qt_config->setValue("camera_inner_config",
                         QString::fromStdString(Settings::values.camera_config[InnerCamera]));
+    qt_config->setValue("camera_inner_flip", Settings::values.camera_flip[InnerCamera]);
     qt_config->setValue("camera_outer_left_name",
                         QString::fromStdString(Settings::values.camera_name[OuterLeftCamera]));
     qt_config->setValue("camera_outer_left_config",
                         QString::fromStdString(Settings::values.camera_config[OuterLeftCamera]));
+    qt_config->setValue("camera_outer_left_flip", Settings::values.camera_flip[OuterLeftCamera]);
     qt_config->endGroup();
 
     qt_config->beginGroup("Data Storage");
diff --git a/src/citra_qt/configuration/configure_camera.cpp b/src/citra_qt/configuration/configure_camera.cpp
index ca6db4623..e9d964b3a 100644
--- a/src/citra_qt/configuration/configure_camera.cpp
+++ b/src/citra_qt/configuration/configure_camera.cpp
@@ -27,14 +27,7 @@ ConfigureCamera::ConfigureCamera(QWidget* parent)
     // Load settings
     camera_name = Settings::values.camera_name;
     camera_config = Settings::values.camera_config;
-    for (auto&& item : camera_name) {
-        if (item == "opencv") {
-            QMessageBox::critical(this, tr("Error"),
-                                  tr("Sorry, Citra has removed support for OpenCV cameras.\n\nYour "
-                                     "existing OpenCV cameras have been replaced with Blank."));
-            item = "blank";
-        }
-    }
+    camera_flip = Settings::values.camera_flip;
     QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
     for (const QCameraInfo& cameraInfo : cameras) {
         ui->system_camera->addItem(cameraInfo.deviceName());
@@ -98,6 +91,8 @@ void ConfigureCamera::connectEvents() {
     connect(ui->system_camera,
             static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
             [=] { stopPreviewing(); });
+    connect(ui->camera_flip, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+            this, [=] { stopPreviewing(); });
 }
 
 void ConfigureCamera::updateCameraMode() {
@@ -148,6 +143,8 @@ void ConfigureCamera::updateImageSourceUI() {
     }
     ui->system_camera_label->setHidden(image_source != 2);
     ui->system_camera->setHidden(image_source != 2);
+    ui->camera_flip_label->setHidden(image_source == 0);
+    ui->camera_flip->setHidden(image_source == 0);
 }
 
 void ConfigureCamera::recordConfig() {
@@ -166,10 +163,12 @@ void ConfigureCamera::recordConfig() {
     if (current_selected == CameraPosition::RearBoth) {
         camera_name[0] = camera_name[2] = implementation;
         camera_config[0] = camera_config[2] = config;
+        camera_flip[0] = camera_flip[2] = ui->camera_flip->currentIndex();
     } else if (current_selected != CameraPosition::Null) {
         int index = static_cast<int>(current_selected);
         camera_name[index] = implementation;
         camera_config[index] = config;
+        camera_flip[index] = ui->camera_flip->currentIndex();
     }
     current_selected = getCameraSelection();
 }
@@ -187,9 +186,9 @@ void ConfigureCamera::startPreviewing() {
     ui->preview_box->setToolTip(tr("Resolution: ") + QString::number(preview_width) + "*" +
                                 QString::number(preview_height));
     // Load previewing camera
-    previewing_camera =
-        Camera::CreateCameraPreview(camera_name[camera_selection], camera_config[camera_selection],
-                                    preview_width, preview_height);
+    previewing_camera = Camera::CreateCameraPreview(
+        camera_name[camera_selection], camera_config[camera_selection], preview_width,
+        preview_height, static_cast<Service::CAM::Flip>(camera_flip[camera_selection]));
     if (!previewing_camera) {
         stopPreviewing();
         return;
@@ -262,6 +261,7 @@ void ConfigureCamera::setConfiguration() {
     } else {
         ui->camera_file->setText(QString::fromStdString(camera_config[index]));
     }
+    ui->camera_flip->setCurrentIndex(camera_flip[index]);
     updateImageSourceUI();
 }
 
@@ -288,6 +288,7 @@ void ConfigureCamera::applyConfiguration() {
     stopPreviewing();
     Settings::values.camera_name = camera_name;
     Settings::values.camera_config = camera_config;
+    Settings::values.camera_flip = camera_flip;
     Settings::Apply();
 }
 
diff --git a/src/citra_qt/configuration/configure_camera.h b/src/citra_qt/configuration/configure_camera.h
index 5621de7ef..0aa55996e 100644
--- a/src/citra_qt/configuration/configure_camera.h
+++ b/src/citra_qt/configuration/configure_camera.h
@@ -47,6 +47,7 @@ private:
     std::unique_ptr<Ui::ConfigureCamera> ui;
     std::array<std::string, 3> camera_name;
     std::array<std::string, 3> camera_config;
+    std::array<int, 3> camera_flip;
     int timer_id = 0;
     int preview_width = 0;
     int preview_height = 0;
diff --git a/src/citra_qt/configuration/configure_camera.ui b/src/citra_qt/configuration/configure_camera.ui
index cd4d2e108..46c56b266 100644
--- a/src/citra_qt/configuration/configure_camera.ui
+++ b/src/citra_qt/configuration/configure_camera.ui
@@ -1,257 +1,347 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <ui version="4.0">
-  <class>ConfigureCamera</class>
-  <widget class="QWidget" name="ConfigureCamera">
-    <layout class="QVBoxLayout" name="verticalLayout">
+ <class>ConfigureCamera</class>
+ <widget class="QWidget" name="ConfigureCamera">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Camera</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
       <item>
-        <widget class="QGroupBox" name="groupBox">
-          <property name="title">
-            <string>Camera</string>
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <widget class="QLabel" name="camera_selection_label">
+          <property name="toolTip">
+           <string>Select the camera to configure</string>
           </property>
-          <layout class="QVBoxLayout" name="verticalLayout_2">
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout">
-                <item>
-                  <widget class="QLabel" name="camera_selection_label">
-                    <property name="toolTip">
-                      <string>Select the camera to configure</string>
-                    </property>
-                    <property name="text">
-                      <string>Camera to configure:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QComboBox" name="camera_selection">
-                    <property name="toolTip">
-                      <string>Select the camera to configure</string>
-                    </property>
-                    <item>
-                      <property name="text">
-                        <string>Front</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>Rear</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_2">
-                <item>
-                  <widget class="QLabel" name="camera_mode_label">
-                    <property name="toolTip">
-                      <string>Select the camera mode (single or double)</string>
-                    </property>
-                    <property name="text">
-                      <string>Camera mode:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QComboBox" name="camera_mode">
-                    <property name="toolTip">
-                      <string>Select the camera mode (single or double)</string>
-                    </property>
-                    <item>
-                      <property name="text">
-                        <string>Single (2D)</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>Double (3D)</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_3">
-                <item>
-                  <widget class="QLabel" name="camera_position_label">
-                    <property name="toolTip">
-                      <string>Select the position of camera to configure</string>
-                    </property>
-                    <property name="text">
-                      <string>Camera position:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QComboBox" name="camera_position">
-                    <property name="toolTip">
-                      <string>Select the position of camera to configure</string>
-                    </property>
-                    <item>
-                      <property name="text">
-                        <string>Left</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>Right</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-          </layout>
-        </widget>
+          <property name="text">
+           <string>Camera to configure:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="camera_selection">
+          <property name="toolTip">
+           <string>Select the camera to configure</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>Front</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Rear</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
       </item>
       <item>
-        <widget class="QGroupBox" name="configurationBox">
-          <property name="title">
-            <string>Configuration</string>
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <item>
+         <widget class="QLabel" name="camera_mode_label">
+          <property name="toolTip">
+           <string>Select the camera mode (single or double)</string>
           </property>
-          <layout class="QVBoxLayout" name="verticalLayout_configuration">
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_4">
-                <item>
-                  <widget class="QLabel" name="image_source_label">
-                    <property name="toolTip">
-                      <string>Select where the image of the emulated camera comes from. It may be an image or a real camera.</string>
-                    </property>
-                    <property name="text">
-                      <string>Camera Image Source:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QComboBox" name="image_source">
-                    <property name="toolTip">
-                      <string>Select where the image of the emulated camera come from. It may be an image or a real camera.</string>
-                    </property>
-                    <item>
-                      <property name="text">
-                        <string>Blank (blank)</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>Still Image (image)</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>System Camera (qt)</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_6">
-                <item>
-                  <widget class="QLabel" name="camera_file_label">
-                    <property name="frameShape">
-                      <enum>QFrame::NoFrame</enum>
-                    </property>
-                    <property name="text">
-                      <string>File:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QLineEdit" name="camera_file"/>
-                </item>
-                <item>
-                  <widget class="QToolButton" name="toolButton">
-                    <property name="text">
-                      <string>...</string>
-                    </property>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_7">
-                <item>
-                  <widget class="QLabel" name="system_camera_label">
-                    <property name="frameShape">
-                      <enum>QFrame::NoFrame</enum>
-                    </property>
-                    <property name="text">
-                      <string>Camera:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QComboBox" name="system_camera">
-                    <item>
-                      <property name="text">
-                        <string>&lt;Default&gt;</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <widget class="QCheckBox" name="prompt_before_load">
-                <property name="text">
-                  <string>Prompt before load</string>
-                </property>
-              </widget>
-            </item>
-          </layout>
-        </widget>
+          <property name="text">
+           <string>Camera mode:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="camera_mode">
+          <property name="toolTip">
+           <string>Select the camera mode (single or double)</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>Single (2D)</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Double (3D)</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
       </item>
       <item>
-        <widget class="QGroupBox" name="previewBox">
-          <property name="title">
-            <string>Preview</string>
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <item>
+         <widget class="QLabel" name="camera_position_label">
+          <property name="toolTip">
+           <string>Select the position of camera to configure</string>
           </property>
-          <layout class="QVBoxLayout" name="verticalLayout_3">
-            <item>
-              <widget class="QLabel" name="preview_box">
-                <property name="baseSize">
-                  <size>
-                    <width>512</width>
-                    <height>384</height>
-                  </size>
-                </property>
-                <property name="toolTip">
-                  <string>Resolution: 512*384</string>
-                </property>
-                <property name="text">
-                  <string/>
-                </property>
-              </widget>
-            </item>
-            <item>
-              <widget class="QPushButton" name="preview_button">
-                <property name="text">
-                  <string>Click to preview</string>
-                </property>
-              </widget>
-            </item>
-          </layout>
-        </widget>
+          <property name="text">
+           <string>Camera position:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="camera_position">
+          <property name="toolTip">
+           <string>Select the position of camera to configure</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>Left</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Right</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="configurationBox">
+     <property name="title">
+      <string>Configuration</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_configuration">
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_4">
+        <item>
+         <widget class="QLabel" name="image_source_label">
+          <property name="toolTip">
+           <string>Select where the image of the emulated camera comes from. It may be an image or a real camera.</string>
+          </property>
+          <property name="text">
+           <string>Camera Image Source:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="image_source">
+          <property name="toolTip">
+           <string>Select where the image of the emulated camera comes from. It may be an image or a real camera.</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>Blank (blank)</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Still Image (image)</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>System Camera (qt)</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
       </item>
       <item>
-        <spacer>
-          <property name="orientation">
-            <enum>Qt::Vertical</enum>
+       <layout class="QHBoxLayout" name="horizontalLayout_6">
+        <item>
+         <widget class="QLabel" name="camera_file_label">
+          <property name="frameShape">
+           <enum>QFrame::NoFrame</enum>
           </property>
-          <property name="sizeHint" stdset="0">
-            <size>
-              <width>20</width>
-              <height>40</height>
-            </size>
+          <property name="text">
+           <string>File:</string>
           </property>
-        </spacer>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="camera_file"/>
+        </item>
+        <item>
+         <widget class="QToolButton" name="toolButton">
+          <property name="text">
+           <string>...</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
       </item>
-    </layout>
-  </widget>
-  <resources/>
-  <connections/>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_7">
+        <item>
+         <widget class="QLabel" name="system_camera_label">
+          <property name="frameShape">
+           <enum>QFrame::NoFrame</enum>
+          </property>
+          <property name="toolTip">
+           <string>Select the system camera to use</string>
+          </property>
+          <property name="text">
+           <string>Camera:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="system_camera">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>250</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="toolTip">
+           <string>Select the system camera to use</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>&lt;Default&gt;</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_8">
+        <item>
+         <widget class="QLabel" name="camera_flip_label">
+          <property name="frameShape">
+           <enum>QFrame::NoFrame</enum>
+          </property>
+          <property name="toolTip">
+           <string>Select the image flip to apply</string>
+          </property>
+          <property name="text">
+           <string>Flip:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="camera_flip">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>800</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="toolTip">
+           <string>Select the image flip to apply</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>None</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Horizontal</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Vertical</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Reverse</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="prompt_before_load">
+        <property name="toolTip">
+         <string>Select an image file every time before the camera is loaded</string>
+        </property>
+        <property name="text">
+         <string>Prompt before load</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="previewBox">
+     <property name="title">
+      <string>Preview</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_3">
+      <item>
+       <widget class="QLabel" name="preview_box">
+        <property name="baseSize">
+         <size>
+          <width>512</width>
+          <height>384</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Resolution: 512*384</string>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="preview_button">
+        <property name="text">
+         <string>Click to preview</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer>
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
 </ui>
diff --git a/src/core/frontend/camera/factory.cpp b/src/core/frontend/camera/factory.cpp
index f0434cdad..2a871196c 100644
--- a/src/core/frontend/camera/factory.cpp
+++ b/src/core/frontend/camera/factory.cpp
@@ -17,10 +17,11 @@ void RegisterFactory(const std::string& name, std::unique_ptr<CameraFactory> fac
     factories[name] = std::move(factory);
 }
 
-std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config) {
+std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config,
+                                              const Service::CAM::Flip& flip) {
     auto pair = factories.find(name);
     if (pair != factories.end()) {
-        return pair->second->Create(config);
+        return pair->second->Create(config, flip);
     }
 
     if (name != "blank") {
@@ -31,10 +32,10 @@ std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std
 
 std::unique_ptr<CameraInterface> CreateCameraPreview(const std::string& name,
                                                      const std::string& config, int width,
-                                                     int height) {
+                                                     int height, const Service::CAM::Flip& flip) {
     auto pair = factories.find(name);
     if (pair != factories.end()) {
-        return pair->second->CreatePreview(config, width, height);
+        return pair->second->CreatePreview(config, width, height, flip);
     }
 
     if (name != "blank") {
diff --git a/src/core/frontend/camera/factory.h b/src/core/frontend/camera/factory.h
index 840be7022..2c4ab1479 100644
--- a/src/core/frontend/camera/factory.h
+++ b/src/core/frontend/camera/factory.h
@@ -18,22 +18,26 @@ public:
      * Creates a camera object based on the configuration string.
      * @param config Configuration string to create the camera. The implementation can decide the
      *               meaning of this string.
+     * @param flip The image flip to apply
      * @returns a unique_ptr to the created camera object.
      */
-    virtual std::unique_ptr<CameraInterface> Create(const std::string& config) const = 0;
+    virtual std::unique_ptr<CameraInterface> Create(const std::string& config,
+                                                    const Service::CAM::Flip& flip) const = 0;
 
     /**
      * Creates a camera object for preview based on the configuration string.
      * @param config Configuration string to create the camera. The implementation can decide the
      *               meaning of this string.
+     * @param flip The image flip to apply
      * @returns a unique_ptr to the created camera object.
      * Note: The default implementation for this is to call Create(). Derived classes may have other
      *       Implementations. For example, A dialog may be used instead of LOG_ERROR when error
      * occurs.
      */
     virtual std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,
-                                                           int height) const {
-        return Create(config);
+                                                           int height,
+                                                           const Service::CAM::Flip& flip) const {
+        return Create(config, flip);
     }
 };
 
@@ -50,7 +54,8 @@ void RegisterFactory(const std::string& name, std::unique_ptr<CameraFactory> fac
  * @param config Configuration string to create the camera. The meaning of this string is
  *     defined by the factory.
  */
-std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config);
+std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config,
+                                              const Service::CAM::Flip& flip);
 
 /**
  * Creates a camera from the factory for previewing.
@@ -60,6 +65,6 @@ std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std
  */
 std::unique_ptr<CameraInterface> CreateCameraPreview(const std::string& name,
                                                      const std::string& config, int width,
-                                                     int height);
+                                                     int height, const Service::CAM::Flip& flip);
 
 } // namespace Camera
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index 3328dcf8e..78cdb23e8 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -1041,8 +1041,9 @@ void Module::ReloadCameraDevices() {
 }
 
 void Module::LoadCameraImplementation(CameraConfig& camera, int camera_id) {
-    camera.impl = Camera::CreateCamera(Settings::values.camera_name[camera_id],
-                                       Settings::values.camera_config[camera_id]);
+    camera.impl = Camera::CreateCamera(
+        Settings::values.camera_name[camera_id], Settings::values.camera_config[camera_id],
+        static_cast<Service::CAM::Flip>(Settings::values.camera_flip[camera_id]));
     camera.impl->SetFlip(camera.contexts[0].flip);
     camera.impl->SetEffect(camera.contexts[0].effect);
     camera.impl->SetFormat(camera.contexts[0].format);
diff --git a/src/core/settings.h b/src/core/settings.h
index b57a1cbed..5ce4811af 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -140,6 +140,7 @@ struct Values {
     // Camera
     std::array<std::string, Service::CAM::NumCameras> camera_name;
     std::array<std::string, Service::CAM::NumCameras> camera_config;
+    std::array<int, Service::CAM::NumCameras> camera_flip;
 
     // Debugging
     bool use_gdbstub;

From 6e410dcef55d55a40305baa574ace61d5f7fe86b Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Sat, 26 May 2018 11:26:58 +0800
Subject: [PATCH 2/7] camera: refactor (add qt_camera_base)

---
 src/citra_qt/CMakeLists.txt                  |  4 +-
 src/citra_qt/camera/qt_camera_base.cpp       | 57 ++++++++++++++++++++
 src/citra_qt/camera/qt_camera_base.h         | 36 +++++++++++++
 src/citra_qt/camera/qt_camera_factory.cpp    | 24 ---------
 src/citra_qt/camera/qt_camera_factory.h      | 18 -------
 src/citra_qt/camera/qt_multimedia_camera.cpp | 31 ++---------
 src/citra_qt/camera/qt_multimedia_camera.h   | 14 ++---
 src/citra_qt/camera/still_image_camera.cpp   | 32 ++---------
 src/citra_qt/camera/still_image_camera.h     | 14 ++---
 9 files changed, 107 insertions(+), 123 deletions(-)
 create mode 100644 src/citra_qt/camera/qt_camera_base.cpp
 create mode 100644 src/citra_qt/camera/qt_camera_base.h
 delete mode 100644 src/citra_qt/camera/qt_camera_factory.cpp
 delete mode 100644 src/citra_qt/camera/qt_camera_factory.h

diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 4e0fcdbeb..7b0d0eaac 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -13,8 +13,8 @@ add_executable(citra-qt
     camera/camera_util.h
     camera/still_image_camera.cpp
     camera/still_image_camera.h
-    camera/qt_camera_factory.cpp
-    camera/qt_camera_factory.h
+    camera/qt_camera_base.cpp
+    camera/qt_camera_base.h
     camera/qt_multimedia_camera.cpp
     camera/qt_multimedia_camera.h
     citra-qt.rc
diff --git a/src/citra_qt/camera/qt_camera_base.cpp b/src/citra_qt/camera/qt_camera_base.cpp
new file mode 100644
index 000000000..65bf2361c
--- /dev/null
+++ b/src/citra_qt/camera/qt_camera_base.cpp
@@ -0,0 +1,57 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QMessageBox>
+#include "citra_qt/camera/camera_util.h"
+#include "citra_qt/camera/qt_camera_base.h"
+
+namespace Camera {
+
+QtCameraInterface::QtCameraInterface(const Service::CAM::Flip& flip) {
+    using namespace Service::CAM;
+    flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
+}
+
+void QtCameraInterface::SetFormat(Service::CAM::OutputFormat output_format) {
+    output_rgb = output_format == Service::CAM::OutputFormat::RGB565;
+}
+
+void QtCameraInterface::SetResolution(const Service::CAM::Resolution& resolution) {
+    width = resolution.width;
+    height = resolution.height;
+}
+
+void QtCameraInterface::SetFlip(Service::CAM::Flip flip) {
+    using namespace Service::CAM;
+    flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
+}
+
+void QtCameraInterface::SetEffect(Service::CAM::Effect effect) {
+    if (effect != Service::CAM::Effect::None) {
+        NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect));
+    }
+}
+
+std::vector<u16> QtCameraInterface::ReceiveFrame() {
+    return CameraUtil::ProcessImage(QtReceiveFrame(), width, height, output_rgb, flip_horizontal,
+                                    flip_vertical);
+}
+
+std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(
+    const std::string& config, int width, int height, const Service::CAM::Flip& flip) const {
+    std::unique_ptr<CameraInterface> camera = Create(config, flip);
+
+    if (camera->IsPreviewAvailable()) {
+        return camera;
+    }
+    QMessageBox::critical(
+        nullptr, QObject::tr("Error"),
+        (config.empty() ? QObject::tr("Couldn't load the camera")
+                        : QObject::tr("Couldn't load %1").arg(QString::fromStdString(config))));
+    return nullptr;
+}
+
+} // namespace Camera
diff --git a/src/citra_qt/camera/qt_camera_base.h b/src/citra_qt/camera/qt_camera_base.h
new file mode 100644
index 000000000..e66c3bb46
--- /dev/null
+++ b/src/citra_qt/camera/qt_camera_base.h
@@ -0,0 +1,36 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "core/frontend/camera/factory.h"
+
+namespace Camera {
+
+// Base class for camera interfaces of citra_qt
+class QtCameraInterface : public CameraInterface {
+public:
+    QtCameraInterface(const Service::CAM::Flip& flip);
+    void SetResolution(const Service::CAM::Resolution&) override;
+    void SetFlip(Service::CAM::Flip) override;
+    void SetEffect(Service::CAM::Effect) override;
+    void SetFormat(Service::CAM::OutputFormat) override;
+    std::vector<u16> ReceiveFrame() override;
+    virtual QImage QtReceiveFrame() = 0;
+
+private:
+    int width, height;
+    bool output_rgb;
+    bool flip_horizontal, flip_vertical;
+    bool basic_flip_horizontal, basic_flip_vertical;
+};
+
+// Base class for camera factories of citra_qt
+class QtCameraFactory : public CameraFactory {
+    std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width, int height,
+                                                   const Service::CAM::Flip& flip) const override;
+};
+
+} // namespace Camera
diff --git a/src/citra_qt/camera/qt_camera_factory.cpp b/src/citra_qt/camera/qt_camera_factory.cpp
deleted file mode 100644
index 063a600df..000000000
--- a/src/citra_qt/camera/qt_camera_factory.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2018 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <QMessageBox>
-#include "citra_qt/camera/qt_camera_factory.h"
-
-namespace Camera {
-
-std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(
-    const std::string& config, int width, int height, const Service::CAM::Flip& flip) const {
-    std::unique_ptr<CameraInterface> camera = Create(config, flip);
-
-    if (camera->IsPreviewAvailable()) {
-        return camera;
-    }
-    QMessageBox::critical(
-        nullptr, QObject::tr("Error"),
-        (config.empty() ? QObject::tr("Couldn't load the camera")
-                        : QObject::tr("Couldn't load %1").arg(QString::fromStdString(config))));
-    return nullptr;
-}
-
-} // namespace Camera
diff --git a/src/citra_qt/camera/qt_camera_factory.h b/src/citra_qt/camera/qt_camera_factory.h
deleted file mode 100644
index 9e590ca66..000000000
--- a/src/citra_qt/camera/qt_camera_factory.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2018 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <string>
-#include "core/frontend/camera/factory.h"
-
-namespace Camera {
-
-// Base class for camera factories of citra_qt
-class QtCameraFactory : public CameraFactory {
-    std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width, int height,
-                                                   const Service::CAM::Flip& flip) const override;
-};
-
-} // namespace Camera
diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp
index 5f2137835..abf2ff25e 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.cpp
+++ b/src/citra_qt/camera/qt_multimedia_camera.cpp
@@ -48,16 +48,13 @@ bool QtCameraSurface::present(const QVideoFrame& frame) {
 
 QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name,
                                        const Service::CAM::Flip& flip)
-    : handler(QtMultimediaCameraHandler::GetHandler()) {
+    : QtCameraInterface(flip), handler(QtMultimediaCameraHandler::GetHandler()) {
     if (handler->thread() == QThread::currentThread()) {
         handler->CreateCamera(camera_name);
     } else {
         QMetaObject::invokeMethod(handler.get(), "CreateCamera", Qt::BlockingQueuedConnection,
                                   Q_ARG(const std::string&, camera_name));
     }
-    using namespace Service::CAM;
-    flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
-    flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
 }
 
 QtMultimediaCamera::~QtMultimediaCamera() {
@@ -77,10 +74,6 @@ void QtMultimediaCamera::StopCapture() {
     handler->StopCamera();
 }
 
-void QtMultimediaCamera::SetFormat(Service::CAM::OutputFormat output_format) {
-    output_rgb = output_format == Service::CAM::OutputFormat::RGB565;
-}
-
 void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
     const std::array<QCamera::FrameRateRange, 13> FrameRateList = {
         /* Rate_15 */ QCamera::FrameRateRange(15, 15),
@@ -104,27 +97,9 @@ void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
     handler->settings.setMinimumFrameRate(framerate.maximumFrameRate);
 }
 
-void QtMultimediaCamera::SetResolution(const Service::CAM::Resolution& resolution) {
-    width = resolution.width;
-    height = resolution.height;
-}
-
-void QtMultimediaCamera::SetFlip(Service::CAM::Flip flip) {
-    using namespace Service::CAM;
-    flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
-    flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
-}
-
-void QtMultimediaCamera::SetEffect(Service::CAM::Effect effect) {
-    if (effect != Service::CAM::Effect::None) {
-        NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect));
-    }
-}
-
-std::vector<u16> QtMultimediaCamera::ReceiveFrame() {
+QImage QtMultimediaCamera::QtReceiveFrame() {
     QMutexLocker locker(&handler->camera_surface.mutex);
-    return CameraUtil::ProcessImage(handler->camera_surface.current_frame, width, height,
-                                    output_rgb, flip_horizontal, flip_vertical);
+    return handler->camera_surface.current_frame;
 }
 
 bool QtMultimediaCamera::IsPreviewAvailable() {
diff --git a/src/citra_qt/camera/qt_multimedia_camera.h b/src/citra_qt/camera/qt_multimedia_camera.h
index 580834275..41024214c 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.h
+++ b/src/citra_qt/camera/qt_multimedia_camera.h
@@ -13,7 +13,7 @@
 #include <QImage>
 #include <QMutex>
 #include "citra_qt/camera/camera_util.h"
-#include "citra_qt/camera/qt_camera_factory.h"
+#include "citra_qt/camera/qt_camera_base.h"
 #include "core/frontend/camera/interface.h"
 
 class GMainWindow;
@@ -36,26 +36,18 @@ private:
 class QtMultimediaCameraHandler;
 
 /// This class is only an interface. It just calls QtMultimediaCameraHandler.
-class QtMultimediaCamera final : public CameraInterface {
+class QtMultimediaCamera final : public QtCameraInterface {
 public:
     QtMultimediaCamera(const std::string& camera_name, const Service::CAM::Flip& flip);
     ~QtMultimediaCamera();
     void StartCapture() override;
     void StopCapture() override;
-    void SetResolution(const Service::CAM::Resolution&) override;
-    void SetFlip(Service::CAM::Flip) override;
-    void SetEffect(Service::CAM::Effect) override;
-    void SetFormat(Service::CAM::OutputFormat) override;
     void SetFrameRate(Service::CAM::FrameRate frame_rate) override;
-    std::vector<u16> ReceiveFrame() override;
+    QImage QtReceiveFrame() override;
     bool IsPreviewAvailable() override;
 
 private:
     std::shared_ptr<QtMultimediaCameraHandler> handler;
-    int width, height;
-    bool output_rgb;
-    bool flip_horizontal, flip_vertical;
-    bool basic_flip_horizontal, basic_flip_vertical;
 };
 
 class QtMultimediaCameraFactory final : public QtCameraFactory {
diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp
index 7e54fad3e..2b9f4e54b 100644
--- a/src/citra_qt/camera/still_image_camera.cpp
+++ b/src/citra_qt/camera/still_image_camera.cpp
@@ -10,40 +10,14 @@
 namespace Camera {
 
 StillImageCamera::StillImageCamera(QImage image_, const Service::CAM::Flip& flip)
-    : image(std::move(image_)) {
-    using namespace Service::CAM;
-    flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
-    flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
-}
+    : QtCameraInterface(flip), image(std::move(image_)) {}
 
 void StillImageCamera::StartCapture() {}
 
 void StillImageCamera::StopCapture() {}
 
-void StillImageCamera::SetFormat(Service::CAM::OutputFormat output_format) {
-    output_rgb = output_format == Service::CAM::OutputFormat::RGB565;
-}
-
-void StillImageCamera::SetResolution(const Service::CAM::Resolution& resolution) {
-    width = resolution.width;
-    height = resolution.height;
-}
-
-void StillImageCamera::SetFlip(Service::CAM::Flip flip) {
-    using namespace Service::CAM;
-    flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
-    flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
-}
-
-void StillImageCamera::SetEffect(Service::CAM::Effect effect) {
-    if (effect != Service::CAM::Effect::None) {
-        NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect));
-    }
-}
-
-std::vector<u16> StillImageCamera::ReceiveFrame() {
-    return CameraUtil::ProcessImage(image, width, height, output_rgb, flip_horizontal,
-                                    flip_vertical);
+QImage StillImageCamera::QtReceiveFrame() {
+    return image;
 }
 
 bool StillImageCamera::IsPreviewAvailable() {
diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h
index e9016981b..11011622f 100644
--- a/src/citra_qt/camera/still_image_camera.h
+++ b/src/citra_qt/camera/still_image_camera.h
@@ -7,30 +7,22 @@
 #include <vector>
 #include <QImage>
 #include "citra_qt/camera/camera_util.h"
-#include "citra_qt/camera/qt_camera_factory.h"
+#include "citra_qt/camera/qt_camera_base.h"
 #include "core/frontend/camera/interface.h"
 
 namespace Camera {
 
-class StillImageCamera final : public CameraInterface {
+class StillImageCamera final : public QtCameraInterface {
 public:
     StillImageCamera(QImage image, const Service::CAM::Flip& flip);
     void StartCapture() override;
     void StopCapture() override;
-    void SetResolution(const Service::CAM::Resolution&) override;
-    void SetFlip(Service::CAM::Flip) override;
-    void SetEffect(Service::CAM::Effect) override;
-    void SetFormat(Service::CAM::OutputFormat) override;
     void SetFrameRate(Service::CAM::FrameRate frame_rate) override {}
-    std::vector<u16> ReceiveFrame() override;
+    QImage QtReceiveFrame() override;
     bool IsPreviewAvailable() override;
 
 private:
     QImage image;
-    int width, height;
-    bool output_rgb;
-    bool flip_horizontal, flip_vertical;
-    bool basic_flip_horizontal, basic_flip_vertical;
 };
 
 class StillImageCameraFactory final : public QtCameraFactory {

From 3cb91338e966730cbda7940577246b50b35f8259 Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Sat, 26 May 2018 11:32:18 +0800
Subject: [PATCH 3/7] camera: migrate logging macros

---
 src/core/frontend/camera/factory.cpp | 4 ++--
 src/core/frontend/camera/factory.h   | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/core/frontend/camera/factory.cpp b/src/core/frontend/camera/factory.cpp
index 2a871196c..619fa3974 100644
--- a/src/core/frontend/camera/factory.cpp
+++ b/src/core/frontend/camera/factory.cpp
@@ -25,7 +25,7 @@ std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std
     }
 
     if (name != "blank") {
-        LOG_ERROR(Service_CAM, "Unknown camera \"%s\"", name.c_str());
+        NGLOG_ERROR(Service_CAM, "Unknown camera {}", name);
     }
     return std::make_unique<BlankCamera>();
 }
@@ -39,7 +39,7 @@ std::unique_ptr<CameraInterface> CreateCameraPreview(const std::string& name,
     }
 
     if (name != "blank") {
-        LOG_ERROR(Service_CAM, "Unknown camera \"%s\"", name.c_str());
+        NGLOG_ERROR(Service_CAM, "Unknown camera {}", name);
     }
     return std::make_unique<BlankCamera>();
 }
diff --git a/src/core/frontend/camera/factory.h b/src/core/frontend/camera/factory.h
index 2c4ab1479..dc795f0ce 100644
--- a/src/core/frontend/camera/factory.h
+++ b/src/core/frontend/camera/factory.h
@@ -31,7 +31,7 @@ public:
      * @param flip The image flip to apply
      * @returns a unique_ptr to the created camera object.
      * Note: The default implementation for this is to call Create(). Derived classes may have other
-     *       Implementations. For example, A dialog may be used instead of LOG_ERROR when error
+     *       Implementations. For example, A dialog may be used instead of NGLOG_ERROR when error
      * occurs.
      */
     virtual std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,

From 341c07156ac02f213e14c18ca2e28d119df7719f Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Sat, 2 Jun 2018 22:13:54 +0800
Subject: [PATCH 4/7] camera: Single/Double (QtMultimediaCamera)

---
 src/citra_qt/camera/qt_multimedia_camera.cpp | 20 +++++++++++++++++---
 src/citra_qt/camera/qt_multimedia_camera.h   |  4 +++-
 src/citra_qt/camera/still_image_camera.cpp   |  5 ++---
 src/citra_qt/camera/still_image_camera.h     |  2 +-
 4 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp
index abf2ff25e..05bcbd4f8 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.cpp
+++ b/src/citra_qt/camera/qt_multimedia_camera.cpp
@@ -48,7 +48,7 @@ bool QtCameraSurface::present(const QVideoFrame& frame) {
 
 QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name,
                                        const Service::CAM::Flip& flip)
-    : QtCameraInterface(flip), handler(QtMultimediaCameraHandler::GetHandler()) {
+    : QtCameraInterface(flip), handler(QtMultimediaCameraHandler::GetHandler(camera_name)) {
     if (handler->thread() == QThread::currentThread()) {
         handler->CreateCamera(camera_name);
     } else {
@@ -94,7 +94,7 @@ void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
     auto framerate = FrameRateList[static_cast<int>(frame_rate)];
 
     handler->settings.setMinimumFrameRate(framerate.minimumFrameRate);
-    handler->settings.setMinimumFrameRate(framerate.maximumFrameRate);
+    handler->settings.setMaximumFrameRate(framerate.maximumFrameRate);
 }
 
 QImage QtMultimediaCamera::QtReceiveFrame() {
@@ -115,17 +115,25 @@ std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> QtMultimediaCameraHand
 
 std::array<bool, 3> QtMultimediaCameraHandler::status;
 
+std::unordered_map<std::string, std::shared_ptr<QtMultimediaCameraHandler>>
+    QtMultimediaCameraHandler::loaded;
+
 void QtMultimediaCameraHandler::Init() {
     for (auto& handler : handlers) {
         handler = std::make_shared<QtMultimediaCameraHandler>();
     }
 }
 
-std::shared_ptr<QtMultimediaCameraHandler> QtMultimediaCameraHandler::GetHandler() {
+std::shared_ptr<QtMultimediaCameraHandler> QtMultimediaCameraHandler::GetHandler(
+    const std::string& camera_name) {
+    if (loaded.count(camera_name)) {
+        return loaded.at(camera_name);
+    }
     for (int i = 0; i < handlers.size(); i++) {
         if (!status[i]) {
             NGLOG_INFO(Service_CAM, "Successfully got handler {}", i);
             status[i] = true;
+            loaded.emplace(camera_name, handlers[i]);
             return handlers[i];
         }
     }
@@ -140,6 +148,12 @@ void QtMultimediaCameraHandler::ReleaseHandler(
             NGLOG_INFO(Service_CAM, "Successfully released handler {}", i);
             status[i] = false;
             handlers[i]->started = false;
+            for (auto it = loaded.begin(); it != loaded.end(); it++) {
+                if (it->second == handlers[i]) {
+                    loaded.erase(it);
+                    break;
+                }
+            }
             break;
         }
     }
diff --git a/src/citra_qt/camera/qt_multimedia_camera.h b/src/citra_qt/camera/qt_multimedia_camera.h
index 41024214c..e6d7b6b6d 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.h
+++ b/src/citra_qt/camera/qt_multimedia_camera.h
@@ -6,6 +6,7 @@
 
 #include <array>
 #include <string>
+#include <unordered_map>
 #include <vector>
 #include <QAbstractVideoSurface>
 #include <QCamera>
@@ -62,7 +63,7 @@ class QtMultimediaCameraHandler final : public QObject {
 public:
     /// Creates the global handler. Must be called in UI thread.
     static void Init();
-    static std::shared_ptr<QtMultimediaCameraHandler> GetHandler();
+    static std::shared_ptr<QtMultimediaCameraHandler> GetHandler(const std::string& camera_name);
     static void ReleaseHandler(const std::shared_ptr<QtMultimediaCameraHandler>& handler);
 
     /**
@@ -92,6 +93,7 @@ private:
 
     static std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> handlers;
     static std::array<bool, 3> status;
+    static std::unordered_map<std::string, std::shared_ptr<QtMultimediaCameraHandler>> loaded;
 
     friend class QtMultimediaCamera; // For access to camera_surface (and camera)
 };
diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp
index 2b9f4e54b..a166e3336 100644
--- a/src/citra_qt/camera/still_image_camera.cpp
+++ b/src/citra_qt/camera/still_image_camera.cpp
@@ -24,7 +24,7 @@ bool StillImageCamera::IsPreviewAvailable() {
     return !image.isNull();
 }
 
-const std::string StillImageCameraFactory::getFilePath() {
+const std::string StillImageCameraFactory::GetFilePath() {
     QList<QByteArray> types = QImageReader::supportedImageFormats();
     QList<QString> temp_filters;
     for (QByteArray type : types) {
@@ -32,7 +32,6 @@ const std::string StillImageCameraFactory::getFilePath() {
     }
 
     QString filter = QObject::tr("Supported image files (%1)").arg(temp_filters.join(" "));
-
     return QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter)
         .toStdString();
 }
@@ -41,7 +40,7 @@ std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(
     const std::string& config, const Service::CAM::Flip& flip) const {
     std::string real_config = config;
     if (config.empty()) {
-        real_config = getFilePath();
+        real_config = GetFilePath();
     }
     QImage image(QString::fromStdString(real_config));
     if (image.isNull()) {
diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h
index 11011622f..80e43ba17 100644
--- a/src/citra_qt/camera/still_image_camera.h
+++ b/src/citra_qt/camera/still_image_camera.h
@@ -31,7 +31,7 @@ public:
                                             const Service::CAM::Flip& flip) const override;
 
 private:
-    static const std::string getFilePath();
+    static const std::string GetFilePath();
 };
 
 } // namespace Camera

From 7c48160beb8a4b0937dbe39ac2e84bcd422be08e Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Sun, 3 Jun 2018 11:29:46 +0800
Subject: [PATCH 5/7] StillImageCamera: move GetFilePath to UI thread

---
 src/citra_qt/camera/qt_camera_base.cpp       |  5 +++--
 src/citra_qt/camera/qt_camera_base.h         |  2 +-
 src/citra_qt/camera/qt_multimedia_camera.cpp |  4 ++--
 src/citra_qt/camera/qt_multimedia_camera.h   |  2 +-
 src/citra_qt/camera/still_image_camera.cpp   | 16 ++++++++++++----
 src/citra_qt/camera/still_image_camera.h     |  9 +++++----
 src/core/frontend/camera/factory.h           |  4 ++--
 7 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/src/citra_qt/camera/qt_camera_base.cpp b/src/citra_qt/camera/qt_camera_base.cpp
index 65bf2361c..69593ab51 100644
--- a/src/citra_qt/camera/qt_camera_base.cpp
+++ b/src/citra_qt/camera/qt_camera_base.cpp
@@ -40,8 +40,9 @@ std::vector<u16> QtCameraInterface::ReceiveFrame() {
                                     flip_vertical);
 }
 
-std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(
-    const std::string& config, int width, int height, const Service::CAM::Flip& flip) const {
+std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(const std::string& config,
+                                                                int width, int height,
+                                                                const Service::CAM::Flip& flip) {
     std::unique_ptr<CameraInterface> camera = Create(config, flip);
 
     if (camera->IsPreviewAvailable()) {
diff --git a/src/citra_qt/camera/qt_camera_base.h b/src/citra_qt/camera/qt_camera_base.h
index e66c3bb46..6c6095a28 100644
--- a/src/citra_qt/camera/qt_camera_base.h
+++ b/src/citra_qt/camera/qt_camera_base.h
@@ -30,7 +30,7 @@ private:
 // Base class for camera factories of citra_qt
 class QtCameraFactory : public CameraFactory {
     std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width, int height,
-                                                   const Service::CAM::Flip& flip) const override;
+                                                   const Service::CAM::Flip& flip) override;
 };
 
 } // namespace Camera
diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp
index 05bcbd4f8..ad6bad876 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.cpp
+++ b/src/citra_qt/camera/qt_multimedia_camera.cpp
@@ -106,8 +106,8 @@ bool QtMultimediaCamera::IsPreviewAvailable() {
     return handler->CameraAvailable();
 }
 
-std::unique_ptr<CameraInterface> QtMultimediaCameraFactory::Create(
-    const std::string& config, const Service::CAM::Flip& flip) const {
+std::unique_ptr<CameraInterface> QtMultimediaCameraFactory::Create(const std::string& config,
+                                                                   const Service::CAM::Flip& flip) {
     return std::make_unique<QtMultimediaCamera>(config, flip);
 }
 
diff --git a/src/citra_qt/camera/qt_multimedia_camera.h b/src/citra_qt/camera/qt_multimedia_camera.h
index e6d7b6b6d..14242c554 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.h
+++ b/src/citra_qt/camera/qt_multimedia_camera.h
@@ -54,7 +54,7 @@ private:
 class QtMultimediaCameraFactory final : public QtCameraFactory {
 public:
     std::unique_ptr<CameraInterface> Create(const std::string& config,
-                                            const Service::CAM::Flip& flip) const override;
+                                            const Service::CAM::Flip& flip) override;
 };
 
 class QtMultimediaCameraHandler final : public QObject {
diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp
index a166e3336..b466d17df 100644
--- a/src/citra_qt/camera/still_image_camera.cpp
+++ b/src/citra_qt/camera/still_image_camera.cpp
@@ -5,6 +5,7 @@
 #include <QFileDialog>
 #include <QImageReader>
 #include <QMessageBox>
+#include <QThread>
 #include "citra_qt/camera/still_image_camera.h"
 
 namespace Camera {
@@ -24,7 +25,7 @@ bool StillImageCamera::IsPreviewAvailable() {
     return !image.isNull();
 }
 
-const std::string StillImageCameraFactory::GetFilePath() {
+const std::string StillImageCameraFactory::GetFilePath() const {
     QList<QByteArray> types = QImageReader::supportedImageFormats();
     QList<QString> temp_filters;
     for (QByteArray type : types) {
@@ -36,11 +37,18 @@ const std::string StillImageCameraFactory::GetFilePath() {
         .toStdString();
 }
 
-std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(
-    const std::string& config, const Service::CAM::Flip& flip) const {
+std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::string& config,
+                                                                 const Service::CAM::Flip& flip) {
     std::string real_config = config;
     if (config.empty()) {
-        real_config = GetFilePath();
+        // call GetFilePath() in UI thread (note: StillImageCameraFactory itself is initialized in
+        // UI thread, so we can just pass in "this" here)
+        if (thread() == QThread::currentThread()) {
+            real_config = GetFilePath();
+        } else {
+            QMetaObject::invokeMethod(this, "GetFilePath", Qt::BlockingQueuedConnection,
+                                      Q_RETURN_ARG(std::string, real_config));
+        }
     }
     QImage image(QString::fromStdString(real_config));
     if (image.isNull()) {
diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h
index 80e43ba17..ccfc13211 100644
--- a/src/citra_qt/camera/still_image_camera.h
+++ b/src/citra_qt/camera/still_image_camera.h
@@ -25,13 +25,14 @@ private:
     QImage image;
 };
 
-class StillImageCameraFactory final : public QtCameraFactory {
+class StillImageCameraFactory final : public QObject, public QtCameraFactory {
+    Q_OBJECT
+
 public:
     std::unique_ptr<CameraInterface> Create(const std::string& config,
-                                            const Service::CAM::Flip& flip) const override;
+                                            const Service::CAM::Flip& flip) override;
 
-private:
-    static const std::string GetFilePath();
+    Q_INVOKABLE const std::string GetFilePath() const;
 };
 
 } // namespace Camera
diff --git a/src/core/frontend/camera/factory.h b/src/core/frontend/camera/factory.h
index dc795f0ce..0fe9f314f 100644
--- a/src/core/frontend/camera/factory.h
+++ b/src/core/frontend/camera/factory.h
@@ -22,7 +22,7 @@ public:
      * @returns a unique_ptr to the created camera object.
      */
     virtual std::unique_ptr<CameraInterface> Create(const std::string& config,
-                                                    const Service::CAM::Flip& flip) const = 0;
+                                                    const Service::CAM::Flip& flip) = 0;
 
     /**
      * Creates a camera object for preview based on the configuration string.
@@ -36,7 +36,7 @@ public:
      */
     virtual std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,
                                                            int height,
-                                                           const Service::CAM::Flip& flip) const {
+                                                           const Service::CAM::Flip& flip) {
         return Create(config, flip);
     }
 };

From a15e4e80c695e8a5976418c333a99b610f3b6d9d Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Thu, 7 Jun 2018 12:59:18 +0800
Subject: [PATCH 6/7] QtMultimediaCamera: fix invalid settings

---
 src/citra_qt/camera/qt_multimedia_camera.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp
index ad6bad876..76a21453d 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.cpp
+++ b/src/citra_qt/camera/qt_multimedia_camera.cpp
@@ -93,8 +93,10 @@ void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
 
     auto framerate = FrameRateList[static_cast<int>(frame_rate)];
 
-    handler->settings.setMinimumFrameRate(framerate.minimumFrameRate);
-    handler->settings.setMaximumFrameRate(framerate.maximumFrameRate);
+    if (handler->camera->supportedViewfinderFrameRateRanges().contains(framerate)) {
+        handler->settings.setMinimumFrameRate(framerate.minimumFrameRate);
+        handler->settings.setMaximumFrameRate(framerate.maximumFrameRate);
+    }
 }
 
 QImage QtMultimediaCamera::QtReceiveFrame() {
@@ -171,6 +173,7 @@ void QtMultimediaCameraHandler::CreateCamera(const std::string& camera_name) {
     settings.setMinimumFrameRate(30);
     settings.setMaximumFrameRate(30);
     camera->setViewfinder(&camera_surface);
+    camera->load();
 }
 
 void QtMultimediaCameraHandler::StopCamera() {

From 3c554153c78ece768e05b126ff2bc51338f0c08d Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Thu, 7 Jun 2018 14:48:52 +0800
Subject: [PATCH 7/7] StillImageCamera: fix multiple prompt

---
 src/citra_qt/camera/still_image_camera.cpp | 14 ++++++++++++--
 src/citra_qt/camera/still_image_camera.h   |  7 +++++++
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp
index b466d17df..e02d0d0d3 100644
--- a/src/citra_qt/camera/still_image_camera.cpp
+++ b/src/citra_qt/camera/still_image_camera.cpp
@@ -13,6 +13,10 @@ namespace Camera {
 StillImageCamera::StillImageCamera(QImage image_, const Service::CAM::Flip& flip)
     : QtCameraInterface(flip), image(std::move(image_)) {}
 
+StillImageCamera::~StillImageCamera() {
+    StillImageCameraFactory::last_path.clear();
+}
+
 void StillImageCamera::StartCapture() {}
 
 void StillImageCamera::StopCapture() {}
@@ -25,7 +29,12 @@ bool StillImageCamera::IsPreviewAvailable() {
     return !image.isNull();
 }
 
+std::string StillImageCameraFactory::last_path;
+
 const std::string StillImageCameraFactory::GetFilePath() const {
+    if (!last_path.empty()) {
+        return last_path;
+    }
     QList<QByteArray> types = QImageReader::supportedImageFormats();
     QList<QString> temp_filters;
     for (QByteArray type : types) {
@@ -33,8 +42,9 @@ const std::string StillImageCameraFactory::GetFilePath() const {
     }
 
     QString filter = QObject::tr("Supported image files (%1)").arg(temp_filters.join(" "));
-    return QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter)
-        .toStdString();
+    last_path =
+        QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter).toStdString();
+    return last_path;
 }
 
 std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::string& config,
diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h
index ccfc13211..19ca044f0 100644
--- a/src/citra_qt/camera/still_image_camera.h
+++ b/src/citra_qt/camera/still_image_camera.h
@@ -15,6 +15,7 @@ namespace Camera {
 class StillImageCamera final : public QtCameraInterface {
 public:
     StillImageCamera(QImage image, const Service::CAM::Flip& flip);
+    ~StillImageCamera();
     void StartCapture() override;
     void StopCapture() override;
     void SetFrameRate(Service::CAM::FrameRate frame_rate) override {}
@@ -33,6 +34,12 @@ public:
                                             const Service::CAM::Flip& flip) override;
 
     Q_INVOKABLE const std::string GetFilePath() const;
+
+private:
+    /// Record the path chosen to avoid multiple prompt problem
+    static std::string last_path;
+
+    friend class StillImageCamera;
 };
 
 } // namespace Camera