Add error handling for getting gst_caps
[platform/core/multimedia/libmm-imgp-gstcs.git] / gstcs / mm_util_gstcs.c
1 /*
2  * libmm-imgp-gstcs
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: YoungHun Kim <yh8004.kim@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 #include <stdbool.h>
22 #include "mm_util_gstcs_internal.h"
23 #include <gst/check/gstcheck.h>
24 #include <gst/video/video-format.h>
25
26 #define MM_UTIL_ROUND_UP_2(num) (((num)+1)&~1)
27 #define MM_UTIL_ROUND_UP_4(num) (((num)+3)&~3)
28 #define MM_UTIL_ROUND_UP_8(num) (((num)+7)&~7)
29
30 #define SAFE_UNREF_CAPS(caps)   { if (caps)     { gst_caps_unref(caps); caps = NULL; } }
31
32
33 static GstFlowReturn
34 _mm_sink_sample(GstElement * appsink, gpointer user_data)
35 {
36         GstBuffer *_buf = NULL;
37         GstSample *_sample = NULL;
38         gstreamer_s * pGstreamer_s = (gstreamer_s*) user_data;
39         _sample = gst_app_sink_pull_sample((GstAppSink*)appsink);
40         if (_sample) {
41                 _buf = gst_sample_get_buffer(_sample);
42
43                 pGstreamer_s->output_buffer = _buf;
44
45                 if (pGstreamer_s->output_buffer != NULL) {
46                         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
47                         gst_buffer_map(pGstreamer_s->output_buffer, &mapinfo, GST_MAP_READ);
48                         gstcs_debug("Create Output Buffer: GST_BUFFER_DATA: %p\t GST_BUFFER_SIZE: %zu", mapinfo.data, mapinfo.size);
49                         gst_buffer_unmap(pGstreamer_s->output_buffer, &mapinfo);
50                 } else {
51                         gstcs_error("ERROR -Input Prepare Buffer! Check createoutput buffer function");
52                 }
53         }
54
55         gst_buffer_ref(pGstreamer_s->output_buffer); /* when you want to avoid flushing */
56         gst_sample_unref(_sample);
57
58         return GST_FLOW_OK;
59 }
60
61 static gboolean
62 _mm_on_src_message(GstBus * bus, GstMessage * message, gpointer user_data)
63 {
64         gstreamer_s * pGstreamer_s = (gstreamer_s*) user_data;
65         switch (GST_MESSAGE_TYPE(message)) {
66         case GST_MESSAGE_EOS: {
67                 gstcs_debug("The source got dry");
68                 gst_app_src_end_of_stream(GST_APP_SRC(pGstreamer_s->appsrc));
69                 g_main_context_pop_thread_default(pGstreamer_s->context);
70                 g_main_loop_quit(pGstreamer_s->loop);
71                 break;
72                 }
73         case GST_MESSAGE_ERROR: {
74                 GError *err = NULL;
75                 gchar *dbg_info = NULL;
76
77                 gst_message_parse_error(message, &err, &dbg_info);
78                 gstcs_error("ERROR from element %s: %s\n", GST_OBJECT_NAME(message->src), err->message);
79                 gstcs_error("Debugging info: %s\n", (dbg_info) ? dbg_info : "none");
80                 g_error_free(err);
81                 g_free(dbg_info);
82                 g_main_context_pop_thread_default(pGstreamer_s->context);
83                 g_main_loop_quit(pGstreamer_s->loop);
84                 gstcs_debug("Quit GST_CS\n");
85                 break;
86                 }
87         default:
88                 break;
89         }
90         return TRUE;
91 }
92
93 static int _mm_get_byte_per_pixcel(mm_util_color_format_e color_format)
94 {
95         int byte_per_pixcel = 1;
96
97         switch (color_format) {
98         case MM_UTIL_COLOR_YUV420:
99         case MM_UTIL_COLOR_YUV422:
100         case MM_UTIL_COLOR_I420:
101         case MM_UTIL_COLOR_NV12:
102         case MM_UTIL_COLOR_UYVY:
103         case MM_UTIL_COLOR_YUYV:
104                 byte_per_pixcel = 1;
105                 break;
106         case MM_UTIL_COLOR_RGB16:
107                 byte_per_pixcel = 2;
108                 break;
109         case MM_UTIL_COLOR_RGB24:
110                 byte_per_pixcel = 3;
111                 break;
112         case MM_UTIL_COLOR_ARGB:
113         case MM_UTIL_COLOR_BGRA:
114         case MM_UTIL_COLOR_RGBA:
115         case MM_UTIL_COLOR_BGRX:
116                 byte_per_pixcel = 4;
117                 break;
118         default:
119                 gstcs_error("Not supported format");
120                 break;
121         }
122
123         gstcs_debug("color_format [%d] byte per pixcel [%d]", color_format, byte_per_pixcel);
124
125         return byte_per_pixcel;
126 }
127
128 static int _mm_create_pipeline(gstreamer_s* pGstreamer_s)
129 {
130         int ret = GSTCS_ERROR_NONE;
131         pGstreamer_s->pipeline = gst_pipeline_new("pipeline");
132         if (!pGstreamer_s->pipeline) {
133                 gstcs_error("pipeline could not be created. Exiting.\n");
134                 return GSTCS_ERROR_INVALID_PARAMETER;
135         }
136         pGstreamer_s->appsrc = gst_element_factory_make("appsrc" , "appsrc");
137         if (!pGstreamer_s->appsrc) {
138                 gstcs_error("appsrc could not be created. Exiting.\n");
139                 gst_object_unref(pGstreamer_s->pipeline);
140                 return GSTCS_ERROR_INVALID_PARAMETER;
141         }
142         pGstreamer_s->colorspace = gst_element_factory_make("videoconvert" , "convert");
143         if (!pGstreamer_s->colorspace) {
144                 gstcs_error("colorspace could not be created. Exiting.\n");
145                 gst_object_unref(pGstreamer_s->pipeline);
146                 return GSTCS_ERROR_INVALID_PARAMETER;
147         }
148         pGstreamer_s->videoscale = gst_element_factory_make("videoscale", "scale");
149         if (!pGstreamer_s->videoscale) {
150                 gstcs_error("videoscale could not be created. Exiting.\n");
151                 gst_object_unref(pGstreamer_s->pipeline);
152                 return GSTCS_ERROR_INVALID_PARAMETER;
153         }
154         pGstreamer_s->videoflip = gst_element_factory_make("videoflip", "flip");
155         if (!pGstreamer_s->videoflip) {
156                 gstcs_error("videoflip could not be created. Exiting.\n");
157                 gst_object_unref(pGstreamer_s->pipeline);
158                 return GSTCS_ERROR_INVALID_PARAMETER;
159         }
160         pGstreamer_s->appsink = gst_element_factory_make("appsink" , "appsink");
161         if (!pGstreamer_s->appsink) {
162                 gstcs_error("appsink could not be created. Exiting.\n");
163                 gst_object_unref(pGstreamer_s->pipeline);
164                 return GSTCS_ERROR_INVALID_PARAMETER;
165         }
166         return ret;
167 }
168
169 static void _mm_destroy_notify(gpointer data)
170 {
171         unsigned char *_data = (unsigned char *)data;
172         if (_data != NULL) {
173                 free(_data);
174                 _data = NULL;
175         }
176 }
177
178 static void
179 _mm_check_caps_format(GstCaps* caps)
180 {
181         GstStructure *caps_structure = gst_caps_get_structure(caps, 0);
182         const gchar* formatInfo = gst_structure_get_string(caps_structure, "format");
183         gstcs_debug("[%d] caps: %s", GST_IS_CAPS(caps), formatInfo);
184 }
185
186 static void
187 _mm_link_pipeline(gstreamer_s* pGstreamer_s, int value)
188 {
189         gstcs_fenter();
190
191         /* set property */
192         gst_bin_add_many(GST_BIN(pGstreamer_s->pipeline), pGstreamer_s->appsrc, pGstreamer_s->colorspace, pGstreamer_s->videoscale, pGstreamer_s->videoflip, pGstreamer_s->appsink, NULL);
193         if (!gst_element_link_many(pGstreamer_s->appsrc, pGstreamer_s->colorspace, pGstreamer_s->videoscale, pGstreamer_s->videoflip, pGstreamer_s->appsink, NULL))
194                 gstcs_error("Fail to link pipeline");
195         else
196                 gstcs_debug("Success to link pipeline");
197
198         g_object_set(G_OBJECT(pGstreamer_s->appsrc), "stream-type", 0, "format", GST_FORMAT_TIME, NULL);
199         g_object_set(pGstreamer_s->appsrc, "num-buffers", 1, NULL);
200         g_object_set(pGstreamer_s->appsrc, "is-live", TRUE, NULL); /* add because of gstreamer_s time issue */
201
202         g_object_set(pGstreamer_s->videoflip, "method", value, NULL); /* GST_VIDEO_FLIP_METHOD_IDENTITY (0): none- Identity (no rotation) (1): clockwise - Rotate clockwise 90 degrees (2): rotate-180 - Rotate 180 degrees (3): counterclockwise - Rotate counter-clockwise 90 degrees (4): horizontal-flip - Flip horizontally (5): vertical-flip - Flip vertically (6): upper-left-diagonal - Flip across upper left/lower right diagonal (7): upper-right-diagonal - Flip across upper right/lower left diagonal */
203
204         /*g_object_set(pGstreamer_s->appsink, "drop", TRUE, NULL);*/
205         g_object_set(pGstreamer_s->appsink, "emit-signals", TRUE, "sync", FALSE, NULL);
206
207         gstcs_fleave();
208 }
209
210 static GstVideoFormat _mm_get_video_format(mm_util_color_format_e color_format)
211 {
212         GstVideoFormat videoFormat = GST_VIDEO_FORMAT_UNKNOWN;
213         int _bpp = 0;
214         int _depth = 0;
215         int _red_mask = 0;
216         int _green_mask = 0;
217         int _blue_mask = 0;
218         int _alpha_mask = 0;
219         int _endianness = 0;
220
221         switch (color_format) {
222         case MM_UTIL_COLOR_YUV420:
223                 videoFormat = GST_VIDEO_FORMAT_YV12;
224                 break;
225         case MM_UTIL_COLOR_YUV422:
226                 videoFormat = GST_VIDEO_FORMAT_Y42B;
227                 break;
228         case MM_UTIL_COLOR_I420:
229                 videoFormat = GST_VIDEO_FORMAT_I420;
230                 break;
231         case MM_UTIL_COLOR_NV12:
232                 videoFormat = GST_VIDEO_FORMAT_NV12;
233                 break;
234         case MM_UTIL_COLOR_UYVY:
235                 videoFormat = GST_VIDEO_FORMAT_UYVY;
236                 break;
237         case MM_UTIL_COLOR_YUYV:
238                 videoFormat = GST_VIDEO_FORMAT_YVYU;
239                 break;
240         case MM_UTIL_COLOR_RGB16:
241                 _bpp = 16; _depth = 16; _red_mask = 63488; _green_mask = 2016; _blue_mask = 31; _endianness = 1234; _alpha_mask = 0;
242                 videoFormat = gst_video_format_from_masks(_depth, _bpp, _endianness, _red_mask, _green_mask, _blue_mask, _alpha_mask);
243                 break;
244         case MM_UTIL_COLOR_RGB24:
245                 _bpp = 24; _depth = 24; _red_mask = 16711680; _green_mask = 65280; _blue_mask = 255; _endianness = 4321; _alpha_mask = 0;
246                 videoFormat = gst_video_format_from_masks(_depth, _bpp, _endianness, _red_mask, _green_mask, _blue_mask, _alpha_mask);
247                 break;
248         case MM_UTIL_COLOR_ARGB:
249                 _bpp = 32; _depth = 32; _red_mask = 16711680; _green_mask = 65280; _blue_mask = 255; _alpha_mask = -16777216; _endianness = 4321;
250                 videoFormat = gst_video_format_from_masks(_depth, _bpp, _endianness, _red_mask, _green_mask, _blue_mask, _alpha_mask);
251                 break;
252         case MM_UTIL_COLOR_BGRA:
253                 _bpp = 32; _depth = 32; _red_mask = 65280; _green_mask = 16711680; _blue_mask = -16777216; _alpha_mask = 255; _endianness = 4321;
254                 videoFormat = gst_video_format_from_masks(_depth, _bpp, _endianness, _red_mask, _green_mask, _blue_mask, _alpha_mask);
255                 break;
256         case MM_UTIL_COLOR_RGBA:
257                 _bpp = 32; _depth = 32; _red_mask = -16777216; _green_mask = 16711680; _blue_mask = 65280; _alpha_mask = 255; _endianness = 4321;
258                 videoFormat = gst_video_format_from_masks(_depth, _bpp, _endianness, _red_mask, _green_mask, _blue_mask, _alpha_mask);
259                 break;
260         case MM_UTIL_COLOR_BGRX:
261                 _bpp = 32; _depth = 24; _red_mask = 65280; _green_mask = 16711680; _blue_mask = -16777216; _endianness = 4321; _alpha_mask = 0;
262                 videoFormat = gst_video_format_from_masks(_depth, _bpp, _endianness, _red_mask, _green_mask, _blue_mask, _alpha_mask);
263                 break;
264         default:
265                 gstcs_error("Not supported format");
266                 break;
267         }
268
269         gstcs_debug("color_format [%d], Chosen video format [%s]", color_format, gst_video_format_to_string(videoFormat));
270
271         return videoFormat;
272
273 }
274
275 static GstCaps* _mm_get_capabilities(mm_util_color_format_e color_format, unsigned int width, unsigned int height)
276 {
277         GstCaps *caps = NULL;
278         GstVideoFormat videoFormat = GST_VIDEO_FORMAT_UNKNOWN;
279
280         videoFormat = _mm_get_video_format(color_format);
281         gstcs_retvm_if(videoFormat == GST_VIDEO_FORMAT_UNKNOWN, NULL, "Unkown video format (%d)", color_format);
282
283         caps = gst_caps_new_simple("video/x-raw",
284                         "format", G_TYPE_STRING, gst_video_format_to_string(videoFormat),
285                         "framerate", GST_TYPE_FRACTION, 25, 1,
286                         "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
287                         "width", G_TYPE_INT, width,
288                         "height", G_TYPE_INT, height,
289                         "framerate", GST_TYPE_FRACTION, 1, 1,
290                         NULL);
291
292         if (caps)
293                 _mm_check_caps_format(caps);
294         else
295                 gstcs_error("caps is NULL");
296
297         return caps;
298 }
299
300 static void _mm_get_round_up_width_height(mm_util_color_format_e color_format, unsigned int width, unsigned int height, unsigned int *stride, unsigned int *elevation)
301 {
302         switch (color_format) {
303         case MM_UTIL_COLOR_YUV420:
304         case MM_UTIL_COLOR_YUV422:
305         case MM_UTIL_COLOR_I420:
306         case MM_UTIL_COLOR_NV12:
307         case MM_UTIL_COLOR_UYVY:
308         case MM_UTIL_COLOR_YUYV:
309                 *stride = width;
310                 *elevation = height;
311                 break;
312         case MM_UTIL_COLOR_RGB16:
313         case MM_UTIL_COLOR_RGB24:
314                 *stride = MM_UTIL_ROUND_UP_4(width);
315                 *elevation = MM_UTIL_ROUND_UP_2(height);
316                 break;
317         case MM_UTIL_COLOR_ARGB:
318         case MM_UTIL_COLOR_BGRA:
319         case MM_UTIL_COLOR_RGBA:
320         case MM_UTIL_COLOR_BGRX:
321                 *stride = width;
322                 *elevation = MM_UTIL_ROUND_UP_2(height);
323                 break;
324         default:
325                 gstcs_error("Not supported format");
326                 break;
327         }
328
329         gstcs_debug("color_format[%d] width[%u] height[%u] stride[%u], elevation[%u]", color_format, width, height, *stride, *elevation);
330 }
331
332 static size_t _mm_setup_image_size(mm_util_color_format_e color_format, unsigned int width, unsigned int height)
333 {
334         size_t size = 0;
335
336         gstcs_debug("color_format [%d] width [%u] height [%u]", color_format, width, height);
337
338         switch (color_format) {
339         case MM_UTIL_COLOR_YUV420:
340                 size = (MM_UTIL_ROUND_UP_4(width) * MM_UTIL_ROUND_UP_2(height) + MM_UTIL_ROUND_UP_8(width) * MM_UTIL_ROUND_UP_2(height) / 2); /* width * height *1; */
341                 break;
342         case MM_UTIL_COLOR_YUV422:
343                 size = (MM_UTIL_ROUND_UP_4(width) * height + MM_UTIL_ROUND_UP_8(width) * height); /*width * height *2; */
344                 break;
345         case MM_UTIL_COLOR_I420:
346                 size = (MM_UTIL_ROUND_UP_4(width) * MM_UTIL_ROUND_UP_2(height) + MM_UTIL_ROUND_UP_8(width) * MM_UTIL_ROUND_UP_2(height) /2); /*width * height *1.5; */
347                 break;
348         case MM_UTIL_COLOR_NV12:
349                 size = (MM_UTIL_ROUND_UP_4(width) * MM_UTIL_ROUND_UP_2(height) * 1.5); /* width * height *1.5; */
350                 break;
351         case MM_UTIL_COLOR_UYVY:
352                 size = (MM_UTIL_ROUND_UP_2(width) * 2 * height); /* width * height *2; */
353                 break;
354         case MM_UTIL_COLOR_YUYV:
355                 size = (MM_UTIL_ROUND_UP_2(width) * 2 * height); /* width * height *2; */
356                 break;
357         case MM_UTIL_COLOR_RGB16:
358                 size = (MM_UTIL_ROUND_UP_4(width) * 2 * height); /* width * height *2; */
359                 break;
360         case MM_UTIL_COLOR_RGB24:
361                 size = (MM_UTIL_ROUND_UP_4(width) * 3 * height); /* width * height *3; */
362                 break;
363         case MM_UTIL_COLOR_ARGB:
364         case MM_UTIL_COLOR_BGRA:
365         case MM_UTIL_COLOR_RGBA:
366         case MM_UTIL_COLOR_BGRX:
367                 size = width * height *4;
368                 break;
369         default:
370                 gstcs_error("Not supported format");
371                 break;
372         }
373
374
375         gstcs_debug("Image size [%zu]", size);
376
377         return size;
378 }
379
380 static int _mm_push_buffer_into_pipeline(imgp_info_s* pImgp_info, unsigned char *src, gstreamer_s * pGstreamer_s)
381 {
382         int ret = GSTCS_ERROR_NONE;
383         size_t data_size = 0;
384         GstBuffer* gst_buf = NULL;
385
386         gstcs_fenter();
387
388         gstcs_retvm_if(pGstreamer_s->pipeline == NULL, GSTCS_ERROR_INVALID_PARAMETER, "Invalid pipeline");
389
390         data_size = _mm_setup_image_size(pImgp_info->src_format, pImgp_info->src_width, pImgp_info->src_height);
391         gst_buf = gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, src, data_size, 0, data_size, NULL, NULL);
392
393         gstcs_retvm_if(gst_buf == NULL, GSTCS_ERROR_INVALID_OPERATION, "buffer is NULL");
394
395         gst_app_src_push_buffer(GST_APP_SRC(pGstreamer_s->appsrc), gst_buf); /* push buffer to pipeline */
396
397         gstcs_fleave();
398
399         return ret;
400 }
401
402 static int _mm_push_buffer_into_pipeline_new(unsigned char *src, gstreamer_s * pGstreamer_s, mm_util_color_format_e color_format, unsigned int width, unsigned int height, unsigned int stride, unsigned int elevation)
403 {
404         int ret = GSTCS_ERROR_NONE;
405         GstBuffer *gst_buf = NULL;
406         size_t src_size = 0;
407         unsigned char *data = NULL;
408
409         gstcs_fenter();
410
411         gstcs_retvm_if(pGstreamer_s->pipeline == NULL, GSTCS_ERROR_INVALID_PARAMETER, "Invalid pipeline");
412         gstcs_retvm_if((width == 0 || height == 0), GSTCS_ERROR_INVALID_PARAMETER, "Invalid width(%u) and height(%u)", width, height);
413
414         src_size = _mm_setup_image_size(color_format, stride, elevation);
415
416         int byte_per_pixcel = _mm_get_byte_per_pixcel(color_format);
417         unsigned int src_row = width * byte_per_pixcel;
418         unsigned int stride_row = stride * byte_per_pixcel;
419         unsigned int i = 0, y = 0;
420
421         data = (unsigned char *) malloc(src_size);
422         gstcs_retvm_if(data == NULL, GSTCS_ERROR_OUT_OF_MEMORY, "data is NULL");
423
424         for (y = 0; y < height; y++) {
425                 guint8 *pLine = (guint8 *) &(src[src_row * y]);
426                 for (i = 0; i < src_row; i++)
427                         data[y * stride_row + i] = pLine[i];
428                 guint8 stride_row_color = pLine[i - 1];
429                 for (i = src_row; i < stride_row; i++)
430                         data[y * stride_row + i] = stride_row_color;
431         }
432         for (y = height; y < elevation; y++) {
433                 for (i = 0; i < stride_row; i++)
434                         data[y * stride_row + i] = data[(y - 1) * stride_row + i];
435         }
436         gst_buf = gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, data, src_size, 0, src_size, data, _mm_destroy_notify);
437
438         if (gst_buf == NULL) {
439                 gstcs_error("buffer is NULL\n");
440                 GSTCS_FREE(data);
441                 return GSTCS_ERROR_INVALID_PARAMETER;
442         }
443
444         gst_app_src_push_buffer(GST_APP_SRC(pGstreamer_s->appsrc), gst_buf); /* push buffer to pipeline */
445
446         gstcs_fleave();
447
448         return ret;
449 }
450
451 static int _mm_imgp_gstcs_processing(gstreamer_s* pGstreamer_s, unsigned char *src, unsigned char **dst, imgp_info_s* pImgp_info)
452 {
453         GstBus *bus = NULL;
454         GstStateChangeReturn ret_state;
455         int ret = GSTCS_ERROR_NONE;
456         GstCaps *src_caps = NULL;
457         GstCaps *dst_caps = NULL;
458         unsigned int src_stride = 0;
459         unsigned int src_elevation = 0;
460
461         gstcs_fenter();
462
463         /*create pipeline*/
464         ret = _mm_create_pipeline(pGstreamer_s);
465         if (ret != GSTCS_ERROR_NONE) {
466                 gstcs_error("ERROR - mm_create_pipeline ");
467                 return ret;
468         }
469
470         /* Make appsink emit the "new-preroll" and "new-sample" signals. This option is by default disabled because signal emission is expensive and unneeded when the application prefers to operate in pull mode. */
471         gst_app_sink_set_emit_signals((GstAppSink*)pGstreamer_s->appsink, TRUE);
472
473         bus = gst_pipeline_get_bus(GST_PIPELINE(pGstreamer_s->pipeline));
474         gst_bus_add_watch(bus, (GstBusFunc) _mm_on_src_message, pGstreamer_s);
475         gst_object_unref(bus);
476
477         _mm_get_round_up_width_height(pImgp_info->src_format, pImgp_info->src_width, pImgp_info->src_height, &src_stride, &src_elevation);
478         _mm_get_round_up_width_height(pImgp_info->dst_format, pImgp_info->dst_width, pImgp_info->dst_height, &pImgp_info->output_stride, &pImgp_info->output_elevation);
479
480         src_caps = _mm_get_capabilities(pImgp_info->src_format, src_stride, src_elevation);
481         dst_caps = _mm_get_capabilities(pImgp_info->dst_format, pImgp_info->output_stride, pImgp_info->output_elevation);
482         if (src_caps == NULL || dst_caps == NULL) {
483                 gstcs_error("ERROR - _mm_get_capabilities ");
484                 SAFE_UNREF_CAPS(src_caps);
485                 SAFE_UNREF_CAPS(dst_caps);
486                 gst_object_unref(pGstreamer_s->pipeline);
487                 return ret;
488         }
489
490         gst_app_src_set_caps(GST_APP_SRC(pGstreamer_s->appsrc), src_caps);
491         gst_app_sink_set_caps(GST_APP_SINK(pGstreamer_s->appsink), dst_caps);
492
493         if ((pImgp_info->src_width != src_stride) || (pImgp_info->src_height != src_elevation)) {
494                 ret = _mm_push_buffer_into_pipeline_new(src, pGstreamer_s, pImgp_info->src_format, pImgp_info->src_width, pImgp_info->src_height, src_stride, src_elevation);
495         } else {
496                 ret = _mm_push_buffer_into_pipeline(pImgp_info, src, pGstreamer_s);
497         }
498
499         if (ret != GSTCS_ERROR_NONE) {
500                 gstcs_error("ERROR - mm_push_buffer_into_pipeline ");
501                 SAFE_UNREF_CAPS(src_caps);
502                 SAFE_UNREF_CAPS(dst_caps);
503                 gst_object_unref(pGstreamer_s->pipeline);
504                 return ret;
505         }
506
507         /*link pipeline*/
508         _mm_link_pipeline(pGstreamer_s, pImgp_info->angle);
509
510         /* Conecting to the new-sample signal emited by the appsink*/
511         gstcs_debug("Start G_CALLBACK(_mm_sink_sample)");
512         g_signal_connect(pGstreamer_s->appsink, "new-sample", G_CALLBACK(_mm_sink_sample), pGstreamer_s);
513         gstcs_debug("End G_CALLBACK(_mm_sink_sample)");
514
515         /* GST_STATE_PLAYING*/
516         gstcs_debug("Start GST_STATE_PLAYING");
517         ret_state = gst_element_set_state(pGstreamer_s->pipeline, GST_STATE_PLAYING);
518         gstcs_debug("End GST_STATE_PLAYING ret_state: %d", ret_state);
519
520         /*g_main_loop_run*/
521         gstcs_debug("g_main_loop_run");
522         g_main_loop_run(pGstreamer_s->loop);
523
524         gstcs_debug("Sucess GST_STATE_CHANGE");
525
526         /*GST_STATE_NULL*/
527         gst_element_set_state(pGstreamer_s->pipeline, GST_STATE_NULL);
528         gstcs_debug("End GST_STATE_NULL");
529
530         gstcs_debug("###pGstreamer_s->output_buffer### : %p", pGstreamer_s->output_buffer);
531
532         ret_state = gst_element_get_state(pGstreamer_s->pipeline, NULL, NULL, 1*GST_SECOND);
533
534         if (ret_state == GST_STATE_CHANGE_SUCCESS)
535                 gstcs_debug("GST_STATE_NULL ret_state = %d (GST_STATE_CHANGE_SUCCESS)\n", ret_state);
536         else if (ret_state == GST_STATE_CHANGE_ASYNC)
537                 gstcs_debug("GST_STATE_NULL ret_state = %d (GST_STATE_CHANGE_ASYNC)\n", ret_state);
538
539         gstcs_debug("Success gst_element_get_state\n");
540
541         SAFE_UNREF_CAPS(src_caps);
542         SAFE_UNREF_CAPS(dst_caps);
543
544         if (ret_state == GST_STATE_CHANGE_FAILURE) {
545                 gstcs_error("GST_STATE_CHANGE_FAILURE");
546         } else {
547                 if (pGstreamer_s->output_buffer != NULL) {
548                         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
549                         gst_buffer_map(pGstreamer_s->output_buffer, &mapinfo, GST_MAP_READ);
550                         size_t buffer_size = mapinfo.size;
551                         size_t calc_buffer_size = 0;
552
553                         calc_buffer_size = _mm_setup_image_size(pImgp_info->dst_format, pImgp_info->output_stride, pImgp_info->output_elevation);
554
555                         gstcs_debug("buffer size[%zu], calc[%zu]", buffer_size, calc_buffer_size);
556                         if (buffer_size != calc_buffer_size) {
557                                 gstcs_debug("Buffer size is different \n");
558                                 gstcs_debug("unref output buffer");
559                                 gst_buffer_unref(pGstreamer_s->output_buffer);
560                                 gst_object_unref(pGstreamer_s->pipeline);
561                                 pGstreamer_s->output_buffer = NULL;
562                                 return GSTCS_ERROR_INVALID_OPERATION;
563                         }
564                         gstcs_debug("pGstreamer_s->output_buffer: %p\n", pGstreamer_s->output_buffer);
565                         *dst = calloc(1, buffer_size);
566                         if (*dst == NULL) {
567                                 gstcs_error("ERROR - calloc ");
568                                 gst_buffer_unref(pGstreamer_s->output_buffer);
569                                 gst_object_unref(pGstreamer_s->pipeline);
570                                 pGstreamer_s->output_buffer = NULL;
571                                 return GSTCS_ERROR_INVALID_OPERATION;
572                         }
573
574                         memcpy(*dst, mapinfo.data, buffer_size);
575                         pImgp_info->buffer_size = buffer_size;
576                         gst_buffer_unmap(pGstreamer_s->output_buffer, &mapinfo);
577                 } else {
578                         gstcs_debug("pGstreamer_s->output_buffer is NULL");
579                 }
580         }
581         gstcs_debug("unref output buffer");
582         gst_buffer_unref(pGstreamer_s->output_buffer);
583         gst_object_unref(pGstreamer_s->pipeline);
584         pGstreamer_s->output_buffer = NULL;
585
586         gstcs_debug("dst: %p", *dst);
587         gstcs_fleave();
588
589         return ret;
590 }
591
592 static int _gstcs_create_default_thread(gstreamer_s *gstreamer)
593 {
594         gstcs_retvm_if(gstreamer == NULL, GSTCS_ERROR_INVALID_PARAMETER, "Invalid gstreamer");
595
596         gstreamer->context = g_main_context_new();
597         gstcs_retvm_if(gstreamer->context == NULL, GSTCS_ERROR_INVALID_OPERATION, "ERROR - g_main_context_new");
598
599         gstreamer->loop = g_main_loop_new(gstreamer->context, FALSE);
600         if (gstreamer->loop == NULL) {
601                 gstcs_error("ERROR - g_main_loop_new ");
602                 g_main_context_unref(gstreamer->context);
603                 return GSTCS_ERROR_INVALID_OPERATION;
604         }
605
606         g_main_context_push_thread_default(gstreamer->context);
607
608         return GSTCS_ERROR_NONE;
609 }
610
611 static int _gstcs_destroy_default_thread(gstreamer_s *gstreamer)
612 {
613         gstcs_retvm_if(gstreamer == NULL, GSTCS_ERROR_INVALID_PARAMETER, "Invalid gstreamer");
614
615         if (gstreamer->loop != NULL)
616                 g_main_loop_unref(gstreamer->loop);
617
618         if (gstreamer->context != NULL)
619                 g_main_context_unref(gstreamer->context);
620
621         return GSTCS_ERROR_NONE;
622 }
623
624 static int _gstcs_init(gstreamer_s** gstreamer)
625 {
626         static const int max_argc = 50;
627         gint argc = 0;
628         gchar** argv = NULL;
629         int i = 0;
630         int ret = GSTCS_ERROR_NONE;
631
632         argv = malloc(sizeof(gchar*) * max_argc);
633
634         gstcs_retvm_if(argv == NULL, GSTCS_ERROR_OUT_OF_MEMORY, "argv is not allocated");
635
636         memset(argv, 0, sizeof(gchar*) * max_argc);
637
638         argv[argc] = g_strdup("mmutil_gstcs");
639         if (argv[argc] == NULL) {
640                 gstcs_error("argv[%d] is not allocated", argc);
641                 ret = GSTCS_ERROR_OUT_OF_MEMORY;
642         }
643         argc++;
644         /* check disable registry scan */
645         argv[argc] = g_strdup("--gst-disable-registry-update");
646         if (argv[argc] == NULL) {
647                 gstcs_error("argv[%d] is not allocated", argc);
648                 ret = GSTCS_ERROR_OUT_OF_MEMORY;
649         }
650         argc++;
651         if (ret != GSTCS_ERROR_NONE) {
652                 for (i = 0; i < argc; i++)
653                         GSTCS_FREE(argv[i]);
654
655                 GSTCS_FREE(argv);
656                 return ret;
657         }
658
659         gst_init(&argc, &argv);
660
661         *gstreamer = g_new0(gstreamer_s, 1);
662         if (*gstreamer == NULL) {
663                 gstcs_error("gstreamer structure is not allocated");
664                 ret = GSTCS_ERROR_OUT_OF_MEMORY;
665         }
666
667         for (i = 0; i < argc; i++)
668                 GSTCS_FREE(argv[i]);
669
670         GSTCS_FREE(argv);
671         return ret;
672 }
673
674 static int _mm_imgp_gstcs(imgp_info_s* pImgp_info, unsigned char *src, unsigned char **dst)
675 {
676         gstreamer_s* pGstreamer_s;
677         int ret = GSTCS_ERROR_NONE;
678
679         /* Print debug message for inout structure */
680         gstcs_debug("src_width [%d] src_height [%d] src_format [%d] dst_width [%d] dst_height [%d] dst_format [%d] rotation [%d]",
681         pImgp_info->src_width, pImgp_info->src_height, pImgp_info->src_format, pImgp_info->dst_width, pImgp_info->dst_height, pImgp_info->dst_format, pImgp_info->angle);
682
683         /* Initialize gstreamer */
684         ret = _gstcs_init(&pGstreamer_s);
685         if (ret != GSTCS_ERROR_NONE) {
686                 gstcs_error("Error: _gstcs_new is failed");
687                 return ret;
688         }
689
690         /* Create default thread for async behavior */
691         ret = _gstcs_create_default_thread(pGstreamer_s);
692         if (ret != GSTCS_ERROR_NONE) {
693                 gstcs_error("Error: _gstcs_create_default_thread is failed");
694                 GSTCS_FREE(pGstreamer_s);
695                 return ret;
696         }
697
698         /* Do gstreamer processing */
699         ret = _mm_imgp_gstcs_processing(pGstreamer_s, src, dst, pImgp_info); /* input: buffer pointer for input image , input image format, input image width, input image height, output: buffer porinter for output image */
700
701         if (ret == GSTCS_ERROR_NONE)
702                 gstcs_debug("End _mm_imgp_gstcs_processing [dst: %p]", *dst);
703         else if (ret != GSTCS_ERROR_NONE)
704                 gstcs_error("ERROR - _mm_imgp_gstcs_processing");
705
706         /* Free resouces */
707         ret = _gstcs_destroy_default_thread(pGstreamer_s);
708         if (ret != GSTCS_ERROR_NONE)
709                 gstcs_error("Error: _gstcs_create_default_thread is failed");
710
711         GSTCS_FREE(pGstreamer_s);
712
713         return ret;
714 }
715
716 static bool _mm_imgp_check_format(mm_util_color_format_e color_format)
717 {
718         if ((color_format >= MM_UTIL_COLOR_YUV420) && (color_format <= MM_UTIL_COLOR_BGRX))
719                 return TRUE;
720
721         return FALSE;
722 }
723
724 int mm_imgp(imgp_info_s* pImgp_info, unsigned char *src, unsigned char **dst, imgp_type_e _imgp_type)
725 {
726         gstcs_retvm_if(pImgp_info == NULL, GSTCS_ERROR_INVALID_PARAMETER, "Invalid info");
727         gstcs_retvm_if(src == NULL, GSTCS_ERROR_INVALID_PARAMETER, "Invalid src");
728         gstcs_retvm_if(dst == NULL, GSTCS_ERROR_INVALID_PARAMETER, "Invalid dst");
729         gstcs_retvm_if((_imgp_type < 0 || _imgp_type > IMGP_MAX), GSTCS_ERROR_INVALID_PARAMETER, "Invalid _imgp_type[%d]", _imgp_type);
730         gstcs_retvm_if((_mm_imgp_check_format(pImgp_info->src_format) == FALSE), GSTCS_ERROR_NOT_SUPPORTED_FORMAT, "not supported src_format [%d]", pImgp_info->src_format);
731         gstcs_retvm_if((_mm_imgp_check_format(pImgp_info->dst_format) == FALSE), GSTCS_ERROR_NOT_SUPPORTED_FORMAT, "not supported dst_format [%d]", pImgp_info->dst_format);
732
733         gstcs_debug("[src %p] [dst %p]", src, dst);
734
735         return _mm_imgp_gstcs(pImgp_info, src, dst);
736 }