Commit 431cee5d authored by Philippe Gorley's avatar Philippe Gorley

recorder: add preferences

Adds whether or not the local video feed should be overlaid on the
remote video feed. Adds a quality setting for the recorder.

Change-Id: I60bd80c6441c7d516120680bebb1acdeb3824c49
parent 693c8725
......@@ -757,6 +757,26 @@
</arg>
</method>
<method name="getRecordPreview" tp:name-for-bindings="getRecordPreview">
<arg type="b" name="res" direction="out">
</arg>
</method>
<method name="setRecordPreview" tp:name-for-bindings="setRecordPreview">
<arg type="b" name="enabled" direction="in">
</arg>
</method>
<method name="getRecordQuality" tp:name-for-bindings="getRecordQuality">
<arg type="i" name="res" direction="out">
</arg>
</method>
<method name="setRecordQuality" tp:name-for-bindings="setRecordQuality">
<arg type="i" name="enabled" direction="in">
</arg>
</method>
<!-- /////////////////////// -->
<!-- Codecs-related methods -->
......
......@@ -431,6 +431,30 @@ DBusConfigurationManager::setIsAlwaysRecording(const bool& rec)
DRing::setIsAlwaysRecording(rec);
}
auto
DBusConfigurationManager::getRecordPreview() -> decltype(DRing::getRecordPreview())
{
return DRing::getRecordPreview();
}
void
DBusConfigurationManager::setRecordPreview(const bool& rec)
{
DRing::setRecordPreview(rec);
}
auto
DBusConfigurationManager::getRecordQuality() -> decltype(DRing::getRecordQuality())
{
return DRing::getRecordQuality();
}
void
DBusConfigurationManager::setRecordQuality(const int32_t& quality)
{
DRing::setRecordQuality(quality);
}
void
DBusConfigurationManager::setHistoryLimit(const int32_t& days)
{
......
......@@ -126,6 +126,10 @@ class DRING_PUBLIC DBusConfigurationManager :
void setRecordPath(const std::string& recPath);
bool getIsAlwaysRecording();
void setIsAlwaysRecording(const bool& rec);
bool getRecordPreview();
void setRecordPreview(const bool& rec);
int32_t getRecordQuality();
void setRecordQuality(const int32_t& quality);
void setHistoryLimit(const int32_t& days);
int32_t getHistoryLimit();
void setRingingTimeout(const int32_t& timeout);
......
......@@ -148,6 +148,10 @@ std::string getRecordPath();
void setRecordPath(const std::string& recPath);
bool getIsAlwaysRecording();
void setIsAlwaysRecording(bool rec);
bool getRecordPreview();
void setRecordPreview(bool rec);
int32_t getRecordQuality();
void setRecordQuality(int32_t rec);
void setHistoryLimit(int32_t days);
int32_t getHistoryLimit();
......
......@@ -142,6 +142,10 @@ std::string getRecordPath();
void setRecordPath(const std::string& recPath);
bool getIsAlwaysRecording();
void setIsAlwaysRecording(bool rec);
bool getRecordPreview();
void setRecordPreview(bool rec);
int32_t getRecordQuality();
void setRecordQuality(int32_t rec);
void setHistoryLimit(int32_t days);
int32_t getHistoryLimit();
......
......@@ -2,7 +2,7 @@ dnl Jami - configure.ac for automake 1.9 and autoconf 2.59
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
AC_INIT([Jami Daemon],[7.7.0],[ring@gnu.org],[jami])
AC_INIT([Jami Daemon],[7.8.0],[ring@gnu.org],[jami])
AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2019]])
AC_REVISION([$Revision$])
......
......@@ -5,6 +5,7 @@
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
* Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
* Author: Philippe Gorley <philippe.gorley@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
......@@ -697,6 +698,44 @@ setIsAlwaysRecording(bool rec)
jami::Manager::instance().setIsAlwaysRecording(rec);
}
bool
getRecordPreview()
{
#ifdef ENABLE_VIDEO
return jami::Manager::instance().videoPreferences.getRecordPreview();
#else
return false;
#endif
}
void
setRecordPreview(bool rec)
{
#ifdef ENABLE_VIDEO
jami::Manager::instance().videoPreferences.setRecordPreview(rec);
jami::Manager::instance().saveConfig();
#endif
}
int32_t
getRecordQuality()
{
#ifdef ENABLE_VIDEO
return jami::Manager::instance().videoPreferences.getRecordQuality();
#else
return 0;
#endif
}
void
setRecordQuality(int32_t quality)
{
#ifdef ENABLE_VIDEO
jami::Manager::instance().videoPreferences.setRecordQuality(quality);
jami::Manager::instance().saveConfig();
#endif
}
int32_t
getHistoryLimit()
{
......
......@@ -7,6 +7,7 @@
* Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
* Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Author: Philippe Gorley <philippe.gorley@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
......@@ -126,6 +127,10 @@ DRING_PUBLIC std::string getRecordPath();
DRING_PUBLIC void setRecordPath(const std::string& recPath);
DRING_PUBLIC bool getIsAlwaysRecording();
DRING_PUBLIC void setIsAlwaysRecording(bool rec);
DRING_PUBLIC bool getRecordPreview();
DRING_PUBLIC void setRecordPreview(bool rec);
DRING_PUBLIC int getRecordQuality();
DRING_PUBLIC void setRecordQuality(int quality);
DRING_PUBLIC void setHistoryLimit(int32_t days);
DRING_PUBLIC int32_t getHistoryLimit();
......
......@@ -10,6 +10,7 @@
* Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
* Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Author: Philippe Gorley <philippe.gorley@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
......@@ -982,10 +983,6 @@ Manager::answerCall(const std::string& call_id)
addAudio(*call);
// Start recording if set in preference
if (audioPreference.getIsAlwaysRecording())
toggleRecordingCall(call_id);
return result;
}
......@@ -1995,9 +1992,6 @@ Manager::peerAnsweredCall(Call& call)
getRingBufferPool().flushAllBuffers();
pimpl_->audiodriver_->flushUrgent();
}
if (audioPreference.getIsAlwaysRecording())
toggleRecordingCall(call_id);
}
//THREAD=VoIP Call=Outgoing
......
......@@ -94,6 +94,8 @@ MediaEncoder::setOptions(const MediaStream& opts)
videoOpts_.height -= videoOpts_.height % 2;
if (not videoOpts_.frameRate)
videoOpts_.frameRate = 30;
if (opts.bitrate)
libav_utils::setDictValue(&options_, "max_rate", std::to_string(opts.bitrate));
} else {
audioOpts_ = opts;
}
......
......@@ -136,7 +136,7 @@ MediaFilter::getOutputParams() const
output.timeBase = av_buffersink_get_time_base(output_);
output.width = av_buffersink_get_w(output_);
output.height = av_buffersink_get_h(output_);
output.aspectRatio = av_buffersink_get_sample_aspect_ratio(output_);
output.bitrate = 0;
output.frameRate = av_buffersink_get_frame_rate(output_);
break;
case AVMEDIA_TYPE_AUDIO:
......@@ -275,7 +275,6 @@ MediaFilter::initInputFilter(AVFilterInOut* in, MediaStream msp)
if (mediaType == AVMEDIA_TYPE_VIDEO) {
params->width = msp.width;
params->height = msp.height;
params->sample_aspect_ratio = msp.aspectRatio;
params->frame_rate = msp.frameRate;
buffersrc = avfilter_get_by_name("buffer");
} else {
......
......@@ -22,6 +22,7 @@
#include "client/ring_signal.h"
#include "fileutils.h"
#include "logger.h"
#include "manager.h"
#include "media_io_handle.h"
#include "media_recorder.h"
#include "system_codec_container.h"
......@@ -352,6 +353,7 @@ MediaRecorder::setupVideoOutput()
if (ret >= 0) {
encoderStream = videoFilter_->getOutputParams();
encoderStream.bitrate = Manager::instance().videoPreferences.getRecordQuality();
JAMI_DBG() << "Recorder output: " << encoderStream;
} else {
JAMI_ERR() << "Failed to initialize video filter";
......
......@@ -37,7 +37,7 @@ struct MediaStream {
int64_t firstTimestamp {0};
int width {0};
int height {0};
rational<int> aspectRatio;
int bitrate;
rational<int> frameRate;
int sampleRate {0};
int nbChannels {0};
......@@ -47,14 +47,14 @@ struct MediaStream {
{}
MediaStream(const std::string& streamName, int fmt, rational<int> tb, int w, int h,
rational<int> sar, rational<int> fr)
int br, rational<int> fr)
: name(streamName)
, format(fmt)
, isVideo(true)
, timeBase(tb)
, width(w)
, height(h)
, aspectRatio(sar)
, bitrate(br)
, frameRate(fr)
{}
......@@ -99,7 +99,7 @@ struct MediaStream {
isVideo = true;
width = c->width;
height = c->height;
aspectRatio = c->sample_aspect_ratio;
bitrate = c->bit_rate;
frameRate = c->framerate;
break;
case AVMEDIA_TYPE_AUDIO:
......@@ -131,12 +131,11 @@ struct MediaStream {
void update(AVFrame* f)
{
// update all info possible (AVFrame has no fps data)
// update all info possible (AVFrame has no fps or bitrate data)
format = f->format;
if (isVideo) {
width = f->width;
height = f->height;
aspectRatio = f->sample_aspect_ratio;
} else {
sampleRate = f->sample_rate;
nbChannels = f->channels;
......@@ -154,6 +153,8 @@ inline std::ostream& operator<<(std::ostream& os, const MediaStream& ms)
<< av_get_pix_fmt_name(static_cast<AVPixelFormat>(ms.format)) << " video, "
<< ms.width << "x" << ms.height << ", "
<< ms.frameRate << " fps (" << ms.timeBase << ")";
if (ms.bitrate > 0)
os << ", " << ms.bitrate << " kb/s";
} else {
os << (ms.name.empty() ? "(null)" : ms.name) << ": "
<< av_get_sample_fmt_name(static_cast<AVSampleFormat>(ms.format)) << " audio, "
......
......@@ -64,7 +64,7 @@ getTransposeFilter(int rotation, std::string inputName, int width, int height, i
const auto one = rational<int>(1);
std::vector<MediaStream> msv;
msv.emplace_back(inputName, format, one, width, height, one, one);
msv.emplace_back(inputName, format, one, width, height, 0, one);
std::unique_ptr<MediaFilter> filter(new MediaFilter);
auto ret = filter->initialize(ss.str(), msv);
......
......@@ -3,6 +3,7 @@
*
* Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
* Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
* Author: Philippe Gorley <philippe.gorley@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
......@@ -505,9 +506,11 @@ VideoRtpSession::initRecorder(std::shared_ptr<MediaRecorder>& rec)
receiveThread_->attach(ob);
}
}
if (auto input = std::static_pointer_cast<VideoInput>(videoLocal_)) {
if (auto ob = rec->addStream(input->getInfo())) {
input->attach(ob);
if (Manager::instance().videoPreferences.getRecordPreview()) {
if (auto input = std::static_pointer_cast<VideoInput>(videoLocal_)) {
if (auto ob = rec->addStream(input->getInfo())) {
input->attach(ob);
}
}
}
}
......
......@@ -2,6 +2,7 @@
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
*
* Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
* Author: Philippe Gorley <philippe.gorley@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
......@@ -139,6 +140,8 @@ static constexpr const char* TOGGLE_PICKUP_HANGUP_SHORT_KEY {"togglePickupHangup
constexpr const char * const VideoPreferences::CONFIG_LABEL;
static constexpr const char* DECODING_ACCELERATED_KEY {"decodingAccelerated"};
static constexpr const char* ENCODING_ACCELERATED_KEY {"encodingAccelerated"};
static constexpr const char* RECORD_PREVIEW_KEY {"recordPreview"};
static constexpr const char* RECORD_QUALITY_KEY {"recordQuality"};
#endif
static constexpr int PULSE_LENGTH_DEFAULT {250}; /** Default DTMF length */
......@@ -564,12 +567,16 @@ void ShortcutPreferences::unserialize(const YAML::Node &in)
VideoPreferences::VideoPreferences()
: decodingAccelerated_(true)
, encodingAccelerated_(false)
, recordPreview_(true)
, recordQuality_(0)
{
}
void VideoPreferences::serialize(YAML::Emitter &out) const
{
out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
out << YAML::Key << RECORD_PREVIEW_KEY << YAML::Value << recordPreview_;
out << YAML::Key << RECORD_QUALITY_KEY << YAML::Value << recordQuality_;
#ifdef RING_ACCEL
out << YAML::Key << DECODING_ACCELERATED_KEY << YAML::Value << decodingAccelerated_;
out << YAML::Key << ENCODING_ACCELERATED_KEY << YAML::Value << encodingAccelerated_;
......@@ -580,9 +587,16 @@ void VideoPreferences::serialize(YAML::Emitter &out) const
void VideoPreferences::unserialize(const YAML::Node &in)
{
// values may or may not be present
const auto &node = in[CONFIG_LABEL];
try {
parseValue(node, RECORD_PREVIEW_KEY, recordPreview_);
parseValue(node, RECORD_QUALITY_KEY, recordQuality_);
} catch (...) {
recordPreview_ = true;
recordQuality_ = 0;
}
#ifdef RING_ACCEL
// value may or may not be present
try {
parseValue(node, DECODING_ACCELERATED_KEY, decodingAccelerated_);
parseValue(node, ENCODING_ACCELERATED_KEY, encodingAccelerated_);
......
......@@ -2,6 +2,7 @@
* Copyright (C) 2004-2019 Savoir-faire Linux Inc.
*
* Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
* Author: Philippe Gorley <philippe.gorley@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
......@@ -475,9 +476,27 @@ class VideoPreferences : public Serializable {
emitSignal<DRing::ConfigurationSignal::HardwareEncodingChanged>(encodingAccelerated_);
}
bool getRecordPreview() const {
return recordPreview_;
}
void setRecordPreview(bool rec) {
recordPreview_ = rec;
}
int getRecordQuality() const {
return recordQuality_;
}
void setRecordQuality(int rec) {
recordQuality_ = rec;
}
private:
bool decodingAccelerated_;
bool encodingAccelerated_;
bool recordPreview_;
int recordQuality_;
constexpr static const char* const CONFIG_LABEL = "video";
};
#endif // ENABLE_VIDEO
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment