From 14fcf70fb6771406232e362e77136178bdc83401 Mon Sep 17 00:00:00 2001 From: Martin Piatka Date: Wed, 24 Feb 2021 16:58:23 +0100 Subject: [PATCH] capabilities: report video compression codecs, encoders, options --- src/host.cpp | 45 +++++++++++ src/video_compress.h | 35 ++++++++- src/video_compress/cmpto_j2k.cpp | 3 +- src/video_compress/cuda_dxt.cpp | 3 +- src/video_compress/dxt_glsl.cpp | 3 +- src/video_compress/libavcodec.cpp | 122 +++++++++++++++++++----------- src/video_compress/none.cpp | 3 +- src/video_compress/uyvy.cpp | 3 +- 8 files changed, 167 insertions(+), 50 deletions(-) diff --git a/src/host.cpp b/src/host.cpp index b63e18871..12d26db8b 100644 --- a/src/host.cpp +++ b/src/host.cpp @@ -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 diff --git a/src/video_compress.h b/src/video_compress.h index fd5906373..d957135fb 100644 --- a/src/video_compress.h +++ b/src/video_compress.h @@ -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 #include #include +#include /** * @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 encoders; +}; + +struct compress_module_info{ + std::string name; + std::vector opts; + std::vector 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 (*get_presets)(); + + compress_module_info (*get_module_info)(); }; std::shared_ptr compress_pop(struct compress_state *); diff --git a/src/video_compress/cmpto_j2k.cpp b/src/video_compress/cmpto_j2k.cpp index af29a8eb6..59f772201 100644 --- a/src/video_compress/cmpto_j2k.cpp +++ b/src/video_compress/cmpto_j2k.cpp @@ -451,7 +451,8 @@ static struct video_compress_info j2k_compress_info = { NULL, j2k_compress_push, j2k_compress_pop, - [] { return list{}; } + [] { return list{}; }, + NULL }; REGISTER_MODULE(cmpto_j2k, &j2k_compress_info, LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION); diff --git a/src/video_compress/cuda_dxt.cpp b/src/video_compress/cuda_dxt.cpp index fb60fe02f..0e68cfddb 100644 --- a/src/video_compress/cuda_dxt.cpp +++ b/src/video_compress/cuda_dxt.cpp @@ -299,7 +299,8 @@ const struct video_compress_info cuda_dxt_info = { NULL, NULL, NULL, - [] { return list{}; } + [] { return list{}; }, + NULL }; REGISTER_MODULE(cuda_dxt, &cuda_dxt_info, LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION); diff --git a/src/video_compress/dxt_glsl.cpp b/src/video_compress/dxt_glsl.cpp index 3a933dd5f..8d426a755 100644 --- a/src/video_compress/dxt_glsl.cpp +++ b/src/video_compress/dxt_glsl.cpp @@ -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{}; - } + }, + NULL }; REGISTER_MODULE(rtdxt, &rtdxt_info, LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION); diff --git a/src/video_compress/libavcodec.cpp b/src/video_compress/libavcodec.cpp index 371c03950..dbb126f91 100644 --- a/src/video_compress/libavcodec.cpp +++ b/src/video_compress/libavcodec.cpp @@ -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 encoders; + std::vector 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 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); diff --git a/src/video_compress/none.cpp b/src/video_compress/none.cpp index 6006a12aa..32c74f295 100644 --- a/src/video_compress/none.cpp +++ b/src/video_compress/none.cpp @@ -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); diff --git a/src/video_compress/uyvy.cpp b/src/video_compress/uyvy.cpp index aa1fade91..b8f8a4c9c 100644 --- a/src/video_compress/uyvy.cpp +++ b/src/video_compress/uyvy.cpp @@ -308,7 +308,8 @@ const struct video_compress_info uyvy_info = { NULL, NULL, NULL, - [] {return list{}; } + [] {return list{}; }, + NULL }; REGISTER_MODULE(uyvy, &uyvy_info, LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION);