Merge "[0.6.147] Apply new attribute API of libmm-common" into tizen
[platform/core/multimedia/libmm-player.git] / src / mm_player_gst.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_error.h>
30 #include <gst/app/gstappsrc.h>
31
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36
37 /*===========================================================================================
38 |                                                                                                                                                                                       |
39 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
40 |                                                                                                                                                                                       |
41 ========================================================================================== */
42
43 /*---------------------------------------------------------------------------
44 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
45 ---------------------------------------------------------------------------*/
46
47 /*---------------------------------------------------------------------------
48 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
49 ---------------------------------------------------------------------------*/
50
51 /*---------------------------------------------------------------------------
52 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
53 ---------------------------------------------------------------------------*/
54
55 /*---------------------------------------------------------------------------
56 |    LOCAL #defines:                                                                                                            |
57 ---------------------------------------------------------------------------*/
58
59 /*---------------------------------------------------------------------------
60 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
61 ---------------------------------------------------------------------------*/
62
63 /*---------------------------------------------------------------------------
64 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
65 ---------------------------------------------------------------------------*/
66
67 /*---------------------------------------------------------------------------
68 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
69 ---------------------------------------------------------------------------*/
70
71 /*---------------------------------------------------------------------------
72 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
73 ---------------------------------------------------------------------------*/
74
75 /*---------------------------------------------------------------------------
76 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
77 ---------------------------------------------------------------------------*/
78
79 /*===========================================================================================
80 |                                                                                                                                                                                       |
81 |  FUNCTION DEFINITIONS                                                                                                                                         |
82 |                                                                                                                                                                                       |
83 ========================================================================================== */
84
85 /* NOTE : decide gstreamer state whether there is some playable track or not. */
86 static gint
87 __mmplayer_gst_transform_gsterror(mm_player_t* player, GstMessage * message, GError* error)
88 {
89         gchar *src_element_name = NULL;
90         GstElement *src_element = NULL;
91         GstElementFactory *factory = NULL;
92         const gchar* klass = NULL;
93
94         MMPLAYER_FENTER();
95
96         MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
97         MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
98         MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
99         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
100                                                                 player->pipeline &&
101                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
102
103         src_element = GST_ELEMENT_CAST(message->src);
104         if (!src_element)
105                 goto INTERNAL_ERROR;
106
107         src_element_name = GST_ELEMENT_NAME(src_element);
108         if (!src_element_name)
109                 goto INTERNAL_ERROR;
110
111         factory = gst_element_get_factory(src_element);
112         if (!factory)
113                 goto INTERNAL_ERROR;
114
115         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
116         if (!klass)
117                 goto INTERNAL_ERROR;
118
119         LOGD("error code=%d, msg=%s, src element=%s, class=%s\n",
120                         error->code, error->message, src_element_name, klass);
121
122         /* check whether the error is posted from not-activated track or not */
123         if (player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst) {
124                 int msg_src_pos = 0;
125                 gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
126                 LOGD("current  active pad index  -%d", active_pad_index);
127
128                 if  (src_element_name) {
129                         int idx = 0;
130
131                         if (player->audio_decoders) {
132                                 GList *adec = player->audio_decoders;
133                                 for (; adec ; adec = g_list_next(adec)) {
134                                         gchar *name = adec->data;
135
136                                         LOGD("found audio decoder name  = %s", name);
137                                         if (g_strrstr(name, src_element_name)) {
138                                                 msg_src_pos = idx;
139                                                 break;
140                                         }
141                                         idx++;
142                                 }
143                         }
144                         LOGD("active pad = %d, error src index = %d", active_pad_index,  msg_src_pos);
145                 }
146
147                 if (active_pad_index != msg_src_pos) {
148                         LOGD("skip error because error is posted from no activated track");
149                         return MM_ERROR_NONE;
150                 }
151         }
152
153         switch (error->code) {
154         case GST_STREAM_ERROR_DECODE:
155         {
156                 /* Demuxer can't parse one track because it's corrupted.
157                  * So, the decoder for it is not linked.
158                  * But, it has one playable track.
159                  */
160                 if (g_strrstr(klass, "Demux")) {
161                         if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
162                                 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
163                         } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
164                                 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
165                         } else {
166                                 if (player->pipeline->audiobin) // PCM
167                                         return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
168                                 else
169                                         goto CODEC_NOT_FOUND;
170                         }
171                 }
172                 return MM_ERROR_PLAYER_INVALID_STREAM;
173         }
174                 break;
175
176         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
177         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
178         case GST_STREAM_ERROR_WRONG_TYPE:
179         {
180                 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
181                         LOGE("Not supported subtitle.");
182                         return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
183                 }
184                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
185         }
186
187         case GST_STREAM_ERROR_FAILED:
188         {
189                 /* Decoder Custom Message */
190                 if (strstr(error->message, "ongoing")) {
191                         if (strncasecmp(klass, "audio", 5)) {
192                                 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
193                                         LOGD("Video can keep playing.\n");
194                                         return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
195                                 } else
196                                         goto CODEC_NOT_FOUND;
197
198                         } else if (strncasecmp(klass, "video", 5)) {
199                                 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
200                                         LOGD("Audio can keep playing.\n");
201                                         return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
202                                 } else
203                                         goto CODEC_NOT_FOUND;
204                         }
205                 }
206                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
207         }
208                 break;
209
210         case GST_STREAM_ERROR_DECRYPT:
211         case GST_STREAM_ERROR_DECRYPT_NOKEY:
212         {
213                 LOGE("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
214
215                 if (strstr(error->message, "rights expired"))
216                         return MM_ERROR_PLAYER_DRM_EXPIRED;
217                 else if (strstr(error->message, "no rights"))
218                         return MM_ERROR_PLAYER_DRM_NO_LICENSE;
219                 else if (strstr(error->message, "has future rights"))
220                         return MM_ERROR_PLAYER_DRM_FUTURE_USE;
221                 else if (strstr(error->message, "opl violation"))
222                         return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
223                 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
224         }
225                 break;
226
227         default:
228                 break;
229         }
230
231         MMPLAYER_FLEAVE();
232
233         return MM_ERROR_PLAYER_INVALID_STREAM;
234
235 INTERNAL_ERROR:
236         return MM_ERROR_PLAYER_INTERNAL;
237
238 CODEC_NOT_FOUND:
239         LOGD("not found any available codec. Player should be destroyed.\n");
240         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
241 }
242
243 gint
244 __mmplayer_gst_handle_core_error(mm_player_t* player, int code)
245 {
246         gint trans_err = MM_ERROR_NONE;
247
248         MMPLAYER_FENTER();
249
250         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
251
252         switch (code) {
253         case GST_CORE_ERROR_MISSING_PLUGIN:
254                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
255         case GST_CORE_ERROR_STATE_CHANGE:
256         case GST_CORE_ERROR_SEEK:
257         case GST_CORE_ERROR_NOT_IMPLEMENTED:
258         case GST_CORE_ERROR_FAILED:
259         case GST_CORE_ERROR_TOO_LAZY:
260         case GST_CORE_ERROR_PAD:
261         case GST_CORE_ERROR_THREAD:
262         case GST_CORE_ERROR_NEGOTIATION:
263         case GST_CORE_ERROR_EVENT:
264         case GST_CORE_ERROR_CAPS:
265         case GST_CORE_ERROR_TAG:
266         case GST_CORE_ERROR_CLOCK:
267         case GST_CORE_ERROR_DISABLED:
268         default:
269                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
270                 break;
271         }
272
273         MMPLAYER_FLEAVE();
274
275         return trans_err;
276 }
277
278 gint
279 __mmplayer_gst_handle_library_error(mm_player_t* player, int code)
280 {
281         gint trans_err = MM_ERROR_NONE;
282
283         MMPLAYER_FENTER();
284
285         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
286
287         switch (code) {
288         case GST_LIBRARY_ERROR_FAILED:
289         case GST_LIBRARY_ERROR_TOO_LAZY:
290         case GST_LIBRARY_ERROR_INIT:
291         case GST_LIBRARY_ERROR_SHUTDOWN:
292         case GST_LIBRARY_ERROR_SETTINGS:
293         case GST_LIBRARY_ERROR_ENCODE:
294         default:
295                 trans_err =  MM_ERROR_PLAYER_INVALID_STREAM;
296                 break;
297         }
298
299         MMPLAYER_FLEAVE();
300
301         return trans_err;
302 }
303
304 gint
305 __mmplayer_gst_handle_resource_error(mm_player_t* player, int code, GstMessage * message)
306 {
307         gint trans_err = MM_ERROR_NONE;
308
309         MMPLAYER_FENTER();
310
311         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
312
313         switch (code) {
314         case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
315                 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
316                 break;
317         case GST_RESOURCE_ERROR_NOT_FOUND:
318         case GST_RESOURCE_ERROR_OPEN_READ:
319                 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
320                         || MMPLAYER_IS_RTSP_STREAMING(player)) {
321                         trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
322                         break;
323                 }
324         case GST_RESOURCE_ERROR_READ:
325                 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
326                         || MMPLAYER_IS_RTSP_STREAMING(player)) {
327                         trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
328                         break;
329                 } else if (message != NULL && message->src != NULL) {
330                         storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
331                         MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
332
333                         if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
334                                 path_type = MMPLAYER_PATH_VOD;
335                         else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
336                                 path_type = MMPLAYER_PATH_TEXT;
337
338                         if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
339                                 /* check storage state */
340                                 storage_get_state(player->storage_info[path_type].id, &storage_state);
341                                 player->storage_info[path_type].state = storage_state;
342                                 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
343                         }
344                 } /* fall through */
345         case GST_RESOURCE_ERROR_WRITE:
346         case GST_RESOURCE_ERROR_FAILED:
347         case GST_RESOURCE_ERROR_SEEK:
348         case GST_RESOURCE_ERROR_TOO_LAZY:
349         case GST_RESOURCE_ERROR_BUSY:
350         case GST_RESOURCE_ERROR_OPEN_WRITE:
351         case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
352         case GST_RESOURCE_ERROR_CLOSE:
353         case GST_RESOURCE_ERROR_SYNC:
354         case GST_RESOURCE_ERROR_SETTINGS:
355         default:
356                 trans_err = MM_ERROR_PLAYER_INTERNAL;
357         break;
358         }
359
360         MMPLAYER_FLEAVE();
361
362         return trans_err;
363 }
364
365 gint
366 __mmplayer_gst_handle_stream_error(mm_player_t* player, GError* error, GstMessage * message)
367 {
368         gint trans_err = MM_ERROR_NONE;
369
370         MMPLAYER_FENTER();
371
372         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
373         MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
374         MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
375
376         switch (error->code) {
377         case GST_STREAM_ERROR_FAILED:
378         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
379         case GST_STREAM_ERROR_DECODE:
380         case GST_STREAM_ERROR_WRONG_TYPE:
381         case GST_STREAM_ERROR_DECRYPT:
382         case GST_STREAM_ERROR_DECRYPT_NOKEY:
383         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
384                 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
385                 break;
386
387         case GST_STREAM_ERROR_NOT_IMPLEMENTED:
388         case GST_STREAM_ERROR_TOO_LAZY:
389         case GST_STREAM_ERROR_ENCODE:
390         case GST_STREAM_ERROR_DEMUX:
391         case GST_STREAM_ERROR_MUX:
392         case GST_STREAM_ERROR_FORMAT:
393         default:
394                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
395                 break;
396         }
397
398         MMPLAYER_FLEAVE();
399
400         return trans_err;
401 }
402
403 gboolean
404 __mmplayer_handle_gst_error(mm_player_t* player, GstMessage * message, GError* error)
405 {
406         MMMessageParamType msg_param;
407         gchar *msg_src_element;
408
409         MMPLAYER_FENTER();
410
411         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
412         MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
413
414         /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
415
416         memset(&msg_param, 0, sizeof(MMMessageParamType));
417
418         if (error->domain == GST_CORE_ERROR) {
419                 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
420         } else if (error->domain == GST_LIBRARY_ERROR) {
421                 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
422         } else if (error->domain == GST_RESOURCE_ERROR) {
423                 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
424         } else if (error->domain == GST_STREAM_ERROR) {
425                 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
426         } else {
427                 LOGW("This error domain is not defined.\n");
428
429                 /* we treat system error as an internal error */
430                 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
431         }
432
433         if (message->src) {
434                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
435
436                 msg_param.data = (void *) error->message;
437
438                 LOGE("-Msg src : [%s]   Domain : [%s]   Error : [%s]  Code : [%d] is tranlated to error code : [0x%x]\n",
439                         msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
440         }
441
442         /* no error */
443         if (msg_param.code == MM_ERROR_NONE)
444                 return TRUE;
445
446         /* skip error to avoid duplicated posting */
447         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
448                  (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
449                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
450                  (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
451
452                 /* The error will be handled by mused.
453                  * @ref _mmplayer_manage_external_storage_state() */
454
455                 LOGW("storage is removed, skip error post");
456                 return TRUE;
457         }
458
459         /* post error to application */
460         if (!player->msg_posted) {
461                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
462                 /* don't post more if one was sent already */
463                 player->msg_posted = TRUE;
464         } else
465                 LOGD("skip error post because it's sent already.\n");
466
467         MMPLAYER_FLEAVE();
468
469         return TRUE;
470 }
471
472 static gboolean
473 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
474 {
475         LOGD("\n");
476         MMMessageParamType msg_param;
477         gchar *msg_src_element = NULL;
478         GstStructure *s = NULL;
479         guint error_id = 0;
480         gchar *error_string = NULL;
481
482         MMPLAYER_FENTER();
483
484         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
485         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
486
487         s = gst_structure_copy(gst_message_get_structure(message));
488
489
490         if (!gst_structure_get_uint(s, "error_id", &error_id))
491                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
492
493         switch (error_id) {
494         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
495                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
496                 break;
497         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
498                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
499                 break;
500         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
501                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
502                 break;
503         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
504                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
505                 break;
506         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
507                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
508                 break;
509         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
510                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
511                 break;
512         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
513                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
514                 break;
515         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
516                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
517                 break;
518         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
519                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
520                 break;
521         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
522                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
523                 break;
524         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
525                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
526                 break;
527         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
528                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
529                 break;
530         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
531                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
532                 break;
533         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
534                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
535                 break;
536         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
537                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
538                 break;
539         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
540                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
541                 break;
542         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
543                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
544                 break;
545         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
546                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
547                 break;
548         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
549                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
550                 break;
551         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
552                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
553                 break;
554         case MMPLAYER_STREAMING_ERROR_GONE:
555                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
556                 break;
557         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
558                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
559                 break;
560         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
561                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
562                 break;
563         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
564                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
565                 break;
566         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
567                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
568                 break;
569         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
570                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
571                 break;
572         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
573                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
574                 break;
575         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
576                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
577                 break;
578         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
579                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
580                 break;
581         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
582                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
583                 break;
584         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
585                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
586                 break;
587         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
588                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
589                 break;
590         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
591                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
592                 break;
593         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
594                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
595                 break;
596         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
597                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
598                 break;
599         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
600                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
601                 break;
602         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
603                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
604                 break;
605         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
606                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
607                 break;
608         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
609                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
610                 break;
611         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
612                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
613                 break;
614         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
615                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
616                 break;
617         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
618                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
619                 break;
620         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
621                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
622                 break;
623         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
624                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
625                 break;
626         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
627                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
628                 break;
629         default:
630                 {
631                         gst_structure_free(s);
632                         return MM_ERROR_PLAYER_STREAMING_FAIL;
633                 }
634         }
635
636         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
637         if (error_string)
638                 msg_param.data = (void *) error_string;
639
640         if (message->src) {
641                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
642
643                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
644                         msg_src_element, msg_param.code, (char*)msg_param.data);
645         }
646
647         /* post error to application */
648         if (!player->msg_posted) {
649                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
650
651                 /* don't post more if one was sent already */
652                 player->msg_posted = TRUE;
653         } else
654                 LOGD("skip error post because it's sent already.\n");
655
656         gst_structure_free(s);
657         g_free(error_string);
658
659         MMPLAYER_FLEAVE();
660         return TRUE;
661
662 }
663
664 static void
665 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata)
666 {
667         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
668         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
669         gst_tag_list_get_string(tags, "stitching_software",
670                         &metadata->stitching_software);
671         gst_tag_list_get_string(tags, "projection_type",
672                         &metadata->projection_type_string);
673         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
674         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
675         gst_tag_list_get_int(tags, "init_view_heading",
676                         &metadata->init_view_heading);
677         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
678         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
679         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
680         gst_tag_list_get_int(tags, "full_pano_width_pixels",
681                         &metadata->full_pano_width_pixels);
682         gst_tag_list_get_int(tags, "full_pano_height_pixels",
683                         &metadata->full_pano_height_pixels);
684         gst_tag_list_get_int(tags, "cropped_area_image_width",
685                         &metadata->cropped_area_image_width);
686         gst_tag_list_get_int(tags, "cropped_area_image_height",
687                         &metadata->cropped_area_image_height);
688         gst_tag_list_get_int(tags, "cropped_area_left",
689                         &metadata->cropped_area_left);
690         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
691         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
692         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
693         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
694 }
695
696 static gboolean
697 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
698 {
699
700 /* macro for better code readability */
701 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
702 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
703         if (string != NULL) { \
704                 SECURE_LOGD("update tag string : %s\n", string); \
705                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
706                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
707                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
708                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
709                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
710                         g_free(new_string); \
711                         new_string = NULL; \
712                 } else { \
713                         mm_attrs_set_string_by_name(attribute, playertag, string); \
714                 } \
715                 g_free(string); \
716                 string = NULL; \
717         } \
718 }
719
720 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
721 do {    \
722         GstSample *sample = NULL;\
723         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
724                 GstMapInfo info = GST_MAP_INFO_INIT;\
725                 buffer = gst_sample_get_buffer(sample);\
726                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
727                         LOGD("failed to get image data from tag");\
728                         gst_sample_unref(sample);\
729                         return FALSE;\
730                 } \
731                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
732                 MMPLAYER_FREEIF(player->album_art);\
733                 player->album_art = (gchar *)g_malloc(info.size);\
734                 if (player->album_art) {\
735                         memcpy(player->album_art, info.data, info.size);\
736                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
737                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
738                                 msg_param.data = (void *)player->album_art;\
739                                 msg_param.size = info.size;\
740                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
741                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
742                         } \
743                 } \
744                 gst_buffer_unmap(buffer, &info);\
745                 gst_sample_unref(sample);\
746         }       \
747 } while (0)
748
749 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
750 do {    \
751         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
752                 if (v_uint) { \
753                         int i = 0; \
754                         gchar *tag_list_str = NULL; \
755                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
756                         if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
757                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
758                         else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
759                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
760                         else \
761                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
762                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
763                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
764                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
765                                 player->bitrate[track_type] = v_uint; \
766                                 player->total_bitrate = 0; \
767                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
768                                         player->total_bitrate += player->bitrate[i]; \
769                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
770                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
771                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
772                                 player->maximum_bitrate[track_type] = v_uint; \
773                                 player->total_maximum_bitrate = 0; \
774                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
775                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
776                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
777                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
778                         } else { \
779                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
780                         } \
781                         v_uint = 0;\
782                         g_free(tag_list_str); \
783                 } \
784         } \
785 } while (0)
786
787 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
788 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
789         if (date != NULL) {\
790                 string = g_strdup_printf("%d", g_date_get_year(date));\
791                 mm_attrs_set_string_by_name(attribute, playertag, string);\
792                 SECURE_LOGD("metainfo year : %s\n", string);\
793                 MMPLAYER_FREEIF(string);\
794                 g_date_free(date);\
795         } \
796 }
797
798 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
799 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
800         if (datetime != NULL) {\
801                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
802                 mm_attrs_set_string_by_name(attribute, playertag, string);\
803                 SECURE_LOGD("metainfo year : %s\n", string);\
804                 MMPLAYER_FREEIF(string);\
805                 gst_date_time_unref(datetime);\
806         } \
807 }
808
809 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
810 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
811         if (v_uint64) {\
812                 /* FIXIT : don't know how to store date */\
813                 g_assert(1);\
814                 v_uint64 = 0;\
815         } \
816 }
817
818 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
819 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
820         if (v_double) {\
821                 /* FIXIT : don't know how to store date */\
822                 g_assert(1);\
823                 v_double = 0;\
824         } \
825 }
826
827         /* function start */
828         GstTagList* tag_list = NULL;
829
830         MMHandleType attrs = 0;
831
832         char *string = NULL;
833         guint v_uint = 0;
834         GDate *date = NULL;
835         GstDateTime *datetime = NULL;
836         /* album cover */
837         GstBuffer *buffer = NULL;
838         gint index = 0;
839         MMMessageParamType msg_param = {0, };
840
841         /* currently not used. but those are needed for above macro */
842         //guint64 v_uint64 = 0;
843         //gdouble v_double = 0;
844
845         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
846
847         attrs = MMPLAYER_GET_ATTRS(player);
848
849         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
850
851         /* get tag list from gst message */
852         gst_message_parse_tag(msg, &tag_list);
853
854         /* store tags to player attributes */
855         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
856         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
857         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
858         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
859         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
860         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
861         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
862         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
863         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
864         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
865         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
866         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
867         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
868         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
869         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
870         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
871         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
872         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
873         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
874         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
875         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
876         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
877         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
878         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
879         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
880         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
881         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
882         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
883         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
884         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
885         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
886         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
887         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
888         MMPLAYER_UPDATE_TAG_LOCK(player);
889         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
890         MMPLAYER_UPDATE_TAG_UNLOCK(player);
891         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
892         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
893         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
894         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
895         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
896         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
897         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
898         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
899         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
900         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
901         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
902         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
903         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
904
905         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
906                 if (player->video360_metadata.is_spherical == -1) {
907                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
908                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
909                                         player->video360_metadata.is_spherical);
910                         if (player->video360_metadata.is_spherical == 1) {
911                                 LOGD("This is spherical content for 360 playback.");
912                                 player->is_content_spherical = TRUE;
913                         } else {
914                                 LOGD("This is not spherical content");
915                                 player->is_content_spherical = FALSE;
916                         }
917
918                         if (player->video360_metadata.projection_type_string) {
919                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
920                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
921                                 } else {
922                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
923                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
924                                 }
925                         }
926
927                         if (player->video360_metadata.stereo_mode_string) {
928                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
929                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
930                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
931                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
932                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
933                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
934                                 } else {
935                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
936                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
937                                 }
938                         }
939                 }
940         }
941
942         if (mm_attrs_commit_all(attrs))
943                 LOGE("failed to commit.\n");
944
945         gst_tag_list_free(tag_list);
946
947         return TRUE;
948 }
949
950 /* if retval is FALSE, it will be dropped for perfomance. */
951 static gboolean
952 __mmplayer_gst_check_useful_message(mm_player_t *player, GstMessage * message)
953 {
954         gboolean retval = FALSE;
955
956         if (!(player->pipeline && player->pipeline->mainbin)) {
957                 LOGE("player pipeline handle is null");
958                 return TRUE;
959         }
960
961         switch (GST_MESSAGE_TYPE(message)) {
962         case GST_MESSAGE_TAG:
963         case GST_MESSAGE_EOS:
964         case GST_MESSAGE_ERROR:
965         case GST_MESSAGE_WARNING:
966         case GST_MESSAGE_CLOCK_LOST:
967         case GST_MESSAGE_NEW_CLOCK:
968         case GST_MESSAGE_ELEMENT:
969         case GST_MESSAGE_DURATION_CHANGED:
970         case GST_MESSAGE_ASYNC_START:
971                 retval = TRUE;
972                 break;
973         case GST_MESSAGE_ASYNC_DONE:
974         case GST_MESSAGE_STATE_CHANGED:
975                 /* we only handle messages from pipeline */
976                 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
977                         retval = TRUE;
978                 else
979                         retval = FALSE;
980                 break;
981         case GST_MESSAGE_BUFFERING:
982         {
983                 gint buffer_percent = 0;
984
985                 retval = TRUE;
986                 gst_message_parse_buffering(message, &buffer_percent);
987                 if (buffer_percent != MAX_BUFFER_PERCENT) {
988                         LOGD("[%s] buffering msg %d%%!!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
989                         break;
990                 }
991
992                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
993                         LOGW("can't get cmd lock, send msg to bus");
994                         break;
995                 }
996
997                 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
998                         LOGD("[%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
999                         player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1000                 }
1001
1002                 MMPLAYER_CMD_UNLOCK(player);
1003
1004                 break;
1005         }
1006         default:
1007                 retval = FALSE;
1008                 break;
1009         }
1010
1011         return retval;
1012 }
1013
1014 static void
1015 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1016 {
1017         MMHandleType attrs = 0;
1018         guint64 data_size = 0;
1019         gchar* path = NULL;
1020         gint64 pos_nsec = 0;
1021         struct stat sb;
1022
1023         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1024
1025         __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1026
1027         attrs = MMPLAYER_GET_ATTRS(player);
1028         if (!attrs) {
1029                 LOGE("fail to get attributes.\n");
1030                 return;
1031         }
1032
1033         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1034                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1035
1036                 if (stat(path, &sb) == 0)
1037                         data_size = (guint64)sb.st_size;
1038         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1039                 data_size = player->http_content_size;
1040         }
1041
1042         __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1043         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1044
1045         return;
1046 }
1047
1048 static int
1049 __mmplayer_handle_buffering_playback(mm_player_t* player)
1050 {
1051         int ret = MM_ERROR_NONE;
1052         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1053         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1054         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1055         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1056
1057         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1058                 LOGW("do nothing for buffering msg\n");
1059                 ret = MM_ERROR_PLAYER_INVALID_STATE;
1060                 goto exit;
1061         }
1062
1063         prev_state = MMPLAYER_PREV_STATE(player);
1064         current_state = MMPLAYER_CURRENT_STATE(player);
1065         target_state = MMPLAYER_TARGET_STATE(player);
1066         pending_state = MMPLAYER_PENDING_STATE(player);
1067
1068         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1069                 MMPLAYER_STATE_GET_NAME(prev_state),
1070                 MMPLAYER_STATE_GET_NAME(current_state),
1071                 MMPLAYER_STATE_GET_NAME(pending_state),
1072                 MMPLAYER_STATE_GET_NAME(target_state),
1073                 player->streamer->buffering_state);
1074
1075         if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1076                 /* NOTE : if buffering has done, player has to go to target state. */
1077                 switch (target_state) {
1078                 case MM_PLAYER_STATE_PAUSED:
1079                         {
1080                                 switch (pending_state) {
1081                                 case MM_PLAYER_STATE_PLAYING:
1082                                         __mmplayer_gst_pause(player, TRUE);
1083                                         break;
1084
1085                                 case MM_PLAYER_STATE_PAUSED:
1086                                         LOGD("player is already going to paused state, there is nothing to do.\n");
1087                                         break;
1088
1089                                 case MM_PLAYER_STATE_NONE:
1090                                 case MM_PLAYER_STATE_NULL:
1091                                 case MM_PLAYER_STATE_READY:
1092                                 default:
1093                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1094                                         break;
1095                                 }
1096                         }
1097                         break;
1098
1099                 case MM_PLAYER_STATE_PLAYING:
1100                         {
1101                                 switch (pending_state) {
1102                                 case MM_PLAYER_STATE_NONE:
1103                                         {
1104                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
1105                                                         __mmplayer_gst_resume(player, TRUE);
1106                                         }
1107                                         break;
1108
1109                                 case MM_PLAYER_STATE_PAUSED:
1110                                         /* NOTE: It should be worked as asynchronously.
1111                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1112                                          */
1113                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
1114                                                 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1115                                                  * The current state should be changed to paused purposely to prevent state conflict.
1116                                                  */
1117                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1118                                         }
1119                                         __mmplayer_gst_resume(player, TRUE);
1120                                         break;
1121
1122                                 case MM_PLAYER_STATE_PLAYING:
1123                                         LOGD("player is already going to playing state, there is nothing to do.\n");
1124                                         break;
1125
1126                                 case MM_PLAYER_STATE_NULL:
1127                                 case MM_PLAYER_STATE_READY:
1128                                 default:
1129                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1130                                         break;
1131                                 }
1132                         }
1133                         break;
1134
1135                 case MM_PLAYER_STATE_NULL:
1136                 case MM_PLAYER_STATE_READY:
1137                 case MM_PLAYER_STATE_NONE:
1138                 default:
1139                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1140                         break;
1141                 }
1142         } else {
1143                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1144                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
1145                  */
1146                 switch (pending_state) {
1147                 case MM_PLAYER_STATE_NONE:
1148                         {
1149                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
1150                                         /* rtsp streaming pause makes rtsp server stop sending data. */
1151                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1152                                                 LOGD("set pause state during buffering\n");
1153                                                 __mmplayer_gst_pause(player, TRUE);
1154                                         }
1155                                 }
1156                         }
1157                         break;
1158
1159                 case MM_PLAYER_STATE_PLAYING:
1160                         /* rtsp streaming pause makes rtsp server stop sending data. */
1161                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
1162                                 __mmplayer_gst_pause(player, TRUE);
1163                         break;
1164
1165                 case MM_PLAYER_STATE_PAUSED:
1166                         break;
1167
1168                 case MM_PLAYER_STATE_NULL:
1169                 case MM_PLAYER_STATE_READY:
1170                 default:
1171                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1172                         break;
1173                 }
1174         }
1175
1176 exit:
1177         return ret;
1178 }
1179
1180 static VariantData *
1181 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1182 {
1183         VariantData *var_info = NULL;
1184         g_return_val_if_fail(self != NULL, NULL);
1185
1186         var_info = g_new0(VariantData, 1);
1187         if (!var_info) return NULL;
1188         var_info->bandwidth = self->bandwidth;
1189         var_info->width = self->width;
1190         var_info->height = self->height;
1191         return var_info;
1192 }
1193
1194 static gboolean
1195 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1196 {
1197         gint64 bytes = 0;
1198
1199         MMPLAYER_FENTER();
1200
1201         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1202         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1203
1204         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1205                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1206                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1207
1208                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1209                         LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1210                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1211                 }
1212         } else {
1213                 /* handling audio clip which has vbr. means duration is keep changing */
1214                 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1215         }
1216
1217         MMPLAYER_FLEAVE();
1218
1219         return TRUE;
1220 }
1221
1222 static gboolean
1223 __mmplayer_eos_timer_cb(gpointer u_data)
1224 {
1225         mm_player_t* player = NULL;
1226         MMHandleType attrs = 0;
1227         int count = 0;
1228
1229         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1230
1231         player = (mm_player_t*) u_data;
1232         attrs = MMPLAYER_GET_ATTRS(player);
1233
1234         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1235
1236         if (count == -1) {
1237                 gint ret_value = 0;
1238                 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1239                 if (ret_value != MM_ERROR_NONE)
1240                         LOGE("seeking to 0 failed in repeat play");
1241         } else {
1242                 /* posting eos */
1243                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1244         }
1245
1246         /* we are returning FALSE as we need only one posting */
1247         return FALSE;
1248 }
1249
1250 static void
1251 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
1252 {
1253         MMPLAYER_RETURN_IF_FAIL(player);
1254
1255         /* post now if delay is zero */
1256         if (delay_in_ms == 0 || player->audio_stream_render_cb) {
1257                 LOGD("eos delay is zero. posting EOS now\n");
1258                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1259
1260                 if (player->audio_stream_render_cb)
1261                         __mmplayer_cancel_eos_timer(player);
1262
1263                 return;
1264         }
1265
1266         /* cancel if existing */
1267         __mmplayer_cancel_eos_timer(player);
1268
1269         /* init new timeout */
1270         /* NOTE : consider give high priority to this timer */
1271         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
1272
1273         player->eos_timer = g_timeout_add(delay_in_ms,
1274                 __mmplayer_eos_timer_cb, player);
1275
1276         player->context.global_default = g_main_context_default();
1277         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1278
1279         /* check timer is valid. if not, send EOS now */
1280         if (player->eos_timer == 0) {
1281                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
1282                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1283         }
1284 }
1285
1286 static int __mmplayer_gst_pending_seek(mm_player_t* player)
1287 {
1288         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1289         int ret = MM_ERROR_NONE;
1290
1291         MMPLAYER_FENTER();
1292
1293         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1294
1295         if (!player->pending_seek.is_pending) {
1296                 LOGD("pending seek is not reserved. nothing to do.\n");
1297                 return ret;
1298         }
1299
1300         /* check player state if player could pending seek or not. */
1301         current_state = MMPLAYER_CURRENT_STATE(player);
1302
1303         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1304                 LOGW("try to pending seek in %s state, try next time. \n",
1305                         MMPLAYER_STATE_GET_NAME(current_state));
1306                 return ret;
1307         }
1308
1309         LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1310
1311         ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1312
1313         if (MM_ERROR_NONE != ret)
1314                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1315
1316         player->pending_seek.is_pending = FALSE;
1317
1318         MMPLAYER_FLEAVE();
1319
1320         return ret;
1321 }
1322
1323 static void
1324 __mmplayer_gst_set_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
1325 {
1326         MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1327
1328         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1329
1330         audiobin = player->pipeline->audiobin; /* can be null */
1331         videobin = player->pipeline->videobin; /* can be null */
1332         textbin = player->pipeline->textbin;   /* can be null */
1333
1334         LOGD("Async will be set to %d about 0x%X type sink", async, type);
1335
1336         if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1337                 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1338
1339         if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1340                 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1341
1342         if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1343                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1344
1345         return;
1346 }
1347
1348 static void
1349 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1350 {
1351         MMPlayerGstElement *textbin;
1352         MMPLAYER_FENTER();
1353
1354         MMPLAYER_RETURN_IF_FAIL(player &&
1355                                         player->pipeline &&
1356                                         player->pipeline->textbin);
1357
1358         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1359
1360         textbin = player->pipeline->textbin;
1361
1362         if (is_drop) {
1363                 LOGD("Drop subtitle text after getting EOS\n");
1364
1365                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1366                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1367
1368                 player->is_subtitle_force_drop = TRUE;
1369         } else {
1370                 if (player->is_subtitle_force_drop == TRUE) {
1371                         LOGD("Enable subtitle data path without drop\n");
1372
1373                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1374                         __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1375
1376                         LOGD("non-connected with external display");
1377
1378                         player->is_subtitle_force_drop = FALSE;
1379                 }
1380         }
1381 }
1382
1383 static void
1384 __mmplayer_gst_handle_eos_message(mm_player_t* player, GstMessage *msg)
1385 {
1386         MMHandleType attrs = 0;
1387         gint count = 0;
1388
1389         MMPLAYER_FENTER();
1390
1391         /* NOTE : EOS event is comming multiple time. watch out it */
1392         /* check state. we only process EOS when pipeline state goes to PLAYING */
1393         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1394                 LOGD("EOS received on non-playing state. ignoring it");
1395                 return;
1396         }
1397
1398         if (player->pipeline && player->pipeline->textbin)
1399                 __mmplayer_drop_subtitle(player, TRUE);
1400
1401         if ((player->audio_stream_render_cb) && (!player->audio_stream_sink_sync))
1402                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1403
1404         /* rewind if repeat count is greater then zero */
1405         /* get play count */
1406         attrs = MMPLAYER_GET_ATTRS(player);
1407
1408         if (attrs) {
1409                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1410
1411                 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1412
1413                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1414                         if (player->playback_rate < 0.0) {
1415                                 player->resumed_by_rewind = TRUE;
1416                                 _mmplayer_set_mute((MMHandleType)player, 0);
1417                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1418                         }
1419
1420                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1421
1422                         /* initialize */
1423                         player->sent_bos = FALSE;
1424
1425                         LOGD("do not post eos msg for repeating");
1426                         return;
1427                 }
1428         }
1429
1430         if (player->pipeline)
1431                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1432
1433         /* post eos message to application */
1434         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1435
1436         /* reset last position */
1437         player->last_position = 0;
1438
1439         MMPLAYER_FLEAVE();
1440         return;
1441 }
1442
1443 static void
1444 __mmplayer_gst_handle_error_message(mm_player_t* player, GstMessage *msg)
1445 {
1446         GError *error = NULL;
1447         gchar* debug = NULL;
1448
1449         MMPLAYER_FENTER();
1450
1451         /* generating debug info before returning error */
1452         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1453
1454         /* get error code */
1455         gst_message_parse_error(msg, &error, &debug);
1456
1457         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1458                 /* Note : the streaming error from the streaming source is handled
1459                  *       using __mmplayer_handle_streaming_error.
1460                  */
1461                 __mmplayer_handle_streaming_error(player, msg);
1462
1463                 /* dump state of all element */
1464                 __mmplayer_dump_pipeline_state(player);
1465         } else {
1466                 /* traslate gst error code to msl error code. then post it
1467                  * to application if needed
1468                  */
1469                 __mmplayer_handle_gst_error(player, msg, error);
1470
1471                 if (debug)
1472                         LOGE("error debug : %s", debug);
1473         }
1474
1475         if (MMPLAYER_IS_HTTP_PD(player))
1476                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1477
1478         MMPLAYER_FREEIF(debug);
1479         g_error_free(error);
1480
1481         MMPLAYER_FLEAVE();
1482         return;
1483 }
1484
1485 static void
1486 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1487 {
1488         MMMessageParamType msg_param = {0, };
1489         int bRet = MM_ERROR_NONE;
1490
1491         MMPLAYER_FENTER();
1492         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1493
1494         if (!MMPLAYER_IS_STREAMING(player)) {
1495                 LOGW("this is not streaming playback.");
1496                 return;
1497         }
1498
1499         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1500                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1501                         /* skip the playback control by buffering msg while user request is handled. */
1502                         gint per = 0;
1503
1504                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1505
1506                         gst_message_parse_buffering(msg, &per);
1507                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1508
1509                         msg_param.connection.buffering = per;
1510                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1511                         return;
1512                 }
1513         } else {
1514                 MMPLAYER_CMD_LOCK(player);
1515         }
1516
1517         if (!player->streamer) {
1518                 LOGW("Pipeline is shutting down");
1519                 MMPLAYER_CMD_UNLOCK(player);
1520                 return;
1521         }
1522
1523         /* ignore the remained buffering message till getting 100% msg */
1524         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1525                 gint buffer_percent = 0;
1526
1527                 gst_message_parse_buffering(msg, &buffer_percent);
1528
1529                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1530                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1531                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1532                 }
1533                 MMPLAYER_CMD_UNLOCK(player);
1534                 return;
1535         }
1536
1537         /* ignore the remained buffering message */
1538         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1539                 gint buffer_percent = 0;
1540
1541                 gst_message_parse_buffering(msg, &buffer_percent);
1542
1543                 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1544                                         player->streamer->buffering_percent, buffer_percent);
1545
1546                 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1547                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1548                         player->streamer->buffering_req.is_pre_buffering = FALSE;
1549
1550                         LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1551                 } else {
1552                         LOGD("interrupted buffering - ignored the remained buffering msg!");
1553                         MMPLAYER_CMD_UNLOCK(player);
1554                         return;
1555                 }
1556         }
1557
1558         __mmplayer_update_buffer_setting(player, msg);
1559
1560         bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1561
1562         if (bRet == MM_ERROR_NONE) {
1563                 msg_param.connection.buffering = player->streamer->buffering_percent;
1564                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1565
1566                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1567                         player->pending_resume &&
1568                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1569
1570                         player->is_external_subtitle_added_now = FALSE;
1571                         player->pending_resume = FALSE;
1572                         _mmplayer_resume((MMHandleType)player);
1573                 }
1574
1575                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1576                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1577
1578                         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1579                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1580                                         player->seek_state = MMPLAYER_SEEK_NONE;
1581                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1582                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1583                                         /* Considering the async state trasition in case of RTSP.
1584                                            After getting state change gst msg, seek cmpleted msg will be posted. */
1585                                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1586                                 }
1587                         }
1588                 }
1589         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1590                 if (!player->streamer) {
1591                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1592                         MMPLAYER_CMD_UNLOCK(player);
1593                         return;
1594                 }
1595
1596                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1597
1598                         LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1599                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1600
1601                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1602                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1603                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1604                         } else {
1605                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1606                         }
1607                 } else {
1608                         msg_param.connection.buffering = player->streamer->buffering_percent;
1609                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1610                 }
1611         }
1612         MMPLAYER_CMD_UNLOCK(player);
1613
1614         MMPLAYER_FLEAVE();
1615         return;
1616
1617 }
1618
1619 static void
1620 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1621 {
1622         MMPlayerGstElement *mainbin;
1623         const GValue *voldstate, *vnewstate, *vpending;
1624         GstState oldstate = GST_STATE_NULL;
1625         GstState newstate = GST_STATE_NULL;
1626         GstState pending = GST_STATE_NULL;
1627
1628         MMPLAYER_FENTER();
1629         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1630
1631         mainbin = player->pipeline->mainbin;
1632
1633         /* we only handle messages from pipeline */
1634         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1635                 return;
1636
1637         /* get state info from msg */
1638         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1639         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1640         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1641
1642         if (!voldstate || !vnewstate) {
1643                 LOGE("received msg has wrong format.");
1644                 return;
1645         }
1646
1647         oldstate = (GstState)voldstate->data[0].v_int;
1648         newstate = (GstState)vnewstate->data[0].v_int;
1649         if (vpending)
1650                 pending = (GstState)vpending->data[0].v_int;
1651
1652         LOGD("state changed [%s] : %s ---> %s     final : %s",
1653                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1654                 gst_element_state_get_name((GstState)oldstate),
1655                 gst_element_state_get_name((GstState)newstate),
1656                 gst_element_state_get_name((GstState)pending));
1657
1658         if (newstate == GST_STATE_PLAYING) {
1659                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1660
1661                         int retVal = MM_ERROR_NONE;
1662                         LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1663
1664                         retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1665
1666                         if (MM_ERROR_NONE != retVal)
1667                                 LOGE("failed to seek pending postion. just keep staying current position.");
1668
1669                         player->pending_seek.is_pending = FALSE;
1670                 }
1671         }
1672
1673         if (oldstate == newstate) {
1674                 LOGD("pipeline reports state transition to old state");
1675                 return;
1676         }
1677
1678         switch (newstate) {
1679         case GST_STATE_PAUSED:
1680                 {
1681                         gboolean prepare_async = FALSE;
1682
1683                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1684                                 // managed prepare async case
1685                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1686                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1687                         }
1688
1689                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1690                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1691
1692                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1693                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1694                                                 player->total_maximum_bitrate, player->total_bitrate);
1695
1696                                 if (player->pending_seek.is_pending) {
1697                                         LOGW("trying to do pending seek");
1698                                         MMPLAYER_CMD_LOCK(player);
1699                                         __mmplayer_gst_pending_seek(player);
1700                                         MMPLAYER_CMD_UNLOCK(player);
1701                                 }
1702                         }
1703                 }
1704                 break;
1705
1706         case GST_STATE_PLAYING:
1707                 {
1708                         if (MMPLAYER_IS_STREAMING(player)) {
1709                                 // managed prepare async case when buffering is completed
1710                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1711                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1712                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1713                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1714
1715                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1716
1717                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1718                                         if (player->streamer->buffering_percent < 100) {
1719
1720                                                 MMMessageParamType msg_param = {0, };
1721                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1722
1723                                                 msg_param.connection.buffering = 100;
1724                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1725                                         }
1726                                 }
1727                         }
1728
1729                         if (player->gapless.stream_changed) {
1730                                 __mmplayer_update_content_attrs(player, ATTR_ALL);
1731                                 player->gapless.stream_changed = FALSE;
1732                         }
1733
1734                         if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1735                                 player->seek_state = MMPLAYER_SEEK_NONE;
1736                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1737                         }
1738                 }
1739                 break;
1740         case GST_STATE_VOID_PENDING:
1741         case GST_STATE_NULL:
1742         case GST_STATE_READY:
1743         default:
1744                 break;
1745         }
1746
1747         MMPLAYER_FLEAVE();
1748         return;
1749 }
1750
1751 static void
1752 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1753 {
1754         const gchar *structure_name;
1755         gint count = 0, idx = 0;
1756         MMHandleType attrs = 0;
1757
1758         MMPLAYER_FENTER();
1759         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1760
1761         attrs = MMPLAYER_GET_ATTRS(player);
1762         if (!attrs) {
1763                 LOGE("Failed to get content attribute");
1764                 return;
1765         }
1766
1767         if (gst_message_get_structure(msg) == NULL)
1768                 return;
1769
1770         structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1771         if (!structure_name)
1772                 return;
1773
1774         LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1775
1776         if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1777                 const GValue *var_info = NULL;
1778
1779                 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1780                 if (var_info != NULL) {
1781                         if (player->adaptive_info.var_list)
1782                                 g_list_free_full(player->adaptive_info.var_list, g_free);
1783
1784                         /* share addr or copy the list */
1785                         player->adaptive_info.var_list =
1786                                 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1787
1788                         count = g_list_length(player->adaptive_info.var_list);
1789                         if (count > 0) {
1790                                 VariantData *temp = NULL;
1791
1792                                 /* print out for debug */
1793                                 LOGD("num of variant_info %d", count);
1794                                 for (idx = 0; idx < count; idx++) {
1795                                         temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1796                                         if (temp)
1797                                                 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1798                                 }
1799                         }
1800                 }
1801         }
1802
1803         if (!strcmp(structure_name, "prepare-decode-buffers")) {
1804                 gint num_buffers = 0;
1805                 gint extra_num_buffers = 0;
1806
1807                 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1808                         player->video_num_buffers = num_buffers;
1809                         LOGD("video_num_buffers : %d", player->video_num_buffers);
1810                 }
1811
1812                 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1813                         player->video_extra_num_buffers = extra_num_buffers;
1814                         LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1815                 }
1816                 return;
1817         }
1818
1819         if (!strcmp(structure_name, "Language_list")) {
1820                 const GValue *lang_list = NULL;
1821                 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1822                 if (lang_list != NULL) {
1823                         count = g_list_length((GList *)g_value_get_pointer(lang_list));
1824                         if (count > 1)
1825                                 LOGD("Total audio tracks(from parser) = %d \n", count);
1826                 }
1827         }
1828
1829         if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1830                 const GValue *lang_list = NULL;
1831                 MMPlayerLangStruct *temp = NULL;
1832
1833                 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1834                 if (lang_list != NULL) {
1835                         count = g_list_length((GList *)g_value_get_pointer(lang_list));
1836                         if (count) {
1837                                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1838                                 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1839                                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1840                                 if (mm_attrs_commit_all(attrs))
1841                                         LOGE("failed to commit.\n");
1842                                 LOGD("Total subtitle tracks = %d \n", count);
1843
1844                                 while (count) {
1845                                         temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1846                                         if (temp)
1847                                                 LOGD("value of lang_key is %s and lang_code is %s",
1848                                                                         temp->language_key, temp->language_code);
1849                                         count--;
1850                                 }
1851                                 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1852                                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1853                         }
1854                 }
1855         }
1856
1857         /* custom message */
1858         if (!strcmp(structure_name, "audio_codec_not_supported")) {
1859                 MMMessageParamType msg_param = {0,};
1860                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1861                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1862         }
1863
1864         /* custom message for RTSP attribute :
1865                 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1866                 sdp which has contents info is received when rtsp connection is opened.
1867                 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1868         if (!strcmp(structure_name, "rtspsrc_properties")) {
1869
1870                 gchar *audio_codec = NULL;
1871                 gchar *video_codec = NULL;
1872                 gchar *video_frame_size = NULL;
1873
1874                 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1875                 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1876                 player->streaming_type = __mmplayer_get_stream_service_type(player);
1877
1878                 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1879                 LOGD("rtsp_audio_codec : %s", audio_codec);
1880                 if (audio_codec)
1881                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1882
1883                 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1884                 LOGD("rtsp_video_codec : %s", video_codec);
1885                 if (video_codec)
1886                         mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1887
1888                 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1889                 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1890                 if (video_frame_size) {
1891
1892                         char *seperator = strchr(video_frame_size, '-');
1893                         if (seperator) {
1894
1895                                 char video_width[10] = {0,};
1896                                 int frame_size_len = strlen(video_frame_size);
1897                                 int separtor_len = strlen(seperator);
1898
1899                                 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1900                                 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1901
1902                                 seperator++;
1903                                 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1904                         }
1905                 }
1906
1907                 if (mm_attrs_commit_all(attrs))
1908                         LOGE("failed to commit.\n");
1909         }
1910
1911         MMPLAYER_FLEAVE();
1912         return;
1913 }
1914
1915 static void
1916 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1917 {
1918         MMPlayerGstElement *mainbin;
1919
1920         MMPLAYER_FENTER();
1921         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1922
1923         mainbin = player->pipeline->mainbin;
1924
1925         LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1926
1927         /* we only handle messages from pipeline */
1928         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1929                 return;
1930
1931         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1932                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1933                         player->seek_state = MMPLAYER_SEEK_NONE;
1934                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1935                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1936                         if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1937                                 LOGD("sync %s state(%s) with parent state(%s)",
1938                                         GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1939                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1940                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1941
1942                                 /* In case of streaming, pause is required before finishing seeking by buffering.
1943                                    After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1944                                    Because the buffering state is controlled according to the state transition for force resume,
1945                                    the decodebin state should be paused as player state. */
1946                                 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1947                         }
1948
1949                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1950                                 (player->streamer) &&
1951                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1952                                 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1953                                 GstQuery *query = NULL;
1954                                 gboolean busy = FALSE;
1955                                 gint percent = 0;
1956
1957                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1958                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1959                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1960                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1961                                         gst_query_unref(query);
1962
1963                                         LOGD("buffered percent(%s): %d\n",
1964                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1965                                 }
1966
1967                                 if (percent >= 100)
1968                                         __mmplayer_handle_buffering_playback(player);
1969                         }
1970
1971                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1972                 }
1973         }
1974
1975         MMPLAYER_FLEAVE();
1976         return;
1977 }
1978
1979 static void
1980 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1981 {
1982         mm_player_t* player = (mm_player_t*)(data);
1983
1984         MMPLAYER_RETURN_IF_FAIL(player);
1985         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1986
1987         switch (GST_MESSAGE_TYPE(msg)) {
1988         case GST_MESSAGE_UNKNOWN:
1989                 LOGD("unknown message received\n");
1990                 break;
1991
1992         case GST_MESSAGE_EOS:
1993                 LOGD("GST_MESSAGE_EOS received");
1994                 __mmplayer_gst_handle_eos_message(player, msg);
1995                 break;
1996
1997         case GST_MESSAGE_ERROR:
1998                 __mmplayer_gst_handle_error_message(player, msg);
1999                 break;
2000
2001         case GST_MESSAGE_WARNING:
2002                 {
2003                         char* debug = NULL;
2004                         GError* error = NULL;
2005
2006                         gst_message_parse_warning(msg, &error, &debug);
2007
2008                         LOGD("warning : %s\n", error->message);
2009                         LOGD("debug : %s\n", debug);
2010
2011                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2012
2013                         MMPLAYER_FREEIF(debug);
2014                         g_error_free(error);
2015                 }
2016                 break;
2017
2018         case GST_MESSAGE_TAG:
2019                 {
2020                         LOGD("GST_MESSAGE_TAG\n");
2021                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2022                                 LOGW("failed to extract tags from gstmessage\n");
2023                 }
2024                 break;
2025
2026         case GST_MESSAGE_BUFFERING:
2027                 __mmplayer_gst_handle_buffering_message(player, msg);
2028                 break;
2029
2030         case GST_MESSAGE_STATE_CHANGED:
2031                 __mmplayer_gst_handle_state_message(player, msg);
2032                 break;
2033
2034         case GST_MESSAGE_CLOCK_LOST:
2035                         {
2036                                 GstClock *clock = NULL;
2037                                 gboolean need_new_clock = FALSE;
2038
2039                                 gst_message_parse_clock_lost(msg, &clock);
2040                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2041
2042                                 if (!player->videodec_linked)
2043                                         need_new_clock = TRUE;
2044                                 else if (!player->ini.use_system_clock)
2045                                         need_new_clock = TRUE;
2046
2047                                 if (need_new_clock) {
2048                                         LOGD("Provide clock is TRUE, do pause->resume\n");
2049                                         __mmplayer_gst_pause(player, FALSE);
2050                                         __mmplayer_gst_resume(player, FALSE);
2051                                 }
2052                         }
2053                         break;
2054
2055         case GST_MESSAGE_NEW_CLOCK:
2056                         {
2057                                 GstClock *clock = NULL;
2058                                 gst_message_parse_new_clock(msg, &clock);
2059                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2060                         }
2061                         break;
2062
2063         case GST_MESSAGE_ELEMENT:
2064                 __mmplayer_gst_handle_element_message(player, msg);
2065                         break;
2066
2067         case GST_MESSAGE_DURATION_CHANGED:
2068                 {
2069                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2070                         if (!__mmplayer_gst_handle_duration(player, msg))
2071                                 LOGW("failed to update duration");
2072                 }
2073                 break;
2074
2075         case GST_MESSAGE_ASYNC_START:
2076                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2077                 break;
2078
2079         case GST_MESSAGE_ASYNC_DONE:
2080                 __mmplayer_gst_handle_async_done_message(player, msg);
2081                 break;
2082
2083         #if 0 /* delete unnecessary logs */
2084         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2085         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
2086         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
2087         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
2088         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
2089         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2090         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2091         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2092         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2093         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2094         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2095         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
2096         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2097         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2098         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
2099         #endif
2100
2101         default:
2102                 break;
2103         }
2104
2105         /* should not call 'gst_message_unref(msg)' */
2106         return;
2107 }
2108
2109 static GstBusSyncReply
2110 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2111 {
2112         mm_player_t *player = (mm_player_t *)data;
2113         GstBusSyncReply reply = GST_BUS_DROP;
2114
2115         if (!(player->pipeline && player->pipeline->mainbin)) {
2116                 LOGE("player pipeline handle is null");
2117                 return GST_BUS_PASS;
2118         }
2119
2120         if (!__mmplayer_gst_check_useful_message(player, message)) {
2121                 gst_message_unref(message);
2122                 return GST_BUS_DROP;
2123         }
2124
2125         switch (GST_MESSAGE_TYPE(message)) {
2126         case GST_MESSAGE_TAG:
2127                 __mmplayer_gst_extract_tag_from_msg(player, message);
2128
2129                 #if 0 // debug
2130                 {
2131                         GstTagList *tags = NULL;
2132
2133                         gst_message_parse_tag(message, &tags);
2134                         if (tags) {
2135                                 LOGE("TAGS received from element \"%s\".\n",
2136                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2137
2138                                 gst_tag_list_foreach(tags, print_tag, NULL);
2139                                 gst_tag_list_free(tags);
2140                                 tags = NULL;
2141                         }
2142                         break;
2143                 }
2144                 #endif
2145                 break;
2146
2147         case GST_MESSAGE_DURATION_CHANGED:
2148                 __mmplayer_gst_handle_duration(player, message);
2149                 break;
2150         case GST_MESSAGE_ASYNC_DONE:
2151                 /* NOTE:Don't call gst_callback directly
2152                  * because previous frame can be showed even though this message is received for seek.
2153                  */
2154         default:
2155                 reply = GST_BUS_PASS;
2156                 break;
2157         }
2158
2159         if (reply == GST_BUS_DROP)
2160                 gst_message_unref(message);
2161
2162         return reply;
2163 }
2164
2165 static void
2166 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2167 {
2168         GstElement *appsrc = element;
2169         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2170         GstBuffer *buffer = NULL;
2171         GstFlowReturn ret = GST_FLOW_OK;
2172         gint len = size;
2173
2174         MMPLAYER_RETURN_IF_FAIL(element);
2175         MMPLAYER_RETURN_IF_FAIL(buf);
2176
2177         buffer = gst_buffer_new();
2178
2179         if (buf->offset < 0 || buf->len < 0) {
2180                 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2181                 return;
2182         }
2183
2184         if (buf->offset >= buf->len) {
2185                 LOGD("call eos appsrc");
2186                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2187                 return;
2188         }
2189
2190         if (buf->len - buf->offset < size)
2191                 len = buf->len - buf->offset;
2192
2193         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2194         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2195         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2196
2197         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2198         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2199
2200         buf->offset += len;
2201 }
2202
2203 static gboolean
2204 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2205 {
2206         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2207
2208         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2209
2210         buf->offset  = (int)size;
2211
2212         return TRUE;
2213 }
2214
2215 void
2216 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2217 {
2218         mm_player_t *player  = (mm_player_t*)user_data;
2219         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2220         guint64 current_level_bytes = 0;
2221
2222         MMPLAYER_RETURN_IF_FAIL(player);
2223
2224         if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2225                 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2226         else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2227                 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2228         else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2229                 type = MM_PLAYER_STREAM_TYPE_TEXT;
2230         else {
2231                 LOGE("can not enter here");
2232                 return;
2233         }
2234
2235         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2236
2237         LOGI("type: %d, level: %llu", type, current_level_bytes);
2238
2239         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2240         if (player->media_stream_buffer_status_cb[type])
2241                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2242         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2243 }
2244
2245 void
2246 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2247 {
2248         mm_player_t *player  = (mm_player_t*)user_data;
2249         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2250         guint64 current_level_bytes = 0;
2251
2252         MMPLAYER_RETURN_IF_FAIL(player);
2253
2254         if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2255                 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2256         else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2257                 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2258         else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2259                 type = MM_PLAYER_STREAM_TYPE_TEXT;
2260         else {
2261                 LOGE("can not enter here");
2262                 return;
2263         }
2264
2265         LOGI("type: %d, buffer is full", type);
2266
2267         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2268
2269         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2270
2271         if (player->media_stream_buffer_status_cb[type])
2272                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2273
2274         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2275 }
2276
2277 gboolean
2278 __mmplayer_gst_appsrc_seek_data(GstElement * element, guint64 position, gpointer user_data)
2279 {
2280         mm_player_t *player  = (mm_player_t*)user_data;
2281         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2282
2283         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2284
2285         if (g_strrstr(GST_ELEMENT_NAME(element), "audio"))
2286                 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2287         else if (g_strrstr(GST_ELEMENT_NAME(element), "video"))
2288                 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2289         else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle"))
2290                 type = MM_PLAYER_STREAM_TYPE_TEXT;
2291         else {
2292                 LOGE("can not enter here");
2293                 return TRUE;
2294         }
2295
2296         LOGD("type: %d, pos: %llu", type, position);
2297         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2298
2299         if (player->media_stream_seek_data_cb[type])
2300                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2301         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2302
2303         return TRUE;
2304 }
2305
2306 static gboolean
2307 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad* srcpad)
2308 {
2309 #define MAX_LEN_NAME 20
2310
2311         gboolean ret = FALSE;
2312         GstPad *sinkpad = NULL;
2313         gchar *prefix = NULL;
2314         gchar dec_name[MAX_LEN_NAME] = {0};
2315         enum MainElementID elem_id = MMPLAYER_M_NUM;
2316
2317         MMPlayerGstElement *mainbin = NULL;
2318         GstElement *decodebin = NULL;
2319         GstCaps *dec_caps = NULL;
2320
2321         MMPLAYER_FENTER();
2322
2323         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2324                                                 player->pipeline &&
2325                                                 player->pipeline->mainbin, FALSE);
2326         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2327
2328         mainbin = player->pipeline->mainbin;
2329         switch (type) {
2330         case MM_PLAYER_STREAM_TYPE_AUDIO:
2331                 prefix = "audio";
2332                 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2333         break;
2334         case MM_PLAYER_STREAM_TYPE_VIDEO:
2335                 prefix = "video";
2336                 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2337         break;
2338         default:
2339                 LOGE("invalid type %d", type);
2340                 return FALSE;
2341         }
2342
2343         if (mainbin[elem_id].gst) {
2344                 LOGE("elem(%d) is already created", elem_id);
2345                 return FALSE;
2346         }
2347
2348         snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2349
2350         /* create decodebin */
2351         decodebin = gst_element_factory_make("decodebin", dec_name);
2352         if (!decodebin) {
2353                 LOGE("failed to create %s", dec_name);
2354                 return FALSE;
2355         }
2356
2357         mainbin[elem_id].id = elem_id;
2358         mainbin[elem_id].gst = decodebin;
2359
2360         /* raw pad handling signal */
2361         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2362                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2363
2364         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2365         before looking for any elements that can handle that stream.*/
2366         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2367                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2368
2369         /* This signal is emitted when a element is added to the bin.*/
2370         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2371                                                                                 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2372
2373         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2374                 LOGE("failed to add new decodebin");
2375                 return FALSE;
2376         }
2377
2378         dec_caps = gst_pad_query_caps(srcpad, NULL);
2379         if (dec_caps) {
2380                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2381                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2382                 gst_caps_unref(dec_caps);
2383         }
2384
2385         sinkpad = gst_element_get_static_pad(decodebin, "sink");
2386
2387         if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2388                 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2389                 goto ERROR;
2390         }
2391         gst_object_unref(GST_OBJECT(sinkpad));
2392
2393         gst_element_sync_state_with_parent(decodebin);
2394         MMPLAYER_FLEAVE();
2395         return TRUE;
2396
2397 ERROR:
2398         if (sinkpad)
2399                 gst_object_unref(GST_OBJECT(sinkpad));
2400
2401         if (mainbin[elem_id].gst) {
2402                 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2403                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2404                 gst_object_unref(mainbin[elem_id].gst);
2405                 mainbin[elem_id].gst = NULL;
2406         }
2407
2408         MMPLAYER_FLEAVE();
2409         return ret;
2410 }
2411
2412 static gboolean
2413 __mmplayer_gst_create_es_path(mm_player_t* player, MMPlayerStreamType type, GstCaps* caps)
2414 {
2415 #define MAX_LEN_NAME 20
2416         MMPlayerGstElement *mainbin = NULL;
2417         gchar *prefix = NULL;
2418         enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2419
2420         gchar src_name[MAX_LEN_NAME] = {0}, queue_name[MAX_LEN_NAME] = {0};
2421         GstElement *src = NULL, *queue = NULL;
2422         GstPad *srcpad = NULL;
2423
2424         MMPLAYER_FENTER();
2425         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2426                                 player->pipeline->mainbin, FALSE);
2427
2428         mainbin = player->pipeline->mainbin;
2429
2430         LOGD("type(%d) path is creating", type);
2431         switch (type) {
2432         case MM_PLAYER_STREAM_TYPE_AUDIO:
2433                 prefix = "audio";
2434                 if (mainbin[MMPLAYER_M_SRC].gst)
2435                         src_id = MMPLAYER_M_2ND_SRC;
2436                 else
2437                         src_id = MMPLAYER_M_SRC;
2438                 queue_id = MMPLAYER_M_A_BUFFER;
2439         break;
2440         case MM_PLAYER_STREAM_TYPE_VIDEO:
2441                 prefix = "video";
2442                 src_id = MMPLAYER_M_SRC;
2443                 queue_id = MMPLAYER_M_V_BUFFER;
2444         break;
2445         case MM_PLAYER_STREAM_TYPE_TEXT:
2446                 prefix = "subtitle";
2447                 src_id = MMPLAYER_M_SUBSRC;
2448                 queue_id = MMPLAYER_M_S_BUFFER;
2449         break;
2450         default:
2451                 LOGE("invalid type %d", type);
2452                 return FALSE;
2453         }
2454
2455         snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2456         snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2457
2458         /* create source */
2459         src = gst_element_factory_make("appsrc", src_name);
2460         if (!src) {
2461                 LOGF("failed to create %s", src_name);
2462                 goto ERROR;
2463         }
2464
2465         mainbin[src_id].id = src_id;
2466         mainbin[src_id].gst = src;
2467
2468         g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2469                                                                 "caps", caps, NULL);
2470
2471         /* size of many video frames are larger than default blocksize as 4096 */
2472         if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2473                 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2474
2475         if (player->media_stream_buffer_max_size[type] > 0)
2476                 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2477
2478         if (player->media_stream_buffer_min_percent[type] > 0)
2479                 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2480
2481         /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2482         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2483
2484         __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2485                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2486         __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2487                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2488         __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2489                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2490
2491         /* create queue */
2492         queue = gst_element_factory_make("queue2", queue_name);
2493         if (!queue) {
2494                 LOGE("failed to create %s", queue_name);
2495                 goto ERROR;
2496         }
2497         g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2498
2499         mainbin[queue_id].id = queue_id;
2500         mainbin[queue_id].gst = queue;
2501
2502         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2503                 LOGE("failed to add src");
2504                 goto ERROR;
2505         }
2506
2507         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2508                 LOGE("failed to add queue");
2509                 goto ERROR;
2510         }
2511
2512         if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2513                 LOGE("failed to link src and queue");
2514                 goto ERROR;
2515         }
2516
2517         /* create decoder */
2518         srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2519         if (!srcpad) {
2520                 LOGE("failed to get srcpad of queue");
2521                 goto ERROR;
2522         }
2523
2524         if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2525                 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2526         } else {
2527                 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2528                         LOGE("failed to create decoder");
2529                         gst_object_unref(GST_OBJECT(srcpad));
2530                         goto ERROR;
2531                 }
2532         }
2533         gst_object_unref(GST_OBJECT(srcpad));
2534         return TRUE;
2535
2536 ERROR:
2537         if (mainbin[src_id].gst) {
2538                 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2539                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2540                 gst_object_unref(mainbin[src_id].gst);
2541                 mainbin[src_id].gst = NULL;
2542         }
2543
2544         if (mainbin[queue_id].gst) {
2545                 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2546                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2547                 gst_object_unref(mainbin[queue_id].gst);
2548                 mainbin[queue_id].gst = NULL;
2549         }
2550
2551         return FALSE;
2552 }
2553
2554 static void
2555 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2556 {
2557         GstPad *sinkpad = NULL;
2558         GstCaps *caps = NULL;
2559         GstElement *new_element = NULL;
2560         GstStructure *str = NULL;
2561         const gchar *name = NULL;
2562
2563         mm_player_t *player = (mm_player_t*) data;
2564
2565         MMPLAYER_FENTER();
2566
2567         MMPLAYER_RETURN_IF_FAIL(element && pad);
2568         MMPLAYER_RETURN_IF_FAIL(player &&
2569                                         player->pipeline &&
2570                                         player->pipeline->mainbin);
2571
2572         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2573          * num_dynamic_pad will decreased after creating a sinkbin.
2574          */
2575         player->num_dynamic_pad++;
2576         LOGD("stream count inc : %d", player->num_dynamic_pad);
2577
2578         caps = gst_pad_query_caps(pad, NULL);
2579         MMPLAYER_CHECK_NULL(caps);
2580
2581         str = gst_caps_get_structure (caps, 0);
2582         name = gst_structure_get_string(str, "media");
2583         if (!name) {
2584                 LOGE("cannot get mimetype from structure.\n");
2585                 goto ERROR;
2586         }
2587
2588         if (strstr(name, "video")) {
2589                 gint stype = 0;
2590                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2591
2592                 if ((stype == MM_DISPLAY_SURFACE_NULL) && (player->set_mode.media_packet_video_stream == FALSE)) {
2593                         if (player->v_stream_caps) {
2594                                 gst_caps_unref(player->v_stream_caps);
2595                                 player->v_stream_caps = NULL;
2596                         }
2597
2598                         new_element = gst_element_factory_make("fakesink", NULL);
2599                         player->num_dynamic_pad--;
2600                         goto NEW_ELEMENT;
2601                 }
2602         }
2603
2604         if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2605                 LOGE("failed to autoplug for caps");
2606                 goto ERROR;
2607         }
2608
2609         gst_caps_unref(caps);
2610         caps = NULL;
2611
2612 NEW_ELEMENT:
2613
2614         /* excute new_element if created*/
2615         if (new_element) {
2616                 LOGD("adding new element to pipeline\n");
2617
2618                 /* set state to READY before add to bin */
2619                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2620
2621                 /* add new element to the pipeline */
2622                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2623                         LOGE("failed to add autoplug element to bin\n");
2624                         goto ERROR;
2625                 }
2626
2627                 /* get pad from element */
2628                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2629                 if (!sinkpad) {
2630                         LOGE("failed to get sinkpad from autoplug element\n");
2631                         goto ERROR;
2632                 }
2633
2634                 /* link it */
2635                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2636                         LOGE("failed to link autoplug element\n");
2637                         goto ERROR;
2638                 }
2639
2640                 gst_object_unref(sinkpad);
2641                 sinkpad = NULL;
2642
2643                 /* run. setting PLAYING here since streamming source is live source */
2644                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2645         }
2646
2647         if (caps)
2648                 gst_caps_unref(caps);
2649
2650         MMPLAYER_FLEAVE();
2651
2652         return;
2653
2654 STATE_CHANGE_FAILED:
2655 ERROR:
2656         /* FIXIT : take care if new_element has already added to pipeline */
2657         if (new_element)
2658                 gst_object_unref(GST_OBJECT(new_element));
2659
2660         if (sinkpad)
2661                 gst_object_unref(GST_OBJECT(sinkpad));
2662
2663         if (caps)
2664                 gst_caps_unref(caps);
2665
2666         /* FIXIT : how to inform this error to MSL ????? */
2667         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2668          * then post an error to application
2669          */
2670 }
2671
2672 static void
2673 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2674 {
2675         mm_player_t* player = (mm_player_t*) data;
2676
2677         MMPLAYER_FENTER();
2678
2679         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2680           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2681           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2682           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2683
2684           * [1] audio and video will be dumped with filesink.
2685           * [2] autoplugging is done by just using pad caps.
2686           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2687           * and the video will be dumped via filesink.
2688           */
2689         if (player->num_dynamic_pad == 0) {
2690                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2691
2692                 if (!__mmplayer_gst_remove_fakesink(player,
2693                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2694                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2695                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2696                          * source element are not same. To overcome this situation, this function will called
2697                          * several places and several times. Therefore, this is not an error case.
2698                          */
2699                         return;
2700         }
2701
2702         /* create dot before error-return. for debugging */
2703         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2704
2705         player->no_more_pad = TRUE;
2706
2707         MMPLAYER_FLEAVE();
2708 }
2709
2710 static GstElement*
2711 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2712 {
2713         GstElement* element = NULL;
2714         gchar *user_agent = NULL;
2715         MMHandleType attrs = 0;
2716
2717         MMPLAYER_FENTER();
2718         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2719
2720         /* get profile attribute */
2721         attrs = MMPLAYER_GET_ATTRS(player);
2722         if (!attrs) {
2723                 LOGE("failed to get content attribute");
2724                 return NULL;
2725         }
2726
2727         element = gst_element_factory_make("rtspsrc", "rtsp source");
2728         if (!element) {
2729                 LOGE("failed to create rtspsrc element");
2730                 return NULL;
2731         }
2732
2733         /* get attribute */
2734         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2735
2736         SECURE_LOGD("user_agent : %s", user_agent);
2737
2738         /* setting property to streaming source */
2739         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2740         if (user_agent)
2741                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2742
2743         __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2744                                                                         G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2745         __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2746                                                                         G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2747
2748         MMPLAYER_FLEAVE();
2749         return element;
2750 }
2751
2752 static GstElement*
2753 __mmplayer_gst_make_http_src(mm_player_t* player)
2754 {
2755         GstElement* element = NULL;
2756         MMHandleType attrs = 0;
2757         gchar *user_agent, *cookies, **cookie_list;
2758         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2759         user_agent = cookies = NULL;
2760         cookie_list = NULL;
2761
2762         MMPLAYER_FENTER();
2763         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2764
2765         /* get profile attribute */
2766         attrs = MMPLAYER_GET_ATTRS(player);
2767         if (!attrs) {
2768                 LOGE("failed to get content attribute");
2769                 return NULL;
2770         }
2771
2772         LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2773
2774         element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2775         if (!element) {
2776                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2777                 return NULL;
2778         }
2779
2780         /* get attribute */
2781         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2782         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2783
2784         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2785                 http_timeout = player->ini.http_timeout;
2786
2787         /* get attribute */
2788         SECURE_LOGD("location : %s", player->profile.uri);
2789         SECURE_LOGD("cookies : %s", cookies);
2790         SECURE_LOGD("user_agent :  %s", user_agent);
2791         LOGD("timeout : %d", http_timeout);
2792
2793         /* setting property to streaming source */
2794         g_object_set(G_OBJECT(element), "location", player->profile.uri,
2795                                 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2796
2797         /* parsing cookies */
2798         if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2799                 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2800                 g_strfreev(cookie_list);
2801         }
2802
2803         if (user_agent)
2804                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2805
2806         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2807                 LOGW("[DASH] this is still experimental feature");
2808
2809         MMPLAYER_FLEAVE();
2810         return element;
2811 }
2812
2813 static GstElement*
2814 __mmplayer_gst_make_file_src(mm_player_t* player)
2815 {
2816         GstElement* element = NULL;
2817
2818         MMPLAYER_FENTER();
2819         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2820
2821         LOGD("using filesrc for 'file://' handler");
2822         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2823                 LOGE("failed to get storage info");
2824                 return NULL;
2825         }
2826
2827         element = gst_element_factory_make("filesrc", "source");
2828         if (!element) {
2829                 LOGE("failed to create filesrc");
2830                 return NULL;
2831         }
2832
2833         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2834
2835         MMPLAYER_FLEAVE();
2836         return element;
2837 }
2838
2839 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2840 {
2841         mm_player_t *player = (mm_player_t *) data;
2842
2843         g_return_val_if_fail(player, FALSE);
2844         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2845
2846         gst_message_ref(msg);
2847
2848         g_mutex_lock(&player->bus_msg_q_lock);
2849         g_queue_push_tail(player->bus_msg_q, msg);
2850         g_mutex_unlock(&player->bus_msg_q_lock);
2851
2852         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2853         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2854         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2855         return TRUE;
2856 }
2857
2858 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2859 {
2860         mm_player_t *player = (mm_player_t*)(data);
2861         GstMessage *msg = NULL;
2862         GstBus *bus = NULL;
2863
2864         MMPLAYER_FENTER();
2865         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2866                                                 player->pipeline &&
2867                                                 player->pipeline->mainbin &&
2868                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2869                                                 NULL);
2870
2871         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2872         if (!bus) {
2873                 LOGE("cannot get BUS from the pipeline");
2874                 return NULL;
2875         }
2876
2877         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2878
2879         LOGD("[handle: %p] gst bus msg thread will be started.", player);
2880         while (!player->bus_msg_thread_exit) {
2881                 g_mutex_lock(&player->bus_msg_q_lock);
2882                 msg = g_queue_pop_head(player->bus_msg_q);
2883                 g_mutex_unlock(&player->bus_msg_q_lock);
2884                 if (msg == NULL) {
2885                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2886                         continue;
2887                 }
2888                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2889                 /* handle the gst msg */
2890                 __mmplayer_gst_bus_msg_callback(msg, player);
2891                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2892                 gst_message_unref(msg);
2893         }
2894
2895         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2896         gst_object_unref(GST_OBJECT(bus));
2897
2898         MMPLAYER_FLEAVE();
2899         return NULL;
2900 }
2901
2902 static int
2903 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2904 {
2905         gint64 dur_nsec = 0;
2906
2907         MMPLAYER_FENTER();
2908         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2909
2910         if (MMPLAYER_IS_MS_BUFF_SRC(player))
2911                 return MM_ERROR_NONE;
2912
2913         /* NOTE : duration cannot be zero except live streaming.
2914          *              Since some element could have some timing problemn with quering duration, try again.
2915          */
2916         if (player->duration == 0) {
2917                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2918                         /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2919                          * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2920                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2921                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2922                                 player->pending_seek.is_pending = TRUE;
2923                                 player->pending_seek.pos = position;
2924                                 player->seek_state = MMPLAYER_SEEK_NONE;
2925                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2926                                 return MM_ERROR_PLAYER_NO_OP;
2927                         } else {
2928                                 player->seek_state = MMPLAYER_SEEK_NONE;
2929                                 return MM_ERROR_PLAYER_SEEK;
2930                         }
2931                 }
2932                 player->duration = dur_nsec;
2933         }
2934
2935         if (player->duration > 0 && player->duration < position) {
2936                 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2937                 return MM_ERROR_INVALID_ARGUMENT;
2938         }
2939
2940         MMPLAYER_FLEAVE();
2941         return MM_ERROR_NONE;
2942 }
2943
2944 static gboolean
2945 __mmplayer_gst_check_seekable(mm_player_t* player)
2946 {
2947         GstQuery *query = NULL;
2948         gboolean seekable = FALSE;
2949
2950         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2951                 return TRUE;
2952         }
2953
2954         query = gst_query_new_seeking(GST_FORMAT_TIME);
2955         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2956                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2957                 gst_query_unref(query);
2958
2959                 if (!seekable) {
2960                         LOGW("non-seekable content");
2961                         player->seek_state = MMPLAYER_SEEK_NONE;
2962                         return FALSE;
2963                 }
2964         } else {
2965                 LOGW("failed to get seeking query");
2966                 gst_query_unref(query); /* keep seeking operation */
2967         }
2968
2969         return TRUE;
2970 }
2971
2972
2973 #if 0
2974 #endif
2975
2976 int
2977 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element,  GstState state, gboolean async, gint timeout)
2978 {
2979         GstState element_state = GST_STATE_VOID_PENDING;
2980         GstState element_pending_state = GST_STATE_VOID_PENDING;
2981         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2982
2983         MMPLAYER_FENTER();
2984
2985         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2986         MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2987
2988         LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2989
2990         /* set state */
2991         ret = gst_element_set_state(element, state);
2992
2993         if (ret == GST_STATE_CHANGE_FAILURE) {
2994                 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
2995
2996                 /* dump state of all element */
2997                 __mmplayer_dump_pipeline_state(player);
2998
2999                 return MM_ERROR_PLAYER_INTERNAL;
3000         }
3001
3002         /* return here so state transition to be done in async mode */
3003         if (async) {
3004                 LOGD("async state transition. not waiting for state complete.\n");
3005                 return MM_ERROR_NONE;
3006         }
3007
3008         /* wait for state transition */
3009         ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3010
3011         if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3012                 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
3013                         GST_ELEMENT_NAME(element),
3014                         gst_element_state_get_name(state), timeout);
3015
3016                 LOGE(" [%s] state : %s   pending : %s \n",
3017                         GST_ELEMENT_NAME(element),
3018                         gst_element_state_get_name(element_state),
3019                         gst_element_state_get_name(element_pending_state));
3020
3021                 /* dump state of all element */
3022                 __mmplayer_dump_pipeline_state(player);
3023
3024                 return MM_ERROR_PLAYER_INTERNAL;
3025         }
3026
3027         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
3028
3029         MMPLAYER_FLEAVE();
3030
3031         return MM_ERROR_NONE;
3032 }
3033
3034 int __mmplayer_gst_start(mm_player_t* player)
3035 {
3036         int ret = MM_ERROR_NONE;
3037         gboolean async = FALSE;
3038
3039         MMPLAYER_FENTER();
3040
3041         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3042
3043         /* NOTE : if SetPosition was called before Start. do it now */
3044         /* streaming doesn't support it. so it should be always sync */
3045         /* !!create one more api to check if there is pending seek rather than checking variables */
3046         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3047                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3048                 ret = __mmplayer_gst_pause(player, FALSE);
3049                 if (ret != MM_ERROR_NONE) {
3050                         LOGE("failed to set state to PAUSED for pending seek");
3051                         return ret;
3052                 }
3053
3054                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3055                 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3056                                 LOGW("failed to seek pending postion. starting from the begin of content");
3057         }
3058
3059         LOGD("current state before doing transition");
3060         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3061         MMPLAYER_PRINT_STATE(player);
3062
3063         /* set pipeline state to PLAYING  */
3064         ret = __mmplayer_gst_set_state(player,
3065                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3066
3067         if (ret == MM_ERROR_NONE) {
3068                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3069         } else {
3070                 LOGE("failed to set state to PLAYING");
3071                 return ret;
3072         }
3073
3074         /* generating debug info before returning error */
3075         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3076
3077         MMPLAYER_FLEAVE();
3078
3079         return ret;
3080 }
3081
3082 int __mmplayer_gst_stop(mm_player_t* player)
3083 {
3084         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3085         MMHandleType attrs = 0;
3086         gboolean rewind = FALSE;
3087         gint timeout = 0;
3088         int ret = MM_ERROR_NONE;
3089
3090         MMPLAYER_FENTER();
3091
3092         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3093         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3094
3095         LOGD("current state before doing transition");
3096         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3097         MMPLAYER_PRINT_STATE(player);
3098
3099         attrs = MMPLAYER_GET_ATTRS(player);
3100         if (!attrs) {
3101                 LOGE("cannot get content attribute\n");
3102                 return MM_ERROR_PLAYER_INTERNAL;
3103         }
3104
3105         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3106         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3107
3108         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3109                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3110                 rewind = TRUE;
3111
3112         if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3113                 /* disable the async state transition because there could be no data in the pipeline */
3114                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3115         }
3116
3117         /* set gst state */
3118         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3119
3120         if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3121                 /* enable the async state transition as default operation */
3122                 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3123         }
3124
3125         /* return if set_state has failed */
3126         if (ret != MM_ERROR_NONE) {
3127                 LOGE("failed to set state.\n");
3128                 return ret;
3129         }
3130
3131         /* rewind */
3132         if (rewind) {
3133                 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3134                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3135                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3136                         LOGW("failed to rewind\n");
3137                         ret = MM_ERROR_PLAYER_SEEK;
3138                 }
3139         }
3140
3141         /* initialize */
3142         player->sent_bos = FALSE;
3143
3144         if (player->es_player_push_mode) //for cloudgame
3145                 timeout = 0;
3146
3147         /* wait for seek to complete */
3148         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3149         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3150                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3151         } else {
3152                 LOGE("fail to stop player.\n");
3153                 ret = MM_ERROR_PLAYER_INTERNAL;
3154                 __mmplayer_dump_pipeline_state(player);
3155         }
3156
3157         /* generate dot file if enabled */
3158         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3159
3160         MMPLAYER_FLEAVE();
3161
3162         return ret;
3163 }
3164
3165 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3166 {
3167         int ret = MM_ERROR_NONE;
3168
3169         MMPLAYER_FENTER();
3170
3171         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3172         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3173
3174         LOGD("current state before doing transition");
3175         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3176         MMPLAYER_PRINT_STATE(player);
3177
3178         /* set pipeline status to PAUSED */
3179         ret = __mmplayer_gst_set_state(player,
3180                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3181
3182         if (FALSE == async) {
3183                 if (ret != MM_ERROR_NONE) {
3184                         GstMessage *msg = NULL;
3185                         GTimer *timer = NULL;
3186                         gdouble MAX_TIMEOUT_SEC = 3;
3187
3188                         LOGE("failed to set state to PAUSED");
3189
3190                         if (!player->bus_watcher) {
3191                                 LOGE("there is no bus msg thread. pipeline is shutting down.");
3192                                 return ret;
3193                         }
3194
3195                         if (player->msg_posted) {
3196                                 LOGE("error msg is already posted.");
3197                                 return ret;
3198                         }
3199
3200                         timer = g_timer_new();
3201                         g_timer_start(timer);
3202
3203                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3204
3205                         do {
3206                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3207                                 if (msg) {
3208                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3209                                                 GError *error = NULL;
3210
3211                                                 /* parse error code */
3212                                                 gst_message_parse_error(msg, &error, NULL);
3213
3214                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3215                                                         /* Note : the streaming error from the streaming source is handled
3216                                                          *   using __mmplayer_handle_streaming_error.
3217                                                          */
3218                                                         __mmplayer_handle_streaming_error(player, msg);
3219
3220                                                 } else if (error) {
3221                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3222
3223                                                         if (error->domain == GST_STREAM_ERROR)
3224                                                                 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3225                                                         else if (error->domain == GST_RESOURCE_ERROR)
3226                                                                 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3227                                                         else if (error->domain == GST_LIBRARY_ERROR)
3228                                                                 ret = __mmplayer_gst_handle_library_error(player, error->code);
3229                                                         else if (error->domain == GST_CORE_ERROR)
3230                                                                 ret = __mmplayer_gst_handle_core_error(player, error->code);
3231
3232                                                         g_error_free(error);
3233                                                 }
3234                                                 player->msg_posted = TRUE;
3235                                         }
3236                                         gst_message_unref(msg);
3237                                 }
3238                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3239                         /* clean */
3240                         gst_object_unref(bus);
3241                         g_timer_stop(timer);
3242                         g_timer_destroy(timer);
3243
3244                         return ret;
3245
3246                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3247                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3248
3249                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3250
3251                 } else {
3252                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3253                 }
3254         }
3255
3256         /* generate dot file before returning error */
3257         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3258
3259         MMPLAYER_FLEAVE();
3260
3261         return ret;
3262 }
3263
3264 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3265 {
3266         int ret = MM_ERROR_NONE;
3267         gint timeout = 0;
3268
3269         MMPLAYER_FENTER();
3270
3271         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3272                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3273
3274         LOGD("current state before doing transition");
3275         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3276         MMPLAYER_PRINT_STATE(player);
3277
3278         if (async)
3279                 LOGD("do async state transition to PLAYING");
3280
3281         /* set pipeline state to PLAYING */
3282         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3283
3284         ret = __mmplayer_gst_set_state(player,
3285                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3286         if (ret != MM_ERROR_NONE) {
3287                 LOGE("failed to set state to PLAYING");
3288                 goto EXIT;
3289         } else {
3290                 if (async == FALSE)
3291                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3292         }
3293
3294 EXIT:
3295         /* generate dot file */
3296         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3297
3298         MMPLAYER_FLEAVE();
3299
3300         return ret;
3301 }
3302
3303 /* sending event to one of sinkelements */
3304 gboolean
3305 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3306 {
3307         GstEvent * event2 = NULL;
3308         GList *sinks = NULL;
3309         gboolean res = FALSE;
3310         MMPLAYER_FENTER();
3311
3312         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3313         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3314
3315         /* While adding subtitles in live feeds seek is getting called.
3316            Adding defensive check in framework layer.*/
3317         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3318                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3319                         LOGE("Should not send seek event during live playback");
3320                         return TRUE;
3321                 }
3322         }
3323
3324         if (player->play_subtitle)
3325                 event2 = gst_event_copy((const GstEvent *)event);
3326
3327         sinks = player->sink_elements;
3328         while (sinks) {
3329                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3330
3331                 if (GST_IS_ELEMENT(sink)) {
3332                         /* keep ref to the event */
3333                         gst_event_ref(event);
3334
3335                         if ((res = gst_element_send_event(sink, event))) {
3336                                 LOGD("sending event[%s] to sink element [%s] success!\n",
3337                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3338
3339                                 /* rtsp case, asyn_done is not called after seek during pause state */
3340                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3341                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3342                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3343                                                         LOGD("RTSP seek completed, after pause state..\n");
3344                                                         player->seek_state = MMPLAYER_SEEK_NONE;
3345                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3346                                                 }
3347
3348                                         }
3349                                 }
3350
3351                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3352                                         sinks = g_list_next(sinks);
3353                                         continue;
3354                                 } else {
3355                                         break;
3356                                 }
3357                         }
3358
3359                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3360                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3361                 }
3362
3363                 sinks = g_list_next(sinks);
3364         }
3365
3366         /* Note : Textbin is not linked to the video or audio bin.
3367          * It needs to send the event to the text sink seperatelly.
3368          */
3369          if (player->play_subtitle && player->pipeline) {
3370                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3371
3372                 if (GST_IS_ELEMENT(text_sink)) {
3373                         /* keep ref to the event */
3374                         gst_event_ref(event2);
3375
3376                         if ((res = gst_element_send_event(text_sink, event2)))
3377                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
3378                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3379                         else
3380                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
3381                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3382
3383                         gst_event_unref(event2);
3384                 }
3385          }
3386
3387         gst_event_unref(event);
3388
3389         MMPLAYER_FLEAVE();
3390
3391         return res;
3392 }
3393
3394 gboolean
3395 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3396                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3397                         gint64 cur, GstSeekType stop_type, gint64 stop)
3398 {
3399         GstEvent* event = NULL;
3400         gboolean result = FALSE;
3401
3402         MMPLAYER_FENTER();
3403
3404         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3405
3406         if (player->pipeline && player->pipeline->textbin)
3407                 __mmplayer_drop_subtitle(player, FALSE);
3408
3409         event = gst_event_new_seek(rate, format, flags, cur_type,
3410                 cur, stop_type, stop);
3411
3412         result = __mmplayer_gst_send_event_to_sink(player, event);
3413
3414         MMPLAYER_FLEAVE();
3415
3416         return result;
3417 }
3418
3419 int
3420 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3421 {
3422         int ret = MM_ERROR_NONE;
3423         gint64 pos_nsec = 0;
3424         gboolean accurated = FALSE;
3425         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3426
3427         MMPLAYER_FENTER();
3428         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3429         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3430
3431         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3432                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3433                 goto PENDING;
3434
3435         ret = __mmplayer_gst_check_duration(player, position);
3436         if (ret != MM_ERROR_NONE) {
3437                 LOGE("failed to check duration 0x%X", ret);
3438                 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3439         }
3440
3441         if (!__mmplayer_gst_check_seekable(player))
3442                 return MM_ERROR_PLAYER_NO_OP;
3443
3444         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3445                                 position, player->playback_rate, player->duration);
3446
3447         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3448            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3449            This causes problem is position calculation during normal pause resume scenarios also.
3450            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3451         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3452                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3453                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3454                         LOGW("getting current position failed in seek");
3455
3456                 player->last_position = pos_nsec;
3457                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3458         }
3459
3460         if (player->seek_state != MMPLAYER_SEEK_NONE) {
3461                 LOGD("not completed seek");
3462                 return MM_ERROR_PLAYER_DOING_SEEK;
3463         }
3464
3465         if (!internal_called)
3466                 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3467
3468         /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3469                 that's why set position through property. */
3470         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3471                 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3472                 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3473                 (!player->videodec_linked) && (!player->audiodec_linked)) {
3474
3475                 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3476                                 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3477
3478                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3479                 player->seek_state = MMPLAYER_SEEK_NONE;
3480                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3481         } else {
3482                 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3483                 if (accurated)
3484                         seek_flags |= GST_SEEK_FLAG_ACCURATE;
3485                 else
3486                         seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3487
3488                 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3489                                                 GST_FORMAT_TIME, seek_flags,
3490                                                 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3491                         LOGE("failed to set position");
3492                         goto SEEK_ERROR;
3493                 }
3494         }
3495
3496         /* NOTE : store last seeking point to overcome some bad operation
3497           *     (returning zero when getting current position) of some elements
3498           */
3499         player->last_position = position;
3500
3501         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3502         if (player->playback_rate > 1.0)
3503                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3504
3505         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3506                 LOGD("buffering should be reset after seeking");
3507                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3508                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3509         }
3510
3511         MMPLAYER_FLEAVE();
3512         return MM_ERROR_NONE;
3513
3514 PENDING:
3515         player->pending_seek.is_pending = TRUE;
3516         player->pending_seek.pos = position;
3517
3518         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3519                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3520                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3521                 player->pending_seek.pos);
3522
3523         return MM_ERROR_NONE;
3524
3525 SEEK_ERROR:
3526         player->seek_state = MMPLAYER_SEEK_NONE;
3527         return MM_ERROR_PLAYER_SEEK;
3528 }
3529
3530 int
3531 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3532 {
3533 #define TRICKPLAY_OFFSET GST_MSECOND
3534
3535         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3536         gint64 pos_nsec = 0;
3537         gboolean ret = TRUE;
3538
3539         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3540                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3541
3542         current_state = MMPLAYER_CURRENT_STATE(player);
3543
3544         /* NOTE : query position except paused state to overcome some bad operation
3545          * please refer to below comments in details
3546          */
3547         if (current_state != MM_PLAYER_STATE_PAUSED)
3548                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3549
3550         /* NOTE : get last point to overcome some bad operation of some elements
3551          *(returning zero when getting current position in paused state
3552          * and when failed to get postion during seeking
3553          */
3554         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3555                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3556
3557                 if (player->playback_rate < 0.0)
3558                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3559                 else
3560                         pos_nsec = player->last_position;
3561
3562                 if (!ret)
3563                         pos_nsec = player->last_position;
3564                 else
3565                         player->last_position = pos_nsec;
3566
3567                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3568
3569         } else {
3570                 if (player->duration > 0 && pos_nsec > player->duration)
3571                         pos_nsec = player->duration;
3572
3573                 player->last_position = pos_nsec;
3574         }
3575
3576         *position = pos_nsec;
3577
3578         return MM_ERROR_NONE;
3579 }
3580
3581 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3582 {
3583 #define STREAMING_IS_FINISHED   0
3584 #define BUFFERING_MAX_PER       100
3585 #define DEFAULT_PER_VALUE       -1
3586 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3587
3588         MMPlayerGstElement *mainbin = NULL;
3589         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3590         gint64 buffered_total = 0;
3591         gint64 position = 0;
3592         gint buffered_sec = -1;
3593         GstBufferingMode mode = GST_BUFFERING_STREAM;
3594         gint64 content_size_time = player->duration;
3595         guint64 content_size_bytes = player->http_content_size;
3596
3597         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3598                                                 player->pipeline &&
3599                                                 player->pipeline->mainbin,
3600                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3601
3602         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3603
3604         *start_pos = 0;
3605         *stop_pos = 0;
3606
3607         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3608                 /* and rtsp is not ready yet. */
3609                 LOGW("it's only used for http streaming case");
3610                 return MM_ERROR_PLAYER_NO_OP;
3611         }
3612
3613         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3614                 LOGW("Time format is not supported yet");
3615                 return MM_ERROR_INVALID_ARGUMENT;
3616         }
3617
3618         if (content_size_time <= 0 || content_size_bytes <= 0) {
3619                 LOGW("there is no content size");
3620                 return MM_ERROR_NONE;
3621         }
3622
3623         if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3624                 LOGW("fail to get current position");
3625                 return MM_ERROR_NONE;
3626         }
3627
3628         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3629                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3630
3631         mainbin = player->pipeline->mainbin;
3632         start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3633
3634         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3635                 GstQuery *query = NULL;
3636                 gint byte_in_rate = 0, byte_out_rate = 0;
3637                 gint64 estimated_total = 0;
3638
3639                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3640                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3641                         LOGW("fail to get buffering query from queue2");
3642                         if (query)
3643                                 gst_query_unref(query);
3644                         return MM_ERROR_NONE;
3645                 }
3646
3647                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3648                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3649
3650                 if (mode == GST_BUFFERING_STREAM) {
3651                         /* using only queue in case of push mode(ts / mp3) */
3652                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3653                                 GST_FORMAT_BYTES, &buffered_total)) {
3654                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3655                                 stop_per = 100 * buffered_total / content_size_bytes;
3656                         }
3657                 } else {
3658                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3659                         guint idx = 0;
3660                         guint num_of_ranges = 0;
3661                         gint64 start_byte = 0, stop_byte = 0;
3662
3663                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3664                         if (estimated_total != STREAMING_IS_FINISHED) {
3665                                 /* buffered size info from queue2 */
3666                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3667                                 for (idx = 0; idx < num_of_ranges; idx++) {
3668                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3669                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3670
3671                                         buffered_total += (stop_byte - start_byte);
3672                                 }
3673                         } else
3674                                 stop_per = BUFFERING_MAX_PER;
3675                 }
3676                 gst_query_unref(query);
3677         }
3678
3679         if (stop_per == DEFAULT_PER_VALUE) {
3680                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3681                 if (dur_sec > 0) {
3682                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3683
3684                         /* buffered size info from multiqueue */
3685                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3686                                 guint curr_size_bytes = 0;
3687                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3688                                         "curr-size-bytes", &curr_size_bytes, NULL);
3689                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3690                                 buffered_total += curr_size_bytes;
3691                         }
3692
3693                         if (avg_byterate > 0)
3694                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3695                         else if (player->total_maximum_bitrate > 0)
3696                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3697                         else if (player->total_bitrate > 0)
3698                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3699
3700                         if (buffered_sec >= 0)
3701                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3702                 }
3703         }
3704
3705         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3706         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3707
3708         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3709                 buffered_total, buffered_sec, *start_pos, *stop_pos);
3710
3711         return MM_ERROR_NONE;
3712 }
3713
3714 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3715 {
3716         GstElement* element = NULL;
3717
3718         MMPLAYER_FENTER();
3719         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3720                                 player->pipeline->mainbin, NULL);
3721
3722         /* setup source for gapless play */
3723         switch (player->profile.uri_type) {
3724         /* file source */
3725         case MM_PLAYER_URI_TYPE_FILE:
3726                 element = __mmplayer_gst_make_file_src(player);
3727                 break;
3728         case MM_PLAYER_URI_TYPE_URL_HTTP:
3729                 element = __mmplayer_gst_make_http_src(player);
3730                 break;
3731         default:
3732                 LOGE("not support uri type %d", player->profile.uri_type);
3733                 break;
3734         }
3735
3736         if (!element) {
3737                 LOGE("failed to create source element");
3738                 return NULL;
3739         }
3740
3741         MMPLAYER_FLEAVE();
3742         return element;
3743 }
3744
3745 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3746 {
3747         MMHandleType attrs = 0;
3748
3749         MMPLAYER_FENTER();
3750         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3751                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3752
3753         /* get profile attribute */
3754         attrs = MMPLAYER_GET_ATTRS(player);
3755         if (!attrs) {
3756                 LOGE("failed to get content attribute");
3757                 return MM_ERROR_PLAYER_INTERNAL;
3758         }
3759
3760         SECURE_LOGD("uri : %s", player->profile.uri);
3761
3762         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3763         if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3764                 LOGE("failed to commit");
3765
3766         if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3767                 return MM_ERROR_PLAYER_INTERNAL;
3768
3769         if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3770                 return MM_ERROR_PLAYER_INTERNAL;
3771
3772         if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3773                 return MM_ERROR_PLAYER_INTERNAL;
3774
3775         MMPLAYER_FLEAVE();
3776         return MM_ERROR_NONE;
3777 }
3778
3779 int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
3780 {
3781         MMPlayerGstElement *mainbin = NULL;
3782         GstElement *pd_src = NULL;
3783         GstElement *pd_queue = NULL;
3784         GstElement *pd_decodebin = NULL;
3785         GList* element_bucket = NULL;
3786         MMHandleType attrs = 0;
3787         gchar *path = NULL;
3788         gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
3789
3790         MMPLAYER_FENTER();
3791         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3792                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3793
3794         /* get profile attribute */
3795         attrs = MMPLAYER_GET_ATTRS(player);
3796         if (!attrs) {
3797                 LOGE("failed to get content attribute");
3798                 return MM_ERROR_PLAYER_INTERNAL;
3799         }
3800
3801         LOGD("http playback with progressive download : %d", player->pd_mode);
3802
3803         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
3804                 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
3805                 MMPLAYER_FREEIF(player->pd_file_save_path);
3806
3807                 SECURE_LOGD("PD Location : %s", path);
3808                 if (!path) {
3809                         LOGE("filed to find pd location");
3810                         return MM_ERROR_PLAYER_INTERNAL;
3811                 }
3812
3813                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
3814                         LOGE("failed to get storage info");
3815                         return MM_ERROR_PLAYER_INTERNAL;
3816                 }
3817                 player->pd_file_save_path = g_strdup(path);
3818         }
3819
3820         pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
3821         if (!pd_src) {
3822                 LOGE("failed to create PD push source");
3823                 return MM_ERROR_PLAYER_INTERNAL;
3824         }
3825
3826         if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
3827                 g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
3828         else
3829                 g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
3830
3831         mainbin = player->pipeline->mainbin;
3832
3833         /* take source element */
3834         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3835         mainbin[MMPLAYER_M_SRC].gst = pd_src;
3836         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3837
3838         /* setting queue */
3839         LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
3840         pd_queue = gst_element_factory_make("queue2", "queue2");
3841         if (!pd_queue) {
3842                 LOGE("failed to create pd buffer element");
3843                 goto ERROR;
3844         }
3845
3846         /* take queue2 */
3847         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3848         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
3849         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
3850
3851         pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
3852
3853         player->streamer->is_pd_mode = TRUE;
3854
3855         __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
3856                         player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
3857                         player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
3858
3859         pd_decodebin = __mmplayer_gst_make_decodebin(player);
3860         if (!pd_decodebin) {
3861                 LOGE("failed to create decodebin");
3862                 goto ERROR;
3863         }
3864
3865         /* default size of mq in decodebin is 2M
3866          * but it can cause blocking issue during seeking depends on content. */
3867         g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
3868
3869         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
3870         mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
3871
3872         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
3873
3874         /* add elements to pipeline */
3875         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3876                 LOGE("failed to add elements to pipeline");
3877                 goto ERROR;
3878         }
3879
3880         /* linking elements in the bucket by added order. */
3881         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3882                 LOGE("failed to link some elements");
3883                 goto ERROR;
3884         }
3885
3886         g_list_free(element_bucket);
3887
3888         MMPLAYER_FLEAVE();
3889         return MM_ERROR_NONE;
3890
3891 ERROR:
3892         MMPLAYER_FREEIF(player->pd_file_save_path);
3893         g_list_free(element_bucket);
3894
3895         if (mainbin[MMPLAYER_M_SRC].gst)
3896                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3897
3898         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
3899                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
3900
3901         if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
3902                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
3903
3904         mainbin[MMPLAYER_M_SRC].gst = NULL;
3905         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
3906         mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
3907
3908         return MM_ERROR_PLAYER_INTERNAL;
3909 }
3910
3911 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3912 {
3913         MMPlayerGstElement *mainbin = NULL;
3914         GstElement* src_elem = NULL;
3915         GstElement *autoplug_elem = NULL;
3916         GList* element_bucket = NULL;
3917         MMHandleType attrs = 0;
3918         enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3919
3920         MMPLAYER_FENTER();
3921         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3922                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3923
3924         /* get profile attribute */
3925         attrs = MMPLAYER_GET_ATTRS(player);
3926         if (!attrs) {
3927                 LOGE("failed to get content attribute");
3928                 return MM_ERROR_PLAYER_INTERNAL;
3929         }
3930
3931         LOGD("uri type %d", player->profile.uri_type);
3932
3933         /* create source element */
3934         switch (player->profile.uri_type) {
3935         case MM_PLAYER_URI_TYPE_URL_RTSP:
3936                 src_elem = __mmplayer_gst_make_rtsp_src(player);
3937                 break;
3938         case MM_PLAYER_URI_TYPE_URL_HTTP:
3939                 src_elem = __mmplayer_gst_make_http_src(player);
3940                 break;
3941         case MM_PLAYER_URI_TYPE_FILE:
3942                 src_elem = __mmplayer_gst_make_file_src(player);
3943                 break;
3944         case MM_PLAYER_URI_TYPE_SS:
3945                 {
3946                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3947                         src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3948                         if (!src_elem) {
3949                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3950                                 break;
3951                         }
3952
3953                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3954                                 LOGD("get timeout from ini");
3955                                 http_timeout = player->ini.http_timeout;
3956                         }
3957
3958                         /* setting property to streaming source */
3959                         g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3960                 }
3961                 break;
3962         case MM_PLAYER_URI_TYPE_MEM:
3963                 {
3964                         GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3965
3966                         src_elem = gst_element_factory_make("appsrc", "mem-source");
3967                         if (!src_elem) {
3968                                 LOGE("failed to create appsrc element");
3969                                 break;
3970                         }
3971
3972                         g_object_set(src_elem, "stream-type", stream_type,
3973                                 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3974
3975                         __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3976                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3977                         __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3978                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3979                 }
3980                 break;
3981         default:
3982                 LOGE("not support uri type");
3983                 break;
3984         }
3985
3986         if (!src_elem) {
3987                 LOGE("failed to create source element");
3988                 return MM_ERROR_PLAYER_INTERNAL;
3989         }
3990
3991         mainbin = player->pipeline->mainbin;
3992
3993         /* take source element */
3994         LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3995
3996         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3997         mainbin[MMPLAYER_M_SRC].gst = src_elem;
3998         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3999
4000         /* create next element for auto-plugging */
4001         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4002                 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4003                 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4004                 if (!autoplug_elem) {
4005                         LOGE("failed to create typefind element");
4006                         goto ERROR;
4007                 }
4008
4009                 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4010                                                                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
4011         } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4012                 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4013                 autoplug_elem = __mmplayer_gst_make_decodebin(player);
4014                 if (!autoplug_elem) {
4015                         LOGE("failed to create decodebin");
4016                         goto ERROR;
4017                 }
4018
4019                 /* default size of mq in decodebin is 2M
4020                  * but it can cause blocking issue during seeking depends on content. */
4021                 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
4022         }
4023
4024         if (autoplug_elem) {
4025                 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4026                 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4027                 mainbin[autoplug_elem_id].gst = autoplug_elem;
4028
4029                 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4030         }
4031
4032         /* add elements to pipeline */
4033         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4034                 LOGE("failed to add elements to pipeline");
4035                 goto ERROR;
4036         }
4037
4038         /* linking elements in the bucket by added order. */
4039         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4040                 LOGE("failed to link some elements");
4041                 goto ERROR;
4042         }
4043
4044         /* FIXME: need to check whether this is required or not. */
4045         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4046                 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4047                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4048                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4049
4050                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4051                         LOGE("failed to create fakesink");
4052                         goto ERROR;
4053                 }
4054                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4055
4056                 /* take ownership of fakesink. we are reusing it */
4057                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4058
4059                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4060                         LOGE("failed to add fakesink to bin");
4061                         gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4062                         goto ERROR;
4063                 }
4064         }
4065
4066         g_list_free(element_bucket);
4067
4068         MMPLAYER_FLEAVE();
4069         return MM_ERROR_NONE;
4070
4071 ERROR:
4072         g_list_free(element_bucket);
4073
4074         if (mainbin[MMPLAYER_M_SRC].gst)
4075                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4076
4077         if (mainbin[autoplug_elem_id].gst)
4078                 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4079
4080         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4081                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4082
4083         mainbin[MMPLAYER_M_SRC].gst = NULL;
4084         mainbin[autoplug_elem_id].gst = NULL;
4085         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4086
4087         return MM_ERROR_PLAYER_INTERNAL;
4088 }
4089
4090 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
4091 {
4092         GstBus  *bus = NULL;
4093         MMPlayerGstElement *mainbin = NULL;
4094
4095         MMPLAYER_FENTER();
4096         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4097                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4098
4099         mainbin = player->pipeline->mainbin;
4100
4101         /* connect bus callback */
4102         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4103         if (!bus) {
4104                 LOGE("cannot get bus from pipeline");
4105                 return MM_ERROR_PLAYER_INTERNAL;
4106         }
4107
4108         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4109         player->context.thread_default = g_main_context_get_thread_default();
4110         if (player->context.thread_default == NULL) {
4111                 player->context.thread_default = g_main_context_default();
4112                 LOGD("thread-default context is the global default context");
4113         }
4114         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4115
4116         /* set sync handler to get tag synchronously */
4117         gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4118         gst_object_unref(GST_OBJECT(bus));
4119
4120         /* create gst bus_msb_cb thread */
4121         g_mutex_init(&player->bus_msg_thread_mutex);
4122         g_cond_init(&player->bus_msg_thread_cond);
4123         player->bus_msg_thread_exit = FALSE;
4124         player->bus_msg_thread =
4125                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4126         if (!player->bus_msg_thread) {
4127                 LOGE("failed to create gst BUS msg thread");
4128                 g_mutex_clear(&player->bus_msg_thread_mutex);
4129                 g_cond_clear(&player->bus_msg_thread_cond);
4130                 return MM_ERROR_PLAYER_INTERNAL;
4131         }
4132
4133         MMPLAYER_FLEAVE();
4134         return MM_ERROR_NONE;
4135 }