mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 04:45:36 +00:00
Merge branch 'master' into 0.11
This commit is contained in:
commit
7f851794d6
9 changed files with 142 additions and 20 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ struct _GstShmSink
|
|||
gboolean wait_for_connection;
|
||||
gboolean stop;
|
||||
gboolean unlock;
|
||||
GstClockTime buffer_time;
|
||||
|
||||
GCond *cond;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue