[0.6.147] Apply new attribute API of libmm-common
[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         gboolean caps_ret = TRUE;
2563
2564         mm_player_t *player = (mm_player_t*) data;
2565
2566         MMPLAYER_FENTER();
2567
2568         MMPLAYER_RETURN_IF_FAIL(element && pad);
2569         MMPLAYER_RETURN_IF_FAIL(player &&
2570                                         player->pipeline &&
2571                                         player->pipeline->mainbin);
2572
2573         MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2574         if (!caps_ret)
2575                 goto ERROR;
2576
2577         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2578          * num_dynamic_pad will decreased after creating a sinkbin.
2579          */
2580         player->num_dynamic_pad++;
2581         LOGD("stream count inc : %d", player->num_dynamic_pad);
2582
2583         /* clear  previous result*/
2584         player->have_dynamic_pad = FALSE;
2585
2586         if (strstr(name, "video")) {
2587                 gint stype = 0;
2588                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2589
2590                 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2591                         if (player->v_stream_caps) {
2592                                 gst_caps_unref(player->v_stream_caps);
2593                                 player->v_stream_caps = NULL;
2594                         }
2595
2596                         new_element = gst_element_factory_make("fakesink", NULL);
2597                         player->num_dynamic_pad--;
2598                         goto NEW_ELEMENT;
2599                 }
2600         }
2601
2602         /* clear  previous result*/
2603         player->have_dynamic_pad = FALSE;
2604
2605         if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2606                 LOGE("failed to autoplug for caps");
2607                 goto ERROR;
2608         }
2609
2610         /* check if there's dynamic pad*/
2611         if (player->have_dynamic_pad) {
2612                 LOGE("using pad caps assums there's no dynamic pad !\n");
2613                 goto ERROR;
2614         }
2615
2616         gst_caps_unref(caps);
2617         caps = NULL;
2618
2619 NEW_ELEMENT:
2620
2621         /* excute new_element if created*/
2622         if (new_element) {
2623                 LOGD("adding new element to pipeline\n");
2624
2625                 /* set state to READY before add to bin */
2626                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2627
2628                 /* add new element to the pipeline */
2629                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2630                         LOGE("failed to add autoplug element to bin\n");
2631                         goto ERROR;
2632                 }
2633
2634                 /* get pad from element */
2635                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2636                 if (!sinkpad) {
2637                         LOGE("failed to get sinkpad from autoplug element\n");
2638                         goto ERROR;
2639                 }
2640
2641                 /* link it */
2642                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2643                         LOGE("failed to link autoplug element\n");
2644                         goto ERROR;
2645                 }
2646
2647                 gst_object_unref(sinkpad);
2648                 sinkpad = NULL;
2649
2650                 /* run. setting PLAYING here since streamming source is live source */
2651                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2652         }
2653
2654         if (caps)
2655                 gst_caps_unref(caps);
2656
2657         MMPLAYER_FLEAVE();
2658
2659         return;
2660
2661 STATE_CHANGE_FAILED:
2662 ERROR:
2663         /* FIXIT : take care if new_element has already added to pipeline */
2664         if (new_element)
2665                 gst_object_unref(GST_OBJECT(new_element));
2666
2667         if (sinkpad)
2668                 gst_object_unref(GST_OBJECT(sinkpad));
2669
2670         if (caps)
2671                 gst_caps_unref(caps);
2672
2673         /* FIXIT : how to inform this error to MSL ????? */
2674         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2675          * then post an error to application
2676          */
2677 }
2678
2679 static void
2680 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2681 {
2682         mm_player_t* player = (mm_player_t*) data;
2683
2684         MMPLAYER_FENTER();
2685
2686         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2687           * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2688           * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2689           * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2690
2691           * [1] audio and video will be dumped with filesink.
2692           * [2] autoplugging is done by just using pad caps.
2693           * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2694           * and the video will be dumped via filesink.
2695           */
2696         if (player->num_dynamic_pad == 0) {
2697                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2698
2699                 if (!__mmplayer_gst_remove_fakesink(player,
2700                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2701                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2702                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2703                          * source element are not same. To overcome this situation, this function will called
2704                          * several places and several times. Therefore, this is not an error case.
2705                          */
2706                         return;
2707         }
2708
2709         /* create dot before error-return. for debugging */
2710         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2711
2712         player->no_more_pad = TRUE;
2713
2714         MMPLAYER_FLEAVE();
2715 }
2716
2717 static GstElement*
2718 __mmplayer_gst_make_rtsp_src(mm_player_t* player)
2719 {
2720         GstElement* element = NULL;
2721         gchar *user_agent = NULL;
2722         MMHandleType attrs = 0;
2723
2724         MMPLAYER_FENTER();
2725         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2726
2727         /* get profile attribute */
2728         attrs = MMPLAYER_GET_ATTRS(player);
2729         if (!attrs) {
2730                 LOGE("failed to get content attribute");
2731                 return NULL;
2732         }
2733
2734         element = gst_element_factory_make("rtspsrc", "rtsp source");
2735         if (!element) {
2736                 LOGE("failed to create rtspsrc element");
2737                 return NULL;
2738         }
2739
2740         /* get attribute */
2741         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2742
2743         SECURE_LOGD("user_agent : %s", user_agent);
2744
2745         /* setting property to streaming source */
2746         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2747         if (user_agent)
2748                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2749
2750         __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2751                                                                         G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2752         __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2753                                                                         G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2754
2755         MMPLAYER_FLEAVE();
2756         return element;
2757 }
2758
2759 static GstElement*
2760 __mmplayer_gst_make_http_src(mm_player_t* player)
2761 {
2762         GstElement* element = NULL;
2763         MMHandleType attrs = 0;
2764         gchar *user_agent, *cookies, **cookie_list;
2765         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2766         user_agent = cookies = NULL;
2767         cookie_list = NULL;
2768
2769         MMPLAYER_FENTER();
2770         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2771
2772         /* get profile attribute */
2773         attrs = MMPLAYER_GET_ATTRS(player);
2774         if (!attrs) {
2775                 LOGE("failed to get content attribute");
2776                 return NULL;
2777         }
2778
2779         LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2780
2781         element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2782         if (!element) {
2783                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2784                 return NULL;
2785         }
2786
2787         /* get attribute */
2788         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2789         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2790
2791         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2792                 http_timeout = player->ini.http_timeout;
2793
2794         /* get attribute */
2795         SECURE_LOGD("location : %s", player->profile.uri);
2796         SECURE_LOGD("cookies : %s", cookies);
2797         SECURE_LOGD("user_agent :  %s", user_agent);
2798         LOGD("timeout : %d", http_timeout);
2799
2800         /* setting property to streaming source */
2801         g_object_set(G_OBJECT(element), "location", player->profile.uri,
2802                                 "timeout", http_timeout, "blocksize", (unsigned long)(64*1024), NULL);
2803
2804         /* parsing cookies */
2805         if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
2806                 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2807                 g_strfreev(cookie_list);
2808         }
2809
2810         if (user_agent)
2811                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2812
2813         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2814                 LOGW("[DASH] this is still experimental feature");
2815
2816         MMPLAYER_FLEAVE();
2817         return element;
2818 }
2819
2820 static GstElement*
2821 __mmplayer_gst_make_file_src(mm_player_t* player)
2822 {
2823         GstElement* element = NULL;
2824
2825         MMPLAYER_FENTER();
2826         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2827
2828         LOGD("using filesrc for 'file://' handler");
2829         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2830                 LOGE("failed to get storage info");
2831                 return NULL;
2832         }
2833
2834         element = gst_element_factory_make("filesrc", "source");
2835         if (!element) {
2836                 LOGE("failed to create filesrc");
2837                 return NULL;
2838         }
2839
2840         g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
2841
2842         MMPLAYER_FLEAVE();
2843         return element;
2844 }
2845
2846 static gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2847 {
2848         mm_player_t *player = (mm_player_t *) data;
2849
2850         g_return_val_if_fail(player, FALSE);
2851         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2852
2853         gst_message_ref(msg);
2854
2855         g_mutex_lock(&player->bus_msg_q_lock);
2856         g_queue_push_tail(player->bus_msg_q, msg);
2857         g_mutex_unlock(&player->bus_msg_q_lock);
2858
2859         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2860         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2861         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2862         return TRUE;
2863 }
2864
2865 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2866 {
2867         mm_player_t *player = (mm_player_t*)(data);
2868         GstMessage *msg = NULL;
2869         GstBus *bus = NULL;
2870
2871         MMPLAYER_FENTER();
2872         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2873                                                 player->pipeline &&
2874                                                 player->pipeline->mainbin &&
2875                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2876                                                 NULL);
2877
2878         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2879         if (!bus) {
2880                 LOGE("cannot get BUS from the pipeline");
2881                 return NULL;
2882         }
2883
2884         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2885
2886         LOGD("[handle: %p] gst bus msg thread will be started.", player);
2887         while (!player->bus_msg_thread_exit) {
2888                 g_mutex_lock(&player->bus_msg_q_lock);
2889                 msg = g_queue_pop_head(player->bus_msg_q);
2890                 g_mutex_unlock(&player->bus_msg_q_lock);
2891                 if (msg == NULL) {
2892                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2893                         continue;
2894                 }
2895                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2896                 /* handle the gst msg */
2897                 __mmplayer_gst_bus_msg_callback(msg, player);
2898                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2899                 gst_message_unref(msg);
2900         }
2901
2902         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2903         gst_object_unref(GST_OBJECT(bus));
2904
2905         MMPLAYER_FLEAVE();
2906         return NULL;
2907 }
2908
2909 static int
2910 __mmplayer_gst_check_duration(mm_player_t* player, gint64 position)
2911 {
2912         gint64 dur_nsec = 0;
2913
2914         MMPLAYER_FENTER();
2915         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2916
2917         if (MMPLAYER_IS_MS_BUFF_SRC(player))
2918                 return MM_ERROR_NONE;
2919
2920         /* NOTE : duration cannot be zero except live streaming.
2921          *              Since some element could have some timing problemn with quering duration, try again.
2922          */
2923         if (player->duration == 0) {
2924                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2925                         /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2926                          * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2927                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2928                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2929                                 player->pending_seek.is_pending = TRUE;
2930                                 player->pending_seek.pos = position;
2931                                 player->seek_state = MMPLAYER_SEEK_NONE;
2932                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2933                                 return MM_ERROR_PLAYER_NO_OP;
2934                         } else {
2935                                 player->seek_state = MMPLAYER_SEEK_NONE;
2936                                 return MM_ERROR_PLAYER_SEEK;
2937                         }
2938                 }
2939                 player->duration = dur_nsec;
2940         }
2941
2942         if (player->duration > 0 && player->duration < position) {
2943                 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2944                 return MM_ERROR_INVALID_ARGUMENT;
2945         }
2946
2947         MMPLAYER_FLEAVE();
2948         return MM_ERROR_NONE;
2949 }
2950
2951 static gboolean
2952 __mmplayer_gst_check_seekable(mm_player_t* player)
2953 {
2954         GstQuery *query = NULL;
2955         gboolean seekable = FALSE;
2956
2957         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2958                 return TRUE;
2959         }
2960
2961         query = gst_query_new_seeking(GST_FORMAT_TIME);
2962         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2963                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2964                 gst_query_unref(query);
2965
2966                 if (!seekable) {
2967                         LOGW("non-seekable content");
2968                         player->seek_state = MMPLAYER_SEEK_NONE;
2969                         return FALSE;
2970                 }
2971         } else {
2972                 LOGW("failed to get seeking query");
2973                 gst_query_unref(query); /* keep seeking operation */
2974         }
2975
2976         return TRUE;
2977 }
2978
2979
2980 #if 0
2981 #endif
2982
2983 int
2984 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element,  GstState state, gboolean async, gint timeout)
2985 {
2986         GstState element_state = GST_STATE_VOID_PENDING;
2987         GstState element_pending_state = GST_STATE_VOID_PENDING;
2988         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2989
2990         MMPLAYER_FENTER();
2991
2992         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2993         MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2994
2995         LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2996
2997         /* set state */
2998         ret = gst_element_set_state(element, state);
2999
3000         if (ret == GST_STATE_CHANGE_FAILURE) {
3001                 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
3002
3003                 /* dump state of all element */
3004                 __mmplayer_dump_pipeline_state(player);
3005
3006                 return MM_ERROR_PLAYER_INTERNAL;
3007         }
3008
3009         /* return here so state transition to be done in async mode */
3010         if (async) {
3011                 LOGD("async state transition. not waiting for state complete.\n");
3012                 return MM_ERROR_NONE;
3013         }
3014
3015         /* wait for state transition */
3016         ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3017
3018         if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3019                 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
3020                         GST_ELEMENT_NAME(element),
3021                         gst_element_state_get_name(state), timeout);
3022
3023                 LOGE(" [%s] state : %s   pending : %s \n",
3024                         GST_ELEMENT_NAME(element),
3025                         gst_element_state_get_name(element_state),
3026                         gst_element_state_get_name(element_pending_state));
3027
3028                 /* dump state of all element */
3029                 __mmplayer_dump_pipeline_state(player);
3030
3031                 return MM_ERROR_PLAYER_INTERNAL;
3032         }
3033
3034         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
3035
3036         MMPLAYER_FLEAVE();
3037
3038         return MM_ERROR_NONE;
3039 }
3040
3041 int __mmplayer_gst_start(mm_player_t* player)
3042 {
3043         int ret = MM_ERROR_NONE;
3044         gboolean async = FALSE;
3045
3046         MMPLAYER_FENTER();
3047
3048         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3049
3050         /* NOTE : if SetPosition was called before Start. do it now */
3051         /* streaming doesn't support it. so it should be always sync */
3052         /* !!create one more api to check if there is pending seek rather than checking variables */
3053         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3054                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3055                 ret = __mmplayer_gst_pause(player, FALSE);
3056                 if (ret != MM_ERROR_NONE) {
3057                         LOGE("failed to set state to PAUSED for pending seek");
3058                         return ret;
3059                 }
3060
3061                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3062                 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3063                                 LOGW("failed to seek pending postion. starting from the begin of content");
3064         }
3065
3066         LOGD("current state before doing transition");
3067         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3068         MMPLAYER_PRINT_STATE(player);
3069
3070         /* set pipeline state to PLAYING  */
3071         ret = __mmplayer_gst_set_state(player,
3072                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3073
3074         if (ret == MM_ERROR_NONE) {
3075                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3076         } else {
3077                 LOGE("failed to set state to PLAYING");
3078                 return ret;
3079         }
3080
3081         /* generating debug info before returning error */
3082         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3083
3084         MMPLAYER_FLEAVE();
3085
3086         return ret;
3087 }
3088
3089 int __mmplayer_gst_stop(mm_player_t* player)
3090 {
3091         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3092         MMHandleType attrs = 0;
3093         gboolean rewind = FALSE;
3094         gint timeout = 0;
3095         int ret = MM_ERROR_NONE;
3096
3097         MMPLAYER_FENTER();
3098
3099         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3100         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3101
3102         LOGD("current state before doing transition");
3103         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3104         MMPLAYER_PRINT_STATE(player);
3105
3106         attrs = MMPLAYER_GET_ATTRS(player);
3107         if (!attrs) {
3108                 LOGE("cannot get content attribute\n");
3109                 return MM_ERROR_PLAYER_INTERNAL;
3110         }
3111
3112         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3113         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3114
3115         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3116                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3117                 rewind = TRUE;
3118
3119         if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3120                 /* disable the async state transition because there could be no data in the pipeline */
3121                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3122         }
3123
3124         /* set gst state */
3125         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3126
3127         if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
3128                 /* enable the async state transition as default operation */
3129                 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3130         }
3131
3132         /* return if set_state has failed */
3133         if (ret != MM_ERROR_NONE) {
3134                 LOGE("failed to set state.\n");
3135                 return ret;
3136         }
3137
3138         /* rewind */
3139         if (rewind) {
3140                 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3141                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3142                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3143                         LOGW("failed to rewind\n");
3144                         ret = MM_ERROR_PLAYER_SEEK;
3145                 }
3146         }
3147
3148         /* initialize */
3149         player->sent_bos = FALSE;
3150
3151         if (player->es_player_push_mode) //for cloudgame
3152                 timeout = 0;
3153
3154         /* wait for seek to complete */
3155         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3156         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3157                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3158         } else {
3159                 LOGE("fail to stop player.\n");
3160                 ret = MM_ERROR_PLAYER_INTERNAL;
3161                 __mmplayer_dump_pipeline_state(player);
3162         }
3163
3164         /* generate dot file if enabled */
3165         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3166
3167         MMPLAYER_FLEAVE();
3168
3169         return ret;
3170 }
3171
3172 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
3173 {
3174         int ret = MM_ERROR_NONE;
3175
3176         MMPLAYER_FENTER();
3177
3178         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3179         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3180
3181         LOGD("current state before doing transition");
3182         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3183         MMPLAYER_PRINT_STATE(player);
3184
3185         /* set pipeline status to PAUSED */
3186         ret = __mmplayer_gst_set_state(player,
3187                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3188
3189         if (FALSE == async) {
3190                 if (ret != MM_ERROR_NONE) {
3191                         GstMessage *msg = NULL;
3192                         GTimer *timer = NULL;
3193                         gdouble MAX_TIMEOUT_SEC = 3;
3194
3195                         LOGE("failed to set state to PAUSED");
3196
3197                         if (!player->bus_watcher) {
3198                                 LOGE("there is no bus msg thread. pipeline is shutting down.");
3199                                 return ret;
3200                         }
3201
3202                         if (player->msg_posted) {
3203                                 LOGE("error msg is already posted.");
3204                                 return ret;
3205                         }
3206
3207                         timer = g_timer_new();
3208                         g_timer_start(timer);
3209
3210                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3211
3212                         do {
3213                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3214                                 if (msg) {
3215                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3216                                                 GError *error = NULL;
3217
3218                                                 /* parse error code */
3219                                                 gst_message_parse_error(msg, &error, NULL);
3220
3221                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3222                                                         /* Note : the streaming error from the streaming source is handled
3223                                                          *   using __mmplayer_handle_streaming_error.
3224                                                          */
3225                                                         __mmplayer_handle_streaming_error(player, msg);
3226
3227                                                 } else if (error) {
3228                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3229
3230                                                         if (error->domain == GST_STREAM_ERROR)
3231                                                                 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3232                                                         else if (error->domain == GST_RESOURCE_ERROR)
3233                                                                 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3234                                                         else if (error->domain == GST_LIBRARY_ERROR)
3235                                                                 ret = __mmplayer_gst_handle_library_error(player, error->code);
3236                                                         else if (error->domain == GST_CORE_ERROR)
3237                                                                 ret = __mmplayer_gst_handle_core_error(player, error->code);
3238
3239                                                         g_error_free(error);
3240                                                 }
3241                                                 player->msg_posted = TRUE;
3242                                         }
3243                                         gst_message_unref(msg);
3244                                 }
3245                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3246                         /* clean */
3247                         gst_object_unref(bus);
3248                         g_timer_stop(timer);
3249                         g_timer_destroy(timer);
3250
3251                         return ret;
3252
3253                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3254                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
3255
3256                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3257
3258                 } else {
3259                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3260                 }
3261         }
3262
3263         /* generate dot file before returning error */
3264         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3265
3266         MMPLAYER_FLEAVE();
3267
3268         return ret;
3269 }
3270
3271 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
3272 {
3273         int ret = MM_ERROR_NONE;
3274         gint timeout = 0;
3275
3276         MMPLAYER_FENTER();
3277
3278         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3279                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3280
3281         LOGD("current state before doing transition");
3282         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3283         MMPLAYER_PRINT_STATE(player);
3284
3285         if (async)
3286                 LOGD("do async state transition to PLAYING");
3287
3288         /* set pipeline state to PLAYING */
3289         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3290
3291         ret = __mmplayer_gst_set_state(player,
3292                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3293         if (ret != MM_ERROR_NONE) {
3294                 LOGE("failed to set state to PLAYING");
3295                 goto EXIT;
3296         } else {
3297                 if (async == FALSE)
3298                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3299         }
3300
3301 EXIT:
3302         /* generate dot file */
3303         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3304
3305         MMPLAYER_FLEAVE();
3306
3307         return ret;
3308 }
3309
3310 /* sending event to one of sinkelements */
3311 gboolean
3312 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
3313 {
3314         GstEvent * event2 = NULL;
3315         GList *sinks = NULL;
3316         gboolean res = FALSE;
3317         MMPLAYER_FENTER();
3318
3319         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3320         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3321
3322         /* While adding subtitles in live feeds seek is getting called.
3323            Adding defensive check in framework layer.*/
3324         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3325                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3326                         LOGE("Should not send seek event during live playback");
3327                         return TRUE;
3328                 }
3329         }
3330
3331         if (player->play_subtitle)
3332                 event2 = gst_event_copy((const GstEvent *)event);
3333
3334         sinks = player->sink_elements;
3335         while (sinks) {
3336                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3337
3338                 if (GST_IS_ELEMENT(sink)) {
3339                         /* keep ref to the event */
3340                         gst_event_ref(event);
3341
3342                         if ((res = gst_element_send_event(sink, event))) {
3343                                 LOGD("sending event[%s] to sink element [%s] success!\n",
3344                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3345
3346                                 /* rtsp case, asyn_done is not called after seek during pause state */
3347                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3348                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3349                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3350                                                         LOGD("RTSP seek completed, after pause state..\n");
3351                                                         player->seek_state = MMPLAYER_SEEK_NONE;
3352                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3353                                                 }
3354
3355                                         }
3356                                 }
3357
3358                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3359                                         sinks = g_list_next(sinks);
3360                                         continue;
3361                                 } else {
3362                                         break;
3363                                 }
3364                         }
3365
3366                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
3367                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3368                 }
3369
3370                 sinks = g_list_next(sinks);
3371         }
3372
3373         /* Note : Textbin is not linked to the video or audio bin.
3374          * It needs to send the event to the text sink seperatelly.
3375          */
3376          if (player->play_subtitle && player->pipeline) {
3377                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3378
3379                 if (GST_IS_ELEMENT(text_sink)) {
3380                         /* keep ref to the event */
3381                         gst_event_ref(event2);
3382
3383                         if ((res = gst_element_send_event(text_sink, event2)))
3384                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
3385                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3386                         else
3387                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
3388                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3389
3390                         gst_event_unref(event2);
3391                 }
3392          }
3393
3394         gst_event_unref(event);
3395
3396         MMPLAYER_FLEAVE();
3397
3398         return res;
3399 }
3400
3401 gboolean
3402 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
3403                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3404                         gint64 cur, GstSeekType stop_type, gint64 stop)
3405 {
3406         GstEvent* event = NULL;
3407         gboolean result = FALSE;
3408
3409         MMPLAYER_FENTER();
3410
3411         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3412
3413         if (player->pipeline && player->pipeline->textbin)
3414                 __mmplayer_drop_subtitle(player, FALSE);
3415
3416         event = gst_event_new_seek(rate, format, flags, cur_type,
3417                 cur, stop_type, stop);
3418
3419         result = __mmplayer_gst_send_event_to_sink(player, event);
3420
3421         MMPLAYER_FLEAVE();
3422
3423         return result;
3424 }
3425
3426 int
3427 __mmplayer_gst_set_position(mm_player_t* player, gint64 position, gboolean internal_called)
3428 {
3429         int ret = MM_ERROR_NONE;
3430         gint64 pos_nsec = 0;
3431         gboolean accurated = FALSE;
3432         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3433
3434         MMPLAYER_FENTER();
3435         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3436         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3437
3438         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
3439                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
3440                 goto PENDING;
3441
3442         ret = __mmplayer_gst_check_duration(player, position);
3443         if (ret != MM_ERROR_NONE) {
3444                 LOGE("failed to check duration 0x%X", ret);
3445                 return (ret == MM_ERROR_PLAYER_NO_OP) ? (MM_ERROR_NONE) : (ret);
3446         }
3447
3448         if (!__mmplayer_gst_check_seekable(player))
3449                 return MM_ERROR_PLAYER_NO_OP;
3450
3451         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3452                                 position, player->playback_rate, player->duration);
3453
3454         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3455            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3456            This causes problem is position calculation during normal pause resume scenarios also.
3457            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3458         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3459                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3460                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3461                         LOGW("getting current position failed in seek");
3462
3463                 player->last_position = pos_nsec;
3464                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3465         }
3466
3467         if (player->seek_state != MMPLAYER_SEEK_NONE) {
3468                 LOGD("not completed seek");
3469                 return MM_ERROR_PLAYER_DOING_SEEK;
3470         }
3471
3472         if (!internal_called)
3473                 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3474
3475         /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3476                 that's why set position through property. */
3477         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3478                 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3479                 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3480                 (!player->videodec_linked) && (!player->audiodec_linked)) {
3481
3482                 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3483                                 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3484
3485                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3486                 player->seek_state = MMPLAYER_SEEK_NONE;
3487                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3488         } else {
3489                 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3490                 if (accurated)
3491                         seek_flags |= GST_SEEK_FLAG_ACCURATE;
3492                 else
3493                         seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3494
3495                 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3496                                                 GST_FORMAT_TIME, seek_flags,
3497                                                 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3498                         LOGE("failed to set position");
3499                         goto SEEK_ERROR;
3500                 }
3501         }
3502
3503         /* NOTE : store last seeking point to overcome some bad operation
3504           *     (returning zero when getting current position) of some elements
3505           */
3506         player->last_position = position;
3507
3508         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3509         if (player->playback_rate > 1.0)
3510                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3511
3512         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3513                 LOGD("buffering should be reset after seeking");
3514                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3515                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3516         }
3517
3518         MMPLAYER_FLEAVE();
3519         return MM_ERROR_NONE;
3520
3521 PENDING:
3522         player->pending_seek.is_pending = TRUE;
3523         player->pending_seek.pos = position;
3524
3525         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3526                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3527                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3528                 player->pending_seek.pos);
3529
3530         return MM_ERROR_NONE;
3531
3532 SEEK_ERROR:
3533         player->seek_state = MMPLAYER_SEEK_NONE;
3534         return MM_ERROR_PLAYER_SEEK;
3535 }
3536
3537 int
3538 __mmplayer_gst_get_position(mm_player_t* player, gint64* position)
3539 {
3540 #define TRICKPLAY_OFFSET GST_MSECOND
3541
3542         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3543         gint64 pos_nsec = 0;
3544         gboolean ret = TRUE;
3545
3546         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3547                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3548
3549         current_state = MMPLAYER_CURRENT_STATE(player);
3550
3551         /* NOTE : query position except paused state to overcome some bad operation
3552          * please refer to below comments in details
3553          */
3554         if (current_state != MM_PLAYER_STATE_PAUSED)
3555                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3556
3557         /* NOTE : get last point to overcome some bad operation of some elements
3558          *(returning zero when getting current position in paused state
3559          * and when failed to get postion during seeking
3560          */
3561         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3562                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3563
3564                 if (player->playback_rate < 0.0)
3565                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3566                 else
3567                         pos_nsec = player->last_position;
3568
3569                 if (!ret)
3570                         pos_nsec = player->last_position;
3571                 else
3572                         player->last_position = pos_nsec;
3573
3574                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3575
3576         } else {
3577                 if (player->duration > 0 && pos_nsec > player->duration)
3578                         pos_nsec = player->duration;
3579
3580                 player->last_position = pos_nsec;
3581         }
3582
3583         *position = pos_nsec;
3584
3585         return MM_ERROR_NONE;
3586 }
3587
3588 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
3589 {
3590 #define STREAMING_IS_FINISHED   0
3591 #define BUFFERING_MAX_PER       100
3592 #define DEFAULT_PER_VALUE       -1
3593 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3594
3595         MMPlayerGstElement *mainbin = NULL;
3596         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
3597         gint64 buffered_total = 0;
3598         gint64 position = 0;
3599         gint buffered_sec = -1;
3600         GstBufferingMode mode = GST_BUFFERING_STREAM;
3601         gint64 content_size_time = player->duration;
3602         guint64 content_size_bytes = player->http_content_size;
3603
3604         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3605                                                 player->pipeline &&
3606                                                 player->pipeline->mainbin,
3607                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3608
3609         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
3610
3611         *start_pos = 0;
3612         *stop_pos = 0;
3613
3614         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3615                 /* and rtsp is not ready yet. */
3616                 LOGW("it's only used for http streaming case");
3617                 return MM_ERROR_PLAYER_NO_OP;
3618         }
3619
3620         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
3621                 LOGW("Time format is not supported yet");
3622                 return MM_ERROR_INVALID_ARGUMENT;
3623         }
3624
3625         if (content_size_time <= 0 || content_size_bytes <= 0) {
3626                 LOGW("there is no content size");
3627                 return MM_ERROR_NONE;
3628         }
3629
3630         if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3631                 LOGW("fail to get current position");
3632                 return MM_ERROR_NONE;
3633         }
3634
3635         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3636                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3637
3638         mainbin = player->pipeline->mainbin;
3639         start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
3640
3641         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3642                 GstQuery *query = NULL;
3643                 gint byte_in_rate = 0, byte_out_rate = 0;
3644                 gint64 estimated_total = 0;
3645
3646                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3647                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3648                         LOGW("fail to get buffering query from queue2");
3649                         if (query)
3650                                 gst_query_unref(query);
3651                         return MM_ERROR_NONE;
3652                 }
3653
3654                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3655                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3656
3657                 if (mode == GST_BUFFERING_STREAM) {
3658                         /* using only queue in case of push mode(ts / mp3) */
3659                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3660                                 GST_FORMAT_BYTES, &buffered_total)) {
3661                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3662                                 stop_per = 100 * buffered_total / content_size_bytes;
3663                         }
3664                 } else {
3665                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3666                         guint idx = 0;
3667                         guint num_of_ranges = 0;
3668                         gint64 start_byte = 0, stop_byte = 0;
3669
3670                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3671                         if (estimated_total != STREAMING_IS_FINISHED) {
3672                                 /* buffered size info from queue2 */
3673                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3674                                 for (idx = 0; idx < num_of_ranges; idx++) {
3675                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3676                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3677
3678                                         buffered_total += (stop_byte - start_byte);
3679                                 }
3680                         } else
3681                                 stop_per = BUFFERING_MAX_PER;
3682                 }
3683                 gst_query_unref(query);
3684         }
3685
3686         if (stop_per == DEFAULT_PER_VALUE) {
3687                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3688                 if (dur_sec > 0) {
3689                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3690
3691                         /* buffered size info from multiqueue */
3692                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3693                                 guint curr_size_bytes = 0;
3694                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3695                                         "curr-size-bytes", &curr_size_bytes, NULL);
3696                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3697                                 buffered_total += curr_size_bytes;
3698                         }
3699
3700                         if (avg_byterate > 0)
3701                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3702                         else if (player->total_maximum_bitrate > 0)
3703                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3704                         else if (player->total_bitrate > 0)
3705                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3706
3707                         if (buffered_sec >= 0)
3708                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3709                 }
3710         }
3711
3712         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3713         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3714
3715         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu",
3716                 buffered_total, buffered_sec, *start_pos, *stop_pos);
3717
3718         return MM_ERROR_NONE;
3719 }
3720
3721 GstElement* __mmplayer_gst_create_source(mm_player_t* player)
3722 {
3723         GstElement* element = NULL;
3724
3725         MMPLAYER_FENTER();
3726         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3727                                 player->pipeline->mainbin, NULL);
3728
3729         /* setup source for gapless play */
3730         switch (player->profile.uri_type) {
3731         /* file source */
3732         case MM_PLAYER_URI_TYPE_FILE:
3733                 element = __mmplayer_gst_make_file_src(player);
3734                 break;
3735         case MM_PLAYER_URI_TYPE_URL_HTTP:
3736                 element = __mmplayer_gst_make_http_src(player);
3737                 break;
3738         default:
3739                 LOGE("not support uri type %d", player->profile.uri_type);
3740                 break;
3741         }
3742
3743         if (!element) {
3744                 LOGE("failed to create source element");
3745                 return NULL;
3746         }
3747
3748         MMPLAYER_FLEAVE();
3749         return element;
3750 }
3751
3752 int __mmplayer_gst_build_es_pipeline(mm_player_t* player)
3753 {
3754         MMHandleType attrs = 0;
3755
3756         MMPLAYER_FENTER();
3757         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3758                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3759
3760         /* get profile attribute */
3761         attrs = MMPLAYER_GET_ATTRS(player);
3762         if (!attrs) {
3763                 LOGE("failed to get content attribute");
3764                 return MM_ERROR_PLAYER_INTERNAL;
3765         }
3766
3767         SECURE_LOGD("uri : %s", player->profile.uri);
3768
3769         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3770         if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3771                 LOGE("failed to commit");
3772
3773         if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3774                 return MM_ERROR_PLAYER_INTERNAL;
3775
3776         if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3777                 return MM_ERROR_PLAYER_INTERNAL;
3778
3779         if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3780                 return MM_ERROR_PLAYER_INTERNAL;
3781
3782         MMPLAYER_FLEAVE();
3783         return MM_ERROR_NONE;
3784 }
3785
3786 int __mmplayer_gst_build_pd_pipeline(mm_player_t* player)
3787 {
3788         MMPlayerGstElement *mainbin = NULL;
3789         GstElement *pd_src = NULL;
3790         GstElement *pd_queue = NULL;
3791         GstElement *pd_decodebin = NULL;
3792         GList* element_bucket = NULL;
3793         MMHandleType attrs = 0;
3794         gchar *path = NULL;
3795         gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
3796
3797         MMPLAYER_FENTER();
3798         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3799                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3800
3801         /* get profile attribute */
3802         attrs = MMPLAYER_GET_ATTRS(player);
3803         if (!attrs) {
3804                 LOGE("failed to get content attribute");
3805                 return MM_ERROR_PLAYER_INTERNAL;
3806         }
3807
3808         LOGD("http playback with progressive download : %d", player->pd_mode);
3809
3810         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
3811                 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
3812                 MMPLAYER_FREEIF(player->pd_file_save_path);
3813
3814                 SECURE_LOGD("PD Location : %s", path);
3815                 if (!path) {
3816                         LOGE("filed to find pd location");
3817                         return MM_ERROR_PLAYER_INTERNAL;
3818                 }
3819
3820                 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
3821                         LOGE("failed to get storage info");
3822                         return MM_ERROR_PLAYER_INTERNAL;
3823                 }
3824                 player->pd_file_save_path = g_strdup(path);
3825         }
3826
3827         pd_src = gst_element_factory_make("pdpushsrc", "PD pushsrc");
3828         if (!pd_src) {
3829                 LOGE("failed to create PD push source");
3830                 return MM_ERROR_PLAYER_INTERNAL;
3831         }
3832
3833         if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
3834                 g_object_set(G_OBJECT(pd_src), "location", player->pd_file_save_path, NULL);
3835         else
3836                 g_object_set(G_OBJECT(pd_src), "location", player->profile.uri, NULL);
3837
3838         mainbin = player->pipeline->mainbin;
3839
3840         /* take source element */
3841         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3842         mainbin[MMPLAYER_M_SRC].gst = pd_src;
3843         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3844
3845         /* setting queue */
3846         LOGD("Picked queue2 element(pre buffer : %d ms)", pre_buffering_time);
3847         pd_queue = gst_element_factory_make("queue2", "queue2");
3848         if (!pd_queue) {
3849                 LOGE("failed to create pd buffer element");
3850                 goto ERROR;
3851         }
3852
3853         /* take queue2 */
3854         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3855         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = pd_queue;
3856         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
3857
3858         pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
3859
3860         player->streamer->is_pd_mode = TRUE;
3861
3862         __mm_player_streaming_set_queue2(player->streamer, pd_queue, TRUE,
3863                         player->ini.http_max_size_bytes, pre_buffering_time, 1.0,
3864                         player->ini.http_buffering_limit, MUXED_BUFFER_TYPE_MEM_QUEUE, NULL, 0);
3865
3866         pd_decodebin = __mmplayer_gst_make_decodebin(player);
3867         if (!pd_decodebin) {
3868                 LOGE("failed to create decodebin");
3869                 goto ERROR;
3870         }
3871
3872         /* default size of mq in decodebin is 2M
3873          * but it can cause blocking issue during seeking depends on content. */
3874         g_object_set(G_OBJECT(pd_decodebin), "max-size-bytes", (5*1024*1024), NULL);
3875
3876         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
3877         mainbin[MMPLAYER_M_AUTOPLUG].gst = pd_decodebin;
3878
3879         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
3880
3881         /* add elements to pipeline */
3882         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3883                 LOGE("failed to add elements to pipeline");
3884                 goto ERROR;
3885         }
3886
3887         /* linking elements in the bucket by added order. */
3888         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3889                 LOGE("failed to link some elements");
3890                 goto ERROR;
3891         }
3892
3893         g_list_free(element_bucket);
3894
3895         MMPLAYER_FLEAVE();
3896         return MM_ERROR_NONE;
3897
3898 ERROR:
3899         MMPLAYER_FREEIF(player->pd_file_save_path);
3900         g_list_free(element_bucket);
3901
3902         if (mainbin[MMPLAYER_M_SRC].gst)
3903                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3904
3905         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)
3906                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst));
3907
3908         if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
3909                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
3910
3911         mainbin[MMPLAYER_M_SRC].gst = NULL;
3912         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
3913         mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
3914
3915         return MM_ERROR_PLAYER_INTERNAL;
3916 }
3917
3918 int __mmplayer_gst_build_pipeline(mm_player_t* player)
3919 {
3920         MMPlayerGstElement *mainbin = NULL;
3921         GstElement* src_elem = NULL;
3922         GstElement *autoplug_elem = NULL;
3923         GList* element_bucket = NULL;
3924         MMHandleType attrs = 0;
3925         enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3926
3927         MMPLAYER_FENTER();
3928         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3929                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3930
3931         /* get profile attribute */
3932         attrs = MMPLAYER_GET_ATTRS(player);
3933         if (!attrs) {
3934                 LOGE("failed to get content attribute");
3935                 return MM_ERROR_PLAYER_INTERNAL;
3936         }
3937
3938         LOGD("uri type %d", player->profile.uri_type);
3939
3940         /* create source element */
3941         switch (player->profile.uri_type) {
3942         case MM_PLAYER_URI_TYPE_URL_RTSP:
3943                 src_elem = __mmplayer_gst_make_rtsp_src(player);
3944                 break;
3945         case MM_PLAYER_URI_TYPE_URL_HTTP:
3946                 src_elem = __mmplayer_gst_make_http_src(player);
3947                 break;
3948         case MM_PLAYER_URI_TYPE_FILE:
3949                 src_elem = __mmplayer_gst_make_file_src(player);
3950                 break;
3951         case MM_PLAYER_URI_TYPE_SS:
3952                 {
3953                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3954                         src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3955                         if (!src_elem) {
3956                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3957                                 break;
3958                         }
3959
3960                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3961                                 LOGD("get timeout from ini");
3962                                 http_timeout = player->ini.http_timeout;
3963                         }
3964
3965                         /* setting property to streaming source */
3966                         g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3967                 }
3968                 break;
3969         case MM_PLAYER_URI_TYPE_MEM:
3970                 {
3971                         GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3972
3973                         src_elem = gst_element_factory_make("appsrc", "mem-source");
3974                         if (!src_elem) {
3975                                 LOGE("failed to create appsrc element");
3976                                 break;
3977                         }
3978
3979                         g_object_set(src_elem, "stream-type", stream_type,
3980                                 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3981
3982                         __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3983                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3984                         __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3985                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3986                 }
3987                 break;
3988         default:
3989                 LOGE("not support uri type");
3990                 break;
3991         }
3992
3993         if (!src_elem) {
3994                 LOGE("failed to create source element");
3995                 return MM_ERROR_PLAYER_INTERNAL;
3996         }
3997
3998         mainbin = player->pipeline->mainbin;
3999
4000         /* take source element */
4001         LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4002
4003         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4004         mainbin[MMPLAYER_M_SRC].gst = src_elem;
4005         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4006
4007         /* create next element for auto-plugging */
4008         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4009                 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4010                 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4011                 if (!autoplug_elem) {
4012                         LOGE("failed to create typefind element");
4013                         goto ERROR;
4014                 }
4015
4016                 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4017                                                                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
4018         } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4019                 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4020                 autoplug_elem = __mmplayer_gst_make_decodebin(player);
4021                 if (!autoplug_elem) {
4022                         LOGE("failed to create decodebin");
4023                         goto ERROR;
4024                 }
4025
4026                 /* default size of mq in decodebin is 2M
4027                  * but it can cause blocking issue during seeking depends on content. */
4028                 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5*1024*1024), NULL);
4029         }
4030
4031         if (autoplug_elem) {
4032                 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4033                 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4034                 mainbin[autoplug_elem_id].gst = autoplug_elem;
4035
4036                 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4037         }
4038
4039         /* add elements to pipeline */
4040         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4041                 LOGE("failed to add elements to pipeline");
4042                 goto ERROR;
4043         }
4044
4045         /* linking elements in the bucket by added order. */
4046         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4047                 LOGE("failed to link some elements");
4048                 goto ERROR;
4049         }
4050
4051         /* FIXME: need to check whether this is required or not. */
4052         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
4053                 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4054                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4055                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4056
4057                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4058                         LOGE("failed to create fakesink");
4059                         goto ERROR;
4060                 }
4061                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4062
4063                 /* take ownership of fakesink. we are reusing it */
4064                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4065
4066                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4067                         LOGE("failed to add fakesink to bin");
4068                         gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4069                         goto ERROR;
4070                 }
4071         }
4072
4073         g_list_free(element_bucket);
4074
4075         MMPLAYER_FLEAVE();
4076         return MM_ERROR_NONE;
4077
4078 ERROR:
4079         g_list_free(element_bucket);
4080
4081         if (mainbin[MMPLAYER_M_SRC].gst)
4082                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4083
4084         if (mainbin[autoplug_elem_id].gst)
4085                 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4086
4087         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4088                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4089
4090         mainbin[MMPLAYER_M_SRC].gst = NULL;
4091         mainbin[autoplug_elem_id].gst = NULL;
4092         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4093
4094         return MM_ERROR_PLAYER_INTERNAL;
4095 }
4096
4097 int __mmplayer_gst_add_bus_watch(mm_player_t* player)
4098 {
4099         GstBus  *bus = NULL;
4100         MMPlayerGstElement *mainbin = NULL;
4101
4102         MMPLAYER_FENTER();
4103         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4104                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4105
4106         mainbin = player->pipeline->mainbin;
4107
4108         /* connect bus callback */
4109         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4110         if (!bus) {
4111                 LOGE("cannot get bus from pipeline");
4112                 return MM_ERROR_PLAYER_INTERNAL;
4113         }
4114
4115         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4116         player->context.thread_default = g_main_context_get_thread_default();
4117         if (player->context.thread_default == NULL) {
4118                 player->context.thread_default = g_main_context_default();
4119                 LOGD("thread-default context is the global default context");
4120         }
4121         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4122
4123         /* set sync handler to get tag synchronously */
4124         gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4125         gst_object_unref(GST_OBJECT(bus));
4126
4127         /* create gst bus_msb_cb thread */
4128         g_mutex_init(&player->bus_msg_thread_mutex);
4129         g_cond_init(&player->bus_msg_thread_cond);
4130         player->bus_msg_thread_exit = FALSE;
4131         player->bus_msg_thread =
4132                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4133         if (!player->bus_msg_thread) {
4134                 LOGE("failed to create gst BUS msg thread");
4135                 g_mutex_clear(&player->bus_msg_thread_mutex);
4136                 g_cond_clear(&player->bus_msg_thread_cond);
4137                 return MM_ERROR_PLAYER_INTERNAL;
4138         }
4139
4140         MMPLAYER_FLEAVE();
4141         return MM_ERROR_NONE;
4142 }