2 * Copyright (C) <2009> Collabora Ltd
3 * @author: Olivier Crete <olivier.crete@collabora.co.uk
4 * Copyright (C) <2009> Nokia Inc
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 * SECTION:element-shmsrc
24 * Receive data from the shared memory sink.
27 * <title>Example launch lines</title>
29 * gst-launch shmsrc socket-path=/tmp/blah ! \
30 * "video/x-raw-yuv, format=(fourcc)YUY2, color-matrix=(string)sdtv, \
31 * chroma-site=(string)mpeg2, width=(int)320, height=(int)240, framerate=(fraction)30/1" ! autovideosink
32 * ]| Render video from shm buffers.
40 #include "gstshmsrc.h"
46 #ifdef GST_TBM_SUPPORT
62 #ifdef GST_TBM_SUPPORT
74 GST_DEBUG_CATEGORY_STATIC (shmsrc_debug);
75 #define GST_CAT_DEFAULT shmsrc_debug
77 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
82 #define gst_shm_src_parent_class parent_class
83 G_DEFINE_TYPE (GstShmSrc, gst_shm_src, GST_TYPE_PUSH_SRC);
85 static void gst_shm_src_set_property (GObject * object, guint prop_id,
86 const GValue * value, GParamSpec * pspec);
87 static void gst_shm_src_get_property (GObject * object, guint prop_id,
88 GValue * value, GParamSpec * pspec);
89 static void gst_shm_src_finalize (GObject * object);
90 static gboolean gst_shm_src_start (GstBaseSrc * bsrc);
91 static gboolean gst_shm_src_stop (GstBaseSrc * bsrc);
92 static GstFlowReturn gst_shm_src_create (GstPushSrc * psrc,
94 static gboolean gst_shm_src_unlock (GstBaseSrc * bsrc);
95 static gboolean gst_shm_src_unlock_stop (GstBaseSrc * bsrc);
96 static GstStateChangeReturn gst_shm_src_change_state (GstElement * element,
97 GstStateChange transition);
99 static void gst_shm_pipe_inc (GstShmPipe * pipe);
100 static void gst_shm_pipe_dec (GstShmPipe * pipe);
102 // static guint gst_shm_src_signals[LAST_SIGNAL] = { 0 };
105 gst_shm_src_class_init (GstShmSrcClass * klass)
107 GObjectClass *gobject_class;
108 GstElementClass *gstelement_class;
109 GstBaseSrcClass *gstbasesrc_class;
110 GstPushSrcClass *gstpush_src_class;
112 gobject_class = (GObjectClass *) klass;
113 gstelement_class = (GstElementClass *) klass;
114 gstbasesrc_class = (GstBaseSrcClass *) klass;
115 gstpush_src_class = (GstPushSrcClass *) klass;
117 gobject_class->set_property = gst_shm_src_set_property;
118 gobject_class->get_property = gst_shm_src_get_property;
119 gobject_class->finalize = gst_shm_src_finalize;
121 gstelement_class->change_state = gst_shm_src_change_state;
123 gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_shm_src_start);
124 gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_shm_src_stop);
125 gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_shm_src_unlock);
126 gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_shm_src_unlock_stop);
128 gstpush_src_class->create = gst_shm_src_create;
130 g_object_class_install_property (gobject_class, PROP_SOCKET_PATH,
131 g_param_spec_string ("socket-path",
132 "Path to the control socket",
133 "The path to the control socket used to control the shared memory",
134 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
136 g_object_class_install_property (gobject_class, PROP_IS_LIVE,
137 g_param_spec_boolean ("is-live", "Is this a live source",
138 "True if the element cannot produce data in PAUSED", FALSE,
139 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
141 g_object_class_install_property (gobject_class, PROP_SHM_AREA_NAME,
142 g_param_spec_string ("shm-area-name",
143 "Name of the shared memory area",
144 "The name of the shared memory area used to get buffers",
145 NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
146 #ifdef GST_TBM_SUPPORT
147 g_object_class_install_property (gobject_class, PROP_USE_TBM,
148 g_param_spec_boolean ("use-tbm",
149 "Use of not the tizen buffer",
150 "Flags of using tizen buffer",
152 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
155 gst_element_class_add_pad_template (gstelement_class,
156 gst_static_pad_template_get (&srctemplate));
158 gst_element_class_set_static_metadata (gstelement_class,
159 "Shared Memory Source",
161 "Receive data from the shared memory sink",
162 "Olivier Crete <olivier.crete@collabora.co.uk>");
164 GST_DEBUG_CATEGORY_INIT (shmsrc_debug, "shmsrc", 0, "Shared Memory Source");
168 gst_shm_src_init (GstShmSrc * self)
170 self->poll = gst_poll_new (TRUE);
171 gst_poll_fd_init (&self->pollfd);
172 self->h_bufmgr = tbm_bufmgr_init(-1);
176 gst_shm_src_finalize (GObject * object)
178 GstShmSrc *self = GST_SHM_SRC (object);
180 gst_poll_free (self->poll);
181 g_free (self->socket_path);
182 tbm_bufmgr_deinit(self->h_bufmgr);
184 G_OBJECT_CLASS (parent_class)->finalize (object);
189 gst_shm_src_set_property (GObject * object, guint prop_id,
190 const GValue * value, GParamSpec * pspec)
192 GstShmSrc *self = GST_SHM_SRC (object);
195 case PROP_SOCKET_PATH:
196 GST_OBJECT_LOCK (object);
198 GST_WARNING_OBJECT (object, "Can not modify socket path while the "
199 "element is playing");
201 g_free (self->socket_path);
202 self->socket_path = g_value_dup_string (value);
204 GST_OBJECT_UNLOCK (object);
207 gst_base_src_set_live (GST_BASE_SRC (object),
208 g_value_get_boolean (value));
210 #ifdef GST_TBM_SUPPORT
212 GST_OBJECT_LOCK (object);
213 self->use_tbm = g_value_get_boolean (value);
214 GST_OBJECT_UNLOCK (object);
218 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
224 gst_shm_src_get_property (GObject * object, guint prop_id,
225 GValue * value, GParamSpec * pspec)
227 GstShmSrc *self = GST_SHM_SRC (object);
230 case PROP_SOCKET_PATH:
231 GST_OBJECT_LOCK (object);
232 g_value_set_string (value, self->socket_path);
233 GST_OBJECT_UNLOCK (object);
236 g_value_set_boolean (value, gst_base_src_is_live (GST_BASE_SRC (object)));
238 case PROP_SHM_AREA_NAME:
239 GST_OBJECT_LOCK (object);
241 g_value_set_string (value, sp_get_shm_area_name (self->pipe->pipe));
242 GST_OBJECT_UNLOCK (object);
244 #ifdef GST_TBM_SUPPORT
246 g_value_set_boolean (value, self->use_tbm);
250 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
256 gst_shm_src_start_reading (GstShmSrc * self)
260 if (!self->socket_path) {
261 GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
262 ("No path specified for socket."), (NULL));
266 gstpipe = g_slice_new0 (GstShmPipe);
267 gstpipe->use_count = 1;
268 gstpipe->src = gst_object_ref (self);
270 GST_DEBUG_OBJECT (self, "Opening socket %s", self->socket_path);
272 GST_OBJECT_LOCK (self);
273 gstpipe->pipe = sp_client_open (self->socket_path);
274 GST_OBJECT_UNLOCK (self);
276 if (!gstpipe->pipe) {
277 GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ_WRITE,
278 ("Could not open socket %s: %d %s", self->socket_path, errno,
279 strerror (errno)), (NULL));
280 gst_shm_pipe_dec (gstpipe);
284 self->pipe = gstpipe;
286 gst_poll_set_flushing (self->poll, FALSE);
288 gst_poll_fd_init (&self->pollfd);
289 self->pollfd.fd = sp_get_fd (self->pipe->pipe);
290 gst_poll_add_fd (self->poll, &self->pollfd);
291 gst_poll_fd_ctl_read (self->poll, &self->pollfd, TRUE);
297 gst_shm_src_stop_reading (GstShmSrc * self)
299 GST_DEBUG_OBJECT (self, "Stopping %p", self);
302 gst_shm_pipe_dec (self->pipe);
306 gst_poll_remove_fd (self->poll, &self->pollfd);
307 gst_poll_fd_init (&self->pollfd);
309 gst_poll_set_flushing (self->poll, TRUE);
313 gst_shm_src_start (GstBaseSrc * bsrc)
315 if (gst_base_src_is_live (bsrc))
318 return gst_shm_src_start_reading (GST_SHM_SRC (bsrc));
322 gst_shm_src_stop (GstBaseSrc * bsrc)
324 if (!gst_base_src_is_live (bsrc))
325 gst_shm_src_stop_reading (GST_SHM_SRC (bsrc));
332 free_buffer (gpointer data)
334 struct GstShmBuffer *gsb = data;
335 g_return_if_fail (gsb->pipe != NULL);
336 g_return_if_fail (gsb->pipe->src != NULL);
338 GST_LOG ("Freeing buffer %p", gsb->buf);
340 GST_OBJECT_LOCK (gsb->pipe->src);
341 sp_client_recv_finish (gsb->pipe->pipe, gsb->buf);
342 GST_OBJECT_UNLOCK (gsb->pipe->src);
344 gst_shm_pipe_dec (gsb->pipe);
346 g_slice_free (struct GstShmBuffer, gsb);
349 #ifdef GST_TBM_SUPPORT
351 free_tbm_buffer (gpointer data)
353 MMVideoBuffer * mm_video_buf = data;
355 GST_LOG ("Freeing tbm buffer %p", data);
357 for(i = 0; i < MM_VIDEO_BUFFER_PLANE_MAX; i++) {
358 if(mm_video_buf->handle.bo[i])
359 tbm_bo_unref(mm_video_buf->handle.bo[i]);
364 g_free(mm_video_buf);
369 gst_shm_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
371 GstShmSrc *self = GST_SHM_SRC (psrc);
374 struct GstShmBuffer *gsb;
377 if (gst_poll_wait (self->poll, GST_CLOCK_TIME_NONE) < 0) {
379 return GST_FLOW_FLUSHING;
380 GST_ELEMENT_ERROR (self, RESOURCE, READ, ("Failed to read from shmsrc"),
381 ("Poll failed on fd: %s", strerror (errno)));
382 return GST_FLOW_ERROR;
386 return GST_FLOW_FLUSHING;
388 if (gst_poll_fd_has_closed (self->poll, &self->pollfd)) {
389 GST_ELEMENT_ERROR (self, RESOURCE, READ, ("Failed to read from shmsrc"),
390 ("Control socket has closed"));
391 return GST_FLOW_ERROR;
394 if (gst_poll_fd_has_error (self->poll, &self->pollfd)) {
395 GST_ELEMENT_ERROR (self, RESOURCE, READ, ("Failed to read from shmsrc"),
396 ("Control socket has error"));
397 return GST_FLOW_ERROR;
400 if (gst_poll_fd_can_read (self->poll, &self->pollfd)) {
402 GST_LOG_OBJECT (self, "Reading from pipe");
403 GST_OBJECT_LOCK (self);
404 rv = sp_client_recv (self->pipe->pipe, &buf);
405 GST_OBJECT_UNLOCK (self);
407 GST_ELEMENT_ERROR (self, RESOURCE, READ, ("Failed to read from shmsrc"),
408 ("Error reading control data: %d", rv));
409 return GST_FLOW_ERROR;
412 } while (buf == NULL);
414 GST_LOG_OBJECT (self, "Got buffer %p of size %d", buf, rv);
416 gsb = g_slice_new0 (struct GstShmBuffer);
418 gsb->pipe = self->pipe;
419 gst_shm_pipe_inc (self->pipe);
421 *outbuf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
422 buf, rv, 0, rv, gsb, free_buffer);
423 #ifdef GST_TBM_SUPPORT
424 GST_DEBUG_OBJECT(self, "use-tbm %d", self->use_tbm);
426 MMVideoBuffer *mm_video_buf = NULL;
427 GstMemory *mem_imgb = NULL;
428 unsigned key[MM_VIDEO_BUFFER_PLANE_MAX];
429 int offset = *(buf + rv - sizeof(int));
431 GST_ERROR_OBJECT(self, "offset error %d", offset);
432 return GST_FLOW_ERROR;
435 GST_LOG_OBJECT(self, "mm_buf offset %d", offset);
437 mm_video_buf = g_malloc0(sizeof(MMVideoBuffer));
438 mem_imgb = gst_memory_new_wrapped(0, mm_video_buf, sizeof(MMVideoBuffer), 0,
439 sizeof(MMVideoBuffer), mm_video_buf, free_tbm_buffer);
440 gst_buffer_append_memory(*outbuf, mem_imgb);
442 memcpy(mm_video_buf, buf + offset, sizeof(MMVideoBuffer));
443 memcpy(key, buf + rv - (sizeof(key) + sizeof(int)), sizeof(key));
444 if (mm_video_buf->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
446 GST_DEBUG_OBJECT(self, "width %d, height %d", mm_video_buf->width[0],
447 mm_video_buf->height[0]);
449 memset(mm_video_buf->handle.bo, 0, sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
450 for(i = 0; i < MM_VIDEO_BUFFER_PLANE_MAX; i++) {
451 GST_DEBUG_OBJECT(self, "%d tbm bo key %d", i, key[i]);
453 mm_video_buf->handle.bo[i] = tbm_bo_import(self->h_bufmgr, key[i]);
457 GST_DEBUG_OBJECT (self, "TBM bo %p %p", mm_video_buf->handle.bo[0],
458 mm_video_buf->handle.bo[1]);
460 GST_WARNING_OBJECT(self, "invaild type %d", mm_video_buf->type);
461 return GST_FLOW_ERROR;
469 static GstStateChangeReturn
470 gst_shm_src_change_state (GstElement * element, GstStateChange transition)
472 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
473 GstShmSrc *self = GST_SHM_SRC (element);
475 switch (transition) {
476 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
477 if (gst_base_src_is_live (GST_BASE_SRC (element)))
478 if (!gst_shm_src_start_reading (self))
479 return GST_STATE_CHANGE_FAILURE;
484 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
485 if (ret == GST_STATE_CHANGE_FAILURE)
488 switch (transition) {
489 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
490 if (gst_base_src_is_live (GST_BASE_SRC (element)))
491 gst_shm_src_stop_reading (self);
500 gst_shm_src_unlock (GstBaseSrc * bsrc)
502 GstShmSrc *self = GST_SHM_SRC (bsrc);
504 self->unlocked = TRUE;
505 gst_poll_set_flushing (self->poll, TRUE);
511 gst_shm_src_unlock_stop (GstBaseSrc * bsrc)
513 GstShmSrc *self = GST_SHM_SRC (bsrc);
515 self->unlocked = FALSE;
516 gst_poll_set_flushing (self->poll, FALSE);
522 gst_shm_pipe_inc (GstShmPipe * pipe)
524 g_return_if_fail (pipe);
525 g_return_if_fail (pipe->src);
526 g_return_if_fail (pipe->use_count > 0);
528 GST_OBJECT_LOCK (pipe->src);
530 GST_OBJECT_UNLOCK (pipe->src);
534 gst_shm_pipe_dec (GstShmPipe * pipe)
536 g_return_if_fail (pipe);
537 g_return_if_fail (pipe->src);
538 g_return_if_fail (pipe->use_count > 0);
540 GST_OBJECT_LOCK (pipe->src);
543 if (pipe->use_count > 0) {
544 GST_OBJECT_UNLOCK (pipe->src);
549 sp_client_close (pipe->pipe);
550 GST_OBJECT_UNLOCK (pipe->src);
552 gst_object_unref (pipe->src);
553 g_slice_free (GstShmPipe, pipe);