[0.6.244] Fix the bug that does not disconnect pad signal
[platform/core/multimedia/libmm-player.git] / src / mm_player_capture.c
1 /*
2  * libmm-player
3  *
4  * Copyright(c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0(the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <dlog.h>
29 #include "mm_player_utils.h"
30 #include "mm_player_capture.h"
31 #include "mm_player_priv.h"
32
33 #include <mm_util_type.h>
34 #include <gst/video/video-info.h>
35
36 //#define       CAPTURE_OUTPUT_DUMP     1
37 #define MM_IMG_UITL_LIBRARY_PATH PATH_LIBDIR"/libmmutil_common.so"
38 #define MM_IMGP_UITL_LIBRARY_PATH PATH_LIBDIR"/libmmutil_imgp.so"
39
40 #define IMG_UTIL_INTERFACE(_player) (((mmplayer_t *)_player)->img_util)
41
42 /*---------------------------------------------------------------------------
43 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
44 ---------------------------------------------------------------------------*/
45 static GstPadProbeReturn __mmplayer_video_capture_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
46 static int  __mmplayer_get_video_frame_from_buffer(mmplayer_t *player, GstPad *pad, GstBuffer *buffer);
47 static gpointer __mmplayer_capture_thread(gpointer data);
48 static void __csc_tiled_to_linear_crop(unsigned char *yuv420_dest, unsigned char *nv12t_src, int yuv420_width, int yuv420_height, int left, int top, int right, int bottom);
49 static int __tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos);
50 static int __mm_player_convert_NV12_tiled(mmplayer_t *player);
51 static int __mm_player_convert_NV12(mmplayer_t *player);
52 static int __mm_player_convert_I420(mmplayer_t *player);
53 static int __mm_player_convert_BGRx(mmplayer_t *player);
54 #ifdef CAPTURE_OUTPUT_DUMP
55 static void capture_output_dump(mmplayer_t *player);
56 #endif
57
58 /*===========================================================================================
59 |                                                                                                                                                                                       |
60 |  FUNCTION DEFINITIONS                                                                                                                                         |
61 |                                                                                                                                                                                       |
62 ========================================================================================== */
63
64 static int __mmplayer_init_img_util_interface(mmplayer_t *player)
65 {
66         int ret = MM_ERROR_NONE;
67         gboolean sym_ret = FALSE;
68         GModule *img_module = NULL;
69         GModule *imgp_module = NULL;
70         mm_img_util_interface_t *img_util = NULL;
71
72         MMPLAYER_FENTER();
73         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
74
75         if ((access(MM_IMG_UITL_LIBRARY_PATH, F_OK) != 0) ||
76                 (access(MM_IMGP_UITL_LIBRARY_PATH, F_OK) != 0)){
77                 LOGE("there is no img util library");
78                 return MM_ERROR_PLAYER_INTERNAL;
79         }
80
81         /* allocate new handle */
82         img_util = (mm_img_util_interface_t *)g_try_malloc0(sizeof(mm_img_util_interface_t));
83         if (!img_util) {
84                 LOGE("failed to alloc memory for image util interface");
85                 ret = MM_ERROR_OUT_OF_MEMORY;
86                 goto _INIT_FAILED;
87         }
88
89         img_module = g_module_open(MM_IMG_UITL_LIBRARY_PATH, G_MODULE_BIND_LAZY);
90         if (!img_module) {
91                 LOGE("failed to open img common module");
92                 goto _INIT_FAILED;
93         }
94
95         imgp_module = g_module_open(MM_IMGP_UITL_LIBRARY_PATH, G_MODULE_BIND_LAZY);
96         if (!imgp_module) {
97                 LOGE("failed to open imgp module");
98                 goto _INIT_FAILED;
99         }
100
101         /* find symbols */
102         sym_ret = g_module_symbol(img_module, "mm_image_create_image", (gpointer *)&img_util->create);
103         sym_ret &= g_module_symbol(img_module, "mm_image_destroy_image", (gpointer *)&img_util->destroy);
104         sym_ret &= g_module_symbol(img_module, "mm_image_get_image", (gpointer *)&img_util->get);
105         sym_ret &= g_module_symbol(img_module, "mm_image_debug_image", (gpointer *)&img_util->debug);
106         sym_ret &= g_module_symbol(imgp_module, "mm_util_rotate_image", (gpointer *)&img_util->rotate);
107         sym_ret &= g_module_symbol(imgp_module, "mm_util_convert_colorspace", (gpointer *)&img_util->convert);
108
109         if (sym_ret == FALSE || !img_util->create || !img_util->rotate) {
110                 LOGE("failed to find symbol %d %p %p", sym_ret, img_util->create, img_util->rotate);
111                 ret = MM_ERROR_PLAYER_INTERNAL;
112                 goto _INIT_FAILED;
113         }
114
115         img_util->img_module = img_module;
116         img_util->imgp_module = imgp_module;
117         player->img_util = img_util;
118
119         LOGD("image util interface handle %p", img_util);
120         return MM_ERROR_NONE;
121
122 _INIT_FAILED:
123         /* release allocated resources */
124         if (img_module) {
125                 g_module_close(img_module);
126                 img_module = NULL;
127         }
128         if (imgp_module) {
129                 g_module_close(imgp_module);
130                 imgp_module = NULL;
131         }
132
133         MMPLAYER_FREEIF(img_util);
134         return ret;
135 }
136
137 static int __mmplayer_deinit_img_util_interface(mmplayer_t *player)
138 {
139         int ret = MM_ERROR_NONE;
140         MMPLAYER_FENTER();
141         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
142
143         if (IMG_UTIL_INTERFACE(player)->img_module) {
144                 LOGD("close img common module %p", IMG_UTIL_INTERFACE(player)->img_module);
145                 if (!g_module_close(IMG_UTIL_INTERFACE(player)->img_module)) {
146                         LOGE("failed to close module");
147                         ret = MM_ERROR_PLAYER_INTERNAL;
148                 }
149         }
150
151         if (IMG_UTIL_INTERFACE(player)->imgp_module) {
152                 LOGD("close imgp module %p", IMG_UTIL_INTERFACE(player)->imgp_module);
153                 if (!g_module_close(IMG_UTIL_INTERFACE(player)->imgp_module)) {
154                         LOGE("failed to close module");
155                         ret = MM_ERROR_PLAYER_INTERNAL;
156                 }
157         }
158
159         MMPLAYER_FREEIF(IMG_UTIL_INTERFACE(player));
160         MMPLAYER_FLEAVE();
161         return ret;
162 }
163
164 int
165 _mmplayer_initialize_video_capture(mmplayer_t *player)
166 {
167         int ret = MM_ERROR_NONE;
168         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
169
170         if (__mmplayer_init_img_util_interface(player) != MM_ERROR_NONE) {
171                 LOGE("failed to initialize img util interface");
172                 return MM_ERROR_PLAYER_INTERNAL;
173         }
174
175         /* create capture mutex */
176         g_mutex_init(&player->capture_thread_mutex);
177
178         /* create capture cond */
179         g_cond_init(&player->capture_thread_cond);
180
181         player->capture_thread_exit = FALSE;
182
183         /* create video capture thread */
184         player->capture_thread =
185                         g_thread_try_new("capture_thread", __mmplayer_capture_thread, (gpointer)player, NULL);
186
187         if (!player->capture_thread) {
188                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
189                 goto ERROR;
190         }
191
192         return ret;
193
194 ERROR:
195         /* capture thread */
196         g_mutex_clear(&player->capture_thread_mutex);
197         g_cond_clear(&player->capture_thread_cond);
198         return ret;
199 }
200
201 int
202 _mmplayer_release_video_capture(mmplayer_t *player)
203 {
204         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
205         if (!IMG_UTIL_INTERFACE(player)) {
206                 LOGW("there is no allocated resource");
207                 return MM_ERROR_NONE;
208         }
209
210         __mmplayer_deinit_img_util_interface(player);
211
212         /* release capture thread */
213         MMPLAYER_CAPTURE_THREAD_LOCK(player);
214         player->capture_thread_exit = TRUE;
215         MMPLAYER_CAPTURE_THREAD_SIGNAL(player);
216         MMPLAYER_CAPTURE_THREAD_UNLOCK(player);
217
218         LOGD("waiting for capture thread exit");
219         g_thread_join(player->capture_thread);
220         g_mutex_clear(&player->capture_thread_mutex);
221         g_cond_clear(&player->capture_thread_cond);
222         LOGD("capture thread released");
223
224         return MM_ERROR_NONE;
225 }
226
227 int
228 _mmplayer_do_video_capture(MMHandleType hplayer)
229 {
230         mmplayer_t *player = (mmplayer_t *)hplayer;
231         int ret = MM_ERROR_NONE;
232         GstPad *pad = NULL;
233
234         MMPLAYER_FENTER();
235         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
236
237         if (!IMG_UTIL_INTERFACE(player)) {
238                 LOGW("video capture is not supported");
239                 return MM_ERROR_NONE;
240         }
241
242         /* capturing or not */
243         if (player->video_capture_cb_probe_id || player->capture.data
244                         || player->captured.data[0] || player->captured.data[1]) {
245                 LOGW("capturing... we can't do any more");
246                 return MM_ERROR_PLAYER_INVALID_STATE;
247         }
248         gint surface_type = 0;
249         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
250
251         /* check if video pipeline is linked or not */
252         if (!player->pipeline->videobin) {
253                 LOGW("not ready to capture");
254                 return MM_ERROR_PLAYER_INVALID_STATE;
255         }
256
257         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
258
259         if (player->state == MM_PLAYER_STATE_PLAYING) {
260                 /* register probe */
261                 player->video_capture_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
262                         __mmplayer_video_capture_probe, player, NULL);
263         } else if (player->state == MM_PLAYER_STATE_PAUSED) {
264                 // get last buffer from video sink
265                 GstSample *sample = NULL;
266
267                 gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, 5 * GST_SECOND);
268                 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "last-sample", &sample, NULL);
269
270                 if (sample) {
271                         GstBuffer *buf = gst_sample_get_buffer(sample);
272                         if (buf) {
273                                 if (__mmplayer_get_video_frame_from_buffer(player, pad, buf) != MM_ERROR_NONE)
274                                         ret = MM_ERROR_PLAYER_INTERNAL;
275                         } else {
276                                 LOGW("failed to get video frame");
277                         }
278                         gst_sample_unref(sample);
279                 }
280         } else {
281                 LOGW("invalid state(%d) to capture", player->state);
282                 ret = MM_ERROR_PLAYER_INVALID_STATE;
283         }
284
285         gst_object_unref(GST_OBJECT(pad));
286         pad = NULL;
287
288         MMPLAYER_FLEAVE();
289
290         return ret;
291 }
292
293 int
294 __mmplayer_handle_orientation(mmplayer_t *player, int orientation, int format)
295 {
296         unsigned char *src_buffer = NULL;
297         int ret = MM_ERROR_NONE;
298         mm_util_image_h src_image = NULL;
299         mm_util_image_h dst_image = NULL;
300         size_t dst_size = 0;
301         mm_util_rotate_type_e rot_enum = MM_UTIL_ROTATE_NUM;
302
303         player->capture.orientation = orientation;
304
305         if (orientation == 0) {
306                 LOGE("no need handle orientation : %d", orientation);
307                 player->capture.width = player->captured.width[0];
308                 player->capture.height = player->captured.height[0];
309                 return MM_ERROR_NONE;
310         }
311
312         src_buffer = (unsigned char *)player->capture.data;
313
314         /* convert orientation degree into enum here */
315         switch (orientation) {
316         case 90:
317                 rot_enum = MM_UTIL_ROTATE_90;
318                 break;
319         case 180:
320                 rot_enum = MM_UTIL_ROTATE_180;
321                 break;
322         case 270:
323                 rot_enum = MM_UTIL_ROTATE_270;
324                 break;
325         default:
326                 LOGE("wrong rotate value");
327                 break;
328         }
329
330         LOGD("source buffer for rotation = %p and rotation = %d", src_buffer, rot_enum);
331
332         ret = IMG_UTIL_INTERFACE(player)->create(player->captured.width[0], player->captured.height[0], format, src_buffer, (size_t)player->capture.size, &src_image);
333         if (ret != MM_ERROR_NONE) {
334                 LOGE("failed to create image");
335                 return ret;
336         }
337
338         ret = IMG_UTIL_INTERFACE(player)->rotate(src_image, rot_enum, &dst_image);
339         IMG_UTIL_INTERFACE(player)->destroy(src_image);
340         if (ret != MM_ERROR_NONE) {
341                 LOGE("failed to rotate image");
342                 return ret;
343         }
344
345         IMG_UTIL_INTERFACE(player)->debug(dst_image, NULL);
346
347         ret = IMG_UTIL_INTERFACE(player)->get(dst_image, &player->capture.width, &player->capture.height, NULL, &player->capture.data, &dst_size);
348         IMG_UTIL_INTERFACE(player)->destroy(dst_image);
349         if (ret != MM_ERROR_NONE) {
350                 LOGE("failed to get image");
351                 return ret;
352         }
353
354         free(src_buffer);
355
356         player->capture.size = (int)dst_size;
357         player->capture.orientation = orientation;
358
359         player->captured.width[0] = player->captured.stride_width[0] = player->capture.width;
360         player->captured.height[0] = player->captured.stride_height[0] = player->capture.height;
361
362         return ret;
363 }
364
365 static gpointer
366 __mmplayer_capture_thread(gpointer data)
367 {
368         mmplayer_t *player = (mmplayer_t *)data;
369         MMMessageParamType msg = {0, };
370         int orientation = 0;
371         int display_angle = 0;
372         int ret = 0;
373         int i;
374
375         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
376
377         MMPLAYER_CAPTURE_THREAD_LOCK(player);
378         while (!player->capture_thread_exit) {
379                 LOGD("capture thread started. waiting for signal");
380                 MMPLAYER_CAPTURE_THREAD_WAIT(player);
381
382                 if (player->capture_thread_exit) {
383                         LOGD("exiting capture thread");
384                         goto EXIT;
385                 }
386                 LOGD("capture thread is received signal");
387
388                 /* NOTE: Don't use MMPLAYER_CMD_LOCK() here.
389                  * Because deadlock can be happened if other player api is used in message callback.
390                  */
391                 if (player->video_cs == MM_PLAYER_COLORSPACE_NV12_TILED) {
392                         /* Colorspace conversion : NV12T-> NV12-> RGB888 */
393                         ret = __mm_player_convert_NV12_tiled(player);
394                         if (ret != MM_ERROR_NONE) {
395                                 LOGE("failed to covert NV12T");
396                                 msg.code = ret;
397                                 goto ERROR;
398                         }
399                 } else if (player->video_cs == MM_PLAYER_COLORSPACE_NV12) {
400                         ret = __mm_player_convert_NV12(player);
401                         if (ret != MM_ERROR_NONE) {
402                                 LOGE("failed to covert NV12");
403                                 msg.code = ret;
404                                 goto ERROR;
405                         }
406                 } else if (player->video_cs == MM_PLAYER_COLORSPACE_I420) {
407                         ret = __mm_player_convert_I420(player);
408                         if (ret != MM_ERROR_NONE) {
409                                 LOGE("failed to covert I420");
410                                 msg.code = ret;
411                                 goto ERROR;
412                         }
413                 } else if (player->video_cs == MM_PLAYER_COLORSPACE_BGRx) {
414                         ret = __mm_player_convert_BGRx(player);
415                         if (ret != MM_ERROR_NONE) {
416                                 LOGE("failed to covert BGRx");
417                                 msg.code = ret;
418                                 goto ERROR;
419                         }
420                 } else {
421                         LOGE("invalid format");
422                         msg.code = MM_ERROR_PLAYER_INTERNAL;
423                         goto ERROR;
424                 }
425
426                 ret = _mmplayer_get_video_angle((MMHandleType)player, &display_angle, &orientation);
427                 if (ret != MM_ERROR_NONE) {
428                         LOGE("failed to get rotation angle");
429                         goto ERROR;
430                 }
431
432                 LOGD("orientation value = %d user_angle = %d", orientation, display_angle);
433
434                 ret = __mmplayer_handle_orientation(player, orientation, MM_UTIL_COLOR_RGB24);
435                 if (ret != MM_ERROR_NONE) {
436                         LOGE("failed to convert nv12 linear");
437                         goto ERROR;
438                 }
439
440                 player->capture.fmt = MM_PLAYER_COLORSPACE_RGB888;
441                 msg.data = &player->capture;
442                 msg.size = player->capture.size;
443
444                 if (player->cmd >= MMPLAYER_COMMAND_START) {
445                         MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_CAPTURED, &msg);
446                         LOGD("returned from capture message callback");
447                 }
448
449                 continue;
450 ERROR:
451                 for (i = 0; i < player->captured.plane_num; i++)
452                         MMPLAYER_FREEIF(player->captured.data[i]);
453
454                 msg.union_type = MM_MSG_UNION_CODE;
455
456                 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_NOT_CAPTURED, &msg);
457         }
458
459 EXIT:
460         MMPLAYER_CAPTURE_THREAD_UNLOCK(player);
461         return NULL;
462 }
463
464 /**
465   * The output is fixed as RGB888
466   */
467 static int
468 __mmplayer_get_video_frame_from_buffer(mmplayer_t *player, GstPad *pad, GstBuffer *buffer)
469 {
470         gint i = 0;
471         guint plane_size = 0;
472         GstCaps *caps = NULL;
473         GstVideoFrame vframe;
474         GstVideoInfo vinfo;
475         guint8 *pixels = NULL;
476         int ret = MM_ERROR_NONE;
477
478         MMPLAYER_FENTER();
479
480         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
481         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, MM_ERROR_INVALID_ARGUMENT);
482
483         /* get fourcc */
484         caps = gst_pad_get_current_caps(pad);
485
486         MMPLAYER_RETURN_VAL_IF_FAIL(caps, MM_ERROR_INVALID_ARGUMENT);
487         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
488
489         /* init capture image buffer */
490         memset(&player->capture, 0x00, sizeof(mmplayer_video_capture_t));
491
492         gst_video_info_from_caps(&vinfo, caps);
493
494         gst_caps_unref(caps);
495
496         LOGI("captured format is %s", gst_video_format_to_string(GST_VIDEO_INFO_FORMAT(&vinfo)));
497
498         player->captured.width[0] = GST_VIDEO_INFO_WIDTH(&vinfo);
499         player->captured.height[0] = GST_VIDEO_INFO_HEIGHT(&vinfo);
500
501         switch (GST_VIDEO_INFO_FORMAT(&vinfo)) {
502         case GST_VIDEO_FORMAT_NV12:
503         case GST_VIDEO_FORMAT_SN12:
504                 player->video_cs = MM_PLAYER_COLORSPACE_NV12;
505                 player->captured.width[1] = player->captured.width[0];
506                 player->captured.height[1] = player->captured.height[0] >> 1;
507                 break;
508         case GST_VIDEO_FORMAT_I420:
509         case GST_VIDEO_FORMAT_S420:
510                 player->video_cs = MM_PLAYER_COLORSPACE_I420;
511                 player->captured.width[1] = player->captured.width[2] = player->captured.width[0] >> 1;
512                 player->captured.height[1] = player->captured.height[2] = player->captured.height[0] >> 1;
513                 break;
514         case GST_VIDEO_FORMAT_ST12:
515                 player->video_cs = MM_PLAYER_COLORSPACE_NV12_TILED;
516                 player->captured.width[1] = player->captured.width[0];
517                 player->captured.height[1] = player->captured.height[0] >> 1;
518                 break;
519         case GST_VIDEO_FORMAT_BGRx:
520                 player->video_cs = MM_PLAYER_COLORSPACE_BGRx;
521                 break;
522         default:
523                 player->video_cs = MM_PLAYER_COLORSPACE_MAX;
524                 ret = MM_ERROR_PLAYER_INTERNAL;
525                 break;
526         }
527
528         if (ret != MM_ERROR_NONE) {
529                 LOGE("unknown format to capture");
530                 return ret;
531         }
532
533         if (gst_video_frame_map(&vframe, &vinfo, buffer, GST_MAP_READ)) {
534                 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES(&vframe); i++) {
535                         player->captured.stride_width[i] = GST_VIDEO_FRAME_PLANE_STRIDE(&vframe, i);
536                         player->captured.stride_height[i] = player->captured.height[i];
537                         plane_size = player->captured.stride_width[i] * player->captured.stride_height[i];
538                         if (!plane_size) {
539                                 LOGE("invalid plane size");
540                                 gst_video_frame_unmap(&vframe);
541                                 return MM_ERROR_PLAYER_INTERNAL;
542                         }
543                         pixels = GST_VIDEO_FRAME_PLANE_DATA(&vframe, i);
544                         player->captured.data[i] = g_malloc(plane_size);
545                         memcpy(player->captured.data[i], pixels, plane_size);
546                 }
547                 player->captured.plane_num = GST_VIDEO_FRAME_N_PLANES(&vframe);
548                 gst_video_frame_unmap(&vframe);
549         }
550         /* do convert colorspace */
551         MMPLAYER_CAPTURE_THREAD_SIGNAL(player);
552
553         return ret;
554 }
555
556 static GstPadProbeReturn
557 __mmplayer_video_capture_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
558 {
559         mmplayer_t *player = (mmplayer_t *)u_data;
560         GstBuffer *buffer = NULL;
561         int ret = MM_ERROR_NONE;
562
563         MMPLAYER_RETURN_VAL_IF_FAIL(info->data, GST_PAD_PROBE_REMOVE);
564         MMPLAYER_FENTER();
565
566         buffer = gst_pad_probe_info_get_buffer(info);
567         ret = __mmplayer_get_video_frame_from_buffer(player, pad, buffer);
568         if (ret != MM_ERROR_NONE) {
569                 LOGE("failed to get video frame");
570                 return GST_PAD_PROBE_REMOVE;
571         }
572
573         /* remove probe to be called at one time */
574         if (player->video_capture_cb_probe_id) {
575                 gst_pad_remove_probe(pad, player->video_capture_cb_probe_id);
576                 player->video_capture_cb_probe_id = 0;
577         }
578
579         MMPLAYER_FLEAVE();
580
581         return GST_PAD_PROBE_OK;
582 }
583
584 static int
585 __mm_player_convert_colorspace(mmplayer_t *player, unsigned char *src_data, size_t src_size, mm_util_color_format_e src_fmt, unsigned int src_w, unsigned int src_h, mm_util_color_format_e dst_fmt)
586 {
587         int ret = MM_ERROR_NONE;
588         mm_util_image_h src_image = NULL;
589         mm_util_image_h dst_image = NULL;
590         size_t size = 0;
591
592         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_INTERNAL);
593         SECURE_LOGD("src size info. width: %d, height: %d", src_w, src_h);
594
595         ret = IMG_UTIL_INTERFACE(player)->create(src_w, src_h, src_fmt, src_data, src_size, &src_image);
596         if (ret != MM_ERROR_NONE) {
597                 LOGE("failed to create image for capture, %d", ret);
598                 return MM_ERROR_PLAYER_INTERNAL;
599         }
600
601         ret = IMG_UTIL_INTERFACE(player)->convert(src_image, dst_fmt, &dst_image);
602         IMG_UTIL_INTERFACE(player)->destroy(src_image);
603         if (ret != MM_ERROR_NONE) {
604                 LOGE("failed to convert for capture, %d", ret);
605                 return MM_ERROR_PLAYER_INTERNAL;
606         }
607         IMG_UTIL_INTERFACE(player)->debug(dst_image, NULL);
608
609         ret = IMG_UTIL_INTERFACE(player)->get(dst_image, NULL, NULL, NULL, &player->capture.data, &size);
610         IMG_UTIL_INTERFACE(player)->destroy(dst_image);
611         if (ret != MM_ERROR_NONE) {
612                 LOGE("failed to get image for capture, %d", ret);
613                 return MM_ERROR_PLAYER_INTERNAL;
614         }
615
616         player->capture.size = (int)size;
617         return MM_ERROR_NONE;
618 }
619
620 /*
621  * Get tiled address of position(x,y)
622  *
623  * @param x_size
624  *   width of tiled[in]
625  *
626  * @param y_size
627  *   height of tiled[in]
628  *
629  * @param x_pos
630  *   x position of tiled[in]
631  *
632  * @param src_size
633  *   y position of tiled[in]
634  *
635  * @return
636  *   address of tiled data
637  */
638 static int
639 __tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos)
640 {
641         int pixel_x_m1, pixel_y_m1;
642         int roundup_x;
643         int linear_addr0, linear_addr1, bank_addr ;
644         int x_addr;
645         int trans_addr;
646
647         pixel_x_m1 = x_size -1;
648         pixel_y_m1 = y_size -1;
649
650         roundup_x = ((pixel_x_m1 >> 7) + 1);
651
652         x_addr = x_pos >> 2;
653
654         if ((y_size <= y_pos+32) && (y_pos < y_size) &&
655                 (((pixel_y_m1 >> 5) & 0x1) == 0) && (((y_pos >> 5) & 0x1) == 0)) {
656                 linear_addr0 = (((y_pos & 0x1f) <<4) | (x_addr & 0xf));
657                 linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 6) & 0x3f));
658
659                 if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1))
660                         bank_addr = ((x_addr >> 4) & 0x1);
661                 else
662                         bank_addr = 0x2 | ((x_addr >> 4) & 0x1);
663         } else {
664                 linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf));
665                 linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 5) & 0x7f));
666
667                 if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1))
668                         bank_addr = ((x_addr >> 4) & 0x1);
669                 else
670                         bank_addr = 0x2 | ((x_addr >> 4) & 0x1);
671         }
672
673         linear_addr0 = linear_addr0 << 2;
674         trans_addr = (linear_addr1 <<13) | (bank_addr << 11) | linear_addr0;
675
676         return trans_addr;
677 }
678
679 /*
680  * Converts tiled data to linear
681  * Crops left, top, right, bottom
682  * 1. Y of NV12T to Y of YUV420P
683  * 2. Y of NV12T to Y of YUV420S
684  * 3. UV of NV12T to UV of YUV420S
685  *
686  * @param yuv420_dest
687  *   Y or UV plane address of YUV420[out]
688  *
689  * @param nv12t_src
690  *   Y or UV plane address of NV12T[in]
691  *
692  * @param yuv420_width
693  *   Width of YUV420[in]
694  *
695  * @param yuv420_height
696  *   Y: Height of YUV420, UV: Height/2 of YUV420[in]
697  *
698  * @param left
699  *   Crop size of left
700  *
701  * @param top
702  *   Crop size of top
703  *
704  * @param right
705  *   Crop size of right
706  *
707  * @param bottom
708  *   Crop size of bottom
709  */
710 static void
711 __csc_tiled_to_linear_crop(unsigned char *yuv420_dest, unsigned char *nv12t_src, int yuv420_width, int yuv420_height,
712                                                         int left, int top, int right, int bottom)
713 {
714         int i, j;
715         int tiled_offset = 0, tiled_offset1 = 0;
716         int linear_offset = 0;
717         int temp1 = 0, temp2 = 0, temp3 = 0, temp4 = 0;
718
719         temp3 = yuv420_width-right;
720         temp1 = temp3-left;
721         /* real width is greater than or equal 256 */
722         if (temp1 >= 256) {
723                 for (i = top; i < yuv420_height-bottom; i = i+1) {
724                         j = left;
725                         temp3 = (j >> 8) << 8;
726                         temp3 = temp3 >> 6;
727                         temp4 = i >> 5;
728                         if (temp4 & 0x1) {
729                                 /* odd formula: 2 + x + (x >> 2) << 2 + x_block_num * (y - 1) */
730                                 tiled_offset = temp4 - 1;
731                                 temp1 = ((yuv420_width + 127) >> 7) << 7;
732                                 tiled_offset = tiled_offset * (temp1 >> 6);
733                                 tiled_offset = tiled_offset + temp3;
734                                 tiled_offset = tiled_offset + 2;
735                                 temp1 = (temp3 >> 2) << 2;
736                                 tiled_offset = tiled_offset + temp1;
737                                 tiled_offset = tiled_offset << 11;
738                                 tiled_offset1 = tiled_offset + 2048 * 2;
739                                 temp4 = 8;
740                         } else {
741                                 temp2 = ((yuv420_height+31) >> 5) << 5;
742                                 if ((i + 32) < temp2) {
743                                         /* even1 formula: x + ((x + 2) >> 2) << 2 + x_block_num * y */
744                                         temp1 = temp3 + 2;
745                                         temp1 = (temp1 >> 2) << 2;
746                                         tiled_offset = temp3 + temp1;
747                                         temp1 = ((yuv420_width + 127) >> 7) << 7;
748                                         tiled_offset = tiled_offset + temp4 * (temp1 >> 6);
749                                         tiled_offset = tiled_offset << 11;
750                                         tiled_offset1 = tiled_offset + 2048 * 6;
751                                         temp4 = 8;
752                                 } else {
753                                         /* even2 formula: x + x_block_num * y */
754                                         temp1 = ((yuv420_width + 127) >> 7) << 7;
755                                         tiled_offset = temp4 * (temp1 >> 6);
756                                         tiled_offset = tiled_offset + temp3;
757                                         tiled_offset = tiled_offset << 11;
758                                         tiled_offset1 = tiled_offset + 2048 * 2;
759                                         temp4 = 4;
760                                 }
761                         }
762
763                         temp1 = i & 0x1F;
764                         tiled_offset = tiled_offset + 64 * temp1;
765                         tiled_offset1 = tiled_offset1 + 64 * temp1;
766                         temp2 = yuv420_width - left - right;
767                         linear_offset = temp2 * (i - top);
768                         temp3 = ((j + 256) >> 8) << 8;
769                         temp3 = temp3 - j;
770                         temp1 = left & 0x3F;
771                         if (temp3 > 192) {
772                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset + temp1, 64 - temp1);
773                                 memcpy(yuv420_dest + linear_offset + 64 - temp1, nv12t_src + tiled_offset + 2048, 64);
774                                 memcpy(yuv420_dest + linear_offset + 128 - temp1, nv12t_src + tiled_offset1, 64);
775                                 memcpy(yuv420_dest + linear_offset + 192 - temp1, nv12t_src + tiled_offset1 + 2048, 64);
776                                 linear_offset = linear_offset + 256 - temp1;
777                         } else if (temp3 > 128) {
778                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset + 2048 + temp1, 64 - temp1);
779                                 memcpy(yuv420_dest + linear_offset + 64 - temp1, nv12t_src + tiled_offset1, 64);
780                                 memcpy(yuv420_dest + linear_offset + 128 - temp1, nv12t_src + tiled_offset1 + 2048, 64);
781                                 linear_offset = linear_offset + 192 - temp1;
782                         } else if (temp3 > 64) {
783                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset1 + temp1, 64 - temp1);
784                                 memcpy(yuv420_dest + linear_offset + 64 - temp1, nv12t_src + tiled_offset1 + 2048, 64);
785                                 linear_offset = linear_offset + 128 - temp1;
786                         } else if (temp3 > 0) {
787                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset1 + 2048 + temp1, 64 - temp1);
788                                 linear_offset = linear_offset + 64 - temp1;
789                         }
790
791                         tiled_offset = tiled_offset + temp4 * 2048;
792                         j = (left >> 8) << 8;
793                         j = j + 256;
794                         temp2 = yuv420_width - right - 256;
795                         for (; j <= temp2; j = j + 256) {
796                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 64);
797                                 tiled_offset1 = tiled_offset1 + temp4 * 2048;
798                                 memcpy(yuv420_dest + linear_offset + 64, nv12t_src + tiled_offset + 2048, 64);
799                                 memcpy(yuv420_dest + linear_offset + 128, nv12t_src + tiled_offset1, 64);
800                                 tiled_offset = tiled_offset + temp4 * 2048;
801                                 memcpy(yuv420_dest + linear_offset + 192, nv12t_src + tiled_offset1 + 2048, 64);
802                                 linear_offset = linear_offset + 256;
803                         }
804
805                         tiled_offset1 = tiled_offset1 + temp4 * 2048;
806                         temp2 = yuv420_width - right - j;
807                         if (temp2 > 192) {
808                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 64);
809                                 memcpy(yuv420_dest + linear_offset + 64, nv12t_src + tiled_offset + 2048, 64);
810                                 memcpy(yuv420_dest + linear_offset + 128, nv12t_src + tiled_offset1, 64);
811                                 memcpy(yuv420_dest + linear_offset + 192, nv12t_src + tiled_offset1 + 2048, temp2 - 192);
812                         } else if (temp2 > 128) {
813                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 64);
814                                 memcpy(yuv420_dest + linear_offset + 64, nv12t_src + tiled_offset + 2048, 64);
815                                 memcpy(yuv420_dest + linear_offset + 128, nv12t_src + tiled_offset1, temp2 - 128);
816                         } else if (temp2 > 64) {
817                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 64);
818                                 memcpy(yuv420_dest + linear_offset + 64, nv12t_src + tiled_offset + 2048, temp2 - 64);
819                         } else {
820                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, temp2);
821                         }
822                 }
823         } else if (temp1 >= 64) {
824                 for (i = top; i < (yuv420_height - bottom); i++) {
825                         j = left;
826                         tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
827                         temp2 = ((j + 64) >> 6) << 6;
828                         temp2 = temp2 - j;
829                         linear_offset = temp1 * (i - top);
830                         temp4 = j & 0x3;
831                         tiled_offset = tiled_offset + temp4;
832                         memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, temp2);
833                         linear_offset = linear_offset + temp2;
834                         j = j + temp2;
835                         if ((j + 64) <= temp3) {
836                                 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
837                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 64);
838                                 linear_offset = linear_offset + 64;
839                                 j += 64;
840                         }
841                         if ((j + 64) <= temp3) {
842                                 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
843                                 memcpy(yuv420_dest+linear_offset, nv12t_src + tiled_offset, 64);
844                                 linear_offset = linear_offset + 64;
845                                 j += 64;
846                         }
847                         if (j < temp3) {
848                                 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
849                                 temp2 = temp3 - j;
850                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, temp2);
851                         }
852                 }
853         } else {
854                 for (i = top; i < (yuv420_height - bottom); i++) {
855                         linear_offset = temp1 * (i - top);
856                         for (j = left; j < (yuv420_width - right); j += 2) {
857                                 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
858                                 temp4 = j & 0x3;
859                                 tiled_offset = tiled_offset + temp4;
860                                 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 2);
861                                 linear_offset = linear_offset + 2;
862                         }
863                 }
864         }
865 }
866
867 #ifdef CAPTURE_OUTPUT_DUMP /* for capture output dump */
868 static void
869 capture_output_dump(mmplayer_t *player)
870 {
871         unsigned char *temp = NULL;
872         char file[100] = { 0, };
873         FILE *fp = NULL;
874         int ret = 0;
875         int i = 0, j = 0;
876
877         LOGE("capture output dump start. size = %d", player->capture.size);
878         sprintf(file, "/tmp/dec_output_dump_%dx%d.yuv", player->captured.width[0], player->captured.height[0]);
879         fp = fopen(file, "ab");
880
881         for (i = 0; i < player->captured.plane_num; i++) {
882                 temp = player->captured.data[i];
883
884                 for (j = 0; j < player->captured.height[i]; j++) {
885                         ret = fwrite(temp, player->captured.width[i], 1, fp);
886                         temp += player->captured.stride_width[i];
887                 }
888         }
889         LOGE("capture yuv dumped!! ret = %d", ret);
890         fclose(fp);
891
892         temp = (unsigned char *)player->capture.data;
893         sprintf(file, "/tmp/dec_output_dump_%dx%d.rgb", player->captured.width[0], player->captured.height[0]);
894         fp = fopen(file, "ab");
895         ret = fwrite(temp, player->capture.size, 1, fp);
896         fclose(fp);
897         LOGE("capture rgb dumped!! ret = %d", ret);
898 }
899 #endif
900
901 static int
902 __mm_player_convert_NV12_tiled(mmplayer_t *player)
903 {
904         /* Colorspace conversion : NV12T-> NV12-> RGB888 */
905         int i;
906         int ret = MM_ERROR_NONE;
907         unsigned char *src_buffer = NULL;
908         unsigned char *linear_y_plane = NULL;
909         unsigned char *linear_uv_plane = NULL;
910         guint linear_y_plane_size;
911         guint linear_uv_plane_size;
912         guint width = player->captured.width[0];
913         guint height = player->captured.height[0];
914
915         linear_y_plane_size = width * height;
916         linear_uv_plane_size = linear_y_plane_size / 2;
917
918         if (!linear_y_plane_size || !linear_uv_plane_size) {
919                 LOGE("invalid plane size");
920                 return MM_ERROR_PLAYER_INTERNAL;
921         }
922         linear_y_plane = (unsigned char *)g_malloc(linear_y_plane_size);
923         linear_uv_plane = (unsigned char *)g_malloc(linear_uv_plane_size);
924
925         /* NV12 tiled to linear */
926         __csc_tiled_to_linear_crop(linear_y_plane,
927                 player->captured.data[0], width, height, 0, 0, 0, 0);
928         __csc_tiled_to_linear_crop(linear_uv_plane,
929                 player->captured.data[1], width, height / 2, 0, 0, 0, 0);
930
931         src_buffer = (unsigned char *)g_malloc(linear_y_plane_size + linear_uv_plane_size);
932
933         memcpy(src_buffer, linear_y_plane, linear_y_plane_size);
934         memcpy(src_buffer + linear_y_plane_size, linear_uv_plane, linear_uv_plane_size);
935
936         /* NV12 linear to RGB888 */
937         ret = __mm_player_convert_colorspace(player, src_buffer, (size_t)(linear_y_plane_size + linear_uv_plane_size),
938                 MM_UTIL_COLOR_NV12, width, height, MM_UTIL_COLOR_RGB24);
939
940         MMPLAYER_FREEIF(src_buffer);
941         MMPLAYER_FREEIF(linear_y_plane);
942         MMPLAYER_FREEIF(linear_uv_plane);
943
944         for (i = 0; i < player->captured.plane_num; i++)
945                 MMPLAYER_FREEIF(player->captured.data[i]);
946
947         return ret;
948 }
949
950 static int
951 __mm_player_convert_NV12(mmplayer_t *player)
952 {
953         unsigned char *src_buffer = NULL;
954         unsigned char *p_buf = NULL;
955         unsigned char *temp = NULL;
956         int planes[MAX_BUFFER_PLANE] = {0, };
957         int ret = MM_ERROR_NONE;
958         int i, j;
959
960         /* using original width otherwise, app can't know aligned to resize */
961         planes[0] =  player->captured.stride_width[0] * player->captured.stride_height[0];
962         planes[1] = player->captured.stride_width[1] * player->captured.stride_height[1];
963         guint src_buffer_size = planes[0] + planes[1];
964
965         if (!src_buffer_size) {
966                 LOGE("invalid data size");
967                 return MM_ERROR_PLAYER_INTERNAL;
968         }
969         src_buffer = (unsigned char *)g_malloc(src_buffer_size);
970
971         p_buf = src_buffer;
972
973         temp = player->captured.data[0];
974
975         /* set Y plane */
976         for (i = 0; i < player->captured.height[0]; i++) {
977                 memcpy(p_buf, temp, player->captured.width[0]);
978                 p_buf += player->captured.width[0];
979                 temp += player->captured.stride_width[0];
980         }
981
982         temp = player->captured.data[1];
983
984         /* set UV plane*/
985         for (j = 0; j < player->captured.height[1]; j++) {
986                 memcpy(p_buf, temp, player->captured.width[1]);
987                 p_buf += player->captured.width[1];
988                 temp += player->captured.stride_width[1];
989         }
990
991         /* NV12 -> RGB888 */
992         ret = __mm_player_convert_colorspace(player, (unsigned char *)src_buffer, (size_t)src_buffer_size,
993                         MM_UTIL_COLOR_NV12, player->captured.width[0],
994                         player->captured.height[0], MM_UTIL_COLOR_RGB24);
995
996 #ifdef CAPTURE_OUTPUT_DUMP
997         capture_output_dump(player);
998 #endif
999         MMPLAYER_FREEIF(src_buffer);
1000
1001         for (i = 0; i < player->captured.plane_num; i++)
1002                 MMPLAYER_FREEIF(player->captured.data[i]);
1003
1004         return ret;
1005 }
1006
1007 static int
1008 __mm_player_convert_I420(mmplayer_t *player)
1009 {
1010         unsigned char *src_buffer = NULL;
1011         unsigned char *p_buf = NULL;
1012         unsigned char *temp = NULL;
1013         int planes[MAX_BUFFER_PLANE] = {0, };
1014         int ret = MM_ERROR_NONE;
1015         int i;
1016
1017         /* using original width otherwise, app can't know aligned to resize */
1018         planes[0] = player->captured.stride_width[0] * player->captured.stride_height[0];
1019         planes[1] = planes[2] = (player->captured.stride_width[0] >> 1)
1020                                                                 * (player->captured.stride_height[0] >> 1);
1021
1022         if (!planes[0] || !planes[1] || !planes[2]) {
1023                 LOGE("invalid plane size");
1024                 return MM_ERROR_PLAYER_INTERNAL;
1025         }
1026         src_buffer = (unsigned char *)g_malloc(planes[0] + planes[1] + planes[2]);
1027
1028         /* set Y plane */
1029         p_buf = src_buffer;
1030
1031         temp = player->captured.data[0];
1032
1033         for (i = 0; i < player->captured.height[0]; i++) {
1034                 memcpy(p_buf, temp, player->captured.width[0]);
1035                 temp += player->captured.stride_width[0];
1036                 p_buf += player->captured.width[0];
1037         }
1038
1039         /* set U plane */
1040         temp = player->captured.data[1];
1041
1042         for (i = 0; i < player->captured.height[1]; i++) {
1043                 memcpy(p_buf, temp, player->captured.width[1]);
1044                 temp += player->captured.stride_width[1];
1045                 p_buf += player->captured.width[1];
1046         }
1047
1048         /* set V plane */
1049         temp = player->captured.data[2];
1050
1051         for (i = 0; i < player->captured.height[2]; i++) {
1052                 memcpy(p_buf, temp, player->captured.width[2]);
1053                 temp += player->captured.stride_width[2];
1054                 p_buf += player->captured.width[2];
1055         }
1056
1057         /* I420 -> RGB888 */
1058         ret = __mm_player_convert_colorspace(player, (unsigned char *)src_buffer, (size_t)(planes[0] + planes[1] + planes[2]),
1059                         MM_UTIL_COLOR_I420, player->captured.width[0], player->captured.height[0], MM_UTIL_COLOR_RGB24);
1060
1061 #ifdef CAPTURE_OUTPUT_DUMP
1062         capture_output_dump(player);
1063 #endif
1064         MMPLAYER_FREEIF(src_buffer);
1065
1066         for (i = 0; i < player->captured.plane_num; i++)
1067                 MMPLAYER_FREEIF(player->captured.data[i]);
1068
1069         return ret;
1070 }
1071
1072 static int
1073 __mm_player_convert_BGRx(mmplayer_t *player)
1074 {
1075         int i;
1076         guint size;
1077         int ret = MM_ERROR_NONE;
1078         unsigned char *src_buffer = NULL;
1079
1080         size = (player->captured.stride_width[0] * player->captured.stride_height[0]);
1081
1082         if (!size) {
1083                 LOGE("invalid size");
1084                 return MM_ERROR_PLAYER_INTERNAL;
1085         }
1086         src_buffer = (unsigned char *)g_malloc(size);
1087         memcpy(src_buffer, player->captured.data[0], size);
1088
1089         /* BGRx -> RGB888 */
1090         ret = __mm_player_convert_colorspace(player, (unsigned char *)src_buffer, (size_t)size, MM_UTIL_COLOR_BGRX,
1091                         player->captured.width[0], player->captured.height[0], MM_UTIL_COLOR_RGB24);
1092
1093 #ifdef CAPTURE_OUTPUT_DUMP
1094         capture_output_dump(player);
1095 #endif
1096         MMPLAYER_FREEIF(src_buffer);
1097
1098         for (i = 0; i < player->captured.plane_num; i++)
1099                 MMPLAYER_FREEIF(player->captured.data[i]);
1100
1101         return ret;
1102 }