rpicamsrc: Checkpoint. Version which writes directly to test.out
authorJan Schmidt <thaytan@noraisin.net>
Sat, 12 Oct 2013 01:42:07 +0000 (12:42 +1100)
committerTim-Philipp Müller <tim@centricular.com>
Fri, 10 Jul 2020 15:42:06 +0000 (16:42 +0100)
Switch to plain basesrc for parent class

sys/rpicamsrc/RaspiCamControl.c
sys/rpicamsrc/RaspiCapture.c
sys/rpicamsrc/RaspiCapture.h
sys/rpicamsrc/RaspiStill.c
sys/rpicamsrc/gstrpicamsrc.c
sys/rpicamsrc/gstrpicamsrc.h

index f379015..80ad6fa 100644 (file)
@@ -187,6 +187,7 @@ static int update_cycle_parameter(int *option, int min, int max, int increment)
    else
       return 1;
 }
+#endif
 
 
 /**
@@ -203,6 +204,9 @@ static int update_cycle_parameter(int *option, int min, int max, int increment)
 
 int raspicamcontrol_cycle_test(MMAL_COMPONENT_T *camera)
 {
+   return 1;
+}
+#if 0
    static int parameter = 0;
    static int parameter_option = parameter_reset; // which value the parameter currently has
 
index d6f9b12..348a5c8 100644 (file)
@@ -57,6 +57,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <memory.h>
 #include <sysexits.h>
 
+
 #include "bcm_host.h"
 #include "interface/vcos/vcos.h"
 
@@ -68,6 +69,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "interface/mmal/util/mmal_default_components.h"
 #include "interface/mmal/util/mmal_connection.h"
 
+#include "RaspiCapture.h"
 #include "RaspiCamControl.h"
 #include "RaspiPreview.h"
 
@@ -97,42 +99,32 @@ const int ABORT_INTERVAL = 100; // ms
 
 int mmal_status_to_int(MMAL_STATUS_T status);
 
-/** Structure containing all state information for the current run
+/** Struct used to pass information in encoder port userdata to callback
  */
 typedef struct
 {
-   int timeout;                        /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
-   int width;                          /// Requested width of image
-   int height;                         /// requested height of image
-   int bitrate;                        /// Requested bitrate
-   int framerate;                      /// Requested frame rate (fps)
-   int intraperiod;                    /// Intra-refresh period (key frame rate)
-   char *filename;                     /// filename of output file
-   int verbose;                        /// !0 if want detailed run information
-   int demoMode;                       /// Run app in demo mode
-   int demoInterval;                   /// Interval between camera settings changes
-   int immutableInput;                 /// Flag to specify whether encoder works in place or creates a new buffer. Result is preview can display either
-                                       /// the camera output or the encoder output (with compression artifacts)
-   int profile;                        /// H264 profile to use for encoding
-   RASPIPREVIEW_PARAMETERS preview_parameters;   /// Preview setup parameters
-   RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters
+   RASPIVID_STATE *state; /// pointer to our state in case required in callback
+   int abort;             /// Set to 1 in callback if an error occurs to attempt to abort the capture
+} PORT_USERDATA;
+
+struct RASPIVID_STATE_T
+{
+   RASPIVID_CONFIG config;
+
+   FILE *output_file;
 
    MMAL_COMPONENT_T *camera_component;    /// Pointer to the camera component
    MMAL_COMPONENT_T *encoder_component;   /// Pointer to the encoder component
    MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview
    MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder
 
+   MMAL_PORT_T *camera_still_port;
+   MMAL_PORT_T *encoder_output_port;
+
    MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port
-} RASPIVID_STATE;
 
-/** Struct used to pass information in encoder port userdata to callback
- */
-typedef struct
-{
-   FILE *file_handle;                   /// File handle to write buffer data to.
-   RASPIVID_STATE *pstate;              /// pointer to our state in case required in callback
-   int abort;                           /// Set to 1 in callback if an error occurs to attempt to abort the capture
-} PORT_USERDATA;
+   PORT_USERDATA callback_data;
+};
 
 #if 0
 /// Structure to cross reference H264 profile strings against the MMAL parameter equivalent
@@ -189,36 +181,27 @@ static void dump_state(RASPIVID_STATE *state);
  *
  * @param state Pointer to state structure to assign defaults to
  */
