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 ]; "
90 "endianness = (int)4321, "
91 "red_mask = (int)65280, "
92 "green_mask = (int)16711680, "
93 "blue_mask = (int)-16777216, "
94 "alpha_mask = (int)255, "
95 "width = (int) [ 1, MAX ], "
96 "height = (int) [ 1, MAX ], "
97 "framerate = (fraction) [ 0, MAX ]; "
102 static GstElementDetails AvsysMemSink_details = {
103 "AV-system Stream callback",
105 "Stream sink for AV-System GStreamer Plug-in",
109 static guint gst_avsysmemsink_signals[LAST_SIGNAL] = { 0 };
112 #ifdef G_ENABLE_DEBUG
113 #define g_marshal_value_peek_int(v) g_value_get_int (v)
114 #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
115 #else /* !G_ENABLE_DEBUG */
116 #define g_marshal_value_peek_int(v) (v)->data[0].v_int
117 #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
118 #endif /* !G_ENABLE_DEBUG */
121 #define GET_PIXEL(buf, x, y, stride) (*((unsigned char*)(buf) + (x) + (y)*(stride)))
123 #define GET_RED(Y,U,V) ((9535 * (Y - 16) + 13074 * (V - 128)) >> 13)
124 #define GET_GREEN(Y,U,V) ((9535 * (Y - 16) - 6660 * (V - 128) - 3203 * (U - 128)) >> 13 )
125 #define GET_BLUE(Y,U,V) ((9535 * (Y - 16) + 16531 * (U - 128)) >> 13 )
127 #define UCLIP(a) (((a)<0)?0:((a)>255)?255:(a))
131 yuv420toargb(unsigned char *src, unsigned char *dst, int width, int height)
137 unsigned char* pixel;
145 GST_DEBUG ("converting yuv420 to argb");
148 pU = src + (width * height) ;
149 pV = src + (width * height) + (width * height /4) ;
153 for(h = 0 ; h < height; h++)
155 for(w = 0 ; w < width; w++)
157 y = GET_PIXEL(pY,w,h,width);
158 u = GET_PIXEL(pU,w/2,h/2,width/2);
159 v = GET_PIXEL(pV,w/2,h/2,width/2);
162 g = GET_GREEN(y,u,v);
169 index = (w + (h* width)) * 4;
179 rotate_pure(unsigned char *src, unsigned char *dst, int width,int height,int angle,int bpp)
186 int src_idx, dst_idx;
188 size = width * height * bpp;
192 memcpy(dst,src,size);
196 for(org_y =0; org_y < height; org_y++)
198 for(org_x = 0; org_x < width ; org_x++)
202 new_x = height - org_y;
207 else if(angle == 180)
209 new_x = width - org_x;
210 new_y = height - org_y;
213 else if(angle == 270)
216 new_y = width - org_x;
221 g_print("Not support Rotate : %d\n",angle);
225 src_idx = org_x + (org_y * width);
226 dst_idx = new_x + (new_y * dst_width);
228 memcpy(dst + (dst_idx*bpp), src+(src_idx *bpp),bpp);
235 resize_pure(unsigned char *src, unsigned char *dst, int src_width, int src_height, int dst_width,int dst_height, int bpp)
237 float xFactor,yFactor;
244 int src_index,dst_index;
246 unsigned short *pshortSrc;
247 unsigned short *pshortDst;
251 pshortSrc = (unsigned short*)src;
252 pshortDst = (unsigned short*)dst;
255 xFactor = (float)((dst_width<<16) / src_width);
256 yFactor = (float)((dst_height<<16) / src_height);
258 for(y = 0; y < dst_height; y++)
260 for(x = 0; x < dst_width; x++)
262 org_fx = (float)((x<<16)/xFactor);
263 org_fy = (float)((y<<16)/yFactor);
265 org_x = (int)(org_fx);
266 org_y = (int)(org_fy);
268 src_index = org_x + (org_y * src_width);
269 dst_index = x + (y*dst_width);
271 memcpy(dst+(dst_index *bpp ),src+(src_index *bpp),bpp);
276 /* BOOLEAN:POINTER,INT,INT (avsysvideosink.c:1) */
278 gst_avsysmemsink_BOOLEAN__POINTER_INT_INT (GClosure *closure,
279 GValue *return_value G_GNUC_UNUSED,
280 guint n_param_values,
281 const GValue *param_values,
282 gpointer invocation_hint G_GNUC_UNUSED,
283 gpointer marshal_data)
285 typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_INT_INT) (gpointer data1,
290 register GMarshalFunc_BOOLEAN__POINTER_INT_INT callback;
291 register GCClosure *cc = (GCClosure*) closure;
292 register gpointer data1, data2;
296 g_return_if_fail (return_value != NULL);
297 g_return_if_fail (n_param_values == 4);
299 if (G_CCLOSURE_SWAP_DATA (closure))
301 data1 = closure->data;
302 data2 = g_value_peek_pointer (param_values + 0);
306 data1 = g_value_peek_pointer (param_values + 0);
307 data2 = closure->data;
309 callback = (GMarshalFunc_BOOLEAN__POINTER_INT_INT) (marshal_data ? marshal_data : cc->callback);
311 v_return = callback (data1,
312 g_marshal_value_peek_pointer (param_values + 1),
313 g_marshal_value_peek_int (param_values + 2),
314 g_marshal_value_peek_int (param_values + 3),
317 g_value_set_boolean (return_value, v_return);
320 static void gst_avsysmemsink_init_interfaces (GType type);
323 GST_BOILERPLATE_FULL (GstAvsysMemSink, gst_avsysmemsink, GstVideoSink, GST_TYPE_VIDEO_SINK, gst_avsysmemsink_init_interfaces);
327 gst_avsysmemsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
329 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (object);
334 if(AvsysMemSink->dst_width != g_value_get_int (value))
336 AvsysMemSink->dst_width = g_value_get_int (value);
337 AvsysMemSink->dst_changed = 1;
341 if(AvsysMemSink->dst_height != g_value_get_int (value))
343 AvsysMemSink->dst_height = g_value_get_int (value);
344 AvsysMemSink->dst_changed = 1;
348 if(AvsysMemSink->rotate != g_value_get_int(value))
350 AvsysMemSink->rotate = g_value_get_int(value);
351 AvsysMemSink->dst_changed = 1;
355 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
356 g_print ("invalid property id\n");
362 gst_avsysmemsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
364 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (object);
370 g_value_set_int (value, AvsysMemSink->dst_width);
373 g_value_set_int (value, AvsysMemSink->dst_height);
376 g_value_set_int (value, AvsysMemSink->rotate);
379 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
380 debug_warning ("invalid property id\n");
386 free_buffer(GstAvsysMemSink *AvsysMemSink)
388 if(AvsysMemSink->con_buf)
389 free(AvsysMemSink->con_buf);
391 if(AvsysMemSink->rot_buf)
392 free(AvsysMemSink->rot_buf);
394 if(AvsysMemSink->rsz_buf)
395 free(AvsysMemSink->rsz_buf);
397 AvsysMemSink->con_buf = NULL;
398 AvsysMemSink->rot_buf = NULL;
399 AvsysMemSink->rsz_buf = NULL;
402 static GstStateChangeReturn
403 gst_avsysmemsink_change_state (GstElement *element, GstStateChange transition)
405 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
406 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (element);
407 switch (transition) {
408 case GST_STATE_CHANGE_NULL_TO_READY:
409 debug_msg ("GST AVSYS DISPLAY SINK: NULL -> READY\n");
411 case GST_STATE_CHANGE_READY_TO_PAUSED:
412 debug_msg ("GST AVSYS DISPLAY SINK: READY -> PAUSED\n");
414 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
415 debug_msg ("GST AVSYS DISPLAY SINK: PAUSED -> PLAYING\n");
421 ret = GST_ELEMENT_CLASS(parent_class)->change_state (element, transition);
422 if (ret == GST_STATE_CHANGE_FAILURE) {
426 switch (transition) {
427 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
428 debug_msg ("GST AVSYS MEM SINK: PLAYING -> PAUSED\n");
430 case GST_STATE_CHANGE_PAUSED_TO_READY:
431 debug_msg ("GST AVSYS MEM SINK: PAUSED -> READY\n");
432 free_buffer(AvsysMemSink);
434 case GST_STATE_CHANGE_READY_TO_NULL:
435 debug_msg ("GST AVSYS MEM SINK: READY -> NULL\n");
448 gst_avsysmemsink_set_caps (GstBaseSink * bs, GstCaps * caps)
450 GstAvsysMemSink *s = GST_AVSYS_MEM_SINK (bs);
451 GstStructure *structure;
459 int bpp = 0, depth = 0;
461 structure = gst_caps_get_structure (caps, 0);
464 name = (char *) gst_structure_get_name (structure);
465 GST_DEBUG_OBJECT (s, "CAPS NAME: %s", name);
467 if (gst_structure_has_name (structure, "video/x-raw-rgb"))
471 else if (gst_structure_has_name (structure, "video/x-raw-yuv"))
476 /* get source size */
477 gst_structure_get_int (structure, "height", &height);
478 gst_structure_get_int (structure, "width", &width);
480 if (gst_structure_get_fourcc (structure, "format", &fourcc))
484 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
485 debug_warning("set format AVSYS_VIDEO_FORMAT_UYVY\n");
487 case GST_MAKE_FOURCC ('Y', 'V', '1', '6'):
488 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
489 debug_warning("set format AVSYS_VIDEO_FORMAT_YUV422\n");
491 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
492 debug_warning("set format AVSYS_VIDEO_FORMAT_YUV420\n");
494 case GST_MAKE_FOURCC ('R', 'G', 'B', ' '):
495 debug_warning("set format AVSYS_VIDEO_FORMAT_RGB565\n");
498 debug_warning("set default format AVSYS_VIDEO_FORMAT_RGB565\n");
503 if( s->src_width != width ||
504 s->src_height != height)
506 debug_warning ("DISPLAY: Video Source Changed! [%d x %d] -> [%d x %d]\n",
507 s->src_width, s->src_height, width, height);
508 s->src_changed = TRUE;
511 s->src_width = width;
512 s->src_height = height;
516 s->dst_width = width;
520 if(s->dst_height == 0)
522 s->dst_height = height;
525 debug_msg ("SRC CAPS: width:%d, height:%d \n", width, height);
529 debug_warning ("caps is NULL.\n");
538 gst_avsysmemsink_preroll (GstBaseSink * bsink, GstBuffer * buf)
540 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (bsink);
542 AvsysMemSink->src_length = GST_BUFFER_SIZE (buf);
543 debug_msg ("SRC LENGTH: %d\n", AvsysMemSink->src_length);
549 gst_avsysmemsink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
551 GstAvsysMemSink *s = GST_AVSYS_MEM_SINK (bsink);
552 gboolean res = FALSE;
554 f_size = GST_BUFFER_SIZE (buf);
555 unsigned char *dst_buf;
559 GST_DEBUG_OBJECT (s, "src format is not rgb");
560 if (s->dst_changed == TRUE)
580 s->con_buf = malloc(s->src_width * s->src_height * 4);
583 s->rot_buf = malloc(s->src_width * s->src_height * 4);
586 s->rsz_buf = malloc(s->dst_width * s->dst_height *4);
588 s->dst_changed = FALSE;
591 yuv420toargb(GST_BUFFER_DATA (buf),s->con_buf,s->src_width, s->src_height);
594 rotate_pure(s->con_buf,s->rot_buf,s->src_width, s->src_height,s->rotate,4);
595 if(s->rotate == 90 || s->rotate == 270)
597 resize_pure(s->rot_buf,s->rsz_buf,s->src_height,s->src_width,
598 s->dst_width, s->dst_height,4);
602 resize_pure(s->rot_buf,s->rsz_buf,s->src_width,s->src_height,
603 s->dst_width, s->dst_height,4);
608 resize_pure(s->con_buf,s->rsz_buf,s->src_width,s->src_height,
609 s->dst_width, s->dst_height,4);
612 /* emit signal for video-stream */
613 g_signal_emit (s,gst_avsysmemsink_signals[SIGNAL_VIDEO_STREAM],
615 s->dst_width,s->dst_height,
620 GST_DEBUG_OBJECT (s, "src format is rgb");
622 /* NOTE : video can be resized by convert plugin's set caps on running time.
623 * So, it should notice it to application through callback func.
625 g_signal_emit (s, gst_avsysmemsink_signals[SIGNAL_VIDEO_STREAM],
626 0, GST_BUFFER_DATA (buf),
627 s->src_width, s->src_height,
630 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));
632 /*check video stream callback result.*/
635 //debug_verbose("Video stream is called.\n");
643 gst_avsysmemsink_init_interfaces (GType type)
650 gst_avsysmemsink_base_init (gpointer klass)
652 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
654 gst_element_class_add_pad_template (element_class,
655 gst_static_pad_template_get (&sink_factory));
656 gst_element_class_set_details (element_class, &AvsysMemSink_details);
660 gst_avsysmemsink_class_init (GstAvsysMemSinkClass *klass)
662 GObjectClass *gobject_class = (GObjectClass*) klass;
663 GstElementClass *gstelement_class = (GstElementClass*) klass;
664 GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
667 parent_class = g_type_class_peek_parent (klass);
669 gobject_class->set_property = gst_avsysmemsink_set_property;
670 gobject_class->get_property = gst_avsysmemsink_get_property;
673 g_object_class_install_property (gobject_class, PROP_WIDTH,
674 g_param_spec_int ("width",
678 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
681 g_object_class_install_property (gobject_class, PROP_HEIGHT,
682 g_param_spec_int ("height",
686 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
688 g_object_class_install_property (gobject_class, PROP_ROTATE,
689 g_param_spec_int ("rotate",
693 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
697 * GstAvsysVideoSink::video-stream:
699 gst_avsysmemsink_signals[SIGNAL_VIDEO_STREAM] = g_signal_new (
701 G_TYPE_FROM_CLASS (klass),
706 gst_avsysmemsink_BOOLEAN__POINTER_INT_INT,
709 G_TYPE_POINTER, G_TYPE_INT, G_TYPE_INT);
711 gstelement_class->change_state = gst_avsysmemsink_change_state;
713 gstbasesink_class->set_caps = gst_avsysmemsink_set_caps;
714 gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_avsysmemsink_preroll);
715 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_avsysmemsink_show_frame);
718 GST_DEBUG_CATEGORY_INIT (avsysmemsink_debug,
721 "AV system based GStreamer Plug-in");
726 gst_avsysmemsink_init (GstAvsysMemSink *AvsysMemSink, GstAvsysMemSinkClass *klass)
729 AvsysMemSink->src_width = 0;
730 AvsysMemSink->src_height = 0;
732 AvsysMemSink->src_changed = 0;
735 AvsysMemSink->dst_width = 0;
736 AvsysMemSink->dst_height = 0;
738 AvsysMemSink->dst_changed = 0;
740 AvsysMemSink->rotate = 0;
742 AvsysMemSink->con_buf = NULL;
743 AvsysMemSink->rot_buf = NULL;
744 AvsysMemSink->rsz_buf = NULL;
746 AvsysMemSink->is_rgb = FALSE;