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