-void raspi_capture_default_state(RASPIVID_STATE *state)
+void raspicapture_default_config(RASPIVID_CONFIG *config)
 {
-   if (!state)
-   {
-      vcos_assert(0);
-      return;
-   }
-
-   // Default everything to zero
-   memset(state, 0, sizeof(RASPIVID_STATE));
 
    // Now set anything non-zero
-   state->timeout = 5000;     // 5s delay before take image
-   state->width = 1920;       // Default to 1080p
-   state->height = 1080;
-   state->bitrate = 17000000; // This is a decent default bitrate for 1080p
-   state->framerate = VIDEO_FRAME_RATE_NUM;
-   state->intraperiod = 0;    // Not set
-   state->demoMode = 0;
-   state->demoInterval = 250; // ms
-   state->immutableInput = 1;
-   state->profile = MMAL_VIDEO_PROFILE_H264_HIGH;
+   config->timeout = 5000;     // 5s delay before take image
+   config->width = 1920;       // Default to 1080p
+   config->height = 1080;
+   config->bitrate = 17000000; // This is a decent default bitrate for 1080p
+   config->framerate = VIDEO_FRAME_RATE_NUM;
+   config->intraperiod = 0;    // Not set
+   config->demoMode = 0;
+   config->demoInterval = 250; // ms
+   config->immutableInput = 1;
+   config->profile = MMAL_VIDEO_PROFILE_H264_HIGH;
 
    // Setup preview window defaults
-   raspipreview_set_defaults(&state->preview_parameters);
+   raspipreview_set_defaults(&config->preview_parameters);
 
    // Set up the camera_parameters to default
-   raspicamcontrol_set_defaults(&state->camera_parameters);
+   raspicamcontrol_set_defaults(&config->camera_parameters);
 
-   dump_state(state);
 }
 
 /**
@@ -234,12 +217,12 @@ static void dump_state(RASPIVID_STATE *state)
       return;
    }
 
-   fprintf(stderr, "Width %d, Height %d, filename %s\n", state->width, state->height, state->filename);
-   fprintf(stderr, "bitrate %d, framerate %d, time delay %d\n", state->bitrate, state->framerate, state->timeout);
-   //fprintf(stderr, "H264 Profile %s\n", raspicli_unmap_xref(state->profile, profile_map, profile_map_size));
+   fprintf(stderr, "Width %d, Height %d, filename %s\n", state->config.width, state->config.height, state->config.filename);
+   fprintf(stderr, "bitrate %d, framerate %d, time delay %d\n", state->config.bitrate, state->config.framerate, state->config.timeout);
+   //fprintf(stderr, "H264 Profile %s\n", raspicli_unmap_xref(state->config.profile, profile_map, profile_map_size));
 
-   raspipreview_dump_parameters(&state->preview_parameters);
-   raspicamcontrol_dump_parameters(&state->camera_parameters);
+   raspipreview_dump_parameters(&state->config.preview_parameters);
+   //raspicamcontrol_dump_parameters(&state->config.camera_parameters);
 }
 
 #if 0
@@ -521,18 +504,19 @@ static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf
    // We pass our file handle and other stuff in via the userdata field.
 
    PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
+   RASPIVID_STATE *state  = pData->state;
 
    if (pData)
    {
       int bytes_written = buffer->length;
 
-      vcos_assert(pData->file_handle);
+      vcos_assert(state->output_file);
 
       if (buffer->length)
       {
          mmal_buffer_header_mem_lock(buffer);
 
-         bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle);
+         bytes_written = fwrite(buffer->data, 1, buffer->length, state->output_file);
 
          mmal_buffer_header_mem_unlock(buffer);
       }
@@ -554,9 +538,9 @@ static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf
    // and send one back to the port (if still open)
    if (port->is_enabled)
    {
-      MMAL_STATUS_T status;
+      MMAL_STATUS_T status = MMAL_SUCCESS;
 
-      new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue);
+      new_buffer = mmal_queue_get(state->encoder_pool->queue);
 
       if (new_buffer)
          status = mmal_port_send_buffer(port, new_buffer);
@@ -616,12 +600,12 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
       MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
       {
          { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
-         .max_stills_w = state->width,
-         .max_stills_h = state->height,
+         .max_stills_w = state->config.width,
+         .max_stills_h = state->config.height,
          .stills_yuv422 = 0,
          .one_shot_stills = 0,
-         .max_preview_video_w = state->width,
-         .max_preview_video_h = state->height,
+         .max_preview_video_w = state->config.width,
+         .max_preview_video_h = state->config.height,
          .num_preview_video_frames = 3,
          .stills_capture_circular_buffer_height = 0,
          .fast_preview_resume = 0,
@@ -641,13 +625,13 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
    format->encoding_variant = MMAL_ENCODING_I420;
 
    format->encoding = MMAL_ENCODING_OPAQUE;
-   format->es->video.width = state->width;
-   format->es->video.height = state->height;
+   format->es->video.width = state->config.width;
+   format->es->video.height = state->config.height;
    format->es->video.crop.x = 0;
    format->es->video.crop.y = 0;
-   format->es->video.crop.width = state->width;
-   format->es->video.crop.height = state->height;
-   format->es->video.frame_rate.num = state->framerate;
+   format->es->video.crop.width = state->config.width;
+   format->es->video.crop.height = state->config.height;
+   format->es->video.frame_rate.num = state->config.framerate;
    format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN;
 
    status = mmal_port_format_commit(preview_port);
@@ -664,13 +648,13 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
    format->encoding_variant = MMAL_ENCODING_I420;
 
    format->encoding = MMAL_ENCODING_OPAQUE;
-   format->es->video.width = state->width;
-   format->es->video.height = state->height;
+   format->es->video.width = state->config.width;
+   format->es->video.height = state->config.height;
    format->es->video.crop.x = 0;
    format->es->video.crop.y = 0;
-   format->es->video.crop.width = state->width;
-   format->es->video.crop.height = state->height;
-   format->es->video.frame_rate.num = state->framerate;
+   format->es->video.crop.width = state->config.width;
+   format->es->video.crop.height = state->config.height;
+   format->es->video.frame_rate.num = state->config.framerate;
    format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN;
 
    status = mmal_port_format_commit(video_port);
@@ -693,12 +677,12 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
    format->encoding = MMAL_ENCODING_OPAQUE;
    format->encoding_variant = MMAL_ENCODING_I420;
 
-   format->es->video.width = state->width;
-   format->es->video.height = state->height;
+   format->es->video.width = state->config.width;
+   format->es->video.height = state->config.height;
    format->es->video.crop.x = 0;
    format->es->video.crop.y = 0;
-   format->es->video.crop.width = state->width;
-   format->es->video.crop.height = state->height;
+   format->es->video.crop.width = state->config.width;
+   format->es->video.crop.height = state->config.height;
    format->es->video.frame_rate.num = 1;
    format->es->video.frame_rate.den = 1;
 
@@ -723,11 +707,11 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
       goto error;
    }
 
-   raspicamcontrol_set_all_parameters(camera, &state->camera_parameters);
+   raspicamcontrol_set_all_parameters(camera, &state->config.camera_parameters);
 
    state->camera_component = camera;
 
-   if (state->verbose)
+   if (state->config.verbose)
       fprintf(stderr, "Camera component done\n");
 
    return status;
@@ -794,7 +778,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
    // Only supporting H264 at the moment
    encoder_output->format->encoding = MMAL_ENCODING_H264;
 
-   encoder_output->format->bitrate = state->bitrate;
+   encoder_output->format->bitrate = state->config.bitrate;
 
    encoder_output->buffer_size = encoder_output->buffer_size_recommended;
 
@@ -829,9 +813,9 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
 
    }
 
-   if (state->intraperiod)
+   if (state->config.intraperiod)
    {
-      MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, state->intraperiod};
+      MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, state->config.intraperiod};
       status = mmal_port_parameter_set(encoder_output, &param.hdr);
       if (status != MMAL_SUCCESS)
       {
@@ -846,7 +830,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
       param.hdr.id = MMAL_PARAMETER_PROFILE;
       param.hdr.size = sizeof(param);
 
-      param.profile[0].profile = state->profile;
+      param.profile[0].profile = state->config.profile;
       param.profile[0].level = MMAL_VIDEO_LEVEL_H264_4; // This is the only value supported
 
       status = mmal_port_parameter_set(encoder_output, &param.hdr);
@@ -858,7 +842,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
    }
 
 
-   if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, state->immutableInput) != MMAL_SUCCESS)
+   if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, state->config.immutableInput) != MMAL_SUCCESS)
    {
       vcos_log_error("Unable to set immutable input flag");
       // Continue rather than abort..
@@ -884,7 +868,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
    state->encoder_pool = pool;
    state->encoder_component = encoder;
 
-   if (state->verbose)
+   if (state->config.verbose)
       fprintf(stderr, "Encoder component done\n");
 
    return status;
@@ -954,258 +938,262 @@ static void check_disable_port(MMAL_PORT_T *port)
       mmal_port_disable(port);
 }
 
-
-int raspi_capture_start()
+void raspicapture_init()
 {
-   // Our main data storage vessel..
-   RASPIVID_STATE state;
-   int exit_code = EX_OK;
-
-   MMAL_STATUS_T status = MMAL_SUCCESS;
-   MMAL_PORT_T *camera_preview_port = NULL;
-   MMAL_PORT_T *camera_video_port = NULL;
-   MMAL_PORT_T *camera_still_port = NULL;
-   MMAL_PORT_T *preview_input_port = NULL;
-   MMAL_PORT_T *encoder_input_port = NULL;
-   MMAL_PORT_T *encoder_output_port = NULL;
-   FILE *output_file = NULL;
-
    bcm_host_init();
 
    // Register our application with the logging system
    vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY);
+}
 
-   raspi_capture_default_state(&state);
-
-   if (state.verbose)
-   {
-      dump_state(&state);
-   }
-
-   // OK, we have a nice set of parameters. Now set up our components
-   // We have three components. Camera, Preview and encoder.
-
-   if ((status = create_camera_component(&state)) != MMAL_SUCCESS)
-   {
-      vcos_log_error("%s: Failed to create camera component", __func__);
-      exit_code = EX_SOFTWARE;
-   }
-   else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS)
-   {
-      vcos_log_error("%s: Failed to create preview component", __func__);
-      destroy_camera_component(&state);
-      exit_code = EX_SOFTWARE;
-   }
-   else if ((status = create_encoder_component(&state)) != MMAL_SUCCESS)
-   {
-      vcos_log_error("%s: Failed to create encode component", __func__);
-      raspipreview_destroy(&state.preview_parameters);
-      destroy_camera_component(&state);
-      exit_code = EX_SOFTWARE;
-   }
-   else
-   {
-      PORT_USERDATA callback_data;
-
-      if (state.verbose)
-         fprintf(stderr, "Starting component connection stage\n");
-
-      camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
-      camera_video_port   = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT];
-      camera_still_port   = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
-      preview_input_port  = state.preview_parameters.preview_component->input[0];
-      encoder_input_port  = state.encoder_component->input[0];
-      encoder_output_port = state.encoder_component->output[0];
-
-      if (state.preview_parameters.wantPreview )
-      {
-         if (state.verbose)
-         {
-            fprintf(stderr, "Connecting camera preview port to preview input port\n");
-            fprintf(stderr, "Starting video preview\n");
-         }
-
-         // Connect camera to preview
-         status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection);
-      }
-      else
-      {
-         status = MMAL_SUCCESS;
-      }
-
-      if (status == MMAL_SUCCESS)
-      {
-         if (state.verbose)
-            fprintf(stderr, "Connecting camera stills port to encoder input port\n");
-
-         // Now connect the camera to the encoder
-         status = connect_ports(camera_video_port, encoder_input_port, &state.encoder_connection);
-
-         if (status != MMAL_SUCCESS)
-         {
-            vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
-            goto error;
-         }
-
-         if (state.filename)
-         {
-            if (state.filename[0] == '-')
-            {
-               output_file = stdout;
-
-               // Ensure we don't upset the output stream with diagnostics/info
-               state.verbose = 0;
-            }
-            else
-            {
-               if (state.verbose)
-                  fprintf(stderr, "Opening output file \"%s\"\n", state.filename);
-
-               output_file = fopen(state.filename, "wb");
-            }
-
-            if (!output_file)
-            {
-               // Notify user, carry on but discarding encoded output buffers
-               vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state.filename);
-            }
-         }
-
-         // Set up our userdata - this is passed though to the callback where we need the information.
-         callback_data.file_handle = output_file;
-         callback_data.pstate = &state;
-         callback_data.abort = 0;
-
-         encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data;
-
-         if (state.verbose)
-            fprintf(stderr, "Enabling encoder output port\n");
-
-         // Enable the encoder output port and tell it its callback function
-         status = mmal_port_enable(encoder_output_port, encoder_buffer_callback);
-
-         if (status != MMAL_SUCCESS)
-         {
-            vcos_log_error("Failed to setup encoder output");
-            goto error;
-         }
-
-         if (state.demoMode)
-         {
-            // Run for the user specific time..
-            int num_iterations = state.timeout / state.demoInterval;
-            int i;
-
-            if (state.verbose)
-               fprintf(stderr, "Running in demo mode\n");
-
-            for (i=0;state.timeout == 0 || i<num_iterations;i++)
-            {
-               raspicamcontrol_cycle_test(state.camera_component);
-               vcos_sleep(state.demoInterval);
-            }
-         }
-         else
-         {
-            // Only encode stuff if we have a filename and it opened
-            if (output_file)
-            {
-               int wait;
-
-               if (state.verbose)
-                  fprintf(stderr, "Starting video capture\n");
-
-               if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
-               {
-                  goto error;
-               }
-
-               // Send all the buffers to the encoder output port
-               {
-                  int num = mmal_queue_length(state.encoder_pool->queue);
-                  int q;
-                  for (q=0;q<num;q++)
-                  {
-                     MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.encoder_pool->queue);
-
-                     if (!buffer)
-                        vcos_log_error("Unable to get a required buffer %d from pool queue", q);
-
-                     if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS)
-                        vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
-
-                  }
-               }
-
-               // Now wait until we need to stop. Whilst waiting we do need to check to see if we have aborted (for example
-               // out of storage space)
-               // Going to check every ABORT_INTERVAL milliseconds
-
-               for (wait = 0; state.timeout == 0 || wait < state.timeout; wait+= ABORT_INTERVAL)
-               {
-                  vcos_sleep(ABORT_INTERVAL);
-                  if (callback_data.abort)
-                     break;
-               }
-
-               if (state.verbose)
-                  fprintf(stderr, "Finished capture\n");
-            }
-            else
-            {
-               if (state.timeout)
-                  vcos_sleep(state.timeout);
-               else
-                  for (;;) vcos_sleep(ABORT_INTERVAL);
-            }
-         }
-      }
-      else
-      {
-         mmal_status_to_int(status);
-         vcos_log_error("%s: Failed to connect camera to preview", __func__);
-      }
+RASPIVID_STATE *
+raspi_capture_start(RASPIVID_CONFIG *config)
+{
+  // Our main data storage vessel..
+  RASPIVID_STATE *state;
+  //int exit_code = EX_OK;
+
+  MMAL_STATUS_T status = MMAL_SUCCESS;
+  MMAL_PORT_T *camera_preview_port = NULL;
+  MMAL_PORT_T *camera_video_port = NULL;
+  MMAL_PORT_T *preview_input_port = NULL;
+  MMAL_PORT_T *encoder_input_port = NULL;
+
+  /* Default everything to zero */
+  state = calloc(1, sizeof(RASPIVID_STATE));
+
+  /* Apply passed in config */
+  state->config = *config;
+
+  if (state->config.verbose)
+  {
+     dump_state(state);
+  }
+
+  // OK, we have a nice set of parameters. Now set up our components
+  // We have three components. Camera, Preview and encoder.
+
+  if ((status = create_camera_component(state)) != MMAL_SUCCESS)
+  {
+     vcos_log_error("%s: Failed to create camera component", __func__);
+     return NULL;
+  }
+
+  if ((status = raspipreview_create(&state->config.preview_parameters)) != MMAL_SUCCESS)
+  {
+     vcos_log_error("%s: Failed to create preview component", __func__);
+     destroy_camera_component(state);
+     return NULL;
+  }
+
+  if ((status = create_encoder_component(state)) != MMAL_SUCCESS)
+  {
+     vcos_log_error("%s: Failed to create encode component", __func__);
+     raspipreview_destroy(&state->config.preview_parameters);
+     destroy_camera_component(state);
+     return NULL;
+  }
+
+  if (state->config.verbose)
+     fprintf(stderr, "Starting component connection stage\n");
+
+  camera_preview_port = state->camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
+  camera_video_port   = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT];
+  preview_input_port  = state->config.preview_parameters.preview_component->input[0];
+  encoder_input_port  = state->encoder_component->input[0];
+  state->camera_still_port   = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
+  state->encoder_output_port = state->encoder_component->output[0];
+
+  if (state->config.preview_parameters.wantPreview )
+  {
+     if (state->config.verbose)
+     {
+        fprintf(stderr, "Connecting camera preview port to preview input port\n");
+        fprintf(stderr, "Starting video preview\n");
+     }
+
+     // Connect camera to preview
+     status = connect_ports(camera_preview_port, preview_input_port, &state->preview_connection);
+     if (status != MMAL_SUCCESS)
+     {
+        mmal_status_to_int(status);
+        vcos_log_error("%s: Failed to connect camera to preview", __func__);
+        goto error;
+     }
+  }
+
+  if (state->config.verbose)
+     fprintf(stderr, "Connecting camera stills port to encoder input port\n");
+
+  // Now connect the camera to the encoder
+  status = connect_ports(camera_video_port, encoder_input_port, &state->encoder_connection);
+
+  if (status != MMAL_SUCCESS)
+  {
+     vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
+     goto error;
+  }
+
+  if (state->config.filename)
+  {
+     if (state->config.filename[0] == '-')
+     {
+        state->output_file = stdout;
+
+        // Ensure we don't upset the output stream with diagnostics/info
+        state->config.verbose = 0;
+     }
+     else
+     {
+        if (state->config.verbose)
+           fprintf(stderr, "Opening output file \"%s\"\n", state->config.filename);
+
+        state->output_file = fopen(state->config.filename, "wb");
+     }
+
+     if (!state->output_file)
+     {
+        // Notify user, carry on but discarding encoded output buffers
+        vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state->config.filename);
+     }
+  }
+
+  // Set up our userdata - this is passed though to the callback where we need the information.
+  state->callback_data.state = state;
+  state->callback_data.abort = 0;
+
+  state->encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state->callback_data;
+
+  if (state->config.verbose)
+     fprintf(stderr, "Enabling encoder output port\n");
+
+  // Enable the encoder output port and tell it its callback function
+  status = mmal_port_enable(state->encoder_output_port, encoder_buffer_callback);
+
+  if (status != MMAL_SUCCESS)
+  {
+     vcos_log_error("Failed to setup encoder output");
+     goto error;
+  }
+
+  if (state->config.demoMode)
+  {
+     // Run for the user specific time..
+     int num_iterations = state->config.timeout / state->config.demoInterval;
+     int i;
+
+     if (state->config.verbose)
+        fprintf(stderr, "Running in demo mode\n");
+
+     for (i=0;state->config.timeout == 0 || i<num_iterations;i++)
+     {
+        raspicamcontrol_cycle_test(state->camera_component);
+        vcos_sleep(state->config.demoInterval);
+     }
+  }
+  else
+  {
+     // Only encode stuff if we have a filename and it opened
+     if (state->output_file)
+     {
+        int wait;
+
+        if (state->config.verbose)
+           fprintf(stderr, "Starting video capture\n");
+
+        if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
+        {
+           goto error;
+        }
+
+        // Send all the buffers to the encoder output port
+        {
+           int num = mmal_queue_length(state->encoder_pool->queue);
+           int q;
+           for (q=0;q<num;q++)
+           {
+              MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoder_pool->queue);
+
+              if (!buffer)
+                 vcos_log_error("Unable to get a required buffer %d from pool queue", q);
+
+              if (mmal_port_send_buffer(state->encoder_output_port, buffer)!= MMAL_SUCCESS)
+                 vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
+
+           }
+        }
+
+        // Now wait until we need to stop. Whilst waiting we do need to check to see if we have aborted (for example
+        // out of storage space)
+        // Going to check every ABORT_INTERVAL milliseconds
+
+        for (wait = 0; state->config.timeout == 0 || wait < state->config.timeout; wait+= ABORT_INTERVAL)
+        {
+           vcos_sleep(ABORT_INTERVAL);
+           if (state->callback_data.abort)
+              break;
+        }
+
+        if (state->config.verbose)
+           fprintf(stderr, "Finished capture\n");
+     }
+     else
+     {
+        if (state->config.timeout)
+           vcos_sleep(state->config.timeout);
+        else
+           for (;;) vcos_sleep(ABORT_INTERVAL);
+     }
+  }
+
+  return state;
 
 error:
+  raspi_capture_stop(state);
 
-      mmal_status_to_int(status);
+  if (status != MMAL_SUCCESS) {
+    mmal_status_to_int(status);
+    raspicamcontrol_check_configuration(128);
+  }
 
-      if (state.verbose)
-         fprintf(stderr, "Closing down\n");
+  return NULL;
+}
 
-      // Disable all our ports that are not handled by connections
-      check_disable_port(camera_still_port);
-      check_disable_port(encoder_output_port);
+void
+raspi_capture_stop(RASPIVID_STATE *state)
+{
+  if (state->config.verbose)
+     fprintf(stderr, "Closing down\n");
 
-      if (state.preview_parameters.wantPreview )
-         mmal_connection_destroy(state.preview_connection);
-      mmal_connection_destroy(state.encoder_connection);
+  // Disable all our ports that are not handled by connections
+  check_disable_port(state->camera_still_port);
+  check_disable_port(state->encoder_output_port);
 
-      // Can now close our file. Note disabling ports may flush buffers which causes
-      // problems if we have already closed the file!
-      if (output_file && output_file != stdout)
-         fclose(output_file);
+  if (state->config.preview_parameters.wantPreview )
+     mmal_connection_destroy(state->preview_connection);
+  mmal_connection_destroy(state->encoder_connection);
 
-      /* Disable components */
-      if (state.encoder_component)
-         mmal_component_disable(state.encoder_component);
+  // Can now close our file. Note disabling ports may flush buffers which causes
+  // problems if we have already closed the file!
+  if (state->output_file && state->output_file != stdout)
+     fclose(state->output_file);
 
-      if (state.preview_parameters.preview_component)
-         mmal_component_disable(state.preview_parameters.preview_component);
+  /* Disable components */
+  if (state->encoder_component)
+     mmal_component_disable(state->encoder_component);
 
-      if (state.camera_component)
-         mmal_component_disable(state.camera_component);
+  if (state->config.preview_parameters.preview_component)
+     mmal_component_disable(state->config.preview_parameters.preview_component);
 
-      destroy_encoder_component(&state);
-      raspipreview_destroy(&state.preview_parameters);
-      destroy_camera_component(&state);
+  if (state->camera_component)
+     mmal_component_disable(state->camera_component);
 
-      if (state.verbose)
-         fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
-   }
+  destroy_encoder_component(state);
+  raspipreview_destroy(&state->config.preview_parameters);
+  destroy_camera_component(state);
 
-   if (status != MMAL_SUCCESS)
-      raspicamcontrol_check_configuration(128);
+  if (state->config.verbose)
+     fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
 
-   return exit_code;
+  free(state);
 }
index f24ab4b..554b898 100644 (file)
@@ -60,6 +60,9 @@ G_BEGIN_DECLS
  */
 typedef struct
 {
+   char *filename;
+   int verbose; /// !0 if want detailed run information
+   
    int timeout;                        /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
    int width;                          /// Requested width of image
    int height;                         /// requested height of image
@@ -73,9 +76,14 @@ typedef struct
    int profile;                        /// H264 profile to use for encoding
    RASPIPREVIEW_PARAMETERS preview_parameters;   /// Preview setup parameters
    RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters
-} RASPIVID_STATE;
+} RASPIVID_CONFIG;
 
-int raspi_capture_start();
+typedef struct RASPIVID_STATE_T RASPIVID_STATE;
+
+void raspicapture_init();
+void raspicapture_default_config(RASPIVID_CONFIG *config);
+RASPIVID_STATE *raspi_capture_start(RASPIVID_CONFIG *config);
+void raspi_capture_stop(RASPIVID_STATE *state);
 
 G_END_DECLS
 
index 62d0b25..32747b8 100644 (file)
@@ -290,7 +290,7 @@ static void dump_status(RASPISTILL_STATE *state)
    }
 
    raspipreview_dump_parameters(&state->preview_parameters);
-   raspicamcontrol_dump_parameters(&state->camera_parameters);
+   //raspicamcontrol_dump_parameters(&state->camera_parameters);
 }
 
 /**
index 94ee7a7..4ac7ebd 100644 (file)
@@ -109,7 +109,7 @@ static GstStaticPadTemplate video_src_template =
   GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (RAW_AND_JPEG_CAPS "; " H264_CAPS)
+    GST_STATIC_CAPS (/*RAW_AND_JPEG_CAPS "; "*/ H264_CAPS)
     );
 
 #define gst_rpi_cam_src_parent_class parent_class
@@ -120,6 +120,7 @@ static void gst_rpi_cam_src_set_property (GObject * object, guint prop_id,
 static void gst_rpi_cam_src_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 static gboolean gst_rpi_cam_src_start (GstBaseSrc *parent);
+static gboolean gst_rpi_cam_src_stop (GstBaseSrc *parent);
 static GstFlowReturn gst_rpi_cam_src_fill_buffer (GstPushSrc *parent, GstBuffer *buf);
 
 static void
@@ -148,7 +149,10 @@ gst_rpi_cam_src_class_init (GstRpiCamSrcClass * klass)
       gst_static_pad_template_get (&video_src_template));
 
   basesrc_class->start = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_start);
+  basesrc_class->stop = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_stop);
   pushsrc_class->fill = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_fill_buffer);
