Commit 19442e3b authored by Philippe Gorley's avatar Philippe Gorley Committed by Sébastien Blin

encoder: support loading per encoder config

This allows users to use different configurations than the one provided
by Jami. File settings overwrite Jami's existing configuration options.

Note that only codec-level options are supported, format-level is not
implemented.

The following options are ignored, as they are set by going into the
settings page: width, height, framerate, sample_rate, channels,
frame_size, parameters (internal option for h264's profile level id).

If a file encoder.json exists in the same folder as dring.yml, it is
loaded into the encoder's configuration options. The config file is
separated by codec. Multiple configurations can exist for the same codec
family (ex: libx264 and h264_vaapi) because each encoder has different
options. Section name should be the codec implementation's name and not
the codec's name (h264 won't work, but libx264 will).

Example configuration file:
{
    "libx264": {
        "crf": 15,
        "preset": "ultrafast"
    },
    "h264_vaapi": {
        "low_power": 1
    },
    "libopus": {
        "application": "voip"
    }
}

Change-Id: Ia6bb184af382638d4016256b393ac7295408ed82
Gitlab: #75Reviewed-by: Sébastien Blin's avatarSébastien Blin <sebastien.blin@savoirfairelinux.com>
parent abb09e1e
......@@ -27,6 +27,7 @@
#include "media_io_handle.h"
#include "audio/audiobuffer.h"
#include "fileutils.h"
#include "string_utils.h"
#include "logger.h"
......@@ -34,9 +35,11 @@ extern "C" {
#include <libavutil/parseutils.h>
}
#include <algorithm>
#include <fstream>
#include <iostream>
#include <json/json.h>
#include <sstream>
#include <algorithm>
#include <thread> // hardware_concurrency
// Define following line if you need to debug libav SDP
......@@ -274,7 +277,8 @@ MediaEncoder::addStream(const SystemCodecInfo& systemCodecInfo, std::string para
currentStreamIdx_ = stream->index;
if (avcodec_open2(encoderCtx, outputCodec, nullptr) < 0)
readConfig(&options_, outputCodec->name);
if (avcodec_open2(encoderCtx, outputCodec, &options_) < 0)
throw MediaEncoderException("Could not open encoder");
#ifndef _WIN32
......@@ -657,4 +661,49 @@ MediaEncoder::getStream(const std::string& name, int streamIdx) const
return MediaStream(name, enc);
}
void
MediaEncoder::readConfig(AVDictionary** dict, const std::string& encoder)
{
std::string path = fileutils::get_config_dir() + DIR_SEPARATOR_STR + "encoder.json";
if (fileutils::isFile(path)) {
try {
Json::Value root;
std::ifstream file(path);
file >> root;
if (!root.isObject()) {
RING_ERR() << "Invalid encoder configuration: root is not an object";
return;
}
const auto& config = root[encoder];
if (config.isNull()) {
RING_WARN() << "Encoder '" << encoder << "' not found in configuration file";
return;
}
if (!config.isObject()) {
RING_ERR() << "Invalid encoder configuration: '" << encoder << "' is not an object";
return;
}
// If users want to change these, they should use the settings page.
std::vector<std::string> ignoredKeys = { "width", "height", "framerate", "sample_rate", "channels", "frame_size", "parameters" };
for (Json::Value::const_iterator it = config.begin(); it != config.end(); ++it) {
Json::Value v = *it;
if (!it.key().isConvertibleTo(Json::ValueType::stringValue)
|| !v.isConvertibleTo(Json::ValueType::stringValue)) {
RING_ERR() << "Invalid configuration for '" << encoder << "'";
return;
}
const auto& key = it.key().asString();
const auto& value = v.asString();
// TODO treat some keys specially, such as profile, level, bit_rate, rate control options, qmin, qmax, as these are AVCodecContext fields
if (std::find(ignoredKeys.cbegin(), ignoredKeys.cend(), key) != ignoredKeys.cend())
continue;
else
libav_utils::setDictValue(dict, key, value);
}
} catch (const Json::Exception& e) {
RING_ERR() << "Failed to load encoder configuration file: " << e.what();
}
}
}
} // namespace ring
......@@ -124,6 +124,7 @@ private:
bool is_muted = false;
protected:
void readConfig(AVDictionary** dict, const std::string& encoder);
AVDictionary *options_ = nullptr;
DeviceParams device_;
std::shared_ptr<const AccountCodecInfo> codec_;
......
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