Merge pull request #2911 from hax0kartik/dl-curl

Dynamically load libcurl, libvlc and libvnc
This commit is contained in:
Isaac Connor 2020-04-22 09:49:37 -04:00 committed by GitHub
commit 4b53c7660e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 279 additions and 108 deletions

View File

@ -324,7 +324,7 @@ if(NOT ZM_NO_CURL)
find_package(CURL) find_package(CURL)
if(CURL_FOUND) if(CURL_FOUND)
set(HAVE_LIBCURL 1) set(HAVE_LIBCURL 1)
list(APPEND ZM_BIN_LIBS ${CURL_LIBRARIES}) #list(APPEND ZM_BIN_LIBS ${CURL_LIBRARIES})
include_directories(${CURL_INCLUDE_DIRS}) include_directories(${CURL_INCLUDE_DIRS})
set(CMAKE_REQUIRED_INCLUDES ${CURL_INCLUDE_DIRS}) set(CMAKE_REQUIRED_INCLUDES ${CURL_INCLUDE_DIRS})
check_include_file("curl/curl.h" HAVE_CURL_CURL_H) check_include_file("curl/curl.h" HAVE_CURL_CURL_H)
@ -363,8 +363,9 @@ else(LIBJWT_FOUND)
endif(LIBJWT_FOUND) endif(LIBJWT_FOUND)
# gnutls (using find_library and find_path) # gnutls (using find_library and find_path)
find_library(GNUTLS_LIBRARIES gnutls) if(HAVE_LIBJWT)
if(GNUTLS_LIBRARIES) find_library(GNUTLS_LIBRARIES gnutls)
if(GNUTLS_LIBRARIES)
set(HAVE_LIBGNUTLS 1) set(HAVE_LIBGNUTLS 1)
list(APPEND ZM_BIN_LIBS "${GNUTLS_LIBRARIES}") list(APPEND ZM_BIN_LIBS "${GNUTLS_LIBRARIES}")
find_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h) find_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h)
@ -375,9 +376,10 @@ if(GNUTLS_LIBRARIES)
mark_as_advanced(FORCE GNUTLS_LIBRARIES GNUTLS_INCLUDE_DIR) mark_as_advanced(FORCE GNUTLS_LIBRARIES GNUTLS_INCLUDE_DIR)
check_include_file("gnutls/gnutls.h" HAVE_GNUTLS_GNUTLS_H) check_include_file("gnutls/gnutls.h" HAVE_GNUTLS_GNUTLS_H)
set(optlibsfound "${optlibsfound} GnuTLS") set(optlibsfound "${optlibsfound} GnuTLS")
else(GNUTLS_LIBRARIES) else(GNUTLS_LIBRARIES)
set(optlibsnotfound "${optlibsnotfound} GnuTLS") set(optlibsnotfound "${optlibsnotfound} GnuTLS")
endif(GNUTLS_LIBRARIES) endif(GNUTLS_LIBRARIES)
endif(HAVE_LIBJWT)
# OpenSSL # OpenSSL
if(NOT HAVE_LIBGNUTLS OR NOT HAVE_LIBJWT) if(NOT HAVE_LIBGNUTLS OR NOT HAVE_LIBJWT)
@ -665,7 +667,7 @@ if(NOT ZM_NO_LIBVLC)
find_library(LIBVLC_LIBRARIES vlc) find_library(LIBVLC_LIBRARIES vlc)
if(LIBVLC_LIBRARIES) if(LIBVLC_LIBRARIES)
set(HAVE_LIBVLC 1) set(HAVE_LIBVLC 1)
list(APPEND ZM_BIN_LIBS "${LIBVLC_LIBRARIES}") #list(APPEND ZM_BIN_LIBS "${LIBVLC_LIBRARIES}")
find_path(LIBVLC_INCLUDE_DIR "vlc/vlc.h") find_path(LIBVLC_INCLUDE_DIR "vlc/vlc.h")
if(LIBVLC_INCLUDE_DIR) if(LIBVLC_INCLUDE_DIR)
include_directories("${LIBVLC_INCLUDE_DIR}") include_directories("${LIBVLC_INCLUDE_DIR}")
@ -684,7 +686,7 @@ if(NOT ZM_NO_LIBVNC)
find_library(LIBVNC_LIBRARIES vncclient) find_library(LIBVNC_LIBRARIES vncclient)
if(LIBVNC_LIBRARIES) if(LIBVNC_LIBRARIES)
set(HAVE_LIBVNC 1) set(HAVE_LIBVNC 1)
list(APPEND ZM_BIN_LIBS "${LIBVNC_LIBRARIES}") #list(APPEND ZM_BIN_LIBS "${LIBVNC_LIBRARIES}")
find_path(LIBVNC_INCLUDE_DIR "rfb/rfb.h") find_path(LIBVNC_INCLUDE_DIR "rfb/rfb.h")
if(LIBVNC_INCLUDE_DIR) if(LIBVNC_INCLUDE_DIR)
include_directories("${LIBVNC_INCLUDE_DIR}") include_directories("${LIBVNC_INCLUDE_DIR}")
@ -773,9 +775,9 @@ if(HAVE_GNUTLS_GNUTLS_H)
HAVE_DECL_GNUTLS_FINGERPRINT) HAVE_DECL_GNUTLS_FINGERPRINT)
endif(HAVE_GNUTLS_GNUTLS_H) endif(HAVE_GNUTLS_GNUTLS_H)
if(HAVE_MD5_OPENSSL) if(NOT HAVE_DECL_GNUTLS_FINGERPRINT AND HAVE_MD5_OPENSSL)
set(HAVE_DECL_MD5 1) set(HAVE_DECL_MD5 1)
endif(HAVE_MD5_OPENSSL) endif(NOT HAVE_DECL_GNUTLS_FINGERPRINT AND HAVE_MD5_OPENSSL)
if((NOT HAVE_MD5_OPENSSL) AND (NOT HAVE_DECL_GNUTLS_FINGERPRINT)) if((NOT HAVE_MD5_OPENSSL) AND (NOT HAVE_DECL_GNUTLS_FINGERPRINT))
message(AUTHOR_WARNING message(AUTHOR_WARNING

View File

@ -17,6 +17,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// //
#include <dlfcn.h>
#include "zm.h" #include "zm.h"
#include "zm_curl_camera.h" #include "zm_curl_camera.h"
@ -25,6 +26,18 @@
#if HAVE_LIBCURL #if HAVE_LIBCURL
/* Func ptrs for libcurl functions */
static void *curl_lib = nullptr;
static CURLcode (*curl_global_init_f)(long) = nullptr;
static void (*curl_global_cleanup_f)(void) = nullptr;
static const char* (*curl_easy_strerror_f)(CURLcode) = nullptr;
static char* (*curl_version_f)(void) = nullptr;
static CURL* (*curl_easy_init_f)(void) = nullptr;
static CURLcode (*curl_easy_getinfo_f)(CURL* , CURLINFO, ...) = nullptr;
static CURLcode (*curl_easy_perform_f)(CURL*) = nullptr;
static CURLcode (*curl_easy_setopt_f)(CURL*, CURLoption, ...) = nullptr;
static void (*curl_easy_cleanup_f)(CURL*) = nullptr;
#define CURL_MAXRETRY 5 #define CURL_MAXRETRY 5
#define CURL_BUFFER_INITIAL_SIZE 65536 #define CURL_BUFFER_INITIAL_SIZE 65536
@ -33,6 +46,31 @@ const char* content_type_match = "Content-Type:";
size_t content_length_match_len; size_t content_length_match_len;
size_t content_type_match_len; size_t content_type_match_len;
void bind_libcurl_symbols() {
if(curl_lib)
return;
curl_lib = dlopen("libcurl.so", RTLD_LAZY | RTLD_GLOBAL);
if(!curl_lib)
curl_lib = dlopen("libcurl-gnutls.so.4", RTLD_LAZY | RTLD_GLOBAL);
if (!curl_lib) {
Error("Could not load libcurl: %s", dlerror());
return;
}
// Load up all required symbols here
*(void**) (&curl_global_init_f) = dlsym(curl_lib, "curl_global_init");
*(void**) (&curl_global_cleanup_f) = dlsym(curl_lib, "curl_global_cleanup");
*(void**) (&curl_easy_strerror_f) = dlsym(curl_lib, "curl_easy_strerror");
*(void**) (&curl_version_f) = dlsym(curl_lib, "curl_version");
*(void**) (&curl_easy_init_f) = dlsym(curl_lib, "curl_easy_init");
*(void**) (&curl_easy_getinfo_f) = dlsym(curl_lib, "curl_easy_getinfo");
*(void**) (&curl_easy_perform_f) = dlsym(curl_lib, "curl_easy_perform");
*(void**) (&curl_easy_setopt_f) = dlsym(curl_lib, "curl_easy_setopt");
*(void**) (&curl_easy_cleanup_f) = dlsym(curl_lib, "curl_easy_cleanup");
}
cURLCamera::cURLCamera( int p_id, const std::string &p_path, const std::string &p_user, const std::string &p_pass, unsigned int p_width, unsigned int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : cURLCamera::cURLCamera( int p_id, const std::string &p_path, const std::string &p_user, const std::string &p_pass, unsigned int p_width, unsigned int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) :
Camera( p_id, CURL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), Camera( p_id, CURL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ),
mPath( p_path ), mUser( p_user ), mPass ( p_pass ), bTerminate( false ), bReset( false ), mode ( MODE_UNSET ) mPath( p_path ), mUser( p_user ), mPass ( p_pass ), bTerminate( false ), bReset( false ), mode ( MODE_UNSET )
@ -56,34 +94,41 @@ void cURLCamera::Initialise() {
databuffer.expand(CURL_BUFFER_INITIAL_SIZE); databuffer.expand(CURL_BUFFER_INITIAL_SIZE);
bind_libcurl_symbols();
/* cURL initialization */ /* cURL initialization */
CURLcode cRet = curl_global_init(CURL_GLOBAL_ALL); CURLcode cRet = (*curl_global_init_f)(CURL_GLOBAL_ALL);
if(cRet != CURLE_OK) { if(cRet != CURLE_OK) {
Fatal("libcurl initialization failed: ", curl_easy_strerror(cRet)); Error("libcurl initialization failed: ", (*curl_easy_strerror_f)(cRet));
dlclose(curl_lib);
return;
} }
Debug(2,"libcurl version: %s",curl_version()); Debug(2,"libcurl version: %s", (*curl_version_f)());
/* Create the shared data mutex */ /* Create the shared data mutex */
int nRet = pthread_mutex_init(&shareddata_mutex, NULL); int nRet = pthread_mutex_init(&shareddata_mutex, NULL);
if(nRet != 0) { if(nRet != 0) {
Fatal("Shared data mutex creation failed: %s",strerror(nRet)); Error("Shared data mutex creation failed: %s",strerror(nRet));
return;
} }
/* Create the data available condition variable */ /* Create the data available condition variable */
nRet = pthread_cond_init(&data_available_cond, NULL); nRet = pthread_cond_init(&data_available_cond, NULL);
if(nRet != 0) { if(nRet != 0) {
Fatal("Data available condition variable creation failed: %s",strerror(nRet)); Error("Data available condition variable creation failed: %s",strerror(nRet));
return;
} }
/* Create the request complete condition variable */ /* Create the request complete condition variable */
nRet = pthread_cond_init(&request_complete_cond, NULL); nRet = pthread_cond_init(&request_complete_cond, NULL);
if(nRet != 0) { if(nRet != 0) {
Fatal("Request complete condition variable creation failed: %s",strerror(nRet)); Error("Request complete condition variable creation failed: %s",strerror(nRet));
return;
} }
/* Create the thread */ /* Create the thread */
nRet = pthread_create(&thread, NULL, thread_func_dispatcher, this); nRet = pthread_create(&thread, NULL, thread_func_dispatcher, this);
if(nRet != 0) { if(nRet != 0) {
Fatal("Thread creation failed: %s",strerror(nRet)); Error("Thread creation failed: %s",strerror(nRet));
return;
} }
} }
@ -102,8 +147,10 @@ void cURLCamera::Terminate() {
pthread_mutex_destroy(&shareddata_mutex); pthread_mutex_destroy(&shareddata_mutex);
/* cURL cleanup */ /* cURL cleanup */
curl_global_cleanup(); (*curl_global_cleanup_f)();
if(curl_lib)
dlclose(curl_lib);
} }
int cURLCamera::PrimeCapture() { int cURLCamera::PrimeCapture() {
@ -287,7 +334,8 @@ int cURLCamera::Capture( Image &image ) {
} }
} else { } else {
/* Failed to match content-type */ /* Failed to match content-type */
Fatal("Unable to match Content-Type. Check URL, username and password"); Error("Unable to match Content-Type. Check URL, username and password");
return -21;
} /* mode */ } /* mode */
} /* frameComplete loop */ } /* frameComplete loop */
@ -376,60 +424,88 @@ void* cURLCamera::thread_func() {
long tRet; long tRet;
double dSize; double dSize;
c = curl_easy_init(); c = (*curl_easy_init_f)();
if(c == NULL) { if(c == NULL) {
Fatal("Failed getting easy handle from libcurl"); dlclose(curl_lib);
Error("Failed getting easy handle from libcurl");
tRet = -51;
return (void*)tRet;
} }
CURLcode cRet; CURLcode cRet;
/* Set URL */ /* Set URL */
cRet = curl_easy_setopt(c, CURLOPT_URL, mPath.c_str()); cRet = (*curl_easy_setopt_f)(c, CURLOPT_URL, mPath.c_str());
if(cRet != CURLE_OK) if(cRet != CURLE_OK) {
Fatal("Failed setting libcurl URL: %s", curl_easy_strerror(cRet)); Error("Failed setting libcurl URL: %s", *(curl_easy_strerror_f)(cRet));
tRet = -52;
return (void*)tRet;
}
/* Header callback */ /* Header callback */
cRet = curl_easy_setopt(c, CURLOPT_HEADERFUNCTION, &header_callback_dispatcher); cRet = (*curl_easy_setopt_f)(c, CURLOPT_HEADERFUNCTION, &header_callback_dispatcher);
if(cRet != CURLE_OK) if(cRet != CURLE_OK) {
Fatal("Failed setting libcurl header callback function: %s", curl_easy_strerror(cRet)); Error("Failed setting libcurl header callback function: %s", (*curl_easy_strerror_f)(cRet));
cRet = curl_easy_setopt(c, CURLOPT_HEADERDATA, this); tRet = -53;
if(cRet != CURLE_OK) return (void*)tRet;
Fatal("Failed setting libcurl header callback object: %s", curl_easy_strerror(cRet)); }
cRet = (*curl_easy_setopt_f)(c, CURLOPT_HEADERDATA, this);
if(cRet != CURLE_OK) {
Error("Failed setting libcurl header callback object: %s", (*curl_easy_strerror_f)(cRet));
tRet = -54;
return (void*)tRet;
}
/* Data callback */ /* Data callback */
cRet = curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, &data_callback_dispatcher); cRet = (*curl_easy_setopt_f)(c, CURLOPT_WRITEFUNCTION, &data_callback_dispatcher);
if(cRet != CURLE_OK) if(cRet != CURLE_OK) {
Fatal("Failed setting libcurl data callback function: %s", curl_easy_strerror(cRet)); Error("Failed setting libcurl data callback function: %s", (*curl_easy_strerror_f)(cRet));
cRet = curl_easy_setopt(c, CURLOPT_WRITEDATA, this); tRet = -55;
if(cRet != CURLE_OK) return (void*)tRet;
Fatal("Failed setting libcurl data callback object: %s", curl_easy_strerror(cRet)); }
cRet = (*curl_easy_setopt_f)(c, CURLOPT_WRITEDATA, this);
if(cRet != CURLE_OK) {
Error("Failed setting libcurl data callback object: %s", (*curl_easy_strerror_f)(cRet));
tRet = -56;
return (void*)tRet;
}
/* Progress callback */ /* Progress callback */
cRet = curl_easy_setopt(c, CURLOPT_NOPROGRESS, 0); cRet = (*curl_easy_setopt_f)(c, CURLOPT_NOPROGRESS, 0);
if(cRet != CURLE_OK) if(cRet != CURLE_OK) {
Fatal("Failed enabling libcurl progress callback function: %s", curl_easy_strerror(cRet)); Error("Failed enabling libcurl progress callback function: %s", (*curl_easy_strerror_f)(cRet));
cRet = curl_easy_setopt(c, CURLOPT_PROGRESSFUNCTION, &progress_callback_dispatcher); tRet = -57;
if(cRet != CURLE_OK) return (void*)tRet;
Fatal("Failed setting libcurl progress callback function: %s", curl_easy_strerror(cRet)); }
cRet = curl_easy_setopt(c, CURLOPT_PROGRESSDATA, this);
if(cRet != CURLE_OK)
Fatal("Failed setting libcurl progress callback object: %s", curl_easy_strerror(cRet));
cRet = (*curl_easy_setopt_f)(c, CURLOPT_PROGRESSFUNCTION, &progress_callback_dispatcher);
if(cRet != CURLE_OK) {
Error("Failed setting libcurl progress callback function: %s", (*curl_easy_strerror_f)(cRet));
tRet = -58;
return (void*)tRet;
}
cRet = (*curl_easy_setopt_f)(c, CURLOPT_PROGRESSDATA, this);
if(cRet != CURLE_OK) {
Error("Failed setting libcurl progress callback object: %s", (*curl_easy_strerror_f)(cRet));
tRet = -59;
return (void*)tRet;
}
/* Set username and password */ /* Set username and password */
if(!mUser.empty()) { if(!mUser.empty()) {
cRet = curl_easy_setopt(c, CURLOPT_USERNAME, mUser.c_str()); cRet = (*curl_easy_setopt_f)(c, CURLOPT_USERNAME, mUser.c_str());
if(cRet != CURLE_OK) if(cRet != CURLE_OK)
Error("Failed setting username: %s", curl_easy_strerror(cRet)); Error("Failed setting username: %s", (*curl_easy_strerror_f)(cRet));
} }
if(!mPass.empty()) { if(!mPass.empty()) {
cRet = curl_easy_setopt(c, CURLOPT_PASSWORD, mPass.c_str()); cRet = (*curl_easy_setopt_f)(c, CURLOPT_PASSWORD, mPass.c_str());
if(cRet != CURLE_OK) if(cRet != CURLE_OK)
Error("Failed setting password: %s", curl_easy_strerror(cRet)); Error("Failed setting password: %s", (*curl_easy_strerror_f)(cRet));
} }
/* Authenication preference */ /* Authenication preference */
cRet = curl_easy_setopt(c, CURLOPT_HTTPAUTH, CURLAUTH_ANY); cRet = (*curl_easy_setopt_f)(c, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
if(cRet != CURLE_OK) if(cRet != CURLE_OK)
Warning("Failed setting libcurl acceptable http authenication methods: %s", curl_easy_strerror(cRet)); Warning("Failed setting libcurl acceptable http authenication methods: %s", (*curl_easy_strerror_f)(cRet));
/* Work loop */ /* Work loop */
@ -437,14 +513,14 @@ void* cURLCamera::thread_func() {
tRet = 0; tRet = 0;
while(!bTerminate) { while(!bTerminate) {
/* Do the work */ /* Do the work */
cRet = curl_easy_perform(c); cRet = (*curl_easy_perform_f)(c);
if(mode == MODE_SINGLE) { if(mode == MODE_SINGLE) {
if(cRet != CURLE_OK) { if(cRet != CURLE_OK) {
break; break;
} }
/* Attempt to get the size of the file */ /* Attempt to get the size of the file */
cRet = curl_easy_getinfo(c, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dSize); cRet = (*curl_easy_getinfo_f)(c, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dSize);
if(cRet != CURLE_OK) { if(cRet != CURLE_OK) {
break; break;
} }
@ -454,12 +530,16 @@ void* cURLCamera::thread_func() {
if(dSize > 0) { if(dSize > 0) {
single_offsets.push_back(dSize); single_offsets.push_back(dSize);
} else { } else {
Fatal("Unable to get the size of the image"); Error("Unable to get the size of the image");
tRet = -60;
return (void*)tRet;
} }
/* Signal the request complete condition variable */ /* Signal the request complete condition variable */
tRet = pthread_cond_signal(&request_complete_cond); tRet = pthread_cond_signal(&request_complete_cond);
if(tRet != 0) { if(tRet != 0) {
Error("Failed signaling request completed condition variable: %s",strerror(tRet)); Error("Failed signaling request completed condition variable: %s",strerror(tRet));
tRet = -61;
return (void*)tRet;
} }
/* Unlock */ /* Unlock */
unlock(); unlock();
@ -475,7 +555,7 @@ void* cURLCamera::thread_func() {
break; break;
} else if (cRet != CURLE_OK) { } else if (cRet != CURLE_OK) {
/* Some error */ /* Some error */
Error("cURL Request failed: %s",curl_easy_strerror(cRet)); Error("cURL Request failed: %s",(*curl_easy_strerror_f)(cRet));
if(attempt < CURL_MAXRETRY) { if(attempt < CURL_MAXRETRY) {
Error("Retrying.. Attempt %d of %d",attempt,CURL_MAXRETRY); Error("Retrying.. Attempt %d of %d",attempt,CURL_MAXRETRY);
/* Do a reset */ /* Do a reset */
@ -491,7 +571,7 @@ void* cURLCamera::thread_func() {
} }
/* Cleanup */ /* Cleanup */
curl_easy_cleanup(c); (*curl_easy_cleanup_f)(c);
c = NULL; c = NULL;
return (void*)tRet; return (void*)tRet;

View File

@ -17,12 +17,51 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <dlfcn.h>
#include "zm.h" #include "zm.h"
#include "zm_signal.h" #include "zm_signal.h"
#include "zm_libvlc_camera.h" #include "zm_libvlc_camera.h"
#if HAVE_LIBVLC #if HAVE_LIBVLC
static void *libvlc_lib = nullptr;
static void (*libvlc_media_player_release_f)(libvlc_media_player_t* ) = nullptr;
static void (*libvlc_media_release_f)(libvlc_media_t* ) = nullptr;
static void (*libvlc_release_f)(libvlc_instance_t* ) = nullptr;
static void (*libvlc_media_player_stop_f)(libvlc_media_player_t* ) = nullptr;
static libvlc_instance_t* (*libvlc_new_f)(int, const char* const *) = nullptr;
static void (*libvlc_log_set_f)(libvlc_instance_t*, libvlc_log_cb, void *) = nullptr;
static libvlc_media_t* (*libvlc_media_new_location_f)(libvlc_instance_t*, const char*) = nullptr;
static libvlc_media_player_t* (*libvlc_media_player_new_from_media_f)(libvlc_media_t*) = nullptr;
static void (*libvlc_video_set_format_f)(libvlc_media_player_t*, const char*, unsigned, unsigned, unsigned) = nullptr;
static void (*libvlc_video_set_callbacks_f)(libvlc_media_player_t*, libvlc_video_lock_cb, libvlc_video_unlock_cb, libvlc_video_display_cb, void*) = nullptr;
static int (*libvlc_media_player_play_f)(libvlc_media_player_t *) = nullptr;
static const char* (*libvlc_errmsg_f)(void) = nullptr;
static const char* (*libvlc_get_version_f)(void) = nullptr;
void bind_libvlc_symbols() {
if(libvlc_lib != nullptr) // Safe-check
return;
libvlc_lib = dlopen("libvlc.so", RTLD_LAZY | RTLD_GLOBAL);
if(!libvlc_lib){
Error("Error loading libvlc: %s", dlerror());
return;
}
*(void**) (&libvlc_media_player_release_f) = dlsym(libvlc_lib, "libvlc_media_player_release");
*(void**) (&libvlc_media_release_f) = dlsym(libvlc_lib, "libvlc_media_release");
*(void**) (&libvlc_release_f) = dlsym(libvlc_lib, "libvlc_release");
*(void**) (&libvlc_media_player_stop_f) = dlsym(libvlc_lib, "libvlc_media_player_stop");
*(void**) (&libvlc_new_f) = dlsym(libvlc_lib, "libvlc_new");
*(void**) (&libvlc_log_set_f) = dlsym(libvlc_lib, "libvlc_log_set");
*(void**) (&libvlc_media_new_location_f) = dlsym(libvlc_lib, "libvlc_media_new_location");
*(void**) (&libvlc_media_player_new_from_media_f) = dlsym(libvlc_lib, "libvlc_media_player_new_from_media");
*(void**) (&libvlc_video_set_format_f) = dlsym(libvlc_lib, "libvlc_video_set_format");
*(void**) (&libvlc_video_set_callbacks_f) = dlsym(libvlc_lib, "libvlc_video_set_callbacks");
*(void**) (&libvlc_media_player_play_f) = dlsym(libvlc_lib, "libvlc_media_player_play");
*(void**) (&libvlc_errmsg_f) = dlsym(libvlc_lib, "libvlc_errmsg");
*(void**) (&libvlc_get_version_f) = dlsym(libvlc_lib, "libvlc_get_version");
}
// Do all the buffer checking work here to avoid unnecessary locking // Do all the buffer checking work here to avoid unnecessary locking
void* LibvlcLockBuffer(void* opaque, void** planes) { void* LibvlcLockBuffer(void* opaque, void** planes) {
LibvlcPrivateData* data = reinterpret_cast<LibvlcPrivateData*>(opaque); LibvlcPrivateData* data = reinterpret_cast<LibvlcPrivateData*>(opaque);
@ -125,15 +164,15 @@ LibvlcCamera::~LibvlcCamera() {
Terminate(); Terminate();
} }
if ( mLibvlcMediaPlayer != NULL ) { if ( mLibvlcMediaPlayer != NULL ) {
libvlc_media_player_release(mLibvlcMediaPlayer); (*libvlc_media_player_release_f)(mLibvlcMediaPlayer);
mLibvlcMediaPlayer = NULL; mLibvlcMediaPlayer = NULL;
} }
if ( mLibvlcMedia != NULL ) { if ( mLibvlcMedia != NULL ) {
libvlc_media_release(mLibvlcMedia); (*libvlc_media_release_f)(mLibvlcMedia);
mLibvlcMedia = NULL; mLibvlcMedia = NULL;
} }
if ( mLibvlcInstance != NULL ) { if ( mLibvlcInstance != NULL ) {
libvlc_release(mLibvlcInstance); (*libvlc_release_f)(mLibvlcInstance);
mLibvlcInstance = NULL; mLibvlcInstance = NULL;
} }
if ( mOptArgV != NULL ) { if ( mOptArgV != NULL ) {
@ -142,14 +181,16 @@ LibvlcCamera::~LibvlcCamera() {
} }
void LibvlcCamera::Initialise() { void LibvlcCamera::Initialise() {
bind_libvlc_symbols();
} }
void LibvlcCamera::Terminate() { void LibvlcCamera::Terminate() {
libvlc_media_player_stop(mLibvlcMediaPlayer); (*libvlc_media_player_stop_f)(mLibvlcMediaPlayer);
if ( mLibvlcData.buffer ) { if ( mLibvlcData.buffer ) {
zm_freealigned(mLibvlcData.buffer); zm_freealigned(mLibvlcData.buffer);
mLibvlcData.buffer = NULL; mLibvlcData.buffer = NULL;
} }
if ( mLibvlcData.prevBuffer ) { if ( mLibvlcData.prevBuffer ) {
zm_freealigned(mLibvlcData.prevBuffer); zm_freealigned(mLibvlcData.prevBuffer);
mLibvlcData.prevBuffer = NULL; mLibvlcData.prevBuffer = NULL;
@ -158,6 +199,7 @@ void LibvlcCamera::Terminate() {
int LibvlcCamera::PrimeCapture() { int LibvlcCamera::PrimeCapture() {
Info("Priming capture from %s", mPath.c_str()); Info("Priming capture from %s", mPath.c_str());
Info("Libvlc Version %s", (*libvlc_get_version_f)());
StringVector opVect = split(Options(), ","); StringVector opVect = split(Options(), ",");
@ -181,28 +223,28 @@ int LibvlcCamera::PrimeCapture() {
} }
} }
mLibvlcInstance = libvlc_new(opVect.size(), (const char* const*)mOptArgV); mLibvlcInstance = (*libvlc_new_f)(opVect.size(), (const char* const*)mOptArgV);
if ( mLibvlcInstance == NULL ) { if ( mLibvlcInstance == NULL ) {
Error("Unable to create libvlc instance due to: %s", libvlc_errmsg()); Error("Unable to create libvlc instance due to: %s", (*libvlc_errmsg_f)());
return -1; return -1;
} }
libvlc_log_set(mLibvlcInstance, LibvlcCamera::log_callback, NULL); (*libvlc_log_set_f)(mLibvlcInstance, LibvlcCamera::log_callback, NULL);
mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str()); mLibvlcMedia = (*libvlc_media_new_location_f)(mLibvlcInstance, mPath.c_str());
if ( mLibvlcMedia == NULL ) { if ( mLibvlcMedia == NULL ) {
Error("Unable to open input %s due to: %s", mPath.c_str(), libvlc_errmsg()); Error("Unable to open input %s due to: %s", mPath.c_str(), (*libvlc_errmsg_f)());
return -1; return -1;
} }
mLibvlcMediaPlayer = libvlc_media_player_new_from_media(mLibvlcMedia); mLibvlcMediaPlayer = (*libvlc_media_player_new_from_media_f)(mLibvlcMedia);
if ( mLibvlcMediaPlayer == NULL ) { if ( mLibvlcMediaPlayer == NULL ) {
Error("Unable to create player for %s due to: %s", mPath.c_str(), libvlc_errmsg()); Error("Unable to create player for %s due to: %s", mPath.c_str(), (*libvlc_errmsg_f)());
return -1; return -1;
} }
libvlc_video_set_format(mLibvlcMediaPlayer, mTargetChroma.c_str(), width, height, width * mBpp); (*libvlc_video_set_format_f)(mLibvlcMediaPlayer, mTargetChroma.c_str(), width, height, width * mBpp);
libvlc_video_set_callbacks(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, NULL, &mLibvlcData); (*libvlc_video_set_callbacks_f)(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, NULL, &mLibvlcData);
mLibvlcData.bufferSize = width * height * mBpp; mLibvlcData.bufferSize = width * height * mBpp;
// Libvlc wants 32 byte alignment for images (should in theory do this for all image lines) // Libvlc wants 32 byte alignment for images (should in theory do this for all image lines)
@ -211,7 +253,7 @@ int LibvlcCamera::PrimeCapture() {
mLibvlcData.newImage.setValueImmediate(false); mLibvlcData.newImage.setValueImmediate(false);
libvlc_media_player_play(mLibvlcMediaPlayer); (*libvlc_media_player_play_f)(mLibvlcMediaPlayer);
return 0; return 0;
} }

View File

@ -1,3 +1,4 @@
#include <dlfcn.h>
#include "zm.h" #include "zm.h"
#include "zm_signal.h" #include "zm_signal.h"
#include "zm_libvnc_camera.h" #include "zm_libvnc_camera.h"
@ -8,14 +9,41 @@
static int TAG_0; static int TAG_0;
static int TAG_1; static int TAG_1;
static int TAG_2; static int TAG_2;
static void *libvnc_lib = nullptr;
static void *(*rfbClientGetClientData_f)(rfbClient*, void*) = nullptr;
static rfbClient *(*rfbGetClient_f)(int, int, int) = nullptr;
static void (*rfbClientSetClientData_f)(rfbClient*, void*, void*) = nullptr;
static rfbBool (*rfbInitClient_f)(rfbClient*, int*, char**) = nullptr;
static void (*rfbClientCleanup_f)(rfbClient*) = nullptr;
static int (*WaitForMessage_f)(rfbClient*, unsigned int) = nullptr;
static rfbBool (*HandleRFBServerMessage_f)(rfbClient*) = nullptr;
void bind_libvnc_symbols() {
if(libvnc_lib != nullptr) // Safe-check
return;
libvnc_lib = dlopen("libvncclient.so", RTLD_LAZY | RTLD_GLOBAL);
if(!libvnc_lib){
Error("Error loading libvlc: %s", dlerror());
return;
}
*(void**) (&rfbClientGetClientData_f) = dlsym(libvnc_lib, "rfbClientGetClientData");
*(void**) (&rfbGetClient_f) = dlsym(libvnc_lib, "rfbGetClient");
*(void**) (&rfbClientSetClientData_f) = dlsym(libvnc_lib, "rfbClientSetClientData");
*(void**) (&rfbInitClient_f) = dlsym(libvnc_lib, "rfbInitClient");
*(void**) (&rfbClientCleanup_f) = dlsym(libvnc_lib, "rfbClientCleanup");
*(void**) (&WaitForMessage_f) = dlsym(libvnc_lib, "WaitForMessage");
*(void**) (&HandleRFBServerMessage_f) = dlsym(libvnc_lib, "HandleRFBServerMessage");
}
static void GotFrameBufferUpdateCallback(rfbClient *rfb, int x, int y, int w, int h){ static void GotFrameBufferUpdateCallback(rfbClient *rfb, int x, int y, int w, int h){
VncPrivateData *data = (VncPrivateData *)rfbClientGetClientData(rfb, &TAG_0); VncPrivateData *data = (VncPrivateData *)(*rfbClientGetClientData_f)(rfb, &TAG_0);
data->buffer = rfb->frameBuffer; data->buffer = rfb->frameBuffer;
} }
static char* GetPasswordCallback(rfbClient* cl){ static char* GetPasswordCallback(rfbClient* cl){
return strdup((const char *)rfbClientGetClientData(cl, &TAG_1)); return strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1));
} }
static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){
@ -25,8 +53,8 @@ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){
return NULL; return NULL;
} }
c->userCredential.password = strdup((const char *)rfbClientGetClientData(cl, &TAG_1)); c->userCredential.password = strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1));
c->userCredential.username = strdup((const char *)rfbClientGetClientData(cl, &TAG_2)); c->userCredential.username = strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_2));
return c; return c;
} }
@ -94,11 +122,12 @@ VncCamera::~VncCamera() {
void VncCamera::Initialise() { void VncCamera::Initialise() {
Debug(2, "Initializing Client"); Debug(2, "Initializing Client");
mRfb = rfbGetClient(8, 3, 4); bind_libvnc_symbols();
mRfb = (*rfbGetClient_f)(8, 3, 4);
rfbClientSetClientData(mRfb, &TAG_0, &mVncData); (*rfbClientSetClientData_f)(mRfb, &TAG_0, &mVncData);
rfbClientSetClientData(mRfb, &TAG_1, (void *)mPass.c_str()); (*rfbClientSetClientData_f)(mRfb, &TAG_1, (void *)mPass.c_str());
rfbClientSetClientData(mRfb, &TAG_2, (void *)mUser.c_str()); (*rfbClientSetClientData_f)(mRfb, &TAG_2, (void *)mUser.c_str());
mRfb->GotFrameBufferUpdate = GotFrameBufferUpdateCallback; mRfb->GotFrameBufferUpdate = GotFrameBufferUpdateCallback;
mRfb->GetPassword = GetPasswordCallback; mRfb->GetPassword = GetPasswordCallback;
@ -107,14 +136,14 @@ void VncCamera::Initialise() {
mRfb->programName = "Zoneminder VNC Monitor"; mRfb->programName = "Zoneminder VNC Monitor";
mRfb->serverHost = strdup(mHost.c_str()); mRfb->serverHost = strdup(mHost.c_str());
mRfb->serverPort = atoi(mPort.c_str()); mRfb->serverPort = atoi(mPort.c_str());
rfbInitClient(mRfb, 0, nullptr); (*rfbInitClient_f)(mRfb, 0, nullptr);
scale.init(); scale.init();
} }
void VncCamera::Terminate() { void VncCamera::Terminate() {
if(mRfb->frameBuffer) if(mRfb->frameBuffer)
free(mRfb->frameBuffer); free(mRfb->frameBuffer);
rfbClientCleanup(mRfb); (*rfbClientCleanup_f)(mRfb);
return; return;
} }
@ -125,8 +154,8 @@ int VncCamera::PrimeCapture() {
int VncCamera::PreCapture() { int VncCamera::PreCapture() {
Debug(2, "PreCapture"); Debug(2, "PreCapture");
WaitForMessage(mRfb, 500); (*WaitForMessage_f)(mRfb, 500);
rfbBool res = HandleRFBServerMessage(mRfb); rfbBool res = (*HandleRFBServerMessage_f)(mRfb);
return res == TRUE ? 1 : -1 ; return res == TRUE ? 1 : -1 ;
} }

View File

@ -403,18 +403,36 @@ char *timeval_to_string( struct timeval tv ) {
} }
std::string UriDecode( const std::string &encoded ) { std::string UriDecode( const std::string &encoded ) {
#ifdef HAVE_LIBCURL char a, b;
CURL *curl = curl_easy_init(); const char *src = encoded.c_str();
int outlength; std::string retbuf;
char *cres = curl_easy_unescape(curl, encoded.c_str(), encoded.length(), &outlength); retbuf.resize(encoded.length() + 1);
std::string res(cres, cres + outlength); char *dst = &retbuf[0];
curl_free(cres); while (*src) {
curl_easy_cleanup(curl); if ((*src == '%') && ((a = src[1]) && (b = src[2])) && (isxdigit(a) && isxdigit(b))) {
return res; if (a >= 'a')
#else a -= 'a'-'A';
Warning("ZM Compiled without LIBCURL. UriDecoding not implemented."); if (a >= 'A')
return encoded; a -= ('A' - 10);
#endif else
a -= '0';
if (b >= 'a')
b -= 'a'-'A';
if (b >= 'A')
b -= ('A' - 10);
else
b -= '0';
*dst++ = 16*a+b;
src+=3;
} else if (*src == '+') {
*dst++ = ' ';
src++;
} else {
*dst++ = *src++;
}
}
*dst++ = '\0';
return retbuf;
} }
void string_toupper( std::string& str) { void string_toupper( std::string& str) {