From 2b79ff2cbdcad999a0c1c6861c9b155835b02451 Mon Sep 17 00:00:00 2001 From: Kfir Itzhak Date: Thu, 19 Dec 2013 18:38:07 +0200 Subject: [PATCH] Initial commit for saving events as videos :) --- CMakeLists.txt | 34 ++ configure.ac | 3 + src/CMakeLists.txt | 2 +- src/zm_config_defines.h | 658 -------------------------- src/zm_event.cpp | 115 ++++- src/zm_event.h | 10 + src/zm_ffmpeg.cpp | 17 +- src/zm_ffmpeg.h | 2 + src/zm_monitor.cpp | 70 ++- src/zm_monitor.h | 12 +- src/zm_video.cpp | 492 +++++++++++++++++++ src/zm_video.h | 168 +++++++ web/ajax/status.php | 14 +- web/includes/functions.php | 3 + web/skins/classic/views/css/event.css | 17 + web/skins/classic/views/event.php | 14 + web/skins/classic/views/js/event.js | 79 +++- web/skins/classic/views/monitor.php | 32 ++ zoneminder-config.cmake | 4 + 19 files changed, 1048 insertions(+), 698 deletions(-) delete mode 100644 src/zm_config_defines.h create mode 100644 src/zm_video.cpp create mode 100644 src/zm_video.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e0a93bf00..e45b0b4ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,6 +224,40 @@ else(MYSQLCLIENT_LIBRARIES) message(FATAL_ERROR "zm requires mysqlclient but it was not found on your system") endif(MYSQLCLIENT_LIBRARIES) +# x264 (using find_library and find_path) +find_library(X264_LIBRARIES x264) +if(X264_LIBRARIES) + set(HAVE_LIBX264 1) + list(APPEND ZM_BIN_LIBS "${X264_LIBRARIES}") + find_path(X264_INCLUDE_DIR x264.h) + if(X264_INCLUDE_DIR) + include_directories("${X264_INCLUDE_DIR}") + set(CMAKE_REQUIRED_INCLUDES "${X264_INCLUDE_DIR}") + endif(X264_INCLUDE_DIR) + mark_as_advanced(FORCE X264_LIBRARIES X264_INCLUDE_DIR) + check_include_files("stdint.h;x264.h" HAVE_X264_H) + set(optlibsfound "${optlibsfound} x264") +else(X264_LIBRARIES) + set(optlibsnotfound "${optlibsnotfound} x264") +endif(X264_LIBRARIES) + +# mp4v2 (using find_library and find_path) +find_library(MP4V2_LIBRARIES mp4v2) +if(MP4V2_LIBRARIES) + set(HAVE_LIBMP4V2 1) + list(APPEND ZM_BIN_LIBS "${MP4V2_LIBRARIES}") + find_path(MP4V2_INCLUDE_DIR mp4.h) + if(MP4V2_INCLUDE_DIR) + include_directories("${MP4V2_INCLUDE_DIR}") + set(CMAKE_REQUIRED_INCLUDES "${MP4V2_INCLUDE_DIR}") + endif(MP4V2_INCLUDE_DIR) + mark_as_advanced(FORCE MP4V2_LIBRARIES MP4V2_INCLUDE_DIR) + check_include_file("mp4.h" HAVE_MP4_H) + set(optlibsfound "${optlibsfound} mp4v2") +else(MP4V2_LIBRARIES) + set(optlibsnotfound "${optlibsnotfound} mp4v2") +endif(MP4V2_LIBRARIES) + set(PATH_FFMPEG "") set(OPT_FFMPEG "no") # Do not check for ffmpeg if ZM_NO_FFMPEG is on diff --git a/configure.ac b/configure.ac index 9e39c06f3..dfd204bf4 100644 --- a/configure.ac +++ b/configure.ac @@ -266,6 +266,7 @@ fi AC_CHECK_LIB(pcre,pcre_compile,,AC_MSG_WARN(libpcre.a may be required for remote/network camera support)) AC_CHECK_LIB(z,zlibVersion) AC_CHECK_LIB(x264,x264_predict_16x16_init) +AC_CHECK_LIB(mp4v2,MP4AddH264VideoTrack) AC_CHECK_LIB(avutil,av_malloc,,AC_MSG_WARN(libavutil.a may be required for MPEG streaming)) # Don't bother to warn about this one AC_CHECK_LIB(avcore,av_image_copy,,) @@ -313,6 +314,8 @@ AC_CHECK_HEADERS(sys/ipc.h,,,) AC_CHECK_HEADERS(sys/shm.h,,,) fi AC_CHECK_HEADERS(zlib.h,,,) +AC_CHECK_HEADERS(x264.h,,,) +AC_CHECK_HEADERS(mp4.h,,,) if test "$ZM_SSL_LIB" == "openssl"; then AC_CHECK_DECLS(MD5,,AC_MSG_ERROR([zm requires openssl/md5.h - use ZM_SSL_LIB option to select gnutls instead]),[#include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b91baa978..5e7c10145 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_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_video.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_config_defines.h b/src/zm_config_defines.h deleted file mode 100644 index 4d3b9085a..000000000 --- a/src/zm_config_defines.h +++ /dev/null @@ -1,658 +0,0 @@ -// The file is autogenerated by zmconfgen.pl -// Do not edit this file as any changes will be overwritten - -#define ZM_LANG_DEFAULT 0 -#define ZM_OPT_USE_AUTH 1 -#define ZM_AUTH_TYPE 2 -#define ZM_AUTH_RELAY 3 -#define ZM_AUTH_HASH_SECRET 4 -#define ZM_AUTH_HASH_IPS 5 -#define ZM_AUTH_HASH_LOGINS 6 -#define ZM_DIR_EVENTS 7 -#define ZM_USE_DEEP_STORAGE 8 -#define ZM_DIR_IMAGES 9 -#define ZM_DIR_SOUNDS 10 -#define ZM_PATH_ZMS 11 -#define ZM_COLOUR_JPEG_FILES 12 -#define ZM_ADD_JPEG_COMMENTS 13 -#define ZM_JPEG_FILE_QUALITY 14 -#define ZM_JPEG_ALARM_FILE_QUALITY 15 -#define ZM_JPEG_IMAGE_QUALITY 16 -#define ZM_JPEG_STREAM_QUALITY 17 -#define ZM_MPEG_TIMED_FRAMES 18 -#define ZM_MPEG_LIVE_FORMAT 19 -#define ZM_MPEG_REPLAY_FORMAT 20 -#define ZM_RAND_STREAM 21 -#define ZM_OPT_CAMBOZOLA 22 -#define ZM_PATH_CAMBOZOLA 23 -#define ZM_RELOAD_CAMBOZOLA 24 -#define ZM_TIMESTAMP_ON_CAPTURE 25 -#define ZM_CPU_EXTENSIONS 26 -#define ZM_FAST_IMAGE_BLENDS 27 -#define ZM_OPT_ADAPTIVE_SKIP 28 -#define ZM_MAX_SUSPEND_TIME 29 -#define ZM_OPT_REMOTE_CAMERAS 30 -#define ZM_NETCAM_REGEXPS 31 -#define ZM_HTTP_VERSION 32 -#define ZM_HTTP_UA 33 -#define ZM_HTTP_TIMEOUT 34 -#define ZM_MIN_RTP_PORT 35 -#define ZM_MAX_RTP_PORT 36 -#define ZM_OPT_FFMPEG 37 -#define ZM_PATH_FFMPEG 38 -#define ZM_FFMPEG_INPUT_OPTIONS 39 -#define ZM_FFMPEG_OUTPUT_OPTIONS 40 -#define ZM_FFMPEG_FORMATS 41 -#define ZM_LOG_LEVEL_SYSLOG 42 -#define ZM_LOG_LEVEL_FILE 43 -#define ZM_LOG_LEVEL_WEBLOG 44 -#define ZM_LOG_LEVEL_DATABASE 45 -#define ZM_LOG_DATABASE_LIMIT 46 -#define ZM_LOG_DEBUG 47 -#define ZM_LOG_DEBUG_TARGET 48 -#define ZM_LOG_DEBUG_LEVEL 49 -#define ZM_LOG_DEBUG_FILE 50 -#define ZM_LOG_CHECK_PERIOD 51 -#define ZM_LOG_ALERT_WAR_COUNT 52 -#define ZM_LOG_ALERT_ERR_COUNT 53 -#define ZM_LOG_ALERT_FAT_COUNT 54 -#define ZM_LOG_ALARM_WAR_COUNT 55 -#define ZM_LOG_ALARM_ERR_COUNT 56 -#define ZM_LOG_ALARM_FAT_COUNT 57 -#define ZM_RECORD_EVENT_STATS 58 -#define ZM_RECORD_DIAG_IMAGES 59 -#define ZM_DUMP_CORES 60 -#define ZM_PATH_MAP 61 -#define ZM_PATH_SOCKS 62 -#define ZM_PATH_LOGS 63 -#define ZM_PATH_SWAP 64 -#define ZM_WEB_TITLE_PREFIX 65 -#define ZM_WEB_RESIZE_CONSOLE 66 -#define ZM_WEB_POPUP_ON_ALARM 67 -#define ZM_OPT_X10 68 -#define ZM_X10_DEVICE 69 -#define ZM_X10_HOUSE_CODE 70 -#define ZM_X10_DB_RELOAD_INTERVAL 71 -#define ZM_WEB_SOUND_ON_ALARM 72 -#define ZM_WEB_ALARM_SOUND 73 -#define ZM_WEB_COMPACT_MONTAGE 74 -#define ZM_OPT_FAST_DELETE 75 -#define ZM_STRICT_VIDEO_CONFIG 76 -#define ZM_SIGNAL_CHECK_POINTS 77 -#define ZM_V4L_MULTI_BUFFER 78 -#define ZM_CAPTURES_PER_FRAME 79 -#define ZM_FILTER_RELOAD_DELAY 80 -#define ZM_FILTER_EXECUTE_INTERVAL 81 -#define ZM_OPT_UPLOAD 82 -#define ZM_UPLOAD_ARCH_FORMAT 83 -#define ZM_UPLOAD_ARCH_COMPRESS 84 -#define ZM_UPLOAD_ARCH_ANALYSE 85 -#define ZM_UPLOAD_PROTOCOL 86 -#define ZM_UPLOAD_FTP_HOST 87 -#define ZM_UPLOAD_HOST 88 -#define ZM_UPLOAD_PORT 89 -#define ZM_UPLOAD_FTP_USER 90 -#define ZM_UPLOAD_USER 91 -#define ZM_UPLOAD_FTP_PASS 92 -#define ZM_UPLOAD_PASS 93 -#define ZM_UPLOAD_FTP_LOC_DIR 94 -#define ZM_UPLOAD_LOC_DIR 95 -#define ZM_UPLOAD_FTP_REM_DIR 96 -#define ZM_UPLOAD_REM_DIR 97 -#define ZM_UPLOAD_FTP_TIMEOUT 98 -#define ZM_UPLOAD_TIMEOUT 99 -#define ZM_UPLOAD_FTP_PASSIVE 100 -#define ZM_UPLOAD_FTP_DEBUG 101 -#define ZM_UPLOAD_DEBUG 102 -#define ZM_OPT_EMAIL 103 -#define ZM_EMAIL_ADDRESS 104 -#define ZM_EMAIL_TEXT 105 -#define ZM_EMAIL_SUBJECT 106 -#define ZM_EMAIL_BODY 107 -#define ZM_OPT_MESSAGE 108 -#define ZM_MESSAGE_ADDRESS 109 -#define ZM_MESSAGE_TEXT 110 -#define ZM_MESSAGE_SUBJECT 111 -#define ZM_MESSAGE_BODY 112 -#define ZM_NEW_MAIL_MODULES 113 -#define ZM_EMAIL_HOST 114 -#define ZM_FROM_EMAIL 115 -#define ZM_URL 116 -#define ZM_MAX_RESTART_DELAY 117 -#define ZM_WATCH_CHECK_INTERVAL 118 -#define ZM_WATCH_MAX_DELAY 119 -#define ZM_RUN_AUDIT 120 -#define ZM_AUDIT_CHECK_INTERVAL 121 -#define ZM_FORCED_ALARM_SCORE 122 -#define ZM_BULK_FRAME_INTERVAL 123 -#define ZM_EVENT_CLOSE_MODE 124 -#define ZM_FORCE_CLOSE_EVENTS 125 -#define ZM_CREATE_ANALYSIS_IMAGES 126 -#define ZM_WEIGHTED_ALARM_CENTRES 127 -#define ZM_EVENT_IMAGE_DIGITS 128 -#define ZM_DEFAULT_ASPECT_RATIO 129 -#define ZM_USER_SELF_EDIT 130 -#define ZM_OPT_FRAME_SERVER 131 -#define ZM_FRAME_SOCKET_SIZE 132 -#define ZM_OPT_CONTROL 133 -#define ZM_OPT_TRIGGERS 134 -#define ZM_CHECK_FOR_UPDATES 135 -#define ZM_UPDATE_CHECK_PROXY 136 -#define ZM_SHM_KEY 137 -#define ZM_WEB_REFRESH_METHOD 138 -#define ZM_WEB_EVENT_SORT_FIELD 139 -#define ZM_WEB_EVENT_SORT_ORDER 140 -#define ZM_WEB_EVENTS_PER_PAGE 141 -#define ZM_WEB_LIST_THUMBS 142 -#define ZM_WEB_LIST_THUMB_WIDTH 143 -#define ZM_WEB_LIST_THUMB_HEIGHT 144 -#define ZM_WEB_USE_OBJECT_TAGS 145 -#define ZM_WEB_H_REFRESH_MAIN 146 -#define ZM_WEB_H_REFRESH_CYCLE 147 -#define ZM_WEB_H_REFRESH_IMAGE 148 -#define ZM_WEB_H_REFRESH_STATUS 149 -#define ZM_WEB_H_REFRESH_EVENTS 150 -#define ZM_WEB_H_CAN_STREAM 151 -#define ZM_WEB_H_STREAM_METHOD 152 -#define ZM_WEB_H_DEFAULT_SCALE 153 -#define ZM_WEB_H_DEFAULT_RATE 154 -#define ZM_WEB_H_VIDEO_BITRATE 155 -#define ZM_WEB_H_VIDEO_MAXFPS 156 -#define ZM_WEB_H_SCALE_THUMBS 157 -#define ZM_WEB_H_EVENTS_VIEW 158 -#define ZM_WEB_H_SHOW_PROGRESS 159 -#define ZM_WEB_H_AJAX_TIMEOUT 160 -#define ZM_WEB_M_REFRESH_MAIN 161 -#define ZM_WEB_M_REFRESH_CYCLE 162 -#define ZM_WEB_M_REFRESH_IMAGE 163 -#define ZM_WEB_M_REFRESH_STATUS 164 -#define ZM_WEB_M_REFRESH_EVENTS 165 -#define ZM_WEB_M_CAN_STREAM 166 -#define ZM_WEB_M_STREAM_METHOD 167 -#define ZM_WEB_M_DEFAULT_SCALE 168 -#define ZM_WEB_M_DEFAULT_RATE 169 -#define ZM_WEB_M_VIDEO_BITRATE 170 -#define ZM_WEB_M_VIDEO_MAXFPS 171 -#define ZM_WEB_M_SCALE_THUMBS 172 -#define ZM_WEB_M_EVENTS_VIEW 173 -#define ZM_WEB_M_SHOW_PROGRESS 174 -#define ZM_WEB_M_AJAX_TIMEOUT 175 -#define ZM_WEB_L_REFRESH_MAIN 176 -#define ZM_WEB_L_REFRESH_CYCLE 177 -#define ZM_WEB_L_REFRESH_IMAGE 178 -#define ZM_WEB_L_REFRESH_STATUS 179 -#define ZM_WEB_L_REFRESH_EVENTS 180 -#define ZM_WEB_L_CAN_STREAM 181 -#define ZM_WEB_L_STREAM_METHOD 182 -#define ZM_WEB_L_DEFAULT_SCALE 183 -#define ZM_WEB_L_DEFAULT_RATE 184 -#define ZM_WEB_L_VIDEO_BITRATE 185 -#define ZM_WEB_L_VIDEO_MAXFPS 186 -#define ZM_WEB_L_SCALE_THUMBS 187 -#define ZM_WEB_L_EVENTS_VIEW 188 -#define ZM_WEB_L_SHOW_PROGRESS 189 -#define ZM_WEB_L_AJAX_TIMEOUT 190 -#define ZM_WEB_P_CAN_STREAM 191 -#define ZM_WEB_P_STREAM_METHOD 192 -#define ZM_WEB_P_DEFAULT_SCALE 193 -#define ZM_WEB_P_DEFAULT_RATE 194 -#define ZM_WEB_P_VIDEO_BITRATE 195 -#define ZM_WEB_P_VIDEO_MAXFPS 196 -#define ZM_WEB_P_SCALE_THUMBS 197 -#define ZM_WEB_P_AJAX_TIMEOUT 198 -#define ZM_DYN_LAST_VERSION 199 -#define ZM_DYN_CURR_VERSION 200 -#define ZM_DYN_DB_VERSION 201 -#define ZM_DYN_LAST_CHECK 202 -#define ZM_DYN_NEXT_REMINDER 203 -#define ZM_DYN_DONATE_REMINDER_TIME 204 -#define ZM_DYN_SHOW_DONATE_REMINDER 205 -#define ZM_EYEZM_DEBUG 206 -#define ZM_EYEZM_LOG_TO_FILE 207 -#define ZM_EYEZM_LOG_FILE 208 -#define ZM_EYEZM_EVENT_VCODEC 209 -#define ZM_EYEZM_FEED_VCODEC 210 -#define ZM_EYEZM_H264_DEFAULT_BR 211 -#define ZM_EYEZM_H264_DEFAULT_EVBR 212 -#define ZM_EYEZM_H264_TIMEOUT 213 -#define ZM_EYEZM_SEG_DURATION 214 - - -#define ZM_MAX_CFG_ID 214 - -#define ZM_CFG_DECLARE_LIST \ - const char *lang_default;\ - bool opt_use_auth;\ - const char *auth_type;\ - const char *auth_relay;\ - const char *auth_hash_secret;\ - bool auth_hash_ips;\ - bool auth_hash_logins;\ - const char *dir_events;\ - bool use_deep_storage;\ - const char *dir_images;\ - const char *dir_sounds;\ - const char *path_zms;\ - bool colour_jpeg_files;\ - bool add_jpeg_comments;\ - int jpeg_file_quality;\ - int jpeg_alarm_file_quality;\ - int jpeg_image_quality;\ - int jpeg_stream_quality;\ - bool mpeg_timed_frames;\ - const char *mpeg_live_format;\ - const char *mpeg_replay_format;\ - bool rand_stream;\ - bool opt_cambozola;\ - const char *path_cambozola;\ - int reload_cambozola;\ - bool timestamp_on_capture;\ - bool cpu_extensions;\ - bool fast_image_blends;\ - bool opt_adaptive_skip;\ - int max_suspend_time;\ - bool opt_remote_cameras;\ - bool netcam_regexps;\ - const char *http_version;\ - const char *http_ua;\ - int http_timeout;\ - int min_rtp_port;\ - int max_rtp_port;\ - bool opt_ffmpeg;\ - const char *path_ffmpeg;\ - const char *ffmpeg_input_options;\ - const char *ffmpeg_output_options;\ - const char *ffmpeg_formats;\ - int log_level_syslog;\ - int log_level_file;\ - int log_level_weblog;\ - int log_level_database;\ - const char *log_database_limit;\ - bool log_debug;\ - const char *log_debug_target;\ - int log_debug_level;\ - const char *log_debug_file;\ - int log_check_period;\ - int log_alert_war_count;\ - int log_alert_err_count;\ - int log_alert_fat_count;\ - int log_alarm_war_count;\ - int log_alarm_err_count;\ - int log_alarm_fat_count;\ - bool record_event_stats;\ - bool record_diag_images;\ - bool dump_cores;\ - const char *path_map;\ - const char *path_socks;\ - const char *path_logs;\ - const char *path_swap;\ - const char *web_title_prefix;\ - bool web_resize_console;\ - bool web_popup_on_alarm;\ - bool opt_x10;\ - const char *x10_device;\ - const char *x10_house_code;\ - int x10_db_reload_interval;\ - bool web_sound_on_alarm;\ - const char *web_alarm_sound;\ - bool web_compact_montage;\ - bool opt_fast_delete;\ - bool strict_video_config;\ - int signal_check_points;\ - bool v4l_multi_buffer;\ - int captures_per_frame;\ - int filter_reload_delay;\ - int filter_execute_interval;\ - bool opt_upload;\ - const char *upload_arch_format;\ - bool upload_arch_compress;\ - bool upload_arch_analyse;\ - const char *upload_protocol;\ - const char *upload_ftp_host;\ - const char *upload_host;\ - int upload_port;\ - const char *upload_ftp_user;\ - const char *upload_user;\ - const char *upload_ftp_pass;\ - const char *upload_pass;\ - const char *upload_ftp_loc_dir;\ - const char *upload_loc_dir;\ - const char *upload_ftp_rem_dir;\ - const char *upload_rem_dir;\ - int upload_ftp_timeout;\ - int upload_timeout;\ - bool upload_ftp_passive;\ - bool upload_ftp_debug;\ - bool upload_debug;\ - bool opt_email;\ - const char *email_address;\ - const char *email_text;\ - const char *email_subject;\ - const char *email_body;\ - bool opt_message;\ - const char *message_address;\ - const char *message_text;\ - const char *message_subject;\ - const char *message_body;\ - bool new_mail_modules;\ - const char *email_host;\ - const char *from_email;\ - const char *url;\ - int max_restart_delay;\ - int watch_check_interval;\ - double watch_max_delay;\ - bool run_audit;\ - int audit_check_interval;\ - int forced_alarm_score;\ - int bulk_frame_interval;\ - const char *event_close_mode;\ - bool force_close_events;\ - bool create_analysis_images;\ - bool weighted_alarm_centres;\ - int event_image_digits;\ - const char *default_aspect_ratio;\ - bool user_self_edit;\ - bool opt_frame_server;\ - int frame_socket_size;\ - bool opt_control;\ - bool opt_triggers;\ - bool check_for_updates;\ - const char *update_check_proxy;\ - int shm_key;\ - const char *web_refresh_method;\ - const char *web_event_sort_field;\ - const char *web_event_sort_order;\ - int web_events_per_page;\ - bool web_list_thumbs;\ - int web_list_thumb_width;\ - int web_list_thumb_height;\ - bool web_use_object_tags;\ - int web_h_refresh_main;\ - int web_h_refresh_cycle;\ - int web_h_refresh_image;\ - int web_h_refresh_status;\ - int web_h_refresh_events;\ - const char *web_h_can_stream;\ - const char *web_h_stream_method;\ - int web_h_default_scale;\ - int web_h_default_rate;\ - int web_h_video_bitrate;\ - int web_h_video_maxfps;\ - bool web_h_scale_thumbs;\ - const char *web_h_events_view;\ - bool web_h_show_progress;\ - int web_h_ajax_timeout;\ - int web_m_refresh_main;\ - int web_m_refresh_cycle;\ - int web_m_refresh_image;\ - int web_m_refresh_status;\ - int web_m_refresh_events;\ - const char *web_m_can_stream;\ - const char *web_m_stream_method;\ - int web_m_default_scale;\ - int web_m_default_rate;\ - int web_m_video_bitrate;\ - int web_m_video_maxfps;\ - bool web_m_scale_thumbs;\ - const char *web_m_events_view;\ - bool web_m_show_progress;\ - int web_m_ajax_timeout;\ - int web_l_refresh_main;\ - int web_l_refresh_cycle;\ - int web_l_refresh_image;\ - int web_l_refresh_status;\ - int web_l_refresh_events;\ - const char *web_l_can_stream;\ - const char *web_l_stream_method;\ - int web_l_default_scale;\ - int web_l_default_rate;\ - int web_l_video_bitrate;\ - int web_l_video_maxfps;\ - bool web_l_scale_thumbs;\ - const char *web_l_events_view;\ - bool web_l_show_progress;\ - int web_l_ajax_timeout;\ - const char *web_p_can_stream;\ - const char *web_p_stream_method;\ - int web_p_default_scale;\ - int web_p_default_rate;\ - int web_p_video_bitrate;\ - int web_p_video_maxfps;\ - bool web_p_scale_thumbs;\ - int web_p_ajax_timeout;\ - const char *dyn_last_version;\ - const char *dyn_curr_version;\ - const char *dyn_db_version;\ - int dyn_last_check;\ - const char *dyn_next_reminder;\ - int dyn_donate_reminder_time;\ - bool dyn_show_donate_reminder;\ - bool eyezm_debug;\ - bool eyezm_log_to_file;\ - const char *eyezm_log_file;\ - const char *eyezm_event_vcodec;\ - const char *eyezm_feed_vcodec;\ - const char *eyezm_h264_default_br;\ - const char *eyezm_h264_default_evbr;\ - const char *eyezm_h264_timeout;\ - const char *eyezm_seg_duration;\ - - -#define ZM_CFG_ASSIGN_LIST \ - lang_default = (const char *)config.Item( ZM_LANG_DEFAULT );\ - opt_use_auth = (bool)config.Item( ZM_OPT_USE_AUTH );\ - auth_type = (const char *)config.Item( ZM_AUTH_TYPE );\ - auth_relay = (const char *)config.Item( ZM_AUTH_RELAY );\ - auth_hash_secret = (const char *)config.Item( ZM_AUTH_HASH_SECRET );\ - auth_hash_ips = (bool)config.Item( ZM_AUTH_HASH_IPS );\ - auth_hash_logins = (bool)config.Item( ZM_AUTH_HASH_LOGINS );\ - dir_events = (const char *)config.Item( ZM_DIR_EVENTS );\ - use_deep_storage = (bool)config.Item( ZM_USE_DEEP_STORAGE );\ - dir_images = (const char *)config.Item( ZM_DIR_IMAGES );\ - dir_sounds = (const char *)config.Item( ZM_DIR_SOUNDS );\ - path_zms = (const char *)config.Item( ZM_PATH_ZMS );\ - colour_jpeg_files = (bool)config.Item( ZM_COLOUR_JPEG_FILES );\ - add_jpeg_comments = (bool)config.Item( ZM_ADD_JPEG_COMMENTS );\ - jpeg_file_quality = (int)config.Item( ZM_JPEG_FILE_QUALITY );\ - jpeg_alarm_file_quality = (int)config.Item( ZM_JPEG_ALARM_FILE_QUALITY );\ - jpeg_image_quality = (int)config.Item( ZM_JPEG_IMAGE_QUALITY );\ - jpeg_stream_quality = (int)config.Item( ZM_JPEG_STREAM_QUALITY );\ - mpeg_timed_frames = (bool)config.Item( ZM_MPEG_TIMED_FRAMES );\ - mpeg_live_format = (const char *)config.Item( ZM_MPEG_LIVE_FORMAT );\ - mpeg_replay_format = (const char *)config.Item( ZM_MPEG_REPLAY_FORMAT );\ - rand_stream = (bool)config.Item( ZM_RAND_STREAM );\ - opt_cambozola = (bool)config.Item( ZM_OPT_CAMBOZOLA );\ - path_cambozola = (const char *)config.Item( ZM_PATH_CAMBOZOLA );\ - reload_cambozola = (int)config.Item( ZM_RELOAD_CAMBOZOLA );\ - timestamp_on_capture = (bool)config.Item( ZM_TIMESTAMP_ON_CAPTURE );\ - cpu_extensions = (bool)config.Item( ZM_CPU_EXTENSIONS );\ - fast_image_blends = (bool)config.Item( ZM_FAST_IMAGE_BLENDS );\ - opt_adaptive_skip = (bool)config.Item( ZM_OPT_ADAPTIVE_SKIP );\ - max_suspend_time = (int)config.Item( ZM_MAX_SUSPEND_TIME );\ - opt_remote_cameras = (bool)config.Item( ZM_OPT_REMOTE_CAMERAS );\ - netcam_regexps = (bool)config.Item( ZM_NETCAM_REGEXPS );\ - http_version = (const char *)config.Item( ZM_HTTP_VERSION );\ - http_ua = (const char *)config.Item( ZM_HTTP_UA );\ - http_timeout = (int)config.Item( ZM_HTTP_TIMEOUT );\ - min_rtp_port = (int)config.Item( ZM_MIN_RTP_PORT );\ - max_rtp_port = (int)config.Item( ZM_MAX_RTP_PORT );\ - opt_ffmpeg = (bool)config.Item( ZM_OPT_FFMPEG );\ - path_ffmpeg = (const char *)config.Item( ZM_PATH_FFMPEG );\ - ffmpeg_input_options = (const char *)config.Item( ZM_FFMPEG_INPUT_OPTIONS );\ - ffmpeg_output_options = (const char *)config.Item( ZM_FFMPEG_OUTPUT_OPTIONS );\ - ffmpeg_formats = (const char *)config.Item( ZM_FFMPEG_FORMATS );\ - log_level_syslog = (int)config.Item( ZM_LOG_LEVEL_SYSLOG );\ - log_level_file = (int)config.Item( ZM_LOG_LEVEL_FILE );\ - log_level_weblog = (int)config.Item( ZM_LOG_LEVEL_WEBLOG );\ - log_level_database = (int)config.Item( ZM_LOG_LEVEL_DATABASE );\ - log_database_limit = (const char *)config.Item( ZM_LOG_DATABASE_LIMIT );\ - log_debug = (bool)config.Item( ZM_LOG_DEBUG );\ - log_debug_target = (const char *)config.Item( ZM_LOG_DEBUG_TARGET );\ - log_debug_level = (int)config.Item( ZM_LOG_DEBUG_LEVEL );\ - log_debug_file = (const char *)config.Item( ZM_LOG_DEBUG_FILE );\ - log_check_period = (int)config.Item( ZM_LOG_CHECK_PERIOD );\ - log_alert_war_count = (int)config.Item( ZM_LOG_ALERT_WAR_COUNT );\ - log_alert_err_count = (int)config.Item( ZM_LOG_ALERT_ERR_COUNT );\ - log_alert_fat_count = (int)config.Item( ZM_LOG_ALERT_FAT_COUNT );\ - log_alarm_war_count = (int)config.Item( ZM_LOG_ALARM_WAR_COUNT );\ - log_alarm_err_count = (int)config.Item( ZM_LOG_ALARM_ERR_COUNT );\ - log_alarm_fat_count = (int)config.Item( ZM_LOG_ALARM_FAT_COUNT );\ - record_event_stats = (bool)config.Item( ZM_RECORD_EVENT_STATS );\ - record_diag_images = (bool)config.Item( ZM_RECORD_DIAG_IMAGES );\ - dump_cores = (bool)config.Item( ZM_DUMP_CORES );\ - path_map = (const char *)config.Item( ZM_PATH_MAP );\ - path_socks = (const char *)config.Item( ZM_PATH_SOCKS );\ - path_logs = (const char *)config.Item( ZM_PATH_LOGS );\ - path_swap = (const char *)config.Item( ZM_PATH_SWAP );\ - web_title_prefix = (const char *)config.Item( ZM_WEB_TITLE_PREFIX );\ - web_resize_console = (bool)config.Item( ZM_WEB_RESIZE_CONSOLE );\ - web_popup_on_alarm = (bool)config.Item( ZM_WEB_POPUP_ON_ALARM );\ - opt_x10 = (bool)config.Item( ZM_OPT_X10 );\ - x10_device = (const char *)config.Item( ZM_X10_DEVICE );\ - x10_house_code = (const char *)config.Item( ZM_X10_HOUSE_CODE );\ - x10_db_reload_interval = (int)config.Item( ZM_X10_DB_RELOAD_INTERVAL );\ - web_sound_on_alarm = (bool)config.Item( ZM_WEB_SOUND_ON_ALARM );\ - web_alarm_sound = (const char *)config.Item( ZM_WEB_ALARM_SOUND );\ - web_compact_montage = (bool)config.Item( ZM_WEB_COMPACT_MONTAGE );\ - opt_fast_delete = (bool)config.Item( ZM_OPT_FAST_DELETE );\ - strict_video_config = (bool)config.Item( ZM_STRICT_VIDEO_CONFIG );\ - signal_check_points = (int)config.Item( ZM_SIGNAL_CHECK_POINTS );\ - v4l_multi_buffer = (bool)config.Item( ZM_V4L_MULTI_BUFFER );\ - captures_per_frame = (int)config.Item( ZM_CAPTURES_PER_FRAME );\ - filter_reload_delay = (int)config.Item( ZM_FILTER_RELOAD_DELAY );\ - filter_execute_interval = (int)config.Item( ZM_FILTER_EXECUTE_INTERVAL );\ - opt_upload = (bool)config.Item( ZM_OPT_UPLOAD );\ - upload_arch_format = (const char *)config.Item( ZM_UPLOAD_ARCH_FORMAT );\ - upload_arch_compress = (bool)config.Item( ZM_UPLOAD_ARCH_COMPRESS );\ - upload_arch_analyse = (bool)config.Item( ZM_UPLOAD_ARCH_ANALYSE );\ - upload_protocol = (const char *)config.Item( ZM_UPLOAD_PROTOCOL );\ - upload_ftp_host = (const char *)config.Item( ZM_UPLOAD_FTP_HOST );\ - upload_host = (const char *)config.Item( ZM_UPLOAD_HOST );\ - upload_port = (int)config.Item( ZM_UPLOAD_PORT );\ - upload_ftp_user = (const char *)config.Item( ZM_UPLOAD_FTP_USER );\ - upload_user = (const char *)config.Item( ZM_UPLOAD_USER );\ - upload_ftp_pass = (const char *)config.Item( ZM_UPLOAD_FTP_PASS );\ - upload_pass = (const char *)config.Item( ZM_UPLOAD_PASS );\ - upload_ftp_loc_dir = (const char *)config.Item( ZM_UPLOAD_FTP_LOC_DIR );\ - upload_loc_dir = (const char *)config.Item( ZM_UPLOAD_LOC_DIR );\ - upload_ftp_rem_dir = (const char *)config.Item( ZM_UPLOAD_FTP_REM_DIR );\ - upload_rem_dir = (const char *)config.Item( ZM_UPLOAD_REM_DIR );\ - upload_ftp_timeout = (int)config.Item( ZM_UPLOAD_FTP_TIMEOUT );\ - upload_timeout = (int)config.Item( ZM_UPLOAD_TIMEOUT );\ - upload_ftp_passive = (bool)config.Item( ZM_UPLOAD_FTP_PASSIVE );\ - upload_ftp_debug = (bool)config.Item( ZM_UPLOAD_FTP_DEBUG );\ - upload_debug = (bool)config.Item( ZM_UPLOAD_DEBUG );\ - opt_email = (bool)config.Item( ZM_OPT_EMAIL );\ - email_address = (const char *)config.Item( ZM_EMAIL_ADDRESS );\ - email_text = (const char *)config.Item( ZM_EMAIL_TEXT );\ - email_subject = (const char *)config.Item( ZM_EMAIL_SUBJECT );\ - email_body = (const char *)config.Item( ZM_EMAIL_BODY );\ - opt_message = (bool)config.Item( ZM_OPT_MESSAGE );\ - message_address = (const char *)config.Item( ZM_MESSAGE_ADDRESS );\ - message_text = (const char *)config.Item( ZM_MESSAGE_TEXT );\ - message_subject = (const char *)config.Item( ZM_MESSAGE_SUBJECT );\ - message_body = (const char *)config.Item( ZM_MESSAGE_BODY );\ - new_mail_modules = (bool)config.Item( ZM_NEW_MAIL_MODULES );\ - email_host = (const char *)config.Item( ZM_EMAIL_HOST );\ - from_email = (const char *)config.Item( ZM_FROM_EMAIL );\ - url = (const char *)config.Item( ZM_URL );\ - max_restart_delay = (int)config.Item( ZM_MAX_RESTART_DELAY );\ - watch_check_interval = (int)config.Item( ZM_WATCH_CHECK_INTERVAL );\ - watch_max_delay = (double) config.Item( ZM_WATCH_MAX_DELAY );\ - run_audit = (bool)config.Item( ZM_RUN_AUDIT );\ - audit_check_interval = (int)config.Item( ZM_AUDIT_CHECK_INTERVAL );\ - forced_alarm_score = (int)config.Item( ZM_FORCED_ALARM_SCORE );\ - bulk_frame_interval = (int)config.Item( ZM_BULK_FRAME_INTERVAL );\ - event_close_mode = (const char *)config.Item( ZM_EVENT_CLOSE_MODE );\ - force_close_events = (bool)config.Item( ZM_FORCE_CLOSE_EVENTS );\ - create_analysis_images = (bool)config.Item( ZM_CREATE_ANALYSIS_IMAGES );\ - weighted_alarm_centres = (bool)config.Item( ZM_WEIGHTED_ALARM_CENTRES );\ - event_image_digits = (int)config.Item( ZM_EVENT_IMAGE_DIGITS );\ - default_aspect_ratio = (const char *)config.Item( ZM_DEFAULT_ASPECT_RATIO );\ - user_self_edit = (bool)config.Item( ZM_USER_SELF_EDIT );\ - opt_frame_server = (bool)config.Item( ZM_OPT_FRAME_SERVER );\ - frame_socket_size = (int)config.Item( ZM_FRAME_SOCKET_SIZE );\ - opt_control = (bool)config.Item( ZM_OPT_CONTROL );\ - opt_triggers = (bool)config.Item( ZM_OPT_TRIGGERS );\ - check_for_updates = (bool)config.Item( ZM_CHECK_FOR_UPDATES );\ - update_check_proxy = (const char *)config.Item( ZM_UPDATE_CHECK_PROXY );\ - shm_key = (int)config.Item( ZM_SHM_KEY );\ - web_refresh_method = (const char *)config.Item( ZM_WEB_REFRESH_METHOD );\ - web_event_sort_field = (const char *)config.Item( ZM_WEB_EVENT_SORT_FIELD );\ - web_event_sort_order = (const char *)config.Item( ZM_WEB_EVENT_SORT_ORDER );\ - web_events_per_page = (int)config.Item( ZM_WEB_EVENTS_PER_PAGE );\ - web_list_thumbs = (bool)config.Item( ZM_WEB_LIST_THUMBS );\ - web_list_thumb_width = (int)config.Item( ZM_WEB_LIST_THUMB_WIDTH );\ - web_list_thumb_height = (int)config.Item( ZM_WEB_LIST_THUMB_HEIGHT );\ - web_use_object_tags = (bool)config.Item( ZM_WEB_USE_OBJECT_TAGS );\ - web_h_refresh_main = (int)config.Item( ZM_WEB_H_REFRESH_MAIN );\ - web_h_refresh_cycle = (int)config.Item( ZM_WEB_H_REFRESH_CYCLE );\ - web_h_refresh_image = (int)config.Item( ZM_WEB_H_REFRESH_IMAGE );\ - web_h_refresh_status = (int)config.Item( ZM_WEB_H_REFRESH_STATUS );\ - web_h_refresh_events = (int)config.Item( ZM_WEB_H_REFRESH_EVENTS );\ - web_h_can_stream = (const char *)config.Item( ZM_WEB_H_CAN_STREAM );\ - web_h_stream_method = (const char *)config.Item( ZM_WEB_H_STREAM_METHOD );\ - web_h_default_scale = (int)config.Item( ZM_WEB_H_DEFAULT_SCALE );\ - web_h_default_rate = (int)config.Item( ZM_WEB_H_DEFAULT_RATE );\ - web_h_video_bitrate = (int)config.Item( ZM_WEB_H_VIDEO_BITRATE );\ - web_h_video_maxfps = (int)config.Item( ZM_WEB_H_VIDEO_MAXFPS );\ - web_h_scale_thumbs = (bool)config.Item( ZM_WEB_H_SCALE_THUMBS );\ - web_h_events_view = (const char *)config.Item( ZM_WEB_H_EVENTS_VIEW );\ - web_h_show_progress = (bool)config.Item( ZM_WEB_H_SHOW_PROGRESS );\ - web_h_ajax_timeout = (int)config.Item( ZM_WEB_H_AJAX_TIMEOUT );\ - web_m_refresh_main = (int)config.Item( ZM_WEB_M_REFRESH_MAIN );\ - web_m_refresh_cycle = (int)config.Item( ZM_WEB_M_REFRESH_CYCLE );\ - web_m_refresh_image = (int)config.Item( ZM_WEB_M_REFRESH_IMAGE );\ - web_m_refresh_status = (int)config.Item( ZM_WEB_M_REFRESH_STATUS );\ - web_m_refresh_events = (int)config.Item( ZM_WEB_M_REFRESH_EVENTS );\ - web_m_can_stream = (const char *)config.Item( ZM_WEB_M_CAN_STREAM );\ - web_m_stream_method = (const char *)config.Item( ZM_WEB_M_STREAM_METHOD );\ - web_m_default_scale = (int)config.Item( ZM_WEB_M_DEFAULT_SCALE );\ - web_m_default_rate = (int)config.Item( ZM_WEB_M_DEFAULT_RATE );\ - web_m_video_bitrate = (int)config.Item( ZM_WEB_M_VIDEO_BITRATE );\ - web_m_video_maxfps = (int)config.Item( ZM_WEB_M_VIDEO_MAXFPS );\ - web_m_scale_thumbs = (bool)config.Item( ZM_WEB_M_SCALE_THUMBS );\ - web_m_events_view = (const char *)config.Item( ZM_WEB_M_EVENTS_VIEW );\ - web_m_show_progress = (bool)config.Item( ZM_WEB_M_SHOW_PROGRESS );\ - web_m_ajax_timeout = (int)config.Item( ZM_WEB_M_AJAX_TIMEOUT );\ - web_l_refresh_main = (int)config.Item( ZM_WEB_L_REFRESH_MAIN );\ - web_l_refresh_cycle = (int)config.Item( ZM_WEB_L_REFRESH_CYCLE );\ - web_l_refresh_image = (int)config.Item( ZM_WEB_L_REFRESH_IMAGE );\ - web_l_refresh_status = (int)config.Item( ZM_WEB_L_REFRESH_STATUS );\ - web_l_refresh_events = (int)config.Item( ZM_WEB_L_REFRESH_EVENTS );\ - web_l_can_stream = (const char *)config.Item( ZM_WEB_L_CAN_STREAM );\ - web_l_stream_method = (const char *)config.Item( ZM_WEB_L_STREAM_METHOD );\ - web_l_default_scale = (int)config.Item( ZM_WEB_L_DEFAULT_SCALE );\ - web_l_default_rate = (int)config.Item( ZM_WEB_L_DEFAULT_RATE );\ - web_l_video_bitrate = (int)config.Item( ZM_WEB_L_VIDEO_BITRATE );\ - web_l_video_maxfps = (int)config.Item( ZM_WEB_L_VIDEO_MAXFPS );\ - web_l_scale_thumbs = (bool)config.Item( ZM_WEB_L_SCALE_THUMBS );\ - web_l_events_view = (const char *)config.Item( ZM_WEB_L_EVENTS_VIEW );\ - web_l_show_progress = (bool)config.Item( ZM_WEB_L_SHOW_PROGRESS );\ - web_l_ajax_timeout = (int)config.Item( ZM_WEB_L_AJAX_TIMEOUT );\ - web_p_can_stream = (const char *)config.Item( ZM_WEB_P_CAN_STREAM );\ - web_p_stream_method = (const char *)config.Item( ZM_WEB_P_STREAM_METHOD );\ - web_p_default_scale = (int)config.Item( ZM_WEB_P_DEFAULT_SCALE );\ - web_p_default_rate = (int)config.Item( ZM_WEB_P_DEFAULT_RATE );\ - web_p_video_bitrate = (int)config.Item( ZM_WEB_P_VIDEO_BITRATE );\ - web_p_video_maxfps = (int)config.Item( ZM_WEB_P_VIDEO_MAXFPS );\ - web_p_scale_thumbs = (bool)config.Item( ZM_WEB_P_SCALE_THUMBS );\ - web_p_ajax_timeout = (int)config.Item( ZM_WEB_P_AJAX_TIMEOUT );\ - dyn_last_version = (const char *)config.Item( ZM_DYN_LAST_VERSION );\ - dyn_curr_version = (const char *)config.Item( ZM_DYN_CURR_VERSION );\ - dyn_db_version = (const char *)config.Item( ZM_DYN_DB_VERSION );\ - dyn_last_check = (int)config.Item( ZM_DYN_LAST_CHECK );\ - dyn_next_reminder = (const char *)config.Item( ZM_DYN_NEXT_REMINDER );\ - dyn_donate_reminder_time = (int)config.Item( ZM_DYN_DONATE_REMINDER_TIME );\ - dyn_show_donate_reminder = (bool)config.Item( ZM_DYN_SHOW_DONATE_REMINDER );\ - eyezm_debug = (bool)config.Item( ZM_EYEZM_DEBUG );\ - eyezm_log_to_file = (bool)config.Item( ZM_EYEZM_LOG_TO_FILE );\ - eyezm_log_file = (const char *)config.Item( ZM_EYEZM_LOG_FILE );\ - eyezm_event_vcodec = (const char *)config.Item( ZM_EYEZM_EVENT_VCODEC );\ - eyezm_feed_vcodec = (const char *)config.Item( ZM_EYEZM_FEED_VCODEC );\ - eyezm_h264_default_br = (const char *)config.Item( ZM_EYEZM_H264_DEFAULT_BR );\ - eyezm_h264_default_evbr = (const char *)config.Item( ZM_EYEZM_H264_DEFAULT_EVBR );\ - eyezm_h264_timeout = (const char *)config.Item( ZM_EYEZM_H264_TIMEOUT );\ - eyezm_seg_duration = (const char *)config.Item( ZM_EYEZM_SEG_DURATION );\ - - diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 827904bbd..66dc3cae9 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -48,6 +48,7 @@ bool Event::initialised = false; char Event::capture_file_format[PATH_MAX]; char Event::analyse_file_format[PATH_MAX]; char Event::general_file_format[PATH_MAX]; +char Event::video_file_format[PATH_MAX]; int Event::pre_alarm_count = 0; Event::PreAlarmData Event::pre_alarm_data[MAX_PRE_ALARM_FRAMES] = { { 0 } }; @@ -161,6 +162,48 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string Fatal( "Can't fopen %s: %s", id_file, strerror(errno)); } last_db_frame = 0; + + video_name[0] = 0; + + /* Save as video */ + if ( monitor->GetOptVideoWriter() != 0 ) { + int nRet; + snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" ); + snprintf( video_file, sizeof(video_file), video_file_format, path, video_name ); + snprintf( timecodes_name, sizeof(timecodes_name), "%d-%s", id, "video.timecodes" ); + snprintf( timecodes_file, sizeof(timecodes_file), video_file_format, path, timecodes_name ); + + + /* X264 MP4 video writer */ + if(monitor->GetOptVideoWriter() == 1) { +#if ZM_HAVE_VIDEOWRITER_X264MP4 + videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams()); +#else + videowriter = NULL; + Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)"); +#endif + } + + if(videowriter != NULL) { + /* Open the video stream */ + nRet = videowriter->Open(); + if(nRet != 0) { + Error("Failed opening video stream"); + delete videowriter; + videowriter = NULL; + } + + /* Create timecodes file */ + timecodes_fd = fopen(timecodes_file, "wb"); + if(timecodes_fd == NULL) { + Error("Failed creating timecodes file"); + } + } + } else { + /* No video object */ + videowriter = NULL; + } + } Event::~Event() @@ -180,12 +223,28 @@ Event::~Event() } } + /* Close the video file */ + if ( videowriter != NULL ) { + int nRet; + + nRet = videowriter->Close(); + if(nRet != 0) { + Error("Failed closing video stream"); + } + delete videowriter; + videowriter = NULL; + + /* Close the timecodes file */ + fclose(timecodes_fd); + timecodes_fd = NULL; + } + static char sql[ZM_SQL_MED_BUFSIZ]; struct DeltaTimeval delta_time; DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 ); - snprintf( sql, sizeof(sql), "update Events set Name='%s%d', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %d", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, id ); + snprintf( sql, sizeof(sql), "update Events set Name='%s%d', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' where Id = %d", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't update event: %s", mysql_error( &dbconn ) ); @@ -368,6 +427,40 @@ bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char return( true ); } +bool Event::WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow ) +{ + const Image* frameimg = image; + Image ts_image; + + /* Checking for invalid parameters */ + if ( videow == NULL ) { + Error("NULL Video object"); + return false; + } + + /* If the image does not contain a timestamp, add the timestamp */ + if (!config.timestamp_on_capture) { + ts_image = *image; + monitor->TimestampImage( &ts_image, ×tamp ); + frameimg = &ts_image; + } + + /* Calculate delta time */ + struct DeltaTimeval delta_time3; + DELTA_TIMEVAL( delta_time3, timestamp, start_time, DT_PREC_3 ); + unsigned int timeMS = (delta_time3.sec * delta_time3.prec) + delta_time3.fsec; + + /* Encode and write the frame */ + if(videowriter->Encode(image, timeMS) != 0) { + Error("Failed encoding video frame"); + } + + /* Add the frame to the timecodes file */ + fprintf(timecodes_fd, "%u\n", timeMS); + + return( true ); +} + void Event::updateNotes( const StringSetMap &newNoteSetMap ) { bool update = false; @@ -514,7 +607,13 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st snprintf( event_file, sizeof(event_file), capture_file_format, path, frames ); Debug( 1, "Writing pre-capture frame %d", frames ); - WriteFrameImage( images[i], *(timestamps[i]), event_file ); + if ( monitor->GetOptSaveJPEGs() & 1) { + WriteFrameImage( images[i], *(timestamps[i]), event_file ); + } + + if ( videowriter != NULL ) { + WriteFrameVideo( images[i], *(timestamps[i]), videowriter ); + } struct DeltaTimeval delta_time; DELTA_TIMEVAL( delta_time, *(timestamps[i]), start_time, DT_PREC_2 ); @@ -556,7 +655,13 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * snprintf( event_file, sizeof(event_file), capture_file_format, path, frames ); Debug( 1, "Writing capture frame %d", frames ); - WriteFrameImage( image, timestamp, event_file ); + if( monitor->GetOptSaveJPEGs() & 1) { + WriteFrameImage( image, timestamp, event_file ); + } + + if ( videowriter != NULL ) { + WriteFrameVideo( image, timestamp, videowriter ); + } struct DeltaTimeval delta_time; DELTA_TIMEVAL( delta_time, timestamp, start_time, DT_PREC_2 ); @@ -604,7 +709,9 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * snprintf( event_file, sizeof(event_file), analyse_file_format, path, frames ); Debug( 1, "Writing analysis frame %d", frames ); - WriteFrameImage( alarm_image, timestamp, event_file, true ); + if ( monitor->GetOptSaveJPEGs() & 2) { + WriteFrameImage( alarm_image, timestamp, event_file, true ); + } } } diff --git a/src/zm_event.h b/src/zm_event.h index f50a5bf06..044cc1e7c 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -37,6 +37,7 @@ #include "zm.h" #include "zm_image.h" #include "zm_stream.h" +#include "zm_video.h" class Zone; class Monitor; @@ -55,6 +56,7 @@ protected: static char capture_file_format[PATH_MAX]; static char analyse_file_format[PATH_MAX]; static char general_file_format[PATH_MAX]; + static char video_file_format[PATH_MAX]; protected: static int sd; @@ -89,6 +91,12 @@ protected: unsigned int tot_score; unsigned int max_score; char path[PATH_MAX]; + VideoWriter* videowriter; + FILE* timecodes_fd; + char video_name[PATH_MAX]; + char video_file[PATH_MAX]; + char timecodes_name[PATH_MAX]; + char timecodes_file[PATH_MAX]; protected: int last_db_frame; @@ -102,6 +110,7 @@ protected: snprintf( capture_file_format, sizeof(capture_file_format), "%%s/%%0%dd-capture.jpg", config.event_image_digits ); snprintf( analyse_file_format, sizeof(analyse_file_format), "%%s/%%0%dd-analyse.jpg", config.event_image_digits ); snprintf( general_file_format, sizeof(general_file_format), "%%s/%%0%dd-%%s", config.event_image_digits ); + snprintf( video_file_format, sizeof(video_file_format), "%%s/%%s"); initialised = true; } @@ -127,6 +136,7 @@ public: bool SendFrameImage( const Image *image, bool alarm_frame=false ); bool WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame=false ); + bool WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow ); void updateNotes( const StringSetMap &stringSetMap ); diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 2369cc745..2322a9570 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -23,6 +23,16 @@ #if HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE +void FFMPEGInit() { + static bool bInit = false; + + if(!bInit) { + av_register_all(); + av_log_set_level(AV_LOG_DEBUG); + bInit = true; + } +} + #if HAVE_LIBAVUTIL enum PixelFormat GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder) { enum PixelFormat pf; @@ -124,10 +134,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint Error("NULL Input or output buffer"); return -1; } - if(in_pf == 0 || out_pf == 0) { - Error("Invalid input or output pixel formats"); - return -2; - } + if(!width || !height) { Error("Invalid width or height"); return -3; @@ -154,7 +161,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint } /* Get the context */ - swscale_ctx = sws_getCachedContext( NULL, width, height, in_pf, width, height, out_pf, 0, NULL, NULL, NULL ); + swscale_ctx = sws_getCachedContext( NULL, width, height, in_pf, width, height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL ); if(swscale_ctx == NULL) { Error("Failed getting swscale context"); return -6; diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index 0a4837d67..ef6a0aa9e 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -97,6 +97,8 @@ extern "C" { #define SWS_CPU_CAPS_SSE2 0x02000000 #endif +/* A single function to initialize ffmpeg, to avoid multiple initializations */ +void FFMPEGInit(); #if HAVE_LIBAVUTIL enum PixelFormat GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 028d32d55..c50736c0a 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -28,6 +28,7 @@ #include "zm_mpeg.h" #include "zm_signal.h" #include "zm_monitor.h" +#include "zm_video.h" #if ZM_HAS_V4L #include "zm_local_camera.h" #endif // ZM_HAS_V4L @@ -274,6 +275,9 @@ Monitor::Monitor( Camera *p_camera, int p_orientation, unsigned int p_deinterlacing, + int p_savejpegs, + int p_videowriter, + std::string p_encoderparams, const char *p_event_prefix, const char *p_label_format, const Coord &p_label_coord, @@ -302,6 +306,9 @@ Monitor::Monitor( height( (p_orientation==ROTATE_90||p_orientation==ROTATE_270)?p_camera->Width():p_camera->Height() ), orientation( (Orientation)p_orientation ), deinterlacing( p_deinterlacing ), + savejpegspref( p_savejpegs ), + videowriterpref( p_videowriter ), + encoderparams( p_encoderparams ), label_coord( p_label_coord ), image_buffer_count( p_image_buffer_count ), warmup_count( p_warmup_count ), @@ -348,6 +355,9 @@ Monitor::Monitor( } } + /* Parse encoder parameters */ + ParseEncoderParameters(encoderparams.c_str(), &encoderparamsvec); + fps = 0.0; event_count = 0; image_count = 0; @@ -1827,11 +1837,11 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose static char sql[ZM_SQL_MED_BUFSIZ]; if ( !device[0] ) { - strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Function != 'None' and Type = 'Local' order by Device, Channel", sizeof(sql) ); + strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Function != 'None' and Type = 'Local' order by Device, Channel", sizeof(sql) ); } else { - snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Function != 'None' and Type = 'Local' and Device = '%s' order by Channel", device ); + snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Function != 'None' and Type = 'Local' and Device = '%s' order by Channel", device ); } if ( mysql_query( &dbconn, sql ) ) { @@ -1870,6 +1880,11 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose int palette = atoi(dbrow[col]); col++; Orientation orientation = (Orientation)atoi(dbrow[col]); col++; unsigned int deinterlacing = atoi(dbrow[col]); col++; + + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; + int brightness = atoi(dbrow[col]); col++; int contrast = atoi(dbrow[col]); col++; int hue = atoi(dbrow[col]); col++; @@ -1935,6 +1950,9 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose camera, orientation, deinterlacing, + savejpegs, + videowriter, + encoderparams, event_prefix, label_format, Coord( label_x, label_y ), @@ -1979,11 +1997,11 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c static char sql[ZM_SQL_MED_BUFSIZ]; if ( !protocol ) { - strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Remote'", sizeof(sql) ); + strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Remote'", sizeof(sql) ); } else { - snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Remote' and Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path ); + snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Remote' and Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path ); } if ( mysql_query( &dbconn, sql ) ) { @@ -2022,7 +2040,12 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c int colours = atoi(dbrow[col]); col++; /* int palette = atoi(dbrow[col]); */ col++; Orientation orientation = (Orientation)atoi(dbrow[col]); col++; - unsigned int deinterlacing = atoi(dbrow[col]); col++; + unsigned int deinterlacing = atoi(dbrow[col]); col++; + + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; + int brightness = atoi(dbrow[col]); col++; int contrast = atoi(dbrow[col]); col++; int hue = atoi(dbrow[col]); col++; @@ -2106,6 +2129,9 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c camera, orientation, deinterlacing, + savejpegs, + videowriter, + encoderparams, event_prefix.c_str(), label_format.c_str(), Coord( label_x, label_y ), @@ -2150,11 +2176,11 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu 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, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'File'", sizeof(sql) ); + strncpy( sql, "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'File'", 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, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'File' and Path = '%s'", file ); + snprintf( sql, sizeof(sql), "select Id, Name, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'File' and Path = '%s'", file ); } if ( mysql_query( &dbconn, sql ) ) { @@ -2190,6 +2216,11 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu /* int palette = atoi(dbrow[col]); */ col++; Orientation orientation = (Orientation)atoi(dbrow[col]); col++; unsigned int deinterlacing = atoi(dbrow[col]); col++; + + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; + int brightness = atoi(dbrow[col]); col++; int contrast = atoi(dbrow[col]); col++; int hue = atoi(dbrow[col]); col++; @@ -2241,6 +2272,9 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu camera, orientation, deinterlacing, + savejpegs, + videowriter, + encoderparams, event_prefix, label_format, Coord( label_x, label_y ), @@ -2286,11 +2320,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, 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, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, 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, 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, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion from Monitors where Function != 'None' and Type = 'Ffmpeg' and Path = '%s'", file ); } if ( mysql_query( &dbconn, sql ) ) { @@ -2326,6 +2360,11 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose /* int palette = atoi(dbrow[col]); */ col++; Orientation orientation = (Orientation)atoi(dbrow[col]); col++; unsigned int deinterlacing = atoi(dbrow[col]); col++; + + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; + int brightness = atoi(dbrow[col]); col++; int contrast = atoi(dbrow[col]); col++; int hue = atoi(dbrow[col]); col++; @@ -2377,6 +2416,9 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose camera, orientation, deinterlacing, + savejpegs, + videowriter, + encoderparams, event_prefix, label_format, Coord( label_x, label_y ), @@ -2419,7 +2461,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, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, 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, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, 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 ) ); @@ -2462,6 +2504,11 @@ Monitor *Monitor::Load( int id, bool load_zones, Purpose purpose ) int palette = atoi(dbrow[col]); col++; Orientation orientation = (Orientation)atoi(dbrow[col]); col++; unsigned int deinterlacing = atoi(dbrow[col]); col++; + + int savejpegs = atoi(dbrow[col]); col++; + int videowriter = atoi(dbrow[col]); col++; + std::string encoderparams = dbrow[col]; col++; + int brightness = atoi(dbrow[col]); col++; int contrast = atoi(dbrow[col]); col++; int hue = atoi(dbrow[col]); col++; @@ -2618,6 +2665,9 @@ Monitor *Monitor::Load( int id, bool load_zones, Purpose purpose ) camera, orientation, deinterlacing, + savejpegs, + videowriter, + encoderparams, event_prefix.c_str(), label_format.c_str(), Coord( label_x, label_y ), diff --git a/src/zm_monitor.h b/src/zm_monitor.h index c8aea5a07..aff5fc91b 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -239,6 +239,11 @@ protected: bool track_motion; // Whether this monitor tries to track detected motion Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected + int savejpegspref; + int videowriterpref; + std::string encoderparams; + std::vector encoderparamsvec; + double fps; Image delta_image; Image ref_image; @@ -288,7 +293,7 @@ protected: public: // OurCheckAlarms seems to be unused. Check it on zm_monitor.cpp for more info. //bool OurCheckAlarms( Zone *zone, const Image *pImage ); - Monitor( int p_id, const char *p_name, int p_function, bool p_enabled, const char *p_linked_monitors, Camera *p_camera, int p_orientation, unsigned int p_deinterlacing, const char *p_event_prefix, const char *p_label_format, const Coord &p_label_coord, int p_image_buffer_count, int p_warmup_count, int p_pre_event_count, int p_post_event_count, int p_stream_replay_buffer, int p_alarm_frame_count, int p_section_length, int p_frame_skip, int p_capture_delay, int p_alarm_capture_delay, int p_fps_report_interval, int p_ref_blend_perc, int p_alarm_ref_blend_perc, bool p_track_motion, Rgb p_signal_check_colour, Purpose p_purpose, int p_n_zones=0, Zone *p_zones[]=0 ); + Monitor( int p_id, const char *p_name, int p_function, bool p_enabled, const char *p_linked_monitors, Camera *p_camera, int p_orientation, unsigned int p_deinterlacing, int p_savejpegs, int p_videowriter, std::string p_encoderparams, const char *p_event_prefix, const char *p_label_format, const Coord &p_label_coord, int p_image_buffer_count, int p_warmup_count, int p_pre_event_count, int p_post_event_count, int p_stream_replay_buffer, int p_alarm_frame_count, int p_section_length, int p_frame_skip, int p_capture_delay, int p_alarm_capture_delay, int p_fps_report_interval, int p_ref_blend_perc, int p_alarm_ref_blend_perc, bool p_track_motion, Rgb p_signal_check_colour, Purpose p_purpose, int p_n_zones=0, Zone *p_zones[]=0 ); ~Monitor(); void AddZones( int p_n_zones, Zone *p_zones[] ); @@ -337,7 +342,10 @@ public: unsigned int Height() const { return( height ); } unsigned int Colours() const { return( camera->Colours() ); } unsigned int SubpixelOrder() const { return( camera->SubpixelOrder() ); } - + + int GetOptSaveJPEGs() const { return( savejpegspref ); } + int GetOptVideoWriter() const { return( videowriterpref ); } + const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } State GetState() const; int GetImage( int index=-1, int scale=100 ) const; diff --git a/src/zm_video.cpp b/src/zm_video.cpp new file mode 100644 index 000000000..851def599 --- /dev/null +++ b/src/zm_video.cpp @@ -0,0 +1,492 @@ +// 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_video.h" +#include "zm_image.h" +#include "zm_utils.h" +#include "zm_rgb.h" +#include + +VideoWriter::VideoWriter(const char* p_container, const char* p_codec, const char* p_path, const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) : +container(p_container), codec(p_codec), path(p_path), width(p_width), height(p_height), colours(p_colours), subpixelorder(p_subpixelorder), frame_count(0) { + Debug(7,"Video object created"); + + /* Parameter checking */ + if(path.empty()) { + Error("Invalid file path"); + } + if(!width || !height) { + Error("Invalid width or height"); + } + +} + +VideoWriter::~VideoWriter() { + Debug(7,"Video object destroyed"); + +} + +int VideoWriter::Reset() { + /* Common variables reset */ + + frame_count = 0; + return 0; +} + + +#if ZM_HAVE_VIDEOWRITER_X264MP4 +X264MP4Writer::X264MP4Writer(const char* p_path, const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, const std::vector* p_user_params) : VideoWriter("mp4", "h264", p_path, p_width, p_height, p_colours, p_subpixelorder), bOpen(false), bGotH264AVCInfo(false), bFirstFrame(true) { + + /* Initialize ffmpeg if it hasn't been initialized yet */ + FFMPEGInit(); + + /* Initialize swscale */ + zm_pf = GetFFMPEGPixelFormat(colours,subpixelorder); + if(zm_pf == 0) { + Error("Unable to match ffmpeg pixelformat"); + } + codec_pf = PIX_FMT_YUV420P; + + swscaleobj.SetDefaults(zm_pf, codec_pf, width, height); + + /* Calculate the image sizes. We will need this for parameter checking */ + zm_imgsize = colours * width * height; + codec_imgsize = avpicture_get_size( codec_pf, width, height); + if(!codec_imgsize) { + Error("Failed calculating codec pixel format image size"); + } + + /* If supplied with user parameters to the encoder, copy them */ + if(p_user_params != NULL) { + user_params = *p_user_params; + } + + /* Setup x264 parameters */ + if(x264config() < 0) { + Error("Failed setting x264 parameters"); + } + + /* Allocate x264 input picture */ + x264_picture_alloc(&x264picin, X264_CSP_I420, x264params.i_width, x264params.i_height); + +} + +X264MP4Writer::~X264MP4Writer() { + + /* Free x264 input picture */ + x264_picture_clean(&x264picin); + + if(bOpen) + Close(); + + //x264_picture_clean(&x264picout); + +} + +int X264MP4Writer::Open() { + + /* Open the encoder */ + x264enc = x264_encoder_open(&x264params); + if(x264enc == NULL) { + Error("Failed opening x264 encoder"); + return -1; + } + + // Debug(4,"x264 maximum delayed frames: %d",x264_encoder_maximum_delayed_frames(x264enc)); + + x264_nal_t* nals; + int i_nals; + if(!x264_encoder_headers(x264enc,&nals,&i_nals)) { + Error("Failed getting encoder headers"); + return -2; + } + + /* Search SPS NAL for AVC information */ + for(int i=0;i 0; i-- ) { + x264encodeloop(true); + } + + /* Close the encoder */ + x264_encoder_close(x264enc); + + /* Close MP4 handle */ + MP4Close(mp4h); + + /* Required for proper HTTP streaming */ + MP4Optimize((path + ".incomplete").c_str(), path.c_str()); + + /* Delete the temporary file */ + unlink((path + ".incomplete").c_str()); + + bOpen = false; + + Debug(7, "Video closed. Total frames: %d", frame_count); + + return 0; +} + +int X264MP4Writer::Reset() { + + VideoWriter::Reset(); + + /* Close the encoder and file */ + if(bOpen) + Close(); + + /* Reset variables */ + bFirstFrame = true; + bGotH264AVCInfo = false; + prevnals.clear(); + prevpayload.clear(); + + /* Reset x264 parameters */ + x264config(); + + /* Open the encoder */ + Open(); + + return 0; +} + +int X264MP4Writer::Encode(const uint8_t* data, const size_t data_size, const unsigned int frame_time) { + + /* Parameter checking */ + if(data == NULL) { + Error("NULL buffer"); + return -1; + } + + if(data_size != zm_imgsize) { + Error("The data buffer size does not match the expected size. Expected: %d Current: %d", zm_imgsize, data_size); + return -2; + } + + if(!bOpen) { + Warning("The encoder was not initialized, initializing now"); + Open(); + } + + /* Convert the image into the x264 input picture */ + if(swscaleobj.ConvertDefaults(data, data_size, x264picin.img.plane[0], codec_imgsize) < 0) { + Error("Image conversion failed"); + return -3; + } + + /* Set PTS */ + x264picin.i_pts = frame_time; + + /* Do the encoding */ + x264encodeloop(); + + /* Increment frame counter */ + frame_count++; + + return 0; +} + +int X264MP4Writer::Encode(const Image* img, const unsigned int frame_time) { + + if(img->Width() != width) { + Error("Source image width differs. Source: %d Output: %d",img->Width(), width); + return -12; + } + + if(img->Height() != height) { + Error("Source image height differs. Source: %d Output: %d",img->Height(), height); + return -13; + } + + return Encode(img->Buffer(),img->Size(),frame_time); +} + +int X264MP4Writer::x264config() { + /* Sets up the encoder configuration */ + + /* Set the defaults and enable the superfast preset and the stillimage tune */ + if(x264_param_default_preset(&x264params,"veryfast","stillimage") != 0) { + Error("Failed setting x264 preset and tune"); + return -1; + } + + /* Set profile */ + if(x264_param_apply_profile(&x264params, "main") != 0) { + Error("Failed setting x264 profile"); + return -2; + } + + /* Input format */ + x264params.i_width = width; + x264params.i_height = height; + x264params.i_csp = X264_CSP_I420; + + /* Quality control */ + x264params.rc.i_rc_method = X264_RC_CRF; + x264params.rc.f_rf_constant = 23.0; + + /* Enable b-frames */ + x264params.i_bframe = 16; + x264params.i_bframe_adaptive = 1; + + /* Timebase */ + x264params.i_timebase_num = 1; + x264params.i_timebase_den = 1000; + + /* Enable variable frame rate */ + x264params.b_vfr_input = 1; + + /* Disable annex-b (start codes) */ + x264params.b_annexb = 0; + + /* TODO: Setup error handler */ + //x264params.i_log_level = X264_LOG_DEBUG; + + /* Process user parameters */ + x264userparams(); + + return 0; +} + +int X264MP4Writer::x264userparams() { + /* Passes user parameters (for the encoder) to x264 */ + int x264ret; + + for(unsigned int i=0; i < user_params.size(); i++) { + x264ret = x264_param_parse(&x264params, user_params[i].pname, user_params[i].pvalue); + + /* Error checking */ + if(x264ret != 0) { + if(x264ret == X264_PARAM_BAD_NAME) { + Error("Failed parsing x264 user parameter %s=%s : Bad name", user_params[i].pname, user_params[i].pvalue); + } else if(x264ret == X264_PARAM_BAD_VALUE) { + Error("Failed parsing x264 user parameter %s=%s : Bad value", user_params[i].pname, user_params[i].pvalue); + } else { + Error("Failed parsing x264 user parameter %s=%s : Unknown error (%d)", user_params[i].pname, user_params[i].pvalue, x264ret); + } + } + } + + return 0; +} + +void X264MP4Writer::x264encodeloop(bool bFlush) { + + x264_nal_t* nals; + int i_nals; + int frame_size; + + if(bFlush) { + frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, NULL, &x264picout); + } else { + frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, &x264picin, &x264picout); + } + + if (frame_size > 0 || bFlush) { + Debug(8, "x264 Frame: %d PTS: %d DTS: %d Size: %d\n",frame_count, x264picout.i_pts, x264picout.i_dts, frame_size); + + /* Handle the previous frame */ + if(!bFirstFrame) { + + /* Process the NALs for the previous frame */ + for(unsigned int i=0; i < prevnals.size(); i++) { + Debug(9,"Processing NAL: Type %d Size %d",prevnals[i].i_type,prevnals[i].i_payload); + + switch(prevnals[i].i_type) { + case NAL_PPS: + /* PPS NAL */ + MP4AddH264PictureParameterSet(mp4h, mp4vtid, prevnals[i].p_payload+4, prevnals[i].i_payload-4); + break; + case NAL_SPS: + /* SPS NAL */ + MP4AddH264SequenceParameterSet(mp4h, mp4vtid, prevnals[i].p_payload+4, prevnals[i].i_payload-4); + break; + default: + /* Anything else, hopefully frames, so copy it into the sample */ + buffer.append(prevnals[i].p_payload, prevnals[i].i_payload); + } + } + + /* Calculate frame duration and offset */ + int duration = x264picout.i_dts - prevDTS; + int offset = prevPTS - prevDTS; + + /* Write the sample */ + if(!buffer.empty()) { + if(!MP4WriteSample(mp4h, mp4vtid, buffer.extract(buffer.size()), buffer.size(), duration, offset, prevKeyframe)) { + Error("Failed writing sample"); + } + } + + /* Cleanup */ + prevnals.clear(); + prevpayload.clear(); + + } + + /* Got a frame. Copy this new frame into the previous frame */ + if(frame_size > 0) { + /* Copy the NALs and the payloads */ + for(int i=0;i* vec) { + if(vec == NULL) { + Error("NULL Encoder parameters vector pointer"); + return -1; + } + + if(str == NULL) { + Error("NULL Encoder parameters string"); + return -2; + } + + if(str[0] == 0) { + /* Empty */ + return 0; + } + + std::string line; + std::stringstream ss(str); + size_t valueoffset; + size_t valuelen; + unsigned int lineno = 0; + EncoderParameter_t param; + + vec->clear(); + + while(std::getline(ss, line) ) { + lineno++; + + /* Remove CR if exists */ + if(line.length() >= 1 && line[line.length()-1] == '\r') { + line.erase(line.length()-1); + } + + /* Skip comments and empty lines */ + if(line.empty() || line[0] == '#') { + continue; + } + + valueoffset = line.find('='); + if(valueoffset == std::string::npos || valueoffset+1 >= line.length() || valueoffset == 0) { + Warning("Failed parsing encoder parameters line %d: Invalid pair", lineno); + continue; + } + + + if(valueoffset > (sizeof(param.pname)-1) ) { + Warning("Failed parsing encoder parameters line %d: Name too long", lineno); + continue; + } + + valuelen = line.length() - (valueoffset+1); + + if( valuelen > (sizeof(param.pvalue)-1) ) { + Warning("Failed parsing encoder parameters line %d: Value too long", lineno); + continue; + } + + /* Copy and NULL terminate */ + line.copy(param.pname, valueoffset, 0); + line.copy(param.pvalue, valuelen, valueoffset+1); + param.pname[valueoffset] = 0; + param.pvalue[valuelen] = 0; + + /* Push to the vector */ + vec->push_back(param); + + Debug(7, "Parsed encoder parameter: %s = %s", param.pname, param.pvalue); + } + + Debug(7, "Parsed %d lines", lineno); + + return 0; +} + + diff --git a/src/zm_video.h b/src/zm_video.h new file mode 100644 index 000000000..622cc81bd --- /dev/null +++ b/src/zm_video.h @@ -0,0 +1,168 @@ +// 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_VIDEO_H +#define ZM_VIDEO_H + +#include "zm.h" +#include "zm_rgb.h" +#include "zm_utils.h" +#include "zm_ffmpeg.h" +#include "zm_buffer.h" + +/* +#define HAVE_LIBX264 1 +#define HAVE_LIBMP4V2 1 +#define HAVE_X264_H 1 +#define HAVE_MP4_H 1 +*/ + +#if HAVE_MP4_H +#include +#endif + +#if HAVE_X264_H +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +} +#endif +#endif + +/* Structure for user parameters to the encoder */ +struct EncoderParameter_t { + char pname[48]; + char pvalue[48]; + +}; +int ParseEncoderParameters(const char* str, std::vector* vec); + +/* VideoWriter is a generic interface that ZM uses to save events as videos */ +/* It is relatively simple and the functions are pure virtual, so they must be implemented by the deriving class */ + +class VideoWriter { + +protected: + std::string container; + std::string codec; + std::string path; + unsigned int width; + unsigned int height; + unsigned int colours; + unsigned int subpixelorder; + + unsigned int frame_count; + +public: + VideoWriter(const char* p_container, const char* p_codec, const char* p_path, const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder); + virtual ~VideoWriter(); + virtual int Encode(const uint8_t* data, const size_t data_size, const unsigned int frame_time) = 0; + virtual int Encode(const Image* img, const unsigned int frame_time) = 0; + virtual int Open() = 0; + virtual int Close() = 0; + virtual int Reset(); + + const char* GetContainer() const { + return container.c_str(); + } + const char* GetCodec() const { + return codec.c_str(); + } + const char* GetPath() const { + return path.c_str(); + } + unsigned int GetWidth() const { + return width; + } + unsigned int GetHeight() const { + return height; + } + unsigned int GetColours() const { + return colours; + } + unsigned int GetSubpixelorder () const { + return subpixelorder; + } + unsigned int GetFrameCount() const { + return frame_count; + } +}; + +#if HAVE_LIBX264 && HAVE_LIBMP4V2 && HAVE_LIBAVUTIL && HAVE_LIBSWSCALE +#define ZM_HAVE_VIDEOWRITER_X264MP4 1 +class X264MP4Writer : public VideoWriter { + +protected: + + bool bOpen; + bool bGotH264AVCInfo; + bool bFirstFrame; + + /* SWScale */ + SWScale swscaleobj; + enum PixelFormat zm_pf; + enum PixelFormat codec_pf; + size_t codec_imgsize; + size_t zm_imgsize; + + /* User parameters */ + std::vector user_params; + + /* AVC Information */ + uint8_t x264_profleindication; + uint8_t x264_profilecompat; + uint8_t x264_levelindication; + + /* NALs */ + Buffer buffer; + + /* Previous frame */ + int prevPTS; + int prevDTS; + bool prevKeyframe; + Buffer prevpayload; + std::vector prevnals; + + /* Internal functions */ + int x264config(); + int x264userparams(); + void x264encodeloop(bool bFlush = false); + + /* x264 objects */ + x264_t* x264enc; + x264_param_t x264params; + x264_picture_t x264picin; + x264_picture_t x264picout; + + /* MP4v2 objects */ + MP4FileHandle mp4h; + MP4TrackId mp4vtid; + + +public: + X264MP4Writer(const char* p_path, const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, const std::vector* p_user_params = NULL); + ~X264MP4Writer(); + int Encode(const uint8_t* data, const size_t data_size, const unsigned int frame_time); + int Encode(const Image* img, const unsigned int frame_time); + int Open(); + int Close(); + int Reset(); + +}; +#endif // HAVE_LIBX264 && HAVE_LIBMP4V2 && HAVE_LIBAVUTIL && HAVE_LIBSWSCALE + +#endif // ZM_VIDEO_H diff --git a/web/ajax/status.php b/web/ajax/status.php index fe82fe5cc..47026060e 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -382,31 +382,33 @@ function getNearEvents() else $midSql = ''; - $sql = "select E.Id as Id from Events as E inner join Monitors as M on E.MonitorId = M.Id where ".dbEscape($sortColumn)." ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn ".($sortOrder=='asc'?'desc':'asc'); + $sql = "select E.* as Id from Events as E inner join Monitors as M on E.MonitorId = M.Id where ".dbEscape($sortColumn)." ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn ".($sortOrder=='asc'?'desc':'asc'); $result = dbQuery( $sql ); while ( $id = dbFetchNext( $result, 'Id' ) ) { if ( $id == $eventId ) { - $prevId = dbFetchNext( $result, 'Id' ); + $prevEvent = dbFetchNext( $result ); break; } } - $sql = "select E.Id as Id from Events as E inner join Monitors as M on E.MonitorId = M.Id where $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn $sortOrder"; + $sql = "select E.* as Id from Events as E inner join Monitors as M on E.MonitorId = M.Id where $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn $sortOrder"; $result = dbQuery( $sql ); while ( $id = dbFetchNext( $result, 'Id' ) ) { if ( $id == $eventId ) { - $nextId = dbFetchNext( $result, 'Id' ); + $nextEvent = dbFetchNext( $result ); break; } } $result = array( 'EventId'=>$eventId ); - $result['PrevEventId'] = empty($prevId)?0:$prevId; - $result['NextEventId'] = empty($nextId)?0:$nextId; + $result['PrevEventId'] = empty($prevEvent)?0:$prevEvent['Id']; + $result['NextEventId'] = empty($nextEvent)?0:$nextEvent['Id']; + $result['PrevEventDefVideoPath'] = empty($prevEvent)?0:(getEventDefaultVideoPath($prevEvent)); + $result['NextEventDefVideoPath'] = empty($nextEvent)?0:(getEventDefaultVideoPath($nextEvent)); return( $result ); } diff --git a/web/includes/functions.php b/web/includes/functions.php index 31fafc3fe..7d18f3c97 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -497,6 +497,9 @@ function getEventPath( $event ) return( $eventPath ); } +function getEventDefaultVideoPath( $event ) { + return ZM_DIR_EVENTS . "/" . getEventPath($event) . "/" . $event['DefaultVideo']; +} function deletePath( $path ) { diff --git a/web/skins/classic/views/css/event.css b/web/skins/classic/views/css/event.css index 995a06c1d..06d98bc85 100644 --- a/web/skins/classic/views/css/event.css +++ b/web/skins/classic/views/css/event.css @@ -57,6 +57,23 @@ text-align: right; } +#videoBar1 div { + text-align: center; + float: center; +} + +#videoBar1 #prevEvent { + float: left; +} + +#videoBar1 #dlEvent { + float: center; +} + +#videoBar1 #nextEvent { + float: right; +} + #imageFeed { text-align: center; } diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 5e9f4a238..28e5333a7 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -125,6 +125,7 @@ if ( canEdit( 'Events' ) )
class="hidden">
class="hidden">
+
class="hidden">HTML5Video
+