Merge pull request #2911 from hax0kartik/dl-curl
Dynamically load libcurl, libvlc and libvnc
This commit is contained in:
commit
4b53c7660e
|
@ -324,7 +324,7 @@ if(NOT ZM_NO_CURL)
|
|||
find_package(CURL)
|
||||
if(CURL_FOUND)
|
||||
set(HAVE_LIBCURL 1)
|
||||
list(APPEND ZM_BIN_LIBS ${CURL_LIBRARIES})
|
||||
#list(APPEND ZM_BIN_LIBS ${CURL_LIBRARIES})
|
||||
include_directories(${CURL_INCLUDE_DIRS})
|
||||
set(CMAKE_REQUIRED_INCLUDES ${CURL_INCLUDE_DIRS})
|
||||
check_include_file("curl/curl.h" HAVE_CURL_CURL_H)
|
||||
|
@ -363,8 +363,9 @@ else(LIBJWT_FOUND)
|
|||
endif(LIBJWT_FOUND)
|
||||
|
||||
# gnutls (using find_library and find_path)
|
||||
find_library(GNUTLS_LIBRARIES gnutls)
|
||||
if(GNUTLS_LIBRARIES)
|
||||
if(HAVE_LIBJWT)
|
||||
find_library(GNUTLS_LIBRARIES gnutls)
|
||||
if(GNUTLS_LIBRARIES)
|
||||
set(HAVE_LIBGNUTLS 1)
|
||||
list(APPEND ZM_BIN_LIBS "${GNUTLS_LIBRARIES}")
|
||||
find_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h)
|
||||
|
@ -375,9 +376,10 @@ if(GNUTLS_LIBRARIES)
|
|||
mark_as_advanced(FORCE GNUTLS_LIBRARIES GNUTLS_INCLUDE_DIR)
|
||||
check_include_file("gnutls/gnutls.h" HAVE_GNUTLS_GNUTLS_H)
|
||||
set(optlibsfound "${optlibsfound} GnuTLS")
|
||||
else(GNUTLS_LIBRARIES)
|
||||
else(GNUTLS_LIBRARIES)
|
||||
set(optlibsnotfound "${optlibsnotfound} GnuTLS")
|
||||
endif(GNUTLS_LIBRARIES)
|
||||
endif(GNUTLS_LIBRARIES)
|
||||
endif(HAVE_LIBJWT)
|
||||
|
||||
# OpenSSL
|
||||
if(NOT HAVE_LIBGNUTLS OR NOT HAVE_LIBJWT)
|
||||
|
@ -665,7 +667,7 @@ if(NOT ZM_NO_LIBVLC)
|
|||
find_library(LIBVLC_LIBRARIES vlc)
|
||||
if(LIBVLC_LIBRARIES)
|
||||
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")
|
||||
if(LIBVLC_INCLUDE_DIR)
|
||||
include_directories("${LIBVLC_INCLUDE_DIR}")
|
||||
|
@ -684,7 +686,7 @@ if(NOT ZM_NO_LIBVNC)
|
|||
find_library(LIBVNC_LIBRARIES vncclient)
|
||||
if(LIBVNC_LIBRARIES)
|
||||
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")
|
||||
if(LIBVNC_INCLUDE_DIR)
|
||||
include_directories("${LIBVNC_INCLUDE_DIR}")
|
||||
|
@ -773,9 +775,9 @@ if(HAVE_GNUTLS_GNUTLS_H)
|
|||
HAVE_DECL_GNUTLS_FINGERPRINT)
|
||||
endif(HAVE_GNUTLS_GNUTLS_H)
|
||||
|
||||
if(HAVE_MD5_OPENSSL)
|
||||
if(NOT HAVE_DECL_GNUTLS_FINGERPRINT AND HAVE_MD5_OPENSSL)
|
||||
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))
|
||||
message(AUTHOR_WARNING
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "zm.h"
|
||||
|
||||
#include "zm_curl_camera.h"
|
||||
|
@ -25,6 +26,18 @@
|
|||
|
||||
#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_BUFFER_INITIAL_SIZE 65536
|
||||
|
||||
|
@ -33,6 +46,31 @@ const char* content_type_match = "Content-Type:";
|
|||
size_t content_length_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 ) :
|
||||
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 )
|
||||
|
@ -56,34 +94,41 @@ void cURLCamera::Initialise() {
|
|||
|
||||
databuffer.expand(CURL_BUFFER_INITIAL_SIZE);
|
||||
|
||||
bind_libcurl_symbols();
|
||||
/* cURL initialization */
|
||||
CURLcode cRet = curl_global_init(CURL_GLOBAL_ALL);
|
||||
CURLcode cRet = (*curl_global_init_f)(CURL_GLOBAL_ALL);
|
||||
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 */
|
||||
int nRet = pthread_mutex_init(&shareddata_mutex, NULL);
|
||||
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 */
|
||||
nRet = pthread_cond_init(&data_available_cond, NULL);
|
||||
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 */
|
||||
nRet = pthread_cond_init(&request_complete_cond, NULL);
|
||||
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 */
|
||||
nRet = pthread_create(&thread, NULL, thread_func_dispatcher, this);
|
||||
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);
|
||||
|
||||
/* cURL cleanup */
|
||||
curl_global_cleanup();
|
||||
(*curl_global_cleanup_f)();
|
||||
|
||||
if(curl_lib)
|
||||
dlclose(curl_lib);
|
||||
}
|
||||
|
||||
int cURLCamera::PrimeCapture() {
|
||||
|
@ -287,7 +334,8 @@ int cURLCamera::Capture( Image &image ) {
|
|||
}
|
||||
} else {
|
||||
/* 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 */
|
||||
|
||||
} /* frameComplete loop */
|
||||
|
@ -376,60 +424,88 @@ void* cURLCamera::thread_func() {
|
|||
long tRet;
|
||||
double dSize;
|
||||
|
||||
c = curl_easy_init();
|
||||
c = (*curl_easy_init_f)();
|
||||
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;
|
||||
/* Set URL */
|
||||
cRet = curl_easy_setopt(c, CURLOPT_URL, mPath.c_str());
|
||||
if(cRet != CURLE_OK)
|
||||
Fatal("Failed setting libcurl URL: %s", curl_easy_strerror(cRet));
|
||||
cRet = (*curl_easy_setopt_f)(c, CURLOPT_URL, mPath.c_str());
|
||||
if(cRet != CURLE_OK) {
|
||||
Error("Failed setting libcurl URL: %s", *(curl_easy_strerror_f)(cRet));
|
||||
tRet = -52;
|
||||
return (void*)tRet;
|
||||
}
|
||||
|
||||
/* Header callback */
|
||||
cRet = curl_easy_setopt(c, CURLOPT_HEADERFUNCTION, &header_callback_dispatcher);
|
||||
if(cRet != CURLE_OK)
|
||||
Fatal("Failed setting libcurl header callback function: %s", curl_easy_strerror(cRet));
|
||||
cRet = curl_easy_setopt(c, CURLOPT_HEADERDATA, this);
|
||||
if(cRet != CURLE_OK)
|
||||
Fatal("Failed setting libcurl header callback object: %s", curl_easy_strerror(cRet));
|
||||
cRet = (*curl_easy_setopt_f)(c, CURLOPT_HEADERFUNCTION, &header_callback_dispatcher);
|
||||
if(cRet != CURLE_OK) {
|
||||
Error("Failed setting libcurl header callback function: %s", (*curl_easy_strerror_f)(cRet));
|
||||
tRet = -53;
|
||||
return (void*)tRet;
|
||||
}
|
||||
|
||||
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 */
|
||||
cRet = curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, &data_callback_dispatcher);
|
||||
if(cRet != CURLE_OK)
|
||||
Fatal("Failed setting libcurl data callback function: %s", curl_easy_strerror(cRet));
|
||||
cRet = curl_easy_setopt(c, CURLOPT_WRITEDATA, this);
|
||||
if(cRet != CURLE_OK)
|
||||
Fatal("Failed setting libcurl data callback object: %s", curl_easy_strerror(cRet));
|
||||
cRet = (*curl_easy_setopt_f)(c, CURLOPT_WRITEFUNCTION, &data_callback_dispatcher);
|
||||
if(cRet != CURLE_OK) {
|
||||
Error("Failed setting libcurl data callback function: %s", (*curl_easy_strerror_f)(cRet));
|
||||
tRet = -55;
|
||||
return (void*)tRet;
|
||||
}
|
||||
|
||||
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 */
|
||||
cRet = curl_easy_setopt(c, CURLOPT_NOPROGRESS, 0);
|
||||
if(cRet != CURLE_OK)
|
||||
Fatal("Failed enabling libcurl progress callback function: %s", curl_easy_strerror(cRet));
|
||||
cRet = curl_easy_setopt(c, CURLOPT_PROGRESSFUNCTION, &progress_callback_dispatcher);
|
||||
if(cRet != CURLE_OK)
|
||||
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_NOPROGRESS, 0);
|
||||
if(cRet != CURLE_OK) {
|
||||
Error("Failed enabling libcurl progress callback function: %s", (*curl_easy_strerror_f)(cRet));
|
||||
tRet = -57;
|
||||
return (void*)tRet;
|
||||
}
|
||||
|
||||
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 */
|
||||
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)
|
||||
Error("Failed setting username: %s", curl_easy_strerror(cRet));
|
||||
Error("Failed setting username: %s", (*curl_easy_strerror_f)(cRet));
|
||||
}
|
||||
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)
|
||||
Error("Failed setting password: %s", curl_easy_strerror(cRet));
|
||||
Error("Failed setting password: %s", (*curl_easy_strerror_f)(cRet));
|
||||
}
|
||||
|
||||
/* 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)
|
||||
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 */
|
||||
|
@ -437,14 +513,14 @@ void* cURLCamera::thread_func() {
|
|||
tRet = 0;
|
||||
while(!bTerminate) {
|
||||
/* Do the work */
|
||||
cRet = curl_easy_perform(c);
|
||||
cRet = (*curl_easy_perform_f)(c);
|
||||
|
||||
if(mode == MODE_SINGLE) {
|
||||
if(cRet != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
/* 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) {
|
||||
break;
|
||||
}
|
||||
|
@ -454,12 +530,16 @@ void* cURLCamera::thread_func() {
|
|||
if(dSize > 0) {
|
||||
single_offsets.push_back(dSize);
|
||||
} 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 */
|
||||
tRet = pthread_cond_signal(&request_complete_cond);
|
||||
if(tRet != 0) {
|
||||
Error("Failed signaling request completed condition variable: %s",strerror(tRet));
|
||||
tRet = -61;
|
||||
return (void*)tRet;
|
||||
}
|
||||
/* Unlock */
|
||||
unlock();
|
||||
|
@ -475,7 +555,7 @@ void* cURLCamera::thread_func() {
|
|||
break;
|
||||
} else if (cRet != CURLE_OK) {
|
||||
/* 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) {
|
||||
Error("Retrying.. Attempt %d of %d",attempt,CURL_MAXRETRY);
|
||||
/* Do a reset */
|
||||
|
@ -491,7 +571,7 @@ void* cURLCamera::thread_func() {
|
|||
}
|
||||
|
||||
/* Cleanup */
|
||||
curl_easy_cleanup(c);
|
||||
(*curl_easy_cleanup_f)(c);
|
||||
c = NULL;
|
||||
|
||||
return (void*)tRet;
|
||||
|
|
|
@ -17,12 +17,51 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "zm.h"
|
||||
#include "zm_signal.h"
|
||||
#include "zm_libvlc_camera.h"
|
||||
|
||||
#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
|
||||
void* LibvlcLockBuffer(void* opaque, void** planes) {
|
||||
LibvlcPrivateData* data = reinterpret_cast<LibvlcPrivateData*>(opaque);
|
||||
|
@ -125,15 +164,15 @@ LibvlcCamera::~LibvlcCamera() {
|
|||
Terminate();
|
||||
}
|
||||
if ( mLibvlcMediaPlayer != NULL ) {
|
||||
libvlc_media_player_release(mLibvlcMediaPlayer);
|
||||
(*libvlc_media_player_release_f)(mLibvlcMediaPlayer);
|
||||
mLibvlcMediaPlayer = NULL;
|
||||
}
|
||||
if ( mLibvlcMedia != NULL ) {
|
||||
libvlc_media_release(mLibvlcMedia);
|
||||
(*libvlc_media_release_f)(mLibvlcMedia);
|
||||
mLibvlcMedia = NULL;
|
||||
}
|
||||
if ( mLibvlcInstance != NULL ) {
|
||||
libvlc_release(mLibvlcInstance);
|
||||
(*libvlc_release_f)(mLibvlcInstance);
|
||||
mLibvlcInstance = NULL;
|
||||
}
|
||||
if ( mOptArgV != NULL ) {
|
||||
|
@ -142,14 +181,16 @@ LibvlcCamera::~LibvlcCamera() {
|
|||
}
|
||||
|
||||
void LibvlcCamera::Initialise() {
|
||||
bind_libvlc_symbols();
|
||||
}
|
||||
|
||||
void LibvlcCamera::Terminate() {
|
||||
libvlc_media_player_stop(mLibvlcMediaPlayer);
|
||||
(*libvlc_media_player_stop_f)(mLibvlcMediaPlayer);
|
||||
if ( mLibvlcData.buffer ) {
|
||||
zm_freealigned(mLibvlcData.buffer);
|
||||
mLibvlcData.buffer = NULL;
|
||||
}
|
||||
|
||||
if ( mLibvlcData.prevBuffer ) {
|
||||
zm_freealigned(mLibvlcData.prevBuffer);
|
||||
mLibvlcData.prevBuffer = NULL;
|
||||
|
@ -158,6 +199,7 @@ void LibvlcCamera::Terminate() {
|
|||
|
||||
int LibvlcCamera::PrimeCapture() {
|
||||
Info("Priming capture from %s", mPath.c_str());
|
||||
Info("Libvlc Version %s", (*libvlc_get_version_f)());
|
||||
|
||||
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 ) {
|
||||
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;
|
||||
}
|
||||
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 ) {
|
||||
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;
|
||||
}
|
||||
|
||||
mLibvlcMediaPlayer = libvlc_media_player_new_from_media(mLibvlcMedia);
|
||||
mLibvlcMediaPlayer = (*libvlc_media_player_new_from_media_f)(mLibvlcMedia);
|
||||
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;
|
||||
}
|
||||
|
||||
libvlc_video_set_format(mLibvlcMediaPlayer, mTargetChroma.c_str(), width, height, width * mBpp);
|
||||
libvlc_video_set_callbacks(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, NULL, &mLibvlcData);
|
||||
(*libvlc_video_set_format_f)(mLibvlcMediaPlayer, mTargetChroma.c_str(), width, height, width * mBpp);
|
||||
(*libvlc_video_set_callbacks_f)(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, NULL, &mLibvlcData);
|
||||
|
||||
mLibvlcData.bufferSize = width * height * mBpp;
|
||||
// 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);
|
||||
|
||||
libvlc_media_player_play(mLibvlcMediaPlayer);
|
||||
(*libvlc_media_player_play_f)(mLibvlcMediaPlayer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <dlfcn.h>
|
||||
#include "zm.h"
|
||||
#include "zm_signal.h"
|
||||
#include "zm_libvnc_camera.h"
|
||||
|
@ -8,14 +9,41 @@
|
|||
static int TAG_0;
|
||||
static int TAG_1;
|
||||
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){
|
||||
VncPrivateData *data = (VncPrivateData *)rfbClientGetClientData(rfb, &TAG_0);
|
||||
VncPrivateData *data = (VncPrivateData *)(*rfbClientGetClientData_f)(rfb, &TAG_0);
|
||||
data->buffer = rfb->frameBuffer;
|
||||
}
|
||||
|
||||
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){
|
||||
|
@ -25,8 +53,8 @@ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){
|
|||
return NULL;
|
||||
}
|
||||
|
||||
c->userCredential.password = strdup((const char *)rfbClientGetClientData(cl, &TAG_1));
|
||||
c->userCredential.username = strdup((const char *)rfbClientGetClientData(cl, &TAG_2));
|
||||
c->userCredential.password = strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1));
|
||||
c->userCredential.username = strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_2));
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -94,11 +122,12 @@ VncCamera::~VncCamera() {
|
|||
|
||||
void VncCamera::Initialise() {
|
||||
Debug(2, "Initializing Client");
|
||||
mRfb = rfbGetClient(8, 3, 4);
|
||||
bind_libvnc_symbols();
|
||||
mRfb = (*rfbGetClient_f)(8, 3, 4);
|
||||
|
||||
rfbClientSetClientData(mRfb, &TAG_0, &mVncData);
|
||||
rfbClientSetClientData(mRfb, &TAG_1, (void *)mPass.c_str());
|
||||
rfbClientSetClientData(mRfb, &TAG_2, (void *)mUser.c_str());
|
||||
(*rfbClientSetClientData_f)(mRfb, &TAG_0, &mVncData);
|
||||
(*rfbClientSetClientData_f)(mRfb, &TAG_1, (void *)mPass.c_str());
|
||||
(*rfbClientSetClientData_f)(mRfb, &TAG_2, (void *)mUser.c_str());
|
||||
|
||||
mRfb->GotFrameBufferUpdate = GotFrameBufferUpdateCallback;
|
||||
mRfb->GetPassword = GetPasswordCallback;
|
||||
|
@ -107,14 +136,14 @@ void VncCamera::Initialise() {
|
|||
mRfb->programName = "Zoneminder VNC Monitor";
|
||||
mRfb->serverHost = strdup(mHost.c_str());
|
||||
mRfb->serverPort = atoi(mPort.c_str());
|
||||
rfbInitClient(mRfb, 0, nullptr);
|
||||
(*rfbInitClient_f)(mRfb, 0, nullptr);
|
||||
scale.init();
|
||||
}
|
||||
|
||||
void VncCamera::Terminate() {
|
||||
if(mRfb->frameBuffer)
|
||||
free(mRfb->frameBuffer);
|
||||
rfbClientCleanup(mRfb);
|
||||
(*rfbClientCleanup_f)(mRfb);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -125,8 +154,8 @@ int VncCamera::PrimeCapture() {
|
|||
|
||||
int VncCamera::PreCapture() {
|
||||
Debug(2, "PreCapture");
|
||||
WaitForMessage(mRfb, 500);
|
||||
rfbBool res = HandleRFBServerMessage(mRfb);
|
||||
(*WaitForMessage_f)(mRfb, 500);
|
||||
rfbBool res = (*HandleRFBServerMessage_f)(mRfb);
|
||||
return res == TRUE ? 1 : -1 ;
|
||||
}
|
||||
|
||||
|
|
|
@ -403,18 +403,36 @@ char *timeval_to_string( struct timeval tv ) {
|
|||
}
|
||||
|
||||
std::string UriDecode( const std::string &encoded ) {
|
||||
#ifdef HAVE_LIBCURL
|
||||
CURL *curl = curl_easy_init();
|
||||
int outlength;
|
||||
char *cres = curl_easy_unescape(curl, encoded.c_str(), encoded.length(), &outlength);
|
||||
std::string res(cres, cres + outlength);
|
||||
curl_free(cres);
|
||||
curl_easy_cleanup(curl);
|
||||
return res;
|
||||
#else
|
||||
Warning("ZM Compiled without LIBCURL. UriDecoding not implemented.");
|
||||
return encoded;
|
||||
#endif
|
||||
char a, b;
|
||||
const char *src = encoded.c_str();
|
||||
std::string retbuf;
|
||||
retbuf.resize(encoded.length() + 1);
|
||||
char *dst = &retbuf[0];
|
||||
while (*src) {
|
||||
if ((*src == '%') && ((a = src[1]) && (b = src[2])) && (isxdigit(a) && isxdigit(b))) {
|
||||
if (a >= 'a')
|
||||
a -= 'a'-'A';
|
||||
if (a >= 'A')
|
||||
a -= ('A' - 10);
|
||||
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) {
|
||||
|
|
Loading…
Reference in New Issue