capabilities: report video compression codecs, encoders, options

This commit is contained in:
Martin Piatka
2021-02-24 16:58:23 +01:00
parent d4d099d1bc
commit 14fcf70fb6
8 changed files with 167 additions and 50 deletions

View File

@@ -314,6 +314,51 @@ void print_capabilities(struct module *root, bool use_vidcap)
it.dec_prop.latency << ";" << it.dec_prop.cpu_cores << ";" << it.dec_prop.gpu_gflops <<
")\n";
}
if(vci->get_module_info){
auto module_info = vci->get_module_info();
cout << "[capability][video_compress][v3] {"
"\"name\":\"" << it.first << "\", "
"\"options\": [";
int i = 0;
for(const auto& opt : module_info.opts){
if(i++ > 0)
cout << ", ";
cout << "{"
"\"display_name\":\"" << opt.display_name << "\", "
"\"display_desc\":\"" << opt.display_desc << "\", "
"\"key\":\"" << opt.key << "\", "
"\"opt_str\":\"" << opt.opt_str << "\", "
"\"is_boolean\":\"" << (opt.is_boolean ? "t" : "f") << "\"}";
}
cout << "], "
"\"codecs\": [";
int j = 0;
for(const auto& c : module_info.codecs){
if(j++ > 0)
cout << ", ";
cout << "{\"name\":\"" << c.name << "\", "
"\"encoders\":[";
int z = 0;
for(const auto& e : c.encoders){
if(z++ > 0)
cout << ", ";
cout << "{\"name\":\"" << e.name << "\", "
"\"opt_str\":\"" << e.opt_str << "\"}";
}
cout << "]}";
}
cout << "]}" << std::endl;
}
}
// capture filters

View File

@@ -68,7 +68,7 @@
#include "types.h"
#define VIDEO_COMPRESS_ABI_VERSION 7
#define VIDEO_COMPRESS_ABI_VERSION 8
#ifdef __cplusplus
extern "C" {
@@ -101,6 +101,7 @@ const char *get_compress_name(struct compress_state *);
#include <list>
#include <memory>
#include <string>
#include <vector>
/**
* @brief Compresses video frame
@@ -174,6 +175,36 @@ struct compress_preset {
compress_prop dec_prop;
};
struct module_option{
std::string display_name; //Name displayed to user
std::string display_desc; //Description displayed to user
/* internal name of option, options that are used in the same way should
* have the same key (e.g. both bitrate for libavcodec and quality for jpeg
* should have the same key). This allows using different labels displayed
* to user */
std::string key;
std::string opt_str; //Option string to pass to ug (e.g. ":bitrate=")
bool is_boolean; //If true, GUI shows a checkbox instead of text edit
};
struct encoder{
std::string name;
std::string opt_str;
};
struct codec{
std::string name;
std::vector<encoder> encoders;
};
struct compress_module_info{
std::string name;
std::vector<module_option> opts;
std::vector<codec> codecs;
};
/**
* There are 4 possible APIs for video compress modules. Each module may choose
* which one to implement, however, only one should be implemented (there is no
@@ -203,6 +234,8 @@ struct video_compress_info {
* Optional - currently not used
*/
std::list<compress_preset> (*get_presets)();
compress_module_info (*get_module_info)();
};
std::shared_ptr<video_frame> compress_pop(struct compress_state *);

View File

@@ -451,7 +451,8 @@ static struct video_compress_info j2k_compress_info = {
NULL,
j2k_compress_push,
j2k_compress_pop,
[] { return list<compress_preset>{}; }
[] { return list<compress_preset>{}; },
NULL
};
REGISTER_MODULE(cmpto_j2k, &j2k_compress_info, LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION);

View File

@@ -299,7 +299,8 @@ const struct video_compress_info cuda_dxt_info = {
NULL,
NULL,
NULL,
[] { return list<compress_preset>{}; }
[] { return list<compress_preset>{}; },
NULL
};
REGISTER_MODULE(cuda_dxt, &cuda_dxt_info, LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION);

View File

@@ -344,7 +344,8 @@ const struct video_compress_info rtdxt_info = {
{ "DXT5", 50, [](const struct video_desc *d){return (long)(d->width * d->height * d->fps * 8.0);},
{75, 0.3, 35}, {15, 0.1, 20} },
} : list<compress_preset>{};
}
},
NULL
};
REGISTER_MODULE(rtdxt, &rtdxt_info, LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION);

View File

@@ -244,76 +244,76 @@ struct state_video_compress_libav {
#endif
};
static void print_codec_info(AVCodecID id, char *buf, size_t buflen)
{
struct codec_encoders_decoders{
std::vector<std::string> encoders;
std::vector<std::string> decoders;
};
static codec_encoders_decoders get_codec_encoders_decoders(AVCodecID id){
codec_encoders_decoders res;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 9, 100)
assert(buflen > 0);
buf[0] = '\0';
const AVCodec *codec = nullptr;
void *i = 0;
char *enc = (char *) alloca(buflen);
char *dec = (char *) alloca(buflen);
dec[0] = enc[0] = '\0';
while ((codec = av_codec_iterate(&i))) {
if (av_codec_is_encoder(codec) && codec->id == id) {
strncat(enc, " ", buflen - strlen(enc) - 1);
strncat(enc, codec->name, buflen - strlen(enc) - 1);
res.encoders.emplace_back(codec->name);
}
if (av_codec_is_decoder(codec) && codec->id == id) {
strncat(dec, " ", buflen - strlen(dec) - 1);
strncat(dec, codec->name, buflen - strlen(dec) - 1);
res.decoders.emplace_back(codec->name);
}
}
if (strlen(enc) || strlen(dec)) {
strncat(buf, " (", buflen - strlen(buf) - 1);
if (strlen(enc)) {
strncat(buf, "encoders:", buflen - strlen(buf) - 1);
strncat(buf, enc, buflen - strlen(buf) - 1);
}
if (strlen(dec)) {
if (strlen(enc)) {
strncat(buf, ", ", buflen - strlen(buf) - 1);
}
strncat(buf, "decoders:", buflen - strlen(buf) - 1);
strncat(buf, dec, buflen - strlen(buf) - 1);
}
strncat(buf, ")", buflen - strlen(buf) - 1);
}
#elif LIBAVCODEC_VERSION_MAJOR >= 54
const AVCodec *codec;
const AVCodec *codec = nullptr;
if ((codec = avcodec_find_encoder(id))) {
strncpy(buf, " (encoders:", buflen - 1);
buf[buflen - 1] = '\0';
do {
if (av_codec_is_encoder(codec) && codec->id == id) {
strncat(buf, " ", buflen - strlen(buf) - 1);
strncat(buf, codec->name, buflen - strlen(buf) - 1);
res.encoders.emplace_back(codec->name);
}
} while ((codec = av_codec_next(codec)));
}
if ((codec = avcodec_find_decoder(id))) {
if (avcodec_find_encoder(id)) {
strncat(buf, ", ", buflen - strlen(buf) - 1);
} else {
strncat(buf, " (", buflen - strlen(buf) - 1);
}
strncat(buf, "decoders:", buflen - strlen(buf) - 1);
do {
if (av_codec_is_decoder(codec) && codec->id == id) {
strncat(buf, " ", buflen - strlen(buf) - 1);
strncat(buf, codec->name, buflen - strlen(buf) - 1);
res.decoders.emplace_back(codec->name);
}
} while ((codec = av_codec_next(codec)));
}
if (avcodec_find_encoder(id) || avcodec_find_decoder(id)) {
strncat(buf, ")", buflen - strlen(buf) - 1);
}
#else
UNUSED(id);
UNUSED(buf);
UNUSED(buflen);
#endif
return res;
}
static void print_codec_info(AVCodecID id, char *buf, size_t buflen)
{
auto info = get_codec_encoders_decoders(id);
assert(buflen > 0);
buf[0] = '\0';
if(info.encoders.empty() && info.decoders.empty())
return;
strncat(buf, " (", buflen - strlen(buf) - 1);
if (!info.encoders.empty()) {
strncat(buf, "encoders:", buflen - strlen(buf) - 1);
for(const auto& enc : info.encoders){
strncat(buf, " ", buflen - strlen(buf) - 1);
strncat(buf, enc.c_str(), buflen - strlen(buf) - 1);
}
}
if (!info.decoders.empty()) {
if (!info.encoders.empty()) {
strncat(buf, ", ", buflen - strlen(buf) - 1);
}
strncat(buf, "decoders:", buflen - strlen(buf) - 1);
for(const auto& dec : info.decoders){
strncat(buf, " ", buflen - strlen(buf) - 1);
strncat(buf, dec.c_str(), buflen - strlen(buf) - 1);
}
}
strncat(buf, ")", buflen - strlen(buf) - 1);
}
static void usage() {
@@ -500,6 +500,39 @@ static list<compress_preset> get_libavcodec_presets() {
return ret;
}
static compress_module_info get_libavcodec_module_info(){
compress_module_info module_info;
module_info.name = "libavcodec";
module_info.opts.emplace_back(module_option{"Bitrate", "Bitrate", "quality", "bitrate=", false});
module_info.opts.emplace_back(module_option{"Crf", "Crf", "crf", "crf=", false});
for (const auto& param : codec_params) {
enum AVCodecID avID = get_ug_to_av_codec(param.first);
if (avID == AV_CODEC_ID_NONE) { // old FFMPEG -> codec id is flushed to 0 in compat
continue;
}
const AVCodec *i;
if (!(i = avcodec_find_encoder(avID))) {
continue;
}
codec codec_info;
codec_info.name = get_codec_name(param.first);
codec_info.encoders.emplace_back(
encoder{"default", ":codec=" + codec_info.name});
auto coders = get_codec_encoders_decoders(avID);
for(const auto& enc : coders.encoders){
codec_info.encoders.emplace_back(
encoder{enc, ":encoder=" + enc});
}
module_info.codecs.emplace_back(std::move(codec_info));
}
return module_info;
}
struct module * libavcodec_compress_init(struct module *parent, const char *opts)
{
struct state_video_compress_libav *s;
@@ -1880,6 +1913,7 @@ const struct video_compress_info libavcodec_info = {
NULL,
NULL,
get_libavcodec_presets,
get_libavcodec_module_info,
};
REGISTER_MODULE(libavcodec, &libavcodec_info, LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION);

View File

@@ -110,7 +110,8 @@ const struct video_compress_info none_info = {
{ "", 100, [](const struct video_desc *d){return (long)(d->width * d->height * d->fps * get_bpp(d->color_spec) * 8.0);},
{0, 1, 0}, {0, 1, 0} },
};
}
},
NULL
};
REGISTER_MODULE(none, &none_info, LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION);

View File

@@ -308,7 +308,8 @@ const struct video_compress_info uyvy_info = {
NULL,
NULL,
NULL,
[] {return list<compress_preset>{}; }
[] {return list<compress_preset>{}; },
NULL
};
REGISTER_MODULE(uyvy, &uyvy_info, LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION);