diff --git a/CMakeLists.txt b/CMakeLists.txt index e0a93bf00..7802b3d67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ set(ZM_EXTRA_LIBS "" CACHE STRING "A list of optional libraries, separated by se set(ZM_MYSQL_ENGINE "InnoDB" CACHE STRING "MySQL engine to use with database, default: InnoDB") 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_FFMPEG "OFF" CACHE BOOL "Set to ON to skip ffmpeg checks and force building ZM without ffmpeg. 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_X10 "OFF" CACHE BOOL "Set to ON to build ZoneMinder without X10 support. default: OFF") set(ZM_PERL_SUBPREFIX "${CMAKE_INSTALL_LIBDIR}/perl5" CACHE PATH "Use a different directory for the zm perl modules. NOTE: This is a subprefix, e.g. lib will be turned into /lib, default: /perl5") set(ZM_PERL_USE_PATH "${CMAKE_INSTALL_PREFIX}/${ZM_PERL_SUBPREFIX}" CACHE PATH "Override the include path for zm perl modules. Useful if you are moving the perl modules without using the ZM_PERL_SUBPREFIX option. default: /") @@ -324,6 +325,26 @@ if(NOT ZM_NO_FFMPEG) endif(NOT ZM_NO_FFMPEG) +# 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) + include_directories("${LIBVLC_INCLUDE_DIR}") + set(CMAKE_REQUIRED_INCLUDES "${LIBVLC_INCLUDE_DIR}") + endif(LIBVLC_INCLUDE_DIR) + mark_as_advanced(FORCE LIBVLC_LIBRARIES LIBVLC_INCLUDE_DIR) + check_include_file("vlc/vlc.h" HAVE_LIBVLC_VLC_H) + set(optlibsfound "${optlibsfound} libVLC") + else(LIBVLC_LIBRARIES) + set(optlibsnotfound "${optlibsnotfound} libVLC") + endif(LIBVLC_LIBRARIES) +endif(NOT ZM_NO_LIBVLC) + # *** END OF LIBRARY CHECKS *** # Check for gnutls or crypto diff --git a/configure.ac b/configure.ac index 9e39c06f3..5e301df9d 100644 --- a/configure.ac +++ b/configure.ac @@ -275,6 +275,7 @@ AC_CHECK_LIB(avformat,avformat_version,,AC_MSG_WARN(libavformat.a is required fo #AC_CHECK_LIB(avformat,av_new_stream,,AC_MSG_WARN(libavformat.a is required for MPEG streaming)) AC_CHECK_LIB(avdevice,avdevice_register_all,,AC_MSG_WARN(libavdevice.a may be required for MPEG streaming)) AC_CHECK_LIB(swscale,sws_scale,,,-lswscale) +AC_CHECK_LIB(vlc,libvlc_new,,AC_MSG_WARN(libvlc.a may be required for streaming)) AC_CHECK_LIB(bz2,BZ2_bzCompress,,AC_MSG_WARN(zm requires libbz2.a for recent versions of ffmpeg)) AC_CHECK_LIB(z,compress,,) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 72c7a4637..b6e0b8223 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -63,7 +63,7 @@ DROP TABLE IF EXISTS `Controls`; CREATE TABLE `Controls` ( `Id` int(10) unsigned NOT NULL auto_increment, `Name` varchar(64) NOT NULL default '', - `Type` enum('Local','Remote','Ffmpeg') NOT NULL default 'Local', + `Type` enum('Local','Remote','Ffmpeg','Libvlc') NOT NULL default 'Local', `Protocol` varchar(64) default NULL, `CanWake` tinyint(3) unsigned NOT NULL default '0', `CanSleep` tinyint(3) unsigned NOT NULL default '0', @@ -282,7 +282,7 @@ DROP TABLE IF EXISTS `MonitorPresets`; CREATE TABLE `MonitorPresets` ( `Id` int(10) unsigned NOT NULL auto_increment, `Name` varchar(64) NOT NULL default '', - `Type` enum('Local','Remote','File','Ffmpeg') NOT NULL default 'Local', + `Type` enum('Local','Remote','File','Ffmpeg','Libvlc') NOT NULL default 'Local', `Device` tinytext, `Channel` tinytext, `Format` int(10) unsigned default NULL, @@ -313,7 +313,7 @@ DROP TABLE IF EXISTS `Monitors`; CREATE TABLE `Monitors` ( `Id` int(10) unsigned NOT NULL auto_increment, `Name` varchar(64) NOT NULL default '', - `Type` enum('Local','Remote','File','Ffmpeg') NOT NULL default 'Local', + `Type` enum('Local','Remote','File','Ffmpeg','Libvlc') NOT NULL default 'Local', `Function` enum('None','Monitor','Modect','Record','Mocord','Nodect') NOT NULL default 'Monitor', `Enabled` tinyint(3) unsigned NOT NULL default '1', `LinkedMonitors` varchar(255) NOT NULL default '', diff --git a/db/zm_update-1.26.6.sql b/db/zm_update-1.26.6.sql new file mode 100644 index 000000000..4b667d8a8 --- /dev/null +++ b/db/zm_update-1.26.6.sql @@ -0,0 +1,11 @@ +-- +-- This updates a 1.26.5 database to 1.26.6 +-- + +-- +-- Add Libvlc monitor type +-- + +ALTER TABLE Controls modify column Type enum('Local','Remote','Ffmpeg','Libvlc') NOT NULL default 'Local'; +ALTER TABLE MonitorPresets modify column Type enum('Local','Remote','File','Ffmpeg','Libvlc') NOT NULL default 'Local'; +ALTER TABLE Monitors modify column Type enum('Local','Remote','File','Ffmpeg','Libvlc') NOT NULL default 'Local'; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b91baa978..8f65e9f4b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY) # Group together all the source files that are used by all the binaries (zmc, zma, zmu, zms etc) -set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_image.cpp zm_jpeg.cpp zm_local_camera.cpp zm_monitor.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_zone.cpp) +set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_zone.cpp) # A fix for cmake recompiling the source files for every target. add_library(zm STATIC ${ZM_BIN_SRC_FILES}) diff --git a/src/zm_camera.h b/src/zm_camera.h index 8713d3956..aff4b8926 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -32,7 +32,7 @@ class Camera { protected: - typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC } SourceType; + typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC } SourceType; int id; SourceType type; @@ -58,6 +58,7 @@ public: 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 ); } unsigned int Width() const { return( width ); } unsigned int Height() const { return( height ); } unsigned int Colours() const { return( colours ); } diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp new file mode 100644 index 000000000..56ac2838a --- /dev/null +++ b/src/zm_libvlc_camera.cpp @@ -0,0 +1,156 @@ +/* + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "zm.h" +#include "zm_libvlc_camera.h" + +#if HAVE_LIBVLC + +void* LibvlcLockBuffer(void* opaque, void** planes) +{ + LibvlcPrivateData* data = (LibvlcPrivateData*)opaque; + data->mutex.lock(); + *planes = data->buffer; + return NULL; +} + +void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) +{ + LibvlcPrivateData* data = (LibvlcPrivateData*)opaque; + data->mutex.unlock(); + data->newImage.updateValueBroadcast(true); +} + +LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : + Camera( p_id, 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 ), + mPath( p_path ) +{ + mLibvlcInstance = NULL; + mLibvlcMedia = NULL; + mLibvlcMediaPlayer = NULL; + + /* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */ + if(colours == ZM_COLOUR_RGB32) { + subpixelorder = ZM_SUBPIX_ORDER_RGBA; + mTargetChroma = "RV32"; + mBpp = 4; + } else if(colours == ZM_COLOUR_RGB24) { + subpixelorder = ZM_SUBPIX_ORDER_RGB; + mTargetChroma = "RV24"; + mBpp = 3; + } else if(colours == ZM_COLOUR_GRAY8) { + subpixelorder = ZM_SUBPIX_ORDER_NONE; + mTargetChroma = "RGB8"; + mBpp = 1; + } else { + Panic("Unexpected colours: %d",colours); + } + + if ( capture ) + { + Initialise(); + } +} + +LibvlcCamera::~LibvlcCamera() +{ + if ( capture ) + { + Terminate(); + } + if(mLibvlcMediaPlayer != NULL) + { + libvlc_media_player_release(mLibvlcMediaPlayer); + mLibvlcMediaPlayer = NULL; + } + if(mLibvlcMedia != NULL) + { + libvlc_media_release(mLibvlcMedia); + mLibvlcMedia = NULL; + } + if(mLibvlcInstance != NULL) + { + libvlc_release(mLibvlcInstance); + mLibvlcInstance = NULL; + } +} + +void LibvlcCamera::Initialise() +{ +} + +void LibvlcCamera::Terminate() +{ + libvlc_media_player_stop(mLibvlcMediaPlayer); + + zm_freealigned(mLibvlcData.buffer); +} + +int LibvlcCamera::PrimeCapture() +{ + Info("Priming capture from %s", mPath.c_str()); + + mLibvlcInstance = libvlc_new (0, NULL); + if(mLibvlcInstance == NULL) + Fatal("Unable to create libvlc instance due to: %s", strerror(errno)); + + mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str()); + if(mLibvlcMedia == NULL) + Fatal( "Unable to open input %s due to: %s", mPath.c_str(), strerror(errno) ); + + mLibvlcMediaPlayer = libvlc_media_player_new_from_media(mLibvlcMedia); + if(mLibvlcMediaPlayer == NULL) + Fatal( "Unable to create player for %s due to: %s", mPath.c_str(), strerror(errno) ); + + libvlc_video_set_format(mLibvlcMediaPlayer, mTargetChroma.c_str(), width, height, width * mBpp); + libvlc_video_set_callbacks(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, NULL, &mLibvlcData); + + mLibvlcData.buffer = (uint8_t*)zm_mallocaligned(32, width * height * mBpp); + mLibvlcData.newImage.setValueImmediate(false); + + libvlc_media_player_play(mLibvlcMediaPlayer); + + return(0); +} + +int LibvlcCamera::PreCapture() +{ + return(0); +} + +// Should not return -1 as cancels capture. Always wait for image if available. +int LibvlcCamera::Capture( Image &image ) +{ + while(!mLibvlcData.newImage.getValue()) + mLibvlcData.newImage.getUpdatedValue(1); + + mLibvlcData.mutex.lock(); + image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp); + mLibvlcData.newImage.setValueImmediate(false); + mLibvlcData.mutex.unlock(); + + return (0); +} + +int LibvlcCamera::PostCapture() +{ + return(0); +} + +#endif // HAVE_LIBVLC diff --git a/src/zm_libvlc_camera.h b/src/zm_libvlc_camera.h new file mode 100644 index 000000000..2db25f9a8 --- /dev/null +++ b/src/zm_libvlc_camera.h @@ -0,0 +1,67 @@ +/* + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef ZM_LIBVLC_CAMERA_H +#define ZM_LIBVLC_CAMERA_H + +#include "zm_buffer.h" +#include "zm_camera.h" +#include "zm_thread.h" + +#if HAVE_LIBVLC +#include "vlc/vlc.h" + +// Used by libvlc callbacks +struct LibvlcPrivateData +{ + uint8_t* buffer; + Mutex mutex; + ThreadData newImage; +}; + +class LibvlcCamera : public Camera +{ +protected: + std::string mPath; + + LibvlcPrivateData mLibvlcData; + std::string mTargetChroma; + uint8_t mBpp; + + libvlc_instance_t *mLibvlcInstance; + libvlc_media_t *mLibvlcMedia; + libvlc_media_player_t *mLibvlcMediaPlayer; + +public: + LibvlcCamera( int p_id, const std::string &path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ); + ~LibvlcCamera(); + + const std::string &Path() const { return( mPath ); } + + void Initialise(); + void Terminate(); + + int PrimeCapture(); + int PreCapture(); + int Capture( Image &image ); + int PostCapture(); +}; + +#endif // HAVE_LIBVLC +#endif // ZM_LIBVLC_CAMERA_H diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 028d32d55..78def1112 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -40,6 +40,9 @@ #if HAVE_LIBAVFORMAT #include "zm_ffmpeg_camera.h" #endif // HAVE_LIBAVFORMAT +#if HAVE_LIBVLC +#include "zm_libvlc_camera.h" +#endif // HAVE_LIBVLC #if ZM_MEM_MAPPED #include @@ -2604,6 +2607,25 @@ Monitor *Monitor::Load( int id, bool load_zones, Purpose purpose ) #else // HAVE_LIBAVFORMAT Fatal( "You must have ffmpeg libraries installed to use ffmpeg cameras for monitor %d", id ); #endif // HAVE_LIBAVFORMAT + } + else if (type == "Libvlc") + { +#if HAVE_LIBVLC + camera = new LibvlcCamera( + id, + path.c_str(), + cam_width, + cam_height, + colours, + brightness, + contrast, + hue, + colour, + purpose==CAPTURE + ); +#else // HAVE_LIBVLC + Fatal( "You must have vlc libraries installed to use vlc cameras for monitor %d", id ); +#endif // HAVE_LIBVLC } else { diff --git a/zoneminder-config.cmake b/zoneminder-config.cmake index a665a3012..cf010d503 100644 --- a/zoneminder-config.cmake +++ b/zoneminder-config.cmake @@ -48,6 +48,7 @@ #cmakedefine HAVE_LIBAVUTIL_MATHEMATICS_H 1 #cmakedefine HAVE_LIBSWSCALE 1 #cmakedefine HAVE_LIBSWSCALE_SWSCALE_H 1 +#cmakedefine HAVE_LIBVLC 1 /* Authenication checks */ #cmakedefine HAVE_MD5_OPENSSL 1