/* vcb should be locked before calling video_record_stop() */ void video_record_stop(VideoCircularBuffer *vcb) { Event *event = NULL; char *cmd; if (!vcb->file) return; fclose(vcb->file); vcb->file = NULL; log_printf("Video %s record stopped.\n", (vcb->state & VCB_STATE_MOTION_RECORD) ? "motion" : "manual"); if (pikrellcam.video_mp4box) { asprintf(&cmd, "(MP4Box %s -fps %d -add %s %s %s ; rm %s)", pikrellcam.verbose ? "" : "-quiet", pikrellcam.camera_adjust.mp4_box_fps, pikrellcam.video_h264, pikrellcam.video_pathname, pikrellcam.verbose ? "" : "2> /dev/null", pikrellcam.video_h264); if ( (vcb->state & VCB_STATE_MOTION_RECORD) && *pikrellcam.on_motion_end_cmd ) event = exec_child_event("motion end command", cmd, NULL); else exec_no_wait(cmd, NULL); free(cmd); } dup_string(&pikrellcam.video_last_save, pikrellcam.video_pathname); pikrellcam.video_notify = TRUE; event_count_down_add("video saved notify", pikrellcam.notify_duration * EVENT_LOOP_FREQUENCY, event_notify_expire, &pikrellcam.video_notify); if (vcb->state & VCB_STATE_MOTION_RECORD) { if (!strcmp(pikrellcam.motion_preview_save_mode, "best")) event_add("preview save command", pikrellcam.t_now, 0, event_preview_save_cmd, pikrellcam.on_motion_preview_save_cmd); if (event) /* a mp4 video save event needs a MP4Box child exit */ { event->data = pikrellcam.on_motion_end_cmd; event->func = event_motion_end_cmd; } else if (*pikrellcam.on_motion_end_cmd) /* a h264 video save */ event_add("motion end command", pikrellcam.t_now, 0, event_motion_end_cmd, pikrellcam.on_motion_end_cmd); } event_add("preview dispose", pikrellcam.t_now, 0, event_preview_dispose, NULL); vcb->state = VCB_STATE_NONE; vcb->pause = FALSE; }
boolean still_capture(char *fname) { Event *event; int n; MMAL_STATUS_T status; boolean result = FALSE; /* timelapse_shapshot() also uses the still_jpeg_encoder, so wait if busy. */ for (n = 0; n < 5; ++n) { if (still_jpeg_encoder.file == NULL) break; usleep(50000); } if (still_jpeg_encoder.file != NULL) { /* inform() */ log_printf("still capture failed because jpeg encoder is busy.\n"); return FALSE; } if ((still_jpeg_encoder.file = fopen(fname, "w")) == NULL) log_printf("Could not create still file %s. %m\n", fname); else { if ((status = mmal_port_parameter_set_boolean( camera.component->output[CAMERA_CAPTURE_PORT], MMAL_PARAMETER_CAPTURE, 1)) != MMAL_SUCCESS) { fclose(still_jpeg_encoder.file); still_jpeg_encoder.file = NULL; log_printf("Still capture startup failed. Status %s\n", mmal_status[status]); } else { result = TRUE; log_printf("Still: %s\n", fname); dup_string(&pikrellcam.still_last_save, fname); n = pikrellcam.notify_duration * EVENT_LOOP_FREQUENCY; if ((event = event_find("still saved")) != NULL) event->count = n; /* rapid stills, extend the time */ else event_count_down_add("still saved", n, event_notify_expire, &pikrellcam.still_notify); pikrellcam.still_capture_event = TRUE; pikrellcam.still_notify = TRUE; } } return result; }
void timelapse_capture(void) { char *path, seq_buf[12], series_buf[12]; int n, nd; MMAL_STATUS_T status; if (time_lapse.on_hold) return; /* still_capture() also uses the still_jpeg_encoder, so wait if busy. */ for (n = 0; n < 5; ++n) { if (still_jpeg_encoder.file == NULL) break; usleep(50000); } if (still_jpeg_encoder.file != NULL) { log_printf("timelapse capture failed because jpeg encoder is busy.\n"); return; } snprintf(seq_buf, sizeof(seq_buf), "%05d", time_lapse.sequence); snprintf(series_buf, sizeof(series_buf), "%05d", time_lapse.series); path = media_pathname(pikrellcam.timelapse_dir, pikrellcam.timelapse_format, 'N', seq_buf, 'n', series_buf); time_lapse.sequence += 1; if ((still_jpeg_encoder.file = fopen(path, "w")) == NULL) log_printf("Could not create timelapse file %s. %m\n", path); else { if ((status = mmal_port_parameter_set_boolean( camera.component->output[CAMERA_CAPTURE_PORT], MMAL_PARAMETER_CAPTURE, 1)) != MMAL_SUCCESS) { fclose(still_jpeg_encoder.file); still_jpeg_encoder.file = NULL; log_printf("Timelapse capture startup failed. Status %s\n", mmal_status[status]); } else { log_printf("Timelapse still: %s\n", path); dup_string(&pikrellcam.timelapse_last_save, path); /* timelapse_capture() is an event call (inside the event loop) | and we here add an event to the list. | This only modifies the last event list next pointer, and | the event loop is not there yet. */ nd = pikrellcam.notify_duration; if (nd > time_lapse.period - 3) nd = time_lapse.period / 2; if (nd > 1) nd *= EVENT_LOOP_FREQUENCY; else nd = EVENT_LOOP_FREQUENCY / 2; event_count_down_add("timelapse saved", nd, event_notify_expire, &pikrellcam.timelapse_notify); pikrellcam.timelapse_notify = TRUE; } } free(path); }