mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-21 13:40:21 +00:00
271 lines
8.6 KiB
C++
271 lines
8.6 KiB
C++
/*
|
|
* This file contains common external definitions
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#include "config_unix.h"
|
|
#include "config_win32.h"
|
|
#endif
|
|
|
|
#include "host.h"
|
|
|
|
#include "audio/audio_capture.h"
|
|
#include "audio/audio_playback.h"
|
|
#include "debug.h"
|
|
#include "lib_common.h"
|
|
#include "messaging.h"
|
|
#include "perf.h"
|
|
#include "video_capture.h"
|
|
#include "video_compress.h"
|
|
#include "video_display.h"
|
|
#include "video.h"
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <set>
|
|
#include <sstream>
|
|
|
|
#ifdef HAVE_X
|
|
#include <dlfcn.h>
|
|
#include <X11/Xlib.h>
|
|
#endif
|
|
|
|
#ifdef USE_MTRACE
|
|
#include <mcheck.h>
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
unsigned int cuda_device = 0;
|
|
unsigned int audio_capture_channels = DEFAULT_AUDIO_CAPTURE_CHANNELS;
|
|
unsigned int audio_capture_bps = 0;
|
|
unsigned int audio_capture_sample_rate = 0;
|
|
|
|
unsigned int cuda_devices[MAX_CUDA_DEVICES] = { 0 };
|
|
unsigned int cuda_devices_count = 1;
|
|
|
|
int audio_init_state_ok;
|
|
|
|
uint32_t RTT = 0; /* this is computed by handle_rr in rtp_callback */
|
|
|
|
int uv_argc;
|
|
char **uv_argv;
|
|
|
|
char *export_dir = NULL;
|
|
volatile bool should_exit = false;
|
|
|
|
volatile int log_level = LOG_LEVEL_INFO;
|
|
bool color_term = (getenv("TERM") && set<string>{"linux", "screen", "xterm", "xterm-256color"}.count(getenv("TERM")) > 0) && isatty(1) && isatty(2);
|
|
|
|
bool ldgm_device_gpu = false;
|
|
|
|
const char *window_title = NULL;
|
|
|
|
volatile int audio_offset;
|
|
volatile int video_offset;
|
|
|
|
std::unordered_map<std::string, std::string> commandline_params;
|
|
|
|
static void common_cleanup()
|
|
{
|
|
#ifdef USE_MTRACE
|
|
muntrace();
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
WSACleanup();
|
|
#endif
|
|
}
|
|
|
|
bool set_output_buffering() {
|
|
/**
|
|
* @addtogroup cmdline_params
|
|
* @{
|
|
* * stdout-buf
|
|
* Buffering for stdout (no, line or full)
|
|
* * stderr-buf
|
|
* Buffering for stdout (no, line or full)
|
|
* @}
|
|
*/
|
|
const unordered_map<const char *, FILE *> outs = {
|
|
{ "stdout-buf", stdout },
|
|
{ "stderr-buf", stderr }
|
|
};
|
|
for (auto outp : outs) {
|
|
if (get_commandline_param(outp.first)) {
|
|
const unordered_map<string, int> buf_map {
|
|
{ "no", _IONBF }, { "line", _IOLBF }, { "full", _IOFBF }
|
|
};
|
|
|
|
auto it = buf_map.find(get_commandline_param(outp.first));
|
|
if (it == buf_map.end()) {
|
|
log_msg(LOG_LEVEL_ERROR, "Wrong buffer type: %s\n", get_commandline_param(outp.first));
|
|
return false;
|
|
} else {
|
|
setvbuf(outp.second, NULL, it->second, 0);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool common_preinit(int argc, char *argv[])
|
|
{
|
|
uv_argc = argc;
|
|
uv_argv = argv;
|
|
|
|
#ifdef HAVE_X
|
|
void *handle = dlopen("libX11.so", RTLD_NOW);
|
|
bool x11_threads_initialized = false;
|
|
|
|
if (handle) {
|
|
Status (*XInitThreadsProc)();
|
|
XInitThreadsProc = (Status (*)()) dlsym(handle, "XInitThreads");
|
|
if (XInitThreadsProc) {
|
|
XInitThreadsProc();
|
|
x11_threads_initialized = true;
|
|
}
|
|
dlclose(handle);
|
|
}
|
|
if (!x11_threads_initialized) {
|
|
log_msg(LOG_LEVEL_WARNING, "Unable to XInitThreads: %s\n", dlerror());
|
|
}
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
WSADATA wsaData;
|
|
int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
if(err != 0) {
|
|
fprintf(stderr, "WSAStartup failed with error %d.", err);
|
|
return false;
|
|
}
|
|
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
|
|
fprintf(stderr, "Counld not found usable version of Winsock.\n");
|
|
WSACleanup();
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
open_all("module_*.so"); // load modules
|
|
|
|
#ifdef USE_MTRACE
|
|
mtrace();
|
|
#endif
|
|
|
|
perf_init();
|
|
perf_record(UVP_INIT, 0);
|
|
|
|
atexit(common_cleanup);
|
|
|
|
return true;
|
|
}
|
|
|
|
#include <sstream>
|
|
|
|
void print_capabilities(struct module *root, bool use_vidcap)
|
|
{
|
|
// try to figure out actual input video format
|
|
struct video_desc desc{};
|
|
if (use_vidcap && root) {
|
|
for (int attempt = 0; attempt < 20; ++attempt) {
|
|
struct msg_sender *m = (struct msg_sender *) new_message(sizeof(struct msg_sender));
|
|
m->type = SENDER_MSG_QUERY_VIDEO_MODE;
|
|
struct response *r = send_message_sync(root, "sender", (struct message *) m, 100, 0);
|
|
if (response_get_status(r) == RESPONSE_OK) {
|
|
const char *text = response_get_text(r);
|
|
istringstream iss(text);
|
|
iss >> desc;
|
|
free_response(r);
|
|
break;
|
|
}
|
|
free_response(r);
|
|
usleep(100*1000);
|
|
}
|
|
}
|
|
|
|
// compressions
|
|
cout << "[cap] Compressions:" << endl;
|
|
auto compressions = get_libraries_for_class(LIBRARY_CLASS_VIDEO_COMPRESS, VIDEO_COMPRESS_ABI_VERSION);
|
|
|
|
for (auto it : compressions) {
|
|
auto vci = static_cast<const struct video_compress_info *>(it.second);
|
|
auto presets = vci->get_presets();
|
|
for (auto const & it : presets) {
|
|
cout << "[cap] (" << vci->name << (it.name.empty() ? "" : ":") <<
|
|
it.name << ";" << it.quality << ";" << setiosflags(ios_base::fixed) << setprecision(2) << it.compute_bitrate(&desc) << ";" <<
|
|
it.enc_prop.latency << ";" << it.enc_prop.cpu_cores << ";" << it.enc_prop.gpu_gflops << ";" <<
|
|
it.dec_prop.latency << ";" << it.dec_prop.cpu_cores << ";" << it.dec_prop.gpu_gflops <<
|
|
")\n";
|
|
}
|
|
}
|
|
|
|
// capturers
|
|
cout << "[cap] Capturers:" << endl;
|
|
print_available_capturers();
|
|
|
|
// displays
|
|
cout << "[cap] Displays:" << endl;
|
|
auto const & display_capabilities =
|
|
get_libraries_for_class(LIBRARY_CLASS_VIDEO_DISPLAY, VIDEO_DISPLAY_ABI_VERSION);
|
|
for (auto const & it : display_capabilities) {
|
|
auto vdi = static_cast<const struct video_display_info *>(it.second);
|
|
int count;
|
|
struct device_info *devices;
|
|
vdi->probe(&devices, &count);
|
|
for (int i = 0; i < count; ++i) {
|
|
cout << "[cap] (" << devices[i].id << ";" << devices[i].name << ";" <<
|
|
devices[i].repeatable << ")\n";
|
|
}
|
|
free(devices);
|
|
}
|
|
|
|
cout << "[cap] Audio capturers:" << endl;
|
|
auto const & audio_cap_capabilities =
|
|
get_libraries_for_class(LIBRARY_CLASS_AUDIO_CAPTURE, AUDIO_CAPTURE_ABI_VERSION);
|
|
for (auto const & it : audio_cap_capabilities) {
|
|
auto aci = static_cast<const struct audio_capture_info *>(it.second);
|
|
int count;
|
|
struct device_info *devices;
|
|
aci->probe(&devices, &count);
|
|
for (int i = 0; i < count; ++i) {
|
|
cout << "[cap] (" << devices[i].id << ";" << devices[i].name << ")\n";
|
|
}
|
|
free(devices);
|
|
}
|
|
|
|
cout << "[cap] Audio playback:" << endl;
|
|
auto const & audio_play_capabilities =
|
|
get_libraries_for_class(LIBRARY_CLASS_AUDIO_PLAYBACK, AUDIO_PLAYBACK_ABI_VERSION);
|
|
for (auto const & it : audio_play_capabilities) {
|
|
auto api = static_cast<const struct audio_playback_info *>(it.second);
|
|
int count;
|
|
struct device_info *devices;
|
|
api->probe(&devices, &count);
|
|
for (int i = 0; i < count; ++i) {
|
|
cout << "[cap] (" << devices[i].id << ";" << devices[i].name << ")\n";
|
|
}
|
|
free(devices);
|
|
}
|
|
}
|
|
|
|
void print_version()
|
|
{
|
|
printf("%s", PACKAGE_STRING);
|
|
#ifdef GIT_VERSION
|
|
printf(" (rev %s)", GIT_VERSION);
|
|
#endif
|
|
printf("\n");
|
|
printf("\n" PACKAGE_NAME " was compiled with following features:\n");
|
|
printf(AUTOCONF_RESULT);
|
|
}
|
|
|
|
const char *get_commandline_param(const char *key)
|
|
{
|
|
auto it = commandline_params.find(key);
|
|
if (it != commandline_params.end()) {
|
|
return it->second.c_str();
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|