diff --git a/sys/rpicamsrc/RaspiCapture.c b/sys/rpicamsrc/RaspiCapture.c index 348a5c8355..e9db8dcf5c 100644 --- a/sys/rpicamsrc/RaspiCapture.c +++ b/sys/rpicamsrc/RaspiCapture.c @@ -57,6 +57,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include "bcm_host.h" #include "interface/vcos/vcos.h" @@ -124,6 +125,8 @@ struct RASPIVID_STATE_T MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port PORT_USERDATA callback_data; + + MMAL_QUEUE_T *encoded_buffer_q; }; #if 0 @@ -499,57 +502,62 @@ static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf */ static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { - MMAL_BUFFER_HEADER_T *new_buffer; - - // 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(state->output_file); - - if (buffer->length) - { - mmal_buffer_header_mem_lock(buffer); - - bytes_written = fwrite(buffer->data, 1, buffer->length, state->output_file); - - mmal_buffer_header_mem_unlock(buffer); - } - - if (bytes_written != buffer->length) - { - vcos_log_error("Failed to write buffer data (%d from %d)- aborting", bytes_written, buffer->length); - pData->abort = 1; - } - } - else + if (pData == NULL) { vcos_log_error("Received a encoder buffer callback with no state"); + // release buffer back to the pool + mmal_buffer_header_release(buffer); + return; } - // release buffer back to the pool - mmal_buffer_header_release(buffer); - - // and send one back to the port (if still open) - if (port->is_enabled) - { - MMAL_STATUS_T status = MMAL_SUCCESS; - - new_buffer = mmal_queue_get(state->encoder_pool->queue); - - if (new_buffer) - status = mmal_port_send_buffer(port, new_buffer); - - if (!new_buffer || status != MMAL_SUCCESS) - vcos_log_error("Unable to return a buffer to the encoder port"); - } + /* Send buffer to GStreamer element for pushing to the pipeline */ + mmal_queue_put(state->encoded_buffer_q, buffer); } +GstFlowReturn +raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp) +{ + GstBuffer *buf; + MMAL_BUFFER_HEADER_T *buffer; + GstFlowReturn ret = GST_FLOW_ERROR; + + /* FIXME: Use our own interruptible cond wait: */ + buffer = mmal_queue_wait(state->encoded_buffer_q); + + mmal_buffer_header_mem_lock(buffer); + buf = gst_buffer_new_allocate(NULL, buffer->length, NULL); + if (buf) { + gst_buffer_fill(buf, 0, buffer->data, buffer->length); + g_print("Buffer of size %u\n", (guint) buffer->length); + ret = GST_FLOW_OK; + } + + mmal_buffer_header_mem_unlock(buffer); + + *bufp = buf; + // release buffer back to the pool + mmal_buffer_header_release(buffer); + + // and send one back to the port (if still open) + if (state->encoder_output_port->is_enabled) + { + MMAL_STATUS_T status = MMAL_SUCCESS; + + buffer = mmal_queue_get(state->encoder_pool->queue); + if (buffer) + status = mmal_port_send_buffer(state->encoder_output_port, buffer); + + if (!buffer || status != MMAL_SUCCESS) { + vcos_log_error("Unable to return a buffer to the encoder port"); + ret = GST_FLOW_ERROR; + } + } + + return ret; +} /** * Create the camera component, set up its ports @@ -785,6 +793,8 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state) if (encoder_output->buffer_size < encoder_output->buffer_size_min) encoder_output->buffer_size = encoder_output->buffer_size_min; + g_print("encoder buffer size is %u\n", (guint)encoder_output->buffer_size); + encoder_output->buffer_num = encoder_output->buffer_num_recommended; if (encoder_output->buffer_num < encoder_output->buffer_num_min) @@ -859,7 +869,6 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state) /* Create pool of buffer headers for the output port to consume */ pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size); - if (!pool) { vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name); @@ -888,6 +897,11 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state) */ static void destroy_encoder_component(RASPIVID_STATE *state) { + /* Empty the buffer header q */ + while (mmal_queue_length(state->encoded_buffer_q)) + (void)(mmal_queue_get(state->encoded_buffer_q)); + mmal_queue_destroy(state->encoded_buffer_q); + // Get rid of any port buffers first if (state->encoder_pool) { @@ -1004,6 +1018,8 @@ raspi_capture_start(RASPIVID_CONFIG *config) state->camera_still_port = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; state->encoder_output_port = state->encoder_component->output[0]; + state->encoded_buffer_q = mmal_queue_create(); + if (state->config.preview_parameters.wantPreview ) { if (state->config.verbose) @@ -1096,7 +1112,7 @@ raspi_capture_start(RASPIVID_CONFIG *config) // Only encode stuff if we have a filename and it opened if (state->output_file) { - int wait; + //int wait; if (state->config.verbose) fprintf(stderr, "Starting video capture\n"); @@ -1127,6 +1143,7 @@ raspi_capture_start(RASPIVID_CONFIG *config) // out of storage space) // Going to check every ABORT_INTERVAL milliseconds +#if 0 for (wait = 0; state->config.timeout == 0 || wait < state->config.timeout; wait+= ABORT_INTERVAL) { vcos_sleep(ABORT_INTERVAL); @@ -1136,13 +1153,16 @@ raspi_capture_start(RASPIVID_CONFIG *config) if (state->config.verbose) fprintf(stderr, "Finished capture\n"); +#endif } else { +#if 0 if (state->config.timeout) vcos_sleep(state->config.timeout); else for (;;) vcos_sleep(ABORT_INTERVAL); +#endif } } diff --git a/sys/rpicamsrc/RaspiCapture.h b/sys/rpicamsrc/RaspiCapture.h index 554b898f65..4069ab3eb2 100644 --- a/sys/rpicamsrc/RaspiCapture.h +++ b/sys/rpicamsrc/RaspiCapture.h @@ -83,6 +83,7 @@ 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); +GstFlowReturn raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **buf); void raspi_capture_stop(RASPIVID_STATE *state); G_END_DECLS diff --git a/sys/rpicamsrc/gstrpicamsrc.c b/sys/rpicamsrc/gstrpicamsrc.c index 4ac7ebd7d6..b9753f3e40 100644 --- a/sys/rpicamsrc/gstrpicamsrc.c +++ b/sys/rpicamsrc/gstrpicamsrc.c @@ -121,7 +121,11 @@ 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 gboolean gst_rpi_cam_src_decide_allocation (GstBaseSrc * src, + GstQuery * query); +static GstFlowReturn gst_rpi_cam_src_create (GstPushSrc *parent, GstBuffer **buf); +static GstCaps *gst_rpi_cam_src_get_caps (GstBaseSrc * src, GstCaps * filter); +static GstCaps *gst_rpi_cam_src_fixate (GstBaseSrc * basesrc, GstCaps * caps); static void gst_rpi_cam_src_class_init (GstRpiCamSrcClass * klass) @@ -150,7 +154,10 @@ gst_rpi_cam_src_class_init (GstRpiCamSrcClass * klass) 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); + basesrc_class->decide_allocation = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_decide_allocation); + basesrc_class->get_caps = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_get_caps); + basesrc_class->fixate = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_fixate); + pushsrc_class->create = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_create); raspicapture_init(); } @@ -197,6 +204,7 @@ static gboolean gst_rpi_cam_src_start (GstBaseSrc *parent) { GstRpiCamSrc *src = GST_RPICAMSRC(parent); + g_print ("In src_start()\n"); src->capture_state = raspi_capture_start(&src->capture_config); return TRUE; } @@ -209,10 +217,61 @@ gst_rpi_cam_src_stop (GstBaseSrc *parent) return TRUE; } -static GstFlowReturn -gst_rpi_cam_src_fill_buffer (GstPushSrc *parent, GstBuffer *buf) +static GstCaps * +gst_rpi_cam_src_get_caps (GstBaseSrc * src, GstCaps * filter) { - return GST_FLOW_ERROR; + g_print ("In get_caps\n"); + //if (src->state == NULL) + return gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (src)); + /* Retrieve limiting parameters from the camera module, max width/height fps-range */ +} + +static gboolean gst_rpi_cam_src_decide_allocation (GstBaseSrc *bsrc, + GstQuery * query) +{ + g_print ("In decide_allocation\n"); + return GST_BASE_SRC_CLASS (parent_class)->decide_allocation (bsrc, query); +} + +static GstCaps *gst_rpi_cam_src_fixate (GstBaseSrc * basesrc, GstCaps * caps) +{ + GstStructure *structure; + gint i; + + GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps); + + caps = gst_caps_make_writable (caps); + + for (i = 0; i < gst_caps_get_size (caps); ++i) { + structure = gst_caps_get_structure (caps, i); + + /* Fixate to the camera's 1920x1080 resolution if possible */ + gst_structure_fixate_field_nearest_int (structure, "width", 1920); + gst_structure_fixate_field_nearest_int (structure, "height", 1080); + gst_structure_fixate_field_nearest_fraction (structure, "framerate", + G_MAXINT, 1); + gst_structure_fixate_field (structure, "format"); + } + + GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, caps); + + caps = GST_BASE_SRC_CLASS (parent_class)->fixate (basesrc, caps); + + return caps; +} + +static GstFlowReturn +gst_rpi_cam_src_create (GstPushSrc *parent, GstBuffer **buf) +{ + GstRpiCamSrc *src = GST_RPICAMSRC(parent); + GstFlowReturn ret; + + /* FIXME: Use custom allocator */ + ret = raspi_capture_fill_buffer(src->capture_state, buf); + if (*buf) + g_print ("Made buffer of size %" G_GSIZE_FORMAT "\n", gst_buffer_get_size(*buf)); + + return ret; } static gboolean