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 GST_DEBUG_CATEGORY_STATIC (avsysmemsink_debug);
67 static GstStaticPadTemplate sink_factory =
68 GST_STATIC_PAD_TEMPLATE ("sink",
69 GST_PAD_SINK, GST_PAD_ALWAYS,
72 "format = (fourcc){YV12}, "
73 "framerate = (fraction) [ 0, MAX ], "
74 "width = (int) [ 1, MAX ], "
75 "height = (int) [ 1, MAX ]; "
77 "format = (fourcc){I420}, "
78 "framerate = (fraction) [ 0, MAX ], "
79 "width = (int) [ 1, MAX ], "
80 "height = (int) [ 1, MAX ]; "
86 static GstElementDetails AvsysMemSink_details = {
87 "AV-system Stream callback",
89 "Stream sink for AV-System GStreamer Plug-in",
93 static guint gst_avsysmemsink_signals[LAST_SIGNAL] = { 0 };
97 #define g_marshal_value_peek_int(v) g_value_get_int (v)
98 #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
99 #else /* !G_ENABLE_DEBUG */
100 #define g_marshal_value_peek_int(v) (v)->data[0].v_int
101 #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
102 #endif /* !G_ENABLE_DEBUG */
105 #define GET_PIXEL(buf, x, y, stride) (*((unsigned char*)(buf) + (x) + (y)*(stride)))
107 #define GET_RED(Y,U,V) ((9535 * (Y - 16) + 13074 * (V - 128)) >> 13)
108 #define GET_GREEN(Y,U,V) ((9535 * (Y - 16) - 6660 * (V - 128) - 3203 * (U - 128)) >> 13 )
109 #define GET_BLUE(Y,U,V) ((9535 * (Y - 16) + 16531 * (U - 128)) >> 13 )
111 #define UCLIP(a) (((a)<0)?0:((a)>255)?255:(a))
115 yuv420toargb(unsigned char *src, unsigned char *dst, int width, int height)
121 unsigned char* pixel;
130 pU = src + (width * height) ;
131 pV = src + (width * height) + (width * height /4) ;
135 for(h = 0 ; h < height; h++)
137 for(w = 0 ; w < width; w++)
139 y = GET_PIXEL(pY,w,h,width);
140 u = GET_PIXEL(pU,w/2,h/2,width/2);
141 v = GET_PIXEL(pV,w/2,h/2,width/2);
144 g = GET_GREEN(y,u,v);
151 index = (w + (h* width)) * 4;
161 rotate_pure(unsigned char *src, unsigned char *dst, int width,int height,int angle,int bpp)
168 int src_idx, dst_idx;
170 size = width * height * bpp;
174 memcpy(dst,src,size);
178 for(org_y =0; org_y < height; org_y++)
180 for(org_x = 0; org_x < width ; org_x++)
184 new_x = height - org_y;
189 else if(angle == 180)
191 new_x = width - org_x;
192 new_y = height - org_y;
195 else if(angle == 270)
198 new_y = width - org_x;
203 g_print("Not support Rotate : %d\n",angle);
207 src_idx = org_x + (org_y * width);
208 dst_idx = new_x + (new_y * dst_width);
210 memcpy(dst + (dst_idx*bpp), src+(src_idx *bpp),bpp);
217 resize_pure(unsigned char *src, unsigned char *dst, int src_width, int src_height, int dst_width,int dst_height, int bpp)
219 float xFactor,yFactor;
226 int src_index,dst_index;
228 unsigned short *pshortSrc;
229 unsigned short *pshortDst;
233 pshortSrc = (unsigned short*)src;
234 pshortDst = (unsigned short*)dst;
237 xFactor = (float)((dst_width<<16) / src_width);
238 yFactor = (float)((dst_height<<16) / src_height);
240 for(y = 0; y < dst_height; y++)
242 for(x = 0; x < dst_width; x++)
244 org_fx = (float)((x<<16)/xFactor);
245 org_fy = (float)((y<<16)/yFactor);
247 org_x = (int)(org_fx);
248 org_y = (int)(org_fy);
250 src_index = org_x + (org_y * src_width);
251 dst_index = x + (y*dst_width);
253 memcpy(dst+(dst_index *bpp ),src+(src_index *bpp),bpp);
258 /* BOOLEAN:POINTER,INT,INT (avsysvideosink.c:1) */
260 gst_avsysmemsink_BOOLEAN__POINTER_INT_INT (GClosure *closure,
261 GValue *return_value G_GNUC_UNUSED,
262 guint n_param_values,
263 const GValue *param_values,
264 gpointer invocation_hint G_GNUC_UNUSED,
265 gpointer marshal_data)
267 typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_INT_INT) (gpointer data1,
272 register GMarshalFunc_BOOLEAN__POINTER_INT_INT callback;
273 register GCClosure *cc = (GCClosure*) closure;
274 register gpointer data1, data2;
278 g_return_if_fail (return_value != NULL);
279 g_return_if_fail (n_param_values == 4);
281 if (G_CCLOSURE_SWAP_DATA (closure))
283 data1 = closure->data;
284 data2 = g_value_peek_pointer (param_values + 0);
288 data1 = g_value_peek_pointer (param_values + 0);
289 data2 = closure->data;
291 callback = (GMarshalFunc_BOOLEAN__POINTER_INT_INT) (marshal_data ? marshal_data : cc->callback);
293 v_return = callback (data1,
294 g_marshal_value_peek_pointer (param_values + 1),
295 g_marshal_value_peek_int (param_values + 2),
296 g_marshal_value_peek_int (param_values + 3),
299 g_value_set_boolean (return_value, v_return);
302 static void gst_avsysmemsink_init_interfaces (GType type);
305 GST_BOILERPLATE_FULL (GstAvsysMemSink, gst_avsysmemsink, GstVideoSink, GST_TYPE_VIDEO_SINK, gst_avsysmemsink_init_interfaces);
309 gst_avsysmemsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
311 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (object);
316 if(AvsysMemSink->dst_width != g_value_get_int (value))
318 AvsysMemSink->dst_width = g_value_get_int (value);
319 AvsysMemSink->dst_changed = 1;
323 if(AvsysMemSink->dst_height != g_value_get_int (value))
325 AvsysMemSink->dst_height = g_value_get_int (value);
326 AvsysMemSink->dst_changed = 1;
330 if(AvsysMemSink->rotate != g_value_get_int(value))
332 AvsysMemSink->rotate = g_value_get_int(value);
333 AvsysMemSink->dst_changed = 1;
337 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
338 g_print ("invalid property id\n");
344 gst_avsysmemsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
346 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (object);
352 g_value_set_int (value, AvsysMemSink->dst_width);
355 g_value_set_int (value, AvsysMemSink->dst_height);
358 g_value_set_int (value, AvsysMemSink->rotate);
361 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
362 debug_warning ("invalid property id\n");
368 free_buffer(GstAvsysMemSink *AvsysMemSink)
370 if(AvsysMemSink->con_buf)
371 free(AvsysMemSink->con_buf);
373 if(AvsysMemSink->rot_buf)
374 free(AvsysMemSink->rot_buf);
376 if(AvsysMemSink->rsz_buf)
377 free(AvsysMemSink->rsz_buf);
379 AvsysMemSink->con_buf = NULL;
380 AvsysMemSink->rot_buf = NULL;
381 AvsysMemSink->rsz_buf = NULL;
384 static GstStateChangeReturn
385 gst_avsysmemsink_change_state (GstElement *element, GstStateChange transition)
387 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
388 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (element);
389 switch (transition) {
390 case GST_STATE_CHANGE_NULL_TO_READY:
391 debug_msg ("GST AVSYS DISPLAY SINK: NULL -> READY\n");
393 case GST_STATE_CHANGE_READY_TO_PAUSED:
394 debug_msg ("GST AVSYS DISPLAY SINK: READY -> PAUSED\n");
396 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
397 debug_msg ("GST AVSYS DISPLAY SINK: PAUSED -> PLAYING\n");
403 ret = GST_ELEMENT_CLASS(parent_class)->change_state (element, transition);
404 if (ret == GST_STATE_CHANGE_FAILURE) {
408 switch (transition) {
409 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
410 debug_msg ("GST AVSYS MEM SINK: PLAYING -> PAUSED\n");
412 case GST_STATE_CHANGE_PAUSED_TO_READY:
413 debug_msg ("GST AVSYS MEM SINK: PAUSED -> READY\n");
414 free_buffer(AvsysMemSink);
416 case GST_STATE_CHANGE_READY_TO_NULL:
417 debug_msg ("GST AVSYS MEM SINK: READY -> NULL\n");
430 gst_avsysmemsink_set_caps (GstBaseSink * bs, GstCaps * caps)
432 GstAvsysMemSink *s = GST_AVSYS_MEM_SINK (bs);
433 GstStructure *structure;
441 int bpp = 0, depth = 0;
443 structure = gst_caps_get_structure (caps, 0);
446 name = (char *) gst_structure_get_name (structure);
447 debug_msg ("CAPS NAME: %s\n", name);
449 if (gst_structure_has_name (structure, "video/x-raw-rgb"))
453 else if (gst_structure_has_name (structure, "video/x-raw-yuv"))
458 /* get source size */
459 gst_structure_get_int (structure, "height", &height);
460 gst_structure_get_int (structure, "width", &width);
462 if (gst_structure_get_fourcc (structure, "format", &fourcc))
466 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
467 debug_warning("set format AVSYS_VIDEO_FORMAT_UYVY\n");
469 case GST_MAKE_FOURCC ('Y', 'V', '1', '6'):
470 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
471 debug_warning("set format AVSYS_VIDEO_FORMAT_YUV422\n");
473 case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
474 debug_warning("set format AVSYS_VIDEO_FORMAT_YUV420\n");
476 case GST_MAKE_FOURCC ('R', 'G', 'B', ' '):
477 debug_warning("set format AVSYS_VIDEO_FORMAT_RGB565\n");
480 debug_warning("set default format AVSYS_VIDEO_FORMAT_RGB565\n");
485 if( s->src_width != width ||
486 s->src_height != height)
488 debug_warning ("DISPLAY: Video Source Changed! [%d x %d] -> [%d x %d]\n",
489 s->src_width, s->src_height, width, height);
490 s->src_changed = TRUE;
493 s->src_width = width;
494 s->src_height = height;
498 s->dst_width = width;
502 if(s->dst_height == 0)
504 s->dst_height = height;
507 debug_msg ("SRC CAPS: width:%d, height:%d \n", width, height);
511 debug_warning ("caps is NULL.\n");
520 gst_avsysmemsink_preroll (GstBaseSink * bsink, GstBuffer * buf)
522 GstAvsysMemSink *AvsysMemSink = GST_AVSYS_MEM_SINK (bsink);
524 AvsysMemSink->src_length = GST_BUFFER_SIZE (buf);
525 debug_msg ("SRC LENGTH: %d\n", AvsysMemSink->src_length);
531 gst_avsysmemsink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
533 GstAvsysMemSink *s = GST_AVSYS_MEM_SINK (bsink);
534 gboolean res = FALSE;
536 f_size = GST_BUFFER_SIZE (buf);
537 unsigned char *dst_buf;
541 if (s->dst_changed == TRUE)
561 s->con_buf = malloc(s->src_width * s->src_height * 4);
564 s->rot_buf = malloc(s->src_width * s->src_height * 4);
567 s->rsz_buf = malloc(s->dst_width * s->dst_height *4);
569 s->dst_changed = FALSE;
572 yuv420toargb(GST_BUFFER_DATA (buf),s->con_buf,s->src_width, s->src_height);
575 rotate_pure(s->con_buf,s->rot_buf,s->src_width, s->src_height,s->rotate,4);
576 if(s->rotate == 90 || s->rotate == 270)
578 resize_pure(s->rot_buf,s->rsz_buf,s->src_height,s->src_width,
579 s->dst_width, s->dst_height,4);
583 resize_pure(s->rot_buf,s->rsz_buf,s->src_width,s->src_height,
584 s->dst_width, s->dst_height,4);
589 resize_pure(s->con_buf,s->rsz_buf,s->src_width,s->src_height,
590 s->dst_width, s->dst_height,4);
593 /* emit signal for video-stream */
594 g_signal_emit (s,gst_avsysmemsink_signals[SIGNAL_VIDEO_STREAM],
596 s->dst_width,s->dst_height,
601 /* NOTE : video can be resized by convert plugin's set caps on running time.
602 * So, it should notice it to application through callback func.
604 g_signal_emit (s, gst_avsysmemsink_signals[SIGNAL_VIDEO_STREAM],
605 0, GST_BUFFER_DATA (buf),
606 s->src_width, s->src_height,
610 /*check video stream callback result.*/
613 //debug_verbose("Video stream is called.\n");
621 gst_avsysmemsink_init_interfaces (GType type)
628 gst_avsysmemsink_base_init (gpointer klass)
630 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
632 gst_element_class_add_pad_template (element_class,
633 gst_static_pad_template_get (&sink_factory));
634 gst_element_class_set_details (element_class, &AvsysMemSink_details);
638 gst_avsysmemsink_class_init (GstAvsysMemSinkClass *klass)
640 GObjectClass *gobject_class = (GObjectClass*) klass;
641 GstElementClass *gstelement_class = (GstElementClass*) klass;
642 GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
645 parent_class = g_type_class_peek_parent (klass);
647 gobject_class->set_property = gst_avsysmemsink_set_property;
648 gobject_class->get_property = gst_avsysmemsink_get_property;
651 g_object_class_install_property (gobject_class, PROP_WIDTH,
652 g_param_spec_int ("width",
656 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
659 g_object_class_install_property (gobject_class, PROP_HEIGHT,
660 g_param_spec_int ("height",
664 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
666 g_object_class_install_property (gobject_class, PROP_ROTATE,
667 g_param_spec_int ("rotate",
671 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
675 * GstAvsysVideoSink::video-stream:
677 gst_avsysmemsink_signals[SIGNAL_VIDEO_STREAM] = g_signal_new (
679 G_TYPE_FROM_CLASS (klass),
684 gst_avsysmemsink_BOOLEAN__POINTER_INT_INT,
687 G_TYPE_POINTER, G_TYPE_INT, G_TYPE_INT);
689 gstelement_class->change_state = gst_avsysmemsink_change_state;
691 gstbasesink_class->set_caps = gst_avsysmemsink_set_caps;
692 gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_avsysmemsink_preroll);
693 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_avsysmemsink_show_frame);
696 GST_DEBUG_CATEGORY_INIT (avsysmemsink_debug,
699 "AV system based GStreamer Plug-in");
704 gst_avsysmemsink_init (GstAvsysMemSink *AvsysMemSink, GstAvsysMemSinkClass *klass)
707 AvsysMemSink->src_width = 0;
708 AvsysMemSink->src_height = 0;
710 AvsysMemSink->src_changed = 0;
713 AvsysMemSink->dst_width = 0;
714 AvsysMemSink->dst_height = 0;
716 AvsysMemSink->dst_changed = 0;
718 AvsysMemSink->rotate = 0;
720 AvsysMemSink->con_buf = NULL;
721 AvsysMemSink->rot_buf = NULL;
722 AvsysMemSink->rsz_buf = NULL;
724 AvsysMemSink->is_rgb = FALSE;