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_;