Skip to content
Snippets Groups Projects
Commit 52bb4c5d authored by Vivien Didelot's avatar Vivien Didelot
Browse files

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
parent 75115561
Branches
No related tags found
No related merge requests found
...@@ -111,7 +111,18 @@ ...@@ -111,7 +111,18 @@
</method> </method>
<method name="switchInput" tp:name-for-bindings="switchInput"> <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> </arg>
</method> </method>
......
...@@ -171,7 +171,7 @@ VideoControls::startCamera() ...@@ -171,7 +171,7 @@ VideoControls::startCamera()
return; return;
} }
const std::string& device = videoPreference_.getDevice(); const std::string device = "v4l2://" + videoPreference_.getDevice();
videoInputSelector_.reset(new sfl_video::VideoInputSelector(device)); videoInputSelector_.reset(new sfl_video::VideoInputSelector(device));
} }
...@@ -188,15 +188,15 @@ VideoControls::stopCamera() ...@@ -188,15 +188,15 @@ VideoControls::stopCamera()
} }
} }
void bool
VideoControls::switchInput(const std::string &device) VideoControls::switchInput(const std::string &resource)
{ {
if (not hasCameraStarted()) { if (not hasCameraStarted()) {
ERROR("Video input selector not initialized"); ERROR("Input selector not initialized");
return; return false;
} }
DEBUG("Switching input device to %s", device.c_str());
videoInputSelector_->switchInput(device); return videoInputSelector_->switchInput(resource);
} }
std::weak_ptr<sfl_video::VideoFrameActiveWriter> std::weak_ptr<sfl_video::VideoFrameActiveWriter>
......
...@@ -128,7 +128,7 @@ class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor, ...@@ -128,7 +128,7 @@ class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor,
void startCamera(); void startCamera();
void stopCamera(); void stopCamera();
void switchInput(const std::string& device); bool switchInput(const std::string& resource);
bool hasCameraStarted(); bool hasCameraStarted();
std::weak_ptr<sfl_video::VideoFrameActiveWriter> getVideoCamera(); std::weak_ptr<sfl_video::VideoFrameActiveWriter> getVideoCamera();
}; };
......
...@@ -43,27 +43,40 @@ ...@@ -43,27 +43,40 @@
namespace sfl_video { 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() VideoGenerator::VideoGenerator()
, id_(SINK_ID) , id_(SINK_ID)
, decoder_(0) , decoder_(0)
, sink_() , sink_()
, mirror_(true) , mirror_(map.find("mirror") != map.end())
, input_(extract(map, "input"))
, input_() , format_(extract(map, "format"))
, format_() , channel_(extract(map, "channel"))
, channel_() , framerate_(extract(map, "framerate"))
, framerate_() , video_size_(extract(map, "video_size"))
, video_size_()
{ {
/* TODO better check for the X11 display name */ DEBUG("initializing video input with: "
if (device.find(':') != std::string::npos) { "mirror: %s, "
DEBUG("Init screen display %s\n", device.c_str()); "input: '%s', "
initX11(device); "format: '%s', "
} else { "channel: '%s', "
DEBUG("Init camera %s\n", device.c_str()); "framerate: '%s', "
initCamera(device); "video_size: '%s'",
} mirror_ ? "yes" : "no",
input_.c_str(),
format_.c_str(),
channel_.c_str(),
framerate_.c_str(),
video_size_.c_str());
start(); start();
} }
...@@ -74,38 +87,6 @@ VideoInput::~VideoInput() ...@@ -74,38 +87,6 @@ VideoInput::~VideoInput()
join(); 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() bool VideoInput::setup()
{ {
decoder_ = new VideoDecoder(); decoder_ = new VideoDecoder();
......
...@@ -51,7 +51,7 @@ class VideoInput : ...@@ -51,7 +51,7 @@ class VideoInput :
public SFLThread public SFLThread
{ {
public: public:
VideoInput(const std::string& device); VideoInput(const std::map<std::string, std::string>& map);
~VideoInput(); ~VideoInput();
// as VideoGenerator // as VideoGenerator
...@@ -73,9 +73,6 @@ private: ...@@ -73,9 +73,6 @@ private:
std::string framerate_; std::string framerate_;
std::string video_size_; std::string video_size_;
void initCamera(std::string device);
void initX11(std::string device);
// as SFLThread // as SFLThread
bool setup(); bool setup();
void process(); void process();
......
...@@ -40,12 +40,12 @@ ...@@ -40,12 +40,12 @@
namespace sfl_video { namespace sfl_video {
VideoInputSelector::VideoInputSelector(const std::string& device) : VideoInputSelector::VideoInputSelector(const std::string& resource) :
VideoFramePassiveReader::VideoFramePassiveReader() VideoFramePassiveReader::VideoFramePassiveReader()
, VideoFrameActiveWriter::VideoFrameActiveWriter() , VideoFrameActiveWriter::VideoFrameActiveWriter()
, currentInput_() , currentInput_(nullptr)
{ {
openInput(device); switchInput(resource);
} }
VideoInputSelector::~VideoInputSelector() VideoInputSelector::~VideoInputSelector()
...@@ -60,25 +60,83 @@ VideoInputSelector::update(Observable<std::shared_ptr<sfl_video::VideoFrame>>* / ...@@ -60,25 +60,83 @@ VideoInputSelector::update(Observable<std::shared_ptr<sfl_video::VideoFrame>>* /
} }
void 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); currentInput_->attach(this);
} }
void void
VideoInputSelector::closeInput(void) VideoInputSelector::closeInput()
{ {
if (currentInput_ == nullptr)
return;
currentInput_->detach(this); currentInput_->detach(this);
delete currentInput_; delete currentInput_;
currentInput_ = nullptr;
} }
void static std::map<std::string, std::string>
VideoInputSelector::switchInput(const std::string& device) initCamera(const std::string& device)
{ {
DEBUG("Switching input to %s", device.c_str()); 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(); closeInput();
openInput(device); openInput(map);
return true;
} }
} // end namespace sfl_video } // end namespace sfl_video
...@@ -44,18 +44,18 @@ class VideoInputSelector : ...@@ -44,18 +44,18 @@ class VideoInputSelector :
public VideoFrameActiveWriter public VideoFrameActiveWriter
{ {
public: public:
VideoInputSelector(const std::string& device); VideoInputSelector(const std::string& resource);
~VideoInputSelector(); ~VideoInputSelector();
/* as of VideoFrameActiveReader (Observer) */ /* as of VideoFrameActiveReader (Observer) */
void update(Observable<std::shared_ptr<sfl_video::VideoFrame>>*, std::shared_ptr<VideoFrame>&); 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: private:
NON_COPYABLE(VideoInputSelector); NON_COPYABLE(VideoInputSelector);
void openInput(const std::string& device); void openInput(const std::map<std::string, std::string>& map);
void closeInput(void); void closeInput(void);
VideoInput *currentInput_; VideoInput *currentInput_;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment