From 52bb4c5d186ad5ba5940ba6efe4a6e1cf34b9c76 Mon Sep 17 00:00:00 2001 From: Vivien Didelot <vivien.didelot@savoirfairelinux.com> Date: Fri, 18 Apr 2014 01:05:31 -0400 Subject: [PATCH] daemon: (VideoInputSelector) use MRL This patch moves the video source parsing logic from the VideoInput class to the VideoInputSelector. Thus the VideoInput class is simpler and only deals with libav input. The VideoInputSelector class now takes as its switchInput() parameter (and thus the constructor parameter) a media resource locator (MRL) as commonly used by video players such as VLC. Currently, "v4l2://" and "display://" schemes are supported. The DBus API and documentation are updated accordingly. In the meantime, this fixes the confusion (and thus a bug) with a camera having a ':' char in its name, which was resulting in using the x11grab format. Refs: #45480 --- .../client/dbus/video_controls-introspec.xml | 13 ++- daemon/src/client/dbus/video_controls.cpp | 14 ++-- daemon/src/client/video_controls.h | 2 +- daemon/src/video/video_input.cpp | 77 +++++++---------- daemon/src/video/video_input.h | 5 +- daemon/src/video/video_input_selector.cpp | 84 ++++++++++++++++--- daemon/src/video/video_input_selector.h | 6 +- 7 files changed, 124 insertions(+), 77 deletions(-) diff --git a/daemon/src/client/dbus/video_controls-introspec.xml b/daemon/src/client/dbus/video_controls-introspec.xml index c95cb19af8..16cad00957 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 74efb5005c..29f3930e41 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 b2e9832d1e..614078bce9 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 b8394a12d1..238af2f126 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 cb7bea7569..469c3443ee 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 90fc45efe8..fd9803a089 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 87563518d5..393c4a86ea 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_; -- GitLab