4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@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
25 #if defined(_MM_PROJECT_FLOATER) || defined(_MM_PROJECT_PROTECTOR) || defined(_MM_PROJECT_VOLANS)
26 #define VERSION "0.10.19" // sec
27 #define PACKAGE "gstreamer"
28 #elif defined(_MM_PROJECT_ADORA)
29 #define VERSION "0.10.9" // mavell
30 #define PACKAGE "gstreamer"
38 #include "gstavsysmemsink.h"
40 #define debug_enter g_print
41 #define debug_leave g_print
42 #define debug_fenter() g_print("enter: %s\n",__FUNCTION__)
43 #define debug_fleave() g_print("leave: %s\n",__FUNCTION__)
44 #define debug_msg g_print
45 #define debug_verbose g_print
46 #define debug_warning g_print
47 #define debug_error g_print
49 #define GST_CAT_DEFAULT avsysmemsink_debug
51 #define DISABLE_YUV_FORMAT_ON_SINK_CAPS
53 GST_DEBUG_CATEGORY_STATIC (avsysmemsink_debug);
69 static GstStaticPadTemplate sink_factory =
70 GST_STATIC_PAD_TEMPLATE ("sink",
71 GST_PAD_SINK, GST_PAD_ALWAYS,
73 #ifndef DISABLE_YUV_FORMAT_ON_SINK_CAPS
75 "format = (fourcc){YV12}, "
76 "framerate = (fraction) [ 0, MAX ], "
77 "width = (int) [ 1, MAX ], "
78 "height = (int) [ 1, MAX ]; "
80 "format = (fourcc){I420}, "
81 "framerate = (fraction) [ 0, MAX ], "
82 "width = (int) [ 1, MAX ], "
83 "height = (int) [ 1, MAX ]; "
91 "endianness = (int)4321, "
92 "red_mask = (int)65280, "
93 "green_mask = (int)16711680, "
94 "blue_mask = (int)-16777216, "
95 "alpha_mask = (int)255, "
96 "width = (int) [ 1, MAX ], "
97 "height = (int) [ 1, MAX ], "
98 "framerate = (fraction) [ 0, MAX ]; "
103 static GstElementDetails AvsysMemSink_details = {
104 "AV-system Stream callback",
106 "Stream sink for AV-System GStreamer Plug-in",
110 static guint gst_avsysmemsink_signals[LAST_SIGNAL] = { 0 };
113 #ifdef G_ENABLE_DEBUG
114 #define g_marshal_value_peek_int(v) g_value_get_int (v)
115 #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
116 #else /* !G_ENABLE_DEBUG */
117 #define g_marshal_value_peek_int(v) (v)->data[0].v_int
118 #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
119 #endif /* !G_ENABLE_DEBUG */
122 #define GET_PIXEL(buf, x, y, stride) (*((unsigned char*)(buf) + (x) + (y)*(stride)))
124 #define GET_RED(Y,U,V) ((9535 * (Y - 16) + 13074 * (V - 128)) >> 13)
125 #define GET_GREEN(Y,U,V) ((9535 * (Y - 16) - 6660 * (V - 128) - 3203 * (U - 128)) >> 13 )
126 #define GET_BLUE(Y,U,V) ((9535 * (Y - 16) + 16531 * (U - 128)) >> 13 )
128 #define UCLIP(a) (((a)<0)?0:((a)>255)?255:(a))
132 yuv420toargb(unsigned char *src, unsigned char *dst, int width, int height)
138 unsigned char* pixel;
146 GST_DEBUG ("converting yuv420 to argb");
149 pU = src + (width * height) ;
150 pV = src + (width * height) + (width * height /4) ;
154 for(h = 0 ; h < height; h++)
156 for(w = 0 ; w < width; w++)
158 y = GET_PIXEL(pY,w,h,width);
159 u = GET_PIXEL(pU,w/2,h/2,width/2);
160 v = GET_PIXEL(pV,w/2,h/2,width/2);
163 g = GET_GREEN(y,u,v);
170 index = (w + (h* width)) * 4;
180 rotate_pure(unsigned char *src, unsigned char *dst, int width,int height,int angle,int bpp)
187 int src_idx, dst_idx;
189 size = width * height * bpp;
193 memcpy(dst,src,size);
197 for(org_y =0; org_y < height; org_y++)
199 for(org_x = 0; org_x < width ; org_x++)
203 new_x = height - org_y;
208 else if(angle == 180)
210 new_x = width - org_x;
211 new_y = height - org_y;
214 else if(angle == 270)
217 new_y = width - org_x;
222 g_print("Not support Rotate : %d\n",angle);
226 src_idx = org_x + (org_y * width);
227 dst_idx = new_x + (new_y * dst_width);
229 memcpy(dst + (dst_idx*bpp), src+(src_idx *bpp),bpp);
236 resize_pure(unsigned char *src, unsigned char *dst, int src_width, int src_height, int dst_width,int dst_height, int bpp)
238 float xFactor,yFactor;
245 int src_index,dst_index;
247 unsigned short *pshortSrc;
248 unsigned short *pshortDst;
252 pshortSrc = (unsigned short*)src;
253 pshortDst = (unsigned short*)dst;
256 xFactor = (float)((dst_width<<16) / src_width);
257 yFactor = (float)((dst_height<<16) / src_height);
259 for(y = 0; y < dst_height; y++)
261 for(x = 0; x < dst_width; x++)
263 org_fx = (float)((x<<16)/xFactor);
264 org_fy = (float)((y<<16)/yFactor);
266 org_x = (int)(org_fx);
267 org_y = (int)(org_fy);
269 src_index = org_x + (org_y * src_width);
270 dst_index = x + (y*dst_width);
272 memcpy(dst+(dst_index *bpp ),src+(src_index *bpp),bpp);
277 /* BOOLEAN:POINTER,INT,INT (avsysvideosink.c:1) */
279 gst_avsysmemsink_BOOLEAN__POINTER_INT_INT (GClosure *closure,
280 GValue *return_value G_GNUC_UNUSED,
281 guint n_param_values,
282 const GValue *param_values,
283 gpointer invocation_hint G_GNUC_UNUSED,
284 gpointer marshal_data)
286 typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_INT_INT) (gpointer data1,
291 register GMarshalFunc_BOOLEAN__POINTER_INT_INT callback;
292 register GCClosure *cc = (GCClosure*) closure;
293 register gpointer data1, data2;
297 g_return_if_fail (return_value != NULL);
298 g_return_if_fail (n_param_values == 4);
300 if (G_CCLOSURE_SWAP_DATA (closure))
302 data1 = closure->data;
303 data2 = g_value_peek_pointer (param_values + 0);
307 data1 = g_value_peek_pointer (param_values + 0);
308 data2 = closure->data;
310 callback = (GMarshalFunc_BOOLEAN__POINTER_INT_INT) (marshal_data ? marshal_data : cc->callback);
312 v_return = callback (data1,
313 g_marshal_value_peek_pointer (param_values + 1),
314 g_marshal_value_peek_int (param_values + 2),
315 g_marshal_value_peek_int (param_values + 3),
318 g_value_set_boolean (return_value, v_return);
321 static void gst_avsysmemsink_init_interfaces (GType type);
324 GST_BOILERPLATE_FULL (GstAvsysMemSink, gst_avsysmemsink, GstVideoSink, GST_TYPE_VIDEO_SINK, gst_avsysmemsink_init_interfaces);
328 gst_avsysmemsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
330 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (object);
335 if(AvsysMemSink->dst_width != g_value_get_int (value))
337 AvsysMemSink->dst_width = g_value_get_int (value);
338 AvsysMemSink->dst_changed = 1;
342 if(AvsysMemSink->dst_height != g_value_get_int (value))
344 AvsysMemSink->dst_height = g_value_get_int (value);
345 AvsysMemSink->dst_changed = 1;
349 if(AvsysMemSink->rotate != g_value_get_int(value))
351 AvsysMemSink->rotate = g_value_get_int(value);
352 AvsysMemSink->dst_changed = 1;
356 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
357 g_print ("invalid property id\n");
363 gst_avsysmemsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
365 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (object);
371 g_value_set_int (value, AvsysMemSink->dst_width);
374 g_value_set_int (value, AvsysMemSink->dst_height);
377 g_value_set_int (value, AvsysMemSink->rotate);
380 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
381 debug_warning ("invalid property id\n");
387 free_buffer(GstAvsysMemSink *AvsysMemSink)
389 if(AvsysMemSink->con_buf)
390 free(AvsysMemSink->con_buf);
392 if(AvsysMemSink->rot_buf)
393 free(AvsysMemSink->rot_buf);
395 if(AvsysMemSink->rsz_buf)
396 free(AvsysMemSink->rsz_buf);
398 AvsysMemSink->con_buf = NULL;
399 AvsysMemSink->rot_buf = NULL;
400 AvsysMemSink->rsz_buf = NULL;
403 static GstStateChangeReturn
404 gst_avsysmemsink_change_state (GstElement *element, GstStateChange transition)
406 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
407 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (element);
408 switch (transition) {
409 case GST_STATE_CHANGE_NULL_TO_READY:
410 debug_msg ("GST AVSYS DISPLAY SINK: NULL -> READY\n");
412 case GST_STATE_CHANGE_READY_TO_PAUSED:
413 debug_msg ("GST AVSYS DISPLAY SINK: READY -> PAUSED\n");
415 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
416 debug_msg ("GST AVSYS DISPLAY SINK: PAUSED -> PLAYING\n");
422 ret = GST_ELEMENT_CLASS(parent_class)->change_state (element, transition);
423 if (ret == GST_STATE_CHANGE_FAILURE) {
427 switch (transition) {
428 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
429 debug_msg ("GST AVSYS MEM SINK: PLAYING -> PAUSED\n");
431 case GST_STATE_CHANGE_PAUSED_TO_READY:
432 debug_msg ("GST AVSYS MEM SINK: PAUSED -> READY\n");
433 free_buffer(AvsysMemSink);
435 case GST_STATE_CHANGE_READY_TO_NULL:
436 debug_msg ("GST AVSYS MEM SINK: READY -> NULL\n");
449 gst_avsysmemsink_set_caps (GstBaseSink * bs, GstCaps * caps)
451 GstAvsysMemSink *s = GST_AVSYS_MEM_SINK (bs);
452 GstStructure *structure;
460 int bpp = 0, depth = 0;
462 structure = gst_caps_get_structure (caps, 0);
465 name = (char *) gst_structure_get_name (structure);
466 GST_DEBUG_OBJECT (s, "CAPS NAME: %s", name);
468 if (gst_structure_has_name (structure, "video/x-raw-rgb"))
472 else if (gst_structure_has_name (structure, "video/x-raw-yuv"))
477 /* get source size */
478 gst_structure_get_int (structure, "height", &height);
479 gst_structure_get_int (structure, "width", &width);
481 if (gst_structure_get_fourcc (structure, "format", &fourcc))
485 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
486 debug_warning("set format AVSYS_VIDEO_FORMAT_UYVY\n");
488 case GST_MAKE_FOURCC ('Y', 'V', '1', '6'):
489 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
490 debug_warning("set format AVSYS_VIDEO_FORMAT_YUV422\n");
492 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
493 debug_warning("set format AVSYS_VIDEO_FORMAT_YUV420\n");
495 case GST_MAKE_FOURCC ('R', 'G', 'B', ' '):
496 debug_warning("set format AVSYS_VIDEO_FORMAT_RGB565\n");
499 debug_warning("set default format AVSYS_VIDEO_FORMAT_RGB565\n");
504 if( s->src_width != width ||
505 s->src_height != height)
507 debug_warning ("DISPLAY: Video Source Changed! [%d x %d] -> [%d x %d]\n",
508 s->src_width, s->src_height, width, height);
509 s->src_changed = TRUE;
512 s->src_width = width;
513 s->src_height = height;
517 s->dst_width = width;
521 if(s->dst_height == 0)
523 s->dst_height = height;
526 debug_msg ("SRC CAPS: width:%d, height:%d \n", width, height);
530 debug_warning ("caps is NULL.\n");
539 gst_avsysmemsink_preroll (GstBaseSink * bsink, GstBuffer * buf)
541 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (bsink);
543 AvsysMemSink->src_length = GST_BUFFER_SIZE (buf);
544 debug_msg ("SRC LENGTH: %d\n", AvsysMemSink->src_length);
550 gst_avsysmemsink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
552 GstAvsysMemSink *s = GST_AVSYS_MEM_SINK (bsink);
553 gboolean res = FALSE;
555 f_size = GST_BUFFER_SIZE (buf);
556 unsigned char *dst_buf;
560 GST_DEBUG_OBJECT (s, "src format is not rgb");
561 if (s->dst_changed == TRUE)
581 s->con_buf = malloc(s->src_width * s->src_height * 4);
584 s->rot_buf = malloc(s->src_width * s->src_height * 4);
587 s->rsz_buf = malloc(s->dst_width * s->dst_height *4);
589 s->dst_changed = FALSE;
592 yuv420toargb(GST_BUFFER_DATA (buf),s->con_buf,s->src_width, s->src_height);
595 rotate_pure(s->con_buf,s->rot_buf,s->src_width, s->src_height,s->rotate,4);
596 if(s->rotate == 90 || s->rotate == 270)
598 resize_pure(s->rot_buf,s->rsz_buf,s->src_height,s->src_width,
599 s->dst_width, s->dst_height,4);
603 resize_pure(s->rot_buf,s->rsz_buf,s->src_width,s->src_height,
604 s->dst_width, s->dst_height,4);
609 resize_pure(s->con_buf,s->rsz_buf,s->src_width,s->src_height,
610 s->dst_width, s->dst_height,4);
613 /* emit signal for video-stream */
614 g_signal_emit (s,gst_avsysmemsink_signals[SIGNAL_VIDEO_STREAM],
616 s->dst_width,s->dst_height,
621 GST_DEBUG_OBJECT (s, "src format is rgb");
623 /* NOTE : video can be resized by convert plugin's set caps on running time.
624 * So, it should notice it to application through callback func.
626 g_signal_emit (s, gst_avsysmemsink_signals[SIGNAL_VIDEO_STREAM],
627 0, GST_BUFFER_DATA (buf),
628 s->src_width, s->src_height,
631 GST_DEBUG_OBJECT (s, "g_signal_emit : src_width=%d, src_height=%d, GST_BUFFER_SIZE=%d", s->src_width,s->src_height,GST_BUFFER_SIZE(buf));
633 /*check video stream callback result.*/
636 //debug_verbose("Video stream is called.\n");
644 gst_avsysmemsink_init_interfaces (GType type)
651 gst_avsysmemsink_base_init (gpointer klass)
653 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
655 gst_element_class_add_pad_template (element_class,
656 gst_static_pad_template_get (&sink_factory));
657 gst_element_class_set_details (element_class, &AvsysMemSink_details);
661 gst_avsysmemsink_class_init (GstAvsysMemSinkClass *klass)
663 GObjectClass *gobject_class = (GObjectClass*) klass;
664 GstElementClass *gstelement_class = (GstElementClass*) klass;
665 GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
668 parent_class = g_type_class_peek_parent (klass);
670 gobject_class->set_property = gst_avsysmemsink_set_property;
671 gobject_class->get_property = gst_avsysmemsink_get_property;
674 g_object_class_install_property (gobject_class, PROP_WIDTH,
675 g_param_spec_int ("width",
679 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
682 g_object_class_install_property (gobject_class, PROP_HEIGHT,
683 g_param_spec_int ("height",
687 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
689 g_object_class_install_property (gobject_class, PROP_ROTATE,
690 g_param_spec_int ("rotate",
694 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
698 * GstAvsysVideoSink::video-stream:
700 gst_avsysmemsink_signals[SIGNAL_VIDEO_STREAM] = g_signal_new (
702 G_TYPE_FROM_CLASS (klass),
707 gst_avsysmemsink_BOOLEAN__POINTER_INT_INT,
710 G_TYPE_POINTER, G_TYPE_INT, G_TYPE_INT);
712 gstelement_class->change_state = gst_avsysmemsink_change_state;
714 gstbasesink_class->set_caps = gst_avsysmemsink_set_caps;
715 gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_avsysmemsink_preroll);
716 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_avsysmemsink_show_frame);
719 GST_DEBUG_CATEGORY_INIT (avsysmemsink_debug,
722 "AV system based GStreamer Plug-in");
727 gst_avsysmemsink_init (GstAvsysMemSink *AvsysMemSink, GstAvsysMemSinkClass *klass)
730 AvsysMemSink->src_width = 0;
731 AvsysMemSink->src_height = 0;
733 AvsysMemSink->src_changed = 0;
736 AvsysMemSink->dst_width = 0;
737 AvsysMemSink->dst_height = 0;
739 AvsysMemSink->dst_changed = 0;
741 AvsysMemSink->rotate = 0;
743 AvsysMemSink->con_buf = NULL;
744 AvsysMemSink->rot_buf = NULL;
745 AvsysMemSink->rsz_buf = NULL;
747 AvsysMemSink->is_rgb = FALSE;