Merge branch 'master' into 0.11

This commit is contained in:
Wim Taymans 2011-10-16 15:28:31 +02:00
commit 7f851794d6
9 changed files with 142 additions and 20 deletions

View file

@ -474,6 +474,9 @@ gst_base_camera_src_change_state (GstElement * element,
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_element_set_state (self->preview_pipeline->pipeline, GST_STATE_READY);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gst_element_set_state (self->preview_pipeline->pipeline, GST_STATE_NULL);
break;

View file

@ -638,6 +638,13 @@ gst_camerabin_video_create_elements (GstCameraBinVideo * vid)
G_CALLBACK (gst_camerabin_drop_eos_probe), vid);
gst_object_unref (vid_srcpad);
/* audio source is not always present and might be set to NULL during operation */
if (vid->aud_src
&& g_object_class_find_property (G_OBJECT_GET_CLASS (vid->aud_src),
"provide-clock")) {
g_object_set (vid->aud_src, "provide-clock", FALSE, NULL);
}
GST_DEBUG ("created video elements");
return TRUE;

View file

@ -1641,6 +1641,7 @@ static void
gst_camerabin_start_video_recording (GstCameraBin * camera)
{
GstStateChangeReturn state_ret;
GstCameraBinVideo *vidbin = (GstCameraBinVideo *) camera->vidbin;
/* FIXME: how to ensure resolution and fps is supported by CPU?
* use a queue overrun signal?
*/
@ -1654,9 +1655,14 @@ gst_camerabin_start_video_recording (GstCameraBin * camera)
gst_camerabin_rewrite_tags (camera);
/* Pause the pipeline in order to distribute new clock in paused_to_playing */
/* Audio source needs to go to null to reset the ringbuffer */
if (vidbin->aud_src)
gst_element_set_state (vidbin->aud_src, GST_STATE_NULL);
state_ret = gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED);
if (state_ret != GST_STATE_CHANGE_FAILURE) {
GstClock *clock = gst_element_get_clock (GST_ELEMENT (camera));
g_mutex_lock (camera->capture_mutex);
camera->capturing = TRUE;
g_mutex_unlock (camera->capture_mutex);
@ -1672,6 +1678,11 @@ gst_camerabin_start_video_recording (GstCameraBin * camera)
g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 2, NULL);
}
/* Clock might be distributed as NULL to audiosrc, messing timestamping */
if (vidbin->aud_src)
gst_element_set_clock (vidbin->aud_src, clock);
gst_object_unref (clock);
/* videobin will not go to playing if file is not writable */
if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {

View file

@ -406,8 +406,10 @@ gst_camera_bin_start_capture (GstCameraBin2 * camerabin)
}
/* store the next preview filename */
g_mutex_lock (camerabin->preview_list_mutex);
camerabin->preview_location_list =
g_slist_append (camerabin->preview_location_list, location);
g_mutex_unlock (camerabin->preview_list_mutex);
g_signal_emit_by_name (camerabin->src, "start-capture", NULL);
if (camerabin->mode == MODE_VIDEO && camerabin->audio_src)
@ -518,6 +520,7 @@ gst_camera_bin_dispose (GObject * object)
GstCameraBin2 *camerabin = GST_CAMERA_BIN2_CAST (object);
g_free (camerabin->location);
g_mutex_free (camerabin->preview_list_mutex);
if (camerabin->src_capture_notify_id)
g_signal_handler_disconnect (camerabin->src,
@ -873,6 +876,7 @@ gst_camera_bin_init (GstCameraBin2 * camera)
camera->zoom = DEFAULT_ZOOM;
camera->max_zoom = MAX_ZOOM;
camera->flags = DEFAULT_FLAGS;
camera->preview_list_mutex = g_mutex_new ();
/* capsfilters are created here as we proxy their caps properties and
* this way we avoid having to store the caps while on NULL state to
@ -945,20 +949,31 @@ gst_camera_bin_handle_message (GstBin * bin, GstMessage * message)
}
} else if (gst_structure_has_name (structure, "preview-image")) {
GValue *value;
gchar *location;
gchar *location = NULL;
location = camerabin->preview_location_list->data;
camerabin->preview_location_list =
g_slist_delete_link (camerabin->preview_location_list,
camerabin->preview_location_list);
GST_DEBUG_OBJECT (camerabin, "Adding preview location to preview "
"message '%s'", location);
g_mutex_lock (camerabin->preview_list_mutex);
if (camerabin->preview_location_list) {
location = camerabin->preview_location_list->data;
camerabin->preview_location_list =
g_slist_delete_link (camerabin->preview_location_list,
camerabin->preview_location_list);
GST_DEBUG_OBJECT (camerabin, "Adding preview location to preview "
"message '%s'", location);
} else {
GST_WARNING_OBJECT (camerabin, "Unexpected preview message received, "
"won't be able to put location field into the message. This can "
"happen if the source is posting previews while camerabin2 is "
"shutting down");
}
g_mutex_unlock (camerabin->preview_list_mutex);
value = g_new0 (GValue, 1);
g_value_init (value, G_TYPE_STRING);
g_value_take_string (value, location);
gst_structure_take_value ((GstStructure *) structure, "location",
value);
if (location) {
value = g_new0 (GValue, 1);
g_value_init (value, G_TYPE_STRING);
g_value_take_string (value, location);
gst_structure_take_value ((GstStructure *) structure, "location",
value);
}
}
}
break;
@ -1725,9 +1740,11 @@ gst_camera_bin_change_state (GstElement * element, GstStateChange trans)
g_slist_free (camera->image_location_list);
camera->image_location_list = NULL;
g_mutex_lock (camera->preview_list_mutex);
g_slist_foreach (camera->preview_location_list, (GFunc) g_free, NULL);
g_slist_free (camera->preview_location_list);
camera->preview_location_list = NULL;
g_mutex_unlock (camera->preview_list_mutex);
/* explicitly set to READY as they might be outside of the bin */
gst_element_set_state (camera->audio_volume, GST_STATE_READY);

View file

@ -94,8 +94,22 @@ struct _GstCameraBin2
* each buffer capture */
GSList *image_location_list;
/* similar to above, but used for giving names to previews */
/*
* Similar to above, but used for giving names to previews
*
* Need to protect with a mutex as this list is used when the
* camera-source posts a preview image. As we have no control
* on how the camera-source will behave (we can only tell how
* it should), the preview location list might be used in an
* inconsistent way.
* One example is the camera-source posting a preview image after
* camerabin2 was put to ready, when this preview list will be
* freed and set to NULL. Concurrent access might lead to crashes in
* this situation. (Concurrency from the state-change freeing the
* list and the message handling function looking at preview names)
*/
GSList *preview_location_list;
GMutex *preview_list_mutex;
gboolean video_profile_switch;
gboolean image_profile_switch;

View file

@ -45,7 +45,8 @@ enum
PROP_SOCKET_PATH,
PROP_PERMS,
PROP_SHM_SIZE,
PROP_WAIT_FOR_CONNECTION
PROP_WAIT_FOR_CONNECTION,
PROP_BUFFER_TIME
};
struct GstShmClient
@ -162,6 +163,13 @@ gst_shm_sink_class_init (GstShmSinkClass * klass)
DEFAULT_WAIT_FOR_CONNECTION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
g_param_spec_uint64 ("buffer-time",
"Buffer Time of the shm buffer",
"Maximum Size of the shm buffer in nanoseconds (-1 to disable)",
0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
signals[SIGNAL_CLIENT_CONNECTED] = g_signal_new ("client-connected",
GST_TYPE_SHM_SINK, G_SIGNAL_RUN_LAST, 0, NULL, NULL,
g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
@ -229,6 +237,12 @@ gst_shm_sink_set_property (GObject * object, guint prop_id,
GST_OBJECT_UNLOCK (object);
g_cond_broadcast (self->cond);
break;
case PROP_BUFFER_TIME:
GST_OBJECT_LOCK (object);
self->buffer_time = g_value_get_uint64 (value);
GST_OBJECT_UNLOCK (object);
g_cond_broadcast (self->cond);
break;
default:
break;
}
@ -263,6 +277,9 @@ gst_shm_sink_get_property (GObject * object, guint prop_id,
case PROP_WAIT_FOR_CONNECTION:
g_value_set_boolean (value, self->wait_for_connection);
break;
case PROP_BUFFER_TIME:
g_value_set_uint64 (value, self->buffer_time);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -358,6 +375,24 @@ gst_shm_sink_stop (GstBaseSink * bsink)
return TRUE;
}
static gboolean
gst_shm_sink_can_render (GstShmSink * self, GstClockTime time)
{
ShmBuffer *b;
if (time == GST_CLOCK_TIME_NONE || self->buffer_time == GST_CLOCK_TIME_NONE)
return TRUE;
b = sp_writer_get_pending_buffers (self->pipe);
for (; b != NULL; b = sp_writer_get_next_buffer (b)) {
GstClockTime t = sp_writer_buf_get_tag (b);
if (GST_CLOCK_DIFF (time, t) > self->buffer_time)
return FALSE;
}
return TRUE;
}
static GstFlowReturn
gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf)
{
@ -373,8 +408,16 @@ gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf)
}
}
while (!gst_shm_sink_can_render (self, GST_BUFFER_TIMESTAMP (buf))) {
g_cond_wait (self->cond, GST_OBJECT_GET_LOCK (self));
if (self->unlock) {
GST_OBJECT_UNLOCK (self);
return GST_FLOW_WRONG_STATE;
}
}
rv = sp_writer_send_buf (self->pipe, (char *) GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (buf));
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
if (rv == -1) {
ShmBlock *block = NULL;
@ -396,10 +439,10 @@ gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf)
}
}
shmbuf = sp_writer_block_get_buf (block);
memcpy (shmbuf, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
sp_writer_send_buf (self->pipe, shmbuf, GST_BUFFER_SIZE (buf));
sp_writer_send_buf (self->pipe, shmbuf, GST_BUFFER_SIZE (buf),
GST_BUFFER_TIMESTAMP (buf));
sp_writer_free_block (block);
}

View file

@ -61,6 +61,7 @@ struct _GstShmSink
gboolean wait_for_connection;
gboolean stop;
gboolean unlock;
GstClockTime buffer_time;
GCond *cond;
};

View file

@ -78,7 +78,6 @@ enum
};
typedef struct _ShmArea ShmArea;
typedef struct _ShmBuffer ShmBuffer;
struct _ShmArea
{
@ -112,6 +111,8 @@ struct _ShmBuffer
int num_clients;
int clients[0];
uint64_t tag;
};
@ -542,7 +543,7 @@ sp_writer_free_block (ShmBlock * block)
/* Returns the number of client this has successfully been sent to */
int
sp_writer_send_buf (ShmPipe * self, char *buf, size_t size)
sp_writer_send_buf (ShmPipe * self, char *buf, size_t size, uint64_t tag)
{
ShmArea *area = NULL;
unsigned long offset = 0;
@ -577,6 +578,7 @@ sp_writer_send_buf (ShmPipe * self, char *buf, size_t size)
sb->size = size;
sb->num_clients = self->num_clients;
sb->ablock = ablock;
sb->tag = tag;
for (client = self->clients; client; client = client->next) {
struct CommandBuffer cb = { 0 };
@ -892,3 +894,21 @@ sp_writer_get_path (ShmPipe * pipe)
{
return pipe->socket_path;
}
ShmBuffer *
sp_writer_get_pending_buffers (ShmPipe * self)
{
return self->buffers;
}
ShmBuffer *
sp_writer_get_next_buffer (ShmBuffer * buffer)
{
return buffer->next;
}
uint64_t
sp_writer_buf_get_tag (ShmBuffer * buffer)
{
return buffer->tag;
}

View file

@ -63,6 +63,7 @@
#define __SHMPIPE_H__
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@ -75,6 +76,7 @@ extern "C" {
typedef struct _ShmClient ShmClient;
typedef struct _ShmPipe ShmPipe;
typedef struct _ShmBlock ShmBlock;
typedef struct _ShmBuffer ShmBuffer;
ShmPipe *sp_writer_create (const char *path, size_t size, mode_t perms);
const char *sp_writer_get_path (ShmPipe *pipe);
@ -90,7 +92,7 @@ int sp_writer_get_client_fd (ShmClient * client);
ShmBlock *sp_writer_alloc_block (ShmPipe * self, size_t size);
void sp_writer_free_block (ShmBlock *block);
int sp_writer_send_buf (ShmPipe * self, char *buf, size_t size);
int sp_writer_send_buf (ShmPipe * self, char *buf, size_t size, uint64_t tag);
char *sp_writer_block_get_buf (ShmBlock *block);
ShmPipe *sp_writer_block_get_pipe (ShmBlock *block);
@ -104,6 +106,10 @@ ShmPipe *sp_client_open (const char *path);
long int sp_client_recv (ShmPipe * self, char **buf);
int sp_client_recv_finish (ShmPipe * self, char *buf);
ShmBuffer *sp_writer_get_pending_buffers (ShmPipe * self);
ShmBuffer *sp_writer_get_next_buffer (ShmBuffer * buffer);
uint64_t sp_writer_buf_get_tag (ShmBuffer * buffer);
#ifdef __cplusplus
}
#endif