diff --git a/db/zm_update-1.27.1.sql b/db/zm_update-1.27.1.sql index df2029fbf..b234285bf 100644 --- a/db/zm_update-1.27.1.sql +++ b/db/zm_update-1.27.1.sql @@ -157,7 +157,7 @@ PREPARE stmt FROM @s; EXECUTE stmt; -- --- Add Monitor Options field; used for specifying Ffmpeg AVoptions like rtsp_transport tcp +-- Add Monitor Options field; used for specifying Ffmpeg AVoptions like rtsp_transport http or libVLC options -- SET @s = (SELECT IF( (SELECT COUNT(*) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index c69907d9c..8db581c72 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -23,9 +23,10 @@ #include "zm_ffmpeg_camera.h" -FfmpegCamera::FfmpegCamera( 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 ) : +FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, 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 ) : Camera( p_id, FFMPEG_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 ) + mPath( p_path ), + mOptions( p_options ) { if ( capture ) { @@ -110,12 +111,23 @@ void FfmpegCamera::Terminate() int FfmpegCamera::PrimeCapture() { Info( "Priming capture from %s", mPath.c_str() ); + + // Open the input, not necessarily a file #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) if ( av_open_input_file( &mFormatContext, mPath.c_str(), NULL, 0, NULL ) !=0 ) #else - if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, NULL ) !=0 ) + // Handle options + AVDictionary *opts = 0; + StringVector opVect = split(Options(), ","); + for (int i=0; i 1) + av_dict_set(&opts, trimSpaces(parts[0]), trimSpaces(parts[1])); + } + if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, &opts ) !=0 ) #endif Fatal( "Unable to open input %s due to: %s", mPath.c_str(), strerror(errno) ); diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index 3b24c4d6f..0da0237da 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -34,6 +34,7 @@ class FfmpegCamera : public Camera { protected: std::string mPath; + std::string mOptions; int frameCount; @@ -52,10 +53,11 @@ protected: #endif public: - FfmpegCamera( 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 ); + FfmpegCamera( int p_id, const std::string &path, 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 ); ~FfmpegCamera(); const std::string &Path() const { return( mPath ); } + const std::string &Options() const { return( mOptions ); } void Initialise(); void Terminate(); diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp index 8c56a5346..f127fe3a0 100644 --- a/src/zm_libvlc_camera.cpp +++ b/src/zm_libvlc_camera.cpp @@ -61,9 +61,10 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) } } -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 ) : +LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, 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 ) : 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 ) + mPath( p_path ), + mOptions( p_options ) { mLibvlcInstance = NULL; mLibvlcMedia = NULL; @@ -115,6 +116,10 @@ LibvlcCamera::~LibvlcCamera() libvlc_release(mLibvlcInstance); mLibvlcInstance = NULL; } + if (mOptArgV != NULL) + { + delete[] mOptArgV; + } } void LibvlcCamera::Initialise() @@ -137,8 +142,17 @@ void LibvlcCamera::Terminate() int LibvlcCamera::PrimeCapture() { Info("Priming capture from %s", mPath.c_str()); - - mLibvlcInstance = libvlc_new (0, NULL); + + StringVector opVect = split(Options(), ","); + + if (opVect.size() > 0) + { + mOptArgV = new char*[opVect.size()];cmd + for (int i=0; i< opVect.size(); i++) + mOptArgV[i] = opVect[i].c_str(); + } + + mLibvlcInstance = libvlc_new (opVect.size(), optArgV); if(mLibvlcInstance == NULL) Fatal("Unable to create libvlc instance due to: %s", libvlc_errmsg()); diff --git a/src/zm_libvlc_camera.h b/src/zm_libvlc_camera.h index 0e5d94821..75d97ad72 100644 --- a/src/zm_libvlc_camera.h +++ b/src/zm_libvlc_camera.h @@ -45,7 +45,8 @@ class LibvlcCamera : public Camera { protected: std::string mPath; - + std::string mOptions; + unisgned char **mOptArgV; LibvlcPrivateData mLibvlcData; std::string mTargetChroma; uint8_t mBpp; @@ -55,10 +56,11 @@ protected: 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( int p_id, const std::string &path, 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 ); ~LibvlcCamera(); const std::string &Path() const { return( mPath ); } + const std::string &Options() const { return( mOptions ); } void Initialise(); void Terminate(); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 9b84ced6b..479ea6c4b 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -56,21 +56,6 @@ #endif // ZM_MEM_MAPPED //============================================================================= -std::string trimSpaces(std::string str) -{ - // Trim Both leading and trailing spaces - size_t startpos = str.find_first_not_of(" \t"); // Find the first character position after excluding leading blank spaces - size_t endpos = str.find_last_not_of(" \t"); // Find the first character position from reverse af - - // if all spaces or empty return an empty string - if(( std::string::npos == startpos ) || ( std::string::npos == endpos)) - { - return std::string(""); - } - else - return str.substr( startpos, endpos-startpos+1 ); -} - std::vector split(const std::string &s, char delim) { std::vector elems; std::stringstream ss(s); @@ -2306,11 +2291,11 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose static char sql[ZM_SQL_MED_BUFSIZ]; if ( !file[0] ) { - strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Ffmpeg'", sizeof(sql) ); + strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Ffmpeg'", sizeof(sql) ); } else { - snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Ffmpeg' and Path = '%s'", file ); + snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Ffmpeg' and Path = '%s'", file ); } if ( mysql_query( &dbconn, sql ) ) { @@ -2339,6 +2324,7 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose const char *linked_monitors = dbrow[col]; col++; const char *path = dbrow[col]; col++; + const char *options = dbrow[col]; col++; int width = atoi(dbrow[col]); col++; int height = atoi(dbrow[col]); col++; @@ -2379,6 +2365,7 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose Camera *camera = new FfmpegCamera( id, path, // File + options, cam_width, cam_height, colours, @@ -2441,7 +2428,7 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose Monitor *Monitor::Load( int id, bool load_zones, Purpose purpose ) { static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "select Id, Name, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, Protocol, Method, Host, Port, Path, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = %d", id ); + snprintf( sql, sizeof(sql), "select Id, Name, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = %d", id ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); @@ -2477,6 +2464,7 @@ Monitor *Monitor::Load( int id, bool load_zones, Purpose purpose ) std::string host = dbrow[col]; col++; std::string port = dbrow[col]; col++; std::string path = dbrow[col]; col++; + std::string options = dbrow[col]; col++; std::string user = dbrow[col]; col++; std::string pass = dbrow[col]; col++; @@ -2617,6 +2605,7 @@ Monitor *Monitor::Load( int id, bool load_zones, Purpose purpose ) camera = new FfmpegCamera( id, path.c_str(), + options, cam_width, cam_height, colours, @@ -2636,6 +2625,7 @@ Monitor *Monitor::Load( int id, bool load_zones, Purpose purpose ) camera = new LibvlcCamera( id, path.c_str(), + options, cam_width, cam_height, colours, diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 2576c3cd0..1347f283d 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -30,6 +30,7 @@ #include "zm_zone.h" #include "zm_event.h" #include "zm_camera.h" +#include "zm_utils.h" #include "zm_image_analyser.h" diff --git a/src/zm_utils.cpp b/src/zm_utils.cpp index d2938b7cd..51beb377d 100644 --- a/src/zm_utils.cpp +++ b/src/zm_utils.cpp @@ -27,6 +27,36 @@ unsigned int sseversion = 0; +std::string trimSet(std::string str, std::string trimset) { + // Trim Both leading and trailing sets + size_t startpos = str.find_first_not_of(trimset); // Find the first character position after excluding leading blank spaces + size_t endpos = str.find_last_not_of(trimset); // Find the first character position from reverse af + + // if all spaces or empty return an empty string + if(( std::string::npos == startpos ) || ( std::string::npos == endpos)) + { + return std::string(""); + } + else + return str.substr( startpos, endpos-startpos+1 ); +} + +std::string trimSpaces(std::string str) +{ + return trimSet(str, " \t"); +} + +std::string replaceAll(std::string str, std::string from, std::string to) { + if(from.empty()) + return str; + size_t start_pos = 0; + while((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } + return str; +} + const std::string stringtf( const char *format, ... ) { va_list ap; diff --git a/src/zm_utils.h b/src/zm_utils.h index 2be9b373b..6536024a9 100644 --- a/src/zm_utils.h +++ b/src/zm_utils.h @@ -27,6 +27,10 @@ typedef std::vector StringVector; +std::string trimSpaces(std::string str); +std::string trimSet(std::string str, std::string trimset); +std::string replaceAll(std::string str, std::string from, std::string to); + const std::string stringtf( const char *format, ... ); const std::string stringtf( const std::string &format, ... ); diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 2417c3dd7..03e444c71 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -63,6 +63,7 @@ else 'Method' => "", 'Host' => "", 'Path' => "", + 'Options' => "", 'Port' => "80", 'User' => "", 'Pass' => "", @@ -506,6 +507,12 @@ if ( $tab != 'source' || ($newMonitor['Type'] != 'Local' && $newMonitor['Type'] + + @@ -722,7 +729,7 @@ switch ( $tab ) @@ -734,6 +741,13 @@ switch ( $tab ) + + + diff --git a/web/skins/flat/views/monitor.php b/web/skins/flat/views/monitor.php index 2752bbb8c..42d122886 100644 --- a/web/skins/flat/views/monitor.php +++ b/web/skins/flat/views/monitor.php @@ -63,6 +63,7 @@ else 'Method' => "", 'Host' => "", 'Path' => "", + 'Options' => "", 'Port' => "80", 'User' => "", 'Pass' => "", @@ -507,6 +508,12 @@ if ( $tab != 'source' || ($newMonitor['Type'] != 'Local' && $newMonitor['Type'] + + @@ -723,7 +730,7 @@ switch ( $tab ) @@ -735,6 +742,13 @@ switch ( $tab ) + + +