Commit f760ff44 authored by Guillaume Roguez's avatar Guillaume Roguez
Browse files

#29564, #29818: new video node based system.

Fix bug #29818.
Note: non-conference mode has been tested and works.
Conference mode may works, but some issues have been detected.
parent 77b017ca
...@@ -182,7 +182,7 @@ VideoControls::stopPreview() ...@@ -182,7 +182,7 @@ VideoControls::stopPreview()
} }
} }
sfl_video::VideoSource* VideoControls::getVideoPreview() sfl_video::VideoFrameActiveWriter* VideoControls::getVideoPreview()
{ {
return videoPreview_.get(); return videoPreview_.get();
} }
......
...@@ -57,16 +57,13 @@ ...@@ -57,16 +57,13 @@
#include <memory> // for shared_ptr #include <memory> // for shared_ptr
#include "video/video_preferences.h" #include "video/video_preferences.h"
#include "video/video_base.h"
namespace sfl_video {
class VideoSource;
}
class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor, class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor,
public DBus::IntrospectableAdaptor, public DBus::IntrospectableAdaptor,
public DBus::ObjectAdaptor { public DBus::ObjectAdaptor {
private: private:
std::shared_ptr<sfl_video::VideoSource> videoPreview_; std::unique_ptr<sfl_video::VideoFrameActiveWriter> videoPreview_;
VideoPreference videoPreference_; VideoPreference videoPreference_;
public: public:
...@@ -126,7 +123,7 @@ class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor, ...@@ -126,7 +123,7 @@ class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor,
void startPreview(); void startPreview();
void stopPreview(); void stopPreview();
bool hasPreviewStarted(); bool hasPreviewStarted();
sfl_video::VideoSource* getVideoPreview(); sfl_video::VideoFrameActiveWriter* getVideoPreview();
}; };
#endif // VIDEO_CONTROLS_H_ #endif // VIDEO_CONTROLS_H_
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
#include "video/video_camera.h" #include "video/video_camera.h"
#endif #endif
#include "logger.h"
Conference::Conference() Conference::Conference()
: id_(Manager::instance().getNewCallID()) : id_(Manager::instance().getNewCallID())
...@@ -51,15 +53,6 @@ Conference::Conference() ...@@ -51,15 +53,6 @@ Conference::Conference()
#endif #endif
{ {
Recordable::initRecFilename(id_); Recordable::initRecFilename(id_);
#ifdef SFL_VIDEO
sfl_video::VideoCamera *camera = static_cast<sfl_video::VideoCamera*>(Manager::instance().getVideoControls()->getVideoPreview());
if (camera) {
videoMixer_.addSource(camera);
camera->setMixer(&videoMixer_);
}
#endif
} }
Conference::ConferenceState Conference::getState() const Conference::ConferenceState Conference::getState() const
...@@ -84,11 +77,16 @@ void Conference::remove(const std::string &participant_id) ...@@ -84,11 +77,16 @@ void Conference::remove(const std::string &participant_id)
void Conference::bindParticipant(const std::string &participant_id) void Conference::bindParticipant(const std::string &participant_id)
{ {
for (const auto &item : participants_) auto mainBuffer = Manager::instance().getMainBuffer();
for (const auto &item : participants_) {
if (participant_id != item) if (participant_id != item)
Manager::instance().getMainBuffer().bindCallID(participant_id, item); mainBuffer.bindCallID(participant_id, item);
mainBuffer.flush(item);
}
Manager::instance().getMainBuffer().bindCallID(participant_id, MainBuffer::DEFAULT_ID); mainBuffer.bindCallID(participant_id, MainBuffer::DEFAULT_ID);
mainBuffer.flush(MainBuffer::DEFAULT_ID);
} }
std::string Conference::getStateStr() const std::string Conference::getStateStr() const
......
...@@ -930,12 +930,15 @@ ManagerImpl::addParticipant(const std::string& callId, const std::string& confer ...@@ -930,12 +930,15 @@ ManagerImpl::addParticipant(const std::string& callId, const std::string& confer
std::string callState(callDetails.find("CALL_STATE")->second); std::string callState(callDetails.find("CALL_STATE")->second);
if (callState == "HOLD") { if (callState == "HOLD") {
ERROR("foo1: %s", callId.c_str());
conf->bindParticipant(callId); conf->bindParticipant(callId);
offHoldCall(callId); offHoldCall(callId);
} else if (callState == "INCOMING") { } else if (callState == "INCOMING") {
ERROR("foo2: %s", callId.c_str());
conf->bindParticipant(callId); conf->bindParticipant(callId);
answerCall(callId); answerCall(callId);
} else if (callState == "CURRENT") } else if (callState == "CURRENT")
ERROR("foo3: %s", callId.c_str());
conf->bindParticipant(callId); conf->bindParticipant(callId);
ParticipantSet participants(conf->getParticipantList()); ParticipantSet participants(conf->getParticipantList());
...@@ -943,13 +946,6 @@ ManagerImpl::addParticipant(const std::string& callId, const std::string& confer ...@@ -943,13 +946,6 @@ ManagerImpl::addParticipant(const std::string& callId, const std::string& confer
if (participants.empty()) if (participants.empty())
ERROR("Participant list is empty for this conference"); ERROR("Participant list is empty for this conference");
// reset ring buffer for all conference participant
// flush conference participants only
for (const auto &p : participants)
getMainBuffer().flush(p);
getMainBuffer().flush(MainBuffer::DEFAULT_ID);
// Connect stream // Connect stream
addStream(callId); addStream(callId);
return true; return true;
...@@ -1349,15 +1345,8 @@ void ManagerImpl::addStream(const std::string& call_id) ...@@ -1349,15 +1345,8 @@ void ManagerImpl::addStream(const std::string& call_id)
if (iter != conferenceMap_.end() and iter->second) { if (iter != conferenceMap_.end() and iter->second) {
Conference* conf = iter->second; Conference* conf = iter->second;
ERROR("bar: %s", call_id.c_str());
conf->bindParticipant(call_id); conf->bindParticipant(call_id);
ParticipantSet participants(conf->getParticipantList());
// reset ring buffer for all conference participant
for (const auto &participant : participants)
getMainBuffer().flush(participant);
getMainBuffer().flush(MainBuffer::DEFAULT_ID);
} }
} else { } else {
......
...@@ -37,10 +37,12 @@ ...@@ -37,10 +37,12 @@
#include "config.h" #include "config.h"
#endif #endif
#include "video_scaler.h"
#include "shm_sink.h" #include "shm_sink.h"
#include "shm_header.h" #include "shm_header.h"
#include "logger.h" #include "logger.h"
#include "video_provider.h"
#include <sys/mman.h> #include <sys/mman.h>
#include <fcntl.h> #include <fcntl.h>
#include <cstdio> #include <cstdio>
...@@ -49,13 +51,15 @@ ...@@ -49,13 +51,15 @@
#include <cerrno> #include <cerrno>
#include <cstring> #include <cstring>
namespace sfl_video {
SHMSink::SHMSink(const std::string &shm_name) : SHMSink::SHMSink(const std::string &shm_name) :
shm_name_(shm_name), shm_name_(shm_name)
fd_(-1), , fd_(-1)
shm_area_(static_cast<SHMHeader*>(MAP_FAILED)), , shm_area_(static_cast<SHMHeader*>(MAP_FAILED))
shm_area_len_(0), , shm_area_len_(0)
opened_name_() , opened_name_()
{} {}
SHMSink::~SHMSink() SHMSink::~SHMSink()
{ {
...@@ -187,8 +191,14 @@ void SHMSink::render(const std::vector<unsigned char> &data) ...@@ -187,8 +191,14 @@ void SHMSink::render(const std::vector<unsigned char> &data)
shm_unlock(); shm_unlock();
} }
void SHMSink::render_callback(sfl_video::VideoProvider &provider, size_t bytes) void SHMSink::render_frame(VideoFrame& src)
{ {
VideoFrame dst;
VideoScaler scaler;
dst.setGeometry(src.getWidth(), src.getHeight(), VIDEO_PIXFMT_BGRA);
size_t bytes = dst.getSize();
shm_lock(); shm_lock();
if (!resize_area(sizeof(SHMHeader) + bytes)) { if (!resize_area(sizeof(SHMHeader) + bytes)) {
...@@ -196,19 +206,38 @@ void SHMSink::render_callback(sfl_video::VideoProvider &provider, size_t bytes) ...@@ -196,19 +206,38 @@ void SHMSink::render_callback(sfl_video::VideoProvider &provider, size_t bytes)
return; return;
} }
provider.fillBuffer(static_cast<void*>(shm_area_->data)); dst.setDestination(shm_area_->data);
scaler.scale(src, dst);
shm_area_->buffer_size = bytes; shm_area_->buffer_size = bytes;
shm_area_->buffer_gen++; shm_area_->buffer_gen++;
sem_post(&shm_area_->notification); sem_post(&shm_area_->notification);
shm_unlock(); shm_unlock();
} }
void SHMSink::shm_lock() void SHMSink::render_callback(VideoProvider &provider, size_t bytes)
{ {
sem_wait(&shm_area_->mutex); shm_lock();
if (!resize_area(sizeof(SHMHeader) + bytes)) {
ERROR("Could not resize area");
return;
}
provider.fillBuffer(static_cast<void*>(shm_area_->data));
shm_area_->buffer_size = bytes;
shm_area_->buffer_gen++;
sem_post(&shm_area_->notification);
shm_unlock();
} }
void SHMSink::shm_lock()
{ sem_wait(&shm_area_->mutex); }
void SHMSink::shm_unlock() void SHMSink::shm_unlock()
{ { sem_post(&shm_area_->mutex); }
sem_post(&shm_area_->mutex);
void SHMSink::update(Observable<VideoFrameSP>* obs, VideoFrameSP& frame_p)
{ render_frame(*frame_p); }
} }
...@@ -36,39 +36,48 @@ ...@@ -36,39 +36,48 @@
#ifndef SHM_SINK_H_ #ifndef SHM_SINK_H_
#define SHM_SINK_H_ #define SHM_SINK_H_
#include "noncopyable.h"
#include "video_provider.h"
#include "video_base.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include "noncopyable.h"
class SHMHeader; class SHMHeader;
namespace sfl_video { namespace sfl_video {
class VideoProvider;
}
class SHMSink { class SHMSink : public VideoFramePassiveReader
public: {
SHMSink(const std::string &shm_name = ""); public:
std::string openedName() const { return opened_name_; } SHMSink(const std::string &shm_name = "");
~SHMSink(); std::string openedName() const { return opened_name_; }
~SHMSink();
bool start();
bool stop();
bool start(); bool resize_area(size_t desired_length);
bool stop();
bool resize_area(size_t desired_length); void render(const std::vector<unsigned char> &data);
void render_frame(VideoFrame& src);
void render_callback(VideoProvider &provider, size_t bytes);
void render(const std::vector<unsigned char> &data); // as VideoFramePassiveReader
void render_callback(sfl_video::VideoProvider &provider, size_t bytes); void update(Observable<VideoFrameSP>*, VideoFrameSP&);
private: private:
NON_COPYABLE(SHMSink); NON_COPYABLE(SHMSink);
void shm_lock(); void shm_lock();
void shm_unlock(); void shm_unlock();
std::string shm_name_; std::string shm_name_;
int fd_; int fd_;
SHMHeader *shm_area_; SHMHeader *shm_area_;
size_t shm_area_len_; size_t shm_area_len_;
std::string opened_name_; std::string opened_name_;
}; };
}
#endif // SHM_SINK_H_ #endif // SHM_SINK_H_
...@@ -222,8 +222,10 @@ int SocketPair::readCallback(void *opaque, uint8_t *buf, int buf_size) ...@@ -222,8 +222,10 @@ int SocketPair::readCallback(void *opaque, uint8_t *buf, int buf_size)
{context->rtcpHandle_, POLLIN, 0}}; {context->rtcpHandle_, POLLIN, 0}};
for(;;) { for(;;) {
if (context->interrupted_) if (context->interrupted_) {
ERROR("interrupted");
return -EINTR; return -EINTR;
}
/* build fdset to listen to RTP and RTCP packets */ /* build fdset to listen to RTP and RTCP packets */
n = poll(p, 2, 100); n = poll(p, 2, 100);
......
...@@ -82,12 +82,14 @@ VideoFrame::~VideoFrame() ...@@ -82,12 +82,14 @@ VideoFrame::~VideoFrame()
avcodec_free_frame(&frame_); avcodec_free_frame(&frame_);
} }
int VideoFrame::getFormat() const int VideoFrame::getPixelFormat() const
{ { return libav_utils::sfl_pixel_format(frame_->format); }
return libav_utils::sfl_pixel_format(frame_->format);
} int VideoFrame::getWidth() const
int VideoFrame::getWidth() const { return frame_->width; } { return frame_->width; }
int VideoFrame::getHeight() const { return frame_->height; }
int VideoFrame::getHeight() const
{ return frame_->height; }
bool VideoFrame::allocBuffer(int width, int height, int pix_fmt) bool VideoFrame::allocBuffer(int width, int height, int pix_fmt)
{ {
...@@ -207,70 +209,24 @@ void VideoFrame::test() ...@@ -207,70 +209,24 @@ void VideoFrame::test()
/*=== VideoGenerator =========================================================*/ /*=== VideoGenerator =========================================================*/
VideoGenerator::VideoGenerator() : VideoFrame& VideoGenerator::getNewFrame()
VideoSource::VideoSource()
, mutex_()
, condition_()
, writableFrame_()
, lastFrame_()
{
pthread_mutex_init(&mutex_, NULL);
pthread_cond_init(&condition_, NULL);
}
VideoGenerator::~VideoGenerator()
{ {
pthread_cond_destroy(&condition_); if (writableFrame_)
pthread_mutex_destroy(&mutex_); writableFrame_->setdefaults();
else
writableFrame_.reset(new VideoFrame());
return *writableFrame_.get();
} }
void VideoGenerator::publishFrame() void VideoGenerator::publishFrame()
{ {
pthread_mutex_lock(&mutex_); lastFrame_ = std::move(writableFrame_);
{ notify(std::ref(lastFrame_));
lastFrame_ = std::move(writableFrame_); // we owns it now
pthread_cond_signal(&condition_);
}
pthread_mutex_unlock(&mutex_);
} }
std::shared_ptr<VideoFrame> VideoGenerator::waitNewFrame() VideoFrameSP VideoGenerator::obtainLastFrame()
{ {
pthread_mutex_lock(&mutex_); return lastFrame_;
pthread_cond_wait(&condition_, &mutex_);
pthread_mutex_unlock(&mutex_);
return obtainLastFrame();
}
std::shared_ptr<VideoFrame> VideoGenerator::obtainLastFrame()
{
std::shared_ptr<VideoFrame> frame;
pthread_mutex_lock(&mutex_);
frame = lastFrame_;
pthread_mutex_unlock(&mutex_);
return frame;
}
VideoFrame& VideoGenerator::getNewFrame()
{
VideoFrame* frame;
pthread_mutex_lock(&mutex_);
{
if (writableFrame_) {
frame = writableFrame_.get();
frame->setdefaults();
} else {
frame = new VideoFrame();
writableFrame_.reset(frame);
}
}
pthread_mutex_unlock(&mutex_);
return *frame;
} }
} }
...@@ -37,7 +37,9 @@ ...@@ -37,7 +37,9 @@
#include <cstdlib> #include <cstdlib>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <forward_list> #include <set>
#include <mutex>
#include <condition_variable>
class AVFrame; class AVFrame;
...@@ -55,10 +57,59 @@ enum VideoPixelFormat { ...@@ -55,10 +57,59 @@ enum VideoPixelFormat {
namespace sfl_video { namespace sfl_video {
template <typename T> class Observator;
template <typename T> class Observable;
class VideoFrame;
typedef int(*io_readcallback)(void *opaque, uint8_t *buf, int buf_size); typedef int(*io_readcallback)(void *opaque, uint8_t *buf, int buf_size);
typedef int(*io_writecallback)(void *opaque, uint8_t *buf, int buf_size); typedef int(*io_writecallback)(void *opaque, uint8_t *buf, int buf_size);
typedef int64_t(*io_seekcallback)(void *opaque, int64_t offset, int whence); typedef int64_t(*io_seekcallback)(void *opaque, int64_t offset, int whence);
typedef std::shared_ptr<VideoFrame> VideoFrameUP;
typedef std::shared_ptr<VideoFrame> VideoFrameSP;
/*=== Observable =============================================================*/
template <typename T>
class Observable
{
public:
Observable() : observators_(), mutex_() {}
virtual ~Observable() {};
void attach(Observator<T>* o) {
std::unique_lock<std::mutex> lk(mutex_);
observators_.insert(o);
}
void detach(Observator<T>* o) {
std::unique_lock<std::mutex> lk(mutex_);
observators_.erase(o);
}
void notify(T& data) {
std::unique_lock<std::mutex> lk(mutex_);
for (auto observator : observators_)
observator->update(this, data);
}
private:
NON_COPYABLE(Observable<T>);
std::set<Observator<T>*> observators_;
std::mutex mutex_; // lock observators_
};
/*=== Observator =============================================================*/
template <typename T>
class Observator
{
public:
virtual ~Observator() {};
virtual void update(Observable<T>*, T&) = 0;
};
/*=== VideoPacket ===========================================================*/ /*=== VideoPacket ===========================================================*/
class VideoPacket { class VideoPacket {
...@@ -115,7 +166,7 @@ public: ...@@ -115,7 +166,7 @@ public:
~VideoFrame(); ~VideoFrame();
AVFrame* get() { return frame_; }; AVFrame* get() { return frame_; };
int getFormat() const; int getPixelFormat() const;
int getWidth() const; int getWidth() const;
int getHeight() const; int getHeight() const;
void setGeometry(int width, int height, int pix_fmt);