Apply tizen allocator to player
[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_imgp.h>
34 #include <gst/video/video-info.h>
35
36 //#define       CAPTURE_OUTPUT_DUMP     1
37 /*---------------------------------------------------------------------------
38 |    LOCAL VARIABLE DEFINITIONS for internal                                                            |
39 ---------------------------------------------------------------------------*/
40
41 /*---------------------------------------------------------------------------
42 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
43 ---------------------------------------------------------------------------*/
44 static GstPadProbeReturn __mmplayer_video_capture_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
45 static int  __mmplayer_get_video_frame_from_buffer(mm_player_t* player, GstPad *pad, GstBuffer *buffer);
46 static gpointer __mmplayer_capture_thread(gpointer data);
47 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 buttom);
48 static int __tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos);
49 static int __mm_player_convert_colorspace(mm_player_t* player, unsigned char* src_data, mm_util_color_format_e src_fmt, unsigned int src_w, unsigned int src_h, mm_util_color_format_e dst_fmt);
50 #ifdef CAPTURE_OUTPUT_DUMP
51 static void capture_output_dump(mm_player_t* player);
52 #endif
53
54 /*===========================================================================================
55 |                                                                                                                                                                                       |
56 |  FUNCTION DEFINITIONS                                                                                                                                         |
57 |                                                                                                                                                                                       |
58 ========================================================================================== */
59 int
60 _mmplayer_initialize_video_capture(mm_player_t* player)
61 {
62         int ret = MM_ERROR_NONE;
63         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
64         /* create capture mutex */
65         g_mutex_init(&player->capture_thread_mutex);
66
67         /* create capture cond */
68         g_cond_init(&player->capture_thread_cond);
69
70
71         player->capture_thread_exit = FALSE;
72
73         /* create video capture thread */
74         player->capture_thread =
75                         g_thread_try_new("capture_thread", __mmplayer_capture_thread, (gpointer)player, NULL);
76
77         if (!player->capture_thread) {
78                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
79                 goto ERROR;
80         }
81
82         return ret;
83
84 ERROR:
85         /* capture thread */
86         g_mutex_clear(&player->capture_thread_mutex);
87
88         g_cond_clear(&player->capture_thread_cond);
89
90         return ret;
91 }
92
93 int
94 _mmplayer_release_video_capture(mm_player_t* player)
95 {
96         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
97         /* release capture thread */
98         MMPLAYER_CAPTURE_THREAD_LOCK(player);
99         player->capture_thread_exit = TRUE;
100         MMPLAYER_CAPTURE_THREAD_SIGNAL(player);
101         MMPLAYER_CAPTURE_THREAD_UNLOCK(player);
102
103         LOGD("waitting for capture thread exit");
104         g_thread_join(player->capture_thread);
105         g_mutex_clear(&player->capture_thread_mutex);
106         g_cond_clear(&player->capture_thread_cond);
107         LOGD("capture thread released");
108
109         return MM_ERROR_NONE;
110 }
111
112 int
113 _mmplayer_do_video_capture(MMHandleType hplayer)
114 {
115         mm_player_t* player = (mm_player_t*) hplayer;
116         int ret = MM_ERROR_NONE;
117         GstPad *pad = NULL;
118
119         MMPLAYER_FENTER();
120
121         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
122
123         /* capturing or not */
124         if (player->video_capture_cb_probe_id || player->capture.data
125                         || player->captured.data[0] || player->captured.data[1]) {
126                 LOGW("capturing... we can't do any more");
127                 return MM_ERROR_PLAYER_INVALID_STATE;
128         }
129         gint surface_type = 0;
130         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
131
132         /* check if video pipeline is linked or not */
133         if (!player->pipeline->videobin) {
134                 if (surface_type == MM_DISPLAY_SURFACE_REMOTE && player->video_fakesink) {
135                         LOGD("it is evas surface type.");
136                 } else {
137                         LOGW("not ready to capture");
138                         return MM_ERROR_PLAYER_INVALID_STATE;
139                 }
140         }
141
142         if (player->pipeline->videobin)
143                 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
144         else // evas surface
145                 pad = gst_element_get_static_pad(player->video_fakesink, "sink");
146
147         if (player->state != MM_PLAYER_STATE_PLAYING) {
148                 if (player->state == MM_PLAYER_STATE_PAUSED) {
149                         // get last buffer from video sink
150                         GstSample *sample = NULL;
151
152                         gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, 5 * GST_SECOND); //5 seconds
153
154                         if (player->pipeline->videobin)
155                                 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "last-sample", &sample, NULL);
156                         else // evas surface
157                                 g_object_get(player->video_fakesink, "last-sample", &sample, NULL);
158
159                         if (sample) {
160                                 GstBuffer *buf = NULL;
161                                 buf = gst_sample_get_buffer(sample);
162                                 if (buf) {
163                                         if (__mmplayer_get_video_frame_from_buffer(player, pad, buf) != MM_ERROR_NONE)
164                                                 ret = MM_ERROR_PLAYER_INTERNAL;
165                                 } else {
166                                         LOGW("failed to get video frame");
167                                 }
168                                 gst_sample_unref(sample);
169                         }
170                         return ret;
171                 } else {
172                         LOGW("invalid state(%d) to capture", player->state);
173                         gst_object_unref(GST_OBJECT(pad));
174                         pad = NULL;
175                         return MM_ERROR_PLAYER_INVALID_STATE;
176                 }
177         }
178
179         /* register probe */
180         player->video_capture_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
181                 __mmplayer_video_capture_probe, player, NULL);
182
183         gst_object_unref(GST_OBJECT(pad));
184         pad = NULL;
185
186         MMPLAYER_FLEAVE();
187
188         return ret;
189 }
190
191 int
192 __mmplayer_handle_orientation(mm_player_t* player, int orientation, int format)
193 {
194         unsigned char *src_buffer = NULL;
195         int ret = MM_ERROR_NONE;
196         unsigned char *dst_frame = NULL;
197         unsigned int dst_width = 0;
198         unsigned int dst_height = 0;
199         size_t dst_size = 0;
200         mm_util_img_rotate_type rot_enum = MM_UTIL_ROTATE_NUM;
201
202         player->capture.orientation = orientation;
203
204         if (orientation == 90 || orientation == 270) {
205                 dst_width = player->captured.height[0];
206                 dst_height = player->captured.width[0];
207                 LOGD("interchange width & height");
208         } else if (orientation == 180) {
209                 dst_width = player->captured.width[0];
210                 dst_height = player->captured.height[0];
211         } else if (orientation == 0) {
212                 LOGE("no need handle orientation : %d", orientation);
213                 player->capture.width = player->captured.width[0];
214                 player->capture.height = player->captured.height[0];
215                 return MM_ERROR_NONE;
216         } else
217                 LOGE("wrong orientation value...");
218
219         /* height & width will be interchanged for 90 and 270 orientation */
220         LOGD("before rotation : dst_width = %d and dst_height = %d", dst_width, dst_height);
221         src_buffer = (unsigned char*)player->capture.data;
222
223         /* convert orientation degree into enum here */
224         switch (orientation) {
225         case 90:
226                 rot_enum = MM_UTIL_ROTATE_90;
227                 break;
228         case 180:
229                 rot_enum = MM_UTIL_ROTATE_180;
230                 break;
231         case 270:
232                 rot_enum = MM_UTIL_ROTATE_270;
233                 break;
234         default:
235                 LOGE("wrong rotate value");
236                 break;
237         }
238
239         LOGD("source buffer for rotation = %p and rotation = %d", src_buffer, rot_enum);
240
241         ret = mm_util_rotate_image(src_buffer,
242                         player->captured.width[0], player->captured.height[0], format, rot_enum,
243                         &dst_frame, &dst_width, &dst_height, &dst_size);
244         if (ret != MM_ERROR_NONE || !dst_frame) {
245                 LOGE("failed to do rotate image");
246                 free(dst_frame);
247                 return ret;
248         }
249
250         LOGD("after rotation same stride: dst_width = %d and dst_height = %d, dst_size = %zu", dst_width, dst_height, dst_size);
251
252         g_free(src_buffer);
253
254         player->capture.data = dst_frame;
255         player->capture.size = (int)dst_size;
256         player->capture.orientation = orientation;
257         player->capture.width = dst_width;
258         player->capture.height = dst_height;
259
260         player->captured.width[0] = player->captured.stride_width[0] = dst_width;
261         player->captured.height[0] = player->captured.stride_height[0] = dst_height;
262
263         return ret;
264 }
265
266
267 static gpointer
268 __mmplayer_capture_thread(gpointer data)
269 {
270         mm_player_t* player = (mm_player_t*) data;
271         MMMessageParamType msg = {0, };
272         unsigned char * src_buffer = NULL;
273         unsigned char * linear_y_plane = NULL;
274         unsigned char * linear_uv_plane = NULL;
275         int orientation = 0;
276         int user_angle = 0;
277         int ret = 0;
278         int planes[MAX_BUFFER_PLANE] = {0, };
279         unsigned char * p_buf = NULL;
280         unsigned char * temp = NULL;
281         int i, j;
282
283         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
284
285         MMPLAYER_CAPTURE_THREAD_LOCK(player);
286         while (!player->capture_thread_exit) {
287                 LOGD("capture thread started. waiting for signal");
288                 MMPLAYER_CAPTURE_THREAD_WAIT(player);
289
290                 if (player->capture_thread_exit) {
291                         LOGD("exiting capture thread");
292                         goto EXIT;
293                 }
294                 LOGD("capture thread is received signal");
295
296                 /* NOTE: Don't use MMPLAYER_CMD_LOCK() here.
297                  * Because deadlock can be happened if other player api is used in message callback.
298                  */
299                 if (player->video_cs == MM_PLAYER_COLORSPACE_NV12_TILED) {
300                         /* Colorspace conversion : NV12T-> NV12-> RGB888 */
301                         int ret = 0;
302                         int linear_y_plane_size;
303                         int linear_uv_plane_size;
304                         int width = player->captured.width[0];
305                         int height = player->captured.height[0];
306
307                         linear_y_plane_size = (width * height);
308                         linear_uv_plane_size = (width * height / 2);
309
310                         linear_y_plane = (unsigned char*) g_try_malloc(linear_y_plane_size);
311                         if (linear_y_plane == NULL) {
312                                 msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE;
313                                 goto ERROR;
314                         }
315
316                         linear_uv_plane = (unsigned char*) g_try_malloc(linear_uv_plane_size);
317                         if (linear_uv_plane == NULL) {
318                                 msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE;
319                                 goto ERROR;
320                         }
321                         /* NV12 tiled to linear */
322                         __csc_tiled_to_linear_crop(linear_y_plane,
323                                         player->captured.data[0], width, height, 0, 0, 0, 0);
324                         __csc_tiled_to_linear_crop(linear_uv_plane,
325                                         player->captured.data[1], width, height / 2, 0, 0, 0, 0);
326
327                         for (i = 0; i < player->captured.handle_num; i++) {
328                                 MMPLAYER_FREEIF(player->captured.data[i]);
329                         }
330
331                         src_buffer = (unsigned char*) g_try_malloc(linear_y_plane_size+linear_uv_plane_size);
332
333                         if (src_buffer == NULL) {
334                                 msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE;
335                                 goto ERROR;
336                         }
337                         memset(src_buffer, 0x00, linear_y_plane_size+linear_uv_plane_size);
338                         memcpy(src_buffer, linear_y_plane, linear_y_plane_size);
339                         memcpy(src_buffer+linear_y_plane_size, linear_uv_plane, linear_uv_plane_size);
340
341                         /* NV12 linear to RGB888 */
342                         ret = __mm_player_convert_colorspace(player, src_buffer, MM_UTIL_COLOR_NV12,
343                                 width, height, MM_UTIL_COLOR_RGB24);
344
345                         if (ret != MM_ERROR_NONE) {
346                                 LOGE("failed to convert nv12 linear");
347                                 goto ERROR;
348                         }
349                         /* clean */
350                         MMPLAYER_FREEIF(src_buffer);
351                         MMPLAYER_FREEIF(linear_y_plane);
352                         MMPLAYER_FREEIF(linear_uv_plane);
353                 } else if (MM_PLAYER_COLORSPACE_NV12 == player->video_cs) {
354                         int ret = 0;
355                         /* using original width otherwises, app can't know aligned to resize */
356                         planes[0] =  player->captured.stride_width[0] * player->captured.stride_height[0];
357                         planes[1] = player->captured.stride_width[1] * player->captured.stride_height[1];
358                         int src_buffer_size = planes[0] + planes[1];
359                         src_buffer = (unsigned char*) g_try_malloc(src_buffer_size);
360                         p_buf = src_buffer;
361
362                         if (!src_buffer_size) {
363                                 LOGE("invalid data size");
364                                 goto ERROR;
365                         }
366
367                         if (!src_buffer) {
368                                 msg.code = MM_ERROR_PLAYER_NO_FREE_SPACE;
369                                 goto ERROR;
370                         }
371
372                         memset(src_buffer, 0x00, src_buffer_size);
373
374                         temp = player->captured.data[0];
375
376                         /* set Y plane */
377                         for (i = 0; i < player->captured.height[0]; i++) {
378                                 memcpy(p_buf, temp, player->captured.width[0]);
379                                 p_buf += player->captured.width[0];
380                                 temp += player->captured.stride_width[0];
381                         }
382
383                         temp = player->captured.data[1];
384
385                         /* set UV plane*/
386                         for (j = 0; j < player->captured.height[1]; j++) {
387                                 memcpy(p_buf, temp, player->captured.width[1]);
388                                 p_buf += player->captured.width[1];
389                                 temp += player->captured.stride_width[1];
390                         }
391
392                         /* NV12 -> RGB888 */
393                         ret = __mm_player_convert_colorspace(player, (unsigned char*)src_buffer, MM_UTIL_COLOR_NV12,
394                                 player->captured.width[0], player->captured.height[0], MM_UTIL_COLOR_RGB24);
395                         if (ret != MM_ERROR_NONE) {
396                                 LOGE("failed to convert nv12 linear");
397                                 goto ERROR;
398                         }
399 #ifdef CAPTURE_OUTPUT_DUMP
400                         capture_output_dump(player);
401 #endif
402                         /* clean */
403                         MMPLAYER_FREEIF(src_buffer);
404                         /* free captured buf */
405                         for (i = 0; i < player->captured.handle_num; i++) {
406                                 MMPLAYER_FREEIF(player->captured.data[i]);
407                         }
408                 } else if (MM_PLAYER_COLORSPACE_I420 == player->video_cs) {
409                         planes[0] = player->captured.stride_width[0] * player->captured.stride_height[0];
410                         planes[1] = planes[2] = (player->captured.stride_width[0]>>1) * (player->captured.stride_height[0]>>1);
411
412                         src_buffer = (unsigned char*) g_try_malloc(player->captured.stride_width[0] * player->captured.stride_height[0]*3/2);
413                         p_buf = src_buffer;
414                         /* set Y plane */
415                         memset(p_buf, 0x00, planes[0]);
416                         temp = player->captured.data[0];
417
418                         for (i = 0; i < player->captured.height[0]; i++) {
419                                 memcpy(p_buf, temp, player->captured.width[0]);
420                                 temp += player->captured.stride_width[0];
421                                 p_buf += player->captured.width[0];
422                         }
423
424                         /* set U plane */
425                         memset(p_buf, 0x00, planes[1]);
426                         temp = player->captured.data[1];
427
428                         for (i = 0; i < player->captured.height[1]; i++) {
429                                 memcpy(p_buf, temp, player->captured.width[1]);
430                                 temp += player->captured.stride_width[1];
431                                 p_buf += player->captured.width[1];
432                         }
433
434                         /* set V plane */
435                         memset(p_buf, 0x00, planes[2]);
436                         temp = player->captured.data[2];
437
438                         for (i = 0; i < player->captured.height[2]; i++) {
439                                 memcpy(p_buf, temp, player->captured.width[2]);
440                                 temp += player->captured.stride_width[2];
441                                 p_buf += player->captured.width[2];
442                         }
443
444                         /* I420 -> RGB888 */
445                         ret = __mm_player_convert_colorspace(player, (unsigned char*)src_buffer, MM_UTIL_COLOR_I420,
446                                 player->captured.width[0], player->captured.height[0], MM_UTIL_COLOR_RGB24);
447                         if (ret != MM_ERROR_NONE) {
448                                 LOGE("failed to convert I420 linear");
449                                 goto ERROR;
450                         }
451 #ifdef CAPTURE_OUTPUT_DUMP
452                         capture_output_dump(player);
453 #endif
454                         /* clean */
455                         MMPLAYER_FREEIF(src_buffer);
456                         /* free captured buf */
457                         for (i = 0; i < player->captured.handle_num; i++) {
458                                 MMPLAYER_FREEIF(player->captured.data[i]);
459                         }
460                 }
461
462                 ret = __mmplayer_get_video_angle((MMHandleType)player, &user_angle, &orientation);
463                 if (ret != MM_ERROR_NONE) {
464                         LOGE("failed to get rotation angle");
465                         goto ERROR;
466                 }
467
468                 LOGD("orientation value = %d user_angle = %d", orientation, user_angle);
469
470                 ret = __mmplayer_handle_orientation(player, orientation, MM_UTIL_COLOR_RGB24);
471                 if (ret != MM_ERROR_NONE) {
472                         LOGE("failed to convert nv12 linear");
473                         goto ERROR;
474                 }
475
476                 player->capture.fmt = MM_PLAYER_COLORSPACE_RGB888;
477                 msg.data = &player->capture;
478                 msg.size = player->capture.size;
479 //              msg.captured_frame.width = player->capture.width;
480 //              msg.captured_frame.height = player->capture.height;
481 //              msg.captured_frame.orientation = player->capture.orientation;
482
483                 if (player->cmd >= MMPLAYER_COMMAND_START) {
484                         MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_CAPTURED, &msg);
485                         LOGD("returned from capture message callback");
486                 }
487
488                 //MMPLAYER_FREEIF(player->capture.data);
489                 continue;
490 ERROR:
491                 MMPLAYER_FREEIF(src_buffer);
492
493                 for (i = 0; i < player->captured.handle_num; i++) {
494                         MMPLAYER_FREEIF(player->captured.data[i]);
495                 }
496
497                 if (player->video_cs == MM_PLAYER_COLORSPACE_NV12_TILED) {
498                         /* clean */
499                         MMPLAYER_FREEIF(linear_y_plane);
500                         MMPLAYER_FREEIF(linear_uv_plane);
501                 }
502
503                 msg.union_type = MM_MSG_UNION_CODE;
504
505                 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_NOT_CAPTURED, &msg);
506         }
507
508 EXIT:
509         MMPLAYER_CAPTURE_THREAD_UNLOCK(player);
510         return NULL;
511 }
512
513 /**
514   * The output is fixed as RGB888
515   */
516 static int
517 __mmplayer_get_video_frame_from_buffer(mm_player_t* player, GstPad *pad, GstBuffer *buffer)
518 {
519         int ret = MM_ERROR_NONE;
520         gint size = 0;
521         gint i = 0;
522         gint src_width = 0;
523         gint src_height = 0;
524         GstCaps *caps = NULL;
525         GstStructure *structure = NULL;
526         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
527         mm_util_color_format_e src_fmt = MM_UTIL_COLOR_YUV420;
528         mm_util_color_format_e dst_fmt = MM_UTIL_COLOR_RGB24; // fixed
529
530         MMPLAYER_FENTER();
531
532         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
533         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, MM_ERROR_INVALID_ARGUMENT);
534
535         /* get fourcc */
536         caps = gst_pad_get_current_caps(pad);
537
538         MMPLAYER_RETURN_VAL_IF_FAIL(caps, MM_ERROR_INVALID_ARGUMENT);
539         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
540
541         structure = gst_caps_get_structure(caps, 0);
542         if (!structure) {
543                 LOGE("cannot get structure from caps.\n");
544                 ret = MM_ERROR_PLAYER_INTERNAL;
545                 goto ERROR;
546         }
547
548         /* init capture image buffer */
549         memset(&player->capture, 0x00, sizeof(MMPlayerVideoCapture));
550
551         gst_structure_get_int(structure, "width", &src_width);
552         gst_structure_get_int(structure, "height", &src_height);
553
554         GstVideoInfo video_info;
555         gst_video_info_from_caps(&video_info, caps);
556
557         /* check rgb or yuv */
558         if (gst_structure_has_name(structure, "video/x-raw")) {
559                 /* NV12T */
560                 const gchar *gst_format = gst_structure_get_string(structure, "format");
561
562                 if (!g_strcmp0(gst_format, "ST12"))
563                         player->video_cs = MM_PLAYER_COLORSPACE_NV12_TILED;
564                 else if (!g_strcmp0(gst_format, "S420"))
565                         player->video_cs = MM_PLAYER_COLORSPACE_I420;
566                 else if (!g_strcmp0(gst_format, "SN12"))
567                         player->video_cs = MM_PLAYER_COLORSPACE_NV12;
568                 else if (!g_strcmp0(gst_format, "BGRx"))
569                         player->video_cs = MM_PLAYER_COLORSPACE_BGRx;
570                 else
571                         player->video_cs = MM_PLAYER_COLORSPACE_MAX;
572
573                 LOGI("captured format is %s\n", gst_format);
574
575                 if (!g_strcmp0(gst_format, "ST12") || !g_strcmp0(gst_format, "SN12")
576                         || !g_strcmp0(gst_format, "S420")) {
577                         GstVideoFrame vframe;
578                         GstVideoFormat format;
579                         const GstVideoFormatInfo *finfo;
580
581                         /* get video frame info from proved buffer */
582                         format = gst_video_format_from_string(gst_format);
583                         finfo = gst_video_format_get_info(format);
584
585                         if (gst_video_frame_map(&vframe, &video_info, buffer, GST_MAP_READ)) {
586                                 for (i = 0; i < GST_VIDEO_FORMAT_INFO_N_PLANES(finfo); i++) {
587                                         player->captured.width[i] = GST_VIDEO_FRAME_PLANE_STRIDE(&vframe, i);
588                                         player->captured.height[i] = GST_VIDEO_FRAME_COMP_HEIGHT(&vframe, i);
589                                         player->captured.stride_width[i] = GST_VIDEO_FRAME_PLANE_STRIDE(&vframe, i);
590                                         player->captured.stride_height[i] = GST_VIDEO_FRAME_COMP_HEIGHT(&vframe, i);
591                                         size = player->captured.stride_width[i] * player->captured.stride_height[i];
592                                         guint8 *pixels = GST_VIDEO_FRAME_PLANE_DATA(&vframe, i);
593
594                                         player->captured.data[i] = g_try_malloc(size);
595                                         if (!player->captured.data[i]) {
596                                                 gst_video_frame_unmap(&vframe);
597                                                 LOGE("no free space\n");
598                                                 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
599                                                 goto ERROR;
600                                         }
601                                         memcpy(player->captured.data[i], pixels, size);
602                                 }
603                                 gst_video_frame_unmap(&vframe);
604                         }
605                         goto DONE;
606                 } else {
607                         player->captured.width[0] = src_width;
608                         player->captured.height[0] = src_height;
609                         player->captured.stride_width[0] = MM_ALIGN(src_width, 4);
610                         player->captured.stride_height[0] = src_height;
611
612                         switch (GST_VIDEO_INFO_FORMAT(&video_info)) {
613                         case GST_VIDEO_FORMAT_I420:
614                                 src_fmt = MM_UTIL_COLOR_I420;
615                                 player->captured.width[1] = player->captured.width[2] = src_width>>1;
616                                 player->captured.height[1] = player->captured.width[2] = src_height>>1;
617                                 player->captured.stride_width[1] = player->captured.stride_width[2] = MM_ALIGN(player->captured.width[1], 4);
618                                 player->captured.stride_height[1] = player->captured.stride_height[2] = src_height>>1;
619                                 break;
620                         case GST_VIDEO_FORMAT_BGRA:
621                                 src_fmt = MM_UTIL_COLOR_BGRA;
622                                 break;
623                         case GST_VIDEO_FORMAT_BGRx:
624                                 src_fmt = MM_UTIL_COLOR_BGRX;
625                                 break;
626                         default:
627                                 LOGE("unknown format to capture\n");
628                                 ret = MM_ERROR_PLAYER_INTERNAL;
629                                 goto ERROR;
630                                 break;
631                         }
632                 }
633         } else {
634                 LOGE("unknown format to capture\n");
635                 ret = MM_ERROR_PLAYER_INTERNAL;
636                 goto ERROR;
637         }
638
639         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
640         __mm_player_convert_colorspace(player, mapinfo.data, src_fmt, src_width, src_height, dst_fmt);
641         gst_buffer_unmap(buffer, &mapinfo);
642
643 DONE:
644         /* do convert colorspace */
645         MMPLAYER_CAPTURE_THREAD_SIGNAL(player);
646
647         if (caps) {
648                 gst_caps_unref(caps);
649                 caps = NULL;
650         }
651
652         return ret;
653
654 ERROR:
655
656         if (caps) {
657                 gst_caps_unref(caps);
658                 caps = NULL;
659         }
660
661         for (i = 0; i < player->captured.handle_num; i++) {
662                 MMPLAYER_FREEIF(player->captured.data[i]);
663         }
664
665         MMPLAYER_FLEAVE();
666         return ret;
667 }
668
669 static GstPadProbeReturn
670 __mmplayer_video_capture_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
671 {
672         mm_player_t* player = (mm_player_t*) u_data;
673         GstBuffer *buffer = NULL;
674         int ret = MM_ERROR_NONE;
675
676         MMPLAYER_RETURN_VAL_IF_FAIL(info->data, GST_PAD_PROBE_REMOVE);
677         MMPLAYER_FENTER();
678
679         buffer = gst_pad_probe_info_get_buffer(info);
680         ret = __mmplayer_get_video_frame_from_buffer(player, pad, buffer);
681
682         if (ret != MM_ERROR_NONE) {
683                 LOGE("failed to get video frame");
684                 return GST_PAD_PROBE_REMOVE;
685         }
686
687         /* remove probe to be called at one time */
688         if (player->video_capture_cb_probe_id) {
689                 gst_pad_remove_probe(pad, player->video_capture_cb_probe_id);
690                 player->video_capture_cb_probe_id = 0;
691         }
692
693         MMPLAYER_FLEAVE();
694
695         return GST_PAD_PROBE_OK;
696 }
697
698 static int
699 __mm_player_convert_colorspace(mm_player_t* player, unsigned char* src_data, mm_util_color_format_e src_fmt, unsigned int src_w, unsigned int src_h, mm_util_color_format_e dst_fmt)
700 {
701         unsigned char *dst_data = NULL;
702         unsigned int dst_width = 0;
703         unsigned int dst_height = 0;
704         size_t dst_size = 0;
705         int ret = MM_ERROR_NONE;
706
707         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_INTERNAL);
708         SECURE_LOGD("src size info. width: %d, height: %d \n", src_w, src_h);
709
710         ret = mm_util_convert_colorspace(src_data, src_w, src_h, src_fmt, dst_fmt, &dst_data, &dst_width, &dst_height, &dst_size);
711         if (ret != MM_ERROR_NONE || !dst_data) {
712                 LOGE("failed to convert for capture, %d\n", ret);
713                 g_free(dst_data);
714                 return MM_ERROR_PLAYER_INTERNAL;
715         }
716         SECURE_LOGD("dst size info. width: %d, height: %d, size: %zu\n", dst_width, dst_height, dst_size);
717
718         player->capture.size = (int)dst_size;
719         player->capture.data = dst_data;
720
721         return MM_ERROR_NONE;
722 }
723
724 /*
725  * Get tiled address of position(x,y)
726  *
727  * @param x_size
728  *   width of tiled[in]
729  *
730  * @param y_size
731  *   height of tiled[in]
732  *
733  * @param x_pos
734  *   x position of tield[in]
735  *
736  * @param src_size
737  *   y position of tield[in]
738  *
739  * @return
740  *   address of tiled data
741  */
742 static int
743 __tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos)
744 {
745         int pixel_x_m1, pixel_y_m1;
746         int roundup_x;
747         int linear_addr0, linear_addr1, bank_addr ;
748         int x_addr;
749         int trans_addr;
750
751         pixel_x_m1 = x_size -1;
752         pixel_y_m1 = y_size -1;
753
754         roundup_x = ((pixel_x_m1 >> 7) + 1);
755
756         x_addr = x_pos >> 2;
757
758         if ((y_size <= y_pos+32) && (y_pos < y_size) &&
759                 (((pixel_y_m1 >> 5) & 0x1) == 0) && (((y_pos >> 5) & 0x1) == 0)) {
760                 linear_addr0 = (((y_pos & 0x1f) <<4) | (x_addr & 0xf));
761                 linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x +((x_addr >> 6) & 0x3f));
762
763                 if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1))
764                         bank_addr = ((x_addr >> 4) & 0x1);
765                 else
766                         bank_addr = 0x2 | ((x_addr >> 4) & 0x1);
767         } else {
768                 linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf));
769                 linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x +((x_addr >> 5) & 0x7f));
770
771                 if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1))
772                         bank_addr = ((x_addr >> 4) & 0x1);
773                 else
774                         bank_addr = 0x2 | ((x_addr >> 4) & 0x1);
775         }
776
777         linear_addr0 = linear_addr0 << 2;
778         trans_addr = (linear_addr1 <<13) | (bank_addr << 11) | linear_addr0;
779
780         return trans_addr;
781 }
782
783 /*
784  * Converts tiled data to linear
785  * Crops left, top, right, buttom
786  * 1. Y of NV12T to Y of YUV420P
787  * 2. Y of NV12T to Y of YUV420S
788  * 3. UV of NV12T to UV of YUV420S
789  *
790  * @param yuv420_dest
791  *   Y or UV plane address of YUV420[out]
792  *
793  * @param nv12t_src
794  *   Y or UV plane address of NV12T[in]
795  *
796  * @param yuv420_width
797  *   Width of YUV420[in]
798  *
799  * @param yuv420_height
800  *   Y: Height of YUV420, UV: Height/2 of YUV420[in]
801  *
802  * @param left
803  *   Crop size of left
804  *
805  * @param top
806  *   Crop size of top
807  *
808  * @param right
809  *   Crop size of right
810  *
811  * @param buttom
812  *   Crop size of buttom
813  */
814 static void
815 __csc_tiled_to_linear_crop(unsigned char *yuv420_dest, unsigned char *nv12t_src, int yuv420_width, int yuv420_height,
816                                                         int left, int top, int right, int buttom)
817 {
818         int i, j;
819         int tiled_offset = 0, tiled_offset1 = 0;
820         int linear_offset = 0;
821         int temp1 = 0, temp2 = 0, temp3 = 0, temp4 = 0;
822
823         temp3 = yuv420_width-right;
824         temp1 = temp3-left;
825         /* real width is greater than or equal 256 */
826         if (temp1 >= 256) {
827                 for (i = top; i < yuv420_height-buttom; i = i+1) {
828                         j = left;
829                         temp3 = (j>>8)<<8;
830                         temp3 = temp3>>6;
831                         temp4 = i>>5;
832                         if (temp4 & 0x1) {
833                                 /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */
834                                 tiled_offset = temp4-1;
835                                 temp1 = ((yuv420_width+127)>>7)<<7;
836                                 tiled_offset = tiled_offset*(temp1>>6);
837                                 tiled_offset = tiled_offset+temp3;
838                                 tiled_offset = tiled_offset+2;
839                                 temp1 = (temp3>>2)<<2;
840                                 tiled_offset = tiled_offset+temp1;
841                                 tiled_offset = tiled_offset<<11;
842                                 tiled_offset1 = tiled_offset+2048*2;
843                                 temp4 = 8;
844                         } else {
845                                 temp2 = ((yuv420_height+31)>>5)<<5;
846                                 if ((i+32) < temp2) {
847                                         /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */
848                                         temp1 = temp3+2;
849                                         temp1 = (temp1>>2)<<2;
850                                         tiled_offset = temp3+temp1;
851                                         temp1 = ((yuv420_width+127)>>7)<<7;
852                                         tiled_offset = tiled_offset+temp4*(temp1>>6);
853                                         tiled_offset = tiled_offset<<11;
854                                         tiled_offset1 = tiled_offset+2048*6;
855                                         temp4 = 8;
856                                 } else {
857                                         /* even2 fomula: x+x_block_num*y */
858                                         temp1 = ((yuv420_width+127)>>7)<<7;
859                                         tiled_offset = temp4*(temp1>>6);
860                                         tiled_offset = tiled_offset+temp3;
861                                         tiled_offset = tiled_offset<<11;
862                                         tiled_offset1 = tiled_offset+2048*2;
863                                         temp4 = 4;
864                                 }
865                         }
866
867                         temp1 = i&0x1F;
868                         tiled_offset = tiled_offset+64*(temp1);
869                         tiled_offset1 = tiled_offset1+64*(temp1);
870                         temp2 = yuv420_width-left-right;
871                         linear_offset = temp2*(i-top);
872                         temp3 = ((j+256)>>8)<<8;
873                         temp3 = temp3-j;
874                         temp1 = left&0x3F;
875                         if (temp3 > 192) {
876                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset+temp1, 64-temp1);
877                                 memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset+2048, 64);
878                                 memcpy(yuv420_dest+linear_offset+128-temp1, nv12t_src+tiled_offset1, 64);
879                                 memcpy(yuv420_dest+linear_offset+192-temp1, nv12t_src+tiled_offset1+2048, 64);
880                                 linear_offset = linear_offset+256-temp1;
881                         } else if (temp3 > 128) {
882                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset+2048+temp1, 64-temp1);
883                                 memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset1, 64);
884                                 memcpy(yuv420_dest+linear_offset+128-temp1, nv12t_src+tiled_offset1+2048, 64);
885                                 linear_offset = linear_offset+192-temp1;
886                         } else if (temp3 > 64) {
887                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset1+temp1, 64-temp1);
888                                 memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset1+2048, 64);
889                                 linear_offset = linear_offset+128-temp1;
890                         } else if (temp3 > 0) {
891                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset1+2048+temp1, 64-temp1);
892                                 linear_offset = linear_offset+64-temp1;
893                         }
894
895                         tiled_offset = tiled_offset+temp4*2048;
896                         j = (left>>8)<<8;
897                         j = j + 256;
898                         temp2 = yuv420_width-right-256;
899                         for (; j <= temp2; j = j+256) {
900                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64);
901                                 tiled_offset1 = tiled_offset1+temp4*2048;
902                                 memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64);
903                                 memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, 64);
904                                 tiled_offset = tiled_offset+temp4*2048;
905                                 memcpy(yuv420_dest+linear_offset+192, nv12t_src+tiled_offset1+2048, 64);
906                                 linear_offset = linear_offset+256;
907                         }
908
909                         tiled_offset1 = tiled_offset1+temp4*2048;
910                         temp2 = yuv420_width-right-j;
911                         if (temp2 > 192) {
912                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64);
913                                 memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64);
914                                 memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, 64);
915                                 memcpy(yuv420_dest+linear_offset+192, nv12t_src+tiled_offset1+2048, temp2-192);
916                         } else if (temp2 > 128) {
917                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64);
918                                 memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64);
919                                 memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, temp2-128);
920                         } else if (temp2 > 64) {
921                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64);
922                                 memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, temp2-64);
923                         } else
924                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2);
925                 }
926         } else if (temp1 >= 64) {
927                 for (i = top; i < (yuv420_height-buttom); i = i+1) {
928                         j = left;
929                         tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
930                         temp2 = ((j+64)>>6)<<6;
931                         temp2 = temp2-j;
932                         linear_offset = temp1*(i-top);
933                         temp4 = j&0x3;
934                         tiled_offset = tiled_offset+temp4;
935                         memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2);
936                         linear_offset = linear_offset+temp2;
937                         j = j+temp2;
938                         if ((j+64) <= temp3) {
939                                 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
940                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64);
941                                 linear_offset = linear_offset+64;
942                                 j = j+64;
943                         }
944                         if ((j+64) <= temp3) {
945                                 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
946                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64);
947                                 linear_offset = linear_offset+64;
948                                 j = j+64;
949                         }
950                         if (j < temp3) {
951                                 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
952                                 temp2 = temp3-j;
953                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2);
954                         }
955                 }
956         } else {
957                 for (i = top; i < (yuv420_height-buttom); i = i+1) {
958                         linear_offset = temp1*(i-top);
959                         for (j = left; j < (yuv420_width-right); j = j+2) {
960                                 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
961                                 temp4 = j&0x3;
962                                 tiled_offset = tiled_offset+temp4;
963                                 memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 2);
964                                 linear_offset = linear_offset+2;
965                         }
966                 }
967         }
968 }
969
970 #ifdef CAPTURE_OUTPUT_DUMP /* for capture output dump */
971 static void capture_output_dump(mm_player_t* player)
972 {
973         unsigned char *temp = NULL;
974         char file[100] = { 0, };
975         FILE *fp = NULL;
976         int ret = 0;
977         int i = 0, j = 0;
978
979         LOGE("capture output dump start. size = %d", player->capture.size);
980         sprintf(file, "/tmp/dec_output_dump_%dx%d.yuv", player->captured.width[0], player->captured.height[0]);
981         fp = fopen(file, "ab");
982
983         for (i = 0; i < player->captured.plane_num; i++) {
984                 temp = player->captured.data[i];
985
986                 for (j = 0; j < player->captured.height[i]; j++) {
987                         ret = fwrite(temp, player->captured.width[i], 1, fp);
988                         temp += player->captured.width[i];
989                 }
990         }
991         LOGE("capture yuv dumped!! ret = %d", ret);
992         fclose(fp);
993
994         temp = (unsigned char *)player->capture.data;
995         sprintf(file, "/tmp/dec_output_dump_%dx%d.rgb", player->captured.width[0], player->captured.height[0]);
996         fp = fopen(file, "ab");
997         ret = fwrite(temp, player->capture.size, 1, fp);
998         fclose(fp);
999         LOGE("capture rgb dumped!! ret = %d", ret);
1000 }
1001 #endif