diff --git a/src/libcam.cpp b/src/libcam.cpp index 7f2f40c1..99e68c2b 100644 --- a/src/libcam.cpp +++ b/src/libcam.cpp @@ -342,7 +342,7 @@ int cls_libcam::cam_next(ctx_image_data *img_data) int indx; if (started_cam == false) { - return -1; + return CAPTURE_FAILURE; } /* Allow time for request to finish.*/ @@ -361,31 +361,15 @@ int cls_libcam::cam_next(ctx_image_data *img_data) request->reuse(Request::ReuseBuffers); req_add(request); - return 0; + return CAPTURE_SUCCESS; } else { - return -1; + return CAPTURE_FAILURE; } } #endif -/** initialize and start libcam */ -int libcam_start(ctx_cam *cam) -{ - #ifdef HAVE_LIBCAM - int retcd; - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Starting experimental libcamera ."); - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "EXPECT crashes and hung processes!!!"); - cam->libcam = new cls_libcam; - retcd = cam->libcam->cam_start(cam); - return retcd; - #else - (void)cam; - return -1; - #endif -} - /** close and stop libcam */ void libcam_cleanup(ctx_cam *cam) { @@ -393,11 +377,33 @@ void libcam_cleanup(ctx_cam *cam) cam->libcam->cam_stop(); delete cam->libcam; cam->libcam = nullptr; - #else - (void)cam; + #endif + cam->camera_status = STATUS_CLOSED; + cam->running_cam = false; +} + +/** initialize and start libcam */ +void libcam_start(ctx_cam *cam) +{ + #ifdef HAVE_LIBCAM + int retcd; + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening libcam")); + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "Starting experimental libcamera ."); + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "EXPECT crashes and hung processes!!!"); + cam->libcam = new cls_libcam; + retcd = cam->libcam->cam_start(cam); + if (retcd < 0) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("libcam failed to open")); + libcam_cleanup(cam); + } else { + cam->camera_status = STATUS_OPENED; + } + #else + cam->camera_status = STATUS_CLOSED; #endif } + /** get next image from libcam */ int libcam_next(ctx_cam *cam, ctx_image_data *img_data) { @@ -405,17 +411,19 @@ int libcam_next(ctx_cam *cam, ctx_image_data *img_data) int retcd; if (cam->libcam == nullptr){ - return -1; + return CAPTURE_FAILURE; } + retcd = cam->libcam->cam_next(img_data); - if (retcd == 0) { + if (retcd == CAPTURE_SUCCESS) { rotate_map(cam, img_data); } + return retcd; #else (void)cam; (void)img_data; - return -1; + return CAPTURE_FAILURE; #endif } diff --git a/src/libcam.hpp b/src/libcam.hpp index 0ae03086..5071b0f4 100644 --- a/src/libcam.hpp +++ b/src/libcam.hpp @@ -73,7 +73,7 @@ }; #endif - int libcam_start (ctx_cam *cam); + void libcam_start (ctx_cam *cam); int libcam_next (ctx_cam *cam, ctx_image_data *img_data); void libcam_cleanup (ctx_cam *cam); diff --git a/src/mmalcam.cpp b/src/mmalcam.cpp index 4763e82d..eb41cd0e 100644 --- a/src/mmalcam.cpp +++ b/src/mmalcam.cpp @@ -271,26 +271,36 @@ static void destroy_camera_buffer_structures(ctx_mmalcam_ptr mmalcam) #endif -/** - * mmalcam_start - * - * This routine is called from the main motion thread. It's job is - * to open up the requested camera device via MMAL and do any required - * initialization. - * - * Parameters: - * - * cam Pointer to the motion context structure for this device. - * - * Returns: 0 on success - * -1 on any failure - */ - -int mmalcam_start(ctx_cam *cam) +void mmalcam_cleanup(ctx_cam *cam) { #ifdef HAVE_MMAL + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("MMAL Camera cleanup")); + + if (cam->mmalcam != NULL ) { + if (cam->mmalcam->camera_component) { + check_disable_port(cam->mmalcam->camera_capture_port); + mmal_component_disable(cam->mmalcam->camera_component); + destroy_camera_buffer_structures(cam->mmalcam); + destroy_camera_component(cam->mmalcam); + } + myfree(&cam->mmalcam->camera_parameters); + myfree(&cam->mmalcam); + } + #endif + + cam->camera_status = STATUS_CLOSED; + cam->running_cam = false; + +} + +void mmalcam_start(ctx_cam *cam) +{ + #ifdef HAVE_MMAL + ctx_mmalcam_ptr mmalcam; + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening MMAL cam")); + cam->mmalcam = (ctx_mmalcam*) mymalloc(sizeof(ctx_mmalcam)); memset(cam->mmalcam, 0, sizeof(ctx_mmalcam)); mmalcam = cam->mmalcam; @@ -303,7 +313,9 @@ int mmalcam_start(ctx_cam *cam) mmalcam->camera_parameters = (RASPICAM_CAMERA_PARAMETERS*)malloc(sizeof(RASPICAM_CAMERA_PARAMETERS)); if (mmalcam->camera_parameters == NULL) { MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, _("camera params couldn't be allocated")); - return MMALCAM_ERROR; + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("MMAL cam failed to open")); + mmalcam_cleanup(cam); + return; } raspicamcontrol_set_defaults(mmalcam->camera_parameters); @@ -345,62 +357,21 @@ int mmalcam_start(ctx_cam *cam) retval = send_pooled_buffers_to_port(mmalcam->camera_buffer_pool, mmalcam->camera_capture_port); } - return retval; - #else - (void)cam; - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("MMAL Camera not available")); - return -1; - #endif -} - -/** - * mmalcam_cleanup - * - * This routine shuts down any MMAL resources, then releases any allocated data - * within the mmalcam context and frees the context itself. - * This function is also called from motion_init if first time connection - * fails and we start retrying until we get a valid first frame from the - * camera. - * - * Parameters: - * - * mmalcam Pointer to a mmalcam context - * - * Returns: Nothing. - * - */ -void mmalcam_cleanup(ctx_mmalcam *mmalcam) -{ - #ifdef HAVE_MMAL - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("MMAL Camera cleanup")); - - if (mmalcam != NULL ) { - if (mmalcam->camera_component) { - check_disable_port(mmalcam->camera_capture_port); - mmal_component_disable(mmalcam->camera_component); - destroy_camera_buffer_structures(mmalcam); - destroy_camera_component(mmalcam); - } - myfree(&mmalcam->camera_parameters); - myfree(&mmalcam); + if (retval == 0) { + cam->camera_status = STATUS_OPENED; + } else { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("MMAL cam failed to open")); + mmalcam_cleanup(cam); } #else - (void)mmalcam; + cam->camera_status = STATUS_CLOSED; + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("MMAL Camera not available")); #endif } + /** - * mmalcam_next - * - * This routine is called when the main 'motion' thread wants a new - * frame of video. It fetches the most recent frame available from - * the Pi camera already in YUV420P, and returns it to motion. - * - * Parameters: - * cam Pointer to the context for this thread - * image Pointer to a buffer for the returned image - * - * Returns: Error code + * Return image from mmalcam. Runs on motion_loop thread. */ int mmalcam_next(ctx_cam *cam, ctx_image_data *img_data) { @@ -408,7 +379,7 @@ int mmalcam_next(ctx_cam *cam, ctx_image_data *img_data) ctx_mmalcam_ptr mmalcam; if ((!cam) || (!cam->mmalcam)) { - return -1; + return CAPTURE_FAILURE; } mmalcam = cam->mmalcam; @@ -445,11 +416,11 @@ int mmalcam_next(ctx_cam *cam, ctx_image_data *img_data) rotate_map(cam,img_data); - return 0; + return CAPTURE_SUCCESS; #else (void)cam; (void)img_data; - return -1; + return CAPTURE_FAILURE; #endif } diff --git a/src/mmalcam.hpp b/src/mmalcam.hpp index 148288a8..0d3d9a9b 100644 --- a/src/mmalcam.hpp +++ b/src/mmalcam.hpp @@ -38,8 +38,8 @@ #endif } ctx_mmalcam; - int mmalcam_start (ctx_cam *cam); + void mmalcam_start (ctx_cam *cam); int mmalcam_next (ctx_cam *cam, ctx_image_data *img_data); - void mmalcam_cleanup (ctx_mmalcam *mmalcam); + void mmalcam_cleanup (ctx_cam *cam); #endif /* _INCLUDE_MMALCAM_HPP_ */ diff --git a/src/motion_loop.cpp b/src/motion_loop.cpp index 4bbe4480..7fd9d1bc 100644 --- a/src/motion_loop.cpp +++ b/src/motion_loop.cpp @@ -365,25 +365,22 @@ static void mlp_mask_privacy(ctx_cam *cam) /* Close and clean up camera*/ void mlp_cam_close(ctx_cam *cam) { - if (cam->mmalcam) { - mmalcam_cleanup(cam->mmalcam); - cam->mmalcam = NULL; - cam->running_cam = false; + if (cam->mmalcam != NULL) { + mmalcam_cleanup(cam); return; } - if (cam->libcam) { + if (cam->libcam != NULL) { libcam_cleanup(cam); - cam->running_cam = false; return; } - if (cam->netcam) { - netcam_cleanup(cam, false); + if (cam->netcam != NULL) { + netcam_cleanup(cam); return; } - if (cam->camera_type == CAMERA_TYPE_V4L2) { + if (cam->v4l2cam != NULL) { v4l2_cleanup(cam); return; } @@ -394,85 +391,37 @@ void mlp_cam_close(ctx_cam *cam) } /* Start camera */ -int mlp_cam_start(ctx_cam *cam) +void mlp_cam_start(ctx_cam *cam) { - int retcd; - if (cam->camera_type == CAMERA_TYPE_MMAL) { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening MMAL cam")); - retcd = mmalcam_start(cam); - if (retcd < 0) { - mmalcam_cleanup(cam->mmalcam); - cam->mmalcam = NULL; - MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("MMAL cam failed to open")); - } - return retcd; + mmalcam_start(cam); + } else if (cam->camera_type == CAMERA_TYPE_LIBCAM) { + libcam_start(cam); + } else if (cam->camera_type == CAMERA_TYPE_NETCAM) { + netcam_start(cam); + } else if (cam->camera_type == CAMERA_TYPE_V4L2) { + v4l2_start(cam); + } else { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO + ,_("No Camera device specified")); + cam->camera_status = STATUS_CLOSED; } - - if (cam->camera_type == CAMERA_TYPE_LIBCAM) { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening libcam")); - retcd = libcam_start(cam); - if (retcd < 0) { - libcam_cleanup(cam); - MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("libcam failed to open")); - } - return retcd; - } - - if (cam->camera_type == CAMERA_TYPE_NETCAM) { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening Netcam")); - retcd = netcam_setup(cam); - if (retcd < 0) { - netcam_cleanup(cam, true); - MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("Netcam failed to open")); - } - return retcd; - } - - if (cam->camera_type == CAMERA_TYPE_V4L2) { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening V4L2 device")); - retcd = v4l2_start(cam); - if (retcd < 0) { - MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("V4L2 device failed to open")); - } - return retcd; - } - - MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO - ,_("No Camera device specified")); - return -1; - } /* Get next image from camera */ int mlp_cam_next(ctx_cam *cam, ctx_image_data *img_data) { if (cam->camera_type == CAMERA_TYPE_MMAL) { - if (cam->mmalcam == NULL) { - return NETCAM_GENERAL_ERROR; - } return mmalcam_next(cam, img_data); - } - - if (cam->camera_type == CAMERA_TYPE_LIBCAM) { - if (cam->libcam == NULL) { - return NETCAM_GENERAL_ERROR; - } + } else if (cam->camera_type == CAMERA_TYPE_LIBCAM) { return libcam_next(cam, img_data); - } - - if (cam->camera_type == CAMERA_TYPE_NETCAM) { - if (cam->video_dev == -1) { - return NETCAM_GENERAL_ERROR; - } + } else if (cam->camera_type == CAMERA_TYPE_NETCAM) { return netcam_next(cam, img_data); + } else if (cam->camera_type == CAMERA_TYPE_V4L2) { + return v4l2_next(cam, img_data); } - if (cam->camera_type == CAMERA_TYPE_V4L2) { - return v4l2_next(cam, img_data); - } - - return -2; + return CAPTURE_FAILURE; } /* Assign the camera type */ @@ -511,9 +460,9 @@ static void mlp_init_firstimage(ctx_cam *cam) int indx; cam->current_image = &cam->imgs.image_ring[cam->imgs.ring_in]; - if (cam->video_dev >= 0) { + if (cam->camera_status == STATUS_OPENED) { for (indx = 0; indx < 5; indx++) { - if (mlp_cam_next(cam, cam->current_image) == 0) { + if (mlp_cam_next(cam, cam->current_image) == CAPTURE_SUCCESS) { break; } SLEEP(2, 0); @@ -621,7 +570,7 @@ static void mlp_init_values(ctx_cam *cam) } else { cam->threshold_maximum = (cam->imgs.height * cam->imgs.width * 3) / 2; } - + cam->camera_status = STATUS_CLOSED; cam->startup_frames = (cam->conf->framerate * 2) + cam->conf->pre_capture + cam->conf->minimum_motion_frames; cam->minimum_frame_time_downcounter = cam->conf->minimum_frame_time; @@ -638,25 +587,22 @@ static void mlp_init_values(ctx_cam *cam) /* start the camera */ static int mlp_init_cam_start(ctx_cam *cam) { - cam->video_dev = mlp_cam_start(cam); + mlp_cam_start(cam); - if (cam->video_dev == -1) { - MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO - ,_("Could not fetch initial image from camera ")); - return -1; - } else if (cam->video_dev == -2) { + if (cam->camera_status == STATUS_CLOSED) { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO - ,_("Could not fetch initial image from camera ")); + ,_("Failed to start camera.")); MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO - ,_("Motion only supports width and height modulo 8")); + ,_("Use webcontrol to start camera when it is ready.")); + cam->restart_cam = false; return -1; - } else { - cam->imgs.motionsize = (cam->imgs.width * cam->imgs.height); - cam->imgs.size_norm = (cam->imgs.width * cam->imgs.height * 3) / 2; - cam->imgs.size_high = (cam->imgs.width_high * cam->imgs.height_high * 3) / 2; } + cam->imgs.motionsize = (cam->imgs.width * cam->imgs.height); + cam->imgs.size_norm = (cam->imgs.width * cam->imgs.height * 3) / 2; + cam->imgs.size_high = (cam->imgs.width_high * cam->imgs.height_high * 3) / 2; return 0; + } /* initialize reference images*/ @@ -747,7 +693,7 @@ void mlp_cleanup(ctx_cam *cam) algsec_deinit(cam); - if (cam->video_dev >= 0) { + if (cam->camera_status == STATUS_OPENED) { mlp_cam_close(cam); } @@ -895,13 +841,14 @@ static int mlp_retry(ctx_cam *cam) { int size_high; - if (cam->video_dev < 0 && - cam->frame_curr_ts.tv_sec % 10 == 0 && cam->shots == 0) { + if ((cam->camera_status == STATUS_CLOSED) && + (cam->frame_curr_ts.tv_sec % 10 == 0) && + (cam->shots == 0)) { MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO ,_("Retrying until successful connection with camera")); - cam->video_dev = mlp_cam_start(cam); - if (cam->video_dev < 0) { + mlp_cam_start(cam); + if (cam->camera_status != STATUS_OPENED) { return 1; } @@ -945,15 +892,11 @@ static int mlp_capture(ctx_cam *cam) { const char *tmpin; char tmpout[80]; - int vid_return_code = 0; /* Return code used when calling mlp_cam_next */ + int retcd; - if (cam->video_dev >= 0) { - vid_return_code = mlp_cam_next(cam, cam->current_image); - } else { - vid_return_code = 1; /* Non fatal error */ - } + retcd = mlp_cam_next(cam, cam->current_image); - if (vid_return_code == 0) { + if (retcd == CAPTURE_SUCCESS) { cam->lost_connection = 0; cam->connectionlosttime.tv_sec = 0; @@ -966,34 +909,26 @@ static int mlp_capture(ctx_cam *cam) mlp_mask_privacy(cam); memcpy(cam->imgs.image_vprvcy, cam->current_image->image_norm, cam->imgs.size_norm); - } else if (vid_return_code < 0) { + } else if (retcd == CAPTURE_FAILURE) { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO ,_("Video device fatal error - Closing video device")); mlp_cam_close(cam); memcpy(cam->current_image->image_norm, cam->imgs.image_virgin, cam->imgs.size_norm); cam->lost_connection = 1; } else { - if (vid_return_code == NETCAM_RESTART_ERROR) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO - ,_("Restarting Motion thread to reinitialize all " - "image buffers")); - cam->lost_connection = 1; - return 1; - } - if (cam->connectionlosttime.tv_sec == 0) { clock_gettime(CLOCK_REALTIME, &cam->connectionlosttime); } - ++cam->missing_frame_counter; + cam->missing_frame_counter++; - if (cam->video_dev >= 0 && - cam->missing_frame_counter < (cam->conf->camera_tmo * cam->conf->framerate)) { + if ((cam->camera_status == STATUS_OPENED) && + (cam->missing_frame_counter < + (cam->conf->camera_tmo * cam->conf->framerate))) { memcpy(cam->current_image->image_norm, cam->imgs.image_vprvcy, cam->imgs.size_norm); } else { cam->lost_connection = 1; - - if (cam->video_dev >= 0) { + if (cam->camera_status == STATUS_OPENED) { tmpin = "CONNECTION TO CAMERA LOST\\nSINCE %Y-%m-%d %T"; } else { tmpin = "UNABLE TO OPEN VIDEO DEVICE\\nSINCE %Y-%m-%d %T"; @@ -1012,7 +947,7 @@ static int mlp_capture(ctx_cam *cam) event(cam, EVENT_CAMERA_LOST, NULL, NULL, NULL, &cam->connectionlosttime); } - if ((cam->video_dev > 0) && + if ((cam->camera_status == STATUS_OPENED) && (cam->missing_frame_counter == ((cam->conf->camera_tmo * 4) * cam->conf->framerate))) { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO ,_("Video signal still lost - Trying to close video device")); diff --git a/src/motionplus.hpp b/src/motionplus.hpp index 7ff4a1a3..930f0c0f 100644 --- a/src/motionplus.hpp +++ b/src/motionplus.hpp @@ -174,6 +174,17 @@ enum MOTION_SIGNAL { MOTION_SIGNAL_SIGTERM }; +enum CAPTURE_RESULT { + CAPTURE_SUCCESS, + CAPTURE_FAILURE, + CAPTURE_ATTEMPTED +}; + +enum CAM_STATUS { + STATUS_CLOSED, /* Camera is closed and not Initialized */ + STATUS_OPENED /* Successfully started the camera */ +}; + struct ctx_webu_clients { std::string clientip; bool authenticated; @@ -285,10 +296,6 @@ struct ctx_stream { ctx_stream_data secondary; /* Copy of the image to use for web stream*/ }; -/* - * These used to be global variables but now each thread will have its - * own context - */ struct ctx_cam { ctx_motapp *motapp; @@ -320,6 +327,7 @@ struct ctx_cam { int track_posy; int camera_id; enum CAMERA_TYPE camera_type; + enum CAM_STATUS camera_status; unsigned int new_img; int locate_motion_mode; int locate_motion_style; @@ -362,7 +370,6 @@ struct ctx_cam { int missing_frame_counter; /* counts failed attempts to fetch picture frame from camera */ unsigned int lost_connection; - int video_dev; int pipe; int mpipe; @@ -395,7 +402,7 @@ struct ctx_cam { }; -/* ctx_cam for whole motion application including all the cameras */ +/* ctx_motapp for whole motion application including all the cameras */ struct ctx_motapp { ctx_cam **cam_list; diff --git a/src/netcam.cpp b/src/netcam.cpp index dc60aa11..bda88e93 100644 --- a/src/netcam.cpp +++ b/src/netcam.cpp @@ -1502,6 +1502,10 @@ static void netcam_set_parms (ctx_cam *cam, ctx_netcam *netcam ) netcam->motapp = cam->motapp; netcam->conf = cam->conf; + pthread_mutex_lock(&netcam->motapp->global_lock); + netcam->threadnbr = ++netcam->motapp->threads_running; + pthread_mutex_unlock(&netcam->motapp->global_lock); + if (netcam->high_resolution) { netcam->imgsize.width = 0; netcam->imgsize.height = 0; @@ -1582,7 +1586,7 @@ static void netcam_set_parms (ctx_cam *cam, ctx_netcam *netcam ) } -static int netcam_set_dimensions (ctx_cam *cam) +static void netcam_set_dimensions (ctx_cam *cam) { cam->imgs.width = 0; @@ -1617,7 +1621,6 @@ static int netcam_set_dimensions (ctx_cam *cam) cam->imgs.size_norm = (cam->conf->width * cam->conf->height * 3) / 2; cam->imgs.motionsize = cam->conf->width * cam->conf->height; - return 0; } static int netcam_copy_stream(ctx_netcam *netcam) @@ -2064,10 +2067,6 @@ static int netcam_start_handler(ctx_netcam *netcam) pthread_attr_init(&handler_attribute); pthread_attr_setdetachstate(&handler_attribute, PTHREAD_CREATE_DETACHED); - pthread_mutex_lock(&netcam->motapp->global_lock); - netcam->threadnbr = ++netcam->motapp->threads_running; - pthread_mutex_unlock(&netcam->motapp->global_lock); - retcd = pthread_create(&netcam->thread_id, &handler_attribute, &netcam_handler, netcam); if (retcd < 0) { MOTION_LOG(ALR, TYPE_NETCAM, SHOW_ERRNO @@ -2102,141 +2101,8 @@ static int netcam_start_handler(ctx_netcam *netcam) } -int netcam_setup(ctx_cam *cam) +void netcam_cleanup(ctx_cam *cam) { - - int retcd; - int indx_cam, indx_max; - ctx_netcam *netcam; - - cam->netcam = NULL; - cam->netcam_high = NULL; - - if (netcam_set_dimensions(cam) < 0 ) { - return -1; - } - - indx_cam = 1; - if (cam->conf->netcam_high_url != "") { - indx_max = 2; - } else { - indx_max = 1; - } - - while (indx_cam <= indx_max){ - if (indx_cam == 1) { - cam->netcam = netcam_new_context(); - if (cam->netcam == NULL) { - MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO - ,_("unable to create rtsp context")); - return -1; - } - netcam = cam->netcam; - netcam->high_resolution = false; /* Set flag for this being the normal resolution camera */ - } else { - cam->netcam_high = netcam_new_context(); - if (cam->netcam_high == NULL) { - MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO - ,_("unable to create rtsp high context")); - return -1; - } - netcam = cam->netcam_high; - netcam->high_resolution = true; /* Set flag for this being the high resolution camera */ - } - - netcam_null_context(netcam); - - netcam_set_parms(cam, netcam); - - if (netcam_connect(netcam) < 0) { - return -1; - } - - retcd = netcam_read_image(netcam); - if (retcd < 0) { - MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO - ,_("Failed trying to read first image - retval:%d"), retcd); - netcam->status = NETCAM_NOTCONNECTED; - return -1; - } - /* When running dual, there seems to be contamination across norm/high with codec functions. */ - netcam_close_context(netcam); /* Close in this thread to open it again within handler thread */ - netcam->status = NETCAM_RECONNECTING; /* Set as reconnecting to avoid excess messages when starting */ - netcam->first_image = false; /* Set flag that we are not processing our first image */ - - /* For normal resolution, we resize the image to the config parms so we do not need - * to set the dimension parameters here (it is done in the set_parms). For high res - * we must get the dimensions from the first image captured - */ - if (netcam->high_resolution) { - cam->imgs.width_high = netcam->imgsize.width; - cam->imgs.height_high = netcam->imgsize.height; - } - - if (netcam_start_handler(netcam) < 0 ) { - return -1; - } - - indx_cam++; - } - - return 0; - -} - -/* netcam_next (Called from the motion loop thread) */ -int netcam_next(ctx_cam *cam, ctx_image_data *img_data) -{ - if (cam == NULL) { - return 1; - } - - if (cam->netcam != NULL) { - if ((cam->netcam->status == NETCAM_RECONNECTING) || - (cam->netcam->status == NETCAM_NOTCONNECTED)) { - return 1; - } - pthread_mutex_lock(&cam->netcam->mutex); - netcam_pktarray_resize(cam, false); - memcpy(img_data->image_norm - , cam->netcam->img_latest->ptr - , cam->netcam->img_latest->used); - img_data->idnbr_norm = cam->netcam->idnbr; - pthread_mutex_unlock(&cam->netcam->mutex); - } - - if (cam->netcam_high != NULL) { - if ((cam->netcam_high->status == NETCAM_RECONNECTING) || - (cam->netcam_high->status == NETCAM_NOTCONNECTED)) { - return 1; - } - - pthread_mutex_lock(&cam->netcam_high->mutex); - netcam_pktarray_resize(cam, true); - if (!cam->netcam_high->passthrough) { - memcpy(img_data->image_high - ,cam->netcam_high->img_latest->ptr - ,cam->netcam_high->img_latest->used); - } - img_data->idnbr_high = cam->netcam_high->idnbr; - pthread_mutex_unlock(&cam->netcam_high->mutex); - } - - /* Rotate images if requested */ - rotate_map(cam, img_data); - - return 0; -} - -void netcam_cleanup(ctx_cam *cam, bool init_retry_flag) -{ - - /* - * If the init_retry_flag is not set this function was - * called while retrying the initial connection and there is - * no camera-handler started yet and thread_running must - * not be decremented. This is called from motion_loop thread - */ int wait_counter; int indx_cam, indx_max; ctx_netcam *netcam; @@ -2258,11 +2124,6 @@ void netcam_cleanup(ctx_cam *cam, bool init_retry_flag) if (netcam) { MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO ,_("%s: Shutting down network camera."),netcam->cameratype); - - /* Throw the finish flag in context and wait a bit for it to finish its work and close everything - * This is shutting down the thread so for the moment, we are not worrying about the - * cross threading and protecting these variables with mutex's - */ netcam->finish = true; netcam->interruptduration = 0; wait_counter = 0; @@ -2273,17 +2134,13 @@ void netcam_cleanup(ctx_cam *cam, bool init_retry_flag) if (!netcam->handler_finished) { MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO ,_("%s: No response from handler thread."),netcam->cameratype); - /* Last resort. Kill the thread. Not safe for posix but if no response, what to do...*/ - /* pthread_kill(netcam->thread_id); */ + /* Last resort. Kill the thread.*/ pthread_cancel(netcam->thread_id); - pthread_kill(netcam->thread_id, SIGVTALRM); /* This allows the cancel to be processed */ - if (!init_retry_flag) { - pthread_mutex_lock(&netcam->motapp->global_lock); - netcam->motapp->threads_running--; - pthread_mutex_unlock(&netcam->motapp->global_lock); - } + pthread_kill(netcam->thread_id, SIGVTALRM); + pthread_mutex_lock(&netcam->motapp->global_lock); + netcam->motapp->threads_running--; + pthread_mutex_unlock(&netcam->motapp->global_lock); } - /* If we never connect we don't have a handler but we still need to clean up some */ netcam_shutdown(netcam); pthread_mutex_destroy(&netcam->mutex); @@ -2304,8 +2161,133 @@ void netcam_cleanup(ctx_cam *cam, bool init_retry_flag) } cam->netcam = NULL; cam->netcam_high = NULL; - if (init_retry_flag == false) { - cam->running_cam = false; - } + cam->running_cam = false; + cam->camera_status = STATUS_CLOSED; + +} + +void netcam_start(ctx_cam *cam) +{ + int indx_cam, indx_max; + ctx_netcam *netcam; + + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening Netcam")); + + cam->netcam = NULL; + cam->netcam_high = NULL; + + netcam_set_dimensions(cam); + + indx_cam = 1; + if (cam->conf->netcam_high_url != "") { + indx_max = 2; + } else { + indx_max = 1; + } + + while (indx_cam <= indx_max) { + + if (indx_cam == 1) { + cam->netcam = netcam_new_context(); + if (cam->netcam == NULL) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO + ,_("unable to create rtsp context")); + netcam_cleanup(cam); + return; + } + netcam = cam->netcam; + netcam->high_resolution = false; /* Set flag for this being the normal resolution camera */ + } else { + cam->netcam_high = netcam_new_context(); + if (cam->netcam_high == NULL) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO + ,_("unable to create rtsp high context")); + netcam_cleanup(cam); + return; + } + netcam = cam->netcam_high; + netcam->high_resolution = true; /* Set flag for this being the high resolution camera */ + } + + netcam_null_context(netcam); + netcam_set_parms(cam, netcam); + if (netcam_connect(netcam) != 0) { + netcam_cleanup(cam); + return; + } + if (netcam_read_image(netcam) != 0) { + MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO + ,_("Failed trying to read first image")); + netcam->status = NETCAM_NOTCONNECTED; + netcam_cleanup(cam); + return; + } + /* When running dual, there seems to be contamination across norm/high with codec functions. */ + netcam_close_context(netcam); /* Close in this thread to open it again within handler thread */ + netcam->status = NETCAM_RECONNECTING; /* Set as reconnecting to avoid excess messages when starting */ + netcam->first_image = false; /* Set flag that we are not processing our first image */ + + /* For normal resolution, we resize the image to the config parms so we do not need + * to set the dimension parameters here (it is done in the set_parms). For high res + * we must get the dimensions from the first image captured + */ + if (netcam->high_resolution) { + cam->imgs.width_high = netcam->imgsize.width; + cam->imgs.height_high = netcam->imgsize.height; + } + + if (netcam_start_handler(netcam) != 0 ) { + netcam_cleanup(cam); + return; + } + + indx_cam++; + } + + cam->camera_status = STATUS_OPENED; + + return; + +} + +/* netcam_next (Called from the motion loop thread) */ +int netcam_next(ctx_cam *cam, ctx_image_data *img_data) +{ + if ((cam == NULL) || (cam->netcam == NULL)) { + return CAPTURE_FAILURE; + } + + if ((cam->netcam->status == NETCAM_RECONNECTING) || + (cam->netcam->status == NETCAM_NOTCONNECTED)) { + return CAPTURE_ATTEMPTED; + } + pthread_mutex_lock(&cam->netcam->mutex); + netcam_pktarray_resize(cam, false); + memcpy(img_data->image_norm + , cam->netcam->img_latest->ptr + , cam->netcam->img_latest->used); + img_data->idnbr_norm = cam->netcam->idnbr; + pthread_mutex_unlock(&cam->netcam->mutex); + + if (cam->netcam_high != NULL) { + if ((cam->netcam_high->status == NETCAM_RECONNECTING) || + (cam->netcam_high->status == NETCAM_NOTCONNECTED)) { + return CAPTURE_ATTEMPTED; + } + + pthread_mutex_lock(&cam->netcam_high->mutex); + netcam_pktarray_resize(cam, true); + if (!cam->netcam_high->passthrough) { + memcpy(img_data->image_high + ,cam->netcam_high->img_latest->ptr + ,cam->netcam_high->img_latest->used); + } + img_data->idnbr_high = cam->netcam_high->idnbr; + pthread_mutex_unlock(&cam->netcam_high->mutex); + } + + rotate_map(cam, img_data); + + return CAPTURE_SUCCESS; } diff --git a/src/netcam.hpp b/src/netcam.hpp index 77fe426b..7736a84e 100644 --- a/src/netcam.hpp +++ b/src/netcam.hpp @@ -22,8 +22,6 @@ #ifndef _INCLUDE_NETCAM_HPP_ #define _INCLUDE_NETCAM_HPP_ -#define NETCAM_GENERAL_ERROR 0x02 /* binary 000010 */ -#define NETCAM_RESTART_ERROR 0x12 /* binary 010010 */ #define NETCAM_BUFFSIZE 4096 enum NETCAM_STATUS { @@ -151,8 +149,8 @@ struct ctx_netcam { }; -int netcam_setup(ctx_cam *cam); +void netcam_start(ctx_cam *cam); int netcam_next(ctx_cam *cam, ctx_image_data *img_data); -void netcam_cleanup(ctx_cam *cam, bool init_retry_flag); +void netcam_cleanup(ctx_cam *cam); #endif /* _INCLUDE_NETCAM_HPP_ */ diff --git a/src/video_v4l2.cpp b/src/video_v4l2.cpp index 71cdc7ed..7bdd3bdf 100644 --- a/src/video_v4l2.cpp +++ b/src/video_v4l2.cpp @@ -836,7 +836,7 @@ static int v4l2_capture(ctx_v4l2cam *v4l2cam) if (retcd == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_QBUF"); pthread_sigmask(SIG_UNBLOCK, &old, NULL); - return retcd; + return -1; } } @@ -850,7 +850,7 @@ static int v4l2_capture(ctx_v4l2cam *v4l2cam) if (retcd == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_DQBUF"); pthread_sigmask(SIG_UNBLOCK, &old, NULL); - return retcd; + return -1; } v4l2cam->pframe = v4l2cam->buf.index; @@ -935,7 +935,7 @@ static int v4l2_convert(ctx_cam *cam, ctx_v4l2cam *v4l2cam, unsigned char *img_n return 0; } - return 1; + return -1; } @@ -1199,10 +1199,6 @@ void v4l2_cleanup(ctx_cam *cam) MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO ,_("Closing video device %s"), cam->conf->v4l2_device.c_str()); - if (cam->v4l2cam == NULL) { - return; - } - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (cam->v4l2cam->fd_device != -1) { @@ -1232,19 +1228,20 @@ void v4l2_cleanup(ctx_cam *cam) myfree(&cam->v4l2cam->params); myfree(&cam->v4l2cam); - - cam->running_cam = false; - #else - (void)cam; #endif // HAVE_V4L2 + + cam->running_cam = false; + cam->camera_status = STATUS_CLOSED; + } -int v4l2_start(ctx_cam *cam) +void v4l2_start(ctx_cam *cam) { #ifdef HAVE_V4L2 - int retcd; + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening V4L2 device")); + retcd = v4l2_device_init(cam); if (retcd == 0) retcd = v4l2_device_open(cam); if (retcd == 0) v4l2_log_types(cam->v4l2cam); @@ -1259,15 +1256,14 @@ int v4l2_start(ctx_cam *cam) if (retcd == 0) v4l2_ctrls_set(cam->v4l2cam); if (retcd == 0) retcd = v4l2_set_mmap(cam->v4l2cam); if (retcd == 0) v4l2_set_imgs(cam); - if (retcd < 0) { + if (retcd == 0) { + cam->camera_status = STATUS_OPENED; + } else { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("V4L2 device failed to open")); v4l2_cleanup(cam); - return retcd; } - - return cam->v4l2cam->fd_device; #else - (void)cam; - return -1; + cam->camera_status = STATUS_CLOSED; #endif // HAVE_V4l2 } @@ -1276,25 +1272,29 @@ int v4l2_next(ctx_cam *cam, ctx_image_data *img_data) #ifdef HAVE_V4L2 int retcd; + if (cam->v4l2cam == NULL) { + return CAPTURE_FAILURE; + } + v4l2_device_select(cam); retcd = v4l2_capture(cam->v4l2cam); if (retcd != 0) { - return retcd; + return CAPTURE_FAILURE; } retcd = v4l2_convert(cam, cam->v4l2cam, img_data->image_norm); if (retcd != 0) { - return retcd; + return CAPTURE_FAILURE; } rotate_map(cam, img_data); - return retcd; + return CAPTURE_SUCCESS; #else (void)cam; (void)img_data; - return -1; + return CAPTURE_FAILURE; #endif // HAVE_V4L2 } diff --git a/src/video_v4l2.hpp b/src/video_v4l2.hpp index 07c18aef..80d4d078 100644 --- a/src/video_v4l2.hpp +++ b/src/video_v4l2.hpp @@ -73,7 +73,7 @@ struct ctx_v4l2cam { #endif }; - int v4l2_start(ctx_cam *cam); + void v4l2_start(ctx_cam *cam); int v4l2_next(ctx_cam *cam, ctx_image_data *img_data); void v4l2_cleanup(ctx_cam *cam);