33#include <libavformat/avio.h>
41#include <sys/syscall.h>
45#include <libavutil/display.h>
62#if (defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS))
75 if (videoManagedByClient()) {
86VideoInput::startLoop()
88 if (videoManagedByClient()) {
97VideoInput::switchDevice()
99 if (switchPending_.exchange(
false)) {
101 if (decOpts_.
input.empty()) {
114 if (videoManagedByClient()) {
115 return decOpts_.
width;
117 return decoder_ ? decoder_->getWidth() : 0;
123 if (videoManagedByClient()) {
126 return decoder_ ? decoder_->getHeight() : 0;
132 if (!videoManagedByClient()) {
133 return decoder_->getPixelFormat();
139VideoInput::setRotation(
int angle)
162 JAMI_DBG(
"VideoInput ready to capture");
171 if (paused_ || !decoder_->emitFrame(
false)) {
172 std::this_thread::sleep_for(std::chrono::milliseconds(20));
179 if (
not captureFrame()) {
189 decoder_->setSeekTime(
time);
202VideoInput::captureFrame()
208 switch (decoder_->decode()) {
211 return static_cast<bool>(decoder_);
213 JAMI_ERR() <<
"Failed to decode frame";
223 decoder_->flushBuffers();
229 std::shared_ptr<MediaDemuxer>&
demuxer,
237 [
this](std::shared_ptr<MediaFrame>&&
frame) {
239 std::static_pointer_cast<VideoFrame>(
243 [](
void* data) ->
int {
return not static_cast<VideoInput*
>(data)->isCapturing(); },
this);
252 sink_->setFrameSize(decoder_->getWidth(), decoder_->getHeight());
256 decOpts_.
width = ((decoder_->getWidth() >> 3) << 3);
257 decOpts_.
height = ((decoder_->getHeight() >> 3) << 3);
263 JAMI_WARN(
"Unable to determine pixel format, using default");
267 if (onSuccessfulSetup_)
269 foundDecOpts(decOpts_);
270 futureDecOpts_ = foundDecOpts_.get_future().share();
276 recorderCallback_ =
cb;
278 decoder_->setContextCallback([
this]() {
279 if (recorderCallback_)
285VideoInput::createDecoder()
289 switchPending_ =
false;
291 if (decOpts_.
input.empty()) {
292 foundDecOpts(decOpts_);
296 auto decoder = std::make_unique<MediaDecoder>(
297 [
this](
const std::shared_ptr<MediaFrame>&
frame)
mutable {
305 [](
void* data) ->
int {
return not static_cast<VideoInput*
>(data)->isCapturing(); },
this);
308 if ((decOpts_.
format ==
"x11grab" || decOpts_.
format ==
"dxgigrab" || decOpts_.
format ==
"pipewiregrab") && !decOpts_.
is_area) {
312 while (!ready && !isStopped_) {
317 JAMI_ERR(
"Unable to open input \"%s\" with status %i", decOpts_.
input.c_str(),
ret);
318 foundDecOpts(decOpts_);
326 std::this_thread::sleep_for(std::chrono::milliseconds(10));
337 if (
decoder->setupVideo() < 0) {
338 JAMI_ERR(
"decoder IO startup failed");
339 foundDecOpts(decOpts_);
356 JAMI_WARN(
"Unable to determine pixel format, using default");
360 JAMI_DBG(
"created decoder with video params : size=%dX%d, fps=%lf pix=%s",
365 if (onSuccessfulSetup_)
370 foundDecOpts(decOpts_);
373 sink_->setFrameSize(decoder_->getWidth(), decoder_->getHeight());
375 decoder_->setContextCallback([
this]() {
376 if (recorderCallback_)
382VideoInput::deleteDecoder()
391VideoInput::clearOptions()
394 emulateRate_ =
false;
400 if (videoManagedByClient()) {
407VideoInput::initCamera(
const std::string& device)
410 decOpts_ =
dm->getDeviceParams(device);
416static constexpr unsigned
419 return (
i >>
n) <<
n;
422#if !defined(WIN32) && !defined(__APPLE__)
424VideoInput::initLinuxGrab(
const std::string& display)
436 size_t space = display.find(
' ');
441 if (
winIdPos != std::string::npos) {
447 std::string
fpsStr =
"fps:";
448 if (display.find(
fpsStr) != std::string::npos) {
450 int fps = std::stoi(display.substr(
fpsPos));
454 if (display.find(
"pipewire") != std::string::npos) {
455 std::string
pidStr =
"pid:";
456 std::string
fdStr =
"fd:";
464 int fd = std::stoi(display.substr(
fdPos));
466#ifdef SYS_pidfd_getfd
471 JAMI_ERROR(
"Unable to duplicate PipeWire fd: call to pidfd_open failed (errno = {})",
errno);
476 JAMI_ERROR(
"Unable to duplicate PipeWire fd: call to pidfd_getfd failed (errno = {})",
errno);
480 JAMI_ERROR(
"Unable to duplicate PipeWire fd: pidfd_getfd syscall not available");
486 }
else if (
space != std::string::npos) {
504 emulateRate_ =
false;
512VideoInput::initAVFoundation(
const std::string& display)
518 size_t space = display.find(
' ');
521 decOpts_.
format =
"avfoundation";
523 decOpts_.
name =
"Capture screen 0";
524 decOpts_.
input =
"Capture screen 0";
527 if (
space != std::string::npos) {
528 std::istringstream
iss(display.substr(
space + 1));
544VideoInput::initWindowsGrab(
const std::string& display)
554 size_t space = display.find(
' ');
567 p.input = display.substr(1);
568 p.name = display.substr(1);
570 if (
space != std::string::npos) {
579 size_t plus = display.find(
'+');
591 std::string
fpsStr =
"fps:";
592 if (display.find(
fpsStr) != std::string::npos) {
594 int fps = std::stoi(display.substr(
fpsPos));
599 auto dec = std::make_unique<MediaDecoder>();
600 if (
dec->openInput(p) < 0 ||
dec->setupVideo() < 0)
605 decOpts_.
width =
dec->getStream().width;
606 decOpts_.
height =
dec->getStream().height;
613VideoInput::initFile(std::string path)
619 size_t dot = path.find_last_of(
'.');
620 std::string
ext =
dot == std::string::npos ?
"" : path.substr(
dot + 1);
624 JAMI_ERR(
"file '%s' unavailable\n", path.c_str());
634 auto dec = std::make_unique<MediaDecoder>();
635 if (
dec->openInput(p) < 0 ||
dec->setupVideo() < 0) {
641 decOpts_.
input = path;
642 decOpts_.
name = path;
646 if (
ext ==
"jpeg" ||
ext ==
"jpg" ||
ext ==
"png") {
647 decOpts_.
format =
"image2";
650 JAMI_WARN(
"Guessing file type for %s", path.c_str());
660 switchInput(resource_);
663std::shared_future<DeviceParams>
664VideoInput::switchInput(
const std::string&
resource)
668 if (switchPending_.exchange(
true)) {
669 JAMI_ERR(
"Video switch already requested");
674 decOptsFound_ =
false;
676 std::promise<DeviceParams> p;
677 foundDecOpts_.swap(p);
680 if (resource_.empty()) {
682 futureDecOpts_ = foundDecOpts_.get_future();
684 return futureDecOpts_;
690 const auto pos = resource_.find(
sep);
691 if (
pos == std::string::npos)
694 const auto prefix = resource_.substr(0,
pos);
695 if ((
pos +
sep.size()) >= resource_.size())
704 ready = initCamera(
suffix);
712 ready = initLinuxGrab(
suffix);
720 foundDecOpts(decOpts_);
722 futureDecOpts_ = foundDecOpts_.get_future().share();
724 return futureDecOpts_;
730 if (!videoManagedByClient()) {
732 return decoder_->getStream(
"v:local");
734 auto opts = futureDecOpts_.get();
748 if (
not decOptsFound_) {
749 decOptsFound_ =
true;
750 foundDecOpts_.set_value(
params);
765 sink_->setFrameSize(width, height);
static LIBJAMI_TEST_EXPORT Manager & instance()
bool attach(Observer< std::shared_ptr< MediaFrame > > *o)
bool detach(Observer< std::shared_ptr< MediaFrame > > *o)
bool isStopping() const noexcept
bool isRunning() const noexcept
Naive implementation of the boost::rational interface, described here: http://www....
void av_buffer_unref(AVBufferRef **buf)
#define JAMI_ERROR(formatstr,...)
#define JAMI_LOG(formatstr,...)
static constexpr const char DEVICE_DESKTOP[]
static constexpr unsigned default_grab_width
static constexpr unsigned default_grab_height
static constexpr unsigned round2pow(unsigned i, unsigned n)
void emitSignal(Args... args)
std::vector< unsigned > split_string_to_unsigned(std::string_view str, char delim)
DeviceParams Parameters used by MediaDecoder and MediaEncoder to open a LibAV device/stream.
rational< double > framerate