4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hyunil Park <hyunil46.park@samsung.com>
8 * This library is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by the
10 * Free Software Foundation; either version 2.1 of the License, or (at your option)
13 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
14 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 * License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software Foundation, Inc., 51
20 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * SECTION:element-xvimagesrc
26 * xvimagesrc captures frame buffer which includes the application data along with video layer data
27 * from the XServer and pushes the data to the downstream element.
31 * <title>Example launch line</title>
33 * gst-launch xvimagesrc ! "video/x-raw-yuv, width=720, height=1280, framerate=(fraction)30/1, format=(fourcc)ST12" ! fakesink
34 * ]| captures the frame buffer from the XServer and send the buffers to a fakesink.
42 #include "gstxvimagesrc.h"
46 #include <sys/ioctl.h>
48 #include <sys/times.h>
53 #include <X11/Xlibint.h>
56 #include <exynos_drm.h>
58 GST_DEBUG_CATEGORY_STATIC (xvimagesrc_debug);
59 #define GST_CAT_DEFAULT xvimagesrc_debug
62 #define GST_XV_IMAGE_SRC_CAPS \
65 "depth = (int) 24, " \
66 "endianness = (int) BIG_ENDIAN, " \
67 "red_mask = (int) 0xFF000000, " \
68 "green_mask = (int) 0x00FF0000, " \
69 "blue_mask = (int) 0x0000FF00, " \
70 "width = (int) [ 16, 4096 ], " \
71 "height = (int) [ 16, 4096 ], " \
72 "framerate = (fraction) [0/1, 2147483647/1];" \
74 "format = (fourcc) { SN12, ST12, NV12 }, " \
75 "width = (int) [ 1, 4096 ], " \
76 "height = (int) [ 1, 4096 ], " \
77 "framerate = (fraction) [0/1, 2147483647/1];" \
79 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
82 GST_STATIC_CAPS(GST_XV_IMAGE_SRC_CAPS)
96 VIDEO_TYPE_VIDEO_WITH_UI,
97 VIDEO_TYPE_VIDEO_ONLY,
103 SIGNAL_VIDEO_WITH_UI,
105 SIGNAL_SELECTION_NOTIFY,
109 #define GEM_NAME_MAX 10
111 #define SCMN_CS_YUV420 1 /* Y:U:V 4:2:0 */
112 #define SCMN_CS_I420 SCMN_CS_YUV420 /* Y:U:V */
113 #define SCMN_CS_NV12 6
114 #define SCMN_CS_NV12_T64X32 11 /* 64x32 Tiled NV12 type */
115 #define SCMN_CS_UYVY 100
116 #define SCMN_CS_YUYV 101
117 #define SCMN_CS_YUY2 SCMN_CS_YUYV
119 /* max channel count *********************************************************/
120 #define SCMN_IMGB_MAX_PLANE (4)
122 /* image buffer definition ***************************************************
124 +------------------------------------------+ ---
127 | +---------------------------+ --- | |
129 | |<---------- w[] ---------->| | | |
137 | +---------------------------+ --- | |
139 +------------------------------------------+ ---
141 |<----------------- s[] ------------------>|
146 /* width of each image plane */
147 int w[SCMN_IMGB_MAX_PLANE];
148 /* height of each image plane */
149 int h[SCMN_IMGB_MAX_PLANE];
150 /* stride of each image plane */
151 int s[SCMN_IMGB_MAX_PLANE];
152 /* elevation of each image plane */
153 int e[SCMN_IMGB_MAX_PLANE];
154 /* user space address of each image plane */
155 void *a[SCMN_IMGB_MAX_PLANE];
156 /* physical address of each image plane, if needs */
157 void *p[SCMN_IMGB_MAX_PLANE];
158 /* color space type of image */
160 /* left postion, if needs */
162 /* top position, if needs */
164 /* to align memory */
169 gint32 fd[SCMN_IMGB_MAX_PLANE];
170 /* flag for buffer share */
171 int buf_share_method;
172 /* Y plane size in case of ST12 */
174 /* UV plane size in case of ST12 */
177 /* Tizen buffer object of each image plane */
178 void *bo[SCMN_IMGB_MAX_PLANE];
191 void *address[GEM_NAME_MAX];
192 int buffer_size[GEM_NAME_MAX];
193 int name[GEM_NAME_MAX];
194 gint32 fd[GEM_NAME_MAX];
195 gint32 handle[GEM_NAME_MAX];
199 BUF_SHARE_METHOD_PADDR = 0,
201 } buf_share_method_t;
203 typedef struct GstXvImageOutBuffer GstXvImageOutBuffer;
205 struct GstXvImageOutBuffer {
209 GstXVImageSrc * xvimagesrc;
214 #define DEFAULT_USER_AGENT "GStreamer xvimagesrc "
218 #define YUV_FRAME_SIZE 3110400
219 #define YUV_720_FRAME_SIZE 1382400
220 #define YUV_VGA_FRAME_SIZE 460800
222 static int g_prev_frame[YUV_FRAME_SIZE] = {0,};
223 static int g_dump_frame[100][YUV_720_FRAME_SIZE];
224 //static int g_dump_frame[200][YUV_VGA_FRAME_SIZE];
225 static int f_idx = 0;
226 static int f_done = 0;
229 static guint gst_xv_image_src_signals[SIGNAL_LAST] = { 0 };
231 //#define COUNT_FRAMES
233 gchar old_time[10] = {0, };
235 static gboolean error_caught = FALSE;
237 #define HANDLE_OUTBUF_UNREF
239 #ifdef HANDLE_OUTBUF_UNREF
240 #define BUFFER_COND_WAIT_TIMEOUT 1000000
241 #define GST_TYPE_GST_XV_IMAGE_OUT_BUFFER (gst_xv_image_out_buffer_get_type())
242 #define GST_IS_GST_XV_IMAGE_OUT_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GST_XV_IMAGE_OUT_BUFFER))
243 static GstBufferClass *gst_xv_image_out_buffer_parent_class = NULL;
244 static void gst_xv_image_out_buffer_class_init(gpointer g_class, gpointer class_data);
245 static void gst_xv_image_out_buffer_finalize(GstXvImageOutBuffer *buffer);
246 static GstXvImageOutBuffer *gst_xv_image_out_buffer_new(GstXVImageSrc *src);
248 static GstStateChangeReturn gst_xv_image_src_change_state (GstElement * element, GstStateChange transition);
249 static void gst_xv_image_src_finalize (GObject * gobject);
251 static void gst_xv_image_src_set_property (GObject *object, guint prop_id, const GValue * value, GParamSpec * pspec);
252 static void gst_xv_image_src_get_property (GObject *object, guint prop_id, GValue * value, GParamSpec * pspec);
253 static GstFlowReturn gst_xv_image_src_create (GstPushSrc * psrc, GstBuffer ** outbuf);
254 static gboolean gst_xv_image_src_start (GstBaseSrc * bsrc);
255 static gboolean gst_xv_image_src_stop (GstBaseSrc * bsrc);
256 static gboolean gst_xv_image_src_get_size (GstBaseSrc * bsrc, guint64 * size);
257 static gboolean gst_xv_image_src_is_seekable (GstBaseSrc * bsrc);
258 static gboolean gst_xv_image_src_query (GstBaseSrc * bsrc, GstQuery * query);
259 static gboolean gst_xv_image_src_unlock (GstBaseSrc * bsrc);
260 static gboolean gst_xv_image_src_unlock_stop (GstBaseSrc * bsrc);
261 static gboolean gst_xv_image_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
263 static tbm_bufmgr bufmgr_get (Display *dpy, Pixmap pixmap);
264 static int port_get (GstXVImageSrc * src, unsigned int id);
265 static void pixmap_update (GstXVImageSrc * src,Display *dpy, tbm_bufmgr bufmgr, Pixmap pixmap,
266 int x, int y, int width, int height);
267 static Pixmap pixmap_create (GstXVImageSrc * src, Display *dpy, int width, int height);
269 static void* gst_xv_image_src_update_thread (void * asrc);
270 static gboolean xvimagesrc_thread_start(GstXVImageSrc *src);
271 static void drm_init(GstXVImageSrc *src);
272 static void drm_finalize(GstXVImageSrc *src);
273 static gint32 drm_convert_gem_to_fd(int * gemname_cnt, int drm_fd, unsigned int name, void * data, void **virtual_address);
274 static void gst_xv_get_image_sleep(void *asrc, long duration);
277 _do_init (GType type)
279 GST_DEBUG_CATEGORY_INIT (xvimagesrc_debug, "xvimagesrc", 0, "Xv image src");
282 GST_BOILERPLATE_FULL (GstXVImageSrc, gst_xv_image_src, GstPushSrc, GST_TYPE_PUSH_SRC, _do_init);
284 #ifdef HANDLE_OUTBUF_UNREF
285 static void gst_xv_image_out_buffer_class_init(gpointer g_class, gpointer class_data)
287 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS(g_class);
288 gst_xv_image_out_buffer_parent_class = g_type_class_peek_parent(g_class);
289 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)gst_xv_image_out_buffer_finalize;
292 static GType gst_xv_image_out_buffer_get_type(void)
294 static GType _gst_gst_xv_image_out_buffer_type;
296 if (G_UNLIKELY(_gst_gst_xv_image_out_buffer_type == 0)) {
297 static const GTypeInfo gst_xv_image_out_buffer_info = {
298 sizeof (GstBufferClass),
301 gst_xv_image_out_buffer_class_init,
304 sizeof (GstXvImageOutBuffer),
309 _gst_gst_xv_image_out_buffer_type = g_type_register_static(GST_TYPE_BUFFER,
311 &gst_xv_image_out_buffer_info, 0);
313 return _gst_gst_xv_image_out_buffer_type;
317 static int value_count =0;
320 static GstStateChangeReturn
321 gst_xv_image_src_change_state (GstElement * element, GstStateChange transition)
323 GstXVImageSrc *src = GST_XV_IMAGE_SRC (element);
325 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
326 switch (transition) {
327 case GST_STATE_CHANGE_NULL_TO_READY:
329 case GST_STATE_CHANGE_READY_TO_PAUSED:
331 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
332 src->pause_cond_var = FALSE;
333 g_cond_signal(src->pause_cond);
335 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
336 GST_WARNING("GST_STATE_CHANGE_PLAYING_TO_PAUSED: START");
337 src->pause_cond_var = TRUE;
338 g_cond_wait(src->pause_resp, src->pause_resp_lock);
339 GST_WARNING("GST_STATE_CHANGE_PLAYING_TO_PAUSED: End");
341 case GST_STATE_CHANGE_PAUSED_TO_READY:
342 GST_WARNING("GST_STATE_CHANGE_PAUSED_TO_READY");
343 src->thread_return = TRUE;
344 g_cond_signal(src->pause_cond);
345 g_cond_signal(src->queue_cond);
347 case GST_STATE_CHANGE_READY_TO_NULL:
352 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
357 static void gst_xv_image_out_buffer_finalize(GstXvImageOutBuffer *buffer)
359 Atom atom_retbuf = 0;
360 if (buffer->xvimagesrc->thread_return) {
361 GST_INFO("xvimagesrc is being shutdown");
365 g_mutex_lock (buffer->xvimagesrc->dpy_lock);
366 atom_retbuf = XInternAtom (buffer->xvimagesrc->dpy, "_USER_WM_PORT_ATTRIBUTE_RETURN_BUFFER", False);
367 XvSetPortAttribute (buffer->xvimagesrc->dpy, buffer->xvimagesrc->p, atom_retbuf, buffer->YBuf); //data->YBuf is gemname, refer to drm_convert_gem_to_fd
368 g_mutex_unlock (buffer->xvimagesrc->dpy_lock);
369 g_cond_signal(buffer->xvimagesrc->buffer_cond);
370 GST_INFO(" xvimagesrc = %p, gem_name =%d, fd_name =%d", buffer->xvimagesrc, buffer->YBuf, buffer->fd_name);
374 if (value[i] == buffer->YBuf) {
376 GST_ERROR("value[%d]=%d", i, value[i]);
384 static GstXvImageOutBuffer *gst_xv_image_out_buffer_new(GstXVImageSrc *src)
386 GstXvImageOutBuffer *newbuf = NULL;
387 GST_LOG("gst_omx_out_buffer_new");
389 newbuf = (GstXvImageOutBuffer *)gst_mini_object_new(GST_TYPE_GST_XV_IMAGE_OUT_BUFFER);
392 GST_ERROR("gst_omx_out_buffer_new out of memory");
395 GST_LOG("creating buffer : %p", newbuf);
396 newbuf->xvimagesrc = gst_object_ref(GST_OBJECT(src));
404 gst_xv_image_src_base_init (gpointer g_class)
406 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
407 gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&srctemplate));
408 gst_element_class_set_details_simple (element_class, "XServer Display FB video source",
410 "Receive frame buffer data from XServer and passes to next element",
415 gst_xv_image_src_class_init (GstXVImageSrcClass * klass)
417 GObjectClass *gobject_class;
418 GstBaseSrcClass *gstbasesrc_class;
419 GstPushSrcClass *gstpushsrc_class;
420 GstElementClass *gstelement_class;
421 gobject_class = G_OBJECT_CLASS (klass);
422 gstelement_class = (GstElementClass *) klass;
423 gstbasesrc_class = (GstBaseSrcClass *) klass;
424 gstpushsrc_class = (GstPushSrcClass *) klass;
425 gobject_class->set_property = gst_xv_image_src_set_property;
426 gobject_class->get_property = gst_xv_image_src_get_property;
427 gobject_class->finalize = gst_xv_image_src_finalize;
429 gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_xv_image_src_start);
430 gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_xv_image_src_stop);
431 gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_xv_image_src_unlock);
432 gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_xv_image_src_unlock_stop);
433 gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_xv_image_src_get_size);
434 gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_xv_image_src_is_seekable);
435 gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_xv_image_src_query);
436 gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_xv_image_src_setcaps);
437 gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_xv_image_src_create);
438 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_xv_image_src_change_state);
439 g_object_class_install_property (gobject_class, PROP_DISPLAY_ROTATE,
440 g_param_spec_uint64 ("display-rotate",
442 "Display rotate info",
443 0, G_MAXUINT64, 0, G_PARAM_READWRITE));
445 gst_xv_image_src_signals[SIGNAL_UI_ONLY] =
446 g_signal_new ("ui-only", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
447 G_STRUCT_OFFSET (GstXVImageSrcClass, ui_only), NULL, NULL,
448 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
450 gst_xv_image_src_signals[SIGNAL_VIDEO_WITH_UI] =
451 g_signal_new ("video-with-ui", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
452 G_STRUCT_OFFSET (GstXVImageSrcClass, video_with_ui), NULL, NULL,
453 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
455 gst_xv_image_src_signals[SIGNAL_VIDEO_ONLY] =
456 g_signal_new ("video-only", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
457 G_STRUCT_OFFSET (GstXVImageSrcClass, video_only), NULL, NULL,
458 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
460 gst_xv_image_src_signals[SIGNAL_SELECTION_NOTIFY] =
461 g_signal_new ("selection-notify", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
462 G_STRUCT_OFFSET (GstXVImageSrcClass, selection_notify), NULL, NULL,
463 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
466 static gboolean gst_xv_image_src_get_frame_size(int fourcc, int width, int height, unsigned int *outsize)
469 /* case GST_MAKE_FOURCC('I','4','2','0'): // V4L2_PIX_FMT_YUV420
470 *outsize = GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height);
471 *outsize += 2 * ((GST_ROUND_UP_8 (width) / 2) * (GST_ROUND_UP_2 (height) / 2));
473 case GST_MAKE_FOURCC('N','V','1','2'): // V4L2_PIX_FMT_NV12 non-linear
475 *outsize = GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height);
476 *outsize += (GST_ROUND_UP_4 (width) * height) / 2;
478 case GST_MAKE_FOURCC('S','N','1','2'): // V4L2_PIX_FMT_NV12 non-linear
480 *outsize = GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height);
481 *outsize += (GST_ROUND_UP_4 (width) * height) / 2;
483 case GST_MAKE_FOURCC('S','T','1','2'): // V4L2_PIX_FMT_NV12 tiled non-linear
485 *outsize = GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height);
486 *outsize += (GST_ROUND_UP_4 (width) * height) / 2;
488 case GST_MAKE_FOURCC('R','G','B','4'):
489 /* jpeg size can't be calculated here. */
490 *outsize = width * height * 4;
493 /* unkown format!! */
501 gst_xv_image_src_parse_caps (const GstCaps * caps, guint32 *fourcc,
502 gint * width, gint * height, gint * rate_numerator, gint * rate_denominator, unsigned int *framesize)
504 const GstStructure *structure;
505 GstPadLinkReturn ret = TRUE;
506 const GValue *framerate;
507 const char *media_type = NULL;
508 GST_DEBUG ("parsing caps");
509 if (gst_caps_get_size (caps) < 1) return FALSE;
510 GST_INFO("xvimagesrc src caps:%"GST_PTR_FORMAT, caps);
511 structure = gst_caps_get_structure (caps, 0);
512 ret = gst_structure_get_int (structure, "width", width);
514 GST_ERROR ("xvimagesrc width not specified in caps");
517 ret = gst_structure_get_int (structure, "height", height);
519 GST_ERROR ("xvimagesrc height not specified in caps");
522 media_type = gst_structure_get_name (structure);
523 if(media_type == NULL) {
524 GST_ERROR ("xvimagesrc media type not specified in caps");
527 framerate = gst_structure_get_value (structure, "framerate");
529 *rate_numerator = gst_value_get_fraction_numerator (framerate);
530 *rate_denominator = gst_value_get_fraction_denominator (framerate);
532 GST_ERROR ("xvimagesrc frametype not specified in caps");
535 if (g_strcmp0 (media_type, "video/x-raw-rgb") == 0) {
536 gst_xv_image_src_get_frame_size(FOURCC_RGB32, *width, *height, framesize);
537 *fourcc = FOURCC_RGB32;
538 GST_DEBUG ("Caps set to RGB32");
539 } else if(g_strcmp0 (media_type, "video/x-raw-yuv") == 0) {
541 GST_INFO ("media_type is video/x-raw-yuv");
542 guint32 format = FOURCC_SN12;
543 ret = gst_structure_get_fourcc (structure, "format", &format);
544 if (!ret) GST_DEBUG ("xvimagesrc format not specified in caps, SN12 selected as default");
545 ret = gst_xv_image_src_get_frame_size(format, *width, *height, framesize);
547 GST_ERROR ("xvimagesrc unsupported format type specified in caps");
558 static gboolean gst_xv_image_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
561 gint width, height, rate_denominator, rate_numerator;
563 src = GST_XV_IMAGE_SRC (bsrc);
564 res = gst_xv_image_src_parse_caps (caps, &src->format_id, &width, &height,
565 &rate_numerator, &rate_denominator, &src->framesize);
569 src->height = height;
570 src->rate_numerator = rate_numerator;
571 src->rate_denominator = rate_denominator;
572 GST_DEBUG_OBJECT (src, "size %dx%d, %d/%d fps",
573 src->width, src->height,
574 src->rate_numerator, src->rate_denominator);
575 if(src->rate_numerator)
577 src->sleep_base_time = (long) (((int)(1000/src->rate_numerator))*1000);
578 src->sleep_limit_time = (long) (-1*src->sleep_base_time);
581 xvimagesrc_thread_start(src);
585 gst_xv_image_src_reset (GstXVImageSrc * src)
590 gst_xv_image_src_init (GstXVImageSrc * src, GstXVImageSrcClass * g_class)
593 src->running_time = GST_CLOCK_TIME_NONE;
594 src->frame_duration = GST_CLOCK_TIME_NONE;
597 src->dri2_buffers = NULL;
598 src->queue_lock = g_mutex_new ();
599 src->queue = g_queue_new ();
600 src->queue_cond = g_cond_new ();
601 src->cond_lock = g_mutex_new ();
602 src->buffer_cond = g_cond_new ();
603 src->buffer_cond_lock = g_mutex_new ();
604 src->pause_cond = g_cond_new ();
605 src->pause_cond_lock = g_mutex_new ();
606 src->pause_resp = g_cond_new ();
607 src->pause_resp_lock = g_mutex_new ();
608 src->dpy_lock = g_mutex_new ();
609 src->pause_cond_var = FALSE;
611 src->current_data_type = VIDEO_TYPE_VIDEO_WITH_UI;
612 src->new_data_type = VIDEO_TYPE_VIDEO_WITH_UI;
613 src->get_image_overtime = 0;
614 src->get_image_overtime_cnt = 0;
615 src->gemname_cnt = 0;
617 src->sleep_base_time = 0;
618 src->sleep_limit_time = 0;
619 src->switching_to_udp = FALSE;
621 gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
625 gst_xv_image_src_finalize (GObject * gobject)
627 GstXVImageSrc *src = GST_XV_IMAGE_SRC (gobject);
628 GST_DEBUG_OBJECT (src, "finalize");
629 g_mutex_free (src->queue_lock);
631 G_OBJECT_CLASS (parent_class)->finalize (gobject);
633 static void drm_init(GstXVImageSrc *src)
636 int eventBase, errorBase;
637 int dri2Major, dri2Minor;
638 char *driverName, *deviceName;
639 struct drm_auth auth_arg = {0};
642 dpy = XOpenDisplay(0);
645 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
646 GST_ERROR("DRI2QueryExtension !!");
649 if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
650 GST_ERROR("DRI2QueryVersion !!");
653 if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
654 GST_ERROR("DRI2Connect !!");
657 GST_INFO("Open drm device : %s", deviceName);
659 /* get the drm_fd though opening the deviceName */
660 src->drm_fd = open(deviceName, O_RDWR);
661 if (src->drm_fd < 0) {
662 GST_ERROR("cannot open drm device (%s)", deviceName);
666 /* get magic from drm to authentication */
667 if (ioctl(src->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
668 GST_ERROR("cannot get drm auth magic");
673 if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
674 GST_ERROR("cannot get drm authentication from X");
680 static void drm_finalize(GstXVImageSrc *src)
682 if (src->drm_fd >= 0) {
688 static gint32 drm_convert_gem_to_fd(int *gemname_cnt, int drm_fd, unsigned int name, void *data, void **virtual_address)
690 g_return_val_if_fail((data != NULL),0);
693 count = *gemname_cnt;
694 GST_DEBUG("gamname_cnt = %d", count);
695 GST_DEBUG("name = %u", name);
698 GEM_MMAP *xv_gem_mmap = NULL;
699 xv_gem_mmap = (GEM_MMAP *) data;
700 if(count >=GEM_NAME_MAX)
703 if (count < GEM_NAME_MAX ) {
705 for ( i =0 ; i < GEM_NAME_MAX ; i++) {
706 if (name == xv_gem_mmap->name[i])
710 struct drm_prime_handle prime;
711 struct drm_gem_open gem_open;
712 struct drm_exynos_gem_mmap gem_mmap; //for virtual address
714 memset (&gem_open, 0, sizeof (struct drm_gem_open));
715 gem_open.name = name;
716 if (ioctl(drm_fd, DRM_IOCTL_GEM_OPEN, &gem_open)) {
717 GST_ERROR("Gem Open failed");
720 memset (&prime, 0, sizeof (struct drm_prime_handle));
721 prime.handle = gem_open.handle;
722 prime.flags = DRM_CLOEXEC;
723 /*get gem_open handle*/
724 xv_gem_mmap->handle[count] = gem_open.handle;
725 GST_DEBUG("gem_open.handle =%d, xv_gem_mmap->handle[count]=%d", gem_open.handle, xv_gem_mmap->handle[count]);
726 /*get virtual address */
728 xv_gem_mmap->name[count] = name;
729 memset (&gem_mmap, 0, sizeof (struct drm_exynos_gem_mmap));
730 gem_mmap.handle = prime.handle;
731 gem_mmap.size = gem_open.size;
733 xv_gem_mmap->buffer_size[count] = gem_mmap.size;
734 if (drmIoctl(drm_fd, DRM_IOCTL_EXYNOS_GEM_MMAP, &gem_mmap) !=0) {
735 GST_ERROR("Gem mmap failed [handle %d, size %d]", gem_mmap.handle, gem_mmap.size);
738 /*set virtual address*/
739 xv_gem_mmap->address[count] = (void *)(gem_mmap.mapped);
740 GST_DEBUG ("%d - Virtual address[%d] = %p size=%d ", name, count, xv_gem_mmap->address[count], xv_gem_mmap->buffer_size[count] );
743 if (ioctl(drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime) < 0) {
744 GST_ERROR("Gem Handle to Fd failed");
747 xv_gem_mmap->fd[count] = prime.fd;
748 GST_DEBUG("fd = %d", xv_gem_mmap->fd[count]);
751 if (count < GEM_NAME_MAX) {
753 *gemname_cnt = count;
758 if (name == xv_gem_mmap->name[0]) {
759 *virtual_address = xv_gem_mmap->address[0];
760 fd = xv_gem_mmap->fd[0];
761 } else if (name == xv_gem_mmap->name[1]) {
762 *virtual_address = xv_gem_mmap->address[1];
763 fd = xv_gem_mmap->fd[1];
764 } else if (name == xv_gem_mmap->name[2]) {
765 *virtual_address = xv_gem_mmap->address[2];
766 fd = xv_gem_mmap->fd[2];
767 } else if ( name == xv_gem_mmap->name[3]) {
768 *virtual_address = xv_gem_mmap->address[3];
769 fd = xv_gem_mmap->fd[3];
770 } else if (name == xv_gem_mmap->name[4]) {
771 *virtual_address = xv_gem_mmap->address[4];
772 fd = xv_gem_mmap->fd[4];
773 } else if ( name == xv_gem_mmap->name[5]) {
774 *virtual_address = xv_gem_mmap->address[5];
775 fd = xv_gem_mmap->fd[5];
776 } else if (name == xv_gem_mmap->name[6]) {
777 *virtual_address = xv_gem_mmap->address[6];
778 fd = xv_gem_mmap->fd[6];
779 } else if (name == xv_gem_mmap->name[7]) {
780 *virtual_address = xv_gem_mmap->address[7];
781 fd = xv_gem_mmap->fd[7];
782 } else if ( name == xv_gem_mmap->name[8]) {
783 *virtual_address = xv_gem_mmap->address[8];
784 fd = xv_gem_mmap->fd[8];
785 } else if (name == xv_gem_mmap->name[9]) {
786 *virtual_address = xv_gem_mmap->address[9];
787 fd = xv_gem_mmap->fd[9];
790 GST_DEBUG("virtual_address = %p fd = %d", *virtual_address, fd);
795 gst_xv_image_src_set_property (GObject * object, guint prop_id,
796 const GValue * value, GParamSpec * pspec)
798 GstXVImageSrc *src = GST_XV_IMAGE_SRC (object);
799 GST_INFO ("set property function %x", src);
801 case PROP_DISPLAY_ROTATE:
802 src->display_rotate = g_value_get_uint64 (value);
803 GST_DEBUG("display_rotate [%d]", src->display_rotate);
806 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
813 gst_xv_image_src_get_property (GObject * object, guint prop_id,
814 GValue * value, GParamSpec * pspec)
816 GstXVImageSrc *src = GST_XV_IMAGE_SRC (object);
817 GST_INFO ("get property function %x", src);
819 case PROP_DISPLAY_ROTATE:
820 g_value_set_uint64 (value, src->display_rotate);
823 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
828 static inline GstClockTime xvimagesrc_clock (GstXVImageSrc *src)
831 gettimeofday (&tv, NULL);
832 if(!src->base_time) {
833 src->base_time = GST_TIMEVAL_TO_TIME(tv);
835 return (GstClockTime)(GST_TIMEVAL_TO_TIME(tv) - src->base_time);
838 static gboolean gst_xv_image_src_get_timeinfo2(GstXVImageSrc *src, GstClockTime *time, GstClockTime *dur)
842 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
843 GstClockTime duration = GST_CLOCK_TIME_NONE;
844 static GstClockTime prev_timestamp = 0;
848 GST_WARNING("Invalid pointer [handle:%p]", src);
851 clock = gst_element_get_clock (GST_ELEMENT (src));
853 timestamp = gst_clock_get_time (clock);
854 if(!gst_element_get_base_time (GST_ELEMENT(src)))
855 timestamp = GST_CLOCK_TIME_NONE;
856 else timestamp -= gst_element_get_base_time (GST_ELEMENT (src));
857 gst_object_unref (clock);
859 /* not an error not to have a clock */
860 timestamp = GST_CLOCK_TIME_NONE;
863 if ((timestamp - prev_timestamp <= 30000000) || (timestamp-prev_timestamp >=36000000)) {
864 //GST_ERROR("Gap is below 30ms or over 36ms!!");
867 /* if we have a framerate adjust timestamp for frame latency */
868 if ((int)((float)src->rate_numerator / (float)src->rate_denominator) <= 0) {
869 /*if fps is zero, auto fps mode*/
874 fps_de = (int)((float)src->rate_numerator / (float)src->rate_denominator);
876 if (fps_nu > 0 && fps_de > 0) {
877 GstClockTime latency;
878 latency = gst_util_uint64_scale_int(GST_SECOND, fps_nu, fps_de);
881 timestamp+=src->initial_audio_latency;
884 prev_timestamp = timestamp;
888 static gboolean gst_xv_image_src_get_timeinfo(GstXVImageSrc *src, GstBuffer *buffer)
892 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
893 GstClockTime duration = GST_CLOCK_TIME_NONE;
895 if (!src || !buffer) {
896 GST_WARNING("Invalid pointer [handle:%p, buffer:%p]", src, buffer);
899 clock = gst_element_get_clock (GST_ELEMENT (src));
901 timestamp = gst_clock_get_time (clock);
902 timestamp -= gst_element_get_base_time (GST_ELEMENT (src));
903 gst_object_unref (clock);
905 /* not an error not to have a clock */
906 timestamp = GST_CLOCK_TIME_NONE;
909 //timestamp = xvimagesrc_clock(src);
910 /* if we have a framerate adjust timestamp for frame latency */
911 if ((int)((float)src->rate_numerator / (float)src->rate_denominator) <= 0) {
912 /*if fps is zero, auto fps mode*/
917 fps_de = (int)((float)src->rate_numerator / (float)src->rate_denominator);
919 if (fps_nu > 0 && fps_de > 0) {
920 GstClockTime latency;
921 latency = gst_util_uint64_scale_int(GST_SECOND, fps_nu, fps_de);
924 GST_BUFFER_TIMESTAMP(buffer) = timestamp;
925 GST_BUFFER_DURATION(buffer) = duration;
931 static gchar *get_current_system_time()
933 gchar target[10]={0,};
939 /*localtimer_r : available since libc 5.2.5*/
940 if(localtime_r(&t, &tm) == NULL) {
943 snprintf(target, sizeof(target), "%02i:%02i:%02i", tm.tm_hour, tm.tm_min, tm.tm_sec);
944 return g_strdup(target);
947 static void gst_xv_get_image_sleep(void *asrc, long duration)
949 GST_INFO("end_time duration=%d", duration);
950 if (duration < 0) return;
951 GstXVImageSrc *src = (GstXVImageSrc *)asrc;
952 g_return_if_fail(src != NULL);
954 sleep_time = src->sleep_base_time - duration;
956 if (sleep_time < 0) {
957 src->get_image_overtime_cnt ++;
958 src->get_image_overtime += sleep_time;
959 if (src->get_image_overtime_cnt > 2)
960 src->get_image_overtime = 0;
961 if (src->get_image_overtime <= src->sleep_limit_time)
962 src->get_image_overtime = 0;
963 //GST_WARNING("Over Time[%d] : %d", src->get_image_overtime_cnt, src->get_image_overtime);
964 } else if (sleep_time > 0) {
965 src->get_image_overtime_cnt = 0;
966 sleep_time = sleep_time + src->get_image_overtime;
968 if (src->get_image_overtime < 0) {
969 //GST_WARNING("Over Time : %d, So sleep time : %d", src->get_image_overtime, sleep_time);
972 src->get_image_overtime = (sleep_time < 0) ? sleep_time : 0;
975 GST_INFO("end_time : sleep_time = %d", sleep_time);
981 gst_xv_image_src_create (GstPushSrc * psrc, GstBuffer ** buffer)
983 GST_INFO("gst_xv_image_src_create");
985 GstXvImageOutBuffer *outbuf = NULL;
986 src = GST_XV_IMAGE_SRC (psrc);
987 g_mutex_lock (src->queue_lock);
988 if(g_queue_is_empty (src->queue)) {
989 GST_INFO("g_queue_is_empty");
990 g_mutex_unlock (src->queue_lock);
991 GST_INFO("g_cond_wait");
992 g_cond_wait(src->queue_cond, src->cond_lock);
993 if(src->pause_cond_var) return GST_FLOW_WRONG_STATE;
994 g_mutex_lock (src->queue_lock);
996 if(src->switching_to_udp == TRUE) {
997 GstStructure *structure;
998 structure = gst_structure_new("Switch_udp", "switch_to_udp", G_TYPE_BOOLEAN, NULL, NULL);
999 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, structure);
1000 GstPad *srcpad = gst_element_get_static_pad(src, "src");
1001 gst_pad_push_event(srcpad, event);
1002 GST_INFO("sending the event");
1003 src->switching_to_udp = FALSE;
1006 outbuf = (GstXvImageOutBuffer *)g_queue_pop_head(src->queue);
1007 GST_INFO("g_queue_pop_head");
1008 g_mutex_unlock (src->queue_lock);
1011 GstXvImageOutBuffer *tempbuf = NULL;
1012 if((tempbuf = (GstXvImageOutBuffer*)g_queue_pop_head(src->queue)) != NULL)
1014 outbuf = tempbuf; // To reduce latency, skipping the old frames and submitting only latest frames
1015 g_mutex_unlock (src->queue_lock);
1017 GST_INFO("g_queue_pop_head end");
1019 if(outbuf == NULL) return GST_FLOW_ERROR;
1020 GST_INFO("gem_name=%d, fd_name=%d, Time stamp of the buffer is %"GST_TIME_FORMAT, outbuf->YBuf, outbuf->fd_name, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(outbuf)));
1021 *buffer = GST_BUFFER_CAST(outbuf);
1023 gchar *current_time = NULL;
1024 current_time = get_current_system_time();
1025 if (strncmp(current_time, old_time, 10) == 0) {
1027 strncpy(old_time, current_time, 10);
1029 g_printf("xvimagesrc %s - fps : %d\n", old_time, fps);
1031 strncpy(old_time, current_time, 10);
1034 GST_INFO("return ok");
1038 static gboolean xvimagesrc_thread_start(GstXVImageSrc *src)
1041 if(!src->updates_thread) src->updates_thread = g_thread_create ((GThreadFunc) gst_xv_image_src_update_thread, src, TRUE, &error);
1042 else GST_LOG_OBJECT (src, "The thread function already running");
1047 gst_xv_image_src_start (GstBaseSrc * bsrc)
1049 GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc);
1050 if(src->format_id) xvimagesrc_thread_start(src);
1054 gboolean signal_emit_func(void *asrc)
1056 GstXVImageSrc *src = (GstXVImageSrc *)asrc;
1058 if (src->current_data_type == VIDEO_TYPE_UI) {
1059 src->switching_to_udp = TRUE;
1060 g_signal_emit (src, gst_xv_image_src_signals[SIGNAL_UI_ONLY] , 0, NULL);
1061 } else if (src->current_data_type == VIDEO_TYPE_VIDEO_ONLY) {
1062 g_signal_emit (src, gst_xv_image_src_signals[SIGNAL_VIDEO_ONLY] , 0, NULL);
1063 } else if (src->current_data_type == VIDEO_TYPE_VIDEO_WITH_UI) {
1064 g_signal_emit (src, gst_xv_image_src_signals[SIGNAL_VIDEO_WITH_UI] , 0, NULL);
1070 gboolean signal_selection_emit_func(void *asrc)
1072 GstXVImageSrc *src = (GstXVImageSrc *)asrc;
1074 g_signal_emit (src, gst_xv_image_src_signals[SIGNAL_SELECTION_NOTIFY] , 0, NULL);
1080 gst_xvimagesrc_handle_xerror (Display * display, XErrorEvent * xevent)
1082 char error_msg[1024];
1084 XGetErrorText (display, xevent->error_code, error_msg, 1024);
1085 GST_DEBUG ("XError. error: %s", error_msg);
1086 error_caught = TRUE;
1090 //static gboolean first_frame=TRUE;
1091 static int framecount=0;
1092 static void* gst_xv_image_src_update_thread (void * asrc)
1094 GstXVImageSrc *src = (GstXVImageSrc *)asrc;
1095 Atom atom_data_type = 0;
1096 Atom atom_secure = 0, atom_capture=0, atom_display=0;
1098 g_return_val_if_fail((src != NULL),NULL);
1100 struct drm_gem_close gem_close;
1101 GEM_MMAP *xv_gem_mmap = NULL;
1102 xv_gem_mmap = (GEM_MMAP *)malloc(sizeof(GEM_MMAP));
1103 g_return_val_if_fail((xv_gem_mmap != NULL),NULL);
1105 memset(xv_gem_mmap, 0, sizeof(GEM_MMAP));
1107 GST_LOG_OBJECT (src, "The thread function start");
1109 int damage_err_base = 0;
1110 Atom atom_format = 0;
1111 src->dpy = XOpenDisplay (NULL);
1112 src->p = port_get (src, src->format_id);
1113 if (src->p < 0) goto finish;
1114 /*src->width and src->height is set by caps info */
1115 GST_DEBUG (" width and height of caps : %dx%d ", src->width, src->height);
1116 if (src->width == 0 || src->height == 0) goto finish;
1117 GST_DEBUG ("gst_xv_image_src_update_thread pixmap_create !!");
1118 src->pixmap = pixmap_create (src, src->dpy, src->width, src->height);
1119 GST_DEBUG ("gst_xv_image_src_update_thread pixmap_create !!");
1120 src->gc = XCreateGC (src->dpy, src->pixmap, 0, 0);
1121 GST_DEBUG ("gst_xv_image_src_update_thread XCreateGC !!");
1122 src->bufmgr = bufmgr_get (src->dpy, src->pixmap);
1123 if (!src->bufmgr) goto finish;
1124 GST_DEBUG ("gst_xv_image_src_update_thread bufmgr_get !!");
1125 if (!XDamageQueryExtension(src->dpy, &src->damage_base, &damage_err_base)) goto finish;
1126 GST_DEBUG ("gst_xv_image_src_update_thread XDamageQueryExtension !!");
1127 src->damage = XDamageCreate (src->dpy, src->pixmap, XDamageReportNonEmpty);
1128 atom_format = XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_FORMAT", False);
1129 atom_capture = XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_CAPTURE", False);
1130 atom_display = XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_DISPLAY", False);
1133 atom_data_type = XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_DATA_TYPE", False);
1134 /* _USER_WM_PORT_ATTRIBUTE_STREAM_OFF is removed */
1135 //src->atom_stream_off = XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False);
1137 XvSetPortAttribute (src->dpy, src->p, atom_format, src->format_id);
1138 XvSetPortAttribute (src->dpy, src->p, atom_capture, 2);
1139 XvSetPortAttribute (src->dpy, src->p, atom_display, 1);
1141 XvSelectPortNotify (src->dpy, src->p, 1);
1142 XvGetPortAttribute (src->dpy, src->p, atom_data_type, &(src->new_data_type));
1145 /* Set display type */
1146 Atom atom_select_display=0;
1147 Atom atom_select_display_type=0;
1148 Atom atom_encoding=0;
1150 const char *display_type = "WFD";
1152 atom_select_display = XInternAtom(src->dpy, "SEL_EXT_DISPLAY", False);
1153 atom_select_display_type = XInternAtom(src->dpy, "SEL_EXT_DISPLAY_TYPE", False);
1154 atom_encoding = XInternAtom(src->dpy, "UTF8_STRING", False);
1155 src->win = DefaultRootWindow(src->dpy);
1157 XSetSelectionOwner(src->dpy, atom_select_display, src->win, 0);
1159 xtp.value = (unsigned char *)display_type;
1161 xtp.encoding = atom_encoding;
1162 xtp.nitems = strlen(display_type);
1163 XSetTextProperty(src->dpy, src->win, &xtp, atom_select_display_type);
1166 struct timeval start_time, end_time;
1168 long starttime, endtime;
1173 void *virtual_address = NULL;
1174 int (*handler) (Display *, XErrorEvent *);
1175 GstXvImageOutBuffer *outbuf = NULL;
1177 GstClockTime ts_putstill = 0;
1178 GstClockTime dur_putstill = 0;
1180 gboolean got_display_select_req = FALSE;
1182 while(!src->thread_return) {
1183 if(src->pause_cond_var == TRUE) {
1184 GST_WARNING("PAUSED in thread");
1185 g_cond_signal(src->pause_resp);
1186 g_cond_wait(src->pause_cond,src->pause_cond_lock);
1189 if (src->thread_return) {
1190 GST_WARNING("Thread return");
1198 start_time.tv_sec = 0;
1199 start_time.tv_usec = 0;
1200 end_time.tv_sec = 0;
1201 end_time.tv_usec = 0;
1202 gettimeofday(&start_time, NULL);
1207 virtual_address = NULL;
1210 g_mutex_lock (src->dpy_lock);
1211 GST_DEBUG("[XCALL] call XSync");
1213 GST_INFO ("gst_xv_image_src_update_thread XSync@@ !!");
1214 g_mutex_unlock (src->dpy_lock);
1215 error_caught = FALSE;
1216 //GST_DEBUG ("gst_xv_image_src_update_thread XSetErrorHandler in !!");
1217 handler = XSetErrorHandler (gst_xvimagesrc_handle_xerror);
1218 //GST_INFO ("gst_xv_image_src_update_thread XSetErrorHandler !!");
1219 //GST_INFO ("gst_xv_image_src_update_thread XvPutStill in !!");
1220 g_mutex_lock (src->dpy_lock);
1221 GST_DEBUG("[XCALL] call XvPutStill");
1222 XvPutStill (src->dpy, src->p, src->pixmap, src->gc, 0, 0, src->width, src->height, 0, 0, src->width, src->height);
1224 gst_xv_image_src_get_timeinfo2(src, &ts_putstill, &dur_putstill);
1226 //GST_INFO ("gst_xv_image_src_update_thread XvPutStill !!");
1227 GST_DEBUG("[XCALL] call 2nd XSync");
1228 XSync (src->dpy, 0);
1229 GST_DEBUG("[XCALL] call 2nd XSync done");
1230 g_mutex_unlock (src->dpy_lock);
1232 GST_ERROR("gst_xv_image_src_update_thread error_caught is TRUE, X is out of buffers");
1233 error_caught = FALSE;
1234 XSetErrorHandler(handler);
1235 g_get_current_time(&timeout);
1236 g_time_val_add(&timeout, BUFFER_COND_WAIT_TIMEOUT);
1237 if(!g_cond_timed_wait(src->buffer_cond, src->buffer_cond_lock, &timeout)) {
1238 GST_ERROR("skip wating");
1240 GST_ERROR("Signal received");
1244 /*reset error handler*/
1245 error_caught = FALSE;
1246 XSetErrorHandler(handler);
1248 //GST_INFO ("gst_xv_image_src_update_thread XSync !!");
1250 g_mutex_lock (src->dpy_lock);
1251 //GST_INFO("XNextEvent in");
1252 XNextEvent (src->dpy, &ev); /* wating for x event */
1253 //GST_INFO("XNextEvent out");
1254 g_mutex_unlock (src->dpy_lock);
1255 //GST_INFO ("gst_xv_image_src_update_thread XNextEvent !!");
1256 if (ev.type == (src->damage_base + XDamageNotify)) {
1257 XDamageNotifyEvent *damage_ev = (XDamageNotifyEvent *)&ev;
1258 GST_INFO ("gst_xv_image_src_update_thread XDamageNotifyEvent");
1259 g_mutex_lock (src->dpy_lock);
1260 if (damage_ev->drawable == src->pixmap) {
1261 pixmap_update (src, src->dpy, src->bufmgr, src->pixmap,
1264 damage_ev->area.width,
1265 damage_ev->area.height);
1266 GST_INFO("gst_xv_image_src_update_thread pixmap_update");
1268 XDamageSubtract (src->dpy, src->damage, None, None );
1269 g_mutex_unlock (src->dpy_lock);
1270 GST_INFO ("gst_xv_image_src_update_thread XDamageSubtract");
1272 /* Added to handle display selection notify */
1273 else if (ev.type == SelectionClear) {
1274 XSelectionEvent *selection_ev = (XSelectionEvent*)&ev;
1276 GST_ERROR("ev.type : %d SelectionClear", ev.type);
1277 //g_timeout_add(1, signal_selection_emit_func, src);
1279 else if (ev.type == SelectionRequest) {
1280 XSelectionRequestEvent *selection_ev = (XSelectionRequestEvent*)&ev;
1282 GST_ERROR("ev.type : %d SelectionRequest", ev.type);
1283 src->requestor = selection_ev->requestor;
1284 src->selection = selection_ev->selection;
1285 src->target = selection_ev->target;
1286 src->property = selection_ev->property;
1288 got_display_select_req = TRUE;
1289 g_timeout_add(1, signal_selection_emit_func, src);
1291 else if (ev.type == SelectionNotify) {
1292 XSelectionEvent *selection_ev = (XSelectionEvent*)&ev;
1294 GST_ERROR("ev.type : %d SelectionNotify", ev.type);
1295 //g_timeout_add(1, signal_selection_emit_func, src);
1297 else if (ev.type == (src->evt_base + XvPortNotify)) {
1298 XvPortNotifyEvent *notify_ev = (XvPortNotifyEvent*)&ev;
1299 if (notify_ev->attribute == atom_secure) {
1300 GST_WARNING ("secure attr changed : %s \n", ((int)notify_ev->value)?"Secure":"Normal");
1301 src->tz_enable = (int)notify_ev->value;
1302 GST_ERROR("src->tz_enable = %d", src->tz_enable);
1305 if (notify_ev->attribute == atom_data_type) {
1306 /* got a port notify, data_type */
1307 src->new_data_type = (int)notify_ev->value;
1308 if (src->current_data_type != src->new_data_type) {
1309 src->current_data_type = src->new_data_type;
1310 //GST_WARNING("current_data_type : %s \n", (src->current_data_type)?"Video":"UI+Video");
1311 if (src->current_data_type == VIDEO_TYPE_UI) {
1312 GST_WARNING("current_data_type : UI\n");
1313 } else if (src->current_data_type == VIDEO_TYPE_VIDEO_WITH_UI) {
1314 GST_WARNING("current_data_type : Video+UI\n");
1315 } else if (src->current_data_type == VIDEO_TYPE_VIDEO_ONLY) {
1316 GST_WARNING("current_data_type : VideoOnly\n");
1319 g_timeout_add(1, signal_emit_func, src);
1325 if(!src->virtual) continue;
1326 if(src->format_id == FOURCC_RGB32) {
1327 outbuf = (GstXvImageOutBuffer*)gst_buffer_new_and_alloc (src->framesize);
1328 gst_buffer_set_caps (GST_BUFFER_CAST(outbuf), GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
1329 memcpy(GST_BUFFER_DATA (outbuf), src->virtual, src->framesize);
1330 } else if ((src->format_id == FOURCC_SN12) || (src->format_id == FOURCC_NV12)) {
1331 XV_DATA_PTR data = (XV_DATA_PTR)src->virtual;
1332 int error = XV_VALIDATE_DATA (data);
1333 outbuf = gst_xv_image_out_buffer_new(src);
1336 GST_ERROR("Out of memory");
1339 gst_buffer_set_caps (GST_BUFFER_CAST(outbuf), GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
1340 if (error == XV_HEADER_ERROR)
1341 GST_ERROR ("XV_HEADER_ERROR\n");
1342 else if (error == XV_VERSION_MISMATCH)
1343 GST_ERROR ("XV_VERSION_MISMATCH\n");
1346 SCMN_IMGB *psimgb = NULL;
1347 psimgb = (SCMN_IMGB *)malloc(sizeof(SCMN_IMGB));
1348 if (psimgb == NULL) {
1349 GST_ERROR_OBJECT(src, "failed to alloc SCMN_IMGB");
1352 memset(psimgb, 0x00, sizeof(SCMN_IMGB));
1353 if (data->BufType == XV_BUF_TYPE_LEGACY) {
1354 psimgb->p[0] = (void *)data->YBuf;
1355 psimgb->p[1] = (void *)data->CbBuf;
1356 psimgb->buf_share_method = BUF_SHARE_METHOD_PADDR;
1357 psimgb->a[0] = NULL;
1358 psimgb->a[1] = NULL;
1359 } else if (data->BufType == XV_BUF_TYPE_DMABUF)
1361 psimgb->fd[0] = drm_convert_gem_to_fd(&src->gemname_cnt, src->drm_fd, (void *)data->YBuf, xv_gem_mmap, &virtual_address);
1362 if(!virtual_address) continue;
1363 psimgb->a[0] = virtual_address;
1364 GST_DEBUG("YBuf gem to fd[0]=%d virtual_address = %p", psimgb->fd[0], psimgb->a[0]);
1365 psimgb->fd[1] = drm_convert_gem_to_fd(&src->gemname_cnt, src->drm_fd, (void *)data->CbBuf, xv_gem_mmap, &virtual_address);
1366 if(!virtual_address) continue;
1367 psimgb->a[1] = virtual_address;
1368 GST_DEBUG("CbBuf gem to fd[1]=%d virtual_address = %p", psimgb->fd[1], psimgb->a[1]);
1369 psimgb->buf_share_method = BUF_SHARE_METHOD_FD;
1370 psimgb->w[1] = src->width;
1371 psimgb->h[1] = src->height >> 1;
1372 psimgb->s[1] = GST_ROUND_UP_16(psimgb->w[1]);
1373 psimgb->e[1] = GST_ROUND_UP_16(psimgb->h[1]);
1374 psimgb->cs = SCMN_CS_NV12;
1375 psimgb->tz_enable = 0;
1377 psimgb->w[0] = src->width;
1378 psimgb->h[0] = src->height;
1379 psimgb->s[0] = GST_ROUND_UP_16(psimgb->w[0]);
1380 psimgb->e[0] = GST_ROUND_UP_16(psimgb->h[0]);
1381 outbuf->fd_name = psimgb->fd[0];
1382 GST_BUFFER_MALLOCDATA(outbuf) = (unsigned char*)psimgb;
1383 GST_BUFFER_DATA(outbuf) = src->virtual;
1384 outbuf->YBuf = data->YBuf;
1385 outbuf->fd_name = psimgb->fd[0];
1387 for ( i=0; i<5 ; i++) {
1388 if(value[value_count] == outbuf->YBuf ) {
1389 GST_ERROR("ERROR: value[%d](%d)==YBUf(%d)", value_count, value[value_count], outbuf->YBuf);
1392 value[value_count] = outbuf->YBuf ;
1393 GST_ERROR("value[%d]=%d", value_count, value[value_count]);
1394 if( value_count < 4){
1403 if (src->running_time > 14000000000 && src->running_time < 20000000000) {
1404 GST_ERROR("Mem copy");
1405 if (virtual_address == NULL) {
1406 GST_ERROR("Mem virtual is NULL[%d]", f_idx);
1408 memcpy(g_dump_frame[f_idx++], virtual_address, YUV_720_FRAME_SIZE);
1409 //memcpy(g_dump_frame[f_idx++], virtual_address, YUV_VGA_FRAME_SIZE);
1410 GST_ERROR("Mem copy done[%d]", f_idx);
1415 GST_ERROR("File DUMP!!");
1417 fp = fopen("/opt/usr/media/Videos/frame.yuv", "a");
1419 for (i = 0; i < 100; i++) {
1420 fwrite(g_dump_frame[i], YUV_720_FRAME_SIZE, 1, fp);
1421 //fwrite(g_dump_frame[i], YUV_VGA_FRAME_SIZE, 1, fp);
1425 GST_ERROR("File DUMP done!!");
1431 if(!outbuf) continue;
1432 GST_BUFFER_SIZE (outbuf) = src->framesize;
1433 //gst_xv_image_src_get_timeinfo(src, GST_BUFFER_CAST(outbuf));
1434 GST_BUFFER_TIMESTAMP(outbuf) = ts_putstill;
1435 GST_BUFFER_DURATION(outbuf) = dur_putstill;
1436 src->running_time = GST_BUFFER_TIMESTAMP(outbuf);
1437 src->frame_duration = GST_BUFFER_DURATION(outbuf);
1438 //first_frame = FALSE;
1439 g_mutex_lock (src->queue_lock);
1440 g_queue_push_tail(src->queue, outbuf);
1441 //GST_INFO("g_queue_push_tail");
1442 g_mutex_unlock (src->queue_lock);
1443 g_cond_signal(src->queue_cond);
1444 //GST_INFO("g_cond_signal");
1447 if (src->virtual) tbm_bo_unmap(src->bo);
1448 src->virtual = NULL;
1449 GST_INFO("g_cond_signal");
1450 if (src->bo) tbm_bo_unref(src->bo);
1452 if (src->dri2_buffers) free(src->dri2_buffers);
1453 src->dri2_buffers = NULL;
1454 gettimeofday(&end_time, NULL);
1455 starttime = start_time.tv_usec;
1456 endtime = end_time.tv_usec;
1457 //GST_INFO("star_time: %d, end_time:%d", starttime, endtime);
1458 if (endtime > starttime) {
1459 //GST_INFO("end_time > start_time");
1460 duration = endtime - starttime;
1462 //GST_INFO("end_time.tv_usec < start_time.tv_usec");
1463 endtime=endtime+1000000;
1464 //GST_INFO("end_time =%d", endtime);
1465 duration = endtime -starttime;
1468 GST_INFO("end_time duration = %d", duration);
1469 //if (src->sleep_base_time > duration)
1470 gst_xv_get_image_sleep (src, duration);
1473 GST_INFO("gst_xv_image_src_update_thread cleanup !!");
1475 GST_WARNING("gst_xv_image_src_update_thread loop ended");
1477 for ( i=0 ; i < GEM_NAME_MAX ; i++) {
1479 if (xv_gem_mmap->address[i]) {
1480 if (-1 == munmap(xv_gem_mmap->address[i],xv_gem_mmap->buffer_size[i])) {
1481 GST_ERROR ("munmap failed");
1485 if (xv_gem_mmap->handle[i]) {
1486 gem_close.handle = xv_gem_mmap->handle[i];
1487 if (ioctl(src->drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close)) {
1488 GST_ERROR("Gem Close failed");
1491 if (xv_gem_mmap->fd[i]) {
1492 close(xv_gem_mmap->fd[i]);
1499 GST_LOG_OBJECT (src, "The thread function cleanup");
1501 XvStopVideo(src->dpy, src->p, src->pixmap);
1504 tbm_bufmgr_deinit (src->bufmgr);
1508 XvUngrabPort (src->dpy, src->p, 0);
1512 if (got_display_select_req) {
1513 /* Notify miracast-destroyed to X */
1514 GST_WARNING_OBJECT (src, "There is display selection request");
1516 XSelectionEvent xnotify;
1518 xnotify.type = SelectionNotify;
1519 xnotify.display = src->dpy;
1520 xnotify.requestor = src->requestor;
1521 xnotify.selection = src->selection;
1522 xnotify.target = src->target;
1523 xnotify.property = src->property;
1525 xnotify.send_event = True;
1527 xev.xselection = xnotify;
1528 if (XSendEvent(src->dpy, src->requestor, False, 0, &xev) < 0) {
1529 GST_ERROR("XSendEvent failed!");
1531 GST_INFO("XSendEvent success!");
1536 XFreeGC (src->dpy, src->gc);
1539 if (src->pixmap > 0) {
1540 XFreePixmap (src->dpy, src->pixmap);
1544 XCloseDisplay (src->dpy);
1548 GST_LOG_OBJECT (src, "The thread function stop");
1551 GST_LOG_OBJECT (src, "The thread function Error cleanup");
1553 XvStopVideo(src->dpy, src->p, src->pixmap);
1555 if (src->bufmgr) tbm_bufmgr_deinit (src->bufmgr);
1557 if (src->p > 0) XvUngrabPort (src->dpy, src->p, 0);
1559 if (src->gc) XFreeGC (src->dpy, src->gc);
1561 if (src->pixmap > 0) XFreePixmap (src->dpy, src->pixmap);
1563 if (src->dpy) XCloseDisplay (src->dpy);
1565 GST_LOG_OBJECT (src, "The thread function Error stop");
1569 static tbm_bufmgr bufmgr_get (Display *dpy, Pixmap pixmap)
1574 int eventBase, errorBase;
1575 int dri2Major, dri2Minor;
1576 char *driverName = NULL, *deviceName = NULL;
1579 screen = DefaultScreen(dpy);
1580 if (!DRI2QueryExtension (dpy, &eventBase, &errorBase)) {
1581 GST_ERROR ("!!Error : DRI2QueryExtension !!");
1584 if (!DRI2QueryVersion (dpy, &dri2Major, &dri2Minor)) {
1585 GST_ERROR ("!!Error : DRI2QueryVersion !!");
1588 if (!DRI2Connect (dpy, RootWindow(dpy, screen), &driverName, &deviceName)) {
1589 GST_ERROR ( "!!Error : DRI2Connect !!");
1590 if(driverName) Xfree(driverName);
1591 if(deviceName) Xfree(deviceName);
1595 if(driverName) Xfree(driverName);
1596 if(!deviceName) return NULL;
1598 GST_DEBUG("Open drm device : %s", deviceName);
1599 // get the drm_fd though opening the deviceName
1600 drm_fd = open (deviceName, O_RDWR);
1602 GST_ERROR ("!!Error : cannot open drm device (%s)", deviceName);
1603 if(deviceName) Xfree(deviceName);
1606 if(deviceName) Xfree(deviceName);
1607 /* get the drm magic */
1608 drmGetMagic(drm_fd, &magic);
1609 fprintf(stderr, ">>> drm magic=%d \n", magic);
1610 if (!DRI2Authenticate(dpy, RootWindow(dpy, screen), magic))
1612 fprintf(stderr, "!!Error : DRI2Authenticate !!\n");
1616 // drm slp buffer manager init
1617 bufmgr = tbm_bufmgr_init (drm_fd);
1619 GST_ERROR ("!!Error : fail to init buffer manager ");
1623 DRI2CreateDrawable (dpy, pixmap);
1627 static int port_get (GstXVImageSrc * src, unsigned int id)
1629 unsigned int ver, rev, req_base, err_base;
1630 unsigned int adaptors;
1631 XvAdaptorInfo *ai = NULL;
1632 XvAttribute *at = NULL;
1633 XvImageFormatValues *fo = NULL;
1634 int attributes, formats;
1637 if (XvQueryExtension (src->dpy, &ver, &rev, &req_base, &src->evt_base, &err_base) != Success) return -1;
1638 if (XvQueryAdaptors (src->dpy, DefaultRootWindow (src->dpy), &adaptors, &ai) != Success) return -1;
1640 for (i = 0; i < adaptors; i++) {
1641 int support_format = False;
1642 if (!(ai[i].type & XvInputMask) || !(ai[i].type & XvStillMask)) continue;
1643 GST_LOG ("===========================================");
1644 GST_LOG (" name: %s"
1651 GST_LOG (" attribute list:");
1652 at = XvQueryPortAttributes (src->dpy, p, &attributes);
1653 for (j = 0; j < attributes; j++) GST_LOG ("\t- name: %s\n"
1654 "\t\t flags: %s%s\n"
1655 "\t\t min_value: %i\n"
1656 "\t\t max_value: %i\n",
1658 (at[j].flags & XvGettable) ? " get" : "",
1659 (at[j].flags & XvSettable) ? " set" : "",
1660 at[j].min_value, at[j].max_value);
1662 GST_LOG (" image format list:");
1663 fo = XvListImageFormats (src->dpy, p, &formats);
1664 for (j = 0; j < formats; j++) {
1665 GST_LOG ("\t- 0x%x (%4.4s) %s", fo[j].id, (char *)&fo[j].id, (fo[j].format == XvPacked) ? "packed" : "planar");
1666 if (fo[j].id == (int)id) support_format = True;
1669 if (!support_format) continue;
1670 for (; p < ai[i].base_id + ai[i].num_ports; p++) {
1671 if (XvGrabPort (src->dpy, p, 0) == Success) {
1672 GST_LOG ("========================================");
1673 GST_DEBUG ("XvGrabPort success : %d", p);
1674 GST_LOG ("========================================");
1675 XvFreeAdaptorInfo (ai);
1680 XvFreeAdaptorInfo (ai);
1684 static void pixmap_update (GstXVImageSrc * src, Display *dpy, tbm_bufmgr bufmgr, Pixmap pixmap,
1685 int x, int y, int width, int height)
1687 unsigned int attachments[1];
1688 int dri2_count, dri2_out_count;
1689 int dri2_width, dri2_height, dri2_stride;
1691 tbm_bo_handle temp_virtual;
1692 attachments[0] = DRI2BufferFrontLeft;
1694 GST_DEBUG ("DRI2GetBuffers");
1695 src->dri2_buffers = DRI2GetBuffers (dpy, pixmap, &dri2_width, &dri2_height, attachments, dri2_count, &dri2_out_count);
1696 if (!src->dri2_buffers) {
1697 GST_ERROR ("[Error] : fail to get buffers");
1700 if (!src->dri2_buffers[0].name) {
1701 GST_ERROR ("[Error] : a handle of the dri2 buffer is null ");
1704 GST_DEBUG ("tbm_bo_import");
1705 src->bo = tbm_bo_import(bufmgr, src->dri2_buffers[0].name);
1707 GST_ERROR ("[Error] : cannot import bo (key:%d)", src->dri2_buffers[0].name);
1710 dri2_stride = src->dri2_buffers[0].pitch;
1711 opt = TBM_OPTION_READ|TBM_OPTION_WRITE;
1712 GST_DEBUG ("tbm_bo_map");
1713 temp_virtual = tbm_bo_map (src->bo, TBM_DEVICE_CPU, opt);
1714 src->virtual = temp_virtual.ptr;
1715 if (!src->virtual) {
1716 GST_ERROR ("[Error] : fail to map ");
1721 if (src->virtual) tbm_bo_unmap(src->bo);
1722 src->virtual = NULL;
1723 if (src->bo) tbm_bo_unref(src->bo);
1725 if (src->dri2_buffers) free(src->dri2_buffers);
1726 src->dri2_buffers = NULL;
1730 static Pixmap pixmap_create (GstXVImageSrc * src, Display *dpy, int width, int height)
1732 src->pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), width, height, DefaultDepth(dpy, DefaultScreen(dpy)));
1733 src->gc = XCreateGC (dpy, src->pixmap, 0, 0);
1734 XSetForeground (dpy, src->gc, 0xFFFF0000);
1735 XFillRectangle (dpy, src->pixmap, src->gc, 0, 0, width, height);
1737 XFreeGC (dpy, src->gc);
1742 gst_xv_image_src_stop (GstBaseSrc * bsrc)
1744 GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc);
1745 GST_WARNING ("stop()");
1747 if(src->updates_thread) {
1748 src->thread_return = TRUE;
1749 g_cond_signal(src->pause_cond);
1750 g_thread_join ( src->updates_thread);
1751 src->updates_thread = NULL;
1753 GST_WARNING ("stop end ");
1757 /* Interrupt a blocking request. */
1759 gst_xv_image_src_unlock (GstBaseSrc * bsrc)
1761 GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc);
1762 GST_DEBUG_OBJECT (src, "unlock()");
1763 g_cond_signal(src->queue_cond);
1767 /* Interrupt interrupt. */
1769 gst_xv_image_src_unlock_stop (GstBaseSrc * bsrc)
1771 GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc);
1772 GST_DEBUG_OBJECT (src, "unlock_stop()");
1777 gst_xv_image_src_get_size (GstBaseSrc * bsrc, guint64 * size)
1779 GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc);
1780 GST_INFO ("Get size %x", src);
1785 gst_xv_image_src_is_seekable (GstBaseSrc * bsrc)
1787 GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc);
1788 GST_INFO ("Is seekable %x", src);
1793 gst_xv_image_src_query (GstBaseSrc * bsrc, GstQuery * query)
1795 GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc);
1797 GST_INFO ("src query %x", src);
1798 switch (GST_QUERY_TYPE (query)) {
1808 ret = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
1814 plugin_init (GstPlugin * plugin)
1816 GST_DEBUG_CATEGORY_INIT (xvimagesrc_debug, "xvimagesrc", 0, "XServer display FB video capture Source");
1817 return gst_element_register (plugin, "xvimagesrc", GST_RANK_PRIMARY, GST_TYPE_XV_IMAGE_SRC);
1820 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1823 "XServer display video src",
1824 plugin_init, VERSION, "LGPL", "Samsung Electronics Co", "http://www.samsung.com")