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