From b0645ae51285f09feb14e559ec57feddd57bbf8f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 20 Sep 2026 18:12:47 -0400 Subject: [PATCH] feat: remove the Libvlc capture method from the daemons and build Ffmpeg reaches the same network cameras libvlc did, so carrying a second streaming library -- with its own threading, its own bugs and its own build dependency -- buys nothing. The preceding migration moves existing monitors to Ffmpeg first, so Monitor::Load cannot meet a type it no longer recognises, which is Fatal and would stop zmc rather than skip the monitor. Drops LibvlcCamera, the LIBVLC camera type and its parse and construction arms, LIBVLC_SRC and Camera::IsLibvlc, the ZM_NO_LIBVLC option and the libvlc probe, and the HAVE_LIBVLC and HAVE_VLC_VLC_H defines. Since the camera resolved libvlc through dlopen rather than linking it, this removes a headers-only build dependency and a runtime one, and nothing else needed relinking. kOptionSeparators stays -- the Ffmpeg path still parses the Options field with it -- but it is no longer a contract shared between two readers, so its comment and the test that pins its behaviour are reworded rather than removed. Built clean from a fresh cmake configure, which no longer lists libVLC among optional libraries; unit suite passes (147 cases, 12531 assertions); no libvlc strings remain in zmc. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015Y6FieTwEXuLhhR4e2yiax --- CMakeLists.txt | 22 --- src/CMakeLists.txt | 1 - src/zm_camera.h | 3 +- src/zm_libvlc_camera.cpp | 346 --------------------------------------- src/zm_libvlc_camera.h | 85 ---------- src/zm_monitor.cpp | 37 ----- src/zm_monitor.h | 1 - src/zm_utils.h | 5 +- tests/zm_utils.cpp | 7 +- zoneminder-config.cmake | 2 - 10 files changed, 7 insertions(+), 502 deletions(-) delete mode 100644 src/zm_libvlc_camera.cpp delete mode 100644 src/zm_libvlc_camera.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 493c12138..e28527309 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -260,8 +260,6 @@ set(ZM_MYSQL_ENGINE "InnoDB" CACHE STRING set(ZM_NO_MMAP "OFF" CACHE BOOL "Set to ON to not use mmap shared memory. Shouldn't be enabled unless you experience problems with the shared memory. default: OFF") -set(ZM_NO_LIBVLC "OFF" CACHE BOOL - "Set to ON to skip libvlc checks and force building ZM without libvlc. default: OFF") set(ZM_NO_LIBVNC "OFF" CACHE BOOL "Set to ON to skip libvnc checks and force building ZM without libvnc. default: OFF") set(ZM_NO_CURL "OFF" CACHE BOOL @@ -630,26 +628,6 @@ if(FFMPEG_EXECUTABLE) mark_as_advanced(FFMPEG_EXECUTABLE) endif() -# Do not check for libvlc if ZM_NO_LIBVLC is on -if(NOT ZM_NO_LIBVLC) - # libvlc (using find_library and find_path) - find_library(LIBVLC_LIBRARIES vlc) - if(LIBVLC_LIBRARIES) - set(HAVE_LIBVLC 1) - #list(APPEND ZM_BIN_LIBS "${LIBVLC_LIBRARIES}") - find_path(LIBVLC_INCLUDE_DIR "vlc/vlc.h") - if(LIBVLC_INCLUDE_DIR) - list(APPEND ZM_INCLUDE_DIRS "${LIBVLC_INCLUDE_DIR}") - set(CMAKE_REQUIRED_INCLUDES "${LIBVLC_INCLUDE_DIR}") - endif() - mark_as_advanced(FORCE LIBVLC_LIBRARIES LIBVLC_INCLUDE_DIR) - check_include_file("vlc/vlc.h" HAVE_VLC_VLC_H) - set(optlibsfound "${optlibsfound} libVLC") - else() - set(optlibsnotfound "${optlibsnotfound} libVLC") - endif() -endif() - if(NOT ZM_NO_LIBVNC) # libvncclient (using find_library and find_path) find_library(LIBVNC_LIBRARIES vncclient) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e6222b94d..05b646a46 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,7 +33,6 @@ set(ZM_BIN_SRC_FILES zm_group.cpp zm_image.cpp zm_jpeg.cpp - zm_libvlc_camera.cpp zm_libvnc_camera.cpp zm_local_camera.cpp zm_monitor.cpp diff --git a/src/zm_camera.h b/src/zm_camera.h index 15c0b6e48..c23df2fae 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -36,7 +36,7 @@ class ZMPacket; // class Camera { protected: - typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC, VNC_SRC } SourceType; + typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, CURL_SRC, VNC_SRC } SourceType; const Monitor *monitor; SourceType type; @@ -95,7 +95,6 @@ class Camera { bool IsRemote() const { return type == REMOTE_SRC; } bool IsFile() const { return type == FILE_SRC; } bool IsFfmpeg() const { return type == FFMPEG_SRC; } - bool IsLibvlc() const { return type == LIBVLC_SRC; } bool IscURL() const { return type == CURL_SRC; } bool IsVNC() const { return type == VNC_SRC; } unsigned int Width() const { return width; } diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp deleted file mode 100644 index 25d5df877..000000000 --- a/src/zm_libvlc_camera.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/* - * ZoneMinder Libvlc Camera Class Implementation, $Date$, $Revision$ - * Copyright (C) 2001-2008 Philip Coombes - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 "zm_libvlc_camera.h" - -#include "zm_packet.h" -#include "zm_signal.h" -#include - -#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(opaque); - data->mutex.lock(); - - uint8_t* buffer = data->buffer; - data->buffer = data->prevBuffer; - data->prevBuffer = buffer; - - *planes = data->buffer; - return nullptr; -} - -void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) { - LibvlcPrivateData* data = reinterpret_cast(opaque); - - bool newFrame = false; - for( size_t i=0; i < data->bufferSize; i++ ) { - if ( data->buffer[i] != data->prevBuffer[i] ) { - newFrame = true; - break; - } - } - data->mutex.unlock(); - - time_t now; - time(&now); - // Return frames slightly faster than 1fps (if time() supports greater than one second resolution) - if ( newFrame || difftime(now, data->prevTime) >= 0.8 ) { - data->prevTime = now; - { - std::lock_guard lck(data->newImageMutex); - data->newImage = true; - } - data->newImageCv.notify_all(); - } -} - -LibvlcCamera::LibvlcCamera( - const Monitor *monitor, - const std::string &p_path, - const std::string &p_user, - const std::string &p_pass, - const std::string &p_method, - const std::string &p_options, - int p_width, - 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( - monitor, - LIBVLC_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(UriEncode(p_user)), - mPass(UriEncode(p_pass)), - mMethod(p_method), - mOptions(p_options) { - mLibvlcInstance = nullptr; - mLibvlcMedia = nullptr; - mLibvlcMediaPlayer = nullptr; - mLibvlcData.buffer = nullptr; - mLibvlcData.prevBuffer = nullptr; - mOptArgV = nullptr; - - /* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */ - if ( zm_is_rgb32(pixelFormat) ) { - subpixelorder = ZM_SUBPIX_ORDER_BGRA; - pixelFormat = zm_pixformat_from_colours(colours, subpixelorder); - mTargetChroma = "RV32"; - mBpp = 4; - } else if ( zm_is_rgb24(pixelFormat) ) { - subpixelorder = ZM_SUBPIX_ORDER_BGR; - pixelFormat = zm_pixformat_from_colours(colours, subpixelorder); - mTargetChroma = "RV24"; - mBpp = 3; - } else if ( pixelFormat == AV_PIX_FMT_GRAY8 ) { - subpixelorder = ZM_SUBPIX_ORDER_NONE; - pixelFormat = zm_pixformat_from_colours(colours, subpixelorder); - mTargetChroma = "GREY"; - mBpp = 1; - } else { - mBpp = 0; - Panic("Unexpected colours: %d",colours); - } - - if ( capture ) { - Initialise(); - } -} - -LibvlcCamera::~LibvlcCamera() { - if ( capture ) { - Terminate(); - } - - mLibvlcData.newImageCv.notify_all(); // to unblock on termination (zm_terminate) - - if ( mLibvlcMediaPlayer != nullptr ) { - (*libvlc_media_player_release_f)(mLibvlcMediaPlayer); - mLibvlcMediaPlayer = nullptr; - } - if ( mLibvlcMedia != nullptr ) { - (*libvlc_media_release_f)(mLibvlcMedia); - mLibvlcMedia = nullptr; - } - if ( mLibvlcInstance != nullptr ) { - (*libvlc_release_f)(mLibvlcInstance); - mLibvlcInstance = nullptr; - } - if (libvlc_lib) { - dlclose(libvlc_lib); - libvlc_lib = nullptr; - } - if ( mOptArgV != nullptr ) { - delete[] mOptArgV; - } -} - -void LibvlcCamera::Initialise() { - bind_libvlc_symbols(); -} - -void LibvlcCamera::Terminate() { - if (libvlc_media_player_stop_f && mLibvlcMediaPlayer) - (*libvlc_media_player_stop_f)(mLibvlcMediaPlayer); - if ( mLibvlcData.buffer ) { - zm_freealigned(mLibvlcData.buffer); - mLibvlcData.buffer = nullptr; - } - - if ( mLibvlcData.prevBuffer ) { - zm_freealigned(mLibvlcData.prevBuffer); - mLibvlcData.prevBuffer = nullptr; - } -} - -int LibvlcCamera::PrimeCapture() { - Debug(1, "Priming capture from %s, libvlc version %s", mPath.c_str(), (*libvlc_get_version_f)()); - - opVect = Split(Options(), kOptionSeparators); - - Debug(1, "Method: '%s'", Method().c_str()); - - // Set transport method as specified by method field, rtpUni is default - if ( Method() == "rtpMulti" ) - opVect.push_back("--rtsp-mcast"); - else if ( Method() == "rtpRtsp" ) - opVect.push_back("--rtsp-tcp"); - else if ( Method() == "rtpRtspHttp" ) - opVect.push_back("--rtsp-http"); - - opVect.push_back("--no-audio"); - - if ( opVect.size() > 0 ) { - mOptArgV = new char*[opVect.size()]; - Debug(2, "Number of Options: %zu", opVect.size()); - for (size_t i=0; i< opVect.size(); i++) { - opVect[i] = TrimSpaces(opVect[i]); - mOptArgV[i] = (char *)opVect[i].c_str(); - Debug(2, "set option %zu to '%s'", i, opVect[i].c_str()); - } - } - - mLibvlcInstance = (*libvlc_new_f)(opVect.size(), (const char* const*)mOptArgV); - if ( mLibvlcInstance == nullptr ) { - Error("Unable to create libvlc instance due to: %s", (*libvlc_errmsg_f)()); - return -1; - } - (*libvlc_log_set_f)(mLibvlcInstance, LibvlcCamera::log_callback, nullptr); - - // recreate the path with encoded authentication info - if( mUser.length() > 0 ) { - std::string mMaskedPath = remove_authentication(mPath); - - std::string protocol = StringToUpper(mPath.substr(0, 4)); - if ( protocol == "RTSP" ) { - // build the actual uri string with encoded parameters (from the user and pass fields) - mPath = StringToLower(protocol) + "://" + mUser + ":" + mPass + "@" + mMaskedPath.substr(7, std::string::npos); - Debug(1, "Rebuilt URI with encoded parameters: '%s'", mPath.c_str()); - } - } - - mLibvlcMedia = (*libvlc_media_new_location_f)(mLibvlcInstance, mPath.c_str()); - if ( mLibvlcMedia == nullptr ) { - Error("Unable to open input %s due to: %s", mPath.c_str(), (*libvlc_errmsg_f)()); - return -1; - } - - mLibvlcMediaPlayer = (*libvlc_media_player_new_from_media_f)(mLibvlcMedia); - if ( mLibvlcMediaPlayer == nullptr ) { - Error("Unable to create player for %s due to: %s", mPath.c_str(), (*libvlc_errmsg_f)()); - return -1; - } - - (*libvlc_video_set_format_f)(mLibvlcMediaPlayer, mTargetChroma.c_str(), width, height, width * mBpp); - (*libvlc_video_set_callbacks_f)(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, nullptr, &mLibvlcData); - - mLibvlcData.bufferSize = static_cast(width) * height * mBpp; - // Libvlc wants 32 byte alignment for images (should in theory do this for all image lines) - mLibvlcData.buffer = (uint8_t*)zm_mallocaligned(64, mLibvlcData.bufferSize); - mLibvlcData.prevBuffer = (uint8_t*)zm_mallocaligned(64, mLibvlcData.bufferSize); - - mLibvlcData.newImage = false; - - (*libvlc_media_player_play_f)(mLibvlcMediaPlayer); - - return 0; -} - - -int LibvlcCamera::PreCapture() { - return 0; -} - -// Should not return -1 as cancels capture. Always wait for image if available. -int LibvlcCamera::Capture(std::shared_ptr &zm_packet) { - // newImage is a mutex/condition based flag to tell us when there is an image available - { - std::unique_lock lck(mLibvlcData.newImageMutex); - mLibvlcData.newImageCv.wait(lck, [&] { return mLibvlcData.newImage || zm_terminate; }); - mLibvlcData.newImage = false; - } - - if (zm_terminate) - return 0; - - mLibvlcData.mutex.lock(); - zm_packet->image->Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, mLibvlcData.bufferSize); - zm_packet->packet->stream_index = mVideoStreamId; - zm_packet->stream = mVideoStream; - mLibvlcData.mutex.unlock(); - - return 1; -} - -int LibvlcCamera::PostCapture() { - return 0; -} - -void LibvlcCamera::log_callback(void *ptr, int level, const libvlc_log_t *ctx, const char *fmt, va_list vargs) { - Logger *log = Logger::fetch(); - int log_level = Logger::NOLOG; - if ( level == LIBVLC_ERROR ) { - log_level = Logger::WARNING; // ffmpeg outputs a lot of errors that don't really affect anything. - //log_level = Logger::ERROR; - } else if ( level == LIBVLC_WARNING ) { - log_level = Logger::INFO; - //log_level = Logger::WARNING; - } else if ( level == LIBVLC_NOTICE ) { - log_level = Logger::DEBUG1; - //log_level = Logger::INFO; - } else if ( level == LIBVLC_DEBUG ) { - log_level = Logger::DEBUG3; - } else { - Error("Unknown log level %d", level); - } - - if ( log ) { - char logString[8192]; - vsnprintf(logString, sizeof(logString) - 1, fmt, vargs); - log->logPrint(false, __FILE__, __LINE__, log_level, "%s", logString); - } -} -#endif // HAVE_LIBVLC diff --git a/src/zm_libvlc_camera.h b/src/zm_libvlc_camera.h deleted file mode 100644 index 1a7c45fab..000000000 --- a/src/zm_libvlc_camera.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * ZoneMinder Libvlc Camera Class Interface, $Date$, $Revision$ - * Copyright (C) 2001-2008 Philip Coombes - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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. -*/ - -#ifndef ZM_LIBVLC_CAMERA_H -#define ZM_LIBVLC_CAMERA_H - -#include "zm_camera.h" -#include "zm_utils.h" -#include -#include - -#if HAVE_LIBVLC - -#if HAVE_VLC_VLC_H -#include "vlc/vlc.h" -#endif - -// Used by libvlc callbacks -struct LibvlcPrivateData { - uint8_t* buffer; - uint8_t* prevBuffer; - time_t prevTime; - size_t bufferSize; - std::mutex mutex; - - bool newImage; - std::mutex newImageMutex; - std::condition_variable newImageCv; -}; - -class LibvlcCamera : public Camera { - private: - static void log_callback( void *ptr, int level, const libvlc_log_t *ctx, const char *format, va_list vargs ); - protected: - std::string mPath; - std::string mUser; - std::string mPass; - std::string mMethod; - std::string mOptions; - StringVector opVect; // mOptArgV will point into opVect so it needs to hang around - char **mOptArgV; - LibvlcPrivateData mLibvlcData; - std::string mTargetChroma; - uint8_t mBpp; - - libvlc_instance_t *mLibvlcInstance; - libvlc_media_t *mLibvlcMedia; - libvlc_media_player_t *mLibvlcMediaPlayer; - - public: - LibvlcCamera( const Monitor *monitor, const std::string &path, const std::string &user,const std::string &pass, const std::string &p_method, const std::string &p_options, int p_width, 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 ); - ~LibvlcCamera(); - - const std::string &Path() const { return mPath; } - const std::string &Options() const { return mOptions; } - const std::string &Method() const { return mMethod; } - - void Initialise(); - void Terminate(); - - int PrimeCapture() override; - int PreCapture() override; - int Capture(std::shared_ptr &p) override; - int PostCapture() override; - int Close() override { return 0; }; -}; - -#endif // HAVE_LIBVLC -#endif // ZM_LIBVLC_CAMERA_H diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 0a9fff459..d9fb2731e 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -39,10 +39,6 @@ #include "zm_local_camera.h" #endif // ZM_HAS_V4L2 -#if HAVE_LIBVLC -#include "zm_libvlc_camera.h" -#endif // HAVE_LIBVLC - #if HAVE_LIBVNC #include "zm_libvnc_camera.h" #endif // HAVE_LIBVNC @@ -126,7 +122,6 @@ std::string CameraType_Strings[] = { "Remote", "File", "Ffmpeg", - "LibVLC", "LibCURL", "VNC" }; @@ -392,8 +387,6 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { type = REMOTE; } else if (!strcmp(dbrow[col], "File")) { type = FILE; - } else if (!strcmp(dbrow[col], "Libvlc")) { - type = LIBVLC; } else if (!strcmp(dbrow[col], "VNC")) { type = VNC; } else { @@ -877,36 +870,6 @@ void Monitor::LoadCamera() { ); break; } - case LIBVLC: { - // libvlc reads the same network streams ffmpeg does, through a second - // library with its own build dependency, its own threading and its own - // bugs. Ffmpeg is the maintained path and every url that works here works - // there, so this capture method is on its way out. - Warning("Monitor %u (%s): the Libvlc capture method is deprecated and will be removed. " - "Change this monitor to Type 'Ffmpeg', keeping the same Source Path", - id, name.c_str()); -#if HAVE_LIBVLC - camera = zm::make_unique(this, - path.c_str(), - user, - pass, - method, - options, - camera_width, - camera_height, - colours, - brightness, - contrast, - hue, - colour, - purpose == CAPTURE, - record_audio - ); -#else // HAVE_LIBVLC - Error("You must have vlc libraries installed to use vlc cameras for monitor %d", id); -#endif // HAVE_LIBVLC - break; - } case VNC: { #if HAVE_LIBVNC camera = zm::make_unique(this, diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 1e89e31db..ff255bdb3 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -130,7 +130,6 @@ class Monitor : public std::enable_shared_from_this { REMOTE, FILE, FFMPEG, - LIBVLC, LIBCURL, VNC, } CameraType; diff --git a/src/zm_utils.h b/src/zm_utils.h index 74886d938..78a06d4f7 100644 --- a/src/zm_utils.h +++ b/src/zm_utils.h @@ -99,9 +99,8 @@ std::string ClientAddress(const std::string &remote_addr, // Separator characters between entries in a monitor's Options field. The ui // offers a textarea, so an option may be on its own line as well as after a -// comma. Both consumers - av_dict_parse_string() for Ffmpeg and Split() for -// Libvlc - take a set of separator characters and skip empty entries, so a -// blank line, crlf or a trailing newline all just work. +// comma. av_dict_parse_string() takes a set of separator characters and skips +// empty entries, so a blank line, crlf or a trailing newline all just work. constexpr const char kOptionSeparators[] = ",\r\n"; inline bool StartsWith(const std::string &haystack, const std::string &needle) { diff --git a/tests/zm_utils.cpp b/tests/zm_utils.cpp index 43305a994..e1edddda5 100644 --- a/tests/zm_utils.cpp +++ b/tests/zm_utils.cpp @@ -129,9 +129,10 @@ TEST_CASE("Split (string delimiter)") { items = Split("a b c", " ", 2); REQUIRE(items == std::vector{"a", "b c"}); - // LibvlcCamera splits the monitor Options field this way. The field is a - // textarea, so an option may be on its own line rather than after a comma, - // and runs of separators (a blank line, or crlf) must not become entries. + // A monitor's Options field is a textarea, so an entry may be on its own + // line rather than after a comma, and runs of separators (a blank line, or + // crlf) must not become empty entries. Split() is no longer the reader of + // that field, but this is the contract kOptionSeparators is chosen for. items = Split("--rate=1\n--no-audio", kOptionSeparators); REQUIRE(items == std::vector{"--rate=1", "--no-audio"}); diff --git a/zoneminder-config.cmake b/zoneminder-config.cmake index 9f6f904e9..229524b6b 100644 --- a/zoneminder-config.cmake +++ b/zoneminder-config.cmake @@ -38,8 +38,6 @@ #cmakedefine HAVE_MYSQL_OPT_SSL_MODE 1 #cmakedefine HAVE_MYSQL_OPT_SSL_VERIFY_SERVER_CERT 1 #cmakedefine HAVE_LIBAVUTIL_HWCONTEXT_H 1 -#cmakedefine HAVE_LIBVLC 1 -#cmakedefine HAVE_VLC_VLC_H 1 #cmakedefine HAVE_LIBVNC 1 #cmakedefine HAVE_RFB_RFB_H 1 #cmakedefine HAVE_LIBJWT 1