mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
rpicamsrc: First version which generates buffers on the src pad
Fixed to 1920x1080 h264 regardless of caps.
This commit is contained in:
parent
7ffb618b20
commit
1416631df9
3 changed files with 129 additions and 49 deletions
|
@ -57,6 +57,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#include <sysexits.h>
|
#include <sysexits.h>
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
#include "bcm_host.h"
|
#include "bcm_host.h"
|
||||||
#include "interface/vcos/vcos.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
|
MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port
|
||||||
|
|
||||||
PORT_USERDATA callback_data;
|
PORT_USERDATA callback_data;
|
||||||
|
|
||||||
|
MMAL_QUEUE_T *encoded_buffer_q;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
#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)
|
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;
|
PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
|
||||||
RASPIVID_STATE *state = pData->state;
|
RASPIVID_STATE *state = pData->state;
|
||||||
|
|
||||||
if (pData)
|
if (pData == NULL)
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
vcos_log_error("Received a encoder buffer callback with no state");
|
vcos_log_error("Received a encoder buffer callback with no state");
|
||||||
|
// release buffer back to the pool
|
||||||
|
mmal_buffer_header_release(buffer);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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
|
// release buffer back to the pool
|
||||||
mmal_buffer_header_release(buffer);
|
mmal_buffer_header_release(buffer);
|
||||||
|
|
||||||
// and send one back to the port (if still open)
|
// and send one back to the port (if still open)
|
||||||
if (port->is_enabled)
|
if (state->encoder_output_port->is_enabled)
|
||||||
{
|
{
|
||||||
MMAL_STATUS_T status = MMAL_SUCCESS;
|
MMAL_STATUS_T status = MMAL_SUCCESS;
|
||||||
|
|
||||||
new_buffer = mmal_queue_get(state->encoder_pool->queue);
|
buffer = mmal_queue_get(state->encoder_pool->queue);
|
||||||
|
if (buffer)
|
||||||
|
status = mmal_port_send_buffer(state->encoder_output_port, buffer);
|
||||||
|
|
||||||
if (new_buffer)
|
if (!buffer || status != MMAL_SUCCESS) {
|
||||||
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");
|
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
|
* 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)
|
if (encoder_output->buffer_size < encoder_output->buffer_size_min)
|
||||||
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;
|
encoder_output->buffer_num = encoder_output->buffer_num_recommended;
|
||||||
|
|
||||||
if (encoder_output->buffer_num < encoder_output->buffer_num_min)
|
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 */
|
/* 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);
|
pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size);
|
||||||
|
|
||||||
if (!pool)
|
if (!pool)
|
||||||
{
|
{
|
||||||
vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name);
|
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)
|
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
|
// Get rid of any port buffers first
|
||||||
if (state->encoder_pool)
|
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->camera_still_port = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
|
||||||
state->encoder_output_port = state->encoder_component->output[0];
|
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.preview_parameters.wantPreview )
|
||||||
{
|
{
|
||||||
if (state->config.verbose)
|
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
|
// Only encode stuff if we have a filename and it opened
|
||||||
if (state->output_file)
|
if (state->output_file)
|
||||||
{
|
{
|
||||||
int wait;
|
//int wait;
|
||||||
|
|
||||||
if (state->config.verbose)
|
if (state->config.verbose)
|
||||||
fprintf(stderr, "Starting video capture\n");
|
fprintf(stderr, "Starting video capture\n");
|
||||||
|
@ -1127,6 +1143,7 @@ raspi_capture_start(RASPIVID_CONFIG *config)
|
||||||
// out of storage space)
|
// out of storage space)
|
||||||
// Going to check every ABORT_INTERVAL milliseconds
|
// Going to check every ABORT_INTERVAL milliseconds
|
||||||
|
|
||||||
|
#if 0
|
||||||
for (wait = 0; state->config.timeout == 0 || wait < state->config.timeout; wait+= ABORT_INTERVAL)
|
for (wait = 0; state->config.timeout == 0 || wait < state->config.timeout; wait+= ABORT_INTERVAL)
|
||||||
{
|
{
|
||||||
vcos_sleep(ABORT_INTERVAL);
|
vcos_sleep(ABORT_INTERVAL);
|
||||||
|
@ -1136,13 +1153,16 @@ raspi_capture_start(RASPIVID_CONFIG *config)
|
||||||
|
|
||||||
if (state->config.verbose)
|
if (state->config.verbose)
|
||||||
fprintf(stderr, "Finished capture\n");
|
fprintf(stderr, "Finished capture\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
if (state->config.timeout)
|
if (state->config.timeout)
|
||||||
vcos_sleep(state->config.timeout);
|
vcos_sleep(state->config.timeout);
|
||||||
else
|
else
|
||||||
for (;;) vcos_sleep(ABORT_INTERVAL);
|
for (;;) vcos_sleep(ABORT_INTERVAL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,7 @@ typedef struct RASPIVID_STATE_T RASPIVID_STATE;
|
||||||
void raspicapture_init();
|
void raspicapture_init();
|
||||||
void raspicapture_default_config(RASPIVID_CONFIG *config);
|
void raspicapture_default_config(RASPIVID_CONFIG *config);
|
||||||
RASPIVID_STATE *raspi_capture_start(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);
|
void raspi_capture_stop(RASPIVID_STATE *state);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
@ -121,7 +121,11 @@ static void gst_rpi_cam_src_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
static gboolean gst_rpi_cam_src_start (GstBaseSrc *parent);
|
static gboolean gst_rpi_cam_src_start (GstBaseSrc *parent);
|
||||||
static gboolean gst_rpi_cam_src_stop (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
|
static void
|
||||||
gst_rpi_cam_src_class_init (GstRpiCamSrcClass * klass)
|
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->start = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_start);
|
||||||
basesrc_class->stop = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_stop);
|
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();
|
raspicapture_init();
|
||||||
}
|
}
|
||||||
|
@ -197,6 +204,7 @@ static gboolean
|
||||||
gst_rpi_cam_src_start (GstBaseSrc *parent)
|
gst_rpi_cam_src_start (GstBaseSrc *parent)
|
||||||
{
|
{
|
||||||
GstRpiCamSrc *src = GST_RPICAMSRC(parent);
|
GstRpiCamSrc *src = GST_RPICAMSRC(parent);
|
||||||
|
g_print ("In src_start()\n");
|
||||||
src->capture_state = raspi_capture_start(&src->capture_config);
|
src->capture_state = raspi_capture_start(&src->capture_config);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -209,10 +217,61 @@ gst_rpi_cam_src_stop (GstBaseSrc *parent)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstCaps *
|
||||||
gst_rpi_cam_src_fill_buffer (GstPushSrc *parent, GstBuffer *buf)
|
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
|
static gboolean
|
||||||
|
|
Loading…
Reference in a new issue