diff --git a/.github/scripts/Linux/ffmpeg-patches/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch b/.github/scripts/Linux/ffmpeg-patches/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch index 3357f93ab..3f0a7f9ed 100644 --- a/.github/scripts/Linux/ffmpeg-patches/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch +++ b/.github/scripts/Linux/ffmpeg-patches/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch @@ -1,4 +1,4 @@ -From 19f4bd57e3d60dc6e40bc1ff96fbb91916dd7cc4 Mon Sep 17 00:00:00 2001 +From 6fe97a207e1094365f4be54dff0a2412d3130042 Mon Sep 17 00:00:00 2001 From: Jing Sun Date: Wed, 21 Nov 2018 11:33:04 +0800 Subject: [PATCH] lavc/svt_hevc: add libsvt hevc encoder wrapper @@ -21,10 +21,10 @@ UPDATED 2025-06-20 by Martin Pulec: rebased against 45a30e036 + fix compile create mode 100644 libavcodec/libsvt_hevc.c diff --git a/configure b/configure -index e1809a3e58..936cea82ab 100755 +index 60e33e26e4..da24e814a4 100755 --- a/configure +++ b/configure -@@ -339,6 +339,7 @@ External library support: +@@ -345,6 +345,7 @@ External library support: --enable-whisper enable whisper filter [no] --disable-xlib disable xlib [autodetect] --disable-zlib disable zlib [autodetect] @@ -32,15 +32,15 @@ index e1809a3e58..936cea82ab 100755 The following libraries provide various hardware acceleration features: --disable-amf disable AMF video encoding code [autodetect] -@@ -1979,6 +1980,7 @@ EXTERNAL_LIBRARY_LIST=" +@@ -2052,6 +2053,7 @@ EXTERNAL_LIBRARY_LIST=" libsrt libssh libsvtav1 + libsvthevc + libsvtjpegxs libtensorflow libtesseract - libtheora -@@ -3678,6 +3680,7 @@ vapoursynth_demuxer_deps="vapoursynth" +@@ -3792,6 +3794,7 @@ vapoursynth_demuxer_deps="vapoursynth" videotoolbox_suggest="coreservices" videotoolbox_deps="corefoundation coremedia corevideo VTDecompressionSessionDecodeFrame" videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" @@ -48,19 +48,19 @@ index e1809a3e58..936cea82ab 100755 # demuxers / muxers ac3_demuxer_select="ac3_parser" -@@ -7149,6 +7152,7 @@ enabled libssh && require_pkg_config libssh "libssh >= 0.6.0" libssh/ +@@ -7313,6 +7316,7 @@ enabled libssh && require_pkg_config libssh "libssh >= 0.6.0" libssh/ enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init enabled libsrt && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket enabled libsvtav1 && require_pkg_config libsvtav1 "SvtAv1Enc >= 0.9.0" EbSvtAv1Enc.h svt_av1_enc_init_handle +enabled libsvthevc && require_pkg_config libsvthevc SvtHevcEnc EbApi.h EbInitHandle + enabled libsvtjpegxs && require_pkg_config libsvtjpegxs "SvtJpegxs >= 0.10.0" SvtJpegxsEnc.h svt_jpeg_xs_encoder_init enabled libtensorflow && require libtensorflow tensorflow/c/c_api.h TF_Version -ltensorflow enabled libtesseract && require_pkg_config libtesseract tesseract tesseract/capi.h TessBaseAPICreate - enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index 35408949ac..12f534a1d7 100644 +index 3d60347a19..db09ee37de 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile -@@ -1202,6 +1202,7 @@ OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_anim +@@ -1225,6 +1225,7 @@ OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_anim OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o OBJS-$(CONFIG_LIBX265_ENCODER) += libx265.o @@ -69,10 +69,10 @@ index 35408949ac..12f534a1d7 100644 OBJS-$(CONFIG_LIBXAVS2_ENCODER) += libxavs2.o OBJS-$(CONFIG_LIBXEVD_DECODER) += libxevd.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c -index f5ec2e01e8..7844040a00 100644 +index 042b07c895..69005226ef 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c -@@ -827,6 +827,7 @@ extern const FFCodec ff_libxavs_encoder; +@@ -841,6 +841,7 @@ extern const FFCodec ff_libxavs_encoder; extern const FFCodec ff_libxavs2_encoder; extern const FFCodec ff_libxvid_encoder; extern const FFCodec ff_libzvbi_teletext_decoder; @@ -671,5 +671,5 @@ index 0000000000..07f62fa762 + .p.wrapper_name = "libsvt_hevc", +}; -- -2.50.1 +2.52.0 diff --git a/configure.ac b/configure.ac index 146523bb8..657be9d13 100644 --- a/configure.ac +++ b/configure.ac @@ -520,6 +520,9 @@ if test $cuda_req != no; then # nvcc is intentional here AC_PATH_PROG(NVCC, nvcc, [], [$CUDA_PATH_SEP$PATH]dnl [$PATH_SEPARATOR/opt/cuda/bin$PATH_SEPARATOR/usr/local/cuda/bin]) + if -z "$NVCC" && -e "$CUDACXX"; then + NVCC=$CUDACXX + fi fi if test -n "${NVCC?}" && test "${cross_compile?}" = no && test "${cuda_req?}" != no @@ -1095,8 +1098,6 @@ AC_ARG_ENABLE(deltacast, [deltacast_req=$enableval], [deltacast_req=$build_default] ) -DELTACAST_PATH=$DELTACAST_DIRECTORY - AC_ARG_WITH(deltacast, [ --with-deltacast=DIR specify location of DELTACAST], [DELTACAST_PATH=$withval @@ -1106,21 +1107,26 @@ if test "$deltacast_req" != no; then if test "$system" = Linux || test "$system" = Windows; then AC_LANG_PUSH(C++) - if test -n "$DELTACAST_PATH"; then - DELTA_INC="-I$DELTACAST_PATH/Include\ - -I$DELTACAST_PATH/include/videomaster" - CXXFLAGS_SAVE=$CXXFLAGS - CXXFLAGS="$CXXFLAGS ${DELTA_INC?}" - CPPFLAGS_SAVE=$CPPFLAGS - CPPFLAGS="$CPPFLAGS ${DELTA_INC?}" - fi - - if test $system = Windows; then + if test ${system?} = Windows; then + DELTACAST_PATH=\ +${DELTACAST_DIRECTORY:-/c/PROGRA~1/DELTACAST/VideoMaster/resources} + DELTA_INC=-I$DELTACAST_PATH/include + DELTACAST_LIB=-L$DELTACAST_PATH/lib EXTRA_HEADERS="#include " else + DELTACAST_PATH=${DELTACAST_DIRECTORY:-/usr} + DELTA_INC=-I$DELTACAST_PATH/include/videomaster + DELTA_INC="$DELTA_INC -I$DELTACAST_PATH/Include" # old SDK compat + DELTACAST_LIB=-L$DELTACAST_PATH/lib + # no lib path compat for old SDKs - install them with 'make install' EXTRA_HEADERS= fi + CXXFLAGS_SAVE=$CXXFLAGS + CXXFLAGS="$CXXFLAGS ${DELTA_INC?}" + CPPFLAGS_SAVE=$CPPFLAGS + CPPFLAGS="$CPPFLAGS ${DELTA_INC?}" + AC_CHECK_HEADERS([VideoMasterHD_Core.h VideoMasterHD_Sdi.h VideoMasterHD_Sdi_Audio.h], [], [], [[$EXTRA_HEADERS @@ -1133,15 +1139,7 @@ if test "$deltacast_req" != no; then ]]) SAVED_LIBS=$LIBS - DELTACAST_LIB="-lvideomasterhd_audio -lvideomasterhd" - if test -n "$DELTACAST_PATH"; then - if test "${ac_cv_sizeof_int_p?}" -eq 8 && - test "${system?}" = Linux; then - DELTACAST_LIB="$DELTACAST_LIB -L$DELTACAST_PATH/Library/x64" - else - DELTACAST_LIB="$DELTACAST_LIB -L$DELTACAST_PATH/Library/x86" - fi - fi + DELTACAST_LIB="$DELTACAST_LIB -lvideomasterhd_audio -lvideomasterhd" LIBS="$LIBS $DELTACAST_LIB" AC_MSG_CHECKING([DELTACAST library presence]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[$EXTRA_HEADERS diff --git a/src/control_socket.cpp b/src/control_socket.cpp index 8b8595ea6..3e0507b34 100644 --- a/src/control_socket.cpp +++ b/src/control_socket.cpp @@ -88,7 +88,7 @@ using namespace std; struct client { fd_t fd; - char buff[1024]; + char buff[2048]; int buff_len; struct client *prev; @@ -655,17 +655,25 @@ static int process_msg(struct control_state *s, fd_t client_fd, char *message, s dump_tree(s->root_module, 0); resp = new_response(RESPONSE_OK, NULL); } else { // assume message in format "path message" - struct msg_universal *msg = (struct msg_universal *) - new_message(sizeof(struct msg_universal)); - - if (strchr(message, ' ')) { - memcpy(path, message, strchr(message, ' ') - message); - strncpy(msg->text, strchr(message, ' ') + 1, sizeof(path) - 1); - } else { - strncpy(path, message, sizeof(path) - 1); // empty message ?? + struct msg_universal *msg = (struct msg_universal *) + new_message(sizeof(struct msg_universal)); + + if (strchr(message, ' ')) { + size_t path_len = strchr(message, ' ') - message; + memcpy(path, message, path_len); + path[path_len] = '\0'; + strncpy(msg->text, strchr(message, ' ') + 1, sizeof(msg->text) - 1); + + // If path is "root", send directly to root module + if (strcmp(path, "root") == 0) { + path[0] = '\0'; } + } else { + path[0] = '\0'; + strncpy(msg->text, message, sizeof(msg->text) - 1); + } - resp = send_message(s->root_module, path, (struct message *) msg); + resp = send_message_sync(s->root_module, path, (struct message *) msg, 100, 0); } if(!resp) { @@ -695,8 +703,12 @@ static void send_response(fd_t fd, struct response *resp) if (ret < 0) { socket_error("Unable to write response"); } + #ifndef _WIN32 + // Force flush on POSIX systems + fsync(fd); + #endif - free_response(resp); + free_response(resp); } static bool parse_msg(char *buffer, int buffer_len, /* out */ char *message, int *new_buffer_len) @@ -852,7 +864,6 @@ static void * control_thread(void *args) socket_error("[control socket] accept"); continue; } - // all remote sockets are written sequentially so // we don't want to block if one gets stuck set_socket_nonblock(fd); @@ -1063,7 +1074,8 @@ get_control_state(struct module *mod) return (struct control_state *) control_mod->priv_data; } -static void print_control_help() { + + static void print_control_help() { color_printf("Control internal commands:\n" TBOLD("\texit") "\n" TBOLD("\tpause") "\n" @@ -1081,10 +1093,14 @@ static void print_control_help() { " - (un)mutes audio sender or receiver\n" TBOLD("\tpostprocess | flush") "\n" TBOLD("\tdump-tree")"\n"); + color_printf("\nHD-RUM Translator commands:\n" + TBOLD("\tcreate-port [compression]") " - create new output port\n" + TBOLD("\tdelete-port ") " - remove output port\n" + TBOLD("\tlist-ports") " - show all configured output ports and their IP addresses\n"); color_printf("\nOther commands can be issued directly to individual " "modules (see \"" TBOLD("dump-tree") "\"), eg.:\n" "\t" TBOLD("capture.filter mirror") "\n" "\nSometimes those modules support help (eg. \"" TBOLD("capture.filter help") "\")\n\n"); color_printf(TBOLD(u8"ยน") " audio commands applying to receiver\n\n"); -} + } diff --git a/src/control_socket.h b/src/control_socket.h index e94520943..434b1b0a3 100644 --- a/src/control_socket.h +++ b/src/control_socket.h @@ -51,6 +51,7 @@ struct module; * @retval 0 if success */ int control_init(int port, int connection_type, struct control_state **state, struct module *root_module, int force_ip_version); +int control_get_port(struct control_state *state); struct control_state *get_control_state(struct module *mod); void control_start(struct control_state *state); void control_done(struct control_state *s); diff --git a/src/hd-rum-translator/hd-rum-translator.cpp b/src/hd-rum-translator/hd-rum-translator.cpp index 56649e7dc..cf7c454ef 100644 --- a/src/hd-rum-translator/hd-rum-translator.cpp +++ b/src/hd-rum-translator/hd-rum-translator.cpp @@ -106,6 +106,7 @@ struct replica { replica(const char *addr, uint16_t rx_port, uint16_t tx_port, int bufsize, struct module *parent, int force_ip_version) { magic = REPLICA_MAGIC; host = addr; + ip_address = addr; // Store IP address for identification m_tx_port = tx_port; sock = std::shared_ptr(udp_init(addr, rx_port, tx_port, 255, force_ip_version, false), udp_exit); int mode = 0; @@ -133,6 +134,7 @@ struct replica { struct module mod; uint32_t magic; string host; + string ip_address; int m_tx_port; enum type_t { @@ -146,9 +148,13 @@ struct replica { socklen_t sockaddr_len; }; +void writer_new_message_callback(struct module *m); + struct hd_rum_translator_state { hd_rum_translator_state() { init_root_module(&mod); + mod.priv_data = this; + mod.new_message = writer_new_message_callback; pthread_mutex_init(&qempty_mtx, NULL); pthread_mutex_init(&qfull_mtx, NULL); pthread_cond_init(&qempty_cond, NULL); @@ -331,8 +337,18 @@ static int create_output_port(struct hd_rum_translator_state *s, { struct replica *rep; try { - rep = new replica(addr, rx_port, tx_port, bufsize, &s->mod, + // Process the address string to handle IPv6 brackets + char *processed_addr = strdup(addr); + if (processed_addr[0] == '[' && processed_addr[strlen(processed_addr) - 1] == ']') { + processed_addr[0] = '\0'; + memmove(processed_addr, processed_addr + 1, strlen(processed_addr)); + processed_addr[strlen(processed_addr) - 1] = '\0'; + } + + rep = new replica(processed_addr, rx_port, tx_port, bufsize, &s->mod, common->force_ip_version); + free(processed_addr); + if(use_server_sock){ rep->sock = s->server_socket; } @@ -360,11 +376,24 @@ static int create_output_port(struct hd_rum_translator_state *s, } assert((unsigned) idx == s->replicas.size() - 1); - recompress_port_set_active(s->recompress, idx, compression != nullptr); + recompress_port_set_active(s->recompress, idx, + rep->type == replica::type_t::RECOMPRESS); return idx; } +void writer_new_message_callback(struct module *m) { + // add callback function + struct hd_rum_translator_state *s = (struct hd_rum_translator_state *) m->priv_data; + if (s) { + log_msg(LOG_LEVEL_DEBUG, "Message callback triggered, waking up writer thread\n"); + // Wake up the writer thread when a new message arrives + pthread_mutex_lock(&s->qempty_mtx); + pthread_cond_signal(&s->qempty_cond); + pthread_mutex_unlock(&s->qempty_mtx); + } +} + static void *writer(void *arg) { struct hd_rum_translator_state *s = @@ -384,88 +413,161 @@ static void *writer(void *arg) while ((msg = (struct msg_universal *) check_message(&s->mod))) { struct response *r = NULL; if (strncasecmp(msg->text, "delete-port ", strlen("delete-port ")) == 0) { + char buffer[2048]; char *port_spec = msg->text + strlen("delete-port "); int index = -1; - if (isdigit(port_spec[0])) { + bool is_all_digits = true; + for (int j = 0; port_spec[j] != '\0'; j++) { + if (!isdigit(port_spec[j])) { + is_all_digits = false; + break; + } + } + if (is_all_digits && strlen(port_spec) > 0) { int i = stoi(port_spec); if (i >= 0 && i < (int) s->replicas.size()) { index = i; } else { log_msg(LOG_LEVEL_WARNING, "Invalid port index: %d. Not removing.\n", i); + snprintf(buffer, sizeof(buffer), "Invalid port index: %d. Not removing.\n", i); } } else { + // It's not all digits, so treat as IP address or name int i = 0; + // Check for IP address match first for (auto r : s->replicas) { - if (strcmp(r->mod.name, port_spec) == 0) { + // Ensure replica and its IP address are valid before comparing + if (!r->ip_address.empty() && r->ip_address == port_spec) { index = i; break; } i++; } + // If not found by IP, check by port name + if (index == -1) { + i = 0; + for (auto r : s->replicas) { + if (strcmp(r->mod.name, port_spec) == 0) { + index = i; + break; + } + i++; + } + } + // Log if neither IP address or name matches if (index == -1) { - log_msg(LOG_LEVEL_WARNING, "Unknown port name: %s. Not removing.\n", port_spec); + log_msg(LOG_LEVEL_WARNING, "Unknown port (IP or name): %s. Not removing.\n", port_spec); + snprintf(buffer, sizeof(buffer), "Unknown port (IP or name): %s. Not removing.\n", port_spec); } } if (index >= 0) { recompress_remove_port(s->recompress, index); delete s->replicas[index]; s->replicas.erase(s->replicas.begin() + index); - log_msg(LOG_LEVEL_NOTICE, "Deleted output port %d.\n", index); + snprintf(buffer, sizeof(buffer), "Deleted output port %d.\n", index); + log_msg(LOG_LEVEL_NOTICE, "%s", buffer); + r = new_response(RESPONSE_OK, buffer); + } else { + r = new_response(RESPONSE_NOT_FOUND, "Port not found"); } - } else if (strncasecmp(msg->text, "create-port", strlen("create-port")) == 0) { - // format of parameters is either: - // : [] - // or (for compat with older CoUniverse version) - // [] - char *host_port, *port_str = NULL, *save_ptr; - char *host; - int tx_port; - strtok_r(msg->text, " ", &save_ptr); - host_port = strtok_r(NULL, " ", &save_ptr); - if (host_port && (strchr(host_port, ':') != NULL || (port_str = strtok_r(NULL, " ", &save_ptr)) != NULL)) { - if (port_str) { - host = host_port; - tx_port = stoi(port_str); + log_msg(LOG_LEVEL_NOTICE, "%s", buffer); + r = new_response(RESPONSE_OK, buffer); + free_message((struct message *) msg, r); + continue; + } else if (strncasecmp(msg->text, "list-ports", strlen("list-ports")) == 0 || + strncasecmp(msg->text, "query-ports", strlen("query-ports")) == 0) { + char buffer[2048]; + // List all current root ports and their IP addresses + string port_list = "\n"; + if (s->replicas.empty()) { + port_list += " No ports configured.\n"; } else { - tx_port = stoi(strrchr(host_port, ':') + 1); - host = host_port; - *strrchr(host_port, ':') = '\0'; - } - // handle square brackets around an IPv6 address - if (host[0] == '[' && host[strlen(host) - 1] == ']') { - host += 1; - host[strlen(host) - 1] = '\0'; + for (size_t i = 0; i < s->replicas.size(); i++) { + const auto& replica = s->replicas[i]; + const char* type_str = (replica->type == replica::type_t::USE_SOCK) ? "forwarding" : + (replica->type == replica::type_t::RECOMPRESS) ? "transcoding" : "none"; + char port_info[512]; + snprintf(port_info, sizeof(port_info), "[%zu] %s:%d (%s) - %s\n", + i, replica->ip_address.c_str(), replica->m_tx_port, + replica->mod.name, type_str); + port_list += port_info; // FIXED: was port_list += port_list + } } - } else { - const char *err_msg = "wrong format"; - log_msg(LOG_LEVEL_ERROR, "%s\n", err_msg); - free_message((struct message *) msg, new_response(RESPONSE_BAD_REQUEST, err_msg)); + snprintf(buffer, sizeof(buffer), "Ports: %s\n", port_list.c_str()); + log_msg(LOG_LEVEL_NOTICE, "%s", buffer); + r = new_response(RESPONSE_OK, buffer); + free_message((struct message *) msg, r); continue; - } - char *compress = strtok_r(NULL, " ", &save_ptr); + } else if (strncasecmp(msg->text, "create-port", strlen("create-port")) == 0) { + // format of parameters is either: + // : [] + // or (for compat with older CoUniverse version) + // [] + char buffer[2048]; + char *host_port, *port_str = NULL, *save_ptr; + char *host; + int tx_port; + strtok_r(msg->text, " ", &save_ptr); + host_port = strtok_r(NULL, " ", &save_ptr); + if (host_port && (strchr(host_port, ':') != NULL || (port_str = strtok_r(NULL, " ", &save_ptr)) != NULL)) { + if (port_str) { + host = host_port; + tx_port = stoi(port_str); + } else { + tx_port = stoi(strrchr(host_port, ':') + 1); + host = host_port; + *strrchr(host_port, ':') = '\0'; + } + // handle square brackets around an IPv6 address + if (host[0] == '[' && host[strlen(host) - 1] == ']') { + host += 1; + host[strlen(host) - 1] = '\0'; + } + } else { + const char *err_msg = "wrong format\n"; + log_msg(LOG_LEVEL_ERROR, "%s\n", err_msg); + free_message((struct message *) msg, new_response(RESPONSE_BAD_REQUEST, err_msg)); + continue; + } + char *compress = strtok_r(NULL, " ", &save_ptr); - struct common_opts opts = { COMMON_OPTS_INIT }; - int idx = create_output_port(s, - host, 0, tx_port, s->bufsize, &opts, - compress, nullptr, RATE_UNLIMITED, s->server_socket != nullptr); + // Check if a replica with the same host and port already exists + bool exists = false; + for (auto r : s->replicas) { + if (r->ip_address == host && r->m_tx_port == tx_port) { + exists = true; + break; + } + } - if(idx < 0) { - free_message((struct message *) msg, new_response(RESPONSE_INT_SERV_ERR, "Cannot create output port.")); - continue; - } + if (exists) { + log_msg(LOG_LEVEL_ERROR, "Output port %s:%d already exists.\n", host, tx_port); + r = new_response(RESPONSE_CONFLICT, "Port already exists\n"); + free_message((struct message *) msg, r); + continue; + } - if(compress) - log_msg(LOG_LEVEL_NOTICE, "Created new transcoding output port %s:%d:0x%08" PRIx32 ".\n", host, tx_port, recompress_get_port_ssrc(s->recompress, idx)); - else - log_msg(LOG_LEVEL_NOTICE, "Created new forwarding output port %s:%d.\n", host, tx_port); + struct common_opts opts = { COMMON_OPTS_INIT }; + int idx = create_output_port(s, + host, 0, tx_port, s->bufsize, &opts, + compress, nullptr, RATE_UNLIMITED, s->server_socket != nullptr); - } else { - r = new_response(RESPONSE_BAD_REQUEST, NULL); - } + if(idx < 0) { + r = new_response(RESPONSE_INT_SERV_ERR, "Cannot create output port.\n"); + continue; + } - free_message((struct message *) msg, r ? r : new_response(RESPONSE_OK, NULL)); + if(compress) { + snprintf(buffer, sizeof(buffer), "Created new transcoding output port %s:%d:0x%08" PRIx32 ".\n", host, tx_port, recompress_get_port_ssrc(s->recompress, idx)); + } else { + snprintf(buffer, sizeof(buffer), "Created new forwarding output port %s:%d.\n", host, tx_port); + } + log_msg(LOG_LEVEL_NOTICE, "%s", buffer); + r = new_response(RESPONSE_OK, buffer); + free_message((struct message *) msg, r); + continue; + } } - // then process incoming packets while (s->qhead != s->qtail) { if(s->qhead->size == 0) { // poisoned pill @@ -482,7 +584,7 @@ static void *writer(void *arg) // distribute it to output ports that don't need transcoding #ifdef _WIN32 - // send it asynchronously in MSW (performance optimalization) + // send it asynchronously in MSW (performance optimization) SleepEx(0, true); // allow system to call our completion routines in APC int ref = 0; for (unsigned int i = 0; i < s->replicas.size(); i++) { @@ -525,14 +627,14 @@ static void *writer(void *arg) pthread_cond_signal(&s->qfull_cond); pthread_mutex_unlock(&s->qfull_mtx); } - pthread_mutex_lock(&s->qempty_mtx); - if (s->qempty) + if (s->qempty) { + // Wait indefinitely - we'll be woken up by new packets or messages pthread_cond_wait(&s->qempty_cond, &s->qempty_mtx); + } s->qempty = 1; pthread_mutex_unlock(&s->qempty_mtx); } - return NULL; } diff --git a/src/messaging.h b/src/messaging.h index 8e93c1f4a..8b8e320e4 100644 --- a/src/messaging.h +++ b/src/messaging.h @@ -62,6 +62,7 @@ struct response; #define RESPONSE_BAD_REQUEST 400 #define RESPONSE_NOT_FOUND 404 #define RESPONSE_REQ_TIMEOUT 408 +#define RESPONSE_CONFLICT 409 #define RESPONSE_INT_SERV_ERR 500 #define RESPONSE_NOT_IMPL 501 diff --git a/src/video_capture/deltacast_dvi.cpp b/src/video_capture/deltacast_dvi.cpp index 3c634f970..b48b74b8b 100644 --- a/src/video_capture/deltacast_dvi.cpp +++ b/src/video_capture/deltacast_dvi.cpp @@ -729,9 +729,9 @@ vidcap_deltacast_dvi_done(void *state) VHD_GetStreamProperty(s->StreamHandle, VHD_CORE_SP_SLOTS_COUNT, &SlotsCount); log_msg(SlotsDropped > 0 ? LOG_LEVEL_WARNING : LOG_LEVEL_INFO, - "%" PRIu_ULONG " frames %s (%" PRIu_ULONG + "%" PRIu_ULONG " frames received (%" PRIu_ULONG " dropped)\n", - SlotsCount, "hh", SlotsDropped); + SlotsCount, SlotsDropped); VHD_StopStream(s->StreamHandle); VHD_CloseStreamHandle(s->StreamHandle);