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