+
+  raspicapture_init();
 }
 
 static void
@@ -156,6 +160,11 @@ gst_rpi_cam_src_init (GstRpiCamSrc *src)
 {
   gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
   gst_base_src_set_live (GST_BASE_SRC (src), TRUE); 
+  raspicapture_default_config(&src->capture_config);
+
+  src->capture_config.verbose = 1;
+  src->capture_config.filename = "test.out";
+
 }
 
 static void
@@ -185,21 +194,18 @@ gst_rpi_cam_src_get_property (GObject * object, guint prop_id,
 }
 
 static gboolean
-rpicamsrc_init (GstPlugin * rpicamsrc)
+gst_rpi_cam_src_start (GstBaseSrc *parent)
 {
-  GST_DEBUG_CATEGORY_INIT (gst_rpi_cam_src_debug, "rpicamsrc",
-      0, "rpicamsrc debug");
-
-  return gst_element_register (rpicamsrc, "rpicamsrc", GST_RANK_NONE,
-      GST_TYPE_RPICAMSRC);
+  GstRpiCamSrc *src = GST_RPICAMSRC(parent);
+  src->capture_state = raspi_capture_start(&src->capture_config);
+  return TRUE;
 }
 
 static gboolean
-gst_rpi_cam_src_start (GstBaseSrc *parent)
+gst_rpi_cam_src_stop (GstBaseSrc *parent)
 {
   GstRpiCamSrc *src = GST_RPICAMSRC(parent);
-  g_print ("In start()\n");
-  raspi_capture_start();
+  raspi_capture_stop(src->capture_state);
   return TRUE;
 }
 
@@ -209,6 +215,16 @@ gst_rpi_cam_src_fill_buffer (GstPushSrc *parent, GstBuffer *buf)
   return GST_FLOW_ERROR;
 }
 
+static gboolean
+plugin_init (GstPlugin * rpicamsrc)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_rpi_cam_src_debug, "rpicamsrc",
+      0, "rpicamsrc debug");
+
+  return gst_element_register (rpicamsrc, "rpicamsrc", GST_RANK_NONE,
+      GST_TYPE_RPICAMSRC);
+}
+
 #ifndef PACKAGE
 #define PACKAGE "gstrpicamsrc"
 #endif
@@ -218,7 +234,7 @@ GST_PLUGIN_DEFINE (
     GST_VERSION_MINOR,
     rpicamsrc,
     "Raspberry Pi Camera Source",
-    rpicamsrc_init,
+    plugin_init,
     VERSION,
     "LGPL",
     "GStreamer",
index b8eb2e6..e321df4 100644 (file)
@@ -46,6 +46,7 @@
 
 #include <gst/gst.h>
 #include <gst/base/gstpushsrc.h>
+#include "RaspiCapture.h"
 
 G_BEGIN_DECLS
 
@@ -67,6 +68,9 @@ struct _GstRpiCamSrc
   GstPushSrc parent;
 
   GstPad *video_srcpad;
+
+  RASPIVID_CONFIG capture_config;
+  RASPIVID_STATE *capture_state;
 };
 
 struct _GstRpiCamSrcClass