Commit 51c132ff authored by Guillaume Roguez's avatar Guillaume Roguez
Browse files

Merge branch 'video_mixing'

parents 34ace3a7 eca34446
build-aux/
aclocal.m4
build-aux
......
......@@ -86,6 +86,8 @@ libsflphone_la_SOURCES = conference.cpp \
fileutils.cpp \
scoped_lock.cpp \
scoped_lock.h \
sflthread.cpp \
sflthread.h \
conference.h \
voiplink.h \
preferences.h \
......
......@@ -32,7 +32,7 @@
#include "video_controls.h"
#include "video/libav_utils.h"
#include "video/video_preview.h"
#include "video/video_camera.h"
#include "account.h"
#include "logger.h"
#include "manager.h"
......@@ -42,7 +42,9 @@ const char * const SERVER_PATH = "/org/sflphone/SFLphone/VideoControls";
}
VideoControls::VideoControls(DBus::Connection& connection) :
DBus::ObjectAdaptor(connection, SERVER_PATH), preview_(), videoPreference_()
DBus::ObjectAdaptor(connection, SERVER_PATH)
, videoPreview_()
, videoPreference_()
{
// initialize libav libraries
libav_utils::sfl_avcodec_init();
......@@ -157,7 +159,7 @@ VideoControls::getSettings() {
void
VideoControls::startPreview()
{
if (preview_.get()) {
if (videoPreview_.get()) {
ERROR("Video preview was already started!");
return;
}
......@@ -166,24 +168,29 @@ VideoControls::startPreview()
using std::string;
map<string, string> args(videoPreference_.getSettings());
preview_.reset(new sfl_video::VideoPreview(args));
videoPreview_.reset(new sfl_video::VideoCamera(args));
}
void
VideoControls::stopPreview()
{
if (preview_.get()) {
if (videoPreview_.get()) {
DEBUG("Stopping video preview");
preview_.reset();
videoPreview_.reset();
} else {
WARN("Video preview was already stopped");
}
}
sfl_video::VideoSource* VideoControls::getVideoPreview()
{
return videoPreview_.get();
}
bool
VideoControls::hasPreviewStarted()
{
return preview_.get() != 0;
return videoPreview_.get() != 0;
}
std::string
......
......@@ -55,18 +55,18 @@
#endif // HAVE_DBUS
#include <tr1/memory> // for shared_ptr
#include <memory> // for shared_ptr
#include "video/video_preferences.h"
namespace sfl_video {
class VideoPreview;
class VideoSource;
}
class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor,
public DBus::IntrospectableAdaptor,
public DBus::ObjectAdaptor {
private:
std::tr1::shared_ptr<sfl_video::VideoPreview> preview_;
std::shared_ptr<sfl_video::VideoSource> videoPreview_;
VideoPreference videoPreference_;
public:
......@@ -126,6 +126,7 @@ class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor,
void startPreview();
void stopPreview();
bool hasPreviewStarted();
sfl_video::VideoSource* getVideoPreview();
};
#endif // VIDEO_CONTROLS_H_
......@@ -36,12 +36,30 @@
#include "audio/audiolayer.h"
#include "audio/mainbuffer.h"
#ifdef SFL_VIDEO
#include "client/video_controls.h"
#include "video/video_camera.h"
#endif
Conference::Conference()
: id_(Manager::instance().getNewCallID())
, confState_(ACTIVE_ATTACHED)
, participants_()
#ifdef SFL_VIDEO
, videoMixer_()
#endif
{
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
......@@ -127,3 +145,9 @@ std::string Conference::getConfID() const {
return id_;
}
#ifdef SFL_VIDEO
sfl_video::VideoMixer* Conference::getVideoMixer()
{
return &videoMixer_;
}
#endif
......@@ -30,11 +30,19 @@
#ifndef CONFERENCE_H
#define CONFERENCE_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <set>
#include <string>
#include "audio/recordable.h"
#ifdef SFL_VIDEO
#include "video/video_mixer.h"
#endif
typedef std::set<std::string> ParticipantSet;
class Conference : public Recordable {
......@@ -90,10 +98,19 @@ class Conference : public Recordable {
* Start/stop recording toggle
*/
virtual bool toggleRecording();
#ifdef SFL_VIDEO
sfl_video::VideoMixer* getVideoMixer();
#endif
private:
std::string id_;
ConferenceState confState_;
ParticipantSet participants_;
#ifdef SFL_VIDEO
sfl_video::VideoMixer videoMixer_;
#endif
};
#endif
......@@ -95,7 +95,8 @@
ManagerImpl::ManagerImpl() :
preferences(), voipPreferences(),
hookPreference(), audioPreference(), shortcutPreferences(),
hasTriedToRegister_(false), audioCodecFactory(), client_(), config_(),
hasTriedToRegister_(false), audioCodecFactory(), client_(),
config_(),
currentCallId_(), currentCallMutex_(), audiodriver_(0), dtmfKey_(),
toneMutex_(), telephoneTone_(), audiofile_(), audioLayerMutex_(),
waitingCalls_(), waitingCallsMutex_(), path_(),
......
/*
* Copyright (C) 2011-2013 Savoir-Faire Linux Inc.
* Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
* Copyright (C) 2013 Savoir-Faire Linux Inc.
*
* Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -28,15 +29,65 @@
* as that of the covered work.
*/
#include "packet_handle.h"
// libav includes
extern "C" {
#include <libavformat/avformat.h>
#include "sflthread.h"
#include "logger.h"
#define set_false_atomic(x) static_cast<void>(__sync_fetch_and_and(x, false))
void* SFLThread::run_(void* data)
{
SFLThread *obj = static_cast<SFLThread*>(data);
obj->mainloop_();
return nullptr;
}
void SFLThread::mainloop_()
{
if (setup()) {
while (running_)
process();
cleanup();
} else
ERROR("setup failed");
}
SFLThread::SFLThread() : thread_(), running_(false)
{}
SFLThread::~SFLThread()
{
if (isRunning()) {
stop();
join();
}
}
void SFLThread::start()
{
if (!running_) {
running_ = true;
pthread_create(&thread_, NULL, &run_, this);
}
}
void SFLThread::stop()
{
set_false_atomic(&running_);
}
PacketHandle::PacketHandle(AVPacket &inpacket) : inpacket_(inpacket) {}
void SFLThread::join()
{
if (thread_)
pthread_join(thread_, NULL);
}
void SFLThread::exit()
{
stop();
pthread_exit(NULL);
}
PacketHandle::~PacketHandle()
bool SFLThread::isRunning()
{
av_free_packet(&inpacket_);
return running_;
}
/*
* Copyright (C) 2011-2013 Savoir-Faire Linux Inc.
* Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
* Copyright (C) 2013 Savoir-Faire Linux Inc.
*
* Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -28,26 +29,34 @@
* as that of the covered work.
*/
#ifndef __VIDEO_PREVIEW_H__
#define __VIDEO_PREVIEW_H__
#ifndef __SFLTHREAD_H__
#define __SFLTHREAD_H__
#include <pthread.h>
class SFLThread {
public:
SFLThread();
virtual ~SFLThread();
#include <tr1/memory>
#include <string>
#include <map>
void start();
void stop();
void join();
bool isRunning();
namespace sfl_video {
protected:
virtual bool setup() { return true; };
virtual void process() {};
virtual void cleanup() {};
class VideoReceiveThread;
void exit();
class VideoPreview {
public:
VideoPreview(const std::map<std::string, std::string> &args);
~VideoPreview();
private:
static void* run_(void*);
void mainloop_();
pthread_t thread_;
private:
std::map<std::string, std::string> args_;
std::tr1::shared_ptr<VideoReceiveThread> receiveThread_;
bool running_;
};
}
#endif // __VIDEO_PREVIEW_H__
#endif // __SFLTHREAD_H__
......@@ -1914,7 +1914,6 @@ void sdp_media_update_cb(pjsip_inv_session *inv, pj_status_t status)
call->getAudioRtp().setDtmfPayloadType(sdpSession->getTelephoneEventType());
#ifdef SFL_VIDEO
Manager::instance().getVideoControls()->stopPreview();
call->getVideoRtp().updateSDP(*call->getLocalSDP());
call->getVideoRtp().updateDestination(call->getLocalSDP()->getRemoteIP(), call->getLocalSDP()->getRemoteVideoPort());
call->getVideoRtp().start(call->getLocalSDP()->getLocalVideoPort());
......
......@@ -3,15 +3,23 @@ include $(top_srcdir)/globals.mak
SUBDIRS=test
noinst_LTLIBRARIES = libvideo.la
libvideo_la_SOURCES = libav_utils.cpp libav_utils.h video_rtp_session.cpp \
video_rtp_session.h video_send_thread.h video_send_thread.cpp \
video_receive_thread.h video_receive_thread.cpp \
video_preview.h video_preview.cpp video_v4l2.cpp \
video_v4l2_list.cpp video_v4l2.h video_v4l2_list.h \
video_preferences.h video_preferences.cpp \
packet_handle.h packet_handle.cpp check.h shm_header.h \
shm_sink.cpp shm_sink.h video_provider.h \
socket_pair.cpp socket_pair.h
libvideo_la_SOURCES = \
video_v4l2.cpp \
video_v4l2_list.cpp video_v4l2.h video_v4l2_list.h \
video_preferences.cpp video_preferences.h \
video_base.cpp video_base.h \
video_scaler.cpp video_scaler.h \
video_decoder.cpp video_decoder.h \
video_encoder.cpp video_encoder.h \
video_mixer.cpp video_mixer.h \
socket_pair.cpp socket_pair.h \
shm_sink.cpp shm_sink.h \
video_camera.cpp video_camera.h \
video_receive_thread.cpp video_receive_thread.h \
video_send_thread.cpp video_send_thread.h \
video_rtp_session.cpp video_rtp_session.h \
check.h shm_header.h video_provider.h \
libav_utils.cpp libav_utils.h libav_deps.h
libvideo_la_LIBADD = @LIBAVCODEC_LIBS@ @LIBAVFORMAT_LIBS@ @LIBAVDEVICE_LIBS@ @LIBSWSCALE_LIBS@ @LIBAVUTIL_LIBS@ @UDEV_LIBS@
......
......@@ -32,13 +32,16 @@
#define CHECK_H_
#include "logger.h"
#include "sflthread.h"
// cast to void to avoid compiler warnings about unused return values
#define set_false_atomic(x) static_cast<void>(__sync_fetch_and_and(x, false))
#define set_true_atomic(x) static_cast<void>(__sync_fetch_and_or(x, true))
#define atomic_increment(x) static_cast<void>(__sync_fetch_and_add(x, 1))
#define atomic_decrement(x) static_cast<void>(__sync_fetch_and_sub(x, 1))
// If condition A is false, print the error message in M and exit thread
#define EXIT_IF_FAIL(A, M, ...) if (!(A)) { ERROR(M, ##__VA_ARGS__); set_false_atomic(&threadRunning_); pthread_exit(NULL); }
#define EXIT_IF_FAIL(A, M, ...) if (!(A)) { \
ERROR(M, ##__VA_ARGS__); this->exit(); }
#endif // CHECK_H_
/*
* Copyright (C) 2013 Savoir-Faire Linux Inc.
* Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#ifndef __LIBAV_DEPS_H__
#define __LIBAV_DEPS_H__
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libavutil/opt.h>
}
#include "libav_utils.h"
/* LIBAVFORMAT_VERSION_CHECK checks for the right version of libav and FFmpeg
* a is the major version
* b and c the minor and micro versions of libav
* d and e the minor and micro versions of FFmpeg */
#define LIBAVFORMAT_VERSION_CHECK( a, b, c, d, e ) \
( (LIBAVFORMAT_VERSION_MICRO < 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT( a, b, c ) ) || \
(LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT( a, d, e ) ) )
#define HAVE_SDP_CUSTOM_IO LIBAVFORMAT_VERSION_CHECK(54,20,3,59,103)
#if (LIBAVUTIL_VERSION_MAJOR < 53) && !defined(FF_API_PIX_FMT)
#define AVPixelFormat PixelFormat
#endif
#if (LIBAVCODEC_VERSION_MAJOR < 54) \
|| ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR < 28))
#define avcodec_free_frame(x) av_freep(x)
#endif
#endif // __LIBAV_DEPS_H__
......@@ -2,6 +2,7 @@
* Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
* Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
* Author: Luca Barbato <lu_zero@gentoo.org>
* Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -29,18 +30,15 @@
* as that of the covered work.
*/
#include "libav_utils.h"
#include "libav_deps.h"
#include "video_base.h"
#include "logger.h"
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
#include "logger.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
}
namespace {
using std::string;
......@@ -174,4 +172,29 @@ getDefaultCodecs()
return result;
}
int libav_pixel_format(int fmt)
{
switch (fmt) {
case VIDEO_PIXFMT_BGRA: return PIX_FMT_BGRA;
case VIDEO_PIXFMT_YUV420P: return PIX_FMT_YUV420P;
}
return fmt;
}
int sfl_pixel_format(int fmt)
{
switch (fmt) {
case PIX_FMT_YUV420P: return VIDEO_PIXFMT_YUV420P;
}
return fmt;
}
void sfl_url_split(const char *url,
char *hostname, size_t hostname_size, int *port,
char *path, size_t path_size)
{
av_url_split(NULL, 0, NULL, 0, hostname, hostname_size, port,
path, path_size, url);
}
} // end namespace libav_utils
......@@ -35,20 +35,25 @@
#include <map>
#include <string>
namespace libav_utils {
void
sfl_avcodec_init();
void sfl_avcodec_init();
int libav_pixel_format(int fmt);
int sfl_pixel_format(int fmt);
std::map<std::string, std::string>
encodersMap();
std::map<std::string, std::string> encodersMap();
std::vector<std::string>
getVideoCodecList();
std::vector<std::string> getVideoCodecList();
std::vector<std::map <std::string, std::string> > getDefaultCodecs();
std::vector<std::map<std::string, std::string> >
getDefaultCodecs();
const char *const DEFAULT_H264_PROFILE_LEVEL_ID = "profile-level-id=428014";
const char *const MAX_H264_PROFILE_LEVEL_ID = "profile-level-id=640034";
void sfl_url_split(const char *url,
char *hostname, size_t hostname_size, int *port,
char *path, size_t path_size);
}
#endif // __LIBAV_UTILS_H__
......@@ -62,8 +62,7 @@ SHMSink::~SHMSink()
stop();
}
bool
SHMSink::start()
bool SHMSink::start()
{
if (fd_ != -1) {
ERROR("fd must be -1");
......@@ -123,8 +122,7 @@ SHMSink::start()
return true;
}
bool
SHMSink::stop()
bool SHMSink::stop()
{
if (fd_ >= 0)
close(fd_);
......@@ -143,8 +141,7 @@ SHMSink::stop()
return true;
}
bool
SHMSink::resize_area(size_t desired_length)
bool SHMSink::resize_area(size_t desired_length)
{
if (desired_length <= shm_area_len_)
return true;
......
......@@ -30,9 +30,12 @@
* as that of the covered work.
*/
#include "libav_deps.h"
#include "socket_pair.h"
#include "scoped_lock.h"
#include "libav_utils.h"
#include "logger.h"
#include <cstring>
#include <stdexcept>
#include <unistd.h>
......@@ -42,11 +45,6 @@
#include <netdb.h>
extern "C" {
#include <libavutil/avstring.h>
#include <libavformat/avformat.h>
}
namespace {
int ff_network_wait_fd(int fd)
......@@ -54,16 +52,16 @@ int ff_network_wait_fd(int fd)
struct pollfd p = { fd, POLLOUT, 0 };
int ret;
ret = poll(&p, 1, 100);
return ret < 0 ? errno : p.revents & (POLLOUT | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN);
return ret < 0 ? errno : p.revents & (POLLOUT | POLLERR | POLLHUP) ? 0 : -EAGAIN;
}
struct addrinfo*
udp_resolve_host