4 * Copyright(c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
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>
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 /*===========================================================================================
27 ========================================================================================== */
29 #include "mm_player_utils.h"
30 #include "mm_player_capture.h"
31 #include "mm_player_priv.h"
33 #include <mm_util_type.h>
34 #include <gst/video/video-info.h>
36 //#define CAPTURE_OUTPUT_DUMP 1
37 #define MM_IMG_UITL_LIBRARY_PATH PATH_LIBDIR"/libmmutil_common.so"
38 #define MM_IMGP_UITL_LIBRARY_PATH PATH_LIBDIR"/libmmutil_imgp.so"
40 #define IMG_UTIL_INTERFACE(_player) (((mmplayer_t *)_player)->img_util)
42 /*---------------------------------------------------------------------------
43 | LOCAL FUNCTION PROTOTYPES: |
44 ---------------------------------------------------------------------------*/
45 static GstPadProbeReturn __mmplayer_video_capture_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
46 static int __mmplayer_get_video_frame_from_buffer(mmplayer_t *player, GstPad *pad, GstBuffer *buffer);
47 static gpointer __mmplayer_capture_thread(gpointer data);
48 static void __csc_tiled_to_linear_crop(unsigned char *yuv420_dest, unsigned char *nv12t_src, int yuv420_width, int yuv420_height, int left, int top, int right, int bottom);
49 static int __tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos);
50 static int __mm_player_convert_NV12_tiled(mmplayer_t *player);
51 static int __mm_player_convert_NV12(mmplayer_t *player);
52 static int __mm_player_convert_I420(mmplayer_t *player);
53 static int __mm_player_convert_BGRx(mmplayer_t *player);
54 #ifdef CAPTURE_OUTPUT_DUMP
55 static void capture_output_dump(mmplayer_t *player);
58 /*===========================================================================================
60 | FUNCTION DEFINITIONS |
62 ========================================================================================== */
64 static int __mmplayer_init_img_util_interface(mmplayer_t *player)
66 int ret = MM_ERROR_NONE;
67 gboolean sym_ret = FALSE;
68 GModule *img_module = NULL;
69 GModule *imgp_module = NULL;
70 mm_img_util_interface_t *img_util = NULL;
73 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
75 if ((access(MM_IMG_UITL_LIBRARY_PATH, F_OK) != 0) ||
76 (access(MM_IMGP_UITL_LIBRARY_PATH, F_OK) != 0)){
77 LOGE("there is no img util library");
78 return MM_ERROR_PLAYER_INTERNAL;
81 /* allocate new handle */
82 img_util = (mm_img_util_interface_t *)g_try_malloc0(sizeof(mm_img_util_interface_t));
84 LOGE("failed to alloc memory for image util interface");
85 ret = MM_ERROR_OUT_OF_MEMORY;
89 img_module = g_module_open(MM_IMG_UITL_LIBRARY_PATH, G_MODULE_BIND_LAZY);
91 LOGE("failed to open img common module");
95 imgp_module = g_module_open(MM_IMGP_UITL_LIBRARY_PATH, G_MODULE_BIND_LAZY);
97 LOGE("failed to open imgp module");
102 sym_ret = g_module_symbol(img_module, "mm_image_create_image", (gpointer *)&img_util->create);
103 sym_ret &= g_module_symbol(img_module, "mm_image_destroy_image", (gpointer *)&img_util->destroy);
104 sym_ret &= g_module_symbol(img_module, "mm_image_get_image", (gpointer *)&img_util->get);
105 sym_ret &= g_module_symbol(img_module, "mm_image_debug_image", (gpointer *)&img_util->debug);
106 sym_ret &= g_module_symbol(imgp_module, "mm_util_rotate_image", (gpointer *)&img_util->rotate);
107 sym_ret &= g_module_symbol(imgp_module, "mm_util_convert_colorspace", (gpointer *)&img_util->convert);
109 if (sym_ret == FALSE || !img_util->create || !img_util->rotate) {
110 LOGE("failed to find symbol %d %p %p", sym_ret, img_util->create, img_util->rotate);
111 ret = MM_ERROR_PLAYER_INTERNAL;
115 img_util->img_module = img_module;
116 img_util->imgp_module = imgp_module;
117 player->img_util = img_util;
119 LOGD("image util interface handle %p", img_util);
120 return MM_ERROR_NONE;
123 /* release allocated resources */
125 g_module_close(img_module);
129 g_module_close(imgp_module);
133 MMPLAYER_FREEIF(img_util);
137 static int __mmplayer_deinit_img_util_interface(mmplayer_t *player)
139 int ret = MM_ERROR_NONE;
141 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
143 if (IMG_UTIL_INTERFACE(player)->img_module) {
144 LOGD("close img common module %p", IMG_UTIL_INTERFACE(player)->img_module);
145 if (!g_module_close(IMG_UTIL_INTERFACE(player)->img_module)) {
146 LOGE("failed to close module");
147 ret = MM_ERROR_PLAYER_INTERNAL;
151 if (IMG_UTIL_INTERFACE(player)->imgp_module) {
152 LOGD("close imgp module %p", IMG_UTIL_INTERFACE(player)->imgp_module);
153 if (!g_module_close(IMG_UTIL_INTERFACE(player)->imgp_module)) {
154 LOGE("failed to close module");
155 ret = MM_ERROR_PLAYER_INTERNAL;
159 MMPLAYER_FREEIF(IMG_UTIL_INTERFACE(player));
165 _mmplayer_initialize_video_capture(mmplayer_t *player)
167 int ret = MM_ERROR_NONE;
168 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
170 if (__mmplayer_init_img_util_interface(player) != MM_ERROR_NONE) {
171 LOGE("failed to initialize img util interface");
172 return MM_ERROR_PLAYER_INTERNAL;
175 /* create capture mutex */
176 g_mutex_init(&player->capture_thread_mutex);
178 /* create capture cond */
179 g_cond_init(&player->capture_thread_cond);
181 player->capture_thread_exit = FALSE;
183 /* create video capture thread */
184 player->capture_thread =
185 g_thread_try_new("capture_thread", __mmplayer_capture_thread, (gpointer)player, NULL);
187 if (!player->capture_thread) {
188 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
196 g_mutex_clear(&player->capture_thread_mutex);
197 g_cond_clear(&player->capture_thread_cond);
202 _mmplayer_release_video_capture(mmplayer_t *player)
204 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
205 if (!IMG_UTIL_INTERFACE(player)) {
206 LOGW("there is no allocated resource");
207 return MM_ERROR_NONE;
210 __mmplayer_deinit_img_util_interface(player);
212 /* release capture thread */
213 MMPLAYER_CAPTURE_THREAD_LOCK(player);
214 player->capture_thread_exit = TRUE;
215 MMPLAYER_CAPTURE_THREAD_SIGNAL(player);
216 MMPLAYER_CAPTURE_THREAD_UNLOCK(player);
218 LOGD("waiting for capture thread exit");
219 g_thread_join(player->capture_thread);
220 g_mutex_clear(&player->capture_thread_mutex);
221 g_cond_clear(&player->capture_thread_cond);
222 LOGD("capture thread released");
224 return MM_ERROR_NONE;
228 _mmplayer_do_video_capture(MMHandleType hplayer)
230 mmplayer_t *player = (mmplayer_t *)hplayer;
231 int ret = MM_ERROR_NONE;
235 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
237 if (!IMG_UTIL_INTERFACE(player)) {
238 LOGW("video capture is not supported");
239 return MM_ERROR_NONE;
242 /* capturing or not */
243 if (player->video_capture_cb_probe_id || player->capture.data
244 || player->captured.data[0] || player->captured.data[1]) {
245 LOGW("capturing... we can't do any more");
246 return MM_ERROR_PLAYER_INVALID_STATE;
248 gint surface_type = 0;
249 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
251 /* check if video pipeline is linked or not */
252 if (!player->pipeline->videobin) {
253 LOGW("not ready to capture");
254 return MM_ERROR_PLAYER_INVALID_STATE;
257 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
259 if (player->state == MM_PLAYER_STATE_PLAYING) {
261 player->video_capture_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
262 __mmplayer_video_capture_probe, player, NULL);
263 } else if (player->state == MM_PLAYER_STATE_PAUSED) {
264 // get last buffer from video sink
265 GstSample *sample = NULL;
267 gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, 5 * GST_SECOND);
268 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "last-sample", &sample, NULL);
271 GstBuffer *buf = gst_sample_get_buffer(sample);
273 if (__mmplayer_get_video_frame_from_buffer(player, pad, buf) != MM_ERROR_NONE)
274 ret = MM_ERROR_PLAYER_INTERNAL;
276 LOGW("failed to get video frame");
278 gst_sample_unref(sample);
281 LOGW("invalid state(%d) to capture", player->state);
282 ret = MM_ERROR_PLAYER_INVALID_STATE;
285 gst_object_unref(GST_OBJECT(pad));
294 __mmplayer_handle_orientation(mmplayer_t *player, int orientation, int format)
296 unsigned char *src_buffer = NULL;
297 int ret = MM_ERROR_NONE;
298 mm_util_image_h src_image = NULL;
299 mm_util_image_h dst_image = NULL;
301 mm_util_rotate_type_e rot_enum = MM_UTIL_ROTATE_NUM;
303 player->capture.orientation = orientation;
305 if (orientation == 0) {
306 LOGE("no need handle orientation : %d", orientation);
307 player->capture.width = player->captured.width[0];
308 player->capture.height = player->captured.height[0];
309 return MM_ERROR_NONE;
312 src_buffer = (unsigned char *)player->capture.data;
314 /* convert orientation degree into enum here */
315 switch (orientation) {
317 rot_enum = MM_UTIL_ROTATE_90;
320 rot_enum = MM_UTIL_ROTATE_180;
323 rot_enum = MM_UTIL_ROTATE_270;
326 LOGE("wrong rotate value");
330 LOGD("source buffer for rotation = %p and rotation = %d", src_buffer, rot_enum);
332 ret = IMG_UTIL_INTERFACE(player)->create(player->captured.width[0], player->captured.height[0], format, src_buffer, (size_t)player->capture.size, &src_image);
333 if (ret != MM_ERROR_NONE) {
334 LOGE("failed to create image");
338 ret = IMG_UTIL_INTERFACE(player)->rotate(src_image, rot_enum, &dst_image);
339 IMG_UTIL_INTERFACE(player)->destroy(src_image);
340 if (ret != MM_ERROR_NONE) {
341 LOGE("failed to rotate image");
345 IMG_UTIL_INTERFACE(player)->debug(dst_image, NULL);
347 ret = IMG_UTIL_INTERFACE(player)->get(dst_image, &player->capture.width, &player->capture.height, NULL, &player->capture.data, &dst_size);
348 IMG_UTIL_INTERFACE(player)->destroy(dst_image);
349 if (ret != MM_ERROR_NONE) {
350 LOGE("failed to get image");
356 player->capture.size = (int)dst_size;
357 player->capture.orientation = orientation;
359 player->captured.width[0] = player->captured.stride_width[0] = player->capture.width;
360 player->captured.height[0] = player->captured.stride_height[0] = player->capture.height;
366 __mmplayer_capture_thread(gpointer data)
368 mmplayer_t *player = (mmplayer_t *)data;
369 MMMessageParamType msg = {0, };
371 int display_angle = 0;
375 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
377 MMPLAYER_CAPTURE_THREAD_LOCK(player);
378 while (!player->capture_thread_exit) {
379 LOGD("capture thread started. waiting for signal");
380 MMPLAYER_CAPTURE_THREAD_WAIT(player);
382 if (player->capture_thread_exit) {
383 LOGD("exiting capture thread");
386 LOGD("capture thread is received signal");
388 /* NOTE: Don't use MMPLAYER_CMD_LOCK() here.
389 * Because deadlock can be happened if other player api is used in message callback.
391 if (player->video_cs == MM_PLAYER_COLORSPACE_NV12_TILED) {
392 /* Colorspace conversion : NV12T-> NV12-> RGB888 */
393 ret = __mm_player_convert_NV12_tiled(player);
394 if (ret != MM_ERROR_NONE) {
395 LOGE("failed to covert NV12T");
399 } else if (player->video_cs == MM_PLAYER_COLORSPACE_NV12) {
400 ret = __mm_player_convert_NV12(player);
401 if (ret != MM_ERROR_NONE) {
402 LOGE("failed to covert NV12");
406 } else if (player->video_cs == MM_PLAYER_COLORSPACE_I420) {
407 ret = __mm_player_convert_I420(player);
408 if (ret != MM_ERROR_NONE) {
409 LOGE("failed to covert I420");
413 } else if (player->video_cs == MM_PLAYER_COLORSPACE_BGRx) {
414 ret = __mm_player_convert_BGRx(player);
415 if (ret != MM_ERROR_NONE) {
416 LOGE("failed to covert BGRx");
421 LOGE("invalid format");
422 msg.code = MM_ERROR_PLAYER_INTERNAL;
426 ret = _mmplayer_get_video_angle((MMHandleType)player, &display_angle, &orientation);
427 if (ret != MM_ERROR_NONE) {
428 LOGE("failed to get rotation angle");
432 LOGD("orientation value = %d user_angle = %d", orientation, display_angle);
434 ret = __mmplayer_handle_orientation(player, orientation, MM_UTIL_COLOR_RGB24);
435 if (ret != MM_ERROR_NONE) {
436 LOGE("failed to convert nv12 linear");
440 player->capture.fmt = MM_PLAYER_COLORSPACE_RGB888;
441 msg.data = &player->capture;
442 msg.size = player->capture.size;
444 if (player->cmd >= MMPLAYER_COMMAND_START) {
445 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_CAPTURED, &msg);
446 LOGD("returned from capture message callback");
451 for (i = 0; i < player->captured.plane_num; i++)
452 MMPLAYER_FREEIF(player->captured.data[i]);
454 msg.union_type = MM_MSG_UNION_CODE;
456 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_NOT_CAPTURED, &msg);
460 MMPLAYER_CAPTURE_THREAD_UNLOCK(player);
465 * The output is fixed as RGB888
468 __mmplayer_get_video_frame_from_buffer(mmplayer_t *player, GstPad *pad, GstBuffer *buffer)
471 guint plane_size = 0;
472 GstCaps *caps = NULL;
473 GstVideoFrame vframe;
475 guint8 *pixels = NULL;
476 int ret = MM_ERROR_NONE;
480 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
481 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, MM_ERROR_INVALID_ARGUMENT);
484 caps = gst_pad_get_current_caps(pad);
486 MMPLAYER_RETURN_VAL_IF_FAIL(caps, MM_ERROR_INVALID_ARGUMENT);
487 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
489 /* init capture image buffer */
490 memset(&player->capture, 0x00, sizeof(mmplayer_video_capture_t));
492 gst_video_info_from_caps(&vinfo, caps);
494 gst_caps_unref(caps);
496 LOGI("captured format is %s", gst_video_format_to_string(GST_VIDEO_INFO_FORMAT(&vinfo)));
498 player->captured.width[0] = GST_VIDEO_INFO_WIDTH(&vinfo);
499 player->captured.height[0] = GST_VIDEO_INFO_HEIGHT(&vinfo);
501 switch (GST_VIDEO_INFO_FORMAT(&vinfo)) {
502 case GST_VIDEO_FORMAT_NV12:
503 case GST_VIDEO_FORMAT_SN12:
504 player->video_cs = MM_PLAYER_COLORSPACE_NV12;
505 player->captured.width[1] = player->captured.width[0];
506 player->captured.height[1] = player->captured.height[0] >> 1;
508 case GST_VIDEO_FORMAT_I420:
509 case GST_VIDEO_FORMAT_S420:
510 player->video_cs = MM_PLAYER_COLORSPACE_I420;
511 player->captured.width[1] = player->captured.width[2] = player->captured.width[0] >> 1;
512 player->captured.height[1] = player->captured.height[2] = player->captured.height[0] >> 1;
514 case GST_VIDEO_FORMAT_ST12:
515 player->video_cs = MM_PLAYER_COLORSPACE_NV12_TILED;
516 player->captured.width[1] = player->captured.width[0];
517 player->captured.height[1] = player->captured.height[0] >> 1;
519 case GST_VIDEO_FORMAT_BGRx:
520 player->video_cs = MM_PLAYER_COLORSPACE_BGRx;
523 player->video_cs = MM_PLAYER_COLORSPACE_MAX;
524 ret = MM_ERROR_PLAYER_INTERNAL;
528 if (ret != MM_ERROR_NONE) {
529 LOGE("unknown format to capture");
533 if (gst_video_frame_map(&vframe, &vinfo, buffer, GST_MAP_READ)) {
534 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES(&vframe); i++) {
535 player->captured.stride_width[i] = GST_VIDEO_FRAME_PLANE_STRIDE(&vframe, i);
536 player->captured.stride_height[i] = player->captured.height[i];
537 plane_size = player->captured.stride_width[i] * player->captured.stride_height[i];
539 LOGE("invalid plane size");
540 gst_video_frame_unmap(&vframe);
541 return MM_ERROR_PLAYER_INTERNAL;
543 pixels = GST_VIDEO_FRAME_PLANE_DATA(&vframe, i);
544 player->captured.data[i] = g_malloc(plane_size);
545 memcpy(player->captured.data[i], pixels, plane_size);
547 player->captured.plane_num = GST_VIDEO_FRAME_N_PLANES(&vframe);
548 gst_video_frame_unmap(&vframe);
550 /* do convert colorspace */
551 MMPLAYER_CAPTURE_THREAD_SIGNAL(player);
556 static GstPadProbeReturn
557 __mmplayer_video_capture_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
559 mmplayer_t *player = (mmplayer_t *)u_data;
560 GstBuffer *buffer = NULL;
561 int ret = MM_ERROR_NONE;
563 MMPLAYER_RETURN_VAL_IF_FAIL(info->data, GST_PAD_PROBE_REMOVE);
566 buffer = gst_pad_probe_info_get_buffer(info);
567 ret = __mmplayer_get_video_frame_from_buffer(player, pad, buffer);
568 if (ret != MM_ERROR_NONE) {
569 LOGE("failed to get video frame");
570 return GST_PAD_PROBE_REMOVE;
573 /* remove probe to be called at one time */
574 if (player->video_capture_cb_probe_id) {
575 gst_pad_remove_probe(pad, player->video_capture_cb_probe_id);
576 player->video_capture_cb_probe_id = 0;
581 return GST_PAD_PROBE_OK;
585 __mm_player_convert_colorspace(mmplayer_t *player, unsigned char *src_data, size_t src_size, mm_util_color_format_e src_fmt, unsigned int src_w, unsigned int src_h, mm_util_color_format_e dst_fmt)
587 int ret = MM_ERROR_NONE;
588 mm_util_image_h src_image = NULL;
589 mm_util_image_h dst_image = NULL;
592 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_INTERNAL);
593 SECURE_LOGD("src size info. width: %d, height: %d", src_w, src_h);
595 ret = IMG_UTIL_INTERFACE(player)->create(src_w, src_h, src_fmt, src_data, src_size, &src_image);
596 if (ret != MM_ERROR_NONE) {
597 LOGE("failed to create image for capture, %d", ret);
598 return MM_ERROR_PLAYER_INTERNAL;
601 ret = IMG_UTIL_INTERFACE(player)->convert(src_image, dst_fmt, &dst_image);
602 IMG_UTIL_INTERFACE(player)->destroy(src_image);
603 if (ret != MM_ERROR_NONE) {
604 LOGE("failed to convert for capture, %d", ret);
605 return MM_ERROR_PLAYER_INTERNAL;
607 IMG_UTIL_INTERFACE(player)->debug(dst_image, NULL);
609 ret = IMG_UTIL_INTERFACE(player)->get(dst_image, NULL, NULL, NULL, &player->capture.data, &size);
610 IMG_UTIL_INTERFACE(player)->destroy(dst_image);
611 if (ret != MM_ERROR_NONE) {
612 LOGE("failed to get image for capture, %d", ret);
613 return MM_ERROR_PLAYER_INTERNAL;
616 player->capture.size = (int)size;
617 return MM_ERROR_NONE;
621 * Get tiled address of position(x,y)
627 * height of tiled[in]
630 * x position of tiled[in]
633 * y position of tiled[in]
636 * address of tiled data
639 __tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos)
641 int pixel_x_m1, pixel_y_m1;
643 int linear_addr0, linear_addr1, bank_addr ;
647 pixel_x_m1 = x_size -1;
648 pixel_y_m1 = y_size -1;
650 roundup_x = ((pixel_x_m1 >> 7) + 1);
654 if ((y_size <= y_pos+32) && (y_pos < y_size) &&
655 (((pixel_y_m1 >> 5) & 0x1) == 0) && (((y_pos >> 5) & 0x1) == 0)) {
656 linear_addr0 = (((y_pos & 0x1f) <<4) | (x_addr & 0xf));
657 linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 6) & 0x3f));
659 if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1))
660 bank_addr = ((x_addr >> 4) & 0x1);
662 bank_addr = 0x2 | ((x_addr >> 4) & 0x1);
664 linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf));
665 linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 5) & 0x7f));
667 if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1))
668 bank_addr = ((x_addr >> 4) & 0x1);
670 bank_addr = 0x2 | ((x_addr >> 4) & 0x1);
673 linear_addr0 = linear_addr0 << 2;
674 trans_addr = (linear_addr1 <<13) | (bank_addr << 11) | linear_addr0;
680 * Converts tiled data to linear
681 * Crops left, top, right, bottom
682 * 1. Y of NV12T to Y of YUV420P
683 * 2. Y of NV12T to Y of YUV420S
684 * 3. UV of NV12T to UV of YUV420S
687 * Y or UV plane address of YUV420[out]
690 * Y or UV plane address of NV12T[in]
692 * @param yuv420_width
693 * Width of YUV420[in]
695 * @param yuv420_height
696 * Y: Height of YUV420, UV: Height/2 of YUV420[in]
708 * Crop size of bottom
711 __csc_tiled_to_linear_crop(unsigned char *yuv420_dest, unsigned char *nv12t_src, int yuv420_width, int yuv420_height,
712 int left, int top, int right, int bottom)
715 int tiled_offset = 0, tiled_offset1 = 0;
716 int linear_offset = 0;
717 int temp1 = 0, temp2 = 0, temp3 = 0, temp4 = 0;
719 temp3 = yuv420_width-right;
721 /* real width is greater than or equal 256 */
723 for (i = top; i < yuv420_height-bottom; i = i+1) {
725 temp3 = (j >> 8) << 8;
729 /* odd formula: 2 + x + (x >> 2) << 2 + x_block_num * (y - 1) */
730 tiled_offset = temp4 - 1;
731 temp1 = ((yuv420_width + 127) >> 7) << 7;
732 tiled_offset = tiled_offset * (temp1 >> 6);
733 tiled_offset = tiled_offset + temp3;
734 tiled_offset = tiled_offset + 2;
735 temp1 = (temp3 >> 2) << 2;
736 tiled_offset = tiled_offset + temp1;
737 tiled_offset = tiled_offset << 11;
738 tiled_offset1 = tiled_offset + 2048 * 2;
741 temp2 = ((yuv420_height+31) >> 5) << 5;
742 if ((i + 32) < temp2) {
743 /* even1 formula: x + ((x + 2) >> 2) << 2 + x_block_num * y */
745 temp1 = (temp1 >> 2) << 2;
746 tiled_offset = temp3 + temp1;
747 temp1 = ((yuv420_width + 127) >> 7) << 7;
748 tiled_offset = tiled_offset + temp4 * (temp1 >> 6);
749 tiled_offset = tiled_offset << 11;
750 tiled_offset1 = tiled_offset + 2048 * 6;
753 /* even2 formula: x + x_block_num * y */
754 temp1 = ((yuv420_width + 127) >> 7) << 7;
755 tiled_offset = temp4 * (temp1 >> 6);
756 tiled_offset = tiled_offset + temp3;
757 tiled_offset = tiled_offset << 11;
758 tiled_offset1 = tiled_offset + 2048 * 2;
764 tiled_offset = tiled_offset + 64 * temp1;
765 tiled_offset1 = tiled_offset1 + 64 * temp1;
766 temp2 = yuv420_width - left - right;
767 linear_offset = temp2 * (i - top);
768 temp3 = ((j + 256) >> 8) << 8;
772 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset + temp1, 64 - temp1);
773 memcpy(yuv420_dest + linear_offset + 64 - temp1, nv12t_src + tiled_offset + 2048, 64);
774 memcpy(yuv420_dest + linear_offset + 128 - temp1, nv12t_src + tiled_offset1, 64);
775 memcpy(yuv420_dest + linear_offset + 192 - temp1, nv12t_src + tiled_offset1 + 2048, 64);
776 linear_offset = linear_offset + 256 - temp1;
777 } else if (temp3 > 128) {
778 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset + 2048 + temp1, 64 - temp1);
779 memcpy(yuv420_dest + linear_offset + 64 - temp1, nv12t_src + tiled_offset1, 64);
780 memcpy(yuv420_dest + linear_offset + 128 - temp1, nv12t_src + tiled_offset1 + 2048, 64);
781 linear_offset = linear_offset + 192 - temp1;
782 } else if (temp3 > 64) {
783 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset1 + temp1, 64 - temp1);
784 memcpy(yuv420_dest + linear_offset + 64 - temp1, nv12t_src + tiled_offset1 + 2048, 64);
785 linear_offset = linear_offset + 128 - temp1;
786 } else if (temp3 > 0) {
787 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset1 + 2048 + temp1, 64 - temp1);
788 linear_offset = linear_offset + 64 - temp1;
791 tiled_offset = tiled_offset + temp4 * 2048;
792 j = (left >> 8) << 8;
794 temp2 = yuv420_width - right - 256;
795 for (; j <= temp2; j = j + 256) {
796 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 64);
797 tiled_offset1 = tiled_offset1 + temp4 * 2048;
798 memcpy(yuv420_dest + linear_offset + 64, nv12t_src + tiled_offset + 2048, 64);
799 memcpy(yuv420_dest + linear_offset + 128, nv12t_src + tiled_offset1, 64);
800 tiled_offset = tiled_offset + temp4 * 2048;
801 memcpy(yuv420_dest + linear_offset + 192, nv12t_src + tiled_offset1 + 2048, 64);
802 linear_offset = linear_offset + 256;
805 tiled_offset1 = tiled_offset1 + temp4 * 2048;
806 temp2 = yuv420_width - right - j;
808 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 64);
809 memcpy(yuv420_dest + linear_offset + 64, nv12t_src + tiled_offset + 2048, 64);
810 memcpy(yuv420_dest + linear_offset + 128, nv12t_src + tiled_offset1, 64);
811 memcpy(yuv420_dest + linear_offset + 192, nv12t_src + tiled_offset1 + 2048, temp2 - 192);
812 } else if (temp2 > 128) {
813 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 64);
814 memcpy(yuv420_dest + linear_offset + 64, nv12t_src + tiled_offset + 2048, 64);
815 memcpy(yuv420_dest + linear_offset + 128, nv12t_src + tiled_offset1, temp2 - 128);
816 } else if (temp2 > 64) {
817 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 64);
818 memcpy(yuv420_dest + linear_offset + 64, nv12t_src + tiled_offset + 2048, temp2 - 64);
820 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, temp2);
823 } else if (temp1 >= 64) {
824 for (i = top; i < (yuv420_height - bottom); i++) {
826 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
827 temp2 = ((j + 64) >> 6) << 6;
829 linear_offset = temp1 * (i - top);
831 tiled_offset = tiled_offset + temp4;
832 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, temp2);
833 linear_offset = linear_offset + temp2;
835 if ((j + 64) <= temp3) {
836 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
837 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 64);
838 linear_offset = linear_offset + 64;
841 if ((j + 64) <= temp3) {
842 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
843 memcpy(yuv420_dest+linear_offset, nv12t_src + tiled_offset, 64);
844 linear_offset = linear_offset + 64;
848 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
850 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, temp2);
854 for (i = top; i < (yuv420_height - bottom); i++) {
855 linear_offset = temp1 * (i - top);
856 for (j = left; j < (yuv420_width - right); j += 2) {
857 tiled_offset = __tile_4x2_read(yuv420_width, yuv420_height, j, i);
859 tiled_offset = tiled_offset + temp4;
860 memcpy(yuv420_dest + linear_offset, nv12t_src + tiled_offset, 2);
861 linear_offset = linear_offset + 2;
867 #ifdef CAPTURE_OUTPUT_DUMP /* for capture output dump */
869 capture_output_dump(mmplayer_t *player)
871 unsigned char *temp = NULL;
872 char file[100] = { 0, };
877 LOGE("capture output dump start. size = %d", player->capture.size);
878 sprintf(file, "/tmp/dec_output_dump_%dx%d.yuv", player->captured.width[0], player->captured.height[0]);
879 fp = fopen(file, "ab");
881 for (i = 0; i < player->captured.plane_num; i++) {
882 temp = player->captured.data[i];
884 for (j = 0; j < player->captured.height[i]; j++) {
885 ret = fwrite(temp, player->captured.width[i], 1, fp);
886 temp += player->captured.stride_width[i];
889 LOGE("capture yuv dumped!! ret = %d", ret);
892 temp = (unsigned char *)player->capture.data;
893 sprintf(file, "/tmp/dec_output_dump_%dx%d.rgb", player->captured.width[0], player->captured.height[0]);
894 fp = fopen(file, "ab");
895 ret = fwrite(temp, player->capture.size, 1, fp);
897 LOGE("capture rgb dumped!! ret = %d", ret);
902 __mm_player_convert_NV12_tiled(mmplayer_t *player)
904 /* Colorspace conversion : NV12T-> NV12-> RGB888 */
906 int ret = MM_ERROR_NONE;
907 unsigned char *src_buffer = NULL;
908 unsigned char *linear_y_plane = NULL;
909 unsigned char *linear_uv_plane = NULL;
910 guint linear_y_plane_size;
911 guint linear_uv_plane_size;
912 guint width = player->captured.width[0];
913 guint height = player->captured.height[0];
915 linear_y_plane_size = width * height;
916 linear_uv_plane_size = linear_y_plane_size / 2;
918 if (!linear_y_plane_size || !linear_uv_plane_size) {
919 LOGE("invalid plane size");
920 return MM_ERROR_PLAYER_INTERNAL;
922 linear_y_plane = (unsigned char *)g_malloc(linear_y_plane_size);
923 linear_uv_plane = (unsigned char *)g_malloc(linear_uv_plane_size);
925 /* NV12 tiled to linear */
926 __csc_tiled_to_linear_crop(linear_y_plane,
927 player->captured.data[0], width, height, 0, 0, 0, 0);
928 __csc_tiled_to_linear_crop(linear_uv_plane,
929 player->captured.data[1], width, height / 2, 0, 0, 0, 0);
931 src_buffer = (unsigned char *)g_malloc(linear_y_plane_size + linear_uv_plane_size);
933 memcpy(src_buffer, linear_y_plane, linear_y_plane_size);
934 memcpy(src_buffer + linear_y_plane_size, linear_uv_plane, linear_uv_plane_size);
936 /* NV12 linear to RGB888 */
937 ret = __mm_player_convert_colorspace(player, src_buffer, (size_t)(linear_y_plane_size + linear_uv_plane_size),
938 MM_UTIL_COLOR_NV12, width, height, MM_UTIL_COLOR_RGB24);
940 MMPLAYER_FREEIF(src_buffer);
941 MMPLAYER_FREEIF(linear_y_plane);
942 MMPLAYER_FREEIF(linear_uv_plane);
944 for (i = 0; i < player->captured.plane_num; i++)
945 MMPLAYER_FREEIF(player->captured.data[i]);
951 __mm_player_convert_NV12(mmplayer_t *player)
953 unsigned char *src_buffer = NULL;
954 unsigned char *p_buf = NULL;
955 unsigned char *temp = NULL;
956 int planes[MAX_BUFFER_PLANE] = {0, };
957 int ret = MM_ERROR_NONE;
960 /* using original width otherwise, app can't know aligned to resize */
961 planes[0] = player->captured.stride_width[0] * player->captured.stride_height[0];
962 planes[1] = player->captured.stride_width[1] * player->captured.stride_height[1];
963 guint src_buffer_size = planes[0] + planes[1];
965 if (!src_buffer_size) {
966 LOGE("invalid data size");
967 return MM_ERROR_PLAYER_INTERNAL;
969 src_buffer = (unsigned char *)g_malloc(src_buffer_size);
973 temp = player->captured.data[0];
976 for (i = 0; i < player->captured.height[0]; i++) {
977 memcpy(p_buf, temp, player->captured.width[0]);
978 p_buf += player->captured.width[0];
979 temp += player->captured.stride_width[0];
982 temp = player->captured.data[1];
985 for (j = 0; j < player->captured.height[1]; j++) {
986 memcpy(p_buf, temp, player->captured.width[1]);
987 p_buf += player->captured.width[1];
988 temp += player->captured.stride_width[1];
992 ret = __mm_player_convert_colorspace(player, (unsigned char *)src_buffer, (size_t)src_buffer_size,
993 MM_UTIL_COLOR_NV12, player->captured.width[0],
994 player->captured.height[0], MM_UTIL_COLOR_RGB24);
996 #ifdef CAPTURE_OUTPUT_DUMP
997 capture_output_dump(player);
999 MMPLAYER_FREEIF(src_buffer);
1001 for (i = 0; i < player->captured.plane_num; i++)
1002 MMPLAYER_FREEIF(player->captured.data[i]);
1008 __mm_player_convert_I420(mmplayer_t *player)
1010 unsigned char *src_buffer = NULL;
1011 unsigned char *p_buf = NULL;
1012 unsigned char *temp = NULL;
1013 int planes[MAX_BUFFER_PLANE] = {0, };
1014 int ret = MM_ERROR_NONE;
1017 /* using original width otherwise, app can't know aligned to resize */
1018 planes[0] = player->captured.stride_width[0] * player->captured.stride_height[0];
1019 planes[1] = planes[2] = (player->captured.stride_width[0] >> 1)
1020 * (player->captured.stride_height[0] >> 1);
1022 if (!planes[0] || !planes[1] || !planes[2]) {
1023 LOGE("invalid plane size");
1024 return MM_ERROR_PLAYER_INTERNAL;
1026 src_buffer = (unsigned char *)g_malloc(planes[0] + planes[1] + planes[2]);
1031 temp = player->captured.data[0];
1033 for (i = 0; i < player->captured.height[0]; i++) {
1034 memcpy(p_buf, temp, player->captured.width[0]);
1035 temp += player->captured.stride_width[0];
1036 p_buf += player->captured.width[0];
1040 temp = player->captured.data[1];
1042 for (i = 0; i < player->captured.height[1]; i++) {
1043 memcpy(p_buf, temp, player->captured.width[1]);
1044 temp += player->captured.stride_width[1];
1045 p_buf += player->captured.width[1];
1049 temp = player->captured.data[2];
1051 for (i = 0; i < player->captured.height[2]; i++) {
1052 memcpy(p_buf, temp, player->captured.width[2]);
1053 temp += player->captured.stride_width[2];
1054 p_buf += player->captured.width[2];
1057 /* I420 -> RGB888 */
1058 ret = __mm_player_convert_colorspace(player, (unsigned char *)src_buffer, (size_t)(planes[0] + planes[1] + planes[2]),
1059 MM_UTIL_COLOR_I420, player->captured.width[0], player->captured.height[0], MM_UTIL_COLOR_RGB24);
1061 #ifdef CAPTURE_OUTPUT_DUMP
1062 capture_output_dump(player);
1064 MMPLAYER_FREEIF(src_buffer);
1066 for (i = 0; i < player->captured.plane_num; i++)
1067 MMPLAYER_FREEIF(player->captured.data[i]);
1073 __mm_player_convert_BGRx(mmplayer_t *player)
1077 int ret = MM_ERROR_NONE;
1078 unsigned char *src_buffer = NULL;
1080 size = (player->captured.stride_width[0] * player->captured.stride_height[0]);
1083 LOGE("invalid size");
1084 return MM_ERROR_PLAYER_INTERNAL;
1086 src_buffer = (unsigned char *)g_malloc(size);
1087 memcpy(src_buffer, player->captured.data[0], size);
1089 /* BGRx -> RGB888 */
1090 ret = __mm_player_convert_colorspace(player, (unsigned char *)src_buffer, (size_t)size, MM_UTIL_COLOR_BGRX,
1091 player->captured.width[0], player->captured.height[0], MM_UTIL_COLOR_RGB24);
1093 #ifdef CAPTURE_OUTPUT_DUMP
1094 capture_output_dump(player);
1096 MMPLAYER_FREEIF(src_buffer);
1098 for (i = 0; i < player->captured.plane_num; i++)
1099 MMPLAYER_FREEIF(player->captured.data[i]);