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)
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,21 +363,23 @@ else(LIBJWT_FOUND)
endif(LIBJWT_FOUND)
# gnutls (using find_library and find_path)
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)
if(GNUTLS_INCLUDE_DIR)
include_directories("${GNUTLS_INCLUDE_DIR}")
set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}")
endif(GNUTLS_INCLUDE_DIR)
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)
set(optlibsnotfound "${optlibsnotfound} GnuTLS")
endif(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)
if(GNUTLS_INCLUDE_DIR)
include_directories("${GNUTLS_INCLUDE_DIR}")
set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}")
endif(GNUTLS_INCLUDE_DIR)
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)
set(optlibsnotfound "${optlibsnotfound} GnuTLS")
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

View File

@ -15,8 +15,9 @@
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// 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 )
@ -55,35 +93,42 @@ void cURLCamera::Initialise() {
content_type_match_len = strlen(content_type_match);
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;

View File

@ -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;
}

View File

@ -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 ;
}

View File

@ -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) {