diff --git a/daemon/src/client/dbus/video_controls-introspec.xml b/daemon/src/client/dbus/video_controls-introspec.xml
index c95cb19af8c7ab3ec6da81281fb66c05ac60bbb1..16cad00957bba2de5bbff4dc4f6c5bf2c2829fb1 100644
--- a/daemon/src/client/dbus/video_controls-introspec.xml
+++ b/daemon/src/client/dbus/video_controls-introspec.xml
@@ -111,7 +111,18 @@
         </method>
 
         <method name="switchInput" tp:name-for-bindings="switchInput">
-            <arg type="s" name="device" direction="in">
+            <arg type="s" name="resource" direction="in">
+                <tp:docstring>
+                    A media resource locator (MRL).
+                    Currently, the following are supported:
+                    <ul>
+                        <li>v4l2://DEVICE</li>
+                        <li>display://DISPLAY_NAME[ WIDTHxHEIGHT]</li>
+                    </ul>
+                </tp:docstring>
+            </arg>
+            <arg type="b" name="switched" direction="out">
+                <tp:docstring>Returns true if the input stream was successfully changed, false otherwise</tp:docstring>
             </arg>
         </method>
 
diff --git a/daemon/src/client/dbus/video_controls.cpp b/daemon/src/client/dbus/video_controls.cpp
index 74efb5005c253e7d1a04e3c17a0c1f4d8402c3f4..29f3930e41aa38ab49feb39176321d780301ba7c 100644
--- a/daemon/src/client/dbus/video_controls.cpp
+++ b/daemon/src/client/dbus/video_controls.cpp
@@ -171,7 +171,7 @@ VideoControls::startCamera()
         return;
     }
 
-    const std::string& device = videoPreference_.getDevice();
+    const std::string device = "v4l2://" + videoPreference_.getDevice();
     videoInputSelector_.reset(new sfl_video::VideoInputSelector(device));
 }
 
@@ -188,15 +188,15 @@ VideoControls::stopCamera()
     }
 }
 
-void
-VideoControls::switchInput(const std::string &device)
+bool
+VideoControls::switchInput(const std::string &resource)
 {
     if (not hasCameraStarted()) {
-        ERROR("Video input selector not initialized");
-        return;
+        ERROR("Input selector not initialized");
+        return false;
     }
-    DEBUG("Switching input device to %s", device.c_str());
-    videoInputSelector_->switchInput(device);
+
+    return videoInputSelector_->switchInput(resource);
 }
 
 std::weak_ptr<sfl_video::VideoFrameActiveWriter>
diff --git a/daemon/src/client/video_controls.h b/daemon/src/client/video_controls.h
index b2e9832d1eb9cef59ecfdacbd546a812f1f6aa09..614078bce9b813d17703239dd0d6489c35abcf0c 100644
--- a/daemon/src/client/video_controls.h
+++ b/daemon/src/client/video_controls.h
@@ -128,7 +128,7 @@ class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor,
 
         void startCamera();
         void stopCamera();
-        void switchInput(const std::string& device);
+        bool switchInput(const std::string& resource);
         bool hasCameraStarted();
         std::weak_ptr<sfl_video::VideoFrameActiveWriter> getVideoCamera();
 };
diff --git a/daemon/src/video/video_input.cpp b/daemon/src/video/video_input.cpp
index b8394a12d18405e02aa7a2b42de7de9b48c9286e..238af2f12696bd621c7f1fd295038d4925027b53 100644
--- a/daemon/src/video/video_input.cpp
+++ b/daemon/src/video/video_input.cpp
@@ -43,27 +43,40 @@
 
 namespace sfl_video {
 
-VideoInput::VideoInput(const std::string& device) :
+static std::string
+extract(const std::map<std::string, std::string>& map,
+        const std::string& key)
+{
+    const auto iter = map.find(key);
+
+    return iter == map.end() ? "" : iter->second;
+}
+
+VideoInput::VideoInput(const std::map<std::string, std::string>& map) :
     VideoGenerator::VideoGenerator()
     , id_(SINK_ID)
     , decoder_(0)
     , sink_()
-    , mirror_(true)
-
-    , input_()
-    , format_()
-    , channel_()
-    , framerate_()
-    , video_size_()
+    , mirror_(map.find("mirror") != map.end())
+    , input_(extract(map, "input"))
+    , format_(extract(map, "format"))
+    , channel_(extract(map, "channel"))
+    , framerate_(extract(map, "framerate"))
+    , video_size_(extract(map, "video_size"))
 {
-    /* TODO better check for the X11 display name */
-    if (device.find(':') != std::string::npos) {
-        DEBUG("Init screen display %s\n", device.c_str());
-        initX11(device);
-    } else {
-        DEBUG("Init camera %s\n", device.c_str());
-        initCamera(device);
-    }
+    DEBUG("initializing video input with: "
+            "mirror: %s, "
+            "input: '%s', "
+            "format: '%s', "
+            "channel: '%s', "
+            "framerate: '%s', "
+            "video_size: '%s'",
+            mirror_ ? "yes" : "no",
+            input_.c_str(),
+            format_.c_str(),
+            channel_.c_str(),
+            framerate_.c_str(),
+            video_size_.c_str());
 
     start();
 }
@@ -74,38 +87,6 @@ VideoInput::~VideoInput()
     join();
 }
 
-void VideoInput::initCamera(std::string device)
-{
-    std::map<std::string, std::string> map;
-
-    map = Manager::instance().getVideoControls()->getSettingsFor(device);
-
-    input_ = map["input"];
-    format_ = "video4linux2";
-    channel_ = map["channel"];
-    framerate_ = map["framerate"];
-    video_size_ = map["video_size"];
-}
-
-void VideoInput::initX11(std::string device)
-{
-    size_t space = device.find(' ');
-
-    if (space != std::string::npos) {
-        video_size_ = device.substr(space + 1);
-        input_ = device.erase(space);
-    } else {
-        input_ = device;
-        video_size_ = "vga";
-    }
-
-    format_ = "x11grab";
-    framerate_ = "25";
-    mirror_ = false;
-
-    DEBUG("X11 display name %s (%s)", input_.c_str(), video_size_.c_str());
-}
-
 bool VideoInput::setup()
 {
     decoder_ = new VideoDecoder();
diff --git a/daemon/src/video/video_input.h b/daemon/src/video/video_input.h
index cb7bea75699a49de42bfcfba8218d3d456054ace..469c3443eea50e0bd740b561e77b9beb61bbca91 100644
--- a/daemon/src/video/video_input.h
+++ b/daemon/src/video/video_input.h
@@ -51,7 +51,7 @@ class VideoInput :
     public SFLThread
 {
 public:
-    VideoInput(const std::string& device);
+    VideoInput(const std::map<std::string, std::string>& map);
     ~VideoInput();
 
     // as VideoGenerator
@@ -73,9 +73,6 @@ private:
     std::string framerate_;
     std::string video_size_;
 
-    void initCamera(std::string device);
-    void initX11(std::string device);
-
     // as SFLThread
     bool setup();
     void process();
diff --git a/daemon/src/video/video_input_selector.cpp b/daemon/src/video/video_input_selector.cpp
index 90fc45efe80c59b950ac289e4ca16207b2a9201e..fd9803a089dc6cd6dbb960ed3ccffe9914f0eaad 100644
--- a/daemon/src/video/video_input_selector.cpp
+++ b/daemon/src/video/video_input_selector.cpp
@@ -40,12 +40,12 @@
 
 namespace sfl_video {
 
-VideoInputSelector::VideoInputSelector(const std::string& device) :
+VideoInputSelector::VideoInputSelector(const std::string& resource) :
     VideoFramePassiveReader::VideoFramePassiveReader()
     , VideoFrameActiveWriter::VideoFrameActiveWriter()
-    , currentInput_()
+    , currentInput_(nullptr)
 {
-	openInput(device);
+	switchInput(resource);
 }
 
 VideoInputSelector::~VideoInputSelector()
@@ -60,25 +60,83 @@ VideoInputSelector::update(Observable<std::shared_ptr<sfl_video::VideoFrame>>* /
 }
 
 void
-VideoInputSelector::openInput(const std::string& device)
+VideoInputSelector::openInput(const std::map<std::string, std::string>& map)
 {
-	currentInput_ = new VideoInput(device);
+	currentInput_ = new VideoInput(map);
 	currentInput_->attach(this);
 }
 
 void
-VideoInputSelector::closeInput(void)
+VideoInputSelector::closeInput()
 {
-	currentInput_->detach(this);
-	delete currentInput_;
+    if (currentInput_ == nullptr)
+        return;
+
+    currentInput_->detach(this);
+    delete currentInput_;
+    currentInput_ = nullptr;
 }
 
-void
-VideoInputSelector::switchInput(const std::string& device)
+static std::map<std::string, std::string>
+initCamera(const std::string& device)
 {
-	DEBUG("Switching input to %s", device.c_str());
-	closeInput();
-	openInput(device);
+    std::map<std::string, std::string> map =
+        Manager::instance().getVideoControls()->getSettingsFor(device);
+
+    map["format"] = "video4linux2";
+    map["mirror"] = "true"; // only the key matters
+
+    return map;
+}
+
+static std::map<std::string, std::string>
+initX11(std::string display)
+{
+    std::map<std::string, std::string> map;
+    size_t space = display.find(' ');
+
+    if (space != std::string::npos) {
+        map["video_size"] = display.substr(space + 1);
+        map["input"] = display.erase(space);
+    } else {
+        map["input"] = display;
+        map["video_size"] = "vga";
+    }
+
+    map["format"] = "x11grab";
+    map["framerate"] = "25";
+
+    return map;
+}
+
+bool
+VideoInputSelector::switchInput(const std::string& resource)
+{
+    DEBUG("Switching input to MRL '%s'", resource.c_str());
+
+    // Supported MRL schemes
+    static const std::string v4l2("v4l2://");
+    static const std::string display("display://");
+
+    std::map<std::string, std::string> map;
+
+    /* Video4Linux2 */
+    if (resource.compare(0, v4l2.size(), v4l2) == 0)
+        map = initCamera(resource.substr(v4l2.size()));
+
+    /* X11 display name */
+    else if (resource.compare(0, display.size(), display) == 0)
+        map = initX11(resource.substr(display.size()));
+
+    /* Unsupported MRL or failed initialization */
+    if (map.empty()) {
+        ERROR("Failed to init input map for MRL '%s'\n", resource.c_str());
+        return false;
+    }
+
+    closeInput();
+    openInput(map);
+    return true;
 }
 
 } // end namespace sfl_video
diff --git a/daemon/src/video/video_input_selector.h b/daemon/src/video/video_input_selector.h
index 87563518d5140979f66e3f40d21a65168432fdc3..393c4a86ea2163694f79786c3870de8d7c1c7cfb 100644
--- a/daemon/src/video/video_input_selector.h
+++ b/daemon/src/video/video_input_selector.h
@@ -44,18 +44,18 @@ class VideoInputSelector :
     public VideoFrameActiveWriter
 {
 public:
-    VideoInputSelector(const std::string& device);
+    VideoInputSelector(const std::string& resource);
     ~VideoInputSelector();
 
     /* as of VideoFrameActiveReader (Observer) */
     void update(Observable<std::shared_ptr<sfl_video::VideoFrame>>*, std::shared_ptr<VideoFrame>&);
 
-    void switchInput(const std::string& device);
+    bool switchInput(const std::string& resource);
 
 private:
     NON_COPYABLE(VideoInputSelector);
 
-    void openInput(const std::string& device);
+    void openInput(const std::map<std::string, std::string>& map);
     void closeInput(void);
 
     VideoInput *currentInput